From 7e693fcc97689993c130ee55e8e16232cf7c5de3 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 14 Oct 2026 01:06:32 +0200 Subject: [PATCH] Define uAV2 codec IDs and signed keyframe configuration envelopes --- src/stream/stream_media.c | 22 ++++++++++++++++++---- src/stream/stream_media.h | 13 +++++++++++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/stream/stream_media.c b/src/stream/stream_media.c index 6ac28bea..549a3ac6 100644 --- a/src/stream/stream_media.c +++ b/src/stream/stream_media.c @@ -18,7 +18,8 @@ struct stream_media_receiver { /* Проверить весь набор описаний до чтения payload или выделения памяти под кадр. */ static int media_validate(const struct stream_media_block *b, size_t *video_size, size_t *audio_size, uint32_t *first) { if (!b || b->video_count > STREAM_MEDIA_MAX_ENTRIES || b->audio_count > STREAM_MEDIA_MAX_ENTRIES - || !b->format.revision || (!b->video_count && !b->audio_count) || b->format.video_codec != STREAM_MEDIA_H264 + || !b->format.revision || (!b->video_count && !b->audio_count) + || b->format.video_codec < STREAM_MEDIA_H264 || b->format.video_codec > STREAM_MEDIA_H266 || b->format.audio_codec > STREAM_MEDIA_OPUS_STEREO || !b->format.width || b->format.width > 4096 || !b->format.height || b->format.height > 4096 || b->format.rotation > 270 || b->format.rotation % 90) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media format/count invalid present=%d video=%u audio=%u codecs=%u/%u dimensions=%ux%u rotation=%u", @@ -76,7 +77,7 @@ int stream_media_encode(const struct stream_media_block *b, uint8_t *output, siz DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media encode capacity=%zu needed=%zu", capacity, total); return STREAM_ERR_ARGUMENT; } memset(output, 0, header); - memcpy(output, "uAV1", 4); + memcpy(output, "uAV2", 4); output[4] = b->format.video_codec; output[5] = b->format.audio_codec; output[6] = (uint8_t)b->video_count; output[7] = (uint8_t)b->audio_count; stream_write_be(output + 8, b->format.width, 2); stream_write_be(output + 10, b->format.height, 2); @@ -103,7 +104,7 @@ int stream_media_encode(const struct stream_media_block *b, uint8_t *output, siz /* Проверить арифметику областей до вычисления указателей, затем валидировать все описания. */ int stream_media_parse(const uint8_t *data, size_t length, struct stream_media_block *out) { - if (!data || !out || length < STREAM_MEDIA_HEADER_SIZE || length > STREAM_MEDIA_MAX_BLOCK || memcmp(data, "uAV1", 4)) { + if (!data || !out || length < STREAM_MEDIA_HEADER_SIZE || length > STREAM_MEDIA_MAX_BLOCK || memcmp(data, "uAV2", 4)) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media parse bad prefix/length=%zu", length); return STREAM_ERR_FORMAT; } struct stream_media_block b = {.video_count = data[6], .audio_count = data[7]}; @@ -151,6 +152,19 @@ int stream_media_parse(const uint8_t *data, size_t length, struct stream_media_b return STREAM_OK; } +int stream_media_key_parse(const uint8_t *data, size_t length, const uint8_t **config, size_t *config_length, + const uint8_t **frame, size_t *frame_length) { + if (!data || length < 5 || length > STREAM_MEDIA_MAX_FRAME || !config || !config_length || !frame || !frame_length) { + DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "KEY envelope invalid length=%zu", length); return STREAM_ERR_FORMAT; + } + size_t n = (size_t)stream_read_be(data, 4); + if (n > STREAM_MEDIA_MAX_CONFIG || n >= length - 4) { + DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "KEY configuration invalid config=%zu total=%zu", n, length); return STREAM_ERR_FORMAT; + } + *config = data + 4; *config_length = n; *frame = data + 4 + n; *frame_length = length - 4 - n; + return STREAM_OK; +} + /* Receiver имеет один ограниченный буфер; ожидание KEY не мешает доставке независимого аудио. */ int stream_media_receiver_create(struct stream_media_receiver **out, stream_media_frame_fn callback, void *arg) { if (!out || *out || !callback) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media receiver create invalid arguments"); return STREAM_ERR_ARGUMENT; } @@ -180,7 +194,7 @@ int stream_media_receiver_feed(struct stream_media_receiver *r, const uint8_t *d return STREAM_OK; } if (r->configured && (r->format.audio_codec != b.format.audio_codec - || (r->format.revision == b.format.revision && (r->format.width != b.format.width + || (r->format.revision == b.format.revision && (r->format.video_codec != b.format.video_codec || r->format.width != b.format.width || r->format.height != b.format.height || r->format.rotation != b.format.rotation)))) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media conflicting configuration revision=%u/%u dimensions=%ux%u/%ux%u rotation=%u/%u audio=%u/%u", r->format.revision, b.format.revision, r->format.width, r->format.height, b.format.width, b.format.height, diff --git a/src/stream/stream_media.h b/src/stream/stream_media.h index a8d0728c..7134cddf 100644 --- a/src/stream/stream_media.h +++ b/src/stream/stream_media.h @@ -1,8 +1,9 @@ -/* Медиаблок внутри одной FEC-пачки: big-endian, uAV1, fixed header(32), +/* Медиаблок внутри одной FEC-пачки: big-endian, uAV2, fixed header(32), * video descriptors(32 each), audio descriptors(16 each), video bytes, audio bytes. * video descriptor: frame_id:8, PTS_us:8, frame_size:4, fragment_offset:4, length:4, flags:1, reserved:3. * audio descriptor: PTS_us:8, length:4, samples:2, reserved:2. Opus: 48kHz mono/stereo, 960 frames/channel. - * H.264 Annex B; полный ключевой кадр включает SPS/PPS. Видео меняется по revision; аудиотрек фиксирован на source_epoch. + * KEY payload: config_length:4BE, codec configuration, access unit. Остальные кадры — access unit. + * Видео меняется по revision; аудиотрек фиксирован на source_epoch. Конфигурация защищена общей подписью/RS. * first_frame_offset относится к video bytes; UINT32_MAX означает отсутствие начала кадра. * Parser проверяет весь блок до публикации view. Receiver собирает один кадр, после GAP ждёт KEY. * Все вызовы одного контекста последовательны; callbacks заимствуют данные до возврата, без reentry. */ @@ -24,6 +25,11 @@ extern "C" { #define STREAM_MEDIA_MAX_OPUS 1275u #define STREAM_MEDIA_KEY 1 #define STREAM_MEDIA_H264 1 +#define STREAM_MEDIA_H265 2 +#define STREAM_MEDIA_VP9 3 +#define STREAM_MEDIA_AV1 4 +#define STREAM_MEDIA_H266 5 +#define STREAM_MEDIA_MAX_CONFIG 65536u #define STREAM_MEDIA_OPUS 1 #define STREAM_MEDIA_OPUS_STEREO 2 @@ -46,6 +52,9 @@ struct stream_media_block { /* Encode не меняет output/length при отказе; данные не перекрывают output. */ int stream_media_encode(const struct stream_media_block *block, uint8_t *output, size_t capacity, size_t *length); int stream_media_parse(const uint8_t *data, size_t length, struct stream_media_block *block); +/* Разобрать только полностью собранный KEY; указатели заимствованы из data. */ +int stream_media_key_parse(const uint8_t *data, size_t length, const uint8_t **config, size_t *config_length, + const uint8_t **frame, size_t *frame_length); struct stream_media_receiver; /* video=NULL означает один Opus-пакет; audio=NULL — полный H.264 кадр. */