rational: implement NaN mode
Also clarify code where 0 is used as a rational.
This commit is contained in:
@@ -60,7 +60,7 @@ public:
|
||||
*
|
||||
* Starting at `start`, writes samples over anything in the buffer, expanding it if necessary.
|
||||
*/
|
||||
void OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational& start = rational());
|
||||
void OverwriteSamples(SampleBufferPtr samples, int sample_rate, const rational& start = 0);
|
||||
|
||||
/**
|
||||
* @brief Replaces sums at a certain range in this visual waveform
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
*
|
||||
* Maximum length of `sums` to overwrite with.
|
||||
*/
|
||||
void OverwriteSums(const AudioVisualWaveform& sums, const rational& dest, const rational& offset = rational(), const rational &length = rational());
|
||||
void OverwriteSums(const AudioVisualWaveform& sums, const rational& dest, const rational& offset = 0, const rational &length = 0);
|
||||
|
||||
void Shift(const rational& from, const rational& to);
|
||||
|
||||
|
||||
+90
-72
@@ -7,24 +7,28 @@ namespace olive {
|
||||
|
||||
rational rational::fromDouble(const double &flt, bool* ok)
|
||||
{
|
||||
if (qIsNaN(flt)) {
|
||||
// Return NaN rational
|
||||
if (ok) *ok = false;
|
||||
return rational(0, 0);
|
||||
}
|
||||
|
||||
// Use FFmpeg function for the time being
|
||||
AVRational r = av_d2q(flt, INT_MAX);
|
||||
|
||||
if (r.den == 0) {
|
||||
// If den == 0, we were unable to convert to a rational
|
||||
if (ok) {
|
||||
*ok = false;
|
||||
}
|
||||
|
||||
return rational();
|
||||
} else {
|
||||
// Otherwise, assume we received a real rational
|
||||
if (ok) {
|
||||
*ok = true;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
rational rational::fromString(const QString &str, bool* ok)
|
||||
@@ -37,32 +41,32 @@ rational rational::fromString(const QString &str, bool* ok)
|
||||
case 2:
|
||||
return rational(elements.at(0).toLongLong(ok), elements.at(1).toLongLong(ok));
|
||||
default:
|
||||
// Returns NaN with ok set to false
|
||||
if (ok) {
|
||||
*ok = false;
|
||||
}
|
||||
return rational();
|
||||
return rational(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//Function: print number to cout
|
||||
|
||||
void rational::print(std::ostream &out) const
|
||||
{
|
||||
out << this->numer_ << "/" << this->denom_;
|
||||
}
|
||||
|
||||
//Function: ensures denom >= 0
|
||||
|
||||
void rational::fix_signs()
|
||||
{
|
||||
// Normalize so that denominator is always positive and only numerator is positive
|
||||
if (denom_ < 0) {
|
||||
denom_ = -denom_;
|
||||
numer_ = -numer_;
|
||||
}
|
||||
|
||||
if (numer_ == intType(0) || denom_ == intType(0)) {
|
||||
// Normalize to 0/1 if numerator is zero
|
||||
if (numer_ == intType(0)) {
|
||||
denom_ = intType(1);
|
||||
}
|
||||
|
||||
// Normalize to 0/0 (aka NaN) if denominator is zero
|
||||
if (denom_ == intType(0)) {
|
||||
numer_ = intType(0);
|
||||
denom_ = intType(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +111,7 @@ double rational::toDouble() const
|
||||
if (denom_ != 0) {
|
||||
return static_cast<double>(numer_) / static_cast<double>(denom_);
|
||||
} else {
|
||||
return static_cast<double>(0);
|
||||
return qSNaN();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +141,11 @@ rational rational::flipped() const
|
||||
}
|
||||
|
||||
bool rational::isNull() const
|
||||
{
|
||||
return numerator() == 0;
|
||||
}
|
||||
|
||||
bool rational::isNaN() const
|
||||
{
|
||||
return denominator() == 0;
|
||||
}
|
||||
@@ -170,15 +179,21 @@ const rational& rational::operator=(const rational &rhs)
|
||||
|
||||
const rational& rational::operator+=(const rational &rhs)
|
||||
{
|
||||
if (!rhs.isNull()) {
|
||||
if (isNull()) {
|
||||
numer_ = rhs.numer_;
|
||||
denom_ = rhs.denom_;
|
||||
} else {
|
||||
numer_ = (numer_ * rhs.denom_) + (rhs.numer_ * denom_);
|
||||
denom_ = denom_ * rhs.denom_;
|
||||
if (!isNaN()) {
|
||||
if (rhs.isNaN()) {
|
||||
// Set to NaN
|
||||
denom_ = 0;
|
||||
fix_signs();
|
||||
reduce();
|
||||
} else if (!rhs.isNull()) {
|
||||
if (isNull()) {
|
||||
numer_ = rhs.numer_;
|
||||
denom_ = rhs.denom_;
|
||||
} else {
|
||||
numer_ = (numer_ * rhs.denom_) + (rhs.numer_ * denom_);
|
||||
denom_ = denom_ * rhs.denom_;
|
||||
fix_signs();
|
||||
reduce();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,15 +202,21 @@ const rational& rational::operator+=(const rational &rhs)
|
||||
|
||||
const rational& rational::operator-=(const rational &rhs)
|
||||
{
|
||||
if (!rhs.isNull()) {
|
||||
if (isNull()) {
|
||||
numer_ = -rhs.numer_;
|
||||
denom_ = rhs.denom_;
|
||||
} else {
|
||||
numer_ = (numer_ * rhs.denom_) - (rhs.numer_ * denom_);
|
||||
denom_ = denom_ * rhs.denom_;
|
||||
if (!isNaN()) {
|
||||
if (rhs.isNaN()) {
|
||||
// Set to NaN
|
||||
denom_ = 0;
|
||||
fix_signs();
|
||||
reduce();
|
||||
} else if (!rhs.isNull()) {
|
||||
if (isNull()) {
|
||||
numer_ = -rhs.numer_;
|
||||
denom_ = rhs.denom_;
|
||||
} else {
|
||||
numer_ = (numer_ * rhs.denom_) - (rhs.numer_ * denom_);
|
||||
denom_ = denom_ * rhs.denom_;
|
||||
fix_signs();
|
||||
reduce();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,19 +225,36 @@ const rational& rational::operator-=(const rational &rhs)
|
||||
|
||||
const rational& rational::operator/=(const rational &rhs)
|
||||
{
|
||||
numer_ = numer_ * rhs.denom_;
|
||||
denom_ = denom_ * rhs.numer_;
|
||||
fix_signs();
|
||||
reduce();
|
||||
if (!isNaN()) {
|
||||
if (rhs.isNaN()) {
|
||||
// Set to NaN
|
||||
denom_ = 0;
|
||||
fix_signs();
|
||||
} else {
|
||||
numer_ = numer_ * rhs.denom_;
|
||||
denom_ = denom_ * rhs.numer_;
|
||||
fix_signs();
|
||||
reduce();
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const rational& rational::operator*=(const rational &rhs)
|
||||
{
|
||||
numer_ = numer_ * rhs.numer_;
|
||||
denom_ = denom_ * rhs.denom_;
|
||||
fix_signs();
|
||||
reduce();
|
||||
if (!isNaN()) {
|
||||
if (rhs.isNaN()) {
|
||||
denom_ = 0;
|
||||
fix_signs();
|
||||
} else {
|
||||
numer_ = numer_ * rhs.numer_;
|
||||
denom_ = denom_ * rhs.denom_;
|
||||
fix_signs();
|
||||
reduce();
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -254,6 +292,10 @@ rational rational::operator*(const rational &rhs) const
|
||||
|
||||
bool rational::operator<(const rational &rhs) const
|
||||
{
|
||||
if (isNaN() || rhs.isNaN()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isNull() && rhs.isNull()) {
|
||||
return false;
|
||||
}
|
||||
@@ -283,6 +325,10 @@ bool rational::operator<(const rational &rhs) const
|
||||
|
||||
bool rational::operator<=(const rational &rhs) const
|
||||
{
|
||||
if (isNaN() || rhs.isNaN()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isNull() && rhs.isNull()) {
|
||||
return true;
|
||||
}
|
||||
@@ -322,40 +368,16 @@ bool rational::operator>=(const rational &rhs) const
|
||||
|
||||
bool rational::operator==(const rational &rhs) const
|
||||
{
|
||||
if (isNaN() || rhs.isNaN()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (numer_ == rhs.numer_ && denom_ == rhs.denom_);
|
||||
}
|
||||
|
||||
bool rational::operator!=(const rational &rhs) const
|
||||
{
|
||||
return (numer_ != rhs.numer_) || (denom_ != rhs.denom_);
|
||||
}
|
||||
|
||||
//Unary operators
|
||||
|
||||
const rational& rational::operator++()
|
||||
{
|
||||
numer_ += denom_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
rational rational::operator++(int)
|
||||
{
|
||||
rational tmp = *this;
|
||||
numer_ += denom_;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const rational& rational::operator--()
|
||||
{
|
||||
numer_ -= denom_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
rational rational::operator--(int)
|
||||
{
|
||||
rational tmp;
|
||||
numer_ -= denom_;
|
||||
return tmp;
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
const rational& rational::operator+() const
|
||||
@@ -417,8 +439,4 @@ uint qHash(const rational &r, uint seed)
|
||||
QDebug operator<<(QDebug debug, const olive::rational &r)
|
||||
{
|
||||
return debug.space() << r.toDouble();
|
||||
/*
|
||||
debug.nospace() << r.numerator() << "/" << r.denominator();
|
||||
return debug.space();
|
||||
*/
|
||||
}
|
||||
|
||||
+7
-13
@@ -34,13 +34,9 @@ class rational
|
||||
public:
|
||||
//constructors
|
||||
rational(const intType &numerator = 0) :
|
||||
numer_(numerator)
|
||||
numer_(numerator),
|
||||
denom_(1)
|
||||
{
|
||||
if (numer_ == 0) {
|
||||
denom_ = 0;
|
||||
} else {
|
||||
denom_ = 1;
|
||||
}
|
||||
}
|
||||
|
||||
rational(const intType &numerator, const intType &denominator) :
|
||||
@@ -87,10 +83,6 @@ public:
|
||||
bool operator!=(const rational &rhs) const;
|
||||
|
||||
//Unary operators
|
||||
const rational& operator++(); //prefix
|
||||
rational operator++(int); //postfix
|
||||
const rational& operator--(); //prefix
|
||||
rational operator--(int); //postfix
|
||||
const rational& operator+() const;
|
||||
rational operator-() const;
|
||||
bool operator!() const;
|
||||
@@ -108,11 +100,13 @@ public:
|
||||
// Produce "flipped" version
|
||||
rational flipped() const;
|
||||
|
||||
// Returns whether the rational is null or not
|
||||
// Returns whether the rational is valid but equal to zero or not
|
||||
//
|
||||
// A NaN is always a null, but a null is not always a NaN
|
||||
bool isNull() const;
|
||||
|
||||
//Function: print number to cout
|
||||
void print(std::ostream &out = std::cout) const;
|
||||
// Returns whether this rational is not a valid number
|
||||
bool isNaN() const;
|
||||
|
||||
//IO
|
||||
friend std::ostream& operator<<(std::ostream &out, const rational &value);
|
||||
|
||||
@@ -40,6 +40,9 @@ const QString Track::kMutedInput = QStringLiteral("muted_in");
|
||||
|
||||
Track::Track() :
|
||||
track_type_(Track::kNone),
|
||||
track_length_(0),
|
||||
midop_track_length_(0),
|
||||
preop_track_length_(0),
|
||||
index_(-1),
|
||||
locked_(false)
|
||||
{
|
||||
@@ -276,7 +279,7 @@ void Track::InputDisconnectedEvent(const QString &input, int element, const Node
|
||||
if (next) {
|
||||
UpdateInOutFrom(blocks_.indexOf(next));
|
||||
} else if (blocks_.isEmpty()) {
|
||||
SetLengthInternal(rational());
|
||||
SetLengthInternal(0);
|
||||
} else {
|
||||
SetLengthInternal(blocks_.last()->out());
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace olive {
|
||||
TrackList::TrackList(Sequence *parent, const Track::Type &type, const QString &track_input) :
|
||||
QObject(parent),
|
||||
track_input_(track_input),
|
||||
total_length_(0),
|
||||
type_(type)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -37,6 +37,9 @@ const uint64_t ViewerOutput::kVideoParamEditMask = VideoParamEdit::kWidthHeight
|
||||
#define super Node
|
||||
|
||||
ViewerOutput::ViewerOutput(bool create_default_streams) :
|
||||
last_length_(0),
|
||||
video_length_(0),
|
||||
audio_length_(0),
|
||||
video_frame_cache_(this),
|
||||
audio_playback_cache_(this),
|
||||
video_cache_enabled_(true),
|
||||
@@ -226,7 +229,7 @@ void ViewerOutput::InvalidateCache(const TimeRange& range, const QString& from,
|
||||
|
||||
if ((video_cache_enabled_ && (from == kTextureInput || from == kVideoParamsInput))
|
||||
|| (audio_cache_enabled_ && (from == kSamplesInput || from == kAudioParamsInput))) {
|
||||
TimeRange invalidated_range(qMax(rational(), range.in()),
|
||||
TimeRange invalidated_range(qMax(rational(0), range.in()),
|
||||
qMin(GetLength(), range.out()));
|
||||
|
||||
if (invalidated_range.in() != invalidated_range.out()) {
|
||||
@@ -297,8 +300,6 @@ void ViewerOutput::Retranslate()
|
||||
|
||||
void ViewerOutput::VerifyLength()
|
||||
{
|
||||
rational subtitle_length;
|
||||
|
||||
video_length_ = VerifyLengthInternal(Track::kVideo);
|
||||
if (video_cache_enabled_) {
|
||||
video_frame_cache_.SetLength(video_length_);
|
||||
@@ -309,7 +310,7 @@ void ViewerOutput::VerifyLength()
|
||||
audio_playback_cache_.SetLength(audio_length_);
|
||||
}
|
||||
|
||||
subtitle_length = VerifyLengthInternal(Track::kSubtitle);
|
||||
rational subtitle_length = VerifyLengthInternal(Track::kSubtitle);
|
||||
|
||||
rational real_length = qMax(subtitle_length, qMax(video_length_, audio_length_));
|
||||
|
||||
@@ -345,14 +346,19 @@ rational ViewerOutput::VerifyLengthInternal(Track::Type type) const
|
||||
case Track::kVideo:
|
||||
if (IsInputConnected(kTextureInput)) {
|
||||
NodeValueTable t = traverser.GenerateTable(GetConnectedOutput(kTextureInput), TimeRange(0, 0));
|
||||
qDebug() << "Got video length:" << t.Get(NodeValue::kRational, QStringLiteral("length")).value<rational>();
|
||||
return t.Get(NodeValue::kRational, QStringLiteral("length")).value<rational>();
|
||||
rational r = t.Get(NodeValue::kRational, QStringLiteral("length")).value<rational>();
|
||||
if (!r.isNaN()) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Track::kAudio:
|
||||
if (IsInputConnected(kSamplesInput)) {
|
||||
NodeValueTable t = traverser.GenerateTable(GetConnectedOutput(kSamplesInput), TimeRange(0, 0));
|
||||
return t.Get(NodeValue::kRational, QStringLiteral("length")).value<rational>();
|
||||
rational r = t.Get(NodeValue::kRational, QStringLiteral("length")).value<rational>();;
|
||||
if (!r.isNaN()) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Track::kNone:
|
||||
@@ -361,7 +367,7 @@ rational ViewerOutput::VerifyLengthInternal(Track::Type type) const
|
||||
break;
|
||||
}
|
||||
|
||||
return rational();
|
||||
return 0;
|
||||
}
|
||||
|
||||
NodeOutput ViewerOutput::GetConnectedTextureOutput()
|
||||
|
||||
@@ -196,7 +196,7 @@ rational Footage::VerifyLengthInternal(Track::Type type) const
|
||||
}
|
||||
}
|
||||
|
||||
return super::VerifyLengthInternal(type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString Footage::GetColorspaceToUse(const VideoParams ¶ms) const
|
||||
|
||||
@@ -123,7 +123,7 @@ rational Sequence::VerifyLengthInternal(Track::Type type) const
|
||||
}
|
||||
}
|
||||
|
||||
return rational();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sequence::InputConnectedEvent(const QString &input, int element, const NodeOutput &output)
|
||||
|
||||
@@ -322,7 +322,7 @@ void FrameHashCache::ShiftEvent(const rational &from, const rational &to)
|
||||
// POSITIVE if moving forward ->
|
||||
// NEGATIVE if moving backward <-
|
||||
rational diff = to - from;
|
||||
bool diff_is_negative = (diff < rational());
|
||||
bool diff_is_negative = (diff < 0);
|
||||
|
||||
QList<HashTimePair> shifted_times;
|
||||
|
||||
@@ -353,10 +353,12 @@ void FrameHashCache::ShiftEvent(const rational &from, const rational &to)
|
||||
|
||||
void FrameHashCache::InvalidateEvent(const TimeRange &range)
|
||||
{
|
||||
QVector<rational> invalid_frames = GetFrameListFromTimeRange({range});
|
||||
if (!timebase_.isNull()) {
|
||||
QVector<rational> invalid_frames = GetFrameListFromTimeRange({range});
|
||||
|
||||
foreach (const rational& r, invalid_frames) {
|
||||
time_hash_map_.remove(r);
|
||||
foreach (const rational& r, invalid_frames) {
|
||||
time_hash_map_.remove(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,8 @@ class PlaybackCache : public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
PlaybackCache(QObject* parent = nullptr) :
|
||||
QObject(parent)
|
||||
QObject(parent),
|
||||
length_(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ PreviewAutoCacher::PreviewAutoCacher() :
|
||||
last_update_time_(0),
|
||||
ignore_next_mouse_button_(false)
|
||||
{
|
||||
// Set default autocache range
|
||||
SetPlayhead(rational());
|
||||
SetPlayhead(0);
|
||||
|
||||
delayed_requeue_timer_.setInterval(Config::Current()[QStringLiteral("AutoCacheDelay")].toInt());
|
||||
delayed_requeue_timer_.setSingleShot(true);
|
||||
|
||||
@@ -1224,7 +1224,7 @@ void TimelineWidget::RippleTo(Timeline::MovementMode mode)
|
||||
}
|
||||
|
||||
// Find each track's nearest point and determine the overall timeline's nearest point
|
||||
rational closest_point_to_playhead = (mode == Timeline::kTrimIn) ? rational() : RATIONAL_MAX;
|
||||
rational closest_point_to_playhead = (mode == Timeline::kTrimIn) ? 0 : RATIONAL_MAX;
|
||||
|
||||
foreach (const Timeline::EditToInfo& info, tracks) {
|
||||
if (info.nearest_block) {
|
||||
|
||||
@@ -203,7 +203,7 @@ void ViewerWidget::ConnectNodeEvent(ViewerOutput *n)
|
||||
|
||||
SetViewerResolution(vp.width(), vp.height());
|
||||
SetViewerPixelAspect(vp.pixel_aspect_ratio());
|
||||
last_length_ = rational();
|
||||
last_length_ = 0;
|
||||
LengthChangedSlot(n->GetLength());
|
||||
|
||||
ColorManager* color_manager = n->project()->color_manager();
|
||||
@@ -358,7 +358,7 @@ void ViewerWidget::SetAutoCacheEnabled(bool e)
|
||||
|
||||
void ViewerWidget::CacheEntireSequence()
|
||||
{
|
||||
auto_cacher_.ForceCacheRange(TimeRange(rational(), GetConnectedNode()->video_frame_cache()->GetLength()));
|
||||
auto_cacher_.ForceCacheRange(TimeRange(0, GetConnectedNode()->video_frame_cache()->GetLength()));
|
||||
}
|
||||
|
||||
void ViewerWidget::CacheSequenceInOut()
|
||||
|
||||
Reference in New Issue
Block a user