参考:http://blog.csdn.net/luckyboy101/article/details/7836693
http://blog.csdn.net/luckyboy101/article/details/7841673
其它不解释,贴是代码:
IPFilter.h
// // Sample DirectShow In-Place Transform Filter that accepts data for use in application // #include <streams.h> // This is an example transform filter that is created within // the application, and not by CoCreateInstance class CAppTransform : public CTransformFilter { public: CAppTransform(LPUNKNOWN pUnkOuter, HRESULT *phr); HRESULT CheckInputType(const CMediaType* mtIn); HRESULT Transform(IMediaSample *pIn, IMediaSample *pOut); HRESULT CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut); HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties); HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); private: HRESULT Copy(IMediaSample *pSource, IMediaSample *pDest) const; HRESULT Transform(IMediaSample *pSample); }; // DirectShow graph management sample code: // This builds a playback graph using RenderFile // and then inserts a transform filter on the uncompressed video. class CAppGraphBuilder { private: CAppTransform* m_pFilter; DWORD m_dwObjectTable; ICaptureGraphBuilder2 *m_pBuild; IGraphBuilder *m_pGraph; public: CAppGraphBuilder(); ~CAppGraphBuilder(); void DestroyGraph(void); HRESULT BuildFromFile(LPCWSTR pszFile); HRESULT Run(void); HRESULT MakeChild(HWND hwnd); HRESULT ResizeVideoWindow(RECT* prc); private: void CreateAppFilter(void); HRESULT FindFilterByInterface(REFIID riid, IBaseFilter** ppFilter); HRESULT ConnectUpstreamOf(IBaseFilter* pFilter,IBaseFilter*pColor, IBaseFilter* pTransform); HRESULT NextUpstream(IBaseFilter* pFilter, IBaseFilter** ppNext); HRESULT CAppGraphBuilder::AddFilterByCLSID(IGraphBuilder *pGraph,const GUID& clsid,LPCWSTR wszName,IBaseFilter **ppF); HRESULT InitCaptureGraphBuilder(IGraphBuilder **ppGraph,ICaptureGraphBuilder2 **ppBuild); HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum); void DisplayDeviceInformation(IEnumMoniker *pEnum, IMoniker** pMoniker); IPin* GetPin(IBaseFilter* pFilter, PIN_DIRECTION dirRequest); // Helper methods IPin* InputPinOf(IBaseFilter* pFilter) { return GetPin(pFilter, PINDIR_INPUT); } IPin* OutputPinOf(IBaseFilter* pFilter) { return GetPin(pFilter, PINDIR_OUTPUT); } void AddToObjectTable(void) ; void RemoveFromObjectTable(void); };
// // Sample DirectShow Transform Filter that accepts data for use in application // #include "stdafx.h" #include "IPFilter.h" //////////////////////////////////////////////////////////////////////////////// CAppTransform::CAppTransform(LPUNKNOWN pUnkOuter, HRESULT *phr) : CTransformFilter(NAME("App Transform"), pUnkOuter, GUID_NULL) { } // // CheckTransform // // To be able to transform the formats must be identical // HRESULT CAppTransform::CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut) { CheckPointer(mtIn,E_POINTER); CheckPointer(mtOut,E_POINTER); HRESULT hr; if(FAILED(hr = CheckInputType(mtIn))) { return hr; } // format must be a VIDEOINFOHEADER if(*mtOut->FormatType() != FORMAT_VideoInfo) { return E_INVALIDARG; } // formats must be big enough if(mtIn->FormatLength() < sizeof(VIDEOINFOHEADER) || mtOut->FormatLength() < sizeof(VIDEOINFOHEADER)) return E_INVALIDARG; VIDEOINFO *pInput = (VIDEOINFO *) mtIn->Format(); VIDEOINFO *pOutput = (VIDEOINFO *) mtOut->Format(); if(memcmp(&pInput->bmiHeader,&pOutput->bmiHeader,sizeof(BITMAPINFOHEADER)) == 0) { return NOERROR; } return E_INVALIDARG; } // CheckTransform // // DecideBufferSize // // Tell the output pin's allocator what size buffers we // require. Can only do this when the input is connected // HRESULT CAppTransform::DecideBufferSize(IMemAllocator *pAlloc,ALLOCATOR_PROPERTIES *pProperties) { CheckPointer(pAlloc,E_POINTER); CheckPointer(pProperties,E_POINTER); // Is the input pin connected if(m_pInput->IsConnected() == FALSE) { return E_UNEXPECTED; } HRESULT hr = NOERROR; pProperties->cBuffers = 1; pProperties->cbBuffer = m_pInput->CurrentMediaType().GetSampleSize(); ASSERT(pProperties->cbBuffer); // If we don't have fixed sized samples we must guess some size if(!m_pInput->CurrentMediaType().bFixedSizeSamples) { if(pProperties->cbBuffer < 100000) { // nothing more than a guess!! pProperties->cbBuffer = 100000; } } // Ask the allocator to reserve us some sample memory, NOTE the function // can succeed (that is return NOERROR) but still not have allocated the // memory that we requested, so we must check we got whatever we wanted ALLOCATOR_PROPERTIES Actual; hr = pAlloc->SetProperties(pProperties,&Actual); if(FAILED(hr)) { return hr; } ASSERT(Actual.cBuffers == 1); if(pProperties->cBuffers > Actual.cBuffers || pProperties->cbBuffer > Actual.cbBuffer) { return E_FAIL; } return NOERROR; } // DecideBufferSize // // GetMediaType // // I support one type, namely the type of the input pin // We must be connected to support the single output type // HRESULT CAppTransform::GetMediaType(int iPosition, CMediaType *pMediaType) { // Is the input pin connected if(m_pInput->IsConnected() == FALSE) { return E_UNEXPECTED; } // This should never happen if(iPosition < 0) { return E_INVALIDARG; } // Do we have more items to offer if(iPosition > 0) { return VFW_S_NO_MORE_ITEMS; } CheckPointer(pMediaType,E_POINTER); *pMediaType = m_pInput->CurrentMediaType(); return NOERROR; } HRESULT CAppTransform::Copy(IMediaSample *pSource, IMediaSample *pDest) const { CheckPointer(pSource,E_POINTER); CheckPointer(pDest,E_POINTER); // Copy the sample data BYTE *pSourceBuffer, *pDestBuffer; long lSourceSize = pSource->GetActualDataLength(); #ifdef DEBUG long lDestSize = pDest->GetSize(); ASSERT(lDestSize >= lSourceSize); #endif pSource->GetPointer(&pSourceBuffer); pDest->GetPointer(&pDestBuffer); CopyMemory((PVOID) pDestBuffer,(PVOID) pSourceBuffer,lSourceSize); // Copy the sample times REFERENCE_TIME TimeStart, TimeEnd; if(NOERROR == pSource->GetTime(&TimeStart, &TimeEnd)) { pDest->SetTime(&TimeStart, &TimeEnd); } LONGLONG MediaStart, MediaEnd; if(pSource->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR) { pDest->SetMediaTime(&MediaStart,&MediaEnd); } // Copy the Sync point property HRESULT hr = pSource->IsSyncPoint(); if(hr == S_OK) { pDest->SetSyncPoint(TRUE); } else if(hr == S_FALSE) { pDest->SetSyncPoint(FALSE); } else { // an unexpected error has occured... return E_UNEXPECTED; } // Copy the media type AM_MEDIA_TYPE *pMediaType; pSource->GetMediaType(&pMediaType); pDest->SetMediaType(pMediaType); DeleteMediaType(pMediaType); // Copy the preroll property hr = pSource->IsPreroll(); if(hr == S_OK) { pDest->SetPreroll(TRUE); } else if(hr == S_FALSE) { pDest->SetPreroll(FALSE); } else { // an unexpected error has occured... return E_UNEXPECTED; } // Copy the discontinuity property hr = pSource->IsDiscontinuity(); if(hr == S_OK) { pDest->SetDiscontinuity(TRUE); } else if(hr == S_FALSE) { pDest->SetDiscontinuity(FALSE); } else { // an unexpected error has occured... return E_UNEXPECTED; } // Copy the actual data length long lDataLength = pSource->GetActualDataLength(); pDest->SetActualDataLength(lDataLength); return NOERROR; } // Copy // // Transform // // Copy the input sample into the output sample // Then transform the output sample 'in place' // HRESULT CAppTransform::Transform(IMediaSample *pIn, IMediaSample *pOut) { HRESULT hr = Copy(pIn, pOut); if (FAILED(hr)) { return hr; } return Transform(pOut); } // Transform HRESULT CAppTransform::Transform(IMediaSample *pSample) { // Override to do something inside the application // Such as grabbing a poster frame... // ... BYTE *pData; // Pointer to the actual image buffer long lDataLen; // Holds length of any given sample int iPixel; // Used to loop through the image pixels tagRGBTRIPLE *prgb; // Holds a pointer to the current pixel AM_MEDIA_TYPE* pType = &m_pInput->CurrentMediaType(); VIDEOINFOHEADER *pvi = (VIDEOINFOHEADER *) pType->pbFormat; ASSERT(pvi); CheckPointer(pSample,E_POINTER); pSample->GetPointer(&pData); lDataLen = pSample->GetSize(); // Get the image properties from the BITMAPINFOHEADER int cxImage = pvi->bmiHeader.biWidth; int cyImage = pvi->bmiHeader.biHeight; int numPixels = cxImage * cyImage; // int iPixelSize = pvi->bmiHeader.biBitCount / 8; // int cbImage = cyImage * cxImage * iPixelSize; prgb = (tagRGBTRIPLE*) pData; for (iPixel=0; iPixel < numPixels; iPixel++, prgb++) { prgb->rgbtRed=prgb->rgbtBlue=prgb->rgbtGreen=(prgb->rgbtRed+prgb->rgbtBlue+prgb->rgbtGreen)/3; } return S_OK; } // Check if we can support this specific proposed type and format HRESULT CAppTransform::CheckInputType(const CMediaType *pmt) { // We accept a series of raw media types /*if (pmt->majortype == MEDIATYPE_Video && (pmt->subtype == MEDIASUBTYPE_RGB32 || pmt->subtype == MEDIASUBTYPE_RGB24 || pmt->subtype == MEDIASUBTYPE_RGB565 || pmt->subtype == MEDIASUBTYPE_RGB555 || pmt->subtype == MEDIASUBTYPE_UYVY || pmt->subtype == MEDIASUBTYPE_YUY2)|| pmt->subtype==MEDIASUBTYPE_NV12)*/ if (pmt->majortype == MEDIATYPE_Video && (pmt->subtype == MEDIASUBTYPE_RGB24)) { return NOERROR; } return E_FAIL; } // --- graph building (examples) --------- CAppGraphBuilder::CAppGraphBuilder() : m_pBuild(NULL), m_pGraph(NULL), m_pFilter(NULL), m_dwObjectTable(0) { CoInitialize(NULL); } CAppGraphBuilder::~CAppGraphBuilder() { DestroyGraph(); CoUninitialize(); } void CAppGraphBuilder::DestroyGraph(void) { if (m_pGraph) { RemoveFromObjectTable(); // ensure graph window is not child of ours IVideoWindow* pVW = NULL; HRESULT hr = m_pGraph->QueryInterface(IID_IVideoWindow, (void**)&pVW); if (SUCCEEDED(hr)) { pVW->put_Visible(OAFALSE); pVW->put_Owner(NULL); pVW->put_MessageDrain(NULL); pVW->Release(); } m_pGraph->Release(); m_pGraph = NULL; m_pBuild->Release(); m_pBuild = NULL; } if (m_pFilter) { m_pFilter->Release(); m_pFilter = NULL; } } HRESULT CAppGraphBuilder::InitCaptureGraphBuilder( IGraphBuilder **ppGraph, // Receives the pointer. ICaptureGraphBuilder2 **ppBuild // Receives the pointer. ) { if (!ppGraph || !ppBuild) { return E_POINTER; } IGraphBuilder *pGraph = NULL; ICaptureGraphBuilder2 *pBuild = NULL; // Create the Capture Graph Builder. HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuild ); if (SUCCEEDED(hr)) { // Create the Filter Graph Manager. hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGraph); if (SUCCEEDED(hr)) { // Initialize the Capture Graph Builder. pBuild->SetFiltergraph(pGraph); // Return both interface pointers to the caller. *ppBuild = pBuild; *ppGraph = pGraph; // The caller must release both interfaces. return S_OK; } else { pBuild->Release(); } } return hr; // Failed } HRESULT CAppGraphBuilder::EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum) { ICreateDevEnum *pDevEnum = NULL; // Create the System Device Enumerator. HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&pDevEnum)); if (SUCCEEDED(hr)) { // Create an enumerator for the video capture category. hr = pDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, ppEnum, 0); } return hr; } void CAppGraphBuilder::DisplayDeviceInformation(IEnumMoniker *pEnum, IMoniker** pMoniker) { HWND hList; // Handle to the list box. while (pEnum->Next(1, pMoniker, NULL) == S_OK) { IPropertyBag *pPropBag; HRESULT hr = (*pMoniker)->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag)); if (FAILED(hr)) { (*pMoniker)->Release(); continue; // Skip this one, maybe the next one will work. } // Find the description or friendly name. VARIANT varName; VariantInit(&varName); hr = pPropBag->Read(L"Description", &varName, 0); if (FAILED(hr)) { hr = pPropBag->Read(L"FriendlyName", &varName, 0); } if (SUCCEEDED(hr)) { // Add it to the application's list box. USES_CONVERSION; /*(long)SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)OLE2T(varName.bstrVal));*/ VariantClear(&varName); } pPropBag->Release(); (*pMoniker)->Release(); } } HRESULT CAppGraphBuilder::AddFilterByCLSID( IGraphBuilder *pGraph, // Pointer to the Filter Graph Manager. const GUID& clsid, // CLSID of the filter to create. LPCWSTR wszName, // A name for the filter. IBaseFilter **ppF) // Receives a pointer to the filter. { if (!pGraph || ! ppF) return E_POINTER; *ppF = 0; IBaseFilter *pF = 0; HRESULT hr = CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pF)); if (SUCCEEDED(hr)) { hr = pGraph->AddFilter(pF, wszName); if (SUCCEEDED(hr)) *ppF = pF; else pF->Release(); } return hr; } HRESULT CAppGraphBuilder::BuildFromFile(LPCWSTR pszFile) { DestroyGraph(); IMoniker* pMoniker; IMediaEvent *pEvent; InitCaptureGraphBuilder(&m_pGraph,&m_pBuild); HRESULT hr = m_pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent); AddToObjectTable(); IBaseFilter *pCap; // Video capture filter. IEnumMoniker *pEnum; hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum); DisplayDeviceInformation(pEnum, &pMoniker); hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap); if (SUCCEEDED(hr)) { hr = m_pGraph->AddFilter(pCap, L"Capture Filter"); } hr = m_pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap, NULL, NULL); IBaseFilter *pMux; hr = m_pBuild->SetOutputFileName(&MEDIASUBTYPE_Avi,L"D:\\Example.avi",&pMux,NULL); hr = m_pBuild->RenderStream(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,pCap,NULL,pMux); // Try to find the video renderer, by looking for IVideoWindow IBaseFilter* pVR; hr = FindFilterByInterface(IID_IVideoWindow, &pVR); if (FAILED(hr)) { return hr; } // Find the media type on the input pin of the Video Renderer // to check for overlay connection where no actual data is passed IPin* pPin = InputPinOf(pVR); AM_MEDIA_TYPE mt; pPin->ConnectionMediaType(&mt); pPin->Release(); CMediaType mtIn = mt; FreeMediaType(mt); if (mtIn.subtype == MEDIASUBTYPE_Overlay) { // This connection may be a overlay mixer // need to move upstream one place IBaseFilter* pOvMix = NULL; hr = NextUpstream(pVR, &pOvMix); pVR->Release(); if (FAILED(hr)) { return hr; } pVR = pOvMix; } // Create the transform and insert in graph CreateAppFilter(); // Add Color Space Convert IBaseFilter *pColor; hr=AddFilterByCLSID(m_pGraph, CLSID_Colour, L"Color Space Converter", &pColor); // Try to insert our transform filter hr = ConnectUpstreamOf(pVR, pColor,m_pFilter); //pVR->Release(); //pColor->Release(); return hr; } // Start the graph HRESULT CAppGraphBuilder::Run(void) { IMediaControl* pControl = NULL; HRESULT hr = m_pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); if (SUCCEEDED(hr)) { hr = pControl->Run(); pControl->Release(); } return hr; } // Make the video window a child of this app HRESULT CAppGraphBuilder::MakeChild(HWND hwnd) { if (!m_pGraph) { return E_FAIL; } IVideoWindow* pVW = NULL; HRESULT hr = m_pGraph->QueryInterface(IID_IVideoWindow, (void**)&pVW); if (SUCCEEDED(hr)) { HWND hwndOld; pVW->get_Owner((LONG*)&hwndOld); if (hwndOld != hwnd) { pVW->put_AutoShow(OAFALSE); pVW->put_Visible(OAFALSE); long WindowStyle = 0; // Tweak the video's window style to get rid of the caption and frame: hr = pVW->get_WindowStyle(&WindowStyle); if (SUCCEEDED(hr)) { WindowStyle &= ~WS_OVERLAPPEDWINDOW; // No frame junk WindowStyle |= WS_CHILD; // Needs to be child hr = pVW->put_WindowStyle(WindowStyle); } pVW->put_Owner((LONG)hwnd); pVW->put_MessageDrain((LONG)hwnd); if (hwnd != NULL) { RECT rc; GetClientRect(hwnd, &rc); pVW->SetWindowPosition( rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top); pVW->put_Visible(OATRUE); } } pVW->Release(); } return hr; } // Resize the video window HRESULT CAppGraphBuilder::ResizeVideoWindow(RECT* prc) { if (!m_pGraph) { return E_FAIL; } IVideoWindow* pVW = NULL; HRESULT hr = m_pGraph->QueryInterface(IID_IVideoWindow, (void**)&pVW); if (SUCCEEDED(hr)) { hr = pVW->SetWindowPosition( prc->left, prc->top, prc->right - prc->left, prc->bottom - prc->top); pVW->Release(); } return hr; } // Create the app-based filter and insert into graph (unconnected) void CAppGraphBuilder::CreateAppFilter(void) { if (m_pFilter) { m_pFilter->Release(); m_pFilter = NULL; } HRESULT hr = S_OK; m_pFilter = new CAppTransform(NULL, &hr); // Make the initial refcount 1 to match COM creation!!! m_pFilter->AddRef(); // Add to graph -- nb need to Query properly for the // right interface before giving that to the graph object IBaseFilter* pFilter = NULL; hr = m_pFilter->QueryInterface(IID_IBaseFilter, (void**)&pFilter); if (SUCCEEDED(hr)) { hr = m_pGraph->AddFilter(pFilter, L"App Transform"); pFilter->Release(); } } // Locate a filter within the graph by searching (from renderers upstream) // looking for a specific interface on the filter HRESULT CAppGraphBuilder::FindFilterByInterface(REFIID riid, IBaseFilter** ppFilter) { *ppFilter = NULL; IEnumFilters* pEnum; HRESULT hr = m_pGraph->EnumFilters(&pEnum); if (FAILED(hr)) { return hr; } IBaseFilter* pFilter = NULL; while (pEnum->Next(1, &pFilter, NULL) == S_OK) { // Check for required interface IUnknown* pUnk; HRESULT hrQuery = pFilter->QueryInterface(riid, (void**)&pUnk); if (SUCCEEDED(hrQuery)) { pUnk->Release(); pEnum->Release(); *ppFilter = pFilter; return S_OK; } pFilter->Release(); } pEnum->Release(); return E_FAIL; } // Connect the filter pTransform upstream of pFilter by reconnecting pins. // Assumes that pTransform has only one input and one output, and // that pFilter has only one input. HRESULT CAppGraphBuilder::ConnectUpstreamOf(IBaseFilter* pFilter, IBaseFilter*pColor,IBaseFilter* pTransform) { IPin* pPinIn = InputPinOf(pFilter); if (!pPinIn) { return E_FAIL; } // Get the peer output pin IPin* pPinOut = NULL; HRESULT hr = pPinIn->ConnectedTo(&pPinOut); if (FAILED(hr)) { pPinIn->Release(); return hr; } // Disconnect the current connection hr = m_pGraph->Disconnect(pPinOut); if (SUCCEEDED(hr)) { hr = m_pGraph->Disconnect(pPinIn); } // Insert pTransform filter by connecting its input pin and output pin if (SUCCEEDED(hr)) { IPin* pPinInCor = InputPinOf(pColor); hr = m_pGraph->Connect(pPinOut, pPinInCor); pPinInCor->Release(); } if (SUCCEEDED(hr)) { IPin* pPinInXfm = InputPinOf(pTransform); IPin* pPinOutCor = OutputPinOf(pColor); hr = m_pGraph->Connect(pPinOutCor, pPinInXfm); pPinInXfm->Release(); pPinOutCor->Release(); } if (SUCCEEDED(hr)) { IPin* pPinOutXfm = OutputPinOf(pTransform); hr = m_pGraph->Connect(pPinOutXfm, pPinIn); pPinOutXfm->Release(); } pPinIn->Release(); pPinOut->Release(); return hr; } // Find the first pin of a specific direction on a given filter IPin* CAppGraphBuilder::GetPin(IBaseFilter* pFilter, PIN_DIRECTION dirRequest) { IPin * foundPin = NULL; IEnumPins* pEnum = NULL; HRESULT hr = pFilter->EnumPins(&pEnum); if (SUCCEEDED(hr)) { IPin* pPin = NULL; while (!foundPin && pEnum->Next(1, &pPin, 0) == S_OK) { PIN_DIRECTION dir; pPin->QueryDirection(&dir); if (dir == dirRequest) { foundPin = pPin; } else { pPin->Release(); } } pEnum->Release(); } return foundPin; } // Follow the pin connections to return the filter that is // connected to the first input pin of pFilter HRESULT CAppGraphBuilder::NextUpstream(IBaseFilter* pFilter, IBaseFilter** ppNext) { IPin* pPin = InputPinOf(pFilter); if (!pPin) { return E_FAIL; } // Get the peer output pin IPin* pPinOut = NULL; HRESULT hr = pPin->ConnectedTo(&pPinOut); pPin->Release(); if (FAILED(hr)) { return hr; } PIN_INFO info; pPinOut->QueryPinInfo(&info); pPinOut->Release(); *ppNext = info.pFilter; return S_OK; } //////////////////////// For GraphEdit Dubug purpose ///////////////////////////// void CAppGraphBuilder::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)m_pGraph, GetCurrentProcessId()); HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker); if (SUCCEEDED(hr)) { hr = objectTable->Register(0, m_pGraph, pMoniker, &m_dwObjectTable); pMoniker->Release(); } objectTable->Release(); } } void CAppGraphBuilder::RemoveFromObjectTable(void) { IRunningObjectTable * objectTable = 0; if (SUCCEEDED(GetRunningObjectTable(0, &objectTable))) { objectTable->Revoke(m_dwObjectTable); objectTable->Release(); m_dwObjectTable = 0; } }调用:
LPCWSTR wchFile=L"D:\\example.avi"; m_Graph.BuildFromFile(wchFile); m_Graph.MakeChild(GetSafeHwnd()); m_Graph.Run();
最后记得
pControl->Stop();