温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

FFmpeg优化点播延时方案

发布时间:2020-07-13 16:51:02 来源:网络 阅读:36308 作者:fengyuzaitu 栏目:编程语言

场景要求
            项目要求点播速度是300到500毫秒之间,现在最长的点播延时是1300毫秒(有的时候甚至无法播放视频),生产环境是RTSP传输h364裸流数据,研究在接收到I帧的时候,开始出来图像,简化FFmpeg的调用逻辑(SPS/PPS已经预先知道,并且分辨率也是固定为1920*1080)

解决方案
1)指定SPS/PPS参数,方便在调用avcodec_open2函数打开×××的时候,找到正确的视频参数
https://blog.51cto.com/fengyuzaitu/2058138

2)通过指定视频码流格式H264减少探测时间
关键函数是:avformat_open_input和avformat_find_stream_info
https://blog.51cto.com/fengyuzaitu/1573766
https://blog.51cto.com/fengyuzaitu/1982996


3)核心是要求发送端发送的第一帧:强制I帧,根据如下的其他的方案指定码流的格式

4)用户新加入流媒体转发队列,流媒体推送用户的第一帧,不一定是I帧(这一帧之前的SPS/PPS不能少),用户需要等待一段时间才能看到画面,直到I帧的出现随着GOP的增大,时间可能更长。为了解决问题,需要缓存整一个GOP的图像序列,单纯保存I帧,没有效果,因为每一个P帧都会依赖之前的P帧,类似于后面的图片是前面图片效果的叠加。新增加的用户,先发送缓存的GOP序列,然后才发送剩下接收的数据

相关问题点有待研究
1)avformat_open_input取消问题的优化
在代码中指定如下:        
AVInputFormat* pAVInputFormat = av_find_input_format("h364");
pAVFormatContext->iformat = pAVInputFormat;
//if (avformat_open_input(&pAVFormatContext, "", pAVInputFormat, NULL) < 0)
如果不调用avformat_open_input函数实际上,影响到的是av_read_frame(pVideo->m_pAVFormatContext, packet)
出错提示:
No start code is found
Error splitting the input into NAL units
实际上av_read_frame关键作用是从缓冲中拆分出一个个NAL单元(每一个NAL单元都是从00 00 00 01作为开始码,开始的),
目前的解决方案是手动自己进行NAL单元的拆分,然后送到av_send_packet进行分帧解码(从而也取消了
av_read_frame函数的调用),手动拆分出NAL,有点麻烦

正在研究的是avformat_open_input可能会填充pAVFormatContext的URLProtocol协议字段,不过这已经是FFmpeg底层函数,
可能不可访问,正在分析源码

2)non-existing PPS 0 referenced问题
在调用av_read_frame函数的时候,会提示如上错误
non-existing PPS 0 referenced
decode_slice_header error
no frame!

但是实际上,手动添加SPS/PPS的内容到extradata字符串中,
unsigned char sps_pps[] = { 0x00 ,0x00 ,0x01,0x67,0x42,0x00 ,0x2a ,0x96 ,0x35 ,0x40 ,0xf0 ,0x04 ,0x4f ,0xcb ,0x37 ,0x01 ,0x01 ,0x01 ,0x40 ,0x00 ,0x01 ,0xc2 ,0x00 ,0x00 ,0x57 ,0xe4 ,0x01 ,0x00 ,0x00 ,0x00 ,0x01 ,0x68 ,0xce ,0x3c ,0x80, 0x00 };
pAVFormatContext->streams[0]->codecpar->extradata_size = sizeof(sps_pps);
pAVFormatContext->streams[0]->codecpar->extradata = (uint8_t*)av_mallocz(pAVFormatContext->streams[0]->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
memset(pAVFormatContext->streams[0]->codecpar->extradata, 0, sizeof(sps_pps) + FF_INPUT_BUFFER_PADDING_SIZE);
memcpy(pAVFormatContext->streams[0]->codecpar->extradata, sps_pps, sizeof(sps_pps));

FFmpeg需要通过分析数据来确定输入格式,所有程序启动时,ffmpeg收到的数据最先应该是SPS与PPS的nalu单元,然后是具体的视频数据

相关博客
https://blog.51cto.com/fengyuzaitu/2058138
https://blog.51cto.com/fengyuzaitu/2057885

3)如果知道了码流格式,实际上不需要调用什么探测码流格式的函数,直接调用AVCodecContext解码,就可以
目前在网上没有相关的资料


FFmpeg日志定向输出到文件
https://blog.51cto.com/fengyuzaitu/2053210
avcodec_send_packet函数错误定位
https://blog.51cto.com/fengyuzaitu/2046171

相关资料
1)http://www.yidianzixun.com/news_1eff46dc583b688d33a557b5582745dc
MP4的H264视频数据保存在名为mdata的box当中,MediaRecorder通过socket发送出来的MP4数据包含四部分:填充符、ftyp、mdat、slice。
其中slice就是我们要找的视频数据,slice是mdata的一部分,slice与mdata之间可能存在填充符,而slice与slice之间是连在一起的。
slice由视频数据长度(4字节,前两个字节通常为0)和视频数据组成,其中视频数据是不带起始码的H264 Nalu单元,
不难看出其第一个字节为0x65(关键帧)、0x41等。数据长度描述的是 H264 Nalu单元的长度,这样我们已经找到一帧完成的H264码流数据了,
接下来我们只需将 Nalu单元提取出来前面加上0x00 00 00 01的4字节起始码我们就得到了H264裸数据,这样的数据在播放器上还不能播放,
需在H264裸数据文件的最前端加上SPS与PPS信息(他们也是有起始码的哦),至此,播放器能够正常播放文件了

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI