1
This commit is contained in:
parent
71d95e849c
commit
d4d435f572
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user