DirectShow Filter 开发典型例子分析 ——字幕叠加 (FilterTitleOverlay)1

本文分析一下《DirectShow开发指南》中的一个典型的Transform Filter的例子:字幕叠加(FilterTitleOverlay)。通过分析该例子,我们可以学习到DirectShow Transform Filter 开发的方式。

直接打开项目工程(我这里是VC2010),看到项目的结构如下图所示:

先看一下运行的结果:

注意,DirectShow的Filter是不可以直接运行进行调试的。一般情况下需要借助于Graphedit.exe这个程序进行调试。当然这不是绝对的,也可以用graph-studio-next这样的开源程序。

选择右键点击工程->属性->调试->命令。在栏中输入Graphedit.exe的路径,如图所示

这样就可以调试Filter了。

拖入一个文件"五月天 咸鱼.mp4",然后插入本工程的Filter,如图所示。

播放视频,效果如图,可见左上角显示出 "Hello, DirectShow!" 的字样。

看完了结果,就要开始分析代码了~

回顾一下工程结构图:

先看一下CFilterTitleOverlay.h(已经在重要的地方加了注释):

//
// CFilterTitleOverlay.h
// #ifndef __H_CFilterTitleOverlay__
#define __H_CFilterTitleOverlay__ #include "ITitleOverlay.h"
#include "COverlayController.h"
#include "OverlayDefs.h" class CFilterTitleOverlay : public CTransInPlaceFilter
, public ISpecifyPropertyPages
, public ITitleOverlay
{
private:
OVERLAY_TYPE mOverlayType;
COverlayController * mOverlayController; CCritSec mITitleOverlaySync;
BOOL mNeedEstimateFrameRate; private:
CFilterTitleOverlay(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr);
~CFilterTitleOverlay(); HRESULT SetInputVideoInfoToController(void);
void ReleaseOverlayController(void);
void SideEffectOverlayTypeChanged(void); public:
static CUnknown * WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);
//说明必须重写NonDelegatingQueryInterface
DECLARE_IUNKNOWN;
// Basic COM - used here to reveal our own interfaces
//暴露接口,使外部程序可以QueryInterface,关键!
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv); // check if you can support mtIn
virtual HRESULT CheckInputType(const CMediaType* mtIn); // PURE
//必须重写的核心函数
virtual HRESULT Transform(IMediaSample *pSample); // PURE // Delegating methods
virtual HRESULT CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin);
virtual HRESULT StartStreaming();
virtual HRESULT StopStreaming(); // --- ISpecifyPropertyPages ---
STDMETHODIMP GetPages(CAUUID *pPages); // --- ITitleOverlay methods ---
//都是接口函数
STDMETHODIMP put_TitleOverlayType(long inOverlayType);
STDMETHODIMP get_TitleOverlayType(long * outOverlayType);
STDMETHODIMP put_TitleOverlayStyle(int inUsingCover);
STDMETHODIMP get_TitleOverlayStyle(int * outUsingCover);
STDMETHODIMP put_Title(const char * inTitle, int inLength);
STDMETHODIMP get_Title(char * outBuffer, int * outLength);
STDMETHODIMP put_TitleColor(BYTE inR, BYTE inG, BYTE inB);
STDMETHODIMP get_TitleColor(BYTE * outR, BYTE * outG, BYTE * outB);
STDMETHODIMP put_TitleStartPosition(POINT inStartPos);
STDMETHODIMP get_TitleStartPosition(POINT * outStartPos);
STDMETHODIMP put_TitleFont(LOGFONT inFont);
STDMETHODIMP get_TitleFont(LOGFONT * outFont);
STDMETHODIMP put_TitleDuration(double inStart, double inEnd);
STDMETHODIMP get_TitleDuration(double * outStart, double * outEnd);
}; #endif // __H_CFilterTitleOverlay__

CFilterTitleOverlay继承了CTransInPlaceFilter,意味着Transform()函数输入和输出的数据位于同一块内存中。

以下几个函数是必须有的:

CreateInstance():创建Filter
NonDelegatingQueryInterface():暴露接口,使外部程序可以QueryInterface

CheckInputType():检查输入类型

Transform():核心处理函数(字幕叠加)

另外还包含了ITitleOverlay中的函数put_TitleOverlayType()等等一大堆。

下面看一下CFilterTitleOverlay.cpp吧,先列出注册信息部分:

