Reproduce media cursor revision admission inconsistency
This commit is contained in:
1 parent
84472cc276
commit
afa8fd307a
2 files changed
+78
-2
No files matched your search
@@ -4,6 +4,18 @@
|
|||||||
|
|
||||||
## Текущие задачи
|
## Текущие задачи
|
||||||
|
|
||||||
|
[ ] **Live: согласовать выдачу cursor с проверкой revision/KEY в media store** — 14.10.2026:
|
||||||
|
При переносе тестов старого stream_media_receiver на рабочий store/cursor выявлено расхождение:
|
||||||
|
после KEY revision=1, неполного кадра revision=1 и обычного кадра revision=2 индекс остаётся на старом PTS,
|
||||||
|
но cursor выдаёт кадр revision=2 без KEY. Desktop отбрасывает его собственной проверкой waitKey.
|
||||||
|
Воспроизведение: `make -C tests test_stream_media`, затем `tests/test_stream_media --revision-transition`.
|
||||||
|
Диагностический режим намеренно падает: indexed_video_us=1000000, result=0, revision=2, frame=3, flags=0.
|
||||||
|
Обычный запуск test_stream_media сохраняет прежние проверки; старый receiver пока не удалён.
|
||||||
|
Согласовать допуск видео в store/cursor без сброса аудио и без запрета старой revision отстающим readers;
|
||||||
|
проверить фрагменты, KEY, GAP и чтение истории. После исправления включить регрессию в обычный запуск,
|
||||||
|
перенести остальные тесты receiver на store/cursor и удалить неиспользуемый API.
|
||||||
|
Продолжение архитектурного плана: общий viewer reader, измерение запросов кандидатов, граница relay/network.
|
||||||
|
|
||||||
[+] **Live: прямое превью Android без собственного decoder** — 14.10.2026:
|
[+] **Live: прямое превью Android без собственного decoder** — 14.10.2026:
|
||||||
Камера одновременно выводит в encoder Surface и TextureView; собственное превью больше не открывает
|
Камера одновременно выводит в encoder Surface и TextureView; собственное превью больше не открывает
|
||||||
stream viewer/cursor, MediaCodec decoder, AudioTrack и адаптивные часы воспроизведения.
|
stream viewer/cursor, MediaCodec decoder, AudioTrack и адаптивные часы воспроизведения.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "../lib/u_async.h"
|
#include "../lib/u_async.h"
|
||||||
#include "../src/stream/stream_source.h"
|
#include "../src/stream/stream_source.h"
|
||||||
#include "../src/stream/stream_media.h"
|
#include "../src/stream/stream_media.h"
|
||||||
|
#include "../src/stream/stream_media_buffer.h"
|
||||||
|
|
||||||
#define CHECK(x) do { if (!(x)) { debug_set_category_level(DEBUG_CATEGORY_STREAM, DEBUG_LEVEL_ERROR); DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream media test line=%d: %s", __LINE__, #x); exit(1); } } while (0)
|
#define CHECK(x) do { if (!(x)) { debug_set_category_level(DEBUG_CATEGORY_STREAM, DEBUG_LEVEL_ERROR); DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "stream media test line=%d: %s", __LINE__, #x); exit(1); } } while (0)
|
||||||
|
|
||||||
@@ -224,13 +225,76 @@ static void test_codecs(void) {
|
|||||||
memset(key, 0, 4); CHECK(stream_media_key_parse(key, sizeof(key), &config, &config_size, &frame, &frame_size) == STREAM_OK);
|
memset(key, 0, 4); CHECK(stream_media_key_parse(key, sizeof(key), &config, &config_size, &frame, &frame_size) == STREAM_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
struct media_fixture {
|
||||||
|
struct stream_encoder *encoder;
|
||||||
|
struct stream_buffer *buffer;
|
||||||
|
struct stream_media_store *store;
|
||||||
|
struct stream_media_cursor *cursor;
|
||||||
|
uint64_t seq;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void media_fixture_open(struct media_fixture *f) {
|
||||||
|
struct stream_descriptor d = {.group_id = 1, .source_node_id = 2, .source_epoch = 3,
|
||||||
|
.n = 8, .r = 2, .block_size = STREAM_RS_DEFAULT_SIZE};
|
||||||
|
uint8_t key[32] = {1}; memset(f, 0, sizeof(*f));
|
||||||
|
CHECK(stream_encoder_create(&f->encoder, &d, key) == STREAM_OK);
|
||||||
|
CHECK(stream_buffer_create(&f->buffer, &d, stream_encoder_public_key(f->encoder), 128 * 1300) == STREAM_OK);
|
||||||
|
CHECK(stream_media_store_create(&f->store, f->buffer, &d) == STREAM_OK);
|
||||||
|
CHECK(stream_media_cursor_create(&f->cursor, f->store, STREAM_MEDIA_TRACK_VIDEO | STREAM_MEDIA_TRACK_AUDIO) == STREAM_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void media_fixture_close(struct media_fixture *f) {
|
||||||
|
stream_media_cursor_destroy(f->cursor); stream_media_store_destroy(f->store);
|
||||||
|
stream_buffer_destroy(f->buffer); stream_encoder_destroy(f->encoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Проверяем настоящий путь: сериализация, RS-кольцо, проверка подписи, индекс и независимый cursor. */
|
||||||
|
static int media_fixture_feed(struct media_fixture *f, const struct stream_media_block *b) {
|
||||||
|
uint8_t wire[7080], decoded[7080]; size_t length = 0, part_size = 0, decoded_size = 0;
|
||||||
|
const uint8_t *parts[RS_MAX_BLOCKS];
|
||||||
|
CHECK(stream_media_encode(b, wire, sizeof(wire), &length) == STREAM_OK);
|
||||||
|
CHECK(stream_encoder_encode(f->encoder, f->seq, 1, 0, wire, length, parts, &part_size) == STREAM_OK);
|
||||||
|
for (unsigned i = 0; i < 6; i++) CHECK(stream_buffer_put(f->buffer, parts[i], part_size) == STREAM_OK);
|
||||||
|
CHECK(stream_buffer_decode(f->buffer, f->seq, decoded, sizeof(decoded), &decoded_size) == STREAM_OK);
|
||||||
|
CHECK(length == decoded_size && !memcmp(wire, decoded, length));
|
||||||
|
return stream_media_store_feed(f->store, f->seq++, decoded, decoded_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Диагностика расхождения store/cursor; отдельный запуск --revision-transition до согласования контракта. */
|
||||||
|
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};
|
||||||
|
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 && packet.format.revision == 1);
|
||||||
|
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};
|
||||||
|
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);
|
||||||
|
media_fixture_close(&f);
|
||||||
|
CHECK(result == STREAM_WAIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO);
|
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO);
|
||||||
/* Усечения проверяются массово; ожидаемые отказы не загромождают диагностический лог. */
|
/* Усечения проверяются массово; ожидаемые отказы не загромождают диагностический лог. */
|
||||||
debug_set_category_level(DEBUG_CATEGORY_STREAM, DEBUG_LEVEL_DISABLED);
|
debug_set_category_level(DEBUG_CATEGORY_STREAM, DEBUG_LEVEL_DISABLED);
|
||||||
size_t before = u_get_allocated_count();
|
size_t before = u_get_allocated_count();
|
||||||
for (unsigned i = 0; i < sizeof(expected_video); i++) expected_video[i] = (uint8_t)(i * 31 + 7);
|
for (unsigned i = 0; i < sizeof(expected_video); i++) expected_video[i] = (uint8_t)(i * 31 + 7);
|
||||||
test_media(); test_batches(); test_revisions(); test_stereo(); test_codecs();
|
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();
|
||||||
|
} else {
|
||||||
|
CHECK(argc == 1);
|
||||||
|
test_media(); test_batches(); test_revisions(); test_stereo(); test_codecs();
|
||||||
|
}
|
||||||
CHECK(u_get_allocated_count() == before);
|
CHECK(u_get_allocated_count() == before);
|
||||||
debug_set_category_level(DEBUG_CATEGORY_STREAM, DEBUG_LEVEL_INFO);
|
debug_set_category_level(DEBUG_CATEGORY_STREAM, DEBUG_LEVEL_INFO);
|
||||||
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "PASS stream_media: protocol, FEC, frame recovery, boundaries, no leaks");
|
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "PASS stream_media: protocol, FEC, frame recovery, boundaries, no leaks");
|
||||||
|
|||||||
Reference in new issue
Block a user