ffmpeg在avformat_open_input里面已经实现了UDP的协议,所以只需要设置好参数,将url传递进去就可以了。
和打开文件的方式基本一样:
01 | 
AVCodecContext *pVideoCodecCtx = NULL; | 
 
02 | 
AVCodec *pVideoCodec = NULL; | 
 
03 | 
avcodec_register_all(); | 
 
05 | 
avformat_network_init(); | 
 
06 | 
if(m_pConfigManager == NULL) | 
 
13 | 
CString url = m_pConfigManager->GetURL(); | 
 
14 | 
int portNumber = m_pConfigManager->GetPortNumber(channel); | 
 
15 | 
url.Format(_T( "%s:%d"), url, portNumber); | 
 
17 | 
m_pFormatContext[channel] = avformat_alloc_context(); | 
 
18 | 
int err = avformat_open_input(&(m_pFormatContext[channel]), url, NULL, NULL); | 
 
21 | 
   fprintf(stderr, "Can't open %s!", url); | 
 
25 | 
m_pFormatContext[channel]->flags |= AVFMT_FLAG_GENPTS; | 
 
26 | 
m_pFormatContext[channel]->flags |= AVFMT_GENERIC_INDEX; | 
 
27 | 
m_pFormatContext[channel]->max_index_size = 99; | 
 
29 | 
if(av_find_stream_info(m_pFormatContext[channel]) < 0) | 
 
31 | 
   fprintf(stderr,"Can't find stream info \n" ); | 
 
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
 												
												
								- Android上UDP组播无法接收数据的问题
		
最近,想做一个跨平台的局域网的文件传输软件,思路是组播设备信息,TCP连接传输文件.于是进行了一次简单的UDP组播测试,发现Android对于UDP组播接收数据的支持即极为有限. 部分代码如下 pac ...
		 
						- 多网卡情况下接收udp组播
		
多网卡下接收udp组播 往往会接收失败 因为用错了网卡 例如我想要接收2网段 其他电脑出的udp组播  我电脑有有线网和wifi在window下可以这样 route add 230.0.0.1 mas ...
		 
						- UDP及其组播,接收发送封装
		
1.Receiver public class Receiver { public delegate void HeartBeat(byte[] data); public event HeartBe ...
		 
						- Android设备一对多录屏直播--(UDP组播连接,Tcp传输)
		
原文:https://blog.csdn.net/sunmmer123/article/details/82734245 近期需要学习流媒体知识,做一个Android设备相互投屏Demo,因此找到了这 ...
		 
						- C# 使用UDP组播实现局域网桌面共享
		
最近需要在产品中加入桌面共享的功能,暂时不用实现远程控制:参考了园子里的一些文章,加入了一些自己的修改. 需求:将一台机器的桌面通过网络显示到多个客户端的屏幕上,显示内容可能为PPT,Word文档之类 ...
		 
						- 【网络开发】UDP组播接收端解析
		
UDP组播接收端解析 网络中的一台主机如果希望能够接收到来自网络中其它主机发往某一个组播组的数据报,那么这么主机必须先加入该组播组,然后就可以从组地址接收数据包.在广域网中,还涉及到路由器支持组播路由 ...
		 
						- (转)C# 使用UDP组播实现局域网桌面共享
		
转:http://www.cnblogs.com/mobwiz/p/3715743.html 最近需要在产品中加入桌面共享的功能,暂时不用实现远程控制:参考了园子里的一些文章,加入了一些自己的修改.  ...
		 
						- 调皮的udp组播技术
		
2017年本科毕业,经历过千辛万苦的找工作之后,我进入了现在的这家公司.虽是职场小白,但励志成为IT界的一股清流(毕竟开发的妹子少,哈哈).因为公司的业务需要,我负责的部分是利用组播技术实现OSG模型 ...
		 
						- 桌面共享UDP组播实现
		
组播(Multicast)传输:在发送者和每一接收者之间实现点对多点网络连接.如果一台发送者同时给多个的接收者传输相同的数据,也只需复制一份的相同数据包.它提高了数据传送效率.减少了骨干网络出现拥塞的 ...
		 
		
	
随机推荐
	
									- 歌词字幕转换制作专家转换LRC-UTF,出错问题,乱码问题,格式问题
			
我使用歌词字幕转换制作专家把LRC字幕格式转换成UTF格式后竟然是乱码,求助怎么解决. 编码问题... 转换之前,要先把它处理成ANSI码.先用记事本打开lrc,然后文件-> 另存为,在对话框下 ...
			 
						- rsync + inotify-tools实现文件的实时同步
			
文章摘自:http://lxw66.blog.51cto.com/5547576/1331048 rsync 帮助文档:http://man.linuxde.net/rsync 最近有个想法就是部署一 ...
			 
						- Android:不让 EditText 在 Activity 中自动弹出键盘
			
通过属性 android:windowSoftInputMode 可以做到隐藏键盘的. android:windowSoftInputMode 属性有: stateUnspecified,stateU ...
			 
						- Hg(Mercurial)版本管理学习
			
1.关闭分支,首先切到你要关闭的分支 hg commit --close-branch -m. 2.仓库ip地址改变之后,重设仓库ip 找到.hg文件夹 - hgrc文件 - 记事本打开重设 3.推分 ...
			 
						- 【Android】3.8 定位图层展示
			
分类:C#.Android.VS2015.百度地图应用: 创建日期:2016-01-27 一.简介 Android定位SDK v6.2.2(全球定位支持)提供GPS.基站.Wi-Fi等多种定位方式,适 ...
			 
						- Base64转码和解码的帮助类
			
/** * 将字符串进行Base64编码 * * @param s 被编码的字符串 * @return 编码后的字符串 */ public static String encoderBASE64(St ...
			 
						- Spring Boot干货系列:(六)静态资源和拦截器处理
			
Spring Boot干货系列:(六)静态资源和拦截器处理 原创 2017-04-05 嘟嘟MD 嘟爷java超神学堂 前言 本章我们来介绍下SpringBoot对静态资源的支持以及很重要的一个类We ...
			 
						- java web 中 读取windows图标并显示
			
java web中读取windows对应文件名的 系统图标 ....显示 1.获取系统图标工具类 package utils;  import java.awt.Graphics;  import j ...
			 
						- java Map & List 遍历
			
一.Map 遍历 public static void main(String[] args) { Map<String, String> map = new HashMap<Str ...
			 
						- C#处理文本文件TXT实例详解(转)
			
作者:安静平和 字体:[增加 减小] 类型:转载 时间:2015-02-02我要评论 这篇文章主要介绍了C#处理文本文件TXT的方法,以实例形式详细分析了txt文本文件的读取.修改及打印等功能的实现技 ...