Files

69 lines
3.4 KiB
Plaintext

// Exercise the real local seek/decode/presentation loop without worker races.
#include "../Sources/Core/player.cpp"
#include <cstdio>
#include <cstdlib>
static void require(bool condition, const char *message) {
if (!condition) { std::fprintf(stderr, "FAIL: %s\n", message); std::exit(1); }
}
static std::vector<uint8_t> pixels(const AVFrame *frame) {
const auto format = static_cast<AVPixelFormat>(frame->format);
const int size = av_image_get_buffer_size(format, frame->width, frame->height, 1);
require(size > 0, "preview has readable pixels");
std::vector<uint8_t> bytes(size);
require(av_image_copy_to_buffer(bytes.data(), size, frame->data, frame->linesize,
format, frame->width, frame->height, 1) == size, "copy preview pixels");
return bytes;
}
int main(int argc, char **argv) {
require(argc > 1, "provide local media fixtures");
for (int i = 1; i < argc; ++i) {
av_log_set_level(AV_LOG_ERROR);
Player player;
player.shutdown();
player.stopping.store(false);
player.activeEpoch = player.requestedEpoch.load();
player.open(Command{Action::Open, argv[i]});
require(player.tracks[1].codec && player.canSeek, "seekable local video");
player.output.set_volume(0);
for (bool playing : {false, true}) {
for (double fraction : {.01, .79, .21, .59}) {
const double target = player.duration * fraction;
// Full reference decoding supplies an independent expected picture,
// including disposable B-frames at or immediately after the target.
player.seek(target, false);
VideoFrame expected{};
const auto referenceStart = Clock::now();
while (!expected.frame && Clock::now() - referenceStart < std::chrono::seconds(5)) {
player.decodeOne(true);
while (!player.video.empty()) {
auto frame = std::move(player.video.front());
player.videoBytes -= frame.bytes;
player.video.pop_front();
if (frame.pts + sampleTime * .5 >= target) {
expected = std::move(frame);
break;
}
}
}
require(bool(expected.frame), "full decode supplies reference picture");
const auto start = Clock::now();
player.seek(target, playing);
while ((!player.presented.frame || player.presented.pts < target - .002) &&
Clock::now() - start < std::chrono::seconds(5))
player.tick();
const double elapsed = std::chrono::duration<double, std::milli>(Clock::now() - start).count();
std::printf("local-seek fixture=%s playing=%d target=%.3f preview=%.3f latency_ms=%.3f\n",
argv[i], playing, target, player.presented.pts, elapsed);
require(player.presented.frame && player.presented.pts == expected.pts &&
pixels(player.presented.frame.get()) == pixels(expected.frame.get()),
"seek presents the exact fully decoded picture, including B-frame targets");
require(player.status == (playing ? PLAYER_PLAYING : PLAYER_PAUSED),
"seek preserves playback intent");
}
}
}
}