This commit is contained in:
cxh 2025-11-25 08:54:26 +08:00
parent 11d21c467b
commit 07fd785098

View File

@ -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_INFO(std::string("[RTSP] Force pipeline PLAYING for camera: ") + cam_name);
}
// ⚠️ 这里一定要 unref一次 get_element 一次 unref
gst_object_unref(pipeline);
}
else
{
LOG_WARN(std::string("[RTSP] Pipeline is NULL for camera: ") + cam_name);
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);