问题描述
使用ffmpeg进行软解,发现与实时视频相比较,开始没有延迟,随着时间的推移,ffmpeg软解解码延迟越来越高。
下图为工作流程,拉流模块会从相机设备通过rtsp协议拉取原始码流,然后将原始码流传给解码器进行解码。
解码延迟问题如下图记录所示,正常解码耗时如黄色框所示,13ms左右,因为不涉及B帧,因此解码的frame的dts(解码顺序)和pts(显示顺序)应该保持一致。但是经过中间的warnning后,pts和dts相差两帧(图中绿色线和橘黄线),解码耗时也如红色框所示,变为103ms,后面变得异常。
根据日志信息,勾画导致阻塞的情景,如下图所示:
随着吞帧(存帧)的数目越来越多,导致解码延迟越来越严重,表现出来就是视频播放延迟越来越严重。(正常解码不应该出现这种问题,这里推测ffmpeg本身bug)
解决方案
ffmepg会通过发送空流(eos流,data=NULL,size=0)来刷新解码管道,将全部的解码帧刷新数来,如下图所示,序号为127的对应码流的输入,会触发序号970的码流输出,序号127会被空流(eos流)刷新出来(实验是无论滞留解码器几针,都会随着eos流输入全部刷新出来,这说明不是数据不够引起的解码不出来,而是ffmpeg自己存在机制问题)。
因此由上述可以得出,当出现吞帧(存帧,滞留帧)导致解码延迟问题,可以向解码器发送空流来刷新滞留在解码器中的码流,解决该延迟问题。
直接发送空流导致的问题:
ffmpeg官方描述,发送空流后,解码器进入排空模式,从源码来看,数据进行排空模式后不在接受数据,因此向解码器发送空流后,还需要对解码器进行恢复操作。
由于不是很熟悉ffmpeg, 目前暂未找到恢复解码器的API,因此使用暴力手段,直接重新创建解码上下文。
缩减主要代码流程如下所示:
void DecodeVideoHandler::_Decode(BitStreamRef& pkt){
m_ffmpeg_resource.packet->data = (pkt->data == NULL) ? NULL : (uint8_t*)pkt->data;
m_ffmpeg_resource.packet->size = pkt->data_size;
m_ffmpeg_resource.packet->pts = pkt->time_stamp;
m_ffmpeg_resource.<