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

/* 雷霄驊
 * 中國傳媒大學/數字電視技術
 * 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;  
}

一個簡單的基於 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 == 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;  
        }  
    }  
}

其他的函數不再一一列舉,但意思都是一樣的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM