一个简单的基于 DirectShow 的播放器 1(封装类)
DirectShow最主要的功能就是播放视频,在这里介绍一个简单的基于DirectShow的播放器的例子,是用MFC做的,今后有机会可以基于该播放器开发更复杂的播放器软件。
注:该例子取自于《DirectShow开发指南》
首先看一眼最终结果,如图所示,播放器包含了:打开,播放,暂停,停止等功能。该图显示正在播放周杰伦的《听妈妈的话》。
迅速进入主题,看一看工程是由哪些文件组成的,如下图所示
从上图可以看出,该工程最重要的cpp文件有两个:SimplePlayerDlg.cpp和CDXGraph.cpp。前者是视频播放器对话框对应的类,而后者是对DirectShow功能进行封装的类。尤其是后面那个类,写的很好,可以说做到了“可复用”,可以移植到其他DirectShow项目中。
本文首先分析CDXGraph这个类,SimplePlayerDlg在下篇文章中再进行分析。
首先看看它的头文件:
CDXGraph.h
/* 雷霄骅
* 中国传媒大学/数字电视技术
* leixiaohua1020@126.com
*
*/
// CDXGraph.h
#ifndef __H_CDXGraph__
#define __H_CDXGraph__
// Filter graph notification to the specified window
#define WM_GRAPHNOTIFY (WM_USER+20)
class CDXGraph
{
private:
//各种DirectShow接口
IGraphBuilder * mGraph;
IMediaControl * mMediaControl;
IMediaEventEx * mEvent;
IBasicVideo * mBasicVideo;
IBasicAudio * mBasicAudio;
IVideoWindow * mVideoWindow;
IMediaSeeking * mSeeking;
DWORD mObjectTableEntry;
public:
CDXGraph();
virtual ~CDXGraph();
public:
//创建IGraphBuilder,使用CoCreateInstance
virtual bool Create(void);
//释放
virtual void Release(void);
virtual bool Attach(IGraphBuilder * inGraphBuilder);
IGraphBuilder * GetGraph(void); // Not outstanding reference count
IMediaEventEx * GetEventHandle(void);
bool ConnectFilters(IPin * inOutputPin, IPin * inInputPin, const AM_MEDIA_TYPE * inMediaType = 0);
void DisconnectFilters(IPin * inOutputPin);
bool SetDisplayWindow(HWND inWindow);
bool SetNotifyWindow(HWND inWindow);
bool ResizeVideoWindow(long inLeft, long inTop, long inWidth, long inHeight);
void HandleEvent(WPARAM inWParam, LPARAM inLParam);
//各种操作
bool Run(void); // Control filter graph
bool Stop(void);
bool Pause(void);
bool IsRunning(void); // Filter graph status
bool IsStopped(void);
bool IsPaused(void);
bool SetFullScreen(BOOL inEnabled);
bool GetFullScreen(void);
// IMediaSeeking
bool GetCurrentPosition(double * outPosition);
bool GetStopPosition(double * outPosition);
bool SetCurrentPosition(double inPosition);
bool SetStartStopPosition(double inStart, double inStop);
bool GetDuration(double * outDuration);
bool SetPlaybackRate(double inRate);
// Attention: range from -10000 to 0, and 0 is FULL_VOLUME.
bool SetAudioVolume(long inVolume);
long GetAudioVolume(void);
// Attention: range from -10000(left) to 10000(right), and 0 is both.
bool SetAudioBalance(long inBalance);
long GetAudioBalance(void);
bool RenderFile(const char * inFile);
bool SnapshotBitmap(const char * outFile);
private:
void AddToObjectTable(void) ;
void RemoveFromObjectTable(void);
//各种QueryInterface,初始各种接口
bool QueryInterfaces(void);
};
#endif // __H_CDXGraph__
该头文件定义了CDXGraph类封装的各种DirectShow接口,以及提供的各种方法。在这里因为方法种类特别多,所以只能选择最关键的方法进行分析。下面打开CDXGraph.cpp看看如下几个方法吧:
Create():用于创建IGraphBuilder
//创建IGraphBuilder,使用CoCreateInstance
bool CDXGraph::Create(void)
{
if (!mGraph)
{
if (SUCCEEDED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&mGraph)))
{
AddToObjectTable();
return QueryInterfaces();
}
mGraph = 0;
}
return false;
}
需要注意的是,Create()调用了QueryInterfaces()
QueryInterfaces():用于初始化各种接口
//各种QueryInterface,初始各种接口
bool CDXGraph::QueryInterfaces(void)
{
if (mGraph)
{
HRESULT hr = NOERROR;
hr |= mGraph->QueryInterface(IID_IMediaControl, (void **)&mMediaControl);
hr |= mGraph->QueryInterface(IID_IMediaEventEx, (void **)&mEvent);
hr |= mGraph->QueryInterface(IID_IBasicVideo, (void **)&mBasicVideo);
hr |= mGraph->QueryInterface(IID_IBasicAudio, (void **)&mBasicAudio);
hr |= mGraph->QueryInterface(IID_IVideoWindow, (void **)&mVideoWindow);
hr |= mGraph->QueryInterface(IID_IMediaSeeking, (void **)&mSeeking);
if (mSeeking)
{
mSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
}
return SUCCEEDED(hr);
}
return false;
}
Release():释放各种接口
//释放
void CDXGraph::Release(void)
{
if (mSeeking)
{
mSeeking->Release();
mSeeking = NULL;
}
if (mMediaControl)
{
mMediaControl->Release();
mMediaControl = NULL;
}
if (mEvent)
{
mEvent->Release();
mEvent = NULL;
}
if (mBasicVideo)
{
mBasicVideo->Release();
mBasicVideo = NULL;
}
if (mBasicAudio)
{
mBasicAudio->Release();
mBasicAudio = NULL;
}
if (mVideoWindow)
{
mVideoWindow->put_Visible(OAFALSE);
mVideoWindow->put_MessageDrain((OAHWND)NULL);
mVideoWindow->put_Owner(OAHWND(0));
mVideoWindow->Release();
mVideoWindow = NULL;
}
RemoveFromObjectTable();
if (mGraph)
{
mGraph->Release();
mGraph = NULL;
}
}
Run():播放
bool CDXGraph::Run(void)
{
if (mGraph && mMediaControl)
{
if (!IsRunning())
{
if (SUCCEEDED(mMediaControl->Run()))
{
return true;
}
}
else
{
return true;
}
}
return false;
}
Stop():停止
bool CDXGraph::Stop(void)
{
if (mGraph && mMediaControl)
{
if (!IsStopped())
{
if (SUCCEEDED(mMediaControl->Stop()))
{
return true;
}
}
else
{
return true;
}
}
return false;
}
Pause():暂停
bool CDXGraph::Pause(void)
{
if (mGraph && mMediaControl)
{
if (!IsPaused())
{
if (SUCCEEDED(mMediaControl->Pause()))
{
return true;
}
}
else
{
return true;
}
}
return false;
}
SetFullScreen():设置全屏
bool CDXGraph::SetFullScreen(BOOL inEnabled)
{
if (mVideoWindow)
{
HRESULT hr = mVideoWindow->put_FullScreenMode(inEnabled ? OATRUE : OAFALSE);
return SUCCEEDED(hr);
}
return false;
}
GetDuration():获得视频时长
bool CDXGraph::GetDuration(double * outDuration)
{
if (mSeeking)
{
__int64 length = 0;
if (SUCCEEDED(mSeeking->GetDuration(&length)))
{
*outDuration = ((double)length) / 10000000.;
return true;
}
}
return false;
}
SetAudioVolume():设置音量
bool CDXGraph::SetAudioVolume(long inVolume)
{
if (mBasicAudio)
{
HRESULT hr = mBasicAudio->put_Volume(inVolume);
return SUCCEEDED(hr);
}
return false;
}
RenderFile():关键!
bool CDXGraph::RenderFile(const char * inFile)
{
if (mGraph)
{
WCHAR szFilePath[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, inFile, -1, szFilePath, MAX_PATH);
if (SUCCEEDED(mGraph->RenderFile(szFilePath, NULL)))
{
return true;
}
}
return false;
}
播放器源代码下载:http://download.csdn.net/detail/leixiaohua1020/6453467
一个简单的基于 DirectShow 的播放器 1(封装类)的更多相关文章
- 一个简单的基于 DirectShow 的播放器 2(对话框类)
上篇文章分析了一个封装DirectShow各种接口的封装类(CDXGraph):一个简单的基于 DirectShow 的播放器 1(封装类) 本文继续上篇文章,分析一下调用这个封装类(CDXGrap ...
- 转:最简单的基于 DirectShow 的视频播放器
50行代码实现的一个最简单的基于 DirectShow 的视频播放器 本文介绍一个最简单的基于 DirectShow 的视频播放器.该播放器对于初学者来说是十分有用的,它包含了使用 DirectSho ...
- 50行代码实现的一个最简单的基于 DirectShow 的视频播放器
本文介绍一个最简单的基于 DirectShow 的视频播放器.该播放器对于初学者来说是十分有用的,它包含了使用 DirectShow 播放视频所有必备的函数. 直接贴上代码,具体代码的含义都写在注释中 ...
- 一个简单有趣的Python音乐播放器
(赠新手,老鸟绕行0.0) Python版本:3.5.2 源码如下: __Author__ = "Lance#" # -*- coding = utf-8 -*- #导入相应模块 ...
- 自己实现一个简单的网络音乐mp3播放器
大繁至简,把思路搞清楚才是最重要的,如何去做依托于使用什么来实现这项功能 列出我使用的基本类 NSURLSessionDataTask 数据获取类 NSFileHandle 数据缓存和数据读取类 Au ...
- 最简单的基于DirectShow的示例:视频播放器自定义版
===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...
- 最简单的基于DirectShow的示例:视频播放器图形界面版
===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...
- 最简单的基于DirectShow的示例:视频播放器
===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...
- 最简单的基于DirectShow的示例:获取Filter信息
===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...
随机推荐
- Android之Animation动画各属性的参数意思(二)
现在就来讲讲Animation里这四个标签的属性. 一.这四个标签alpha.scale.translate.rotate共有的属性为: android:duration 动画持续时间, ...
- T-SQL动态查询(4)——动态SQL
接上文:T-SQL动态查询(3)--静态SQL 前言: 前面说了很多关于动态查询的内容,本文将介绍使用动态SQL解决动态查询的一些方法. 为什么使用动态SQL: 在很多项目中,动态SQL被广泛使用甚至 ...
- FORM触发器
FORM级触发器 PRE-FORM该触发器是在用户双击功能后,进入form前 WHEN-NEW-FORM-INSTANCE该触发器是在用户一进入form时执行 WHEN-FORM-NAVIGAT ...
- UNIX网络编程——Socket粘包问题
一.两个简单概念长连接与短连接:1.长连接 Client方与Server方先建立通讯连接,连接建立后不断开, 然后再进行报文发送和接收. 2.短连接 Client方与Server每进行一次报文收发交易 ...
- 浅谈Android布局
在前面的博客中,小编介绍了Android的极光推送以及如何实现登录的一个小demo,对于xml布局页面,摆控件这块的内容,小编还不是很熟练,今天小编主要简单总结一下在Android中的布局,学习过An ...
- 内存管理单元--MMU
现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)机制,这需要处理器中的MMU(Memory Management Unit,内存管理单元)提供支持,本节简要介绍M ...
- Docker教程:docker machine的配置和命令
http://blog.csdn.net/pipisorry/article/details/50921335 安装virtualbox 如果要使用virtualbox,首先要安装virtualbox ...
- 03_NoSQL数据库之Redis数据库:list类型
lists类型及操作 List是一个链表结构,主要功能室push,pop.获取一个范围的所有值等等,操作中key理解为链表的名字.Redis的list类型其实就是一个每个元素都是string类型 ...
- Java-IO之字符输入输出流(Reader和Writer)
以字符为单位的输入流的公共父类是Reader: 以字符为单位的输出流的超类是Writer: 基于JDK8的Reader的源码: public abstract class Reader impleme ...
- 【翻译】Ext JS最新技巧——2015-10-21
原文:Top Support Tips Kevin Cassidy:全宽度的字段错误信息 有考虑过让验证信息显示在表单字段的下面(msgTarget:'under'),但最后发现验证信息被压缩显示了吗 ...