Phase 7 step 1
This commit is contained in:
@@ -26,46 +26,86 @@ void VideoBackend::ReleaseResources()
|
||||
{
|
||||
if (mVideoIODevice)
|
||||
mVideoIODevice->ReleaseResources();
|
||||
if (!VideoBackendLifecycle::CanTransition(mLifecycle.State(), VideoBackendLifecycleState::Stopped))
|
||||
ApplyLifecycleFailure("Video backend resources released before lifecycle completed.");
|
||||
ApplyLifecycleTransition(VideoBackendLifecycleState::Stopped, "Video backend resources released.");
|
||||
}
|
||||
|
||||
VideoBackendLifecycleState VideoBackend::LifecycleState() const
|
||||
{
|
||||
return mLifecycle.State();
|
||||
}
|
||||
|
||||
bool VideoBackend::DiscoverDevicesAndModes(const VideoFormatSelection& videoModes, std::string& error)
|
||||
{
|
||||
return mVideoIODevice->DiscoverDevicesAndModes(videoModes, error);
|
||||
ApplyLifecycleTransition(VideoBackendLifecycleState::Discovering, "Discovering video backend devices and modes.");
|
||||
if (mVideoIODevice->DiscoverDevicesAndModes(videoModes, error))
|
||||
return ApplyLifecycleTransition(VideoBackendLifecycleState::Discovered, "Video backend devices and modes discovered.");
|
||||
|
||||
ApplyLifecycleFailure(error.empty() ? "Video backend discovery failed." : error);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VideoBackend::SelectPreferredFormats(const VideoFormatSelection& videoModes, bool outputAlphaRequired, std::string& error)
|
||||
{
|
||||
return mVideoIODevice->SelectPreferredFormats(videoModes, outputAlphaRequired, error);
|
||||
ApplyLifecycleTransition(VideoBackendLifecycleState::Configuring, "Selecting preferred video backend formats.");
|
||||
if (mVideoIODevice->SelectPreferredFormats(videoModes, outputAlphaRequired, error))
|
||||
return true;
|
||||
|
||||
ApplyLifecycleFailure(error.empty() ? "Video backend format selection failed." : error);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VideoBackend::ConfigureInput(const VideoFormat& inputVideoMode, std::string& error)
|
||||
{
|
||||
return mVideoIODevice->ConfigureInput(
|
||||
if (mLifecycle.State() != VideoBackendLifecycleState::Configuring)
|
||||
ApplyLifecycleTransition(VideoBackendLifecycleState::Configuring, "Configuring video backend input.");
|
||||
if (!mVideoIODevice->ConfigureInput(
|
||||
[this](const VideoIOFrame& frame) { HandleInputFrame(frame); },
|
||||
inputVideoMode,
|
||||
error);
|
||||
error))
|
||||
{
|
||||
ApplyLifecycleFailure(error.empty() ? "Video backend input configuration failed." : error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VideoBackend::ConfigureOutput(const VideoFormat& outputVideoMode, bool externalKeyingEnabled, std::string& error)
|
||||
{
|
||||
return mVideoIODevice->ConfigureOutput(
|
||||
if (mLifecycle.State() != VideoBackendLifecycleState::Configuring)
|
||||
ApplyLifecycleTransition(VideoBackendLifecycleState::Configuring, "Configuring video backend output.");
|
||||
if (!mVideoIODevice->ConfigureOutput(
|
||||
[this](const VideoIOCompletion& completion) { HandleOutputFrameCompletion(completion); },
|
||||
outputVideoMode,
|
||||
externalKeyingEnabled,
|
||||
error);
|
||||
error))
|
||||
{
|
||||
ApplyLifecycleFailure(error.empty() ? "Video backend output configuration failed." : error);
|
||||
return false;
|
||||
}
|
||||
return ApplyLifecycleTransition(VideoBackendLifecycleState::Configured, "Video backend configured.");
|
||||
}
|
||||
|
||||
bool VideoBackend::Start()
|
||||
{
|
||||
ApplyLifecycleTransition(VideoBackendLifecycleState::Prerolling, "Video backend preroll starting.");
|
||||
const bool started = mVideoIODevice->Start();
|
||||
PublishBackendStateChanged(started ? "started" : "start-failed", started ? "Video backend started." : StatusMessage());
|
||||
if (started)
|
||||
ApplyLifecycleTransition(VideoBackendLifecycleState::Running, "Video backend started.");
|
||||
else
|
||||
ApplyLifecycleFailure(StatusMessage().empty() ? "Video backend start failed." : StatusMessage());
|
||||
return started;
|
||||
}
|
||||
|
||||
bool VideoBackend::Stop()
|
||||
{
|
||||
ApplyLifecycleTransition(VideoBackendLifecycleState::Stopping, "Video backend stopping.");
|
||||
const bool stopped = mVideoIODevice->Stop();
|
||||
PublishBackendStateChanged(stopped ? "stopped" : "stop-failed", stopped ? "Video backend stopped." : StatusMessage());
|
||||
if (stopped)
|
||||
ApplyLifecycleTransition(VideoBackendLifecycleState::Stopped, "Video backend stopped.");
|
||||
else
|
||||
ApplyLifecycleFailure(StatusMessage().empty() ? "Video backend stop failed." : StatusMessage());
|
||||
return stopped;
|
||||
}
|
||||
|
||||
@@ -198,7 +238,7 @@ void VideoBackend::PublishStatus(bool externalKeyingConfigured, const std::strin
|
||||
externalKeyingConfigured,
|
||||
ExternalKeyingActive(),
|
||||
StatusMessage());
|
||||
PublishBackendStateChanged("status", StatusMessage());
|
||||
PublishBackendStateChanged(VideoBackendLifecycle::StateName(mLifecycle.State()), StatusMessage());
|
||||
}
|
||||
|
||||
void VideoBackend::ReportNoInputDeviceSignalStatus()
|
||||
@@ -240,7 +280,7 @@ void VideoBackend::HandleOutputFrameCompletion(const VideoIOCompletion& completi
|
||||
AccountForCompletionResult(completion.result);
|
||||
if (!rendered)
|
||||
{
|
||||
PublishBackendStateChanged("output-render-failed", "Output frame render request failed; skipping schedule for this frame.");
|
||||
ApplyLifecycleTransition(VideoBackendLifecycleState::Degraded, "Output frame render request failed; skipping schedule for this frame.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -283,6 +323,32 @@ void VideoBackend::RecordFramePacing(VideoIOCompletionResult completionResult)
|
||||
PublishTimingSample("VideoBackend", "smoothedCompletionInterval", mSmoothedCompletionIntervalMilliseconds, "ms");
|
||||
}
|
||||
|
||||
bool VideoBackend::ApplyLifecycleTransition(VideoBackendLifecycleState state, const std::string& message)
|
||||
{
|
||||
const VideoBackendLifecycleTransition transition = mLifecycle.TransitionTo(state, message);
|
||||
if (!transition.accepted)
|
||||
{
|
||||
PublishBackendStateChanged(VideoBackendLifecycle::StateName(transition.current), transition.errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
PublishBackendStateChanged(VideoBackendLifecycle::StateName(transition.current), message);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VideoBackend::ApplyLifecycleFailure(const std::string& message)
|
||||
{
|
||||
const VideoBackendLifecycleTransition transition = mLifecycle.Fail(message);
|
||||
if (!transition.accepted)
|
||||
{
|
||||
PublishBackendStateChanged(VideoBackendLifecycle::StateName(transition.current), transition.errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
PublishBackendStateChanged(VideoBackendLifecycle::StateName(transition.current), message);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoBackend::PublishBackendStateChanged(const std::string& state, const std::string& message)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "VideoBackendLifecycle.h"
|
||||
#include "VideoIOTypes.h"
|
||||
|
||||
#include <chrono>
|
||||
@@ -20,6 +21,7 @@ public:
|
||||
~VideoBackend();
|
||||
|
||||
void ReleaseResources();
|
||||
VideoBackendLifecycleState LifecycleState() const;
|
||||
bool DiscoverDevicesAndModes(const VideoFormatSelection& videoModes, std::string& error);
|
||||
bool SelectPreferredFormats(const VideoFormatSelection& videoModes, bool outputAlphaRequired, std::string& error);
|
||||
bool ConfigureInput(const VideoFormat& inputVideoMode, std::string& error);
|
||||
@@ -58,6 +60,8 @@ private:
|
||||
void HandleInputFrame(const VideoIOFrame& frame);
|
||||
void HandleOutputFrameCompletion(const VideoIOCompletion& completion);
|
||||
void RecordFramePacing(VideoIOCompletionResult completionResult);
|
||||
bool ApplyLifecycleTransition(VideoBackendLifecycleState state, const std::string& message);
|
||||
bool ApplyLifecycleFailure(const std::string& message);
|
||||
void PublishBackendStateChanged(const std::string& state, const std::string& message);
|
||||
void PublishInputSignalChanged(const VideoIOFrame& frame, const VideoIOState& state);
|
||||
void PublishInputFrameArrived(const VideoIOFrame& frame);
|
||||
@@ -69,6 +73,7 @@ private:
|
||||
|
||||
HealthTelemetry& mHealthTelemetry;
|
||||
RuntimeEventDispatcher& mRuntimeEventDispatcher;
|
||||
VideoBackendLifecycle mLifecycle;
|
||||
std::unique_ptr<VideoIODevice> mVideoIODevice;
|
||||
std::unique_ptr<OpenGLVideoIOBridge> mBridge;
|
||||
uint64_t mInputFrameIndex = 0;
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "VideoBackendLifecycle.h"
|
||||
|
||||
VideoBackendLifecycleState VideoBackendLifecycle::State() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
const std::string& VideoBackendLifecycle::FailureReason() const
|
||||
{
|
||||
return mFailureReason;
|
||||
}
|
||||
|
||||
VideoBackendLifecycleTransition VideoBackendLifecycle::TransitionTo(VideoBackendLifecycleState next, const std::string& reason)
|
||||
{
|
||||
VideoBackendLifecycleTransition transition;
|
||||
transition.previous = mState;
|
||||
transition.current = next;
|
||||
transition.reason = reason;
|
||||
transition.accepted = CanTransition(mState, next);
|
||||
if (!transition.accepted)
|
||||
{
|
||||
transition.current = mState;
|
||||
transition.errorMessage = std::string("Invalid video backend lifecycle transition from ") +
|
||||
StateName(mState) + " to " + StateName(next) + ".";
|
||||
return transition;
|
||||
}
|
||||
|
||||
mState = next;
|
||||
transition.current = mState;
|
||||
if (mState != VideoBackendLifecycleState::Failed)
|
||||
mFailureReason.clear();
|
||||
return transition;
|
||||
}
|
||||
|
||||
VideoBackendLifecycleTransition VideoBackendLifecycle::Fail(const std::string& reason)
|
||||
{
|
||||
VideoBackendLifecycleTransition transition = TransitionTo(VideoBackendLifecycleState::Failed, reason);
|
||||
if (transition.accepted)
|
||||
mFailureReason = reason;
|
||||
return transition;
|
||||
}
|
||||
|
||||
bool VideoBackendLifecycle::CanTransition(VideoBackendLifecycleState current, VideoBackendLifecycleState next)
|
||||
{
|
||||
if (current == next)
|
||||
return true;
|
||||
|
||||
switch (current)
|
||||
{
|
||||
case VideoBackendLifecycleState::Uninitialized:
|
||||
return next == VideoBackendLifecycleState::Discovering ||
|
||||
next == VideoBackendLifecycleState::Stopped ||
|
||||
next == VideoBackendLifecycleState::Failed;
|
||||
case VideoBackendLifecycleState::Discovering:
|
||||
return next == VideoBackendLifecycleState::Discovered ||
|
||||
next == VideoBackendLifecycleState::Failed;
|
||||
case VideoBackendLifecycleState::Discovered:
|
||||
return next == VideoBackendLifecycleState::Configuring ||
|
||||
next == VideoBackendLifecycleState::Stopped ||
|
||||
next == VideoBackendLifecycleState::Failed;
|
||||
case VideoBackendLifecycleState::Configuring:
|
||||
return next == VideoBackendLifecycleState::Configured ||
|
||||
next == VideoBackendLifecycleState::Failed;
|
||||
case VideoBackendLifecycleState::Configured:
|
||||
return next == VideoBackendLifecycleState::Prerolling ||
|
||||
next == VideoBackendLifecycleState::Stopped ||
|
||||
next == VideoBackendLifecycleState::Failed;
|
||||
case VideoBackendLifecycleState::Prerolling:
|
||||
return next == VideoBackendLifecycleState::Running ||
|
||||
next == VideoBackendLifecycleState::Stopping ||
|
||||
next == VideoBackendLifecycleState::Failed;
|
||||
case VideoBackendLifecycleState::Running:
|
||||
return next == VideoBackendLifecycleState::Degraded ||
|
||||
next == VideoBackendLifecycleState::Stopping ||
|
||||
next == VideoBackendLifecycleState::Failed;
|
||||
case VideoBackendLifecycleState::Degraded:
|
||||
return next == VideoBackendLifecycleState::Running ||
|
||||
next == VideoBackendLifecycleState::Stopping ||
|
||||
next == VideoBackendLifecycleState::Failed;
|
||||
case VideoBackendLifecycleState::Stopping:
|
||||
return next == VideoBackendLifecycleState::Stopped ||
|
||||
next == VideoBackendLifecycleState::Failed;
|
||||
case VideoBackendLifecycleState::Stopped:
|
||||
return next == VideoBackendLifecycleState::Discovering ||
|
||||
next == VideoBackendLifecycleState::Failed;
|
||||
case VideoBackendLifecycleState::Failed:
|
||||
return next == VideoBackendLifecycleState::Stopped ||
|
||||
next == VideoBackendLifecycleState::Discovering;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const char* VideoBackendLifecycle::StateName(VideoBackendLifecycleState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case VideoBackendLifecycleState::Uninitialized:
|
||||
return "uninitialized";
|
||||
case VideoBackendLifecycleState::Discovering:
|
||||
return "discovering";
|
||||
case VideoBackendLifecycleState::Discovered:
|
||||
return "discovered";
|
||||
case VideoBackendLifecycleState::Configuring:
|
||||
return "configuring";
|
||||
case VideoBackendLifecycleState::Configured:
|
||||
return "configured";
|
||||
case VideoBackendLifecycleState::Prerolling:
|
||||
return "prerolling";
|
||||
case VideoBackendLifecycleState::Running:
|
||||
return "running";
|
||||
case VideoBackendLifecycleState::Degraded:
|
||||
return "degraded";
|
||||
case VideoBackendLifecycleState::Stopping:
|
||||
return "stopping";
|
||||
case VideoBackendLifecycleState::Stopped:
|
||||
return "stopped";
|
||||
case VideoBackendLifecycleState::Failed:
|
||||
return "failed";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class VideoBackendLifecycleState
|
||||
{
|
||||
Uninitialized,
|
||||
Discovering,
|
||||
Discovered,
|
||||
Configuring,
|
||||
Configured,
|
||||
Prerolling,
|
||||
Running,
|
||||
Degraded,
|
||||
Stopping,
|
||||
Stopped,
|
||||
Failed
|
||||
};
|
||||
|
||||
struct VideoBackendLifecycleTransition
|
||||
{
|
||||
VideoBackendLifecycleState previous = VideoBackendLifecycleState::Uninitialized;
|
||||
VideoBackendLifecycleState current = VideoBackendLifecycleState::Uninitialized;
|
||||
bool accepted = false;
|
||||
std::string reason;
|
||||
std::string errorMessage;
|
||||
};
|
||||
|
||||
class VideoBackendLifecycle
|
||||
{
|
||||
public:
|
||||
VideoBackendLifecycleState State() const;
|
||||
const std::string& FailureReason() const;
|
||||
VideoBackendLifecycleTransition TransitionTo(VideoBackendLifecycleState next, const std::string& reason);
|
||||
VideoBackendLifecycleTransition Fail(const std::string& reason);
|
||||
|
||||
static bool CanTransition(VideoBackendLifecycleState current, VideoBackendLifecycleState next);
|
||||
static const char* StateName(VideoBackendLifecycleState state);
|
||||
|
||||
private:
|
||||
VideoBackendLifecycleState mState = VideoBackendLifecycleState::Uninitialized;
|
||||
std::string mFailureReason;
|
||||
};
|
||||
Reference in New Issue
Block a user