Merge branch 'master' into hashremoval

This commit is contained in:
itsmattkc
2022-06-01 10:06:33 -07:00
16 changed files with 123 additions and 77 deletions
+1 -1
View File
@@ -335,7 +335,7 @@ void Decoder::UpdateLastAccessed()
uint qHash(Decoder::CodecStream stream, uint seed)
{
return qHash(stream.filename(), seed) ^ qHash(stream.stream(), seed);
return qHash(stream.filename(), seed) ^ qHash(stream.stream(), seed) ^ qHash(stream.block(), seed);
}
}
+13 -3
View File
@@ -34,6 +34,7 @@ extern "C" {
#include "codec/frame.h"
#include "codec/samplebuffer.h"
#include "common/rational.h"
#include "node/block/block.h"
#include "node/project/footage/footage.h"
#include "node/project/footage/footagedescription.h"
#include "task/task.h"
@@ -85,13 +86,15 @@ public:
{
public:
CodecStream() :
stream_(-1)
stream_(-1),
block_(nullptr)
{
}
CodecStream(const QString& filename, int stream) :
CodecStream(const QString& filename, int stream, Block *block) :
filename_(filename),
stream_(stream)
stream_(stream),
block_(block)
{
}
@@ -125,11 +128,18 @@ public:
return stream_;
}
Block *block() const
{
return block_;
}
private:
QString filename_;
int stream_;
Block *block_;
};
/**
+7 -3
View File
@@ -62,7 +62,6 @@ FFmpegDecoder::FFmpegDecoder() :
native_output_pix_fmt_(VideoParams::kFormatInvalid),
working_frame_(nullptr),
working_packet_(nullptr),
is_working_(false),
cache_at_zero_(false),
cache_at_eof_(false)
{
@@ -749,7 +748,7 @@ AVFramePtr FFmpegDecoder::RetrieveFrame(const rational& time, const QAtomicInt *
int64_t target_ts = GetTimeInTimebaseUnits(time, instance_.avstream()->time_base, instance_.avstream()->start_time);
const int64_t min_seek = -instance_.avstream()->start_time;
int64_t seek_ts = target_ts;
int64_t seek_ts = std::max(min_seek, target_ts - MaximumQueueSize());
bool still_seeking = false;
if (time != kAnyTimecode) {
@@ -838,7 +837,7 @@ AVFramePtr FFmpegDecoder::RetrieveFrame(const rational& time, const QAtomicInt *
} else {
// Cut down to thread count - 1 before we acquire a new frame
if (cached_frames_.size() == size_t(QThread::idealThreadCount())) {
if (cached_frames_.size() == size_t(MaximumQueueSize())) {
RemoveFirstFrame();
}
@@ -1039,6 +1038,11 @@ void FFmpegDecoder::RemoveFirstFrame()
cache_at_zero_ = false;
}
int FFmpegDecoder::MaximumQueueSize()
{
return QThread::idealThreadCount();
}
FFmpegDecoder::Instance::Instance() :
fmt_ctx_(nullptr),
codec_ctx_(nullptr),
+2 -3
View File
@@ -155,6 +155,8 @@ private:
void RemoveFirstFrame();
static int MaximumQueueSize();
RetrieveVideoParams filter_params_;
AVFilterGraph* filter_graph_;
AVFilterContext* buffersrc_ctx_;
@@ -171,9 +173,6 @@ private:
std::list<AVFramePtr> cached_frames_;
bool is_working_;
QMutex is_working_mutex_;
bool cache_at_zero_;
bool cache_at_eof_;
+2
View File
@@ -350,7 +350,9 @@ NodeValueTable NodeTraverser::GenerateBlockTable(const Track *track, const TimeR
NodeValueTable table;
if (active_block) {
block_stack_.push_back(active_block);
table = GenerateTable(active_block, Track::TransformRangeForBlock(active_block, range), track);
block_stack_.pop_back();
}
return table;
+7
View File
@@ -146,6 +146,11 @@ protected:
void ResolveJobs(NodeValue &value, const TimeRange &range);
Block *GetCurrentBlock() const
{
return block_stack_.empty() ? nullptr : block_stack_.back();
}
private:
void PreProcessRow(const TimeRange &range, NodeValueRow &row);
@@ -162,6 +167,8 @@ private:
const Node *transform_now_;
QTransform *transform_;
std::list<Block*> block_stack_;
};
}
+4 -9
View File
@@ -39,15 +39,10 @@ private:
};
struct DecoderPair {
DecoderPair()
{
decoder = nullptr;
last_modified = 0;
}
DecoderPtr decoder;
qint64 last_modified;
struct DecoderPair
{
DecoderPtr decoder = nullptr;
qint64 last_modified = 0;
};
using DecoderCache = RenderCache<Decoder::CodecStream, DecoderPair>;
+13
View File
@@ -72,8 +72,21 @@ TexturePtr Renderer::InterlaceTexture(TexturePtr top, TexturePtr bottom, const V
return output;
}
QVariant Renderer::GetDefaultShader()
{
if (default_shader_.isNull()) {
default_shader_ = CreateNativeShader(ShaderCode(QString(), QString()));
}
return default_shader_;
}
void Renderer::Destroy()
{
if (!default_shader_.isNull()) {
DestroyNativeShader(default_shader_);
}
color_cache_.clear();
if (!interlace_texture_.isNull()) {
+4
View File
@@ -76,6 +76,8 @@ public:
TexturePtr InterlaceTexture(TexturePtr top, TexturePtr bottom, const VideoParams &params);
QVariant GetDefaultShader();
void Destroy();
virtual void PostDestroy() = 0;
@@ -134,6 +136,8 @@ private:
QMutex color_cache_mutex_;
QVariant default_shader_;
QVariant interlace_texture_;
};
+1 -4
View File
@@ -54,7 +54,6 @@ RenderManager::RenderManager(QObject *parent) :
decoder_cache_ = new DecoderCache();
shader_cache_ = new ShaderCache();
default_shader_ = context_->CreateNativeShader(ShaderCode(QString(), QString()));
} else {
qCritical() << "Tried to initialize unknown graphics backend";
context_ = nullptr;
@@ -65,8 +64,6 @@ RenderManager::RenderManager(QObject *parent) :
RenderManager::~RenderManager()
{
if (context_) {
context_->DestroyNativeShader(default_shader_);
delete shader_cache_;
delete decoder_cache_;
@@ -130,7 +127,7 @@ void RenderManager::RunTicket(RenderTicketPtr ticket) const
return;
}
RenderProcessor::Process(ticket, context_, decoder_cache_, shader_cache_, default_shader_);
RenderProcessor::Process(ticket, context_, decoder_cache_, shader_cache_);
}
}
-2
View File
@@ -183,8 +183,6 @@ private:
ShaderCache* shader_cache_;
QVariant default_shader_;
};
}
+11 -12
View File
@@ -35,12 +35,11 @@ namespace olive {
#define super NodeTraverser
RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, DecoderCache* decoder_cache, ShaderCache *shader_cache, QVariant default_shader) :
RenderProcessor::RenderProcessor(RenderTicketPtr ticket, Renderer *render_ctx, DecoderCache* decoder_cache, ShaderCache *shader_cache) :
ticket_(ticket),
render_ctx_(render_ctx),
decoder_cache_(decoder_cache),
shader_cache_(shader_cache),
default_shader_(default_shader)
shader_cache_(shader_cache)
{
}
@@ -116,7 +115,7 @@ FramePtr RenderProcessor::GenerateFrame(TexturePtr texture, const rational& time
job.Insert(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(texture)));
job.Insert(QStringLiteral("ove_mvpmat"), NodeValue(NodeValue::kMatrix, matrix));
render_ctx_->BlitToTexture(default_shader_, job, blit_tex.get());
render_ctx_->BlitToTexture(render_ctx_->GetDefaultShader(), job, blit_tex.get());
// Replace texture that we're going to download in the next step
texture = blit_tex;
@@ -258,10 +257,10 @@ DecoderPtr RenderProcessor::ResolveDecoderFromInput(const QString& decoder_id, c
// No decoder
decoder.decoder = Decoder::CreateFromID(decoder_id);
decoder.last_modified = file_last_modified;
decoder_cache_->insert(stream, decoder);
locker.unlock();
if (decoder.decoder->Open(stream)) {
decoder_cache_->insert(stream, decoder);
} else {
if (!decoder.decoder->Open(stream)) {
qWarning() << "Failed to open decoder for" << stream.filename()
<< "::" << stream.stream();
return nullptr;
@@ -271,9 +270,9 @@ DecoderPtr RenderProcessor::ResolveDecoderFromInput(const QString& decoder_id, c
return decoder.decoder;
}
void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx, DecoderCache *decoder_cache, ShaderCache *shader_cache, QVariant default_shader)
void RenderProcessor::Process(RenderTicketPtr ticket, Renderer *render_ctx, DecoderCache *decoder_cache, ShaderCache *shader_cache)
{
RenderProcessor p(ticket, render_ctx, decoder_cache, shader_cache, default_shader);
RenderProcessor p(ticket, render_ctx, decoder_cache, shader_cache);
p.Run();
}
@@ -404,7 +403,7 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ
qWarning() << "HAVEN'T GOTTEN DEFAULT INPUT COLORSPACE";
}
Decoder::CodecStream default_codec_stream(stream.filename(), stream_data.stream_index());
Decoder::CodecStream default_codec_stream(stream.filename(), stream_data.stream_index(), GetCurrentBlock());
QString decoder_id = stream.decoder();
@@ -426,7 +425,7 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ
frame_filename = Decoder::TransformImageSequenceFileName(stream.filename(), frame_number);
// Decoder will close automatically since it's a stream_ptr
decoder->Open(Decoder::CodecStream(frame_filename, stream_data.stream_index()));
decoder->Open(Decoder::CodecStream(frame_filename, stream_data.stream_index(), GetCurrentBlock()));
break;
}
}
@@ -472,7 +471,7 @@ void RenderProcessor::ProcessVideoFootage(TexturePtr destination, const FootageJ
void RenderProcessor::ProcessAudioFootage(SampleBuffer &destination, const FootageJob &stream, const TimeRange &input_time)
{
DecoderPtr decoder = ResolveDecoderFromInput(stream.decoder(), Decoder::CodecStream(stream.filename(), stream.audio_params().stream_index()));
DecoderPtr decoder = ResolveDecoderFromInput(stream.decoder(), Decoder::CodecStream(stream.filename(), stream.audio_params().stream_index(), nullptr));
if (decoder) {
const AudioParams& audio_params = GetCacheAudioParams();
+2 -4
View File
@@ -32,7 +32,7 @@ namespace olive {
class RenderProcessor : public NodeTraverser
{
public:
static void Process(RenderTicketPtr ticket, Renderer* render_ctx, DecoderCache* decoder_cache, ShaderCache* shader_cache, QVariant default_shader);
static void Process(RenderTicketPtr ticket, Renderer* render_ctx, DecoderCache* decoder_cache, ShaderCache* shader_cache);
struct RenderedWaveform {
const ClipBlock* block;
@@ -69,7 +69,7 @@ protected:
virtual void ConvertToReferenceSpace(TexturePtr destination, TexturePtr source, const QString &input_cs) override;
private:
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, DecoderCache* decoder_cache, ShaderCache* shader_cache, QVariant default_shader);
RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, DecoderCache* decoder_cache, ShaderCache* shader_cache);
TexturePtr GenerateTexture(const rational& time, const rational& frame_length);
@@ -87,8 +87,6 @@ private:
ShaderCache* shader_cache_;
QVariant default_shader_;
};
}
+36 -19
View File
@@ -29,52 +29,67 @@ ThreadPool::ThreadPool(unsigned threads, QObject *parent) :
threads = std::thread::hardware_concurrency();
}
available_count_ = threads;
for (unsigned i = 0; i < threads; i += 1) {
worker_threads_.emplace_back(std::bind(&ThreadPool::thread_exec, this));
worker_threads_.emplace_back(std::bind(&ThreadPool::thread_exec, this, &tasks_, &task_mutex_, &cond_));
}
// Make single reserved thread for high priority tasks (usually audio) so they don't get stuck
// behind a lot of slow tasks
high_thread_ = std::thread(std::thread(std::bind(&ThreadPool::thread_exec, this, &high_tasks_, &high_mutex_, &high_cond_)));
}
void ThreadPool::AddTicket(RenderTicketPtr ticket, RenderTicketPriority priority)
{
std::lock_guard<std::mutex> lock(task_mutex_);
if (priority == RenderTicketPriority::kHigh) {
tasks_.emplace_front(std::move(ticket));
std::lock_guard<std::mutex> lock(high_mutex_);
high_tasks_.emplace_back(std::move(ticket));
high_cond_.notify_one();
} else {
std::lock_guard<std::mutex> lock(task_mutex_);
tasks_.emplace_back(std::move(ticket));
cond_.notify_one();
}
cond_.notify_one();
}
bool ThreadPool::RemoveTicket(RenderTicketPtr ticket)
{
std::lock_guard<std::mutex> lock(task_mutex_);
const auto it = std::find(tasks_.begin(), tasks_.end(), ticket);
if (it == tasks_.end()) {
return false;
{
std::lock_guard<std::mutex> lock(task_mutex_);
const auto it = std::find(tasks_.begin(), tasks_.end(), ticket);
if (it != tasks_.end()) {
tasks_.erase(it);
return true;
}
}
tasks_.erase(it);
return true;
{
std::lock_guard<std::mutex> lock(high_mutex_);
const auto it = std::find(high_tasks_.begin(), high_tasks_.end(), ticket);
if (it != high_tasks_.end()) {
high_tasks_.erase(it);
return true;
}
}
return false;
}
void ThreadPool::thread_exec()
void ThreadPool::thread_exec(std::deque<TaskType> *queue, std::mutex *mutex, std::condition_variable *cond)
{
while (true) {
TaskType task;
{
std::unique_lock<std::mutex> lock(task_mutex_);
cond_.wait(lock, [this]{ return this->end_threadp_ || !this->tasks_.empty(); });
std::unique_lock<std::mutex> lock(*mutex);
cond->wait(lock, [this, queue]{ return this->end_threadp_ || !queue->empty(); });
if (this->end_threadp_ && this->tasks_.empty()) {
if (this->end_threadp_ && queue->empty()) {
break;
}
task = std::move(tasks_.front());
tasks_.pop_front();
task = std::move(queue->front());
queue->pop_front();
}
RunTicket(task);
@@ -85,10 +100,12 @@ ThreadPool::~ThreadPool()
{
end_threadp_ = true;
cond_.notify_all();
high_cond_.notify_all();
for (auto &e : worker_threads_) {
e.join();
}
high_thread_.join();
}
}
+8 -1
View File
@@ -49,13 +49,20 @@ public:
virtual ~ThreadPool() override;
private:
void thread_exec();
void thread_exec(std::deque<TaskType> *queue, std::mutex *mutex, std::condition_variable *cond);
std::vector<std::thread> worker_threads_;
std::deque<TaskType> tasks_;
std::mutex task_mutex_;
std::condition_variable cond_;
std::thread high_thread_;
std::deque<TaskType> high_tasks_;
std::mutex high_mutex_;
std::condition_variable high_cond_;
std::atomic_bool end_threadp_{false};
std::atomic_int available_count_;
};
+12 -16
View File
@@ -702,7 +702,10 @@ void ViewerWidget::UpdateTextureFromNode()
connect(watcher, &RenderTicketWatcher::Finished, this, &ViewerWidget::RendererGeneratedFrame);
nonqueue_watchers_.append(watcher);
watcher->SetTicket(GetFrame(time, RenderTicketPriority::kHigh));
// Clear queue because we want this frame more than any others
auto_cacher_->ClearSingleFrameRenders();
watcher->SetTicket(GetFrame(time, RenderTicketPriority::kNormal));
} else {
// There is definitely no frame here, we can immediately flip to showing nothing
nonqueue_watchers_.clear();
@@ -753,7 +756,7 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
playback_speed_ = speed;
play_in_to_out_only_ = in_to_out_only;
playback_queue_next_frame_ = GetTimestamp();
playback_queue_next_frame_ = GetTimestamp() + playback_speed_;
controls_->ShowPauseButton();
@@ -767,18 +770,10 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
prequeuing_video_ = true;
prequeue_count_ = 0;
// We "prioritize" the frames, which means they're pushed to the top of the render queue,
// we queue in reverse so that they're still queued in order
playback_queue_next_frame_ += playback_speed_ * prequeue_length_;
int64_t temp = playback_queue_next_frame_;
for (int i=0; i<prequeue_length_; i++) {
playback_queue_next_frame_ -= playback_speed_;
RequestNextFrameForQueue(RenderTicketPriority::kHigh, false);
RequestNextFrameForQueue(RenderTicketPriority::kNormal, false);
playback_queue_next_frame_ += playback_speed_;
}
playback_queue_next_frame_ = temp;
}
}
@@ -1484,10 +1479,11 @@ void ViewerWidget::PlaybackTimerUpdate()
}
if (IsPlaying()) {
int count = 0;
for (int i=display_widget_->queue()->size(); i<DeterminePlaybackQueueSize(); i++) {
RequestNextFrameForQueue();
count++;
while (queue_watchers_.size() < DeterminePlaybackQueueSize()) {
if (!RequestNextFrameForQueue()) {
// Prevent infinite loop
break;
}
}
}