moved sequence params into node graph too
Reduces code by reusing more of the existing node infrastructure to synchronize sequence parameters the render backend.
This commit is contained in:
@@ -25,6 +25,9 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QCryptographicHash>
|
||||
|
||||
#include "common/xmlutils.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -172,6 +175,52 @@ bool AudioParams::is_valid() const
|
||||
&& format_ < kFormatCount);
|
||||
}
|
||||
|
||||
QByteArray AudioParams::toBytes() const
|
||||
{
|
||||
QCryptographicHash hasher(QCryptographicHash::Sha1);
|
||||
|
||||
hasher.addData(reinterpret_cast<const char*>(&sample_rate_), sizeof(sample_rate_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&channel_layout_), sizeof(channel_layout_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&format_), sizeof(format_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&timebase_), sizeof(timebase_));
|
||||
|
||||
return hasher.result();
|
||||
}
|
||||
|
||||
void AudioParams::Load(QXmlStreamReader *reader)
|
||||
{
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("samplerate")) {
|
||||
set_sample_rate(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("channellayout")) {
|
||||
set_channel_layout(reader->readElementText().toULongLong());
|
||||
} else if (reader->name() == QStringLiteral("format")) {
|
||||
set_format(static_cast<AudioParams::Format>(reader->readElementText().toInt()));
|
||||
} else if (reader->name() == QStringLiteral("enabled")) {
|
||||
set_enabled(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("streamindex")) {
|
||||
set_stream_index(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("duration")) {
|
||||
set_duration(reader->readElementText().toLongLong());
|
||||
} else if (reader->name() == QStringLiteral("timebase")) {
|
||||
set_time_base(rational::fromString(reader->readElementText()));
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioParams::Save(QXmlStreamWriter *writer) const
|
||||
{
|
||||
writer->writeTextElement(QStringLiteral("samplerate"), QString::number(sample_rate_));
|
||||
writer->writeTextElement(QStringLiteral("channellayout"), QString::number(channel_layout_));
|
||||
writer->writeTextElement(QStringLiteral("format"), QString::number(format_));
|
||||
writer->writeTextElement(QStringLiteral("enabled"), QString::number(enabled_));
|
||||
writer->writeTextElement(QStringLiteral("streamindex"), QString::number(stream_index_));
|
||||
writer->writeTextElement(QStringLiteral("duration"), QString::number(duration_));
|
||||
writer->writeTextElement(QStringLiteral("timebase"), timebase_.toString());
|
||||
}
|
||||
|
||||
QString AudioParams::SampleRateToString(const int &sample_rate)
|
||||
{
|
||||
return QCoreApplication::translate("AudioParams", "%1 Hz").arg(sample_rate);
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#include <QAudioFormat>
|
||||
#include <QtMath>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
#include "common/rational.h"
|
||||
|
||||
@@ -63,6 +65,7 @@ public:
|
||||
channel_layout_(0),
|
||||
format_(kFormatInvalid)
|
||||
{
|
||||
set_default_footage_parameters();
|
||||
}
|
||||
|
||||
AudioParams(const int& sample_rate, const uint64_t& channel_layout, const Format& format) :
|
||||
@@ -70,28 +73,83 @@ public:
|
||||
channel_layout_(channel_layout),
|
||||
format_(format)
|
||||
{
|
||||
set_default_footage_parameters();
|
||||
}
|
||||
|
||||
const int& sample_rate() const
|
||||
int sample_rate() const
|
||||
{
|
||||
return sample_rate_;
|
||||
}
|
||||
|
||||
const uint64_t& channel_layout() const
|
||||
void set_sample_rate(int sample_rate)
|
||||
{
|
||||
sample_rate_ = sample_rate;
|
||||
}
|
||||
|
||||
uint64_t channel_layout() const
|
||||
{
|
||||
return channel_layout_;
|
||||
}
|
||||
|
||||
rational time_base() const
|
||||
void set_channel_layout(uint64_t channel_layout)
|
||||
{
|
||||
return rational(1, sample_rate());
|
||||
channel_layout_ = channel_layout;
|
||||
}
|
||||
|
||||
const Format &format() const
|
||||
rational time_base() const
|
||||
{
|
||||
if (timebase_.isNull()) {
|
||||
return rational(1, sample_rate());
|
||||
} else {
|
||||
return timebase_;
|
||||
}
|
||||
}
|
||||
|
||||
void set_time_base(const rational& timebase)
|
||||
{
|
||||
timebase_ = timebase;
|
||||
}
|
||||
|
||||
Format format() const
|
||||
{
|
||||
return format_;
|
||||
}
|
||||
|
||||
void set_format(Format format)
|
||||
{
|
||||
format_ = format;
|
||||
}
|
||||
|
||||
bool enabled() const
|
||||
{
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
void set_enabled(bool e)
|
||||
{
|
||||
enabled_ = e;
|
||||
}
|
||||
|
||||
int stream_index() const
|
||||
{
|
||||
return stream_index_;
|
||||
}
|
||||
|
||||
void set_stream_index(int s)
|
||||
{
|
||||
stream_index_ = s;
|
||||
}
|
||||
|
||||
int64_t duration() const
|
||||
{
|
||||
return duration_;
|
||||
}
|
||||
|
||||
void set_duration(int64_t duration)
|
||||
{
|
||||
duration_ = duration;
|
||||
}
|
||||
|
||||
qint64 time_to_bytes(const double& time) const;
|
||||
qint64 time_to_bytes(const rational& time) const;
|
||||
qint64 time_to_samples(const double& time) const;
|
||||
@@ -105,6 +163,12 @@ public:
|
||||
int bits_per_sample() const;
|
||||
bool is_valid() const;
|
||||
|
||||
QByteArray toBytes() const;
|
||||
|
||||
void Load(QXmlStreamReader* reader);
|
||||
|
||||
void Save(QXmlStreamWriter* writer) const;
|
||||
|
||||
bool operator==(const AudioParams& other) const;
|
||||
bool operator!=(const AudioParams& other) const;
|
||||
|
||||
@@ -124,12 +188,25 @@ public:
|
||||
static QString ChannelLayoutToString(const uint64_t &layout);
|
||||
|
||||
private:
|
||||
void set_default_footage_parameters()
|
||||
{
|
||||
enabled_ = true;
|
||||
stream_index_ = 0;
|
||||
duration_ = 0;
|
||||
}
|
||||
|
||||
int sample_rate_;
|
||||
|
||||
uint64_t channel_layout_;
|
||||
|
||||
Format format_;
|
||||
|
||||
// Footage-specific
|
||||
bool enabled_;
|
||||
int stream_index_;
|
||||
int64_t duration_;
|
||||
rational timebase_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+58
-11
@@ -28,28 +28,75 @@ namespace olive {
|
||||
class FootageJob
|
||||
{
|
||||
public:
|
||||
FootageJob() = default;
|
||||
|
||||
FootageJob(const Footage::StreamReference& ref, const TimeRange& range) :
|
||||
footage_(ref),
|
||||
range_(range)
|
||||
FootageJob() :
|
||||
type_(Stream::kUnknown)
|
||||
{
|
||||
}
|
||||
|
||||
const Footage::StreamReference& footage() const
|
||||
FootageJob(const QString& decoder, const QString& filename, Stream::Type type) :
|
||||
decoder_(decoder),
|
||||
filename_(filename),
|
||||
type_(type)
|
||||
{
|
||||
return footage_;
|
||||
}
|
||||
|
||||
const TimeRange& range() const
|
||||
const QString& decoder() const
|
||||
{
|
||||
return range_;
|
||||
return decoder_;
|
||||
}
|
||||
|
||||
const QString& filename() const
|
||||
{
|
||||
return filename_;
|
||||
}
|
||||
|
||||
Stream::Type type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
const VideoParams& video_params() const
|
||||
{
|
||||
return video_params_;
|
||||
}
|
||||
|
||||
void set_video_params(const VideoParams& p)
|
||||
{
|
||||
video_params_ = p;
|
||||
}
|
||||
|
||||
const AudioParams& audio_params() const
|
||||
{
|
||||
return audio_params_;
|
||||
}
|
||||
|
||||
void set_audio_params(const AudioParams& p)
|
||||
{
|
||||
audio_params_ = p;
|
||||
}
|
||||
|
||||
const QString& cache_path() const
|
||||
{
|
||||
return cache_path_;
|
||||
}
|
||||
|
||||
void set_cache_path(const QString& p)
|
||||
{
|
||||
cache_path_ = p;
|
||||
}
|
||||
|
||||
private:
|
||||
Footage::StreamReference footage_;
|
||||
QString decoder_;
|
||||
|
||||
TimeRange range_;
|
||||
QString filename_;
|
||||
|
||||
Stream::Type type_;
|
||||
|
||||
VideoParams video_params_;
|
||||
|
||||
AudioParams audio_params_;
|
||||
|
||||
QString cache_path_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -437,8 +437,8 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video
|
||||
case NodeValue::kRational:
|
||||
case NodeValue::kFont:
|
||||
case NodeValue::kFile:
|
||||
case NodeValue::kVideoStreamProperties:
|
||||
case NodeValue::kAudioStreamProperties:
|
||||
case NodeValue::kVideoParams:
|
||||
case NodeValue::kAudioParams:
|
||||
case NodeValue::kShaderJob:
|
||||
case NodeValue::kSampleJob:
|
||||
case NodeValue::kGenerateJob:
|
||||
|
||||
@@ -65,7 +65,7 @@ void PreviewAutoCacher::GenerateHashes(Sequence *viewer, FrameHashCache* cache,
|
||||
|
||||
foreach (const rational& time, times) {
|
||||
// See if hash already exists in disk cache
|
||||
QByteArray hash = RenderManager::Hash(viewer->GetConnectedNode(ViewerOutput::kTextureInput), viewer->video_params(), time);
|
||||
QByteArray hash = RenderManager::Hash(viewer->GetConnectedNode(Sequence::kTextureInput), viewer->video_params(), time);
|
||||
|
||||
// Check memory list since disk checking is slow
|
||||
bool hash_exists = (std::find(existing_hashes.begin(), existing_hashes.end(), hash) != existing_hashes.end());
|
||||
@@ -264,12 +264,6 @@ void PreviewAutoCacher::ProcessUpdateQueue()
|
||||
case QueuedJob::kValueChanged:
|
||||
CopyValue(job.input);
|
||||
break;
|
||||
case QueuedJob::kVideoParamsChanged:
|
||||
UpdateVideoParams();
|
||||
break;
|
||||
case QueuedJob::kAudioParamsChanged:
|
||||
UpdateAudioParams();
|
||||
break;
|
||||
}
|
||||
}
|
||||
graph_update_queue_.clear();
|
||||
@@ -330,16 +324,6 @@ void PreviewAutoCacher::CopyValue(const NodeInput &input)
|
||||
Node::CopyValuesOfElement(input.node(), our_input, input.input(), input.element());
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::UpdateVideoParams()
|
||||
{
|
||||
copied_viewer_node_->set_video_params(viewer_node_->video_params());
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::UpdateAudioParams()
|
||||
{
|
||||
copied_viewer_node_->set_audio_params(viewer_node_->audio_params());
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::SetPlayhead(const rational &playhead)
|
||||
{
|
||||
cache_range_ = TimeRange(playhead - Config::Current()[QStringLiteral("DiskCacheBehind")].value<rational>(),
|
||||
@@ -449,23 +433,6 @@ void PreviewAutoCacher::ValueChanged(const NodeInput &input)
|
||||
graph_update_queue_.append({QueuedJob::kValueChanged, nullptr, input, NodeOutput()});
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::VideoParamsChanged()
|
||||
{
|
||||
// In case the user is pressing the mouse at this exact moment
|
||||
IgnoreNextMouseButton();
|
||||
|
||||
graph_update_queue_.append({QueuedJob::kVideoParamsChanged, nullptr, NodeInput(), NodeOutput()});
|
||||
ClearVideoQueue();
|
||||
TryRender();
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::AudioParamsChanged()
|
||||
{
|
||||
graph_update_queue_.append({QueuedJob::kAudioParamsChanged, nullptr, NodeInput(), NodeOutput()});
|
||||
ClearAudioQueue();
|
||||
TryRender();
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::TryRender()
|
||||
{
|
||||
if (!graph_update_queue_.isEmpty()) {
|
||||
@@ -639,16 +606,6 @@ void PreviewAutoCacher::SetViewerNode(Sequence *viewer_node)
|
||||
disconnect(graph, &NodeGraph::ValueChanged, this, &PreviewAutoCacher::ValueChanged);
|
||||
|
||||
// Disconnect signal (will be a no-op if the signal was never connected)
|
||||
disconnect(viewer_node_,
|
||||
&ViewerOutput::VideoParamsChanged,
|
||||
this,
|
||||
&PreviewAutoCacher::VideoParamsChanged);
|
||||
|
||||
disconnect(viewer_node_,
|
||||
&ViewerOutput::AudioParamsChanged,
|
||||
this,
|
||||
&PreviewAutoCacher::AudioParamsChanged);
|
||||
|
||||
disconnect(viewer_node_->video_frame_cache(),
|
||||
&PlaybackCache::Invalidated,
|
||||
this,
|
||||
@@ -672,7 +629,7 @@ void PreviewAutoCacher::SetViewerNode(Sequence *viewer_node)
|
||||
}
|
||||
|
||||
// Find copied viewer node
|
||||
copied_viewer_node_ = static_cast<ViewerOutput*>(copy_map_.value(viewer_node_));
|
||||
copied_viewer_node_ = static_cast<Sequence*>(copy_map_.value(viewer_node_));
|
||||
|
||||
// Copy parameters
|
||||
copied_viewer_node_->set_video_params(viewer_node_->video_params());
|
||||
@@ -698,20 +655,6 @@ void PreviewAutoCacher::SetViewerNode(Sequence *viewer_node)
|
||||
invalidated_video_ = viewer_node_->video_frame_cache()->GetInvalidatedRanges();
|
||||
invalidated_audio_ = viewer_node_->audio_playback_cache()->GetInvalidatedRanges();
|
||||
|
||||
// We begin an operation and never end it which prevents the copy from unnecessarily
|
||||
// invalidating its own cache
|
||||
copied_viewer_node_->BeginOperation();
|
||||
|
||||
connect(viewer_node_,
|
||||
&ViewerOutput::VideoParamsChanged,
|
||||
this,
|
||||
&PreviewAutoCacher::VideoParamsChanged);
|
||||
|
||||
connect(viewer_node_,
|
||||
&ViewerOutput::AudioParamsChanged,
|
||||
this,
|
||||
&PreviewAutoCacher::AudioParamsChanged);
|
||||
|
||||
connect(viewer_node_->video_frame_cache(),
|
||||
&PlaybackCache::Invalidated,
|
||||
this,
|
||||
|
||||
@@ -111,8 +111,6 @@ private:
|
||||
void AddEdge(const NodeOutput& output, const NodeInput& input);
|
||||
void RemoveEdge(const NodeOutput& output, const NodeInput& input);
|
||||
void CopyValue(const NodeInput& input);
|
||||
void UpdateVideoParams();
|
||||
void UpdateAudioParams();
|
||||
|
||||
class QueuedJob {
|
||||
public:
|
||||
@@ -121,9 +119,7 @@ private:
|
||||
kNodeRemoved,
|
||||
kEdgeAdded,
|
||||
kEdgeRemoved,
|
||||
kValueChanged,
|
||||
kVideoParamsChanged,
|
||||
kAudioParamsChanged
|
||||
kValueChanged
|
||||
};
|
||||
|
||||
Type type;
|
||||
@@ -210,10 +206,6 @@ private slots:
|
||||
|
||||
void ValueChanged(const NodeInput& input);
|
||||
|
||||
void VideoParamsChanged();
|
||||
|
||||
void AudioParamsChanged();
|
||||
|
||||
void SingleFrameFinished();
|
||||
|
||||
/**
|
||||
|
||||
@@ -262,7 +262,7 @@ NodeValueTable RenderProcessor::GenerateBlockTable(const Track *track, const Tim
|
||||
}
|
||||
}
|
||||
|
||||
QVariant RenderProcessor::ProcessVideoFootage(const Footage::StreamReference &stream, const rational &input_time)
|
||||
QVariant RenderProcessor::ProcessVideoFootage(const FootageJob &stream, const rational &input_time)
|
||||
{
|
||||
TexturePtr value = nullptr;
|
||||
|
||||
@@ -270,27 +270,34 @@ QVariant RenderProcessor::ProcessVideoFootage(const Footage::StreamReference &st
|
||||
// and color managing them for every frame is a waste of time, so we implement a small cache here
|
||||
// to optimize such a situation
|
||||
const VideoParams& render_params = ticket_->property("vparam").value<VideoParams>();
|
||||
VideoParams stream_params = stream.video_params();
|
||||
VideoParams stream_data = stream.video_params();
|
||||
|
||||
ColorManager* color_manager = Node::ValueToPtr<ColorManager>(ticket_->property("colormanager"));
|
||||
|
||||
// See if we can make this divider larger (i.e. if the fooage is smaller)
|
||||
int footage_divider = render_params.divider();
|
||||
while (footage_divider > 1
|
||||
&& VideoParams::GetScaledDimension(stream_params.width(), footage_divider-1) < render_params.effective_width()
|
||||
&& VideoParams::GetScaledDimension(stream_params.height(), footage_divider-1) < render_params.effective_height()) {
|
||||
&& VideoParams::GetScaledDimension(stream_data.width(), footage_divider-1) < render_params.effective_width()
|
||||
&& VideoParams::GetScaledDimension(stream_data.height(), footage_divider-1) < render_params.effective_height()) {
|
||||
footage_divider--;
|
||||
}
|
||||
|
||||
Stream stream_data = stream.GetStream();
|
||||
QString using_colorspace = stream_data.colorspace();
|
||||
|
||||
if (using_colorspace.isEmpty()) {
|
||||
// FIXME:
|
||||
qWarning() << "HAVEN'T GOTTEN DEFAULT INPUT COLORSPACE";
|
||||
}
|
||||
|
||||
Decoder::CodecStream default_codec_stream(stream.filename(), stream_data.stream_index());
|
||||
|
||||
StillImageCache::EntryPtr want_entry = std::make_shared<StillImageCache::Entry>(
|
||||
nullptr,
|
||||
stream,
|
||||
ColorProcessor::GenerateID(color_manager, stream.video_colorspace(), color_manager->GetReferenceColorSpace()),
|
||||
default_codec_stream,
|
||||
ColorProcessor::GenerateID(color_manager, using_colorspace, color_manager->GetReferenceColorSpace()),
|
||||
stream_data.premultiplied_alpha(),
|
||||
footage_divider,
|
||||
(stream_data.video_type() == Stream::kVideoTypeStill) ? 0 : input_time,
|
||||
(stream_data.video_type() == VideoParams::kVideoTypeStill) ? 0 : input_time,
|
||||
true);
|
||||
|
||||
bool found_existing = false;
|
||||
@@ -327,31 +334,31 @@ QVariant RenderProcessor::ProcessVideoFootage(const Footage::StreamReference &st
|
||||
|
||||
still_image_cache_->mutex()->unlock();
|
||||
|
||||
QString decoder_id = stream.footage()->decoder();
|
||||
QString decoder_id = stream.decoder();
|
||||
|
||||
DecoderPtr decoder = nullptr;
|
||||
|
||||
if (stream_data.video_type() == Stream::kVideoTypeVideo) {
|
||||
decoder = ResolveDecoderFromInput(decoder_id, Decoder::GetCodecStreamFromStreamReference(stream));
|
||||
if (stream_data.video_type() == VideoParams::kVideoTypeVideo) {
|
||||
decoder = ResolveDecoderFromInput(decoder_id, default_codec_stream);
|
||||
} else {
|
||||
// Since image sequences involve multiple files, we don't engage the decoder cache
|
||||
decoder = Decoder::CreateFromID(decoder_id);
|
||||
|
||||
QString frame_filename;
|
||||
|
||||
if (stream_data.video_type() == Stream::kVideoTypeImageSequence) {
|
||||
int64_t frame_number = stream.GetTimeInTimebaseUnits(input_time);
|
||||
if (stream_data.video_type() == VideoParams::kVideoTypeImageSequence) {
|
||||
int64_t frame_number = stream_data.get_time_in_timebase_units(input_time);
|
||||
frame_filename = Decoder::TransformImageSequenceFileName(stream.filename(), frame_number);
|
||||
} else {
|
||||
frame_filename = stream.filename();
|
||||
}
|
||||
|
||||
// Decoder will close automatically since it's a stream_ptr
|
||||
decoder->Open(Decoder::CodecStream(frame_filename, stream.index()));
|
||||
decoder->Open(Decoder::CodecStream(frame_filename, stream_data.stream_index()));
|
||||
}
|
||||
|
||||
if (decoder) {
|
||||
FramePtr frame = decoder->RetrieveVideo((stream_data.video_type() == Stream::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode, footage_divider);
|
||||
FramePtr frame = decoder->RetrieveVideo((stream_data.video_type() == VideoParams::kVideoTypeVideo) ? input_time : Decoder::kAnyTimecode, footage_divider);
|
||||
|
||||
if (frame) {
|
||||
// Return a texture from the derived class
|
||||
@@ -368,7 +375,7 @@ QVariant RenderProcessor::ProcessVideoFootage(const Footage::StreamReference &st
|
||||
value = render_ctx_->CreateTexture(managed_params);
|
||||
|
||||
ColorProcessorPtr processor = ColorProcessor::Create(color_manager,
|
||||
stream.video_colorspace(),
|
||||
using_colorspace,
|
||||
color_manager->GetReferenceColorSpace());
|
||||
|
||||
render_ctx_->BlitColorManaged(processor, unmanaged_texture,
|
||||
@@ -391,17 +398,17 @@ QVariant RenderProcessor::ProcessVideoFootage(const Footage::StreamReference &st
|
||||
return QVariant::fromValue(value);
|
||||
}
|
||||
|
||||
QVariant RenderProcessor::ProcessAudioFootage(const Footage::StreamReference &stream, const TimeRange &input_time)
|
||||
QVariant RenderProcessor::ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time)
|
||||
{
|
||||
QVariant value;
|
||||
|
||||
DecoderPtr decoder = ResolveDecoderFromInput(stream.footage()->decoder(), Decoder::GetCodecStreamFromStreamReference(stream));
|
||||
DecoderPtr decoder = ResolveDecoderFromInput(stream.decoder(), Decoder::CodecStream(stream.filename(), stream.audio_params().stream_index()));
|
||||
|
||||
if (decoder) {
|
||||
const AudioParams& audio_params = ticket_->property("aparam").value<AudioParams>();
|
||||
|
||||
SampleBufferPtr frame = decoder->RetrieveAudio(input_time, audio_params,
|
||||
stream.footage()->project()->cache_path(),
|
||||
stream.cache_path(),
|
||||
&IsCancelled());
|
||||
|
||||
if (frame) {
|
||||
|
||||
@@ -43,9 +43,9 @@ public:
|
||||
protected:
|
||||
virtual NodeValueTable GenerateBlockTable(const Track *track, const TimeRange &range) override;
|
||||
|
||||
virtual QVariant ProcessVideoFootage(const Footage::StreamReference &stream, const rational &input_time) override;
|
||||
virtual QVariant ProcessVideoFootage(const FootageJob &stream, const rational &input_time) override;
|
||||
|
||||
virtual QVariant ProcessAudioFootage(const Footage::StreamReference &stream, const TimeRange &input_time) override;
|
||||
virtual QVariant ProcessAudioFootage(const FootageJob &stream, const TimeRange &input_time) override;
|
||||
|
||||
virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <QHash>
|
||||
#include <QWaitCondition>
|
||||
|
||||
#include "codec/decoder.h"
|
||||
#include "common/rational.h"
|
||||
#include "project/item/footage/footage.h"
|
||||
#include "render/texture.h"
|
||||
@@ -14,7 +15,7 @@ class StillImageCache
|
||||
{
|
||||
public:
|
||||
struct Entry {
|
||||
Entry(TexturePtr t, const Footage::StreamReference& s, const QString& cs, bool a, int d, const rational& i, bool w)
|
||||
Entry(TexturePtr t, const Decoder::CodecStream& s, const QString& cs, bool a, int d, const rational& i, bool w)
|
||||
{
|
||||
texture = t;
|
||||
stream = s;
|
||||
@@ -26,7 +27,7 @@ public:
|
||||
}
|
||||
|
||||
TexturePtr texture;
|
||||
Footage::StreamReference stream;
|
||||
Decoder::CodecStream stream;
|
||||
QString colorspace;
|
||||
bool alpha_is_associated;
|
||||
int divider;
|
||||
|
||||
+114
-1
@@ -67,8 +67,10 @@ VideoParams::VideoParams() :
|
||||
depth_(0),
|
||||
format_(kFormatInvalid),
|
||||
channel_count_(0),
|
||||
interlacing_(Interlacing::kInterlaceNone)
|
||||
interlacing_(Interlacing::kInterlaceNone),
|
||||
divider_(1)
|
||||
{
|
||||
set_defaults_for_footage();
|
||||
}
|
||||
|
||||
VideoParams::VideoParams(int width, int height, Format format, int nb_channels, const rational& pixel_aspect_ratio, Interlacing interlacing, int divider) :
|
||||
@@ -83,6 +85,7 @@ VideoParams::VideoParams(int width, int height, Format format, int nb_channels,
|
||||
{
|
||||
calculate_effective_size();
|
||||
validate_pixel_aspect_ratio();
|
||||
set_defaults_for_footage();
|
||||
}
|
||||
|
||||
VideoParams::VideoParams(int width, int height, int depth, Format format, int nb_channels, const rational &pixel_aspect_ratio, VideoParams::Interlacing interlacing, int divider) :
|
||||
@@ -97,6 +100,7 @@ VideoParams::VideoParams(int width, int height, int depth, Format format, int nb
|
||||
{
|
||||
calculate_effective_size();
|
||||
validate_pixel_aspect_ratio();
|
||||
set_defaults_for_footage();
|
||||
}
|
||||
|
||||
VideoParams::VideoParams(int width, int height, const rational &time_base, Format format, int nb_channels, const rational& pixel_aspect_ratio, Interlacing interlacing, int divider) :
|
||||
@@ -112,6 +116,7 @@ VideoParams::VideoParams(int width, int height, const rational &time_base, Forma
|
||||
{
|
||||
calculate_effective_size();
|
||||
validate_pixel_aspect_ratio();
|
||||
set_defaults_for_footage();
|
||||
}
|
||||
|
||||
int VideoParams::generate_auto_divider(qint64 width, qint64 height)
|
||||
@@ -237,6 +242,16 @@ void VideoParams::validate_pixel_aspect_ratio()
|
||||
}
|
||||
}
|
||||
|
||||
void VideoParams::set_defaults_for_footage()
|
||||
{
|
||||
enabled_ = true;
|
||||
stream_index_ = 0;
|
||||
video_type_ = kVideoTypeVideo;
|
||||
start_time_ = 0;
|
||||
duration_ = 0;
|
||||
premultiplied_alpha_ = false;
|
||||
}
|
||||
|
||||
bool VideoParams::is_valid() const
|
||||
{
|
||||
return (width() > 0
|
||||
@@ -280,4 +295,102 @@ int VideoParams::GetScaledDimension(int dim, int divider)
|
||||
return dim / divider;
|
||||
}
|
||||
|
||||
QByteArray VideoParams::toBytes() const
|
||||
{
|
||||
QCryptographicHash hasher(QCryptographicHash::Sha1);
|
||||
|
||||
hasher.addData(reinterpret_cast<const char*>(&width_), sizeof(width_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&height_), sizeof(height_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&depth_), sizeof(depth_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&time_base_), sizeof(time_base_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&format_), sizeof(format_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&channel_count_), sizeof(channel_count_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&pixel_aspect_ratio_), sizeof(pixel_aspect_ratio_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&interlacing_), sizeof(interlacing_));
|
||||
hasher.addData(reinterpret_cast<const char*>(÷r_), sizeof(divider_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&enabled_), sizeof(enabled_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&stream_index_), sizeof(stream_index_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&video_type_), sizeof(video_type_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&frame_rate_), sizeof(frame_rate_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&start_time_), sizeof(start_time_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&duration_), sizeof(duration_));
|
||||
hasher.addData(reinterpret_cast<const char*>(&premultiplied_alpha_), sizeof(premultiplied_alpha_));
|
||||
hasher.addData(colorspace_.toUtf8());
|
||||
|
||||
return hasher.result();
|
||||
}
|
||||
|
||||
int64_t VideoParams::get_time_in_timebase_units(const rational &time) const
|
||||
{
|
||||
if (time_base_.isNull()) {
|
||||
return AV_NOPTS_VALUE;
|
||||
}
|
||||
|
||||
return Timecode::time_to_timestamp(time, time_base_) + start_time_;
|
||||
}
|
||||
|
||||
void VideoParams::Load(QXmlStreamReader *reader)
|
||||
{
|
||||
while (XMLReadNextStartElement(reader)) {
|
||||
if (reader->name() == QStringLiteral("width")) {
|
||||
set_width(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("height")) {
|
||||
set_height(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("depth")) {
|
||||
set_depth(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("timebase")) {
|
||||
set_time_base(rational::fromString(reader->readElementText()));
|
||||
} else if (reader->name() == QStringLiteral("format")) {
|
||||
set_format(static_cast<VideoParams::Format>(reader->readElementText().toInt()));
|
||||
} else if (reader->name() == QStringLiteral("channelcount")) {
|
||||
set_channel_count(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("pixelaspectratio")) {
|
||||
set_pixel_aspect_ratio(rational::fromString(reader->readElementText()));
|
||||
} else if (reader->name() == QStringLiteral("interlacing")) {
|
||||
set_interlacing(static_cast<VideoParams::Interlacing>(reader->readElementText().toInt()));
|
||||
} else if (reader->name() == QStringLiteral("divider")) {
|
||||
set_divider(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("enabled")) {
|
||||
set_enabled(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("streamindex")) {
|
||||
set_stream_index(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("videotype")) {
|
||||
set_video_type(static_cast<VideoParams::Type>(reader->readElementText().toInt()));
|
||||
} else if (reader->name() == QStringLiteral("framerate")) {
|
||||
set_frame_rate(rational::fromString(reader->readElementText()));
|
||||
} else if (reader->name() == QStringLiteral("starttime")) {
|
||||
set_start_time(reader->readElementText().toLongLong());
|
||||
} else if (reader->name() == QStringLiteral("duration")) {
|
||||
set_duration(reader->readElementText().toLongLong());
|
||||
} else if (reader->name() == QStringLiteral("premultipliedalpha")) {
|
||||
set_premultiplied_alpha(reader->readElementText().toInt());
|
||||
} else if (reader->name() == QStringLiteral("colorspace")) {
|
||||
set_colorspace(reader->readElementText());
|
||||
} else {
|
||||
reader->skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoParams::Save(QXmlStreamWriter *writer) const
|
||||
{
|
||||
writer->writeTextElement(QStringLiteral("width"), QString::number(width_));
|
||||
writer->writeTextElement(QStringLiteral("height"), QString::number(height_));
|
||||
writer->writeTextElement(QStringLiteral("depth"), QString::number(depth_));
|
||||
writer->writeTextElement(QStringLiteral("timebase"), time_base_.toString());
|
||||
writer->writeTextElement(QStringLiteral("format"), QString::number(format_));
|
||||
writer->writeTextElement(QStringLiteral("channelcount"), QString::number(channel_count_));
|
||||
writer->writeTextElement(QStringLiteral("pixelaspectratio"), pixel_aspect_ratio_.toString());
|
||||
writer->writeTextElement(QStringLiteral("interlacing"), QString::number(interlacing_));
|
||||
writer->writeTextElement(QStringLiteral("divider"), QString::number(divider_));
|
||||
writer->writeTextElement(QStringLiteral("enabled"), QString::number(enabled_));
|
||||
writer->writeTextElement(QStringLiteral("streamindex"), QString::number(stream_index_));
|
||||
writer->writeTextElement(QStringLiteral("videotype"), QString::number(video_type_));
|
||||
writer->writeTextElement(QStringLiteral("framerate"), frame_rate_.toString());
|
||||
writer->writeTextElement(QStringLiteral("starttime"), QString::number(start_time_));
|
||||
writer->writeTextElement(QStringLiteral("duration"), QString::number(duration_));
|
||||
writer->writeTextElement(QStringLiteral("premultipliedalpha"), QString::number(premultiplied_alpha_));
|
||||
writer->writeTextElement(QStringLiteral("colorspace"), colorspace_);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
#ifndef VIDEOPARAMS_H
|
||||
#define VIDEOPARAMS_H
|
||||
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "rendermodes.h"
|
||||
|
||||
@@ -57,6 +60,12 @@ public:
|
||||
kInterlacedBottomFirst
|
||||
};
|
||||
|
||||
enum Type {
|
||||
kVideoTypeVideo,
|
||||
kVideoTypeStill,
|
||||
kVideoTypeImageSequence
|
||||
};
|
||||
|
||||
VideoParams();
|
||||
VideoParams(int width, int height, Format format, int nb_channels,
|
||||
const rational& pixel_aspect_ratio = 1,
|
||||
@@ -239,11 +248,101 @@ public:
|
||||
|
||||
static int GetScaledDimension(int dim, int divider);
|
||||
|
||||
QByteArray toBytes() const;
|
||||
|
||||
bool enabled() const
|
||||
{
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
void set_enabled(bool e)
|
||||
{
|
||||
enabled_ = e;
|
||||
}
|
||||
|
||||
int stream_index() const
|
||||
{
|
||||
return stream_index_;
|
||||
}
|
||||
|
||||
void set_stream_index(int s)
|
||||
{
|
||||
stream_index_ = s;
|
||||
}
|
||||
|
||||
Type video_type() const
|
||||
{
|
||||
return video_type_;
|
||||
}
|
||||
|
||||
void set_video_type(Type t)
|
||||
{
|
||||
video_type_ = t;
|
||||
}
|
||||
|
||||
const rational& frame_rate() const
|
||||
{
|
||||
return frame_rate_;
|
||||
}
|
||||
|
||||
void set_frame_rate(const rational& frame_rate)
|
||||
{
|
||||
frame_rate_ = frame_rate;
|
||||
}
|
||||
|
||||
int64_t start_time() const
|
||||
{
|
||||
return start_time_;
|
||||
}
|
||||
|
||||
void set_start_time(int64_t start_time)
|
||||
{
|
||||
start_time_ = start_time;
|
||||
}
|
||||
|
||||
int64_t duration() const
|
||||
{
|
||||
return duration_;
|
||||
}
|
||||
|
||||
void set_duration(int64_t duration)
|
||||
{
|
||||
duration_ = duration;
|
||||
}
|
||||
|
||||
bool premultiplied_alpha() const
|
||||
{
|
||||
return premultiplied_alpha_;
|
||||
}
|
||||
|
||||
void set_premultiplied_alpha(bool premultiplied_alpha)
|
||||
{
|
||||
premultiplied_alpha_ = premultiplied_alpha;
|
||||
}
|
||||
|
||||
const QString& colorspace() const
|
||||
{
|
||||
return colorspace_;
|
||||
}
|
||||
|
||||
void set_colorspace(const QString& c)
|
||||
{
|
||||
colorspace_ = c;
|
||||
}
|
||||
|
||||
int64_t get_time_in_timebase_units(const rational& time) const;
|
||||
|
||||
void Load(QXmlStreamReader* reader);
|
||||
|
||||
void Save(QXmlStreamWriter* writer) const;
|
||||
|
||||
private:
|
||||
void calculate_effective_size();
|
||||
|
||||
void validate_pixel_aspect_ratio();
|
||||
|
||||
void set_defaults_for_footage();
|
||||
|
||||
int width_;
|
||||
int height_;
|
||||
int depth_;
|
||||
@@ -258,9 +357,21 @@ private:
|
||||
Interlacing interlacing_;
|
||||
|
||||
int divider_;
|
||||
|
||||
// Cached values
|
||||
int effective_width_;
|
||||
int effective_height_;
|
||||
int effective_depth_;
|
||||
|
||||
bool enabled_;
|
||||
int stream_index_;
|
||||
Type video_type_;
|
||||
rational frame_rate_;
|
||||
int64_t start_time_;
|
||||
int64_t duration_;
|
||||
bool premultiplied_alpha_;
|
||||
QString colorspace_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user