GStreamer中RTSP与appsrc延迟问题求助:VLC提示画面过晚无法显示
问题根源
你手动用原始帧duration累加时间戳的方式,在主管道丢帧时会彻底打乱时间轴:主管道丢帧后,实际收到的帧间隔远大于设定的fps间隔(比如10fps本该每100ms一帧,丢帧后变成200ms一帧),但你还是按固定duration累加时间戳,导致播放器认为时间流速只有实际的1/2甚至更低,为了对齐时间轴就会持续缓冲数据,最终出现3秒延迟、VLC周期性停缓冲的问题。WebRTC正常是因为它的传输层对时间戳容错性更强,且它的分支直接从主管道tee获取数据,没经过时间篡改。
修复步骤
复用原始帧的时间戳,不要手动计算
主管道里v4l2src输出的帧本身带有正确的PTS/DTS(和系统时钟同步),appsink拿到的buffer直接保留了这些时间戳,你不需要重新赋值,直接传给appsrc即可:// 从appsink拉取样本 GstSample *sample = gst_app_sink_pull_sample(GST_APP_SINK(vidsink)); if (!sample) return; GstBuffer *src_buf = gst_buffer_copy(gst_sample_get_buffer(sample)); // 直接复用原始buffer的PTS/DTS,不需要手动设置 gst_app_src_push_buffer(GST_APP_SRC(videosrc), src_buf); gst_sample_unref(sample);调整appsrc的时间戳配置
在RTSP管道的appsrc中添加do-timestamp=False,明确告诉GStreamer我们自己提供正确的时间戳,不要自动生成:appsrc name=videosrc is-live=True format=GST_FORMAT_TIME block=True do-timestamp=False ! queue max-size-buffers=10 ! videoconvert ! x264enc speed-preset=ultrafast ! rtph264pay name=pay0 pt=96 config-interval=1同时把queue的
max-size-buffers从5调到10,避免因为appsrc下游处理不及时丢帧,减少延迟。优化主管道的丢帧问题
主管道里的queuemax-size-buffers=1太小,很容易因为下游编码慢导致丢帧,把主管道中两个queue的max-size-buffers都调到5:tee name=videotee ! queue ! fakesink v4l2src device=/dev/video0 ! imxvideoconvert_g2d ! video/x-raw,width=1280,height=720,fps=10/1 ! videoconvert! tee name=t0 t0. ! videoconvert! queue max-size-buffers=5 ! x264enc ! video/x-h264, stream-format=byte-stream ! rtph264pay config-interval=1 ! application/x-rtp,media=video,encoding-name=H264,payload=127 ! videotee. t0. ! queue max-size-buffers=5 ! videoconvert! video/x-raw, format=I420 ! appsink name=vidsink max-buffers=1 drop=true减少丢帧能保证时间戳的连续性,从根源上避免时间轴异常。
RTSP编码延迟优化
给x264enc加上speed-preset=ultrafast参数,降低编码延迟,进一步减少RTSP流的整体延迟。
原理说明
Live流的时间戳必须和系统时钟同步,才能让播放器正确判断帧的播放时机。手动累加duration的方式只适用于无丢帧的理想情况,一旦出现丢帧,时间戳就会和实际时间脱节,播放器为了填补时间差就会不断缓冲,最终导致延迟和时间轴流速异常。复用原始帧的时间戳则能保证时间轴和实际播放时间对齐,彻底解决问题。
内容的提问来源于stack exchange,提问作者Александр

