GStreamer多视频流合成模块appsrc is-live配置问题求助
GStreamer多视频流合成模块时间戳与丢包问题解决方案
问题根源分析
is-live=false时冻结:compositor在非live模式下会等待所有sink pad都有数据才输出,当某路流播放结束后无新数据输入,整个合成流会停滞。你设置的ignore-inactive-pads=true本应解决此问题,但非live模式下该参数不生效——compositor仍会等待已结束的流发送数据。is-live=true时丢包:日志中显示buffer的DTS为99:99:99.999999999(无效值),且PTS可能与流水线运行时间不同步。live模式下appsrc会严格校验buffer时间戳,若时间戳滞后或无效,会判定为过期buffer并丢弃。do-timestamp=true无效是因为该参数仅给无时间戳的buffer自动打戳,若buffer本身带错误时间戳,反而会干扰流水线同步。
具体修复步骤
1. 修正输入Buffer的时间戳
推送到appsrc的每个buffer必须携带有效且单调递增的PTS/DTS:
- 对于文件源:保留原始视频帧的PTS,或按帧率计算连续时间戳(如第
n帧的PTS为n * GST_SECOND / fps)。 - 对于RTP流:直接使用RTP包携带的时间戳转换为GStreamer时钟时间。
- 强制清除无效DTS:若输入buffer的DTS为
GST_CLOCK_TIME_NONE或无效值,将其设置为与PTS相同(无B帧场景)。
2. 调整appsrc参数配置
live模式下,确保参数与时间戳逻辑匹配:
for (int i = 0; i < _number_of_inputs; ++i) { g_object_set(G_OBJECT(_appsrcs->at(i)), "block", true, // 推送时阻塞直到流水线接收,避免buffer堆积 "stream-type", GST_APP_STREAM_TYPE_STREAM, "leaky-type", GST_APP_LEAKY_TYPE_NONE, // 关闭自动丢包,先确保时间戳正确 "format", GST_FORMAT_TIME, "do-timestamp", false, // 输入buffer已有正确时间戳,关闭自动打戳 "is-live", true, NULL); }
3. 处理流结束的EOS事件
当某路输入流读取完毕时,给对应的appsrc发送EOS事件,compositor会标记该pad为inactive并继续处理其他流:
// 某路流读取完成后调用 gst_app_src_end_of_stream(GST_APP_SRC(_appsrcs->at(i)));
4. 修复request_pad内存泄漏
你请求的compositor pad需要在流水线销毁时手动释放,否则会造成内存泄漏:
// 在流水线销毁前执行 for (int i = 0; i < _number_of_inputs; ++i) { gchar *pad_name = g_strdup_printf("sink_%u", i); GstPad *compositor_pad = gst_element_get_static_pad(_compositor, pad_name); if (compositor_pad) { gst_element_release_request_pad(_compositor, compositor_pad); gst_object_unref(compositor_pad); } g_free(pad_name); }
5. 推送Buffer时的时间戳校验示例
// 假设读取到帧数据data,帧率fps,帧索引frame_idx GstBuffer *buffer = gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, data, size, 0, size, NULL, NULL); // 计算并设置有效时间戳 GstClockTime frame_duration = GST_SECOND / fps; GstClockTime pts = frame_idx * frame_duration; GST_BUFFER_PTS(buffer) = pts; GST_BUFFER_DTS(buffer) = pts; // 无B帧时DTS与PTS一致 GST_BUFFER_DURATION(buffer) = frame_duration; // 推送buffer GstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(_appsrcs->at(i)), buffer); if (ret != GST_FLOW_OK) { // 处理推送失败逻辑(如日志记录、重试) }
最终效果验证
- 设置
is-live=true+正确时间戳后,丢包警告会消失,多路流可正常同步合成。 - 某路流结束发送EOS后,compositor会忽略该pad,其他流继续播放,不会出现冻结。
内容的提问来源于stack exchange,提问作者Gemms
相关产品推荐
相关产品推荐

