fix: skip disposable pictures during local seek preroll
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user