vcdirectshow:在VC中调用DirectShow全屏播放视频



  有些正在尝试自己编制游戏朋友可能会碰到这样个问题:游戏要播放片头动画可是如何全屏播放动画呢?用媒体播放机Control控件?这是最简单思路方法可是好多功能都用不上不免觉得有些浪费而用vfw的类多媒体库又太麻烦如何办呢?

   其实微软不但提供了DirectX这样便于游戏开发SDK还提供了基于其上DirectX Media SDK这套SDK可以帮助你简化多媒体开发而又充分利用DirectX高性能使用起来很简单功能也很强大它可以自己识别流格式连mpeg2都不放过!

下面我以例子来介绍说明如何DirectShow来全屏播放视频:

首先需要在工程中包含如下头文件:
# \"ddraw.h\"
# \"mmstream.h\"
# \"amstream.h\"
# \"ddstream.h\"

这些头文件提供了必要数据结构和思路方法声明

其次我们可以将整个流程分为3个步骤:
1、建立DirectDraw表面(Surface)
2、从文件中提取视频流(可能还有音频)
3、在DirectDraw上表面播放视频流

必要变量:
DDSURFACEDESC ddsd;
IDirectDraw *pDD;  
IDirectDrawSurface *pPrimarySurface;
IMultiMediaStream *pMMStream;

IMultiMediaStream接口是DirectShow中最高等级接口对象可以包含个或多个多媒体对象
这些多媒体对象可以是区别类型比如音频视频等等下面大家将会看到

化思路方法中加入如下代码:
HRESULT Init
{
......
pDD=NULL;
pPrimarySurface=NULL;
pMMStream=NULL;
ZeroMemmory(ddsd,(ddsd));

HRESULT r;
//化COM
CoInitialize(NULL);
//化DirectDraw
r=InitDDraw;

r;
}

由于DirectShow是基于COM所以要用CoInitialize化COM,该思路方法很简单只有个参数且必
须是NULL
InitDDraw实现将在后面给出

析构思路方法中加入如下代码:
void Uninit
{
......
(pMMStream!=NULL)
pMMStream->Release;
(pPrimarySurface!=NULL)
pPrimarySurface->Release;  
(pDD!=NULL)
pDD->Release; 

CoUninitialize;
}

化DirectDraw并建立DirectDraw表面:(由于DirectDraw不是本文重点原理请参考相关
文献现只给出代码)
不妨建立个思路方法将这些工作统统包括:
HRESULT InitDDraw
{
HRESULT r;
(FAILED(r=DirectDrawCreate(NULL, &pDD, NULL)))
r;
(FAILED(r=pDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN)))
r;
(FAILED(r=pDD->SetDisplayMode(640,480,16))) //分辨率设置
r;
 
ddsd.dwSize = (ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
(FAILED(pDD->CreateSurface(&ddsd, &pPrimarySurface, NULL)))
r;

S_OK;
}

接下来步将从文件中提取视频流
不妨也建立个思路方法将工作封装
HRESULT LoadFromFile(const char * szFileName, IMultiMediaStream **ppMMStream, IDirectDraw *pDD)
{
HRESULT r;
IAMMultiMediaStream *pAMStream;

(FAILED(r=CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER, IID_IAMMultiMediaStream, (void **)&pAMStream)))
r;

WCHAR wPath[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, szFileName, -1, wPath, (wPath)/(wPath[0]));  

(FAILED(r=pAMStream->Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, NULL)))
r;
(FAILED(r=pAMStream->AddMediaStream(pDD, &MSPID_PrimaryVideo, 0, NULL)))
r;
(FAILED(r=pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, AMMSF_ADDDEFAULTRENDERER, NULL)))
r;
(FAILED(r=pAMStream->OpenFile(wPath, 0)))
r;
*ppMMStream = pAMStream;
S_OK;
}
思路方法代码如上

LoadFromFile思路方法有3个参数:
const char * szFileName, IMultiMediaStream **ppMMStream和IDirectDraw *pDD