//唯一标识符
// {E3FB4BFE-8E5C-4aec-8162-7DA55BE486A1}
DEFINE_GUID(CLSID_HQTitleOverlay,
0xe3fb4bfe, 0x8e5c, 0x4aec, 0x81, 0x62, 0x7d, 0xa5, 0x5b, 0xe4, 0x86, 0xa1); // {E70FE57A-19AA-4a4c-B39A-408D49D73851}
DEFINE_GUID(CLSID_HQTitleOverlayProp,
0xe70fe57a, 0x19aa, 0x4a4c, 0xb3, 0x9a, 0x40, 0x8d, 0x49, 0xd7, 0x38, 0x51); //
// setup data
//
//注册时候的信息
const AMOVIESETUP_MEDIATYPE sudPinTypes =
{
&MEDIATYPE_NULL, // Major type
&MEDIASUBTYPE_NULL // Minor type
};
//注册时候的信息
const AMOVIESETUP_PIN psudPins[] =
{
{
L"Input", // String pin name
FALSE, // Is it rendered
FALSE, // Is it an output
FALSE, // Allowed none
FALSE, // Allowed many
&CLSID_NULL, // Connects to filter
L"Output", // Connects to pin
, // Number of types
&sudPinTypes }, // The pin details
{ L"Output", // String pin name
FALSE, // Is it rendered
TRUE, // Is it an output
FALSE, // Allowed none
FALSE, // Allowed many
&CLSID_NULL, // Connects to filter
L"Input", // Connects to pin
, // Number of types
&sudPinTypes // The pin details
}
}; //注册时候的信息
const AMOVIESETUP_FILTER sudFilter =
{
&CLSID_HQTitleOverlay, // Filter CLSID
L"HQ Title Overlay Std.", // Filter name
MERIT_DO_NOT_USE, // Its merit
, // Number of pins
psudPins // Pin details
}; // List of class IDs and creator functions for the class factory. This
// provides the link between the OLE entry point in the DLL and an object
// being created. The class factory will call the static CreateInstance
//注意g_Templates名称是固定的
CFactoryTemplate g_Templates[] =
{
{
L"HQ Title Overlay Std.",
&CLSID_HQTitleOverlay,
CFilterTitleOverlay::CreateInstance,
NULL,
&sudFilter
},
{
L"HQ Title Overlay Property Page",
&CLSID_HQTitleOverlayProp,
CTitleOverlayProp::CreateInstance
}
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[]);

这一部分并不属于CFilterTitleOverlay这个类。主要是DirectShow Filter的一些注册信息。其结构是非常固定的。

再来看看CFilterTitleOverlay中函数实现部分(只列了几个函数,不然内容太多= =):

CreateInstance():

//
// CreateInstance
//
// Override CClassFactory method.
// Provide the way for COM to create a CNullInPlace object
//
//创建
CUnknown * WINAPI CFilterTitleOverlay::CreateInstance(LPUNKNOWN punk, HRESULT *phr)
{
#if 1
//防伪??!!
char szCreatorPath[], szCreatorName[];
::strcpy(szCreatorPath, "");
::strcpy(szCreatorName, "");
HMODULE hModule = ::GetModuleHandle(NULL);
::GetModuleFileName(hModule, szCreatorPath, );
char * backSlash = ::strrchr(szCreatorPath, '\\');
if (backSlash)
{
strcpy(szCreatorName, backSlash);
}
::_strlwr(szCreatorName);
// Please specify your app name with lowercase
// 检查调用该Filter的程序
// 一开始调试不了,就卡在这了 = =
if (::strstr(szCreatorName, "graphedit") == NULL &&
::strstr(szCreatorName, "ourapp") == NULL)
{
*phr = E_FAIL;
return NULL;
}
#endif
//通过New对象的方法
CFilterTitleOverlay *pNewObject = new CFilterTitleOverlay(NAME("TitleOverlay"), punk, phr);
if (pNewObject == NULL)
{
*phr = E_OUTOFMEMORY;
}
return pNewObject;
}

NonDelegatingQueryInterface():

//
// Basic COM - used here to reveal our own interfaces
//暴露接口,使外部程序可以QueryInterface,关键!
STDMETHODIMP CFilterTitleOverlay::NonDelegatingQueryInterface(REFIID riid, void ** ppv)
{
CheckPointer(ppv, E_POINTER);
//根据不同的REFIID,获得不同的接口指针
if (riid == IID_ISpecifyPropertyPages)
{
return GetInterface((ISpecifyPropertyPages *) this, ppv);
}
else if (riid == IID_ITitleOverlay)
{
return GetInterface((ITitleOverlay *) this, ppv);
}
else
{
//不是以上的REFIID的话,调用父类的
return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv);
}
} // NonDelegatingQueryInterface

CheckInputType():

