This commit is contained in:
cxh 2026-01-09 15:08:35 +08:00
parent 71d95e849c
commit d4d435f572

View File

@ -114,24 +114,25 @@ std::string RTMPManager::make_key(const std::string& name) { return name + "_mai
GstElement* RTMPManager::create_pipeline(const Camera& cam) GstElement* RTMPManager::create_pipeline(const Camera& cam)
{ {
const int fps = 30; const int fps = 30;
const int bitrate = cam.bitrate; // 3.5M~4M const int bitrate = cam.bitrate;
const int gop = fps; // 建议1 秒一个 IDR const int gop = fps;
const std::string stream_name = cam.name; const std::string stream_name = cam.name;
const std::string rtmp_url = "rtmp://127.0.0.1:1935/" + stream_name; const std::string rtmp_url = "rtmp://127.0.0.1:1935/" + stream_name;
std::string pipeline_str = "v4l2src device=" + cam.device + std::string pipeline_str =
// === V4L2 ===
"v4l2src device=" + cam.device +
" io-mode=dmabuf do-timestamp=true " " io-mode=dmabuf do-timestamp=true "
// ✅ 相机原生格式:完全匹配驱动 // === 完全匹配驱动格式 ===
"! video/x-raw,format=NV12," "! video/x-raw,format=NV12,width=1280,height=960,framerate=30/1 "
"width=1280,height=960,framerate=30/1 "
// ✅ 缓冲,只负责解耦,不丢帧 // === 解耦缓冲 ===
"! queue max-size-buffers=4 max-size-time=0 max-size-bytes=0 " "! queue max-size-buffers=4 max-size-time=0 max-size-bytes=0 "
// ✅ 硬件编码 // === 硬件编码(命名!)===
"! mpph264enc " "! mpph264enc name=enc "
"rc-mode=cbr " "rc-mode=cbr "
"bps=" + "bps=" +
std::to_string(bitrate) + std::to_string(bitrate) +
@ -142,11 +143,11 @@ GstElement* RTMPManager::create_pipeline(const Camera& cam)
"profile=main " "profile=main "
"header-mode=each-idr " "header-mode=each-idr "
// ✅ H.264 打包 // === H264 ===
"! h264parse config-interval=1 " "! h264parse config-interval=1 "
"! video/x-h264,stream-format=avc,alignment=au " "! video/x-h264,stream-format=avc,alignment=au "
// ✅ FLV / RTMP // === RTMP ===
"! flvmux streamable=true " "! flvmux streamable=true "
"! rtmpsink location=\"" + "! rtmpsink location=\"" +
rtmp_url + "\" sync=false async=false"; rtmp_url + "\" sync=false async=false";
@ -168,8 +169,8 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx)
{ {
const std::string key = make_key(cam.name); const std::string key = make_key(cam.name);
constexpr int64_t START_TIMEOUT_MS = 5000; // 启动阶段无帧 constexpr int64_t START_TIMEOUT_MS = 12000; // 启动阶段无帧
constexpr int64_t NO_FRAME_TIMEOUT_MS = 10000; // 运行阶段突然无帧 ⇒ pipeline 卡死重启 constexpr int64_t NO_FRAME_TIMEOUT_MS = 15000; // 运行阶段突然无帧 ⇒ pipeline 卡死重启
while (ctx->thread_running) while (ctx->thread_running)
{ {
@ -198,20 +199,22 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx)
gst_element_set_name(pipeline, key.c_str()); gst_element_set_name(pipeline, key.c_str());
GstBus* bus = gst_element_get_bus(pipeline); GstBus* bus = gst_element_get_bus(pipeline);
// 3) 帧探测:记录 last_frame_ms // 3) 帧探测:挂在 encoder 的 src pad真实“视频已生成”
ctx->last_frame_ms.store(0, std::memory_order_relaxed); ctx->last_frame_ms.store(0, std::memory_order_relaxed);
{ {
GstElement* src = gst_bin_get_by_name(GST_BIN(pipeline), "src"); GstElement* enc = gst_bin_get_by_name(GST_BIN(pipeline), "enc");
if (src) if (!enc) { LOG_ERROR("[RTMP] Failed to find encoder element"); }
else
{ {
GstPad* pad = gst_element_get_static_pad(src, "src"); GstPad* pad = gst_element_get_static_pad(enc, "src");
if (pad) if (pad)
{ {
gst_pad_add_probe( gst_pad_add_probe(
pad, GST_PAD_PROBE_TYPE_BUFFER, pad, GST_PAD_PROBE_TYPE_BUFFER,
[](GstPad*, GstPadProbeInfo*, gpointer data) -> GstPadProbeReturn [](GstPad*, GstPadProbeInfo*, gpointer data) -> GstPadProbeReturn
{ {
auto ts = static_cast<std::atomic<int64_t>*>(data); auto* ts = static_cast<std::atomic<int64_t>*>(data);
auto now = std::chrono::steady_clock::now().time_since_epoch(); auto now = std::chrono::steady_clock::now().time_since_epoch();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now).count(); auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now).count();
ts->store(ms, std::memory_order_relaxed); ts->store(ms, std::memory_order_relaxed);
@ -220,7 +223,7 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx)
&(ctx->last_frame_ms), nullptr); &(ctx->last_frame_ms), nullptr);
gst_object_unref(pad); gst_object_unref(pad);
} }
gst_object_unref(src); gst_object_unref(enc);
} }
} }