V2 working
This commit is contained in:
148
apps/RenderCadenceCompositor/app/RenderCadenceApp.h
Normal file
148
apps/RenderCadenceCompositor/app/RenderCadenceApp.h
Normal file
@@ -0,0 +1,148 @@
|
||||
#pragma once
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include "../telemetry/TelemetryPrinter.h"
|
||||
#include "../video/DeckLinkOutput.h"
|
||||
#include "../video/DeckLinkOutputThread.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
|
||||
namespace RenderCadenceCompositor
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename RenderThread>
|
||||
auto StartRenderThread(RenderThread& renderThread, std::string& error, int) -> decltype(renderThread.Start(error), bool())
|
||||
{
|
||||
return renderThread.Start(error);
|
||||
}
|
||||
|
||||
template <typename RenderThread>
|
||||
bool StartRenderThreadWithoutError(RenderThread& renderThread, std::true_type)
|
||||
{
|
||||
return renderThread.Start();
|
||||
}
|
||||
|
||||
template <typename RenderThread>
|
||||
bool StartRenderThreadWithoutError(RenderThread& renderThread, std::false_type)
|
||||
{
|
||||
renderThread.Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename RenderThread>
|
||||
auto StartRenderThread(RenderThread& renderThread, std::string&, long) -> decltype(renderThread.Start(), bool())
|
||||
{
|
||||
return StartRenderThreadWithoutError(renderThread, std::is_same<decltype(renderThread.Start()), bool>());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename RenderThread, typename SystemFrameExchange>
|
||||
class RenderCadenceApp
|
||||
{
|
||||
public:
|
||||
RenderCadenceApp(RenderThread& renderThread, SystemFrameExchange& frameExchange, AppConfig config = DefaultAppConfig()) :
|
||||
mRenderThread(renderThread),
|
||||
mFrameExchange(frameExchange),
|
||||
mConfig(config),
|
||||
mOutputThread(mOutput, mFrameExchange, mConfig.outputThread),
|
||||
mTelemetry(mConfig.telemetry)
|
||||
{
|
||||
}
|
||||
|
||||
RenderCadenceApp(const RenderCadenceApp&) = delete;
|
||||
RenderCadenceApp& operator=(const RenderCadenceApp&) = delete;
|
||||
|
||||
~RenderCadenceApp()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool Start(std::string& error)
|
||||
{
|
||||
if (!mOutput.Initialize(
|
||||
mConfig.deckLink,
|
||||
[this](const VideoIOCompletion& completion) {
|
||||
mFrameExchange.ReleaseScheduledByBytes(completion.outputFrameBuffer);
|
||||
},
|
||||
error))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!detail::StartRenderThread(mRenderThread, error, 0))
|
||||
{
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mFrameExchange.WaitForCompletedDepth(mConfig.warmupCompletedFrames, mConfig.warmupTimeout))
|
||||
{
|
||||
error = "Timed out waiting for rendered warmup frames.";
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mOutputThread.Start())
|
||||
{
|
||||
error = "DeckLink output thread failed to start.";
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WaitForPreroll())
|
||||
{
|
||||
error = "Timed out waiting for DeckLink preroll frames.";
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mOutput.StartScheduledPlayback(error))
|
||||
{
|
||||
Stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
mTelemetry.Start(mFrameExchange, mOutput, mOutputThread);
|
||||
mStarted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
mTelemetry.Stop();
|
||||
mOutputThread.Stop();
|
||||
mOutput.Stop();
|
||||
mRenderThread.Stop();
|
||||
mOutput.ReleaseResources();
|
||||
mStarted = false;
|
||||
}
|
||||
|
||||
bool Started() const { return mStarted; }
|
||||
const DeckLinkOutput& Output() const { return mOutput; }
|
||||
|
||||
private:
|
||||
bool WaitForPreroll() const
|
||||
{
|
||||
const auto deadline = std::chrono::steady_clock::now() + mConfig.prerollTimeout;
|
||||
while (std::chrono::steady_clock::now() < deadline)
|
||||
{
|
||||
if (mFrameExchange.Metrics().scheduledCount >= mConfig.outputThread.targetBufferedFrames)
|
||||
return true;
|
||||
std::this_thread::sleep_for(mConfig.prerollPoll);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderThread& mRenderThread;
|
||||
SystemFrameExchange& mFrameExchange;
|
||||
AppConfig mConfig;
|
||||
DeckLinkOutput mOutput;
|
||||
DeckLinkOutputThread<SystemFrameExchange> mOutputThread;
|
||||
TelemetryPrinter mTelemetry;
|
||||
bool mStarted = false;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user