Phase 2 RTSP: --out - / pipe:1 для прямого pipe в ffmpeg

Подтверждено 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-процесса.
This commit is contained in:
2026-06-03 05:15:47 +01:00
parent 1e2b5d4e16
commit 962bea11ca
2 changed files with 35 additions and 15 deletions
+14 -2
View File
@@ -182,8 +182,18 @@ 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 };
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));
@@ -191,6 +201,7 @@ int main(int argc, char **argv)
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);
+10 -2
View File
@@ -180,14 +180,21 @@ int main(int argc, char **argv)
goto cleanup_src;
}
/* 5) Открыть выходной файл. */
/* 5) Открыть выходной файл (или stdout если "-"/"pipe:1"). */
write_ctx_t wctx = { 0 };
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, кодируем. */
uint64_t last_seq = 0;
@@ -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);