ffmpeg丢包原因分析

ffmpeg在avformat_open_input里面已经实现了UDP的协议,所以只需要设置好参数,将url传递进去就可以了。
和打开文件的方式基本一样:
01 AVCodecContext *pVideoCodecCtx = NULL;
02 AVCodec *pVideoCodec = NULL;
03 avcodec_register_all();
04 av_register_all();
05 avformat_network_init();
06 if(m_pConfigManager == NULL)
07 {
08 return E_POINTER;
09 }
10
11 int videoStream = -1;
12
13 CString url = m_pConfigManager->GetURL();
14 int portNumber = m_pConfigManager->GetPortNumber(channel);
15 url.Format(_T( “%s:%d”), url, portNumber);
16
17 m_pFormatContext[channel] = avformat_alloc_context();
18 int err = avformat_open_input(&(m_pFormatContext[channel]), url, NULL, NULL);
19 if(err != 0)
20 {
21 fprintf(stderr, “Can’t open %s!”, url);
22 return E_FAIL;
23 }
24
25 m_pFormatContext[channel]->flags |= AVFMT_FLAG_GENPTS;
26 m_pFormatContext[channel]->flags |= AVFMT_GENERIC_INDEX;
27 m_pFormatContext[channel]->max_index_size = 99;
28
29 if(av_find_stream_info(m_pFormatContext[channel]) < 0)
30 {
31 fprintf(stderr,”Can’t find stream info \n” );
32
33 return E_FAIL;
34 }
35
36 av_dump_format(m_pFormatContext[channel], 0, url,false);
之后就可以通过av_read_frame来获取通过UPD组播协议发送来的packet,并发送至自己的一个队列A进行缓存,再由DirectShow等视频开发框架从该队列A获取数据,并进行解码显示。
与读取文件不同,读取UDP组播协议数据包必须不断调用av_read_frame。这是因为ffmpeg在读取UDP时会新建一个数据缓冲区B,数据 通过UDP组播协议发送出来后,就被存储到这个缓冲区B里;如果长时间不调用av_read_frame(例如在读取文件时,如果自己建立的队列A已满, 则不再调用av_read_frame,而是使本线程休眠若干毫秒,等待DirectShow等前端框架从队列A取出数据包进行解码),那么不断到来的 UDP数据包就会将缓冲区B写爆,之后再调用av_read_frame就会返回-5,代表IO错误。
因为UDP组播一般是与实时源(Live Source)相关联,因此过时的数据包是没有用的,因此当队列A写满时,采取从队列A弹出若干个数据包,之后再进行av_read_frame操作。这 样的代价是在播放过程中会产生丢包(视频中出现马赛克、花屏),但是延时会控制在一个合理的范围内;也可以直接丢弃av_read_frame得到的数据 包,这样视频中的马赛克较少,但是这样会产生无法估计的延时。
另外,在同时读取多路组播数据包时,也会遇到与缓冲区B相关的问题:av_find_stream_info会在视频流中寻找并解析PPS、SPS,是非 常耗时的。在做好第一路的初始化之后,就应该立即新建一个线程用于调用av_read_frame函数获取数据(否则,第一路的缓冲区B会被写爆);与此 同时,第二路的初始化工作也将开始;由于此时有一个读取第一路UDP数据包的线程来争夺CPU时间,因此第二路的av_find_stream_info 将会花费更多的时间,这将导致第二路的缓冲区B被写爆。
上述问题的解决思路有两个,第一个是同时初始化两路UDP连接,但是在我的程序里由于有一些共享资源的限制,线程同步比较麻烦,所以后来放弃了;第二个是 尽量减少av_find_stream_info的时间或者加大缓冲区B的大小。看了AVFormatContext的属性,经过试验发现,减小 probesize和max_analyze_duration可以减少av_find_stream_info的时间,上面两个属性也不可以减少的太多,而要依据视频源的SPS和PPS的特点来确定,否则会找不到stream_info,也就没有分辨率等信息。增大缓冲区B的办法在
udp://127.0.0.1:8080后面加?overrun_nonfatal=1&fifo_size=50000000
即,ffmpeg在接收网络协议流时可以在链接上通过fifo_size进行缓冲大小的设置

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值