generic telemetry

This commit is contained in:
2026-05-22 15:53:56 +10:00
parent 6e8f18e24c
commit 2058f94193
4 changed files with 45 additions and 39 deletions

View File

@@ -42,16 +42,6 @@ struct VideoIOState
bool keyerInterfaceAvailable = false; bool keyerInterfaceAvailable = false;
bool externalKeyingActive = false; bool externalKeyingActive = false;
double frameBudgetMilliseconds = 0.0; double frameBudgetMilliseconds = 0.0;
bool actualDeckLinkBufferedFramesAvailable = false;
uint64_t actualDeckLinkBufferedFrames = 0;
double deckLinkScheduleCallMilliseconds = 0.0;
uint64_t deckLinkScheduleFailureCount = 0;
bool deckLinkScheduleLeadAvailable = false;
int64_t deckLinkPlaybackStreamTime = 0;
uint64_t deckLinkPlaybackFrameIndex = 0;
uint64_t deckLinkNextScheduleFrameIndex = 0;
int64_t deckLinkScheduleLeadFrames = 0;
uint64_t deckLinkScheduleRealignmentCount = 0;
}; };
struct VideoIOFrame struct VideoIOFrame

View File

@@ -72,17 +72,17 @@ DeckLinkOutputMetrics DeckLinkOutput::Metrics() const
metrics.dropped = mDropped.load(); metrics.dropped = mDropped.load();
metrics.flushed = mFlushed.load(); metrics.flushed = mFlushed.load();
const VideoIOState& state = mSession.State(); const DeckLinkSessionTelemetry& telemetry = mSession.Telemetry();
metrics.scheduleFailures = state.deckLinkScheduleFailureCount; metrics.scheduleFailures = telemetry.scheduleFailureCount;
metrics.actualBufferedFramesAvailable = state.actualDeckLinkBufferedFramesAvailable; metrics.actualBufferedFramesAvailable = telemetry.actualBufferedFramesAvailable;
metrics.actualBufferedFrames = state.actualDeckLinkBufferedFrames; metrics.actualBufferedFrames = telemetry.actualBufferedFrames;
metrics.scheduleCallMilliseconds = state.deckLinkScheduleCallMilliseconds; metrics.scheduleCallMilliseconds = telemetry.scheduleCallMilliseconds;
metrics.scheduleLeadAvailable = state.deckLinkScheduleLeadAvailable; metrics.scheduleLeadAvailable = telemetry.scheduleLeadAvailable;
metrics.playbackStreamTime = state.deckLinkPlaybackStreamTime; metrics.playbackStreamTime = telemetry.playbackStreamTime;
metrics.playbackFrameIndex = state.deckLinkPlaybackFrameIndex; metrics.playbackFrameIndex = telemetry.playbackFrameIndex;
metrics.nextScheduleFrameIndex = state.deckLinkNextScheduleFrameIndex; metrics.nextScheduleFrameIndex = telemetry.nextScheduleFrameIndex;
metrics.scheduleLeadFrames = state.deckLinkScheduleLeadFrames; metrics.scheduleLeadFrames = telemetry.scheduleLeadFrames;
metrics.scheduleRealignmentCount = state.deckLinkScheduleRealignmentCount; metrics.scheduleRealignmentCount = telemetry.scheduleRealignmentCount;
return metrics; return metrics;
} }

View File

