From 962bea11caebf119093c9e9293f02ba4d23726eb Mon Sep 17 00:00:00 2001 From: Evgeny Demchenko Date: Wed, 3 Jun 2026 05:15:47 +0100 Subject: [PATCH] =?UTF-8?q?Phase=202=20RTSP:=20--out=20-=20/=20pipe:1=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D1=8F=D0=BC=D0=BE=D0=B3=D0=BE?= =?UTF-8?q?=20pipe=20=D0=B2=20ffmpeg?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Подтверждено live-тестом end-to-end в продакшен-условиях: grid_record --out - → ffmpeg -i pipe:0 -c copy -f rtsp -rtsp_transport tcp → mediamtx rtsp://...:554/cfc-grid → VLC на MacBook VLC принимает поток штатно, картинка не тормозит — лучше чем у предыдущего цельного ffmpeg-pipeline (vf-cuda-grid). 1920x1080 H.264 High@4.0 4Mbps, 4 источника active. Изменения тривиальные: stdout не закрывается через fclose, чтобы пайп оставался открытым для дочернего ffmpeg-процесса. --- examples/grid_record.c | 28 ++++++++++++++++++++-------- examples/simple_record.c | 22 +++++++++++++++------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/examples/grid_record.c b/examples/grid_record.c index d8e53d7..50a9f55 100644 --- a/examples/grid_record.c +++ b/examples/grid_record.c @@ -182,14 +182,25 @@ int main(int argc, char **argv) return 1; } - /* Output file. */ + /* Output: "-" / "/dev/stdout" / "pipe:1" = stdout (для pipe в ffmpeg). + * stdout не закрывается через fclose чтобы не убивать дочерний процесс + * raньше времени. */ write_ctx_t wctx = { 0 }; - wctx.fp = fopen(out_path, "wb"); - if (!wctx.fp) { - fprintf(stderr, "fopen(%s): %s\n", out_path, strerror(errno)); - cfc_encoder_destroy(enc); - cfc_composer_destroy(comp); - return 1; + int is_stdout = (!strcmp(out_path, "-") || !strcmp(out_path, "pipe:1") || + !strcmp(out_path, "/dev/stdout")); + if (is_stdout) { + wctx.fp = stdout; + /* line-buffer'инг disabled — пишем full-buffered для производительности. + * Caller'у нужно flush при exit. */ + setvbuf(stdout, NULL, _IOFBF, 1024 * 1024); + } else { + wctx.fp = fopen(out_path, "wb"); + if (!wctx.fp) { + fprintf(stderr, "fopen(%s): %s\n", out_path, strerror(errno)); + cfc_encoder_destroy(enc); + cfc_composer_destroy(comp); + return 1; + } } fprintf(stderr, "[grid_record] начало записи в %s (Ctrl+C для остановки)\n", out_path); @@ -261,7 +272,8 @@ int main(int argc, char **argv) (unsigned long long)wctx.idr_count, wctx.bytes_written / 1048576.0); - fclose(wctx.fp); + fflush(wctx.fp); + if (!is_stdout) fclose(wctx.fp); cfc_encoder_destroy(enc); cfc_composer_destroy(comp); cuCtxPopCurrent(NULL); diff --git a/examples/simple_record.c b/examples/simple_record.c index 3e5af66..242b8aa 100644 --- a/examples/simple_record.c +++ b/examples/simple_record.c @@ -180,13 +180,20 @@ int main(int argc, char **argv) goto cleanup_src; } - /* 5) Открыть выходной файл. */ + /* 5) Открыть выходной файл (или stdout если "-"/"pipe:1"). */ write_ctx_t wctx = { 0 }; - wctx.fp = fopen(out_path, "wb"); - if (!wctx.fp) { - fprintf(stderr, "[simple_record] fopen(%s) failed: %s\n", - out_path, strerror(errno)); - goto cleanup_enc; + int is_stdout = (!strcmp(out_path, "-") || !strcmp(out_path, "pipe:1") || + !strcmp(out_path, "/dev/stdout")); + if (is_stdout) { + wctx.fp = stdout; + setvbuf(stdout, NULL, _IOFBF, 1024 * 1024); + } else { + wctx.fp = fopen(out_path, "wb"); + if (!wctx.fp) { + fprintf(stderr, "[simple_record] fopen(%s) failed: %s\n", + out_path, strerror(errno)); + goto cleanup_enc; + } } /* 6) Главный цикл — забираем кадры по seq, кодируем. */ @@ -258,7 +265,8 @@ int main(int argc, char **argv) (unsigned long long)wctx.idr_count, wctx.bytes_written / 1048576.0); - fclose(wctx.fp); + fflush(wctx.fp); + if (!is_stdout) fclose(wctx.fp); cleanup_enc: cfc_encoder_destroy(enc);