// Only RGB 32/24/565/555 supported
HRESULT CFilterTitleOverlay::CheckInputType(const CMediaType* mtIn)
{
// Dynamic format change will never be allowed!
if (IsStopped() && *mtIn->Type() == MEDIATYPE_Video)
{
if (*mtIn->Subtype() == MEDIASUBTYPE_RGB32 ||
*mtIn->Subtype() == MEDIASUBTYPE_RGB24 ||
*mtIn->Subtype() == MEDIASUBTYPE_RGB555 ||
*mtIn->Subtype() == MEDIASUBTYPE_RGB565)
{
return NOERROR;
}
}
return E_INVALIDARG;
}

Transform():

HRESULT CFilterTitleOverlay::Transform(IMediaSample *pSample)
{
// If we cann't read frame rate info from input pin's connection media type,
// We estimate it from the first sample's time stamp!
if (mNeedEstimateFrameRate)
{
mNeedEstimateFrameRate = FALSE;
REFERENCE_TIME startTime = ;
REFERENCE_TIME endTime = ;
double estimated = ;
if (SUCCEEDED(pSample->GetTime(&startTime, &endTime)))
{
estimated = 1.0 * UNITS / (endTime - startTime);
}
mOverlayController->SetEstimatedFrameRate(estimated);
} if (mOverlayType != OT_NONE)
{
//PBYTE是unsigned char
PBYTE pData = NULL;
//获取IMediaSample中的数据
pSample->GetPointer(&pData);
//叠加
mOverlayController->DoTitleOverlay(pData);
} return NOERROR;
}

下面列出实现ITitleOverlay接口的函数的实现,就列了一个。

STDMETHODIMP CFilterTitleOverlay::get_Title(char * outBuffer, int * outLength)
{
CAutoLock lockit(&mITitleOverlaySync);
*outLength = mOverlayController->GetTitle(outBuffer);
return NOERROR;
}

暂且分析到这里。

书上提供的代码有误,这是经过修改后,添加了注释的代码:

http://download.csdn.net/detail/leixiaohua1020/6371819

一个简单的基于 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 = );
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 = ;
}
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());
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 = ;
if (SUCCEEDED(mSeeking->GetDuration(&length)))
{
*outDuration = ((double)length) / .;
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, , inFile, -, szFilePath, MAX_PATH);
if (SUCCEEDED(mGraph->RenderFile(szFilePath, NULL)))
{
return true;
}
}
return false;
}

一个简单的基于 DirectShow 的播放器 2(对话框类)

上篇文章分析了一个封装DirectShow各种接口的封装类(CDXGraph):一个简单的基于 DirectShow 的播放器  1(封装类)

本文继续上篇文章,分析一下调用这个封装类(CDXGraph)的对话框类(CSimplePlayerDlg),看看在MFC中如何使用这个类(CDXGraph)。

首先来看看CSimplePlayerDlg这个类的定义,瞧瞧SimplePlayerDlg.h这个头文件。

/* 雷霄骅
* 中国传媒大学/数字电视技术
* leixiaohua1020@126.com
*
*/
// SimplePlayerDlg.h : header file
// #if !defined(AFX_SIMPLEPLAYERDLG_H__3599FE35_3322_4CC7_B30B_6D6050C2EDFF__INCLUDED_)
#define AFX_SIMPLEPLAYERDLG_H__3599FE35_3322_4CC7_B30B_6D6050C2EDFF__INCLUDED_ #if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000 /////////////////////////////////////////////////////////////////////////////
// CSimplePlayerDlg dialog #include <streams.h>
#include "CDXGraph.h" #define SLIDER_TIMER 100 class CSimplePlayerDlg : public CDialog
{
// Construction
public:
CSimplePlayerDlg(CWnd* pParent = NULL); // standard constructor
~CSimplePlayerDlg(); // Dialog Data
//{{AFX_DATA(CSimplePlayerDlg)
enum { IDD = IDD_SIMPLEPLAYER_DIALOG };
CSliderCtrl mSliderGraph;
CStatic mVideoWindow;
//}}AFX_DATA // ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSimplePlayerDlg)
public:
virtual BOOL PreTranslateMessage(MSG* pMsg);
virtual BOOL DestroyWindow();
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL // Implementation
protected:
HICON m_hIcon; CDXGraph * mFilterGraph; // Filter Graph封装
CString mSourceFile; // 源文件
UINT mSliderTimer; // 定时器ID
//创建Graph
void CreateGraph(void); // 创建Filter Graph
void DestroyGraph(void); // 析构Filter Graph
void RestoreFromFullScreen(void); // Just for testing...
HRESULT FindFilterByInterface(REFIID riid, IBaseFilter** ppFilter);
void ShowVRPropertyPage(void); // Generated message map functions
//{{AFX_MSG(CSimplePlayerDlg)
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
//打开
afx_msg void OnButtonOpen();
//播放
afx_msg void OnButtonPlay();
//暂停
afx_msg void OnButtonPause();
//停止
afx_msg void OnButtonStop();
afx_msg void OnButtonGrab();
afx_msg void OnButtonFullscreen();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnTimer(UINT nIDEvent);
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnButtonTest();
//}}AFX_MSG
afx_msg LRESULT OnGraphNotify(WPARAM inWParam, LPARAM inLParam);
DECLARE_MESSAGE_MAP()
}; //{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_SIMPLEPLAYERDLG_H__3599FE35_3322_4CC7_B30B_6D6050C2EDFF__INCLUDED_)