个参数是要提取文件名串常量第 2个参数是多媒体流接口指针指针是用来操纵多媒体流第 3个参数是DirectDraw接口将来播放时就是通过它表面

首先声明个IAMMultiMediaStream接口指针该接口功能十分强大这里只用了它部分:
建立视频和音频流再从文件中提取

然后CoCreateInstance思路方法来创建IAMMultiMediaStream例子该思路方法个参数指定了全局标志(guid下同)第 4个参数指明要创建接口标志第 5个参数是创建好例子返回付给pAMStream变量

接下来两行代码是将char串转换成unicode不必多言

然后化IAMMultiMediaStream建立视频音频流

最后也是最重要步:OpenFile()思路方法从文件中提取流个参数是文件名第 2个参数是打开方式(具体请参考msdn)

这样就完成了流提取工作

下面开始播放
这也是最复杂工作(相对)

同样建个思路方法封装代码
HRESULT Play(IDirectDrawSurface *pSurface, IMultiMediaStream *pMMStream)
{  
IMediaStream *pPrimaryVidStream;  
IDirectDrawMediaStream *pDDStream;
IDirectDrawStreamSample *pSample;
RECT rect;
DDSURFACEDESC ddsd;



pMMStream->GetMediaStream(MSPID_PrimaryVideo, &pPrimaryVidStream);
pPrimaryVidStream->QueryInterface(IID_IDirectDrawMediaStream, (void **)&pDDStream);
ddsd.dwSize = (ddsd);
pDDStream->GetFormat(&ddsd, NULL, NULL, NULL);
 
rect.top =100;
rect.left =150;
rect.bottom = ddsd.dwHeight+100;
rect.right = ddsd.dwWidth+150;
 
pDDStream->CreateSample(pSurface, &rect, 0, &pSample);
pMMStream->SetState(STREAMSTATE_RUN);

while (pSample->Update(0, NULL, NULL, NULL) S_OK)
;

pMMStream->SetState(STREAMSTATE_STOP);
pSample->Release;  
pDDStream->Release;
pPrimaryVidStream->Release;
}

Play思路方法有两个参数个是用来播放视频DirectDraw表面个是含有数据流MultiMediaStream对象

变量声明如下:
IMediaStream *pPrimaryVidStream;  
IDirectDrawMediaStream *pDDStream;
IDirectDrawStreamSample *pSample;
RECT rect;
DDSURFACEDESC ddsd;

他们分别是IMediaStream接口用来查询IDirectDrawMediaStream接口;DirectDrawMediaStream接口用来得到流数据细节如长、宽等等;IDirectDrawStreamSample接口这是个数据样本用来刷新DirectDraw表面也就是播放了
接下来两个分别是:个rect数据结构用来指定播放区域;个表面描述这里用来得到样本数据格式

然后是实现部分:

首先IMultiMediaStreamGetMediaStream()思路方法来得到个IMediaStream视频对象流类型由参数MSPID_PrimaryVideo指定
接着通过IMediaStream来查询得到IDirectDrawMediaStream接口(具体机理请参考COM文献这里不再累述)
然后由IDirectDrawMediaStream接口获取数据格式建立样本并关联到DirectDraw表面IMediaStream接口通过
SetState(STREAMSTATE_RUN)思路方法来播放媒体流播放数据由IDirectDrawStreamSample样本刷新到DirectDraw表面上
如果刷新成功IDirectDrawStreamSample::Update()思路方法返回S_OK放完了以后再IMediaStream::SetState(STREAMSTATE_STOP)停止媒体流

就这样DirectShow通过这些接口互相协作着完成了视频流播放

由于篇幅所限只列出了核心代码如果大家有兴趣可以到我网站WebSite下载个demo(付源码)
网址如下:http://www.sunistudio.com

本人才疏学浅如有的处还望高手指点!^o^

Tags:  vc调用dll directshow播放器 directshow播放 vcdirectshow

延伸阅读

最新评论

发表评论