began node hashing for improved cache
This commit is contained in:
@@ -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
|
||||
*
|
||||
|
||||
@@ -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_) {
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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>(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>(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;
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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<NodeParam*> params = parameters();
|
||||
foreach (NodeParam* param, params) {
|
||||
if (param->type() == NodeParam::kInput && !param->IsConnected()) {
|
||||
// Get the value at this time
|
||||
QVariant v = static_cast<NodeInput*>(param)->get_value(time);
|
||||
hash->addData(v.toByteArray()); // FIXME: Does this work on all value types?
|
||||
}
|
||||
}
|
||||
|
||||
// Add each dependency node
|
||||
QList<NodeDependency> 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<quintptr>(ptr);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef NODE_H
|
||||
#define NODE_H
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user