Gate media cursor revision changes on a complete keyframe
This commit is contained in:
1 parent
afa8fd307a
commit
d209ab94ba
2 files changed
+101
-17
No files matched your search
+80
-10
@@ -260,26 +260,94 @@ static int media_fixture_feed(struct media_fixture *f, const struct stream_media
|
||||
return stream_media_store_feed(f->store, f->seq++, decoded, decoded_size);
|
||||
}
|
||||
|
||||
/* Диагностика расхождения store/cursor; отдельный запуск --revision-transition до согласования контракта. */
|
||||
/* Новая revision начинается с целого KEY; аудио и отстающий reader сохраняют собственные позиции. */
|
||||
static void test_revision_transition(void) {
|
||||
struct media_fixture f; media_fixture_open(&f);
|
||||
struct stream_media_block b = {.format = {1280, 720, 90, STREAM_MEDIA_H264, 0, 1}, .video_count = 1};
|
||||
struct stream_media_block b = {.format = {1280, 720, 90, STREAM_MEDIA_H264, STREAM_MEDIA_OPUS_STEREO, 1},
|
||||
.video_count = 1, .audio_count = 1};
|
||||
b.video[0] = (struct stream_media_video){1, 1000000, 12, 0, 12, STREAM_MEDIA_KEY, expected_video};
|
||||
b.audio[0] = (struct stream_media_audio){1000000, 3, 960, (const uint8_t *)"ops"};
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
struct stream_media_packet packet;
|
||||
struct stream_media_packet packet; struct stream_media_status status; struct stream_media_cursor *slow = NULL;
|
||||
CHECK(stream_media_cursor_create(&slow, f.store, STREAM_MEDIA_TRACK_VIDEO) == STREAM_OK);
|
||||
CHECK(stream_media_cursor_status(slow, &status) == STREAM_OK && status.initialized);
|
||||
CHECK(stream_media_cursor_read(f.cursor, -1, 1, -1, &packet) == STREAM_OK && packet.format.revision == 1);
|
||||
b.audio_count = 0;
|
||||
b.video[0] = (struct stream_media_video){2, 1040000, 12, 0, 6, 0, expected_video};
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
b.format = (struct stream_media_format){1920, 1080, 270, STREAM_MEDIA_H264, 0, 2};
|
||||
CHECK(stream_media_cursor_read(f.cursor, 1000000, 1, -1, &packet) == STREAM_WAIT);
|
||||
b.format = (struct stream_media_format){1920, 1080, 270, STREAM_MEDIA_H264, STREAM_MEDIA_OPUS_STEREO, 2};
|
||||
b.video[0] = (struct stream_media_video){3, 1080000, 12, 0, 12, 0, expected_video};
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
struct stream_media_status status;
|
||||
CHECK(stream_media_cursor_status(f.cursor, &status) == STREAM_OK && status.video_us == 1000000);
|
||||
int result = stream_media_cursor_read(f.cursor, 1000000, 1, -1, &packet);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "revision transition before KEY: indexed_video_us=%lld result=%d kind=%d revision=%u frame=%llu flags=%u",
|
||||
(long long)status.video_us, result, packet.kind, packet.format.revision, (unsigned long long)packet.video.frame_id, packet.video.flags);
|
||||
CHECK(stream_media_cursor_read(f.cursor, 1000000, 1, -1, &packet) == STREAM_WAIT);
|
||||
CHECK(stream_media_cursor_read(f.cursor, 1000000, 0, 0, &packet) == STREAM_OK && packet.kind == STREAM_MEDIA_READ_AUDIO);
|
||||
CHECK(packet.audio.pts_us == 1000000 && packet.format.audio_codec == STREAM_MEDIA_OPUS_STEREO);
|
||||
b.video_count = 0; b.audio_count = 1; b.audio[0].pts_us = 1020000;
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
CHECK(stream_media_cursor_read(f.cursor, 1020000, 0, 0, &packet) == STREAM_OK && packet.kind == STREAM_MEDIA_READ_AUDIO);
|
||||
CHECK(packet.audio.pts_us == 1020000);
|
||||
b.video_count = 1; b.audio_count = 0;
|
||||
b.video[0] = (struct stream_media_video){4, 1120000, 12, 0, 6, STREAM_MEDIA_KEY, expected_video};
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
CHECK(stream_media_cursor_read(f.cursor, 1000000, 1, -1, &packet) == STREAM_WAIT);
|
||||
b.video[0].offset = 6; b.video[0].data = expected_video + 6;
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
CHECK(stream_media_cursor_read(f.cursor, 1000000, 1, -1, &packet) == STREAM_OK && packet.kind == STREAM_MEDIA_READ_VIDEO);
|
||||
CHECK(packet.format.revision == 2 && packet.video.frame_id == 4 && packet.video.flags == STREAM_MEDIA_KEY);
|
||||
CHECK(packet.video.length == 12 && !memcmp(packet.video.data, expected_video, 12));
|
||||
CHECK(stream_media_cursor_read(slow, -1, 1, -1, &packet) == STREAM_OK && packet.format.revision == 1);
|
||||
CHECK(stream_media_cursor_read(slow, 1000000, 1, -1, &packet) == STREAM_OK && packet.format.revision == 2);
|
||||
CHECK(packet.video.frame_id == 4);
|
||||
/* Полный KEY новой конфигурации выдаётся сразу, без таймера и искусственной задержки. */
|
||||
b.format.revision = 3; b.video[0] = (struct stream_media_video){5, 1160000, 12, 0, 12, STREAM_MEDIA_KEY, expected_video};
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
CHECK(stream_media_cursor_read(f.cursor, 1120000, 1, -1, &packet) == STREAM_OK && packet.format.revision == 3);
|
||||
CHECK(packet.video.frame_id == 5 && packet.video.flags == STREAM_MEDIA_KEY);
|
||||
stream_media_cursor_destroy(slow);
|
||||
media_fixture_close(&f);
|
||||
CHECK(result == STREAM_WAIT);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "PASS cursor revisions: missing/fragmented KEY, immediate complete KEY, independent audio and history");
|
||||
}
|
||||
|
||||
/* Пропущенный блок, нарушенные фрагменты и вытеснение запрещают P-кадры до нового целого KEY. */
|
||||
static void test_cursor_key_recovery(void) {
|
||||
for (unsigned failure = 0; failure < 3; failure++) {
|
||||
struct media_fixture f; media_fixture_open(&f);
|
||||
struct stream_media_block b = {.format = {1280, 720, 0, STREAM_MEDIA_H264, 0, 1}, .video_count = 1};
|
||||
b.video[0] = (struct stream_media_video){1, 1000000, 12, 0, 12, STREAM_MEDIA_KEY, expected_video};
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
struct stream_media_packet packet;
|
||||
CHECK(stream_media_cursor_read(f.cursor, -1, 1, -1, &packet) == STREAM_OK);
|
||||
b.video[0] = (struct stream_media_video){2, 1040000, 12, 0, 6, 0, expected_video};
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
CHECK(stream_media_cursor_read(f.cursor, 1000000, 1, -1, &packet) == STREAM_WAIT);
|
||||
if (failure == 0) { stream_media_store_gap(f.store, f.seq, f.seq); f.seq++; }
|
||||
else if (failure == 1) {
|
||||
b.video[0].offset = 5; b.video[0].data = expected_video + 5;
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
} else {
|
||||
for (unsigned i = 0; i < 48; i++) {
|
||||
b.video[0] = (struct stream_media_video){3 + i, 1080000 + i * 40000, 12, 0, 12, 0, expected_video};
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
}
|
||||
}
|
||||
int result = stream_media_cursor_read(f.cursor, 1000000, 1, -1, &packet);
|
||||
CHECK(result == (failure == 2 ? STREAM_EXPIRED : STREAM_GAP));
|
||||
stream_media_cursor_reset(f.cursor);
|
||||
b.video[0] = (struct stream_media_video){100, 4000000, 12, 0, 12, 0, expected_video};
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
CHECK(stream_media_cursor_read(f.cursor, -1, 1, -1, &packet) == STREAM_WAIT);
|
||||
b.video[0] = (struct stream_media_video){101, 4040000, 12, 0, 6, STREAM_MEDIA_KEY, expected_video};
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
CHECK(stream_media_cursor_read(f.cursor, -1, 1, -1, &packet) == STREAM_WAIT);
|
||||
b.video[0].offset = 6; b.video[0].data = expected_video + 6;
|
||||
CHECK(media_fixture_feed(&f, &b) == STREAM_OK);
|
||||
CHECK(stream_media_cursor_read(f.cursor, -1, 1, -1, &packet) == STREAM_OK && packet.kind == STREAM_MEDIA_READ_VIDEO);
|
||||
CHECK(packet.video.frame_id == 101 && packet.video.flags == STREAM_MEDIA_KEY && packet.video.length == 12);
|
||||
CHECK(!memcmp(packet.video.data, expected_video, 12));
|
||||
media_fixture_close(&f);
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "PASS cursor recovery: GAP, fragment discontinuity and expiry resume only from a complete KEY");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
@@ -290,10 +358,12 @@ int main(int argc, char **argv) {
|
||||
for (unsigned i = 0; i < sizeof(expected_video); i++) expected_video[i] = (uint8_t)(i * 31 + 7);
|
||||
if (argc == 2 && !strcmp(argv[1], "--revision-transition")) {
|
||||
debug_set_level(DEBUG_LEVEL_ERROR); debug_set_category_level(DEBUG_CATEGORY_STREAM, DEBUG_LEVEL_DEBUG);
|
||||
test_revision_transition();
|
||||
test_revision_transition(); test_cursor_key_recovery();
|
||||
} else {
|
||||
CHECK(argc == 1);
|
||||
test_media(); test_batches(); test_revisions(); test_stereo(); test_codecs();
|
||||
debug_set_category_level(DEBUG_CATEGORY_STREAM, DEBUG_LEVEL_INFO);
|
||||
test_revision_transition(); test_cursor_key_recovery();
|
||||
}
|
||||
CHECK(u_get_allocated_count() == before);
|
||||
debug_set_category_level(DEBUG_CATEGORY_STREAM, DEBUG_LEVEL_INFO);
|
||||
|
||||
Reference in new issue
Block a user