一个MFC单文档程序,有视频播放、暂停功能。SDK是 DirectX9.0b。 IDE是vc6.0中文版
开始:
先在对话框里插入一个 图片控件。
类型改成矩形。
如果类向导里面 不能创建变量,就把ID改一下。
然后添加封装类,我在网上下载了一个。
// CDXGraph.h // #ifndef __H_CDXGraph__ #define __H_CDXGraph__ // Filter graph notification to the specified window #define WM_GRAPHNOTIFY (WM_USER+20) class CDXGraph { private: IGraphBuilder * mGraph; IMediaControl * mMediaControl; IMediaEventEx * mEvent; IBasicVideo * mBasicVideo; IBasicAudio * mBasicAudio; IVideoWindow * mVideoWindow; IMediaSeeking * mSeeking; DWORD mObjectTableEntry; public: CDXGraph(); virtual ~CDXGraph(); public: 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); bool QueryInterfaces(void); }; #endif // __H_CDXGraph__
// CDXGraph.cpp // #include "stdafx.h" #include <streams.h> #include "CDXGraph.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #pragma comment(lib, "Strmbasd.lib") #pragma comment(lib,"winmm.lib") //////////////////////////////////////////////////////////////////////////////// CDXGraph::CDXGraph() { mGraph = NULL; mMediaControl = NULL; mEvent = NULL; mBasicVideo = NULL; mBasicAudio = NULL; mVideoWindow = NULL; mSeeking = NULL; mObjectTableEntry = 0; } CDXGraph::~CDXGraph() { Release(); } 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; } 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; } 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; } } bool CDXGraph::Attach(IGraphBuilder * inGraphBuilder) { Release(); if (inGraphBuilder) { inGraphBuilder->AddRef(); mGraph = inGraphBuilder; AddToObjectTable(); return QueryInterfaces(); } return true; } IGraphBuilder * CDXGraph::GetGraph(void) { return mGraph; } IMediaEventEx * CDXGraph::GetEventHandle(void) { return mEvent; } // Connect filter from the upstream output pin to the downstream input pin bool CDXGraph::ConnectFilters(IPin * inOutputPin, IPin * inInputPin, const AM_MEDIA_TYPE * inMediaType) { if (mGraph && inOutputPin && inInputPin) { HRESULT hr = mGraph->ConnectDirect(inOutputPin, inInputPin, inMediaType); return SUCCEEDED(hr) ? true : false; } return false; } void CDXGraph::DisconnectFilters(IPin * inOutputPin) { if (mGraph && inOutputPin) { HRESULT hr = mGraph->Disconnect(inOutputPin); } } bool CDXGraph::SetDisplayWindow(HWND inWindow) { if (mVideoWindow) { // long lVisible; // mVideoWindow->get_Visible(&lVisible); // Hide the video window first mVideoWindow->put_Visible(OAFALSE); mVideoWindow->put_Owner((OAHWND)inWindow); RECT windowRect; ::GetClientRect(inWindow, &windowRect); mVideoWindow->put_Left(0); mVideoWindow->put_Top(0); mVideoWindow->put_Width(windowRect.right - windowRect.left); mVideoWindow->put_Height(windowRect.bottom - windowRect.top); mVideoWindow->put_WindowStyle(WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS); mVideoWindow->put_MessageDrain((OAHWND) inWindow); // Restore the video window if (inWindow != NULL) { // mVideoWindow->put_Visible(lVisible); mVideoWindow->put_Visible(OATRUE); } else { mVideoWindow->put_Visible(OAFALSE); } return true; } return false; } bool CDXGraph::ResizeVideoWindow(long inLeft, long inTop, long inWidth, long inHeight) { if (mVideoWindow) { long lVisible = OATRUE; mVideoWindow->get_Visible(&lVisible); // Hide the video window first mVideoWindow->put_Visible(OAFALSE); mVideoWindow->put_Left(inLeft); mVideoWindow->put_Top(inTop); mVideoWindow->put_Width(inWidth); mVideoWindow->put_Height(inHeight); // Restore the video window mVideoWindow->put_Visible(lVisible); return true; } return false; } bool CDXGraph::SetNotifyWindow(HWND inWindow) { if (mEvent) { mEvent->SetNotifyWindow((OAHWND)inWindow, WM_GRAPHNOTIFY, 0); return true; } return false; } void CDXGraph::HandleEvent(WPARAM inWParam, LPARAM inLParam) { if (mEvent) { LONG eventCode = 0, eventParam1 = 0, eventParam2 = 0; while (SUCCEEDED(mEvent->GetEvent(&eventCode, &eventParam1, &eventParam2, 0))) { mEvent->FreeEventParams(eventCode, eventParam1, eventParam2); switch (eventCode) { case EC_COMPLETE: break; case EC_USERABORT: case EC_ERRORABORT: break; default: break; } } } } bool CDXGraph::Run(void) { if (mGraph && mMediaControl) { if (!IsRunning()) { if (SUCCEEDED(mMediaControl->Run())) { return true; } } else { return true; } } return false; } bool CDXGraph::Stop(void) { if (mGraph && mMediaControl) { if (!IsStopped()) { if (SUCCEEDED(mMediaControl->Stop())) { return true; } } else { return true; } } return false; } bool CDXGraph::Pause(void) { if (mGraph && mMediaControl) { if (!IsPaused()) { if (SUCCEEDED(mMediaControl->Pause())) { return true; } } else { return true; } } return false; } bool CDXGraph::IsRunning(void) { if (mGraph && mMediaControl) { OAFilterState state = State_Stopped; if (SUCCEEDED(mMediaControl->GetState(10, &state))) { return state == State_Running; } } return false; } bool CDXGraph::IsStopped(void) { if (mGraph && mMediaControl) { OAFilterState state = State_Stopped; if (SUCCEEDED(mMediaControl->GetState(10, &state))) { return state == State_Stopped; } } return false; } bool CDXGraph::IsPaused(void) { if (mGraph && mMediaControl) { OAFilterState state = State_Stopped; if (SUCCEEDED(mMediaControl->GetState(10, &state))) { return state == State_Paused; } } return false; } bool CDXGraph::SetFullScreen(BOOL inEnabled) { if (mVideoWindow) { HRESULT hr = mVideoWindow->put_FullScreenMode(inEnabled ? OATRUE : OAFALSE); return SUCCEEDED(hr); } return false; } bool CDXGraph::GetFullScreen(void) { if (mVideoWindow) { long fullScreenMode = OAFALSE; mVideoWindow->get_FullScreenMode(&fullScreenMode); return (fullScreenMode == OATRUE); } return false; } // IMediaSeeking features bool CDXGraph::GetCurrentPosition(double * outPosition) { if (mSeeking) { __int64 position = 0; if (SUCCEEDED(mSeeking->GetCurrentPosition(&position))) { *outPosition = ((double)position) / 10000000.; return true; } } return false; } bool CDXGraph::GetStopPosition(double * outPosition) { if (mSeeking) { __int64 position = 0; if (SUCCEEDED(mSeeking->GetStopPosition(&position))) { *outPosition = ((double)position) / 10000000.; return true; } } return false; } bool CDXGraph::SetCurrentPosition(double inPosition) { if (mSeeking) { __int64 one = 10000000; __int64 position = (__int64)(one * inPosition); HRESULT hr = mSeeking->SetPositions(&position, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, 0, AM_SEEKING_NoPositioning); return SUCCEEDED(hr); } return false; } bool CDXGraph::SetStartStopPosition(double inStart, double inStop) { if (mSeeking) { __int64 one = 10000000; __int64 startPos = (__int64)(one * inStart); __int64 stopPos = (__int64)(one * inStop); HRESULT hr = mSeeking->SetPositions(&startPos, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame, &stopPos, AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame); return SUCCEEDED(hr); } return false; } bool CDXGraph::GetDuration(double * outDuration) { if (mSeeking) { __int64 length = 0; if (SUCCEEDED(mSeeking->GetDuration(&length))) { *outDuration = ((double)length) / 10000000.; return true; } } return false; } bool CDXGraph::SetPlaybackRate(double inRate) { if (mSeeking) { if (SUCCEEDED(mSeeking->SetRate(inRate))) { return true; } } return false; } // Attention: range from -10000 to 0, and 0 is FULL_VOLUME. bool CDXGraph::SetAudioVolume(long inVolume) { if (mBasicAudio) { HRESULT hr = mBasicAudio->put_Volume(inVolume); return SUCCEEDED(hr); } return false; } long CDXGraph::GetAudioVolume(void) { long volume = 0; if (mBasicAudio) { mBasicAudio->get_Volume(&volume); } return volume; } // Attention: range from -10000(left) to 10000(right), and 0 is both. bool CDXGraph::SetAudioBalance(long inBalance) { if (mBasicAudio) { HRESULT hr = mBasicAudio->put_Balance(inBalance); return SUCCEEDED(hr); } return false; } long CDXGraph::GetAudioBalance(void) { long balance = 0; if (mBasicAudio) { mBasicAudio->get_Balance(&balance); } return balance; } 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; } bool CDXGraph::SnapshotBitmap(const char * outFile) { if (mBasicVideo) { long bitmapSize = 0; if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, 0))) { bool pass = false; unsigned char * buffer = new unsigned char[bitmapSize]; if (SUCCEEDED(mBasicVideo->GetCurrentImage(&bitmapSize, (long *)buffer))) { BITMAPFILEHEADER hdr; LPBITMAPINFOHEADER lpbi; lpbi = (LPBITMAPINFOHEADER)buffer; int nColors = 1 << lpbi->biBitCount; if (nColors > 256) nColors = 0; hdr.bfType = ((WORD) ('M' << 8) | 'B'); //always is "BM" hdr.bfSize = bitmapSize + sizeof( hdr ); hdr.bfReserved1 = 0; hdr.bfReserved2 = 0; hdr.bfOffBits = (DWORD) (sizeof(BITMAPFILEHEADER) + lpbi->biSize + nColors * sizeof(RGBQUAD)); CFile bitmapFile(outFile, CFile::modeReadWrite | CFile::modeCreate | CFile::typeBinary); bitmapFile.Write(&hdr, sizeof(BITMAPFILEHEADER)); bitmapFile.Write(buffer, bitmapSize); bitmapFile.Close(); pass = true; } delete [] buffer; return pass; } } return false; } //////////////////////// For GraphEdit Dubug purpose ///////////////////////////// void CDXGraph::AddToObjectTable(void) { IMoniker * pMoniker = 0; IRunningObjectTable * objectTable = 0; if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) { WCHAR wsz[256]; wsprintfW(wsz, L"FilterGraph %08p pid %08x", (DWORD_PTR)mGraph, GetCurrentProcessId()); HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker); if (SUCCEEDED(hr)) { hr = objectTable->Register(0, mGraph, pMoniker, &mObjectTableEntry); pMoniker->Release(); } objectTable->Release(); } } void CDXGraph::RemoveFromObjectTable(void) { IRunningObjectTable * objectTable = 0; if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) { objectTable->Revoke(mObjectTableEntry); objectTable->Release(); mObjectTableEntry = 0; } }
然后再编译一下。如果出现问题,
因为这个库是静态的,而常规的设置是加载动态库,所以会冲突。
上面两张,是DX的配置,贴在这里备忘。
后面加调用代码:
自己生成的DIALOG
// DlgMovie.h : header file // #include "afxwin.h" #include <streams.h> #include "CDXGraph.h" #define SLIDER_TIMER 100 ///////////////////////////////////////////////////////////////////////////// // CDlgMovie dialog class CDlgMovie : public CDialog { // Construction public: CDlgMovie(CWnd* pParent = NULL); // standard constructor CDXGraph* mFilterGraph; // Filter Graph封装 CString mSourceFile; // 源文件 UINT mSliderTimer; // 定时器ID // Dialog Data //{{AFX_DATA(CDlgMovie) enum { IDD = IDD_DIALOG1 }; CStatic mVideoWindow; //}}AFX_DATA // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CDlgMovie) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: void RestoreFromFullScreen(void); // BOOL PreTranslateMessage(MSG* pMsg); HICON m_hIcon; void CreateGraph(void); // 创建Filter Graph void DestroyGraph(void); // 析构Filter Graph // Generated message map functions //{{AFX_MSG(CDlgMovie) afx_msg void OnButton1(); virtual BOOL OnInitDialog(); afx_msg void OnButton2(); afx_msg void OnButton3(); afx_msg void OnButton4(); //}}AFX_MSG DECLARE_MESSAGE_MAP() };
// DlgMovie.cpp : implementation file // #include "stdafx.h" #include "MovieDx1.h" #include "DlgMovie.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CDlgMovie dialog CDlgMovie::CDlgMovie(CWnd* pParent /*=NULL*/) : CDialog(CDlgMovie::IDD, pParent) { //{{AFX_DATA_INIT(CDlgMovie) //}}AFX_DATA_INIT mFilterGraph = NULL; mSourceFile = ""; } void CDlgMovie::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CDlgMovie) DDX_Control(pDX, IDC_STATIC1, mVideoWindow); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CDlgMovie, CDialog) //{{AFX_MSG_MAP(CDlgMovie) ON_BN_CLICKED(IDC_BUTTON1, OnButton1) ON_BN_CLICKED(IDC_BUTTON2, OnButton2) ON_BN_CLICKED(IDC_BUTTON3, OnButton3) ON_BN_CLICKED(IDC_BUTTON4, OnButton4) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CDlgMovie message handlers //open/ void CDlgMovie::OnButton1() { // TODO: Add your control notification handler code here CString strFilter = "AVI File (*.avi)|*.avi|"; strFilter += "MPEG File (*.mpg;*.mpeg)|*.mpg;*.mpeg|"; //strFilter += "AVI File (*.avi)|*.avi|"; 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(); CreateGraph(); } } BOOL CDlgMovie::OnInitDialog() { CDialog::OnInitDialog(); CRect rc; GetClientRect(&rc); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } //play/ void CDlgMovie::OnButton2() { // TODO: Add your control notification handler code here if (mFilterGraph) { mFilterGraph->Run(); } } //pause/ void CDlgMovie::OnButton3() { // TODO: Add your control notification handler code here if (mFilterGraph) { mFilterGraph->Pause(); } } //stop/ void CDlgMovie::OnButton4() { // TODO: Add your control notification handler code here } void CDlgMovie::CreateGraph() //创建新的Filter 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(); } } void CDlgMovie::DestroyGraph(void) //析构当前使用的Filter Graph { if (mFilterGraph) { mFilterGraph->Stop(); mFilterGraph->SetNotifyWindow(NULL); delete mFilterGraph; mFilterGraph = NULL; } }
执行效果: