Define uAV2 codec IDs and signed keyframe configuration envelopes
This commit is contained in:
1 parent
84246bea89
commit
7e693fcc97
2 files changed
+29
-6
No files matched your search
@@ -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,
|
||||
|
||||
@@ -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 кадр. */
|
||||
|
||||
Reference in new issue
Block a user