Browse Source

Define uAV2 codec IDs and signed keyframe configuration envelopes

master
evgeny 6 days ago
parent
commit
7e693fcc97
  1. 22
      src/stream/stream_media.c
  2. 13
      src/stream/stream_media.h

22
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,

13
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 кадр. */

Loading…
Cancel
Save