GStreamer分离RTMP音视频经共享内存传输时音频读取停滞问题
问题根因
你当前音频链路卡死的核心原因是**mp4mux/qtdemux组合不适用于实时流式透传场景**:
- 即使开启
streamable=true参数,mp4mux仍需要攒够对应moov box元数据才会输出可被解析的完整数据; qtdemux在未获取到完整moov头之前,不会向下游输出任何音频缓冲区;- 共享内存传输没有常规流的EOS(流结束)信号,
qtdemux会一直等待未拿到的元数据,直接进入停滞状态,这就是你观察到的shmsrc读取音频无响应的现象。
你不需要对音频做二次处理,完全没必要额外加mp4容器做中间层,额外的mux/demux操作只会增加延迟和故障点。
可行解决方案
方案1:直接透传带ADTS头的AAC帧(推荐,零额外开销)
AAC格式本身支持带ADTS同步头的流式传输,不需要容器承载就能识别帧边界,是音频透传场景的最优选择。
修正后接收端音频链路
将原接收端的mp4mux相关逻辑替换为:
demux.audio ! aacparse output-header=true ! queue ! shmsink socket-path=/tmp/foo sync=true wait-for-connection=false shm-size=10000000
aacparse的output-header=true参数会强制给每帧AAC加上ADTS同步头,下游不需要容器就能直接切分帧。
修正后发送端音频链路
将原发送端的qtdemux相关逻辑替换为:
shmsrc socket-path=/tmp/foo ! audio/mpeg, mpegversion=4, stream-format=adts ! aacparse ! queue ! mux.audio
该方案无额外封装/解封装开销,延迟最低,完全不会出现元数据等待导致的卡死问题。
方案2:换用实时友好的容器(特殊场景使用)
如果因业务要求必须用容器承载共享内存内的音频数据,替换掉mp4/mov格式,选用天生支持实时流的容器组合:
- 可选组合1:
flvmux streamable=true搭配flvdemux - 可选组合2:
matroskamux streamable=true搭配matroskademux
以上两类mux拿到一帧数据就会立刻输出,不需要攒元数据,不会出现demux等头卡死的问题。
以flv组合为例,接收端音频链路:
demux.audio ! aacparse ! queue ! flvmux streamable=true ! shmsink socket-path=/tmp/foo sync=true wait-for-connection=false shm-size=10000000
发送端音频链路:
shmsrc socket-path=/tmp/foo ! flvdemux ! aacparse ! queue ! mux.audio
额外排查方向
如果替换链路后仍有异常,按以下顺序排查:
- 时间戳对齐校验:视频经过重编码后会生成新的时间戳,必须保证重编码后的视频时间戳和透传的音频时间戳同源对齐,否则
flvmux会持续等待时间戳匹配的帧,出现链路停滞。可在音频、视频链路末端分别接入fakesink dump=true,确认两类缓冲区都在持续正常输出。 - 共享内存参数调整:10MB大小的共享内存完全足够承载AAC音频流(常规AAC码率仅128~320kbps,10MB可缓存数十秒的音频数据),不要设置过大的shm-size,避免出现写入指针偏移异常。
- 本地链路验证:先将shmsink/shmsrc替换为同进程内的链路直接对接fakesink/flvmux,排除编解码、封装逻辑本身的问题后,再切回跨进程共享内存链路。
内容的提问来源于stack exchange,提问作者BetaVersion
相关产品推荐
相关产品推荐

