社区
C#
帖子详情
视频缓冲器
lijin177036962
2010-05-14 03:14:45
小弟真的属于技术很菜的.
最近小弟给公司做了一个H.264专用播放器.
它只支持本地播放视频.
但是公司给小弟一个任务.
让小弟可以支持网络播放.
小弟觉得应该加一个缓冲.
但是小弟很菜,
没有一点认知.
各位高手能不能给我一点思路.?
...全文
394
11
打赏
收藏
视频缓冲器
小弟真的属于技术很菜的. 最近小弟给公司做了一个H.264专用播放器. 它只支持本地播放视频. 但是公司给小弟一个任务. 让小弟可以支持网络播放. 小弟觉得应该加一个缓冲. 但是小弟很菜, 没有一点认知. 各位高手能不能给我一点思路.?
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
11 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
afeng124
2010-05-14
打赏
举报
回复
不用太感谢,自己对这个也感兴趣。希望以下的文章能帮到你。
大家知道,在网络上传输音/视频等多媒体信息目前主要有下载和流式传输两种方案。下载的主要缺点是,必须等全部内容传输完毕,然后才能在本地机器打开;而采用流式传输方案,声音、影像或动画等时基媒体由音/视频服务器向用户计算机连续、实时地传送,用户不必等到整个文件全部下载完毕,只需经过几秒或十数秒的启动延时即可进行观看。流式传输广泛应用于Internet上视频点播,以及网络视频监控等领域。
本文从Microsoft DirectShow以及Windows Socket等方面的技术角度出发,阐述一个简单的媒体流式传输、实时观看的解决方案。
关键词:DirectShow Filter Windows Socket
一. 开发原理
(一)介绍一下微软的DirectShow技术
长久以来,多媒体应用一直面临着挑战,包括多媒体大量的数据传输,快速的数据处理要求,音视频流的同步,媒体流的格式转换等等。DirectShow正是微软针对以上问题设计,并且很好地解决了这些问题的一种应用架构。它的设计目标是,隔离数据传输、硬件兼容、流同步等底层处理,使客户能够轻轻松松地创建Windows应用平台上的多媒体应用程序。
为提高数据处理的效率,DirectShow运用了DirectDraw和DirectSound技术。同时,DirectShow还运用了COM组件技术,它的名字叫作Filter。Filter大致可分为三种:Source Filters、Transform Filters、Rendering Filters。Filter传输数据的端口叫作Pin。Pin有Input Pin和Output Pin两种。在应用中,将各种Filter连接起来,也就是将前面Filter(Upstream Filter)的Output Pin与后面Filter(Downstream Filter)的Input Pin连接起来,即组成一个完整的Filter Graph。运行这个Filter Graph,多媒体数据就开始从Source Filters,经过Transform Filters到Rendering Filters流动。DirectX提供了一个非常实用的工具——GraphEdit.exe——用以可视化调试Filter。下面看一下DirectShow大致的处理流程图:
在我们后面的应用实例中,我们自己编写了一个Filter(这是一个Source Filter),用于异步读取网络上出来的Mpeg1数据;紧跟这个Filter后面的是Transform Filters,负责Mpeg1数据的音视频分离(Mpeg1 Stream Splitter)、音视频数据的解码(Mpeg Audio Decoder和Mpeg Video Decoder);然后是音视频流各自的Rendering Filters,一个叫Video Renderer的负责视频的显示,一个叫Default DirectSound Device的负责音频数据的播放。参考图如下:
注:Source Filter的改写参考了DirectX 8.0 SDK的例子代码,它的路径为:samplesMultimediaDirectShow FiltersAsyncMemfile。
(二)介绍一下Windows Socket网络传输技术
我们要处理的数据并不在本地计算机,而是由另外一台视频服务器负责发送出来。那么,我们如何得到这些数据,然后再使用我们的DirectShow Filter进行处理呢?这就用到了Windows Socket技术。
运用Windows Socket技术,能够让两台计算机通过网络建立连接,并且通过定义一些上层协议,实现计算机之间的大量数据传输以及其他一些控制。微软的MFC也提供了两个类:CAsyncSocket和CSocket,用以方便客户使用Socket的特性。CAsyncSocket从较低层次封装了Windows Socket API,并且通过内建一个窗口,实现了适合Windows应用的异步机制。CSocket类从CAsyncSocket中继承而来,更简化了客户对Socket的应用。但是,这两个类均有缺陷,特别是在跨线程使用Socket的时候。
在我们后面的应用实例中,因为处理的数据量较大,我们使用了多线程。在负责数据发送的服务器端,使用专门的线程进行数据的发送;在客户端,使用专门的线程进行数据的接收,并把数据放到缓冲队列中,供DirectShow Filter读取处理。因此,我们自己封装了几个Socket的类:CListenSocket(用于服务器端建立监听客户连接的Socket类)、CWorkerSocket(负责数据传输的Socket基类)。从CWorkerSocket再派生两个类:CMediaSocketServer(用于服务器端数据的发送)和CMediaSocketClient(用于客户端数据的接收)。
我们把连续不断的Mpeg1数据分成一个一个小包的负载数据(取一个PACK的大小,2324字节),加上一定的信息头,在网络两端传输。定义的数据结构为:
// Message header
typedef struct
{
unsigned int nMsgType:8; // Payload type
unsigned int nDataSize:16; // Payload size
} MSG_HEADER, *PMSG_HEADER;
typedef struct
{
CHAR MPEGData[2324];
} MPEG1_PACK, *PMPEG1_PACK;
定义的一些信息头参考如下:
// Payload types
#define DATA_REQUEST 0X00 // Request the remote data
#define DATA_REFUSED 0X01 // Refuse the remote data
#define DATA_MEDIA 0X02 // Media data
#define DISCONNECT_REQUEST 0X03 // Request the remote to shut down
至于网络客户端的接收,首先阻塞地接收一个消息头大小(sizeof(MSG_HEADER))的数据,然后根据nDataSize的值接收相应的负载数据。
(三)介绍一种双缓冲队列技术
网络客户端接收到的Mpeg1数据,必须进行一定量的缓冲,然后才能交给DirectShow解码处理。接着,动态地,一边继续从网络接收数据,一边得到新的数据进行解码回放。这里介绍一种使用的双缓冲队列技术。
大致的工作原理是,建立两个队列,一个是PoolList,空闲的缓冲队列,用以接收存放数据;另一个是DataList,尚未处理的数据缓冲队列,等待处理。网络接收这边:当客户端接收到一个包的数据,从PoolList队列的头拿出一个缓冲,存放数据,然后将这个缓冲加入到DataList的尾部等待DirectShow的Filter读取。DirectShow这边:从DataList队列的头拿出一个缓冲,读取数据,将读完的缓冲加到PoolList的尾部,等待再一次地接收数据。
二. 应用实例
开发环境:Windows 2000,PII 400,Microsoft DirectX SDK 8.0
开发工具:Microsoft Visual C++ 6.0
应用模型:Dialog Based Application
开发步骤:
(1) 服务器端(MediaServer)
服务器端负责Mpeg1数据的发送,供演示用。这里主要的工作是,在对话框初始化函数(OnInitDialog)中建立一个监听Socket。当客户端有连接请求时,CListenSocket中就发出一个自定义消息WM_NEW_SOCKET给主对话框;主对话框响应该消息,用CMediaSocketServer与客户端建立建立连接。
CMediaSocketServer有两个独立的工作者线程,用户可以自定义它们的线程循环体。CMediaSocketServer::ReceivingLoop为接收线程处理,当接收到DATA_REQUEST命令后就开始数据发送;数据发送处理在CMediaSocketServer::SendingLoop中。请参考演示代码,下面我们重点讲一下客户端的DirectShow处理技术。
(2) 客户端(MediaClient)
客户端负责数据传输的是CMediaSocketClient类,接收线程处理体为CmediaSocket Client::ReceivingLoop;CDataAdmin类封装了双缓冲队列对数据的管理。实现细节请参考演示代码。
下面重点讲一下DirectShow是如何将数据进行解码回放的。
l CFilterGraph类封装了Filter以及Filter Graph的创建和控制。
HRESULT hr = CoCreateInstance(CLSID_FilterGraph,
NULL,
CLSCTX_INPROC,
IID_IGraphBuilder,
(void**)&m_pGB);
创建了Filter Graph的一个实例。
hr = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
得到了启动、停止这个Filter Graph的控制接口。还有其他控制接口,如控制视频传口的m_pVW、控制音频的m_pBA等。
CMemReader是我们自己编写的一个Filter,通过AddFilter方法将其加入到以上Filter Graph中,如下:
hr = m_pGB->AddFilter(m_pSourceReader, NULL);
最后一步是,得到Source Filter的Output Pin,然后Render这个Pin,完整的Filter Graph就构建成功了。Filter Graph的参考图见上文。
HRESULT hr = m_pGB->Render(m_pSourceReader->GetPin(0));
l 我们编写的这个Filter,相关的源文件有asyncio.cpp、asyncio.h、asyncrdr.cpp、asyncrdr.h和MemFilter.h。前四个是DirectShow SDK提供的基类,我们在MemFilter中派生了自己的两个类CMemStream和CMemReader,以定义我们自己的Filter行为。Filter Graph中有两种基本的数据流模式:推模式(Push Mode)和拉模式(Pull Mode)。推模式情况下,Source Filter主动把数据往下传送;而在拉模式下,需要后面的Filter向Source Filter请求数据。我们的Source Filter就属于拉模式的Filter,它的Output Pin必须实现IAsyncReader接口。数据的流动,主要靠后面的Filter(本例中为Mpeg1 Stream Splitter)调用Source Filter的Output Pin上IAsyncReader接口的Read方法。下面是我们的Filter的Read方法实现,这也是本应用方案的关键部分:
HRESULT Read(PBYTE pbBuffer, DWORD dwBytesToRead,
BOOL bAlign, LPDWORD pdwBytesRead)
{
if (m_pDataList == NULL) return S_FALSE;
CAutoLock lck(&m_csLock);
DWORD dwHaveRead = 0;
PMPEG1_PACK pPack = NULL;
while (dwHaveRead < dwBytesToRead){
if (dwBytesToRead - dwHaveRead >= MPEG1_PACK_SIZE - m_ulPositionInPack) {
// Just copy the whole pack data
pPack = m_pDataList->GetDataBuffer();
if (pPack != NULL) {
CopyMemory((PVOID)(pbBuffer + dwHaveRead),
(PVOID)((PBYTE)(pPack) + m_ulPositionInPack), (SIZE_T)MPEG1_PACK_SIZE - m_ulPositionInPack);
m_pDataList->ReleaseDataBuffer(pPack);
dwHaveRead += MPEG1_PACK_SIZE - m_ulPositionInPack;
m_ulPositionInPack = 0;
}
else if (m_pDataList->IsFlushing()) { return E_FAIL; }
else { Sleep(10); }
}
else {
// Copy part of the pack data
pPack = m_pDataList->PointToDataHead();
if (pPack != NULL) {
m_ulPositionInPack = dwBytesToRead - dwHaveRead;
CopyMemory((PVOID)(pbBuffer + dwHaveRead),
(PVOID)(pPack), (SIZE_T)m_ulPositionInPack);
dwHaveRead += m_ulPositionInPack;
}
else if (m_pDataList->IsFlushing()) {return E_FAIL;}
else {Sleep(10); }
}
}
*pdwBytesRead = dwBytesToRead;
return S_OK;
}
(3) 演示过程
l 运行Builds目录下的MediaServer.exe程序,并选择一个Mpeg1文件(如Demo.mpg);
l 在网络中的另一台计算机(或本机)上运行MediaClient.exe程序,确认启动MediaServer程序的计算机IP地址;
l 然后单击“连接”按钮,再单击“传输”按钮,1-2秒钟后,即可在客户端看到图像,并且界面上有客户端已经接收到数据包个数的动态显示;
l 按“断开”按钮即可将服务器端和客户端的Socket连接断开,停止传输数据。
三. 几点说明
1. 本方案用到了DirectX 8.0 SDK,请确认配置好了您的VC开发环境:首先将DirectX8的安装目录下例子代码中的DirectShow基类编译一下,Debug版本生成strmbasd.lib,Release版本生成strmbase.lib;然后配置VC开发环境:Tools->Options-> Directories->Include files加入两个路径,DirectX8include和DIRECTX8SAMPLESMULTIMEDIADIRECTSHOWBASECLASSES,并且在MFC目录的前面;Library file加入三个路径,DirectX8lib、DIRECTX8SAMPLESMULTIMEDIADIRECTSHOWBASECLASSESDEBUG和DIRECTX8SAMPLESMULTIMEDIADIRECTSHOWBASECLASSESRELEASE。
2. 本演示方案采用Mpeg1格式的数据,但该方案并不局限于Mpeg1。
3. 由于演示代码没有实时的数据源,所以服务器端通过读取Mpeg1文件的方法模拟实时数据。演示中,可以采用较大的Mpeg1文件,效果会更逼真。
4. 本方案应用到网络实时监控时,可能还会涉及到Mpeg数据流的随机访问,即Mpeg数据流分析、截取问题,限于篇幅,本文不作介绍。有兴趣的朋友可以参考相关资料后,对示例代码进行修改。
5. 本方案的演示代码仅限于一对一的传输,只要稍加修改,服务器端便可提供多路数据的传输。
afeng124
2010-05-14
打赏
举报
回复
socket + DirectX
afeng124
2010-05-14
打赏
举报
回复
Visual C#使用DirectX实现视频播放
本文来自[Svn中文网]转发请保留本站地址:http://www.svn8.com/dotnet/Csharp/2010012318719.html
wuyq11
2010-05-14
打赏
举报
回复
网络播放可用media player
http://topic.csdn.net/u/20100423/22/50bb8ea5-ebf1-4181-8f1c-4cdd1aceecd6.html
lijin177036962
2010-05-14
打赏
举报
回复
[Quote=引用 6 楼 yuanhuiqiao 的回复:]
参考
[/Quote]
我现在本地播放已经成功了.
现在 要添加url播放.
这个功能怎么实现.?
yuanhuiqiao
2010-05-14
打赏
举报
回复
参考
Forrest23
2010-05-14
打赏
举报
回复
H.264专用播放器? 没做过这方面的 等待楼下
lijin177036962
2010-05-14
打赏
举报
回复
看过的,不会的,能否帮顶下.?谢谢.!
tashiwoweiyi
2010-05-14
打赏
举报
回复
自己帮顶,要不沉了
lijin177036962
2010-05-14
打赏
举报
回复
自己帮顶,要不沉了.
【粗读webrtc】 jitterbuffer 2 音
视频
抖动缓冲区
webrtc音
视频
抖动缓冲区伪代码 webrtc音
视频
抖动缓冲区伪代码 rtp包几个时间值: 接收时间 ,发送时间,网络传输时间,网络延迟时间(网络排队) rtp包的接收时间 = sendtime + transferTime rtp包的接收时间 = sendtime + transferTime + netdelayTime 抖动缓冲区目的就是为了消除网络延迟对音
视频
的平滑播放造成的影响,如果没有抖动缓冲区,就可能 播放的
视频
时快时慢,播放的音频断断续续。 计算抖动的第一步就是计算网络的延迟,第二部根据.
音
视频
环形缓冲区 介绍与实现
一、什么是环形缓冲区环形缓冲区(也称为循环缓冲区)是固定大小的缓冲区,工作原理就像内存是连续的且可循环的一样。在生成和使用内存时,不需将原来的数据全部重新清理掉,只要调整head/tail 指针即可。当添加数据时,head 指针前进。当使用数据时,tail 指针向前移动。当到达缓冲区的尾部时,指针又回到缓冲区的起始位置。二、为什么使用环形缓冲区环形缓冲区是嵌入式系统中十分...
接收端的
视频
缓冲方法
一种网络
视频
服务系统接收端的
视频
缓冲方法 CN 102665131 A 摘要 本发明的网络
视频
服务系统接收端的
视频
缓冲方法,包括:a.建立缓冲队列;b.接收数据并分块;c.存入缓冲队列;d.比较前n个数据块的接收与播放时间的大小,判断当前网速大小;e.如网速足够,则按照正常速率播放;f.如网速不够,则进行进一步判断;g.降低播放速率。步骤f包括:f-1.如果缓冲队列中数据块个数大于n
帧
缓冲器
:分页
帧
缓冲器
帧
缓冲器
的容量往往设计得比屏幕画面的位图大得多,也就是说,帧
缓冲器
可以同时存放多幅画面的位图,这时帧
缓冲器
区域可分成若干页面,每个页面存放一幅位图,并通过控制器就实现不同画面的切换。页面的大小可以划分得比屏幕位图大得多,甚至是整个帧
缓冲器
,这时,从程序员的角度来看,可输出显示的画面将远大于实际的物理屏幕,此时物理屏幕仅是一个窗口,它显示的不过是全部
【信源编码技术】作业5-
视频
编解码器缓冲区
视频
编解码器缓冲区 对
视频
序列编码导致输出变比特率码流,因此需要一个编码缓冲区,将变比特率(VBR)码流与固定码率(CBR)的信道连接起来;还需要一个解码缓冲区,将固定码率的信道与变比特率码流连接起来.
视频
编解码传输系统示意图 固定码率(CBR)传输分析 A: 发送端缓冲区中积累的比特数 B: 已从解码端缓冲区移出的比特数 C: 从编码器到解码器的比特传输速率,即固定码率(CBR) 编解码器缓冲区的四种溢出状态: 1、当A-C超出编码器缓冲区容量,则编码器缓冲区上溢 2、当A.
C#
110,577
社区成员
642,559
社区内容
发帖
与我相关
我的任务
C#
.NET技术 C#
复制链接
扫一扫
分享
社区描述
.NET技术 C#
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
让您成为最强悍的C#开发者
试试用AI创作助手写篇文章吧
+ 用AI写文章