@@ -443,7 +443,7 @@ bool DeckLinkSession::ScheduleFrame(IDeckLinkMutableVideoFrame* outputVideoFrame
{ {
if (outputVideoFrame == nullptr || output == nullptr) if (outputVideoFrame == nullptr || output == nullptr)
{ {
++mState.deckLinkScheduleFailureCount; ++mTelemetry.scheduleFailureCount;
return false; return false;
} }
@@ -459,9 +459,9 @@ bool DeckLinkSession::ScheduleFrame(IDeckLinkMutableVideoFrame* outputVideoFrame
const auto scheduleStart = std::chrono::steady_clock::now(); const auto scheduleStart = std::chrono::steady_clock::now();
const HRESULT result = output->ScheduleVideoFrame(outputVideoFrame, scheduleTime.streamTime, scheduleTime.duration, scheduleTime.timeScale); const HRESULT result = output->ScheduleVideoFrame(outputVideoFrame, scheduleTime.streamTime, scheduleTime.duration, scheduleTime.timeScale);
const auto scheduleEnd = std::chrono::steady_clock::now(); const auto scheduleEnd = std::chrono::steady_clock::now();
mState.deckLinkScheduleCallMilliseconds = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(scheduleEnd - scheduleStart).count(); mTelemetry.scheduleCallMilliseconds = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(scheduleEnd - scheduleStart).count();
if (result != S_OK) if (result != S_OK)
++mState.deckLinkScheduleFailureCount; ++mTelemetry.scheduleFailureCount;
RefreshBufferedVideoFrameCount(); RefreshBufferedVideoFrameCount();
return result == S_OK; return result == S_OK;
} }
@@ -470,7 +470,7 @@ void DeckLinkSession::UpdateScheduleLeadTelemetry()
{ {
if (output == nullptr) if (output == nullptr)
{ {
mState.deckLinkScheduleLeadAvailable = false; mTelemetry.scheduleLeadAvailable = false;
return; return;
} }
@@ -478,7 +478,7 @@ void DeckLinkSession::UpdateScheduleLeadTelemetry()
double playbackSpeed = 0.0; double playbackSpeed = 0.0;
if (output->GetScheduledStreamTime(mScheduler.TimeScale(), &streamTime, &playbackSpeed) != S_OK || playbackSpeed <= 0.0) if (output->GetScheduledStreamTime(mScheduler.TimeScale(), &streamTime, &playbackSpeed) != S_OK || playbackSpeed <= 0.0)
{ {
mState.deckLinkScheduleLeadAvailable = false; mTelemetry.scheduleLeadAvailable = false;
return; return;
} }
@@ -486,25 +486,25 @@ void DeckLinkSession::UpdateScheduleLeadTelemetry()
? static_cast<uint64_t>(streamTime / mScheduler.FrameDuration()) ? static_cast<uint64_t>(streamTime / mScheduler.FrameDuration())
: 0; : 0;
const uint64_t nextScheduleFrameIndex = mScheduler.ScheduledFrameIndex(); const uint64_t nextScheduleFrameIndex = mScheduler.ScheduledFrameIndex();
mState.deckLinkScheduleLeadAvailable = true; mTelemetry.scheduleLeadAvailable = true;
mState.deckLinkPlaybackStreamTime = streamTime; mTelemetry.playbackStreamTime = streamTime;
mState.deckLinkPlaybackFrameIndex = playbackFrameIndex; mTelemetry.playbackFrameIndex = playbackFrameIndex;
mState.deckLinkNextScheduleFrameIndex = nextScheduleFrameIndex; mTelemetry.nextScheduleFrameIndex = nextScheduleFrameIndex;
mState.deckLinkScheduleLeadFrames = static_cast<int64_t>(nextScheduleFrameIndex) - static_cast<int64_t>(playbackFrameIndex); mTelemetry.scheduleLeadFrames = static_cast<int64_t>(nextScheduleFrameIndex) - static_cast<int64_t>(playbackFrameIndex);
} }
void DeckLinkSession::MaybeRealignScheduleCursorForLowLead() void DeckLinkSession::MaybeRealignScheduleCursorForLowLead()
{ {
if (!mState.deckLinkScheduleLeadAvailable) if (!mTelemetry.scheduleLeadAvailable)
return; return;
if (mState.deckLinkScheduleLeadFrames >= kMinimumHealthyScheduleLeadFrames) if (mTelemetry.scheduleLeadFrames >= kMinimumHealthyScheduleLeadFrames)
{ {
mProactiveScheduleRealignmentArmed = true; mProactiveScheduleRealignmentArmed = true;
return; return;
} }
if (!mProactiveScheduleRealignmentArmed || mState.deckLinkScheduleLeadFrames > kProactiveScheduleLeadFloorFrames) if (!mProactiveScheduleRealignmentArmed || mTelemetry.scheduleLeadFrames > kProactiveScheduleLeadFloorFrames)
return; return;
RealignScheduleCursorToPlayback(); RealignScheduleCursorToPlayback();
@@ -523,7 +523,7 @@ void DeckLinkSession::RealignScheduleCursorToPlayback()
const VideoPlayoutPolicy policy = NormalizeVideoPlayoutPolicy(mPlayoutPolicy); const VideoPlayoutPolicy policy = NormalizeVideoPlayoutPolicy(mPlayoutPolicy);
mScheduler.AlignNextScheduleTimeToPlayback(streamTime, policy.targetPrerollFrames); mScheduler.AlignNextScheduleTimeToPlayback(streamTime, policy.targetPrerollFrames);
++mState.deckLinkScheduleRealignmentCount; ++mTelemetry.scheduleRealignmentCount;
UpdateScheduleLeadTelemetry(); UpdateScheduleLeadTelemetry();
} }
@@ -593,19 +593,19 @@ void DeckLinkSession::RefreshBufferedVideoFrameCount()
{ {
if (output == nullptr) if (output == nullptr)
{ {
mState.actualDeckLinkBufferedFramesAvailable = false; mTelemetry.actualBufferedFramesAvailable = false;
return; return;
} }
unsigned int bufferedFrameCount = 0; unsigned int bufferedFrameCount = 0;
if (output->GetBufferedVideoFrameCount(&bufferedFrameCount) == S_OK) if (output->GetBufferedVideoFrameCount(&bufferedFrameCount) == S_OK)
{ {
mState.actualDeckLinkBufferedFrames = bufferedFrameCount; mTelemetry.actualBufferedFrames = bufferedFrameCount;
mState.actualDeckLinkBufferedFramesAvailable = true; mTelemetry.actualBufferedFramesAvailable = true;
} }
else else
{ {
mState.actualDeckLinkBufferedFramesAvailable = false; mTelemetry.actualBufferedFramesAvailable = false;
} }
} }

View File

@@ -18,6 +18,20 @@
class OpenGLComposite; class OpenGLComposite;
struct DeckLinkSessionTelemetry
{
bool actualBufferedFramesAvailable = false;
uint64_t actualBufferedFrames = 0;
double scheduleCallMilliseconds = 0.0;
uint64_t scheduleFailureCount = 0;
bool scheduleLeadAvailable = false;
int64_t playbackStreamTime = 0;
uint64_t playbackFrameIndex = 0;
uint64_t nextScheduleFrameIndex = 0;
int64_t scheduleLeadFrames = 0;
uint64_t scheduleRealignmentCount = 0;
};
class DeckLinkSession class DeckLinkSession
{ {
public: public:
@@ -63,6 +77,7 @@ public:
void SetStatusMessage(const std::string& message) { mState.statusMessage = message; } void SetStatusMessage(const std::string& message) { mState.statusMessage = message; }
const VideoIOState& State() const { return mState; } const VideoIOState& State() const { return mState; }
VideoIOState& MutableState() { return mState; } VideoIOState& MutableState() { return mState; }
const DeckLinkSessionTelemetry& Telemetry() const { return mTelemetry; }
double FrameBudgetMilliseconds() const; double FrameBudgetMilliseconds() const;
VideoPlayoutRecoveryDecision AccountForCompletionResult(VideoIOCompletionResult completionResult, uint64_t readyQueueDepth); VideoPlayoutRecoveryDecision AccountForCompletionResult(VideoIOCompletionResult completionResult, uint64_t readyQueueDepth);
bool BeginOutputFrame(VideoIOOutputFrame& frame); bool BeginOutputFrame(VideoIOOutputFrame& frame);
@@ -89,6 +104,7 @@ private:
std::mutex mScheduledSystemFrameMutex; std::mutex mScheduledSystemFrameMutex;
std::unordered_map<IDeckLinkVideoFrame*, void*> mScheduledSystemFrameBuffers; std::unordered_map<IDeckLinkVideoFrame*, void*> mScheduledSystemFrameBuffers;
VideoIOState mState; VideoIOState mState;
DeckLinkSessionTelemetry mTelemetry;
VideoPlayoutPolicy mPlayoutPolicy; VideoPlayoutPolicy mPlayoutPolicy;
VideoPlayoutScheduler mScheduler; VideoPlayoutScheduler mScheduler;
bool mScheduleRealignmentPending = false; bool mScheduleRealignmentPending = false;