从头文件来看,和普通的MFC对话框类并没有什么不同,无非是一些消息响应函数,或者MFC控件对应的类。需要注意一下,有一个变量:

CDXGraph *   mFilterGraph

接下来看看CSimplePlayerDlg函数的实现部分吧。
OnButtonOpen():打开媒体文件按钮的响应函数

//打开
void CSimplePlayerDlg::OnButtonOpen()
{
// TODO: Add your control notification handler code here
CString strFilter = "AVI File (*.avi)|*.avi|";
strFilter += "MPEG File (*.mpg;*.mpeg)|*.mpg;*.mpeg|";
strFilter += "Mp3 File (*.mp3)|*.mp3|";
strFilter += "Wave File (*.wav)|*.wav|";
strFilter += "All Files (*.*)|*.*|";
CFileDialog dlgOpen(TRUE, NULL, NULL, OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
strFilter, this);
if (IDOK == dlgOpen.DoModal())
{
mSourceFile = dlgOpen.GetPathName();
// Rebuild the file playback filter graph
//创建Graph
CreateGraph();
}
}

其中CreateGraph()函数如下所示:

//创建Graph
void CSimplePlayerDlg::CreateGraph(void)
{
//(如果有)销毁Graph
DestroyGraph();
//新建一个核心类
mFilterGraph = new CDXGraph();
if (mFilterGraph->Create())
{
// Render the source clip
mFilterGraph->RenderFile(mSourceFile);
// Set video window and notification window
mFilterGraph->SetDisplayWindow(mVideoWindow.GetSafeHwnd());
mFilterGraph->SetNotifyWindow(this->GetSafeHwnd());
// Show the first frame
mFilterGraph->Pause();
}
}

与CreateGraph()相反的还有一个DestroyGraph()

//(如果有)销毁Graph
void CSimplePlayerDlg::DestroyGraph(void)
{
if (mFilterGraph)
{
// Stop the filter graph first
mFilterGraph->Stop();
mFilterGraph->SetNotifyWindow(NULL); delete mFilterGraph;
mFilterGraph = NULL;
}
}

OnButtonPlay():播放按钮的响应函数

//播放
void CSimplePlayerDlg::OnButtonPlay()
{
if (mFilterGraph)
{
mFilterGraph->Run();
// Start a timer
if (mSliderTimer == )
{
mSliderTimer = SetTimer(SLIDER_TIMER, , NULL);
}
}
}

OnButtonPause():暂停按钮的响应函数

void CSimplePlayerDlg::OnButtonPause()
{
if (mFilterGraph)
{
mFilterGraph->Pause();
// Start a timer
if (mSliderTimer == )
{
mSliderTimer = SetTimer(SLIDER_TIMER, , NULL);
}
}
}

OnButtonStop():停止按钮的响应函数

void CSimplePlayerDlg::OnButtonStop()
{
if (mFilterGraph)
{
mFilterGraph->SetCurrentPosition();
mFilterGraph->Stop();
// Stop the timer
if (mSliderTimer)
{
KillTimer(mSliderTimer);
mSliderTimer = ;
}
}
}

其他的函数不再一一列举,但意思都是一样的。

转:Directshow开发的一些例子的更多相关文章

  1. Windows 视频Directshow开发介绍

    在Windows平台上实现一个文件播放器有什么好的开发库和方案呢?方案有很多,比如基于FFmpeg,VLC的插件,mplayer,Directshow.用FFmpeg来实现文件格式解析.分离视频音频流 ...

  2. Directshow开发播放器相关介绍

    原文地址:http://www.cnblogs.com/qiufa/archive/2006/12/19/596949.html DirectShow技术是DirectX推出的建立在DirectDra ...

  3. win7 x64 vs2010 directShow开发环境配置

    近来工作需要,要用dirrectShow写一个视频播放的demo验证自己的想法.开发环境配置了好久都没有成功,最后终于弄完,现在记录下来,以后有同学遇到同样问题,可以以此法解决. windows SD ...

  4. DirectShow开发快速入门之慨述

    摘要:本篇文档概括性的介绍了DirectShow的主要组成部分,以及一些Directshow的基本概念.熟悉这些基本的知识对于Directshow的应用开发或者过滤器的开发者都会有所帮助. Direc ...

  5. 利用 DirectShow 开发自己的 Filter

    学习directshow已经有几天了,下面将自己的学习心得写下来,希望对其他的人有帮助. Filter实质是个COM组件,所以学习开发Filter之前你应该对com的知识有点了解.Com组件的实质是一 ...

  6. JFrame、JPanel 、Layout开发的简单例子

    写了Java这么久,居然发现想手写一个带网格袋布局的JFrame,还不记得怎么写,写了这么多代码真不敢说记得所有细节. 幸好,只要记清楚概念就能快速开发.首先,明确一下3种容器类的差别和用途: No. ...

  7. [deviceone开发]-课程表的例子

    一.简介 这个例子是根据一个真实app的一个页面的需求来实现的demo,通过动态add ui的方式,动态bind数据构建一个完整的课程表示例.示例并不完善,但是可以给大家一个启发. 二.效果图 三.相 ...

  8. React Native 开发之 (04) 例子讲解

    一.了解index.ios.js React-Native就是在开发效率和用户体验间做的一种权衡.React-native是使用JS开发,开发效率高.发布能力强,不仅拥有hybrid的开发效率,同时拥 ...

  9. 本地化web开发的一个例子-jquery.i18n.properties

    关键字:Web本地化, jquery,jquery.i18n.properties. 运行环境:Chrome, IE. 本文介绍使用jquery.i18n.properties对网站前端实现本地化,支 ...

随机推荐

  1. CXF 入门:创建一个基于WS-Security标准的安全验证(CXF回调函数使用,)

    http://jyao.iteye.com/blog/1346547 注意:以下客户端调用代码中获取服务端ws实例,都是通过CXF 入门: 远程接口调用方式实现 直入正题! 以下是服务端配置 ==== ...

  2. CSS透明属性详解

    .transparent_class { filter:alpha(opacity=50); -moz-opacity:0.5; -khtml-opacity: 0.5; opacity: 0.5; ...

  3. 按enter执行click或者搜索问题

    最近需要将按按钮搜索的功能,改为支持按enter回车键,搜索. 实现按enter,执行click事件还是比较简单的. //按回车搜索用户 $(window).keydown(function (eve ...

  4. C#压缩文件 不压缩路径

    我想把 E:\\AA\BB\11.txt 压缩后存入 E:\\AA1\BB1\11.rar 但是当我解压( E:\\AA1\BB1\11.rar)的时候,发现:11.txt 不是在 E:\\AA1\B ...

  5. require.js 使用博客

    没时间写博客,又觉得这篇很不错,或许以后能用到,只能copy与点赞: Javascript模块化编程(三):require.js的用法   作者: 阮一峰 日期: 2012年11月 7日 这个系列的第 ...

  6. delphi常用快捷键(我自己经常使用的)

    代码编辑器: Home 回到当前行的头部 End 回到当前行的尾部 Insert 插入代码,覆盖后面的代码,(按回车无效), 再按撤回效果 Delete 删除 F1 双击一个单词后,按F1调用自带的L ...

  7. HALCON-FUZZY检测用于开关引脚测量

    跟我学机器视觉-HALCON学习例程中文详解-FUZZY检测用于开关引脚测量 * This example program demonstrates the basic usage of a fuzz ...

  8. iOS手势(滑动)返回的实现(自定义返回按钮)

    如果各位使用的是storyboard布局的话,且用的是系统的返回按钮,那么是自动会有滑动返回效果的,但是相信各位做项目的,一般都是用的自定义的返回按钮,所以我贴几行代码,看看怎么实现系统自带的滑动返回 ...

  9. EasyCriteria 3.0 发布

    EasyCriteria 3.0 发布了,这是一个全新的版本,进行了大量的重构.官方发行说明请看:http://uaihebert.com/?p=1898 EasyCriteria 是一个轻量级的框架 ...

  10. 如何在Global.asax中判断是否是ajax请求

    今天在一个应用场景中需要在Global.asax中判断一个请求是否是ajax请求,而在ASP.NET MVC中已经提供了一个现成的扩展方法IsAjaxRequest: namespace System ...