ba68550f4c
Скелет проекта cuframes-composer (LGPL-2.1+) и MVP кодирования
одного источника в файл H.264.
Что включает Phase 1:
- LICENSE (LGPL-2.1+), README с поэтапным планом, корневой CMake
- Подмодули: cuframes v0.4 (pinned), nv-codec-headers (n12.2.72.0)
- include/cuframes_composer/source.h — публичный API источника
с явной машиной состояний (DISCONNECTED → CONNECTING → ACTIVE →
STALE → DEAD) и snapshot-паттерном для чтения без блокировки
- include/cuframes_composer/nvenc.h — публичный API кодировщика
на CUdeviceptr-вход (zero-copy через VMM-mapped указатели)
- src/nvenc_loader.{h,c} — dlopen libnvidia-encode.so.1 и инициализация
таблицы функций NVENC через NvEncodeAPICreateInstance. Идёт через
pthread_once. Сделано отдельно чтобы держать LGPL-совместимость:
проприетарный SDK не статически линкуется
- src/nvenc.c — обвязка над NVENC: open session, init encoder, кеш
registered resources, encode/lock/unlock, flush с EOS, поддержка
H.264 CBR low-latency, preset GUID p1/p4/p7
- src/source.c — обвязка над cuframes_subscriber c фоновым потоком,
exponential backoff reconnect (1с → 30с), и переходами по таймаутам
для stale/dead-детекта
- examples/simple_record — smoke-test программа: подписка на cuframes,
кодирование, запись в .h264 файл, корректное завершение по SIGINT
108 lines
5.4 KiB
C
108 lines
5.4 KiB
C
/* cuframes-composer — обвязка вокруг NVIDIA NVENC API.
|
||
*
|
||
* Динамически грузит libnvidia-encode.so через dlopen, чтобы пакет
|
||
* cuframes-composer оставался под LGPL-2.1+ без статической линковки
|
||
* проприетарного SDK. См. дизайн-документ часть 1.6.
|
||
*
|
||
* Принимает на вход CUdeviceptr на NV12 frame (zero-copy через
|
||
* NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR + nvEncRegisterResource).
|
||
* Выдаёт сжатый H.264 bitstream через callback (caller записывает его
|
||
* в файл / RTP-пакетизирует / etc).
|
||
*
|
||
* Lifecycle:
|
||
* create(cfg) — open session, init encoder
|
||
* encode_frame(...) — на каждый входной кадр (один CUdeviceptr)
|
||
* flush(...) — в конце потока, чтобы вытащить остатки B-кадров
|
||
* destroy(...) — закрыть session, выгрузить SDK
|
||
*
|
||
* Поток должен быть single-threaded для одного encoder'а (NVENC API
|
||
* не реентрабельный для одной сессии).
|
||
*
|
||
* Лицензия: LGPL-2.1+
|
||
*/
|
||
|
||
#ifndef CUFRAMES_COMPOSER_NVENC_H
|
||
#define CUFRAMES_COMPOSER_NVENC_H
|
||
|
||
#include <cuda.h>
|
||
#include <stddef.h>
|
||
#include <stdint.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/* Параметры кодировщика. Для Phase 1 минимальный набор; в будущих фазах
|
||
* будут расширяться для RTSP (rate control, GOP, intra-refresh, и т.п.). */
|
||
typedef struct cfc_encoder_config {
|
||
CUcontext cuda_ctx; /* CUDA-контекст, в котором лежат входные VMM-буферы */
|
||
int32_t width; /* ширина кадра в пикселях */
|
||
int32_t height; /* высота кадра в пикселях */
|
||
int32_t fps_num; /* числитель частоты кадров (25) */
|
||
int32_t fps_den; /* знаменатель частоты кадров (1) */
|
||
int32_t bitrate_kbps; /* битрейт в килобитах в секунду (5000 = 5 Мбит/с) */
|
||
int32_t gop_size; /* интервал между keyframe'ами в кадрах (25 = 1 IDR в секунду) */
|
||
int32_t num_b_frames; /* B-кадры (0 для low-latency RTSP) */
|
||
|
||
/* Пресет — соответствует NV_ENC_TUNING_INFO + preset GUID.
|
||
* "ll" = low-latency, "p4" = preset P4 (баланс), "p7" = highest quality. */
|
||
const char *preset; /* "ll", "p4", "p7" — по умолчанию "ll" */
|
||
} cfc_encoder_config_t;
|
||
|
||
typedef struct cfc_encoder cfc_encoder_t;
|
||
|
||
/* Callback для записанного H.264 bitstream'а. Вызывается синхронно из
|
||
* cfc_encoder_encode_frame / cfc_encoder_flush. Указатель действителен только
|
||
* на время вызова (буфер NVENC будет разблокирован после возврата). */
|
||
typedef void (*cfc_encoder_output_cb)(
|
||
const uint8_t *bitstream, /* данные H.264 (Annex B byte stream) */
|
||
size_t size, /* размер в байтах */
|
||
int64_t pts_ns, /* presentation timestamp (передан в encode_frame) */
|
||
int is_idr, /* 1 если кадр IDR (keyframe) */
|
||
void *user /* user data, переданный в encode_frame */
|
||
);
|
||
|
||
/* Создать encoder. Возвращает 0 при успехе. */
|
||
int cfc_encoder_create(const cfc_encoder_config_t *cfg, cfc_encoder_t **out);
|
||
|
||
/* Закодировать один кадр. ptr — CUdeviceptr на начало NV12 frame в VRAM,
|
||
* pitch — ширина строки в байтах (для NV12 равна width).
|
||
*
|
||
* Callback может быть вызван 0 или 1 раз для одного encode_frame: NVENC
|
||
* может буферизовать кадры внутри (особенно при B-кадрах). Чтобы вытащить
|
||
* последние буферизованные — вызвать flush в конце потока. */
|
||
int cfc_encoder_encode_frame(
|
||
cfc_encoder_t *enc,
|
||
CUdeviceptr ptr,
|
||
int pitch,
|
||
int64_t pts_ns,
|
||
cfc_encoder_output_cb cb,
|
||
void *user
|
||
);
|
||
|
||
/* Завершить поток. Передаёт NVENC флаг end-of-stream, выдаёт оставшиеся
|
||
* закодированные кадры через callback. После flush encoder можно либо
|
||
* destroy, либо использовать снова с новым GOP'ом. */
|
||
int cfc_encoder_flush(
|
||
cfc_encoder_t *enc,
|
||
cfc_encoder_output_cb cb,
|
||
void *user
|
||
);
|
||
|
||
/* Выдать SPS/PPS — заголовки H.264 sequence/picture parameter sets.
|
||
* Нужны для записи в начало MP4-контейнера или для отправки в SDP при RTSP. */
|
||
int cfc_encoder_get_sequence_params(
|
||
cfc_encoder_t *enc,
|
||
uint8_t *out, /* буфер caller'а */
|
||
size_t *inout_size /* при вызове — размер буфера, при возврате — реальный размер */
|
||
);
|
||
|
||
/* Закрыть encoder, выгрузить SDK. */
|
||
int cfc_encoder_destroy(cfc_encoder_t *enc);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* CUFRAMES_COMPOSER_NVENC_H */
|