From 430e44d9faa990e255071573c2fa44f27134d851 Mon Sep 17 00:00:00 2001 From: cxh Date: Tue, 6 Jan 2026 11:21:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E7=AE=A1=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rtmp_manager.cpp | 186 +++++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 93 deletions(-) diff --git a/src/rtmp_manager.cpp b/src/rtmp_manager.cpp index 5c3ccd3..cbf2e7c 100644 --- a/src/rtmp_manager.cpp +++ b/src/rtmp_manager.cpp @@ -63,114 +63,41 @@ void RTMPManager::init() std::string RTMPManager::make_key(const std::string& name) { return name + "_main"; } // ========== 创建推流管线 ========== -// GstElement* RTMPManager::create_pipeline(const Camera& cam) -// { -// const int width = cam.width; -// const int height = cam.height; -// const int fps = cam.fps; -// const int bitrate = cam.bitrate; - -// // MediaMTX 中的 stream key -// const std::string stream_name = cam.name; - -// // RTMP 推送到 MediaMTX -// // mediamtx.yml 中 paths 会自动创建 -// const std::string rtmp_url = "rtmp://127.0.0.1:1935/" + stream_name; - -// /* -// * Pipeline 说明: -// * v4l2src -> mpph264enc -> h264parse -> flvmux -> rtmpsink -// * -// * - 不使用 tee(降低死锁概率) -// * - 不引入音频(MediaMTX 不强制要求) -// * - 纯视频、纯 RTMP、纯 TCP -// */ -// std::string pipeline_str = "v4l2src name=src device=" + cam.device + -// " ! video/x-raw,format=NV12,width=" + std::to_string(width) + -// ",height=" + std::to_string(height) + ",framerate=" + std::to_string(fps) + -// "/1 " -// " ! mpph264enc bps=" + -// std::to_string(bitrate) + " gop=" + std::to_string(fps) + -// " rc-mode=cbr " -// " ! h264parse name=parse " -// " ! flvmux streamable=true " -// " ! rtmpsink location=\"" + -// rtmp_url + -// "\" " -// " sync=false async=false"; - -// GError* error = nullptr; -// GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), &error); -// if (error) -// { -// LOG_ERROR(std::string("[RTMP] Pipeline creation failed: ") + error->message); -// g_error_free(error); -// return nullptr; -// } - -// return pipeline; -// } - GstElement* RTMPManager::create_pipeline(const Camera& cam) { - const int out_width = cam.width; // 推流分辨率(如 1280 / 960 / 720) - const int out_height = cam.height; + const int width = cam.width; + const int height = cam.height; const int fps = cam.fps; const int bitrate = cam.bitrate; - // MediaMTX stream key + // MediaMTX 中的 stream key const std::string stream_name = cam.name; + + // RTMP 推送到 MediaMTX + // mediamtx.yml 中 paths 会自动创建 const std::string rtmp_url = "rtmp://127.0.0.1:1935/" + stream_name; /* - * A 方案 Pipeline: + * Pipeline 说明: + * v4l2src -> mpph264enc -> h264parse -> flvmux -> rtmpsink * - * v4l2src (原生 1280x960) - * -> videoscale + caps(编码前缩放) - * -> queue(低延迟) - * -> mpph264enc(CBR) - * -> h264parse - * -> flvmux - * -> rtmpsink + * - 不使用 tee(降低死锁概率) + * - 不引入音频(MediaMTX 不强制要求) + * - 纯视频、纯 RTMP、纯 TCP */ std::string pipeline_str = "v4l2src name=src device=" + cam.device + - " io-mode=dmabuf " - - // ⭐ 相机真实输出:原生 1280x960 - "! video/x-raw,format=NV12," - "width=1280,height=960," - "framerate=" + - std::to_string(fps) + + " ! video/x-raw,format=NV12,width=" + std::to_string(width) + + ",height=" + std::to_string(height) + ",framerate=" + std::to_string(fps) + "/1 " - - // ⭐ 编码前缩放(关键) - "! videoscale " - "! video/x-raw," - "width=" + - std::to_string(out_width) + ",height=" + std::to_string(out_height) + - " " - - // ⭐ 低延迟队列,防止下游阻塞反噬 v4l2 - "! queue max-size-buffers=2 max-size-time=0 leaky=downstream " - - // ⭐ 硬件编码,SIM 卡友好 - "! mpph264enc " - "rc-mode=cbr " - "bps=" + - std::to_string(bitrate) + - " " - "gop=" + - std::to_string(fps) + - " " - "header-mode=each-idr " - "profile=baseline " - - "! h264parse config-interval=1 " - "! flvmux streamable=true " - "! rtmpsink location=\"" + + " ! mpph264enc bps=" + + std::to_string(bitrate) + " gop=" + std::to_string(fps) + + " rc-mode=cbr " + " ! h264parse name=parse " + " ! flvmux streamable=true " + " ! rtmpsink location=\"" + rtmp_url + "\" " - "sync=false async=false"; + " sync=false async=false"; GError* error = nullptr; GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), &error); @@ -184,6 +111,79 @@ GstElement* RTMPManager::create_pipeline(const Camera& cam) return pipeline; } +// GstElement* RTMPManager::create_pipeline(const Camera& cam) +// { +// const int out_width = cam.width; // 推流分辨率(如 1280 / 960 / 720) +// const int out_height = cam.height; +// const int fps = cam.fps; +// const int bitrate = cam.bitrate; + +// // MediaMTX stream key +// const std::string stream_name = cam.name; +// const std::string rtmp_url = "rtmp://127.0.0.1:1935/" + stream_name; + +// /* +// * A 方案 Pipeline: +// * +// * v4l2src (原生 1280x960) +// * -> videoscale + caps(编码前缩放) +// * -> queue(低延迟) +// * -> mpph264enc(CBR) +// * -> h264parse +// * -> flvmux +// * -> rtmpsink +// */ +// std::string pipeline_str = "v4l2src name=src device=" + cam.device + +// " io-mode=dmabuf " + +// // ⭐ 相机真实输出:原生 1280x960 +// "! video/x-raw,format=NV12," +// "width=1280,height=960," +// "framerate=" + +// std::to_string(fps) + +// "/1 " + +// // ⭐ 编码前缩放(关键) +// "! videoscale " +// "! video/x-raw," +// "width=" + +// std::to_string(out_width) + ",height=" + std::to_string(out_height) + +// " " + +// // ⭐ 低延迟队列,防止下游阻塞反噬 v4l2 +// "! queue max-size-buffers=2 max-size-time=0 leaky=downstream " + +// // ⭐ 硬件编码,SIM 卡友好 +// "! mpph264enc " +// "rc-mode=cbr " +// "bps=" + +// std::to_string(bitrate) + +// " " +// "gop=" + +// std::to_string(fps) + +// " " +// "header-mode=each-idr " +// "profile=baseline " + +// "! h264parse config-interval=1 " +// "! flvmux streamable=true " +// "! rtmpsink location=\"" + +// rtmp_url + +// "\" " +// "sync=false async=false"; + +// GError* error = nullptr; +// GstElement* pipeline = gst_parse_launch(pipeline_str.c_str(), &error); +// if (error) +// { +// LOG_ERROR(std::string("[RTMP] Pipeline creation failed: ") + error->message); +// g_error_free(error); +// return nullptr; +// } + +// return pipeline; +// } + // ========== 主推流循环 ========== void RTMPManager::stream_loop(Camera cam, StreamContext* ctx) {