分类: WINDOWS
2007-01-30 16:26:38
使用directShow播放mpeg的基类 | |
CDXGraph.h // #ifndef __H_CDXGraph__ #define __H_CDXGraph__ // Filter graph notification to the specified window #define WM_GRAPHNOTIFY (WM_USER+20) #include "Dshow.h" #include "amstream.h" #include "Qedit.h" 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" #include "vfw.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //////////////////////////////////////////////////////////////////////////////// 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) { CoInitialize(NULL); if (!mGraph) { HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&mGraph); if (SUCCEEDED(hr)) { #ifdef _DEBUG AddToObjectTable(); #endif 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; } #ifdef _DEBUG RemoveFromObjectTable(); #endif if (mGraph) { mGraph->Release(); mGraph = NULL; } CoUninitialize(); } 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; } } 使用例子 void CMpegImageDlg::OnOpenButton() { // TODO: Add your control notification handler code here CString strFilter = "MPEG File (*.mpg;*.mpeg)|*.mpg;*.mpeg|" "AVI File (*.avi)|*.avi|" "Mp3 File (*.mp3)|*.mp3|" "Wave File (*.wav)|*.wav|" "All Files (*.*)|*.*|"; CFileDialog dlgOpen(TRUE, NULL, NULL, OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, strFilter, this); if (IDOK == dlgOpen.DoModal()) { CString strSourceFile = dlgOpen.GetPathName(); // Rebuild the file playback filter graph CMpegImageDlg::CreateGraph(strSourceFile); GetDlgItem(ID_OPEN_BUTTON)->EnableWindow(FALSE); GetDlgItem(ID_PLAY_BUTTON)->EnableWindow(TRUE); } } void CMpegImageDlg::CreateGraph(const CString& strSourceFile) { CMpegImageDlg::DestroyGraph(); m_FilterGraph = new CDXGraph(); if (m_FilterGraph->Create()) { // Render the source clip m_FilterGraph->RenderFile(strSourceFile); // Set video window and notification window m_FilterGraph->SetDisplayWindow(m_VideoWindow.GetSafeHwnd()); m_FilterGraph->SetNotifyWindow(this->GetSafeHwnd()); // Show the first frame m_FilterGraph->Pause(); } } void CMpegImageDlg::DestroyGraph(void) { if(m_FilterGraph) { // Stop the filter graph first m_FilterGraph->Stop(); m_FilterGraph->SetNotifyWindow(NULL); delete m_FilterGraph; m_FilterGraph = NULL; } } void CMpegImageDlg::OnPlayButton() { // TODO: Add your control notification handler code here if (m_FilterGraph) { GetDlgItem(ID_PLAY_BUTTON)->EnableWindow(FALSE); GetDlgItem(ID_IMAGE_BUTTON)->EnableWindow(TRUE); m_FilterGraph->Run(); // Start a timer if (m_SliderTimer == 0) { m_SliderTimer = SetTimer(SLIDER_TIMER, 100, NULL); } } } |