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的时间,但是没有找到可以增大缓冲区B的办法。。。上面两个属性也不可以减少的太多,而要依据视频源的SPS和PPS的特点来确定,否则会找不到stream_info,也就没有分辨率等信息。

解决了缓冲区的问题后,我发现播放高清视频(1080i,720p,1080p)时播放时丢包非常严重。查了半天,发现播放时队列A几乎是时时处于满状态,导致程序主动丢弃了很多数据包。再看CPU的状态,几乎是满负荷运转。输出解码和缓存的调试信息后,发现基本上解码一帧,会缓存五帧……看来是CPU太慢了(四年前的机器,AMD Turion64×2)。换到旁边同学的i3-2300(盒)上运行就非常流畅了……

看来我该换笔记本了。等28号HKUST出学生机计划,看看价钱靠不靠谱吧~谢谢阳总工提供的消息!

欢迎转载,转载请注明出处:http://guoyb.com/Tech/26.html

ffmpeg笔记——UDP组播接收总结的更多相关文章

  1. Android上UDP组播无法接收数据的问题

    最近,想做一个跨平台的局域网的文件传输软件,思路是组播设备信息,TCP连接传输文件.于是进行了一次简单的UDP组播测试,发现Android对于UDP组播接收数据的支持即极为有限. 部分代码如下 pac ...

  2. 多网卡情况下接收udp组播

    多网卡下接收udp组播 往往会接收失败 因为用错了网卡 例如我想要接收2网段 其他电脑出的udp组播  我电脑有有线网和wifi在window下可以这样 route add 230.0.0.1 mas ...

  3. UDP及其组播,接收发送封装

    1.Receiver public class Receiver { public delegate void HeartBeat(byte[] data); public event HeartBe ...

  4. Android设备一对多录屏直播--(UDP组播连接,Tcp传输)

    原文:https://blog.csdn.net/sunmmer123/article/details/82734245 近期需要学习流媒体知识,做一个Android设备相互投屏Demo,因此找到了这 ...

  5. C# 使用UDP组播实现局域网桌面共享

    最近需要在产品中加入桌面共享的功能,暂时不用实现远程控制:参考了园子里的一些文章,加入了一些自己的修改. 需求:将一台机器的桌面通过网络显示到多个客户端的屏幕上,显示内容可能为PPT,Word文档之类 ...

  6. 【网络开发】UDP组播接收端解析

    UDP组播接收端解析 网络中的一台主机如果希望能够接收到来自网络中其它主机发往某一个组播组的数据报,那么这么主机必须先加入该组播组,然后就可以从组地址接收数据包.在广域网中,还涉及到路由器支持组播路由 ...

  7. (转)C# 使用UDP组播实现局域网桌面共享

    转:http://www.cnblogs.com/mobwiz/p/3715743.html 最近需要在产品中加入桌面共享的功能,暂时不用实现远程控制:参考了园子里的一些文章,加入了一些自己的修改. ...

  8. 调皮的udp组播技术

    2017年本科毕业,经历过千辛万苦的找工作之后,我进入了现在的这家公司.虽是职场小白,但励志成为IT界的一股清流(毕竟开发的妹子少,哈哈).因为公司的业务需要,我负责的部分是利用组播技术实现OSG模型 ...

  9. 桌面共享UDP组播实现

    组播(Multicast)传输:在发送者和每一接收者之间实现点对多点网络连接.如果一台发送者同时给多个的接收者传输相同的数据,也只需复制一份的相同数据包.它提高了数据传送效率.减少了骨干网络出现拥塞的 ...

随机推荐

  1. mac下设置redis开机启动方法

    Mac OS 的开机启动方式 launchd 是 Mac OS 下用于初始化系统环境的关键进程,它是内核装载成功之后在OS环境下启动的第一个进程.其实它的作用就是我们平时说的守护进程,简单来说,用户守 ...

  2. Spring自动装配Bean详解

    1.      Auto-Wiring ‘no’ 2.      Auto-Wiring ‘byName’ 3.      Auto-Wiring ‘byType 4.      Auto-Wirin ...

  3. C++操作 SQL数据库 实例 代码步骤

    C++连接SQL数据库第一步 系统配置 1.设置SQLSERVER服务器为SQL登录方式,并且系统安全性中的sa用户要设置登录功能为“启用”,还有必须要有密码. 2.需要在ODBC中进行数据源配置,数 ...

  4. 【Android】5.7 图片库(Galery)

    分类:C#.Android.VS2015: 创建日期:2016-02-07 一.简介 图库(也叫画廊)是一个布局小部件,用于在可水平滚动的列表中显示每一副图片,当前所选的图片将置于视图的中心. 注意: ...

  5. [转载] C++的那些事:你真的了解引用吗

    我转载了roony的一篇文章 C++的那些事:你真的了解引用吗 以备以后可以查到. 一.引用的本质是什么 说到引用,一般C++的教材中都是这么定义的: 1.引用就是一个对象的别名. 2.引用不是值不占 ...

  6. ORACLE 仿照原表建表语法

    用于: 1.修改表前,可用于对原表表结构或表数据的备份 2.仿照原表的表结构建立一张新表 CREATE TABLE T_XXXX_BAK_130810 AS SELECT * FROM T_XXXX ...

  7. dwz 取不到 form中的值

    在使用dwz的时候,出现的一个问题, <li style=" width:160px;"> <label style=" width:60px;&quo ...

  8. vue2.0的常用功能简介

    路由跳转 当我们想要实现点击链接跳转时,可以使用$router来进行跳转 语法如下: '}}) 这里path是要跳转的路径,query里面是路径跳转时要携带的参数,以对象的形式存在 2 获取路由参数 ...

  9. Linux shell 执行修改配置文件中的内容

    在开发的过程中可能Linux环境不一致需要适应本地环境的HOME目录,可以通过脚本来修改配置文件内容,写一个test.sh的脚本 在脚本里写入以下命令 sed -i “s#ftfts_com_serv ...

  10. iosxcode7以后免证书真机测试方法如下

    步骤比较简单,我就简单总结一下. 1. 进入xcode,菜单栏选择xcode –> preferences (快捷键 command + ,)在Accounts选项卡添加自己的Apple ID ...