diff --git a/app/decoder/decoder.h b/app/decoder/decoder.h index 35950b6bc..0d463857f 100644 --- a/app/decoder/decoder.h +++ b/app/decoder/decoder.h @@ -160,6 +160,13 @@ public: */ virtual void Close() = 0; + /** + * @brief Get a media file's internal timestamp + * + * Used to determine which frame will be served at a given time, useful for caching. + */ + virtual int64_t GetTimestampFromTime(const rational& time) = 0; + /** * @brief Try to probe a Footage file by passing it through all available Decoders * diff --git a/app/decoder/ffmpeg/ffmpegdecoder.cpp b/app/decoder/ffmpeg/ffmpegdecoder.cpp index 38b99a202..5f448295d 100644 --- a/app/decoder/ffmpeg/ffmpegdecoder.cpp +++ b/app/decoder/ffmpeg/ffmpegdecoder.cpp @@ -195,10 +195,7 @@ FramePtr FFmpegDecoder::Retrieve(const rational &timecode, const rational &lengt } // Convert timecode to AVStream timebase - int64_t target_ts = qFloor(timecode.toDouble() * rational(avstream_->time_base).flipped().toDouble()); - - // Find closest actual timebase in the file - target_ts = GetClosestTimestampInIndex(target_ts); + int64_t target_ts = GetTimestampFromTime(timecode); if (target_ts < 0) { Error(tr("Index failed to produce a valid timestamp")); @@ -323,6 +320,21 @@ QString FFmpegDecoder::id() return "ffmpeg"; } +int64_t FFmpegDecoder::GetTimestampFromTime(const rational &time) +{ + if (!open_ && !Open()) { + return -1; + } + + // Convert timecode to AVStream timebase + int64_t target_ts = qFloor(time.toDouble() * rational(avstream_->time_base).flipped().toDouble()); + + // Find closest actual timebase in the file + target_ts = GetClosestTimestampInIndex(target_ts); + + return target_ts; +} + bool FFmpegDecoder::Probe(Footage *f) { if (open_) { diff --git a/app/decoder/ffmpeg/ffmpegdecoder.h b/app/decoder/ffmpeg/ffmpegdecoder.h index 8021edf89..621251f29 100644 --- a/app/decoder/ffmpeg/ffmpegdecoder.h +++ b/app/decoder/ffmpeg/ffmpegdecoder.h @@ -51,6 +51,8 @@ public: virtual QString id() override; + virtual int64_t GetTimestampFromTime(const rational& time) override; + private: /** * @brief Handle an error @@ -117,6 +119,8 @@ private: */ void SaveFrameIndex(); + int64_t GetClosestTimestampInIndex(const int64_t& ts); + /** * @brief Returns an AVPixelFormat that can be * @param pix_fmt @@ -124,8 +128,6 @@ private: */ AVPixelFormat GetCompatiblePixelFormat(const AVPixelFormat& pix_fmt); - int64_t GetClosestTimestampInIndex(const int64_t& ts); - AVFormatContext* fmt_ctx_; AVCodecContext* codec_ctx_; AVStream* avstream_; diff --git a/app/node/input/media/media.cpp b/app/node/input/media/media.cpp index 83ffb64ce..75873f12b 100644 --- a/app/node/input/media/media.cpp +++ b/app/node/input/media/media.cpp @@ -97,6 +97,18 @@ void MediaInput::SetFootage(Footage *f) footage_input_->set_value(PtrToValue(f)); } +void MediaInput::Hash(QCryptographicHash *hash, const rational &time) +{ + Node::Hash(hash, time); + + // Use frame value from Decoder + if (SetupDecoder()) { + hash->addData(QString::number(decoder_->GetTimestampFromTime(time)).toUtf8()); + // FIXME: Add OCIO data + // FIXME: Add alpha association value + } +} + QVariant MediaInput::Value(NodeOutput *output, const rational &time) { // FIXME: Hardcoded value @@ -111,27 +123,11 @@ QVariant MediaInput::Value(NodeOutput *output, const rational &time) return 0; } - // Get currently selected Footage - Footage* footage = ValueToPtr(footage_input_->get_value(time)); - - // If no footage is selected, return nothing - if (footage == nullptr) { + // Make sure decoder is set up + if (!SetupDecoder()) { return 0; } - // Otherwise try to get frame of footage from decoder - - // Determine which decoder to use - if (decoder_ == nullptr - && (decoder_ = Decoder::CreateFromID(footage->decoder())) == nullptr) { - return 0; - } - - if (decoder_->stream() == nullptr) { - // FIXME: Hardcoded stream 0 - decoder_->set_stream(footage->stream(0)); - } - // Get frame from Decoder FramePtr frame = decoder_->Retrieve(time); @@ -247,3 +243,33 @@ QVariant MediaInput::Value(NodeOutput *output, const rational &time) return 0; } + +bool MediaInput::SetupDecoder() +{ + if (decoder_ != nullptr) { + return true; + } + + // Get currently selected Footage + Footage* footage = ValueToPtr(footage_input_->get_value(0)); + + // If no footage is selected, return nothing + if (footage == nullptr) { + return false; + } + + // Otherwise try to get frame of footage from decoder + + // Determine which decoder to use + if (decoder_ == nullptr + && (decoder_ = Decoder::CreateFromID(footage->decoder())) == nullptr) { + return false; + } + + if (decoder_->stream() == nullptr) { + // FIXME: Hardcoded stream 0 + decoder_->set_stream(footage->stream(0)); + } + + return true; +} diff --git a/app/node/input/media/media.h b/app/node/input/media/media.h index 8d9023fb5..f0278a2f0 100644 --- a/app/node/input/media/media.h +++ b/app/node/input/media/media.h @@ -51,10 +51,16 @@ public: void SetFootage(Footage* f); + virtual void Hash(QCryptographicHash *hash, const rational &time) override; + + + protected: virtual QVariant Value(NodeOutput* output, const rational& time) override; private: + bool SetupDecoder(); + NodeInput* footage_input_; NodeInput* matrix_input_; diff --git a/app/node/node.cpp b/app/node/node.cpp index a1e6c9f43..8107c6302 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -279,6 +279,29 @@ bool Node::OutputsTo(Node *n) return false; } +void Node::Hash(QCryptographicHash *hash, NodeOutput* from, const rational &time) +{ + // Add this Node's ID + hash->addData(id().toUtf8()); + + // Add each value + QList params = parameters(); + foreach (NodeParam* param, params) { + if (param->type() == NodeParam::kInput && !param->IsConnected()) { + // Get the value at this time + QVariant v = static_cast(param)->get_value(time); + hash->addData(v.toByteArray()); // FIXME: Does this work on all value types? + } + } + + // Add each dependency node + QList deps = RunDependencies(from, time); + foreach (const NodeDependency& dep, deps) { + // Hash the connected node + dep.node()->parent()->Hash(hash, dep.node(), time); + } +} + QVariant Node::PtrToValue(void *ptr) { return reinterpret_cast(ptr); diff --git a/app/node/node.h b/app/node/node.h index a1112df3d..a908e1340 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -21,6 +21,7 @@ #ifndef NODE_H #define NODE_H +#include #include #include @@ -147,6 +148,11 @@ public: */ bool OutputsTo(Node* n); + /** + * @brief Add's unique information about this Node at the given time to a QCryptographicHash + */ + virtual void Hash(QCryptographicHash* hash, NodeOutput *from, const rational& time); + /** * @brief Convert a pointer to a value that can be sent between NodeParams */