#include "VideoIOTypes.h" #include #include namespace { int gFailures = 0; void Expect(bool condition, const char* message) { if (condition) return; std::cerr << "FAIL: " << message << "\n"; ++gFailures; } class FakeVideoIODevice : public VideoIODevice { public: void ReleaseResources() override {} bool DiscoverDevicesAndModes(const VideoFormatSelection&, std::string&) override { mState.inputFrameSize = { 1920, 1080 }; mState.outputFrameSize = { 1920, 1080 }; mState.inputDisplayModeName = "fake 1080p"; mState.outputModelName = "Fake Video IO"; mState.hasInputDevice = true; return true; } bool SelectPreferredFormats(const VideoFormatSelection&, bool, std::string&) override { mState.inputPixelFormat = VideoIOPixelFormat::Uyvy8; mState.outputPixelFormat = VideoIOPixelFormat::Bgra8; mState.inputFrameRowBytes = VideoIORowBytes(mState.inputPixelFormat, mState.inputFrameSize.width); mState.outputFrameRowBytes = VideoIORowBytes(mState.outputPixelFormat, mState.outputFrameSize.width); mState.captureTextureWidth = PackedTextureWidthFromRowBytes(mState.inputFrameRowBytes); mState.outputPackTextureWidth = mState.outputFrameSize.width; return true; } bool ConfigureInput(InputFrameCallback callback, const VideoFormat&, std::string&) override { mInputCallback = callback; return true; } bool ConfigureOutput(OutputFrameCallback callback, const VideoFormat&, bool, std::string&) override { mOutputCallback = callback; return true; } bool PrepareOutputSchedule() override { mPreparedOutputSchedule = true; return true; } bool StartInputStreams() override { mInputStreamsStarted = true; mState.hasInputSource = true; VideoIOFrame input; input.bytes = mInputBytes.data(); input.rowBytes = static_cast(mState.inputFrameRowBytes); input.width = mState.inputFrameSize.width; input.height = mState.inputFrameSize.height; input.pixelFormat = mState.inputPixelFormat; if (mInputCallback) mInputCallback(input); return true; } bool StartScheduledPlayback() override { mScheduledPlaybackStarted = true; if (mOutputCallback) mOutputCallback(VideoIOCompletion{ VideoIOCompletionResult::Completed }); return true; } bool Start() override { return PrepareOutputSchedule() && StartInputStreams() && StartScheduledPlayback(); } bool Stop() override { return true; } const VideoIOState& State() const override { return mState; } VideoIOState& MutableState() override { return mState; } bool BeginOutputFrame(VideoIOOutputFrame& frame) override { frame.bytes = mOutputBytes.data(); frame.rowBytes = static_cast(mState.outputFrameRowBytes); frame.width = mState.outputFrameSize.width; frame.height = mState.outputFrameSize.height; frame.pixelFormat = mState.outputPixelFormat; return true; } void EndOutputFrame(VideoIOOutputFrame&) override {} bool ScheduleOutputFrame(const VideoIOOutputFrame&) override { ++mScheduledFrames; return true; } VideoPlayoutRecoveryDecision AccountForCompletionResult(VideoIOCompletionResult result, uint64_t readyQueueDepth) override { mLastCompletion = result; mLastReadyQueueDepth = readyQueueDepth; VideoPlayoutRecoveryDecision decision; decision.result = result; decision.readyQueueDepth = readyQueueDepth; return decision; } unsigned ScheduledFrames() const { return mScheduledFrames; } bool PreparedOutputSchedule() const { return mPreparedOutputSchedule; } bool InputStreamsStarted() const { return mInputStreamsStarted; } bool ScheduledPlaybackStarted() const { return mScheduledPlaybackStarted; } VideoIOCompletionResult LastCompletion() const { return mLastCompletion; } uint64_t LastReadyQueueDepth() const { return mLastReadyQueueDepth; } private: VideoIOState mState; InputFrameCallback mInputCallback; OutputFrameCallback mOutputCallback; std::array mInputBytes = {}; std::array mOutputBytes = {}; unsigned mScheduledFrames = 0; bool mPreparedOutputSchedule = false; bool mInputStreamsStarted = false; bool mScheduledPlaybackStarted = false; VideoIOCompletionResult mLastCompletion = VideoIOCompletionResult::Unknown; uint64_t mLastReadyQueueDepth = 0; }; } int main() { FakeVideoIODevice device; VideoFormatSelection selection; std::string error; bool inputSeen = false; bool outputSeen = false; Expect(device.DiscoverDevicesAndModes(selection, error), "fake discovery succeeds"); Expect(device.SelectPreferredFormats(selection, false, error), "fake format selection succeeds"); Expect(device.ConfigureInput([&](const VideoIOFrame& frame) { inputSeen = frame.bytes != nullptr && frame.width == 1920 && frame.pixelFormat == VideoIOPixelFormat::Uyvy8; }, selection.input, error), "fake input config succeeds"); Expect(device.ConfigureOutput([&](const VideoIOCompletion& completion) { outputSeen = completion.result == VideoIOCompletionResult::Completed; }, selection.output, false, error), "fake output config succeeds"); Expect(device.Start(), "fake device starts"); VideoIOOutputFrame outputFrame; Expect(device.BeginOutputFrame(outputFrame), "fake output frame can be acquired"); device.EndOutputFrame(outputFrame); device.AccountForCompletionResult(VideoIOCompletionResult::Completed, 2); Expect(device.ScheduleOutputFrame(outputFrame), "fake output frame can be scheduled"); Expect(inputSeen, "fake input callback emits generic frame"); Expect(outputSeen, "fake output callback emits generic completion"); Expect(device.PreparedOutputSchedule(), "fake output schedule was prepared"); Expect(device.InputStreamsStarted(), "fake input streams started"); Expect(device.ScheduledPlaybackStarted(), "fake scheduled playback started"); Expect(device.ScheduledFrames() == 1, "fake backend schedules one frame"); Expect(device.LastCompletion() == VideoIOCompletionResult::Completed, "fake backend records generic completion"); Expect(device.LastReadyQueueDepth() == 2, "fake backend records ready queue depth"); if (gFailures != 0) { std::cerr << gFailures << " VideoIODevice fake test failure(s).\n"; return 1; } std::cout << "VideoIODevice fake tests passed.\n"; return 0; }