1
This commit is contained in:
parent
0f892b5c5b
commit
5b0b6c1c65
@ -52,36 +52,44 @@ std::string RTMPManager::make_key(const std::string& name) { return name + "_mai
|
|||||||
// ========== 创建 RTMP Pipeline ==========
|
// ========== 创建 RTMP Pipeline ==========
|
||||||
GstElement* RTMPManager::create_pipeline(const Camera& cam)
|
GstElement* RTMPManager::create_pipeline(const Camera& cam)
|
||||||
{
|
{
|
||||||
const int gop = 15;
|
|
||||||
|
|
||||||
const std::string rtmp_url = "rtmp://127.0.0.1:1935/" + cam.name;
|
const std::string rtmp_url = "rtmp://127.0.0.1:1935/" + cam.name;
|
||||||
|
|
||||||
std::string pipeline_str = "v4l2src device=" + cam.device +
|
std::string pipeline_str = "v4l2src device=" + cam.device +
|
||||||
" io-mode=dmabuf "
|
" io-mode=dmabuf "
|
||||||
|
|
||||||
|
// ⭐ 强制打时间戳(关键)
|
||||||
|
"! identity do-timestamp=true "
|
||||||
|
|
||||||
|
// 原始 4:3 输入
|
||||||
"! video/x-raw,format=NV12,width=1280,height=960,framerate=30/1 "
|
"! video/x-raw,format=NV12,width=1280,height=960,framerate=30/1 "
|
||||||
|
|
||||||
|
// 裁成 16:9
|
||||||
"! videocrop top=120 bottom=120 "
|
"! videocrop top=120 bottom=120 "
|
||||||
|
|
||||||
|
// 缩放到目标分辨率
|
||||||
"! videoscale "
|
"! videoscale "
|
||||||
"! video/x-raw,width=" +
|
"! video/x-raw,width=" +
|
||||||
std::to_string(cam.width) + ",height=" + std::to_string(cam.height) +
|
std::to_string(cam.width) + ",height=" + std::to_string(cam.height) +
|
||||||
" "
|
" "
|
||||||
|
|
||||||
|
// 缓冲(只在这里允许丢帧)
|
||||||
"! queue max-size-buffers=12 max-size-time=0 leaky=downstream "
|
"! queue max-size-buffers=12 max-size-time=0 leaky=downstream "
|
||||||
|
|
||||||
|
// 编码
|
||||||
"! mpph264enc rc-mode=cbr "
|
"! mpph264enc rc-mode=cbr "
|
||||||
"bps=" +
|
"bps=" +
|
||||||
std::to_string(cam.bitrate) +
|
std::to_string(cam.bitrate) +
|
||||||
" "
|
" "
|
||||||
"gop=30 "
|
"gop=30 "
|
||||||
"header-mode=each-idr profile=main "
|
"header-mode=each-idr "
|
||||||
|
"profile=main "
|
||||||
|
|
||||||
"! h264parse config-interval=1 "
|
// 解析 + 帧探针位置
|
||||||
|
"! h264parse name=parse config-interval=1 "
|
||||||
"! video/x-h264,stream-format=avc,alignment=au "
|
"! video/x-h264,stream-format=avc,alignment=au "
|
||||||
|
|
||||||
|
// RTMP
|
||||||
"! flvmux streamable=true "
|
"! flvmux streamable=true "
|
||||||
|
|
||||||
"! rtmpsink location=\"" +
|
"! rtmpsink location=\"" +
|
||||||
rtmp_url +
|
rtmp_url +
|
||||||
"\" "
|
"\" "
|
||||||
@ -97,6 +105,7 @@ GstElement* RTMPManager::create_pipeline(const Camera& cam)
|
|||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pipeline;
|
return pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,8 +114,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 = 12000; // ⭐ 启动宽限期
|
constexpr int64_t START_TIMEOUT_MS = 12000; // 启动宽限
|
||||||
constexpr int64_t NO_FRAME_TIMEOUT_MS = 10000;
|
constexpr int64_t NO_FRAME_TIMEOUT_MS = 15000; // 运行期宽限
|
||||||
|
|
||||||
while (ctx->thread_running)
|
while (ctx->thread_running)
|
||||||
{
|
{
|
||||||
@ -129,7 +138,7 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx)
|
|||||||
|
|
||||||
ctx->last_frame_ms.store(0, std::memory_order_relaxed);
|
ctx->last_frame_ms.store(0, std::memory_order_relaxed);
|
||||||
|
|
||||||
// ⭐ 帧探测挂在 h264parse
|
// ⭐ 帧探针挂在 h264parse src
|
||||||
if (GstElement* parse = gst_bin_get_by_name(GST_BIN(pipeline), "parse"))
|
if (GstElement* parse = gst_bin_get_by_name(GST_BIN(pipeline), "parse"))
|
||||||
{
|
{
|
||||||
if (GstPad* pad = gst_element_get_static_pad(parse, "src"))
|
if (GstPad* pad = gst_element_get_static_pad(parse, "src"))
|
||||||
@ -187,9 +196,8 @@ void RTMPManager::stream_loop(Camera cam, StreamContext* ctx)
|
|||||||
else if (std::chrono::duration_cast<std::chrono::milliseconds>(now - launch_tp).count() >
|
else if (std::chrono::duration_cast<std::chrono::milliseconds>(now - launch_tp).count() >
|
||||||
START_TIMEOUT_MS)
|
START_TIMEOUT_MS)
|
||||||
{
|
{
|
||||||
LOG_ERROR("[RTMP] " + key + " - no frames during startup");
|
// ⭐ 启动阶段允许慢,不重启
|
||||||
need_restart = true;
|
LOG_WARN("[RTMP] " + key + " - no frames yet during startup (tolerated)");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user