#include "OpenGLVideoIOBridge.h" #include "HealthTelemetry.h" #include "RenderEngine.h" #include OpenGLVideoIOBridge::OpenGLVideoIOBridge( VideoIODevice& videoIO, RenderEngine& renderEngine, HealthTelemetry& healthTelemetry) : mVideoIO(videoIO), mRenderEngine(renderEngine), mHealthTelemetry(healthTelemetry) { } void OpenGLVideoIOBridge::RecordFramePacing(VideoIOCompletionResult completionResult) { const auto now = std::chrono::steady_clock::now(); if (mLastPlayoutCompletionTime != std::chrono::steady_clock::time_point()) { mCompletionIntervalMilliseconds = std::chrono::duration_cast>(now - mLastPlayoutCompletionTime).count(); if (mSmoothedCompletionIntervalMilliseconds <= 0.0) mSmoothedCompletionIntervalMilliseconds = mCompletionIntervalMilliseconds; else mSmoothedCompletionIntervalMilliseconds = mSmoothedCompletionIntervalMilliseconds * 0.9 + mCompletionIntervalMilliseconds * 0.1; if (mCompletionIntervalMilliseconds > mMaxCompletionIntervalMilliseconds) mMaxCompletionIntervalMilliseconds = mCompletionIntervalMilliseconds; } mLastPlayoutCompletionTime = now; if (completionResult == VideoIOCompletionResult::DisplayedLate) ++mLateFrameCount; else if (completionResult == VideoIOCompletionResult::Dropped) ++mDroppedFrameCount; else if (completionResult == VideoIOCompletionResult::Flushed) ++mFlushedFrameCount; mHealthTelemetry.TryRecordFramePacingStats( mCompletionIntervalMilliseconds, mSmoothedCompletionIntervalMilliseconds, mMaxCompletionIntervalMilliseconds, mLateFrameCount, mDroppedFrameCount, mFlushedFrameCount); } void OpenGLVideoIOBridge::VideoFrameArrived(const VideoIOFrame& inputFrame) { const VideoIOState& state = mVideoIO.State(); mHealthTelemetry.TryReportSignalStatus(!inputFrame.hasNoInputSource, state.inputFrameSize.width, state.inputFrameSize.height, state.inputDisplayModeName); if (inputFrame.hasNoInputSource || inputFrame.bytes == nullptr) return; // don't transfer texture when there's no input mRenderEngine.TryUploadInputFrame(inputFrame, state); } void OpenGLVideoIOBridge::PlayoutFrameCompleted(const VideoIOCompletion& completion) { RecordFramePacing(completion.result); VideoIOOutputFrame outputFrame; if (!mVideoIO.BeginOutputFrame(outputFrame)) return; const VideoIOState& state = mVideoIO.State(); RenderPipelineFrameContext frameContext; frameContext.videoState = state; frameContext.completion = completion; mRenderEngine.RenderOutputFrame(frameContext, outputFrame); mVideoIO.EndOutputFrame(outputFrame); mVideoIO.AccountForCompletionResult(completion.result); // Schedule the next frame for playout after the GL bridge is released so // input uploads are not blocked by non-GL output bookkeeping. mVideoIO.ScheduleOutputFrame(outputFrame); }