1
This commit is contained in:
parent
11d21c467b
commit
07fd785098
@ -32,6 +32,28 @@ bool set_v4l2_format(const std::string &dev, int width, int height)
|
||||
}
|
||||
|
||||
struct v4l2_format fmt;
|
||||
memset(&fmt, 0, sizeof(fmt));
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
|
||||
// 先读当前格式,避免每次都硬 S_FMT
|
||||
if (ioctl(fd, VIDIOC_G_FMT, &fmt) == 0)
|
||||
{
|
||||
bool match = true;
|
||||
if (fmt.fmt.pix_mp.width != (unsigned int)width ||
|
||||
fmt.fmt.pix_mp.height != (unsigned int)height ||
|
||||
fmt.fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12)
|
||||
{
|
||||
match = false;
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
close(fd);
|
||||
LOG_INFO("[RTSP] V4L2 format already NV12 " + std::to_string(width) + "x" + std::to_string(height) + " for " + dev);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&fmt, 0, sizeof(fmt));
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
fmt.fmt.pix_mp.width = width;
|
||||
@ -46,6 +68,8 @@ bool set_v4l2_format(const std::string &dev, int width, int height)
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("[RTSP] Set V4L2 format to NV12 " + std::to_string(width) + "x" + std::to_string(height) + " for " + dev);
|
||||
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
@ -67,7 +91,6 @@ GstRTSPMediaFactory *RTSPManager::create_media_factory(const Camera &cam)
|
||||
int out_width = cam.width;
|
||||
int out_height = cam.height;
|
||||
|
||||
// 先拼 caps,方便看
|
||||
std::string caps =
|
||||
"video/x-raw,format=NV12,"
|
||||
"width=" +
|
||||
@ -75,14 +98,13 @@ GstRTSPMediaFactory *RTSPManager::create_media_factory(const Camera &cam)
|
||||
",height=" + std::to_string(out_height) +
|
||||
",framerate=" + std::to_string(cam.fps) + "/1";
|
||||
|
||||
// 关键改动:
|
||||
// 1) v4l2src 加 is-live / do-timestamp,避免 preroll 卡死
|
||||
// 2) queue 放宽限制,避免首帧被丢导致 pipeline 出错
|
||||
// 3) suspend_mode 改为 NONE,避免客户端断开时 RESET pipeline 导致反复 s_stream(0/1)
|
||||
// 注意:
|
||||
// 1) config-interval 放到 rtph264pay 上
|
||||
// 2) mpph264enc 加 gop / rc-mode / bps
|
||||
// 3) is-live + do-timestamp 避免 preroll 卡死
|
||||
std::string launch_str =
|
||||
"( v4l2src device=" + cam.device +
|
||||
" io-mode=2 is-live=true do-timestamp=true"
|
||||
" ! identity sync=false"
|
||||
" ! " +
|
||||
caps +
|
||||
" ! queue leaky=downstream max-size-buffers=0 max-size-bytes=0 max-size-time=0"
|
||||
@ -90,14 +112,18 @@ GstRTSPMediaFactory *RTSPManager::create_media_factory(const Camera &cam)
|
||||
std::to_string(cam.bitrate) +
|
||||
" gop=" + std::to_string(cam.fps) +
|
||||
" header-mode=1"
|
||||
" ! h264parse config-interval=1"
|
||||
" ! rtph264pay name=pay0 pt=96 )";
|
||||
" ! h264parse"
|
||||
" ! rtph264pay name=pay0 pt=96 config-interval=1 )";
|
||||
|
||||
LOG_INFO("[RTSP] Launch pipeline for " + cam.name + ": " + launch_str);
|
||||
|
||||
GstRTSPMediaFactory *factory = gst_rtsp_media_factory_new();
|
||||
gst_rtsp_media_factory_set_launch(factory, launch_str.c_str());
|
||||
|
||||
// 多客户端共享同一条 pipeline
|
||||
gst_rtsp_media_factory_set_shared(factory, TRUE);
|
||||
|
||||
// 不再在客户端断开时 RESET / 销毁 pipeline,避免频繁触发 MIPI / maxim4c 重新配置
|
||||
// 不在客户端断开时 RESET pipeline,避免频繁 s_stream(0/1)
|
||||
gst_rtsp_media_factory_set_suspend_mode(factory, GST_RTSP_SUSPEND_MODE_NONE);
|
||||
|
||||
g_signal_connect_data(factory,
|
||||
@ -169,6 +195,7 @@ void RTSPManager::on_media_created(GstRTSPMediaFactory *, GstRTSPMedia *media, g
|
||||
|
||||
LOG_INFO(std::string("[RTSP] media-configure for camera: ") + cam_name);
|
||||
|
||||
// media 自身加引用,存入 map
|
||||
g_object_ref(media);
|
||||
|
||||
{
|
||||
@ -184,16 +211,26 @@ void RTSPManager::on_media_created(GstRTSPMediaFactory *, GstRTSPMedia *media, g
|
||||
(GClosureNotify)g_free,
|
||||
(GConnectFlags)0);
|
||||
|
||||
// ★★★ 关键补丁:阻止 preroll 卡死 v4l2 驱动,强制 PLAYING
|
||||
// 强制 pipeline 进入 PLAYING,避免 preroll 阶段卡死在 PAUSED
|
||||
GstElement *pipeline = gst_rtsp_media_get_element(media);
|
||||
if (pipeline)
|
||||
{
|
||||
gst_element_set_state(pipeline, GST_STATE_PLAYING);
|
||||
LOG_INFO(std::string("[RTSP] Force pipeline PLAYING for camera: ") + cam_name);
|
||||
GstStateChangeReturn ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE)
|
||||
{
|
||||
LOG_ERROR(std::string("[RTSP] Failed to set pipeline PLAYING for camera: ") + cam_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARN(std::string("[RTSP] Pipeline is NULL for camera: ") + cam_name);
|
||||
LOG_INFO(std::string("[RTSP] Force pipeline PLAYING for camera: ") + cam_name);
|
||||
}
|
||||
|
||||
// ⚠️ 这里一定要 unref,一次 get_element 一次 unref
|
||||
gst_object_unref(pipeline);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(std::string("[RTSP] Pipeline is NULL for camera: ") + cam_name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,6 +250,10 @@ void RTSPManager::on_media_unprepared(GstRTSPMedia *media, gpointer user_data)
|
||||
if (vec.empty())
|
||||
media_map.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARN(std::string("[RTSP] media-unprepared but no entry in media_map for camera: ") + cam_name);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref(media);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user