187 lines
6.1 KiB
C++
187 lines
6.1 KiB
C++
#include "VideoIOTypes.h"
|
|
|
|
#include <array>
|
|
#include <iostream>
|
|
|
|
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<long>(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<long>(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<unsigned char, 3840> mInputBytes = {};
|
|
std::array<unsigned char, 7680> 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;
|
|
}
|