Clean
This commit is contained in:
@@ -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 (;;)
|
||||
|
||||
@@ -77,6 +77,7 @@ private:
|
||||
void StopOutputProducerWorker();
|
||||
void OutputProducerWorkerMain();
|
||||
void NotifyOutputProducer();
|
||||
bool WarmupOutputPreroll();
|
||||
std::chrono::milliseconds OutputProducerWakeInterval() const;
|
||||
void ProcessOutputFrameCompletion(const VideoIOCompletion& completion);
|
||||
std::size_t ProduceReadyOutputFrames(const VideoIOCompletion& completion, std::size_t maxFrames);
|
||||
|
||||
@@ -116,6 +116,9 @@ public:
|
||||
virtual bool SelectPreferredFormats(const VideoFormatSelection& videoModes, bool outputAlphaRequired, std::string& error) = 0;
|
||||
virtual bool ConfigureInput(InputFrameCallback callback, const VideoFormat& inputVideoMode, std::string& error) = 0;
|
||||
virtual bool ConfigureOutput(OutputFrameCallback callback, const VideoFormat& outputVideoMode, bool externalKeyingEnabled, std::string& error) = 0;
|
||||
virtual bool PrepareOutputSchedule() = 0;
|
||||
virtual bool StartInputStreams() = 0;
|
||||
virtual bool StartScheduledPlayback() = 0;
|
||||
virtual bool Start() = 0;
|
||||
virtual bool Stop() = 0;
|
||||
virtual const VideoIOState& State() const = 0;
|
||||
|
||||
@@ -660,9 +660,45 @@ bool DeckLinkSession::ScheduleOutputFrame(const VideoIOOutputFrame& frame)
|
||||
return scheduled;
|
||||
}
|
||||
|
||||
bool DeckLinkSession::Start()
|
||||
bool DeckLinkSession::PrepareOutputSchedule()
|
||||
{
|
||||
mScheduler.Reset();
|
||||
RefreshBufferedVideoFrameCount();
|
||||
return output != nullptr;
|
||||
}
|
||||
|
||||
bool DeckLinkSession::StartInputStreams()
|
||||
{
|
||||
if (!input)
|
||||
return true;
|
||||
|
||||
if (input->StartStreams() != S_OK)
|
||||
{
|
||||
MessageBoxA(NULL, "Could not start the DeckLink input stream.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeckLinkSession::StartScheduledPlayback()
|
||||
{
|
||||
if (!output)
|
||||
{
|
||||
MessageBoxA(NULL, "Cannot start playout because no DeckLink output device is available.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (output->StartScheduledPlayback(0, mScheduler.TimeScale(), 1.0) != S_OK)
|
||||
{
|
||||
MessageBoxA(NULL, "Could not start DeckLink scheduled playback.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
RefreshBufferedVideoFrameCount();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeckLinkSession::Start()
|
||||
{
|
||||
if (!output)
|
||||
{
|
||||
MessageBoxA(NULL, "Cannot start playout because no DeckLink output device is available.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
@@ -676,6 +712,9 @@ bool DeckLinkSession::Start()
|
||||
|
||||
const VideoPlayoutPolicy policy = NormalizeVideoPlayoutPolicy(mPlayoutPolicy);
|
||||
mPlayoutPolicy = policy;
|
||||
if (!PrepareOutputSchedule())
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < policy.targetPrerollFrames; i++)
|
||||
{
|
||||
CComPtr<IDeckLinkMutableVideoFrame> outputVideoFrame;
|
||||
@@ -691,21 +730,7 @@ bool DeckLinkSession::Start()
|
||||
}
|
||||
}
|
||||
|
||||
if (input)
|
||||
{
|
||||
if (input->StartStreams() != S_OK)
|
||||
{
|
||||
MessageBoxA(NULL, "Could not start the DeckLink input stream.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (output->StartScheduledPlayback(0, mScheduler.TimeScale(), 1.0) != S_OK)
|
||||
{
|
||||
MessageBoxA(NULL, "Could not start DeckLink scheduled playback.", "DeckLink start failed", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return StartInputStreams() && StartScheduledPlayback();
|
||||
}
|
||||
|
||||
bool DeckLinkSession::Stop()
|
||||
|
||||
@@ -28,6 +28,9 @@ public:
|
||||
bool SelectPreferredFormats(const VideoFormatSelection& videoModes, bool outputAlphaRequired, std::string& error) override;
|
||||
bool ConfigureInput(InputFrameCallback callback, const VideoFormat& inputVideoMode, std::string& error) override;
|
||||
bool ConfigureOutput(OutputFrameCallback callback, const VideoFormat& outputVideoMode, bool externalKeyingEnabled, std::string& error) override;
|
||||
bool PrepareOutputSchedule() override;
|
||||
bool StartInputStreams() override;
|
||||
bool StartScheduledPlayback() override;
|
||||
bool Start() override;
|
||||
bool Stop() override;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user