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;
|
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));
|
memset(&fmt, 0, sizeof(fmt));
|
||||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||||
fmt.fmt.pix_mp.width = width;
|
fmt.fmt.pix_mp.width = width;
|
||||||
@ -46,6 +68,8 @@ bool set_v4l2_format(const std::string &dev, int width, int height)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_INFO("[RTSP] Set V4L2 format to NV12 " + std::to_string(width) + "x" + std::to_string(height) + " for " + dev);
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -67,7 +91,6 @@ GstRTSPMediaFactory *RTSPManager::create_media_factory(const Camera &cam)
|
|||||||
int out_width = cam.width;
|
int out_width = cam.width;
|
||||||
int out_height = cam.height;
|
int out_height = cam.height;
|
||||||
|
|
||||||
// 先拼 caps,方便看
|
|
||||||
std::string caps =
|
std::string caps =
|
||||||
"video/x-raw,format=NV12,"
|
"video/x-raw,format=NV12,"
|
||||||
"width=" +
|
"width=" +
|
||||||
@ -75,14 +98,13 @@ GstRTSPMediaFactory *RTSPManager::create_media_factory(const Camera &cam)
|
|||||||
",height=" + std::to_string(out_height) +
|
",height=" + std::to_string(out_height) +
|
||||||
",framerate=" + std::to_string(cam.fps) + "/1";
|
",framerate=" + std::to_string(cam.fps) + "/1";
|
||||||
|
|
||||||
// 关键改动:
|
// 注意:
|
||||||
// 1) v4l2src 加 is-live / do-timestamp,避免 preroll 卡死
|
// 1) config-interval 放到 rtph264pay 上
|
||||||
// 2) queue 放宽限制,避免首帧被丢导致 pipeline 出错
|
// 2) mpph264enc 加 gop / rc-mode / bps
|
||||||
// 3) suspend_mode 改为 NONE,避免客户端断开时 RESET pipeline 导致反复 s_stream(0/1)
|
// 3) is-live + do-timestamp 避免 preroll 卡死
|
||||||
std::string launch_str =
|
std::string launch_str =
|
||||||
"( v4l2src device=" + cam.device +
|
"( v4l2src device=" + cam.device +
|
||||||
" io-mode=2 is-live=true do-timestamp=true"
|
" io-mode=2 is-live=true do-timestamp=true"
|
||||||
" ! identity sync=false"
|
|
||||||
" ! " +
|
" ! " +
|
||||||
caps +
|
caps +
|
||||||
" ! queue leaky=downstream max-size-buffers=0 max-size-bytes=0 max-size-time=0"
|
" ! 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) +
|
std::to_string(cam.bitrate) +
|
||||||
" gop=" + std::to_string(cam.fps) +
|
" gop=" + std::to_string(cam.fps) +
|
||||||
" header-mode=1"
|
" header-mode=1"
|
||||||
" ! h264parse config-interval=1"
|
" ! h264parse"
|
||||||
" ! rtph264pay name=pay0 pt=96 )";
|
" ! 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();
|
GstRTSPMediaFactory *factory = gst_rtsp_media_factory_new();
|
||||||
gst_rtsp_media_factory_set_launch(factory, launch_str.c_str());
|
gst_rtsp_media_factory_set_launch(factory, launch_str.c_str());
|
||||||
|
|
||||||
|
// 多客户端共享同一条 pipeline
|
||||||
gst_rtsp_media_factory_set_shared(factory, TRUE);
|
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);
|
gst_rtsp_media_factory_set_suspend_mode(factory, GST_RTSP_SUSPEND_MODE_NONE);
|
||||||
|
|
||||||
g_signal_connect_data(factory,
|
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);
|
LOG_INFO(std::string("[RTSP] media-configure for camera: ") + cam_name);
|
||||||
|
|
||||||
|
// media 自身加引用,存入 map
|
||||||
g_object_ref(media);
|
g_object_ref(media);
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -184,16 +211,26 @@ void RTSPManager::on_media_created(GstRTSPMediaFactory *, GstRTSPMedia *media, g
|
|||||||
(GClosureNotify)g_free,
|
(GClosureNotify)g_free,
|
||||||
(GConnectFlags)0);
|
(GConnectFlags)0);
|
||||||
|
|
||||||
// ★★★ 关键补丁:阻止 preroll 卡死 v4l2 驱动,强制 PLAYING
|
// 强制 pipeline 进入 PLAYING,避免 preroll 阶段卡死在 PAUSED
|
||||||
GstElement *pipeline = gst_rtsp_media_get_element(media);
|
GstElement *pipeline = gst_rtsp_media_get_element(media);
|
||||||
if (pipeline)
|
if (pipeline)
|
||||||
{
|
{
|
||||||
gst_element_set_state(pipeline, GST_STATE_PLAYING);
|
GstStateChangeReturn ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
|
||||||
LOG_INFO(std::string("[RTSP] Force pipeline PLAYING for camera: ") + cam_name);
|
if (ret == GST_STATE_CHANGE_FAILURE)
|
||||||
|
{
|
||||||
|
LOG_ERROR(std::string("[RTSP] Failed to set pipeline PLAYING for camera: ") + cam_name);
|
||||||
}
|
}
|
||||||
else
|
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())
|
if (vec.empty())
|
||||||
media_map.erase(it);
|
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);
|
g_object_unref(media);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user