转:Directshow开发的一些例子

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
        1,                  // 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
        1,                  // 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
    2,                       // 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[0]);

这一部分并不属于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[256], szCreatorName[256];
    ::strcpy(szCreatorPath, "");
    ::strcpy(szCreatorName, "");
HMODULE hModule = ::GetModuleHandle(NULL);
    ::GetModuleFileName(hModule, szCreatorPath, 256);
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 = 0;
        REFERENCE_TIME  endTime   = 0;
double          estimated = 25;
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

/* 雷霄骅
 * 中国传媒大学/数字电视技术
 * [email protected]
 *
 */
// 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;
}

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

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

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

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

/* 雷霄骅
 * 中国传媒大学/数字电视技术
 * [email protected]
 *
 */
// 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 == 0)
        {
            mSliderTimer = SetTimer(SLIDER_TIMER, 100, NULL);
        }
    }
}

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

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

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

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

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

时间: 2024-10-09 11:40:41

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

android开发最常用例子整理----(1)自定义按钮实现

android开发最常用例子整理----(1)自定义按钮实现 一.Activity MainActivity.java源码: public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }

WEB开发的jsp例子标签库(jstl)的使用

<!-- e1 --> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page import=&quo

android开发最常用例子整理----(2)自定义ListView(SimpleAdapter实现)

android开发最常用例子整理----(2)自定义ListView(SimpleAdapter实现) 一.Activity MainActivity.java源码: public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layou

《DirectShow开发指南》学习笔记

这本书应该八年前学习,这是一个虚度年华的悲剧.希望你好好学习,并做好笔记. <DirectShow开发指南>第一章主要讲述了以下要点: (1)DirectShow组成 我这里要指出两点: 一是Filter管理器,即Filter Graph Manager,它是一个Filter容器,负责创建,销毁所有过滤器:其次是Filter分为三类,Source Filter,Transform Filter,Render Filter.这可以根据它们是否都具备输入Pin或输出Pin来判定. (2)COM组件

《DirectShow开发指南》,《DirectShow 实务精选》及《精通网络视频核心开发技术》作者考证

<DirectShow开发指南>,<DirectShow 实务精选>及<精通网络视频核心开发技术>作者考证 今天看见同事在看一本关于DirectShow的书籍,  <精通网络视频核心开发技术>,  我拿过来随时翻了翻,恰好翻到第260页, 看到这样一句话, "关于DirectShow Filter 开发方法更详细的介绍,限于篇幅,笔者在这里就不详细介绍了 有兴趣的的读者可以参考笔者的另外两本书<DirectShow开发指南>和<D

DirectShow 开发环境搭建(整理)

directshow sdkDirectShow SDK 下载地址: http://www.microsoft.com/en-us/download/details.aspx?id=8442GRMSDK_EN_DVD.iso      x86GRMSDKIAI_EN_DVD.iso  ItaniumGRMSDKX_EN_DVD.iso    64 位的 amd cpu如果你安装的是32位的windows 7,请下载 x86如果你安装的是64位的windows 7,请下载 amd64找到Sampl

使用jQuery进行组件开发(完整例子)

使用jQuery进行组件开发和使用纯JavaScript脚本(不使用框架)原理基本类似,特别是公共方法的组织是一样的. 不同点是,jQuery使用了插件机制,通过$()直接进行操作对象(DOM元素)绑定,然后对DOM元素或HTML代码进行绑定事件等的操作. 另一个不同点则是把jQuery当做工具来使用,用来创建DOM对象,快速查找指定DOM对象等. 例子测试通过. 初级简单示例,只实现了增加页和选择页功能. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML

Javascript模块化开发之初恋例子 ( 弹窗 )

今天是2014年9月30日了,明天就是国庆节了,首先祝咱们伟大的祖国生日快乐. 还有几分钟就要下班了,研究了几天关于require这个库的模块化开发的相关文章, 终于写出了初恋的模块化例子:弹出一个登陆框: 第一:首先在静态页面引入require库文件,并在该引入标签中引入主脚本文件( main.js ) 1 <script data-main='main' src='./require.js'></script> 2:首先在写程序之前需要分清楚需要加载的模块文件和模块文件的依赖关

EXTJS 组件开发(完整例子)

目标:EXTJS组件开发,从component基础实现一个TAB控件. 使用EXTJS版本为5.0.测试通过. 这个例子还很初级,仅仅是说明通过示例使用EXTJS进行组件开发的一个基本思路. <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>EXT JS TEST</title>