参考: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); };
IPFilter.cpp
// // 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( IGraphBui