fa6ab3069a
Несколько сессий попыток реализовать audio mixing в композитор'е.
Не достигнуто sub-секундной latency со стабильным video+audio.
Откатано на parallel mode (cfc-grid video-only, live от pipeline с audio).
Полный набор выводов и pitfall'ов — docs/LESSONS-audio-mixing-attempts.md.
Главные lesson'ы для будущей попытки:
- mpegts mux libavformat авто-инсёртит h264_mp4toannexb BSF которому
не нравится Annex-B + inline SPS/PPS — NVENC OUTPUT_SPSPPS per-frame ломает
- SPSC ring drop newest при full, не oldest (consumer's domain)
- av_new_packet (не av_malloc) для av_interleaved_write_frame ownership
- Monotonic PTS на counter (frame_idx, total_samples) — не wallclock
- mediamtx env-var path names не должны иметь '-' (parser limitation)
- Default mediamtx ReadTimeout=10s короткий для burst write'ов
Изменения в repo сохранены для будущей доработки:
- src/writer.c — mpegts backend с audio stream support
- src/audio.c — RTSP AAC consumer + lock-free SPSC ring
- include/cuframes_composer/{writer,audio}.h — public API
- examples/grid_record.c — --format=mpegts + --audio-source flags
- include/cuframes_composer/composer.h — consumer_prefix field
- docker/Dockerfile — libavformat-dev добавлен в builder/runtime
cfc-grid composer стабильно работает на видео (substantially лучше
монолитного pipeline'а с audio bag'ом). TV рекомендуется использовать
rtsp://...:554/cfc-grid + опционально rtsp://...:554/live-audio
parallel.
67 lines
2.4 KiB
C
67 lines
2.4 KiB
C
/* cuframes-composer — audio consumer (Phase 7).
|
||
*
|
||
* Открывает RTSP-вход с AAC stream'ом (от cuda-grid-audio через mediamtx
|
||
* либо прямо с микрофона). В отдельном thread'е читает packet'ы и кладёт
|
||
* в lock-free SPSC ring buffer. Video-thread (composer main loop) drain'ит
|
||
* ring и пишет audio packet'ы в общий mpegts muxer через
|
||
* cfc_writer_write_audio.
|
||
*
|
||
* Architecture:
|
||
* audio_thread: avformat_open_input → av_read_frame loop → push to ring
|
||
* main thread (video): cfc_audio_drain → cfc_writer_write_audio loop
|
||
*
|
||
* Failure mode: если RTSP source падает, audio_thread пытается reconnect
|
||
* с exponential backoff. Video не блокируется.
|
||
*
|
||
* Лицензия: LGPL-2.1+
|
||
*/
|
||
|
||
#ifndef CUFRAMES_COMPOSER_AUDIO_H
|
||
#define CUFRAMES_COMPOSER_AUDIO_H
|
||
|
||
#include "writer.h"
|
||
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
typedef struct cfc_audio_config {
|
||
const char *rtsp_url; /* "rtsp://mediamtx:8554/live-audio" */
|
||
int reconnect_min_ms; /* default 1000 */
|
||
int reconnect_max_ms; /* default 10000 */
|
||
} cfc_audio_config_t;
|
||
|
||
typedef struct cfc_audio cfc_audio_t;
|
||
|
||
/* Создать audio consumer + запустить background thread.
|
||
* Получает первый packet и сохраняет codec params (sample_rate, channels,
|
||
* extradata) — caller потом передаёт их в cfc_writer_config_t. */
|
||
int cfc_audio_create(const cfc_audio_config_t *cfg, cfc_audio_t **out);
|
||
|
||
/* Получить codec params (заполняется после первого успешного read).
|
||
* Возвращает 0 если params уже доступны, -1 если ещё нет. Caller может
|
||
* polling'ом ждать. */
|
||
int cfc_audio_get_codec_params(
|
||
cfc_audio_t *a,
|
||
int *sample_rate,
|
||
int *channels,
|
||
const uint8_t **extradata,
|
||
size_t *extradata_size
|
||
);
|
||
|
||
/* Drain до N audio packet'ов в writer. Не блокируется. Возвращает число
|
||
* записанных packet'ов. */
|
||
int cfc_audio_drain(cfc_audio_t *a, cfc_writer_t *writer, int max_packets);
|
||
|
||
/* Остановить thread + освободить ресурсы. */
|
||
int cfc_audio_destroy(cfc_audio_t *a);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* CUFRAMES_COMPOSER_AUDIO_H */
|