This commit is contained in:
Aiden
2026-05-12 01:21:42 +10:00
parent f1f4e3421b
commit ea31d0ca13
8 changed files with 527 additions and 35 deletions

View File

@@ -110,19 +110,42 @@ bool VideoBackend::ConfigureOutput(const VideoFormat& outputVideoMode, bool exte
bool VideoBackend::Start()
{
ApplyLifecycleTransition(VideoBackendLifecycleState::Prerolling, "Video backend preroll starting.");
if (!mVideoIODevice->PrepareOutputSchedule())
{
ApplyLifecycleFailure(StatusMessage().empty() ? "Video backend output schedule preparation failed." : StatusMessage());
return false;
}
StartOutputCompletionWorker();
const bool started = mVideoIODevice->Start();
if (started)
{
StartOutputProducerWorker();
ApplyLifecycleTransition(VideoBackendLifecycleState::Running, "Video backend started.");
}
else
StartOutputProducerWorker();
if (!WarmupOutputPreroll())
{
StopOutputProducerWorker();
StopOutputCompletionWorker();
ApplyLifecycleFailure(StatusMessage().empty() ? "Video backend start failed." : StatusMessage());
ApplyLifecycleFailure(StatusMessage().empty() ? "Video backend preroll warmup failed." : StatusMessage());
return false;
}
return started;
if (!mVideoIODevice->StartInputStreams())
{
StopOutputProducerWorker();
StopOutputCompletionWorker();
ApplyLifecycleFailure(StatusMessage().empty() ? "Video backend input stream start failed." : StatusMessage());
return false;
}
if (!mVideoIODevice->StartScheduledPlayback())
{
StopOutputProducerWorker();
mVideoIODevice->Stop();
StopOutputCompletionWorker();
ApplyLifecycleFailure(StatusMessage().empty() ? "Video backend scheduled playback start failed." : StatusMessage());
return false;
}
ApplyLifecycleTransition(VideoBackendLifecycleState::Running, "Video backend started.");
return true;
}
bool VideoBackend::Stop()
@@ -393,6 +416,39 @@ void VideoBackend::NotifyOutputProducer()
mOutputProducerCondition.notify_one();
}
bool VideoBackend::WarmupOutputPreroll()
{
const VideoPlayoutPolicy policy = NormalizeVideoPlayoutPolicy(mPlayoutPolicy);
const std::size_t targetPrerollFrames = static_cast<std::size_t>(policy.targetPrerollFrames);
if (targetPrerollFrames == 0)
return true;
const double frameBudgetMilliseconds = State().frameBudgetMilliseconds > 0.0 ? State().frameBudgetMilliseconds : 16.0;
const auto estimatedCadenceTime = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::duration<double, std::milli>(frameBudgetMilliseconds * static_cast<double>(targetPrerollFrames + 2)));
const auto timeout = (std::max)(std::chrono::milliseconds(1000), estimatedCadenceTime + std::chrono::milliseconds(500));
const auto deadline = std::chrono::steady_clock::now() + timeout;
while (std::chrono::steady_clock::now() < deadline)
{
ScheduleReadyOutputFramesToTarget();
const SystemOutputFramePoolMetrics metrics = mSystemOutputFramePool.GetMetrics();
RecordSystemMemoryPlayoutStats();
if (metrics.scheduledCount >= targetPrerollFrames)
return true;
NotifyOutputProducer();
const auto waitDuration = (std::min)(OutputProducerWakeInterval(), std::chrono::milliseconds(5));
std::unique_lock<std::mutex> lock(mOutputProducerMutex);
mOutputProducerCondition.wait_for(lock, waitDuration);
if (mOutputProducerWorkerStopping)
return false;
}
SetStatusMessage("Timed out warming up DeckLink preroll from rendered system-memory frames.");
return false;
}
void VideoBackend::OutputCompletionWorkerMain()
{
for (;;)