Fix OCIO LUT async processor black screen and freeze
- Pass through input texture when the LUT processor is not ready yet, preventing black frames while the processor is being generated. - Serialize processor generation with a single in-flight task to avoid concurrent OCIO lock contention that could freeze the UI. - Invalidate cached frames after the async processor is set so the viewer refreshes automatically without requiring the playhead to be moved. - Add OAK_DISABLE_HWACCEL environment variable to force software decoding. - Add FFmpegDecoderHW regression test for H.264 4:2:2 10-bit decoding.
This commit is contained in:
@@ -425,13 +425,17 @@ TexturePtr FFmpegDecoder::RetrieveVideoInternal(const RetrieveVideoParams &p)
|
||||
AVFramePtr ptr = PreProcessFrame(f, p);
|
||||
f=std::move(ptr);
|
||||
if (!f) {
|
||||
// Error occurred while software scaling
|
||||
qWarning() << "PreProcessFrame failed";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Finally, perform any GPU processing required
|
||||
TexturePtr texture = ProcessFrameIntoTexture(f, p, original);
|
||||
|
||||
if (!texture) {
|
||||
qWarning() << "ProcessFrameIntoTexture returned null";
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@@ -1476,6 +1480,10 @@ bool FFmpegDecoder::Instance::Open(const char *filename, int stream_index)
|
||||
|
||||
AVHWDeviceType FFmpegDecoder::Instance::ChooseHardwareDevice()
|
||||
{
|
||||
if (qEnvironmentVariableIsSet("OAK_DISABLE_HWACCEL")) {
|
||||
return AV_HWDEVICE_TYPE_NONE;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
// Prefer NVIDIA's NVDEC where available, then VAAPI/VDPAU.
|
||||
for (AVHWDeviceType type : { AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_VAAPI,
|
||||
|
||||
@@ -63,13 +63,19 @@ void OCIOBaseNode::Value(const NodeValueRow &value, const NodeGlobals &globals,
|
||||
{
|
||||
auto tex_met = value[kTextureInput];
|
||||
TexturePtr t = tex_met.toTexture();
|
||||
if (t && processor_) {
|
||||
ColorTransformJob job;
|
||||
if (t) {
|
||||
if (processor_) {
|
||||
ColorTransformJob job;
|
||||
|
||||
job.SetColorProcessor(processor_);
|
||||
job.SetInputTexture(tex_met);
|
||||
job.SetColorProcessor(processor_);
|
||||
job.SetInputTexture(tex_met);
|
||||
|
||||
table->Push(NodeValue::kTexture, t->toJob(job), this);
|
||||
table->Push(NodeValue::kTexture, t->toJob(job), this);
|
||||
} else {
|
||||
// Processor isn't ready yet (e.g. still being generated
|
||||
// asynchronously), pass the input through unchanged.
|
||||
table->Push(NodeValue::kTexture, QVariant::fromValue(t), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -154,10 +154,30 @@ void OCIOLutNode::GenerateProcessor()
|
||||
pending_path_ = path;
|
||||
pending_direction_ = direction;
|
||||
pending_generation_++;
|
||||
const int generation = pending_generation_;
|
||||
ColorManager *manager = this->manager();
|
||||
|
||||
locker.unlock();
|
||||
MaybeStartNextTask();
|
||||
}
|
||||
|
||||
void OCIOLutNode::MaybeStartNextTask()
|
||||
{
|
||||
if (task_running_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pending_path_.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pending_path_ == last_path_ && pending_direction_ == last_direction_ &&
|
||||
last_processor_) {
|
||||
return;
|
||||
}
|
||||
|
||||
task_running_ = true;
|
||||
const int generation = pending_generation_;
|
||||
const QString path = pending_path_;
|
||||
const int direction = pending_direction_;
|
||||
ColorManager *manager = this->manager();
|
||||
|
||||
QThreadPool::globalInstance()->start(
|
||||
new GenerateProcessorTask(this, path, direction, generation, manager));
|
||||
@@ -169,12 +189,16 @@ void OCIOLutNode::SetProcessorResult(ColorProcessorPtr processor,
|
||||
{
|
||||
QMutexLocker locker(&gen_mutex_);
|
||||
|
||||
task_running_ = false;
|
||||
|
||||
if (generation != pending_generation_) {
|
||||
// A newer request was issued while this one was in flight; ignore.
|
||||
// A newer request was issued while this one was in flight; restart.
|
||||
MaybeStartNextTask();
|
||||
return;
|
||||
}
|
||||
|
||||
if (path != pending_path_ || direction != pending_direction_) {
|
||||
MaybeStartNextTask();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -182,6 +206,9 @@ void OCIOLutNode::SetProcessorResult(ColorProcessorPtr processor,
|
||||
last_direction_ = direction;
|
||||
last_processor_ = processor;
|
||||
set_processor(processor);
|
||||
|
||||
// The processor has changed, ensure any cached frames are re-rendered.
|
||||
InvalidateAll(kTextureInput);
|
||||
}
|
||||
|
||||
OCIOLutNode::GenerateProcessorTask::GenerateProcessorTask(
|
||||
|
||||
@@ -80,6 +80,7 @@ private:
|
||||
};
|
||||
|
||||
void GenerateProcessor();
|
||||
void MaybeStartNextTask();
|
||||
|
||||
QMutex gen_mutex_;
|
||||
QString last_path_;
|
||||
@@ -89,6 +90,7 @@ private:
|
||||
QString pending_path_;
|
||||
int pending_direction_ = -1;
|
||||
int pending_generation_ = 0;
|
||||
bool task_running_ = false;
|
||||
};
|
||||
|
||||
} // namespace olive
|
||||
|
||||
Reference in New Issue
Block a user