Remove unused media receiver and test the shared ring cursor

This commit is contained in:
evgeny committed 2026-10-14 16:24:32 +02:00
1 parent d209ab94ba
commit d75aea1a09
3 files changed
+29 -223

No files matched your search

-98
View File
@@ -1,19 +1,8 @@
#include <string.h>
#include "../../lib/debug_config.h"
#include "../../lib/mem.h"
#include "stream_media.h"
struct stream_media_receiver {
stream_media_frame_fn callback;
void *arg;
struct stream_media_format format;
struct stream_media_video frame;
uint8_t *data;
uint32_t used;
uint64_t last_video_pts, last_audio_pts, last_frame_id;
int configured, waiting_key, video_seen, audio_seen;
};
/* Проверить весь набор описаний до чтения payload или выделения памяти под кадр. */
static int media_validate(const struct stream_media_block *b, size_t *video_size, size_t *audio_size, uint32_t *first) {
@@ -165,90 +154,3 @@ int stream_media_key_parse(const uint8_t *data, size_t length, const uint8_t **c
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; }
struct stream_media_receiver *r = u_calloc(1, sizeof(*r));
if (!r) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media receiver allocation failed"); return STREAM_ERR_MEMORY; }
r->callback = callback; r->arg = arg; r->waiting_key = 1; *out = r;
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "media receiver created frame_limit=%u", STREAM_MEDIA_MAX_FRAME);
return STREAM_OK;
}
/* Сбросить недособранный кадр и зависимые P-кадры; PTS-история сохраняется в пределах эпохи. */
void stream_media_receiver_gap(struct stream_media_receiver *r) {
if (!r) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media receiver gap missing context"); return; }
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "media receiver GAP frame=%llu used=%u/%u; waiting for KEY",
(unsigned long long)r->frame.frame_id, r->used, r->frame.frame_size);
u_free(r->data); r->data = NULL; r->used = 0; r->waiting_key = 1;
}
/* Только полный последовательный кадр допускается в декодер; никакого склеивания через GAP. */
int stream_media_receiver_feed(struct stream_media_receiver *r, const uint8_t *data, size_t length) {
if (!r) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media receiver feed missing context"); return STREAM_ERR_ARGUMENT; }
struct stream_media_block b;
int result = stream_media_parse(data, length, &b);
if (result != STREAM_OK) { stream_media_receiver_gap(r); return result; }
if (r->configured && b.format.revision < r->format.revision) {
DEBUG_WARN(DEBUG_CATEGORY_STREAM, "media stale revision=%u current=%u", b.format.revision, r->format.revision);
return STREAM_OK;
}
if (r->configured && (r->format.audio_codec != b.format.audio_codec
|| (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,
r->format.rotation, b.format.rotation, r->format.audio_codec, b.format.audio_codec);
stream_media_receiver_gap(r); return STREAM_ERR_CONFLICT;
}
if (r->configured && b.format.revision > r->format.revision) {
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "media video configuration revision=%u->%u dimensions=%ux%u rotation=%u; preserve audio",
r->format.revision, b.format.revision, b.format.width, b.format.height, b.format.rotation);
stream_media_receiver_gap(r);
}
r->format = b.format; r->configured = 1;
for (unsigned i = 0; i < b.video_count; i++) {
const struct stream_media_video *v = &b.video[i];
if (!v->offset) {
if (r->data) stream_media_receiver_gap(r);
if (r->video_seen && (v->pts_us <= r->last_video_pts || v->frame_id <= r->last_frame_id)) {
DEBUG_WARN(DEBUG_CATEGORY_STREAM, "media stale video frame=%llu", (unsigned long long)v->frame_id); continue;
}
if (r->waiting_key && !(v->flags & STREAM_MEDIA_KEY)) continue;
r->data = u_malloc(v->frame_size);
if (!r->data) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "media frame allocation failed bytes=%u", v->frame_size); return STREAM_ERR_MEMORY; }
r->frame = *v; r->used = 0;
}
if (!r->data) continue;
if (v->frame_id != r->frame.frame_id || v->pts_us != r->frame.pts_us || v->frame_size != r->frame.frame_size
|| v->flags != r->frame.flags || v->offset != r->used) {
DEBUG_WARN(DEBUG_CATEGORY_STREAM, "media fragment discontinuity frame=%llu offset=%u expected=%u",
(unsigned long long)v->frame_id, v->offset, r->used);
stream_media_receiver_gap(r); continue;
}
memcpy(r->data + r->used, v->data, v->length); r->used += v->length;
if (r->used == r->frame.frame_size) {
r->frame.data = r->data; r->frame.length = r->used; r->frame.offset = 0;
if (r->waiting_key) DEBUG_INFO(DEBUG_CATEGORY_STREAM, "media decoder resumes KEY frame=%llu pts=%llu bytes=%u",
(unsigned long long)v->frame_id, (unsigned long long)v->pts_us, r->used);
r->waiting_key = 0; r->video_seen = 1; r->last_video_pts = v->pts_us; r->last_frame_id = v->frame_id;
r->callback(r->arg, &r->format, &r->frame, NULL);
u_free(r->data); r->data = NULL; r->used = 0;
}
}
for (unsigned i = 0; i < b.audio_count; i++) {
const struct stream_media_audio *a = &b.audio[i];
if (r->audio_seen && a->pts_us <= r->last_audio_pts) {
DEBUG_WARN(DEBUG_CATEGORY_STREAM, "media stale audio pts=%llu", (unsigned long long)a->pts_us); continue;
}
r->audio_seen = 1; r->last_audio_pts = a->pts_us; r->callback(r->arg, &r->format, NULL, a);
}
return STREAM_OK;
}
/* Освободить только собственный буфер, не заимствованные данные callback. */
void stream_media_receiver_destroy(struct stream_media_receiver *r) {
if (!r) return;
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "media receiver destroy pending=%u waiting_key=%d", r->used, r->waiting_key);
u_free(r->data); u_free(r);
}
+2 -11
View File
@@ -5,8 +5,8 @@
* 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. */
* Parser проверяет весь блок до публикации view, указатели view заимствованы из входного блока.
* Сборка кадров и восстановление после GAP/revision выполняются store/cursor из stream_media_buffer.h. */
#ifndef STREAM_MEDIA_H
#define STREAM_MEDIA_H
@@ -56,15 +56,6 @@ int stream_media_parse(const uint8_t *data, size_t length, struct stream_media_b
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 кадр. */
typedef void (*stream_media_frame_fn)(void *arg, const struct stream_media_format *format,
const struct stream_media_video *video, const struct stream_media_audio *audio);
int stream_media_receiver_create(struct stream_media_receiver **out, stream_media_frame_fn callback, void *arg);
void stream_media_receiver_gap(struct stream_media_receiver *receiver);
int stream_media_receiver_feed(struct stream_media_receiver *receiver, const uint8_t *data, size_t length);
void stream_media_receiver_destroy(struct stream_media_receiver *receiver);
#ifdef __cplusplus
}
#endif