zdirectshow的原理大概大家都知道,基本就是用微软封装的接口来实现硬件无关性,但是最终调用的接口都要在驱动层有对应的实现:
为了更清楚地演示directshow的数据传输过程,我必须说明的这个程序的基本流程。我采用的是vs2005 + windows mobile 6。0 professional 仿真模拟器,驱动层传出的是176*144格式的rgb565的数据,最后我将保存图片为RGB24的bmppdf图片。
说明:source filter从驱动层获取数据后一般分成两个pin将数据传出,一个是still pin用于传输静态数据,一帧的数据,一个是capture pin用于传出连续的视频数据,用RenderStream的方式gcap.pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video, gcap.pCap, NULL, gcap.pRenderP);默认会产生Smart Tee这个filter,这个filter将接收到的数据分成两份,同样也是分成两个pin传出,本例中我只用到smartTee传出的preview这个pin,连接到Render Filter以显示图象数据.
以下是主要程序部分(DDCam.cpp):
- #include <windows.h>
 - #include <mmsystem.h>
 - #include "streams.h"
 - #include <cs.h>
 - #include <csmedia.h>
 - #include <camera.h>
 - #include <aygshell.h>
 - #include "ddcam.h"
 - #include "grabber.h"
 - #include <windef.h>
 - #define MAX_LOADSTRING 100
 - #define WM_GRAPHNOTIFY WM_APP + 1
 - #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
 - #define CHK( x ) do{ if( FAILED( hr = ( x ))) { goto Cleanup; }} while( FALSE );
 - #define ERR( x ) do{ hr = x; goto Cleanup; } while( FALSE );
 - #define ARRAYSIZE(s) (sizeof(s) / sizeof(s[0]))
 - struct _capstuff
 - {
 - TCHAR szCaptureFile[_MAX_PATH];
 - WORD wCapFileSize;
 - ICaptureGraphBuilder2 *pBuilder;
 - IVideoWindow *pVWS, *pVWP;
 - IMediaEventEx *pME;
 - IAMDroppedFrames *pDF;
 - IAMVideoCompression *pVC;
 - IAMVideoControl *pAMVidControl;
 - IAMCameraControl *pCamControl;
 - IAMVideoProcAmp *pVProcAmp;
 - IAMStreamConfig *pConfigP; //Preview config
 - IAMStreamConfig *pVSC; // for video cap
 - IBaseFilter *pRenderS; //Still render
 - IBaseFilter *pRenderP; //Preview render
 - IBaseFilter *pCap;
 - IGraphBuilder *pGraph;
 - CSampleGrabber *pGrab;
 - IFileSinkFilter *pSink;
 - BOOL fStillGraphBuilt;
 - BOOL fPreviewGraphBuilt;
 - BOOL fStillCapturing;
 - BOOL fPreviewing;
 - } gcap;
 - // Global Variables:
 - HINSTANCE g_hInstance = NULL; // The current instance
 - HWND g_hWnd; //The window instance
 - HWND g_hWndMenu; //Menu handle
 - HWND hWndMenuStill = NULL;
 - // Forward declarations of functions included in this code module:
 - ATOM MyRegisterClass (HINSTANCE, LPTSTR);
 - BOOL InitInstance (HINSTANCE, int);
 - LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
 - LRESULT CALLBACK About (HWND, UINT, WPARAM, LPARAM);
 - HRESULT SetCapMode(IBaseFilter *pCap);
 - HRESULT OpenCamera(LPCOLESTR lpFile,BOOL bCapture,BOOL bStill,BOOL bPreview);
 - BOOL WriteBMPToDisk(unsigned char *pStillImageBuffer,long size);
 - void UpdatePictureNumber();
 - BOOL WriteBMPToTXT(unsigned char *pStillImageBuffer,long lBufferSize);
 - HRESULT ActivatePreviousInstance(const TCHAR* pszClass,const TCHAR* pszTitle,BOOL* pfActivated);
 - int g_PicNumber=0;
 - HRESULT Callback( IMediaSample * pSample, REFERENCE_TIME * StartTime, REFERENCE_TIME *
 - StopTime,BOOL TypeChanged )
 - {
 - unsigned char *pbuf;
 - HRESULT hr = S_OK;
 - // NOTE: We cannot do anything with this sample until we call GetConnectedMediaType
 - // on the filter to find out what format these samples are.
 - RETAILMSG(1, (TEXT("Callback with sample %lx for time %ld"), pSample, long( *StartTime / 10000 ) ) );
 - hr = pSample->GetPointer(&pbuf);
 - LONG lSize = pSample->GetActualDataLength();
 - BOOL bReturn = WriteBMPToDisk(pbuf,lSize);
 - WriteBMPToTXT(pbuf,lSize);
 - if(bReturn == FALSE)
 - {
 - return S_FALSE;
 - }
 - return hr ;
 - }
 - BOOL StartPreview()
 - {
 - HRESULT hr;
 - IMediaControl *pMC = NULL;
 - hr = gcap.pGraph->QueryInterface(IID_IMediaControl, (void **)&pMC);
 - if(SUCCEEDED(hr))
 - {
 - hr = pMC->Run();
 - if(FAILED(hr))
 - {
 - // stop parts that ran
 - pMC->Stop();
 - }
 - pMC->Release();
 - }
 - if(FAILED(hr))
 - {
 - return FALSE;
 - }
 - return TRUE;
 - }
 - // stop the preview graph
 - //
 - BOOL StopPreview()
 - {
 - // way ahead of you
 - if(!gcap.fPreviewing)
 - {
 - return FALSE;
 - }
 - // stop the graph
 - IMediaControl *pMC = NULL;
 - HRESULT hr = gcap.pGraph->QueryInterface(IID_IMediaControl, (void **)&pMC);
 - if(SUCCEEDED(hr))
 - {
 - hr = pMC->Stop();
 - pMC->Release();
 - }
 - if(FAILED(hr))
 - {
 - return FALSE;
 - }
 - gcap.fPreviewing = FALSE;
 - return TRUE;
 - }
 - BOOL CloseCamera()
 - {
 - SAFE_RELEASE(gcap.pCap);
 - SAFE_RELEASE(gcap.pConfigP);
 - SAFE_RELEASE(gcap.pVWS);
 - SAFE_RELEASE(gcap.pVWP);
 - SAFE_RELEASE(gcap.pGraph);
 - SAFE_RELEASE(gcap.pBuilder);
 - return TRUE;
 - }
 - HRESULT CaptureStillImage()
 - {
 - HRESULT hr;
 - hr = SetCapMode(gcap.pCap); //Run still pin
 - return hr;
 - }
 - HRESULT InitCapFilter()
 - {
 - HRESULT hr = S_OK;
 - GUID clsid = DEVCLASS_CAMERA_GUID;
 - IPersistPropertyBag *pPropertyBag = NULL;
 - // Create Capture Filter
 - CHK( hr = CoCreateInstance(CLSID_VideoCapture, NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter,
 - (void **)&gcap.pCap) );
 - DEVMGR_DEVICE_INFORMATION pdi;
 - HANDLE hand = FindFirstDevice(DeviceSearchByGuid,&clsid,&pdi);
 - RETAILMSG(1, (TEXT("CamTest: Find device: %x %x/r/n"),hand,pdi.szDeviceName));
 - CHK( hr = gcap.pCap->QueryInterface(IID_IPersistPropertyBag, (void **)&pPropertyBag) );
 - if (!SUCCEEDED(hr))
 - {
 - return hr;
 - }
 - VARIANT varCamName;
 - IPropertyBag *propBag = NULL;
 - varCamName.byref = L"CAM1:" ;
 - CHK( hr = pPropertyBag->Load(propBag,NULL) );
 - SAFE_RELEASE(pPropertyBag);
 - Cleanup:
 - if(FAILED(hr))
 - {
 - OutputDebugString(L"Initial Error!");
 - SendMessage(g_hWnd,WM_CLOSE,0,0);
 - }
 - return hr;
 - }
 - HRESULT SetupVideoWindow(IVideoWindow *pVW)
 - {
 - HRESULT hr = S_OK;
 - if (pVW)
 - {
 - CHK( hr = pVW->SetWindowPosition(0,0,240,268) );
 - CHK( hr = pVW->put_Owner((OAHWND)g_hWnd) );
 - CHK( hr = pVW->put_WindowStyle(WS_CHILD) );
 - }
 - Cleanup:
 - if(FAILED(hr))
 - {
 - OutputDebugString(L"Setup window Error!");
 - }
 - return hr;
 - }
 - HRESULT ConnectFilters(IGraphBuilder *pGraph,IBaseFilter *pF1, int iPin1,IBaseFilter *pF2,int iPin2,IPin **ppPinout)
 - {
 - IPin *pPin1, *pPin2;
 - IEnumPins *pEnum;
 - unsigned long fetched;
 - HRESULT hr = S_OK;
 - hr = pF1->EnumPins(&pEnum);
 - while (iPin1>0)
 - {
 - hr = pEnum->Next(1,&pPin1,&fetched); //Skip Capture pin
 - iPin1--;
 - }
 - hr = pEnum->Next(1,&pPin1,&fetched);
 - hr = pF2->EnumPins(&pEnum);
 - while (iPin2>0)
 - {
 - hr = pEnum->Next(1,&pPin2,&fetched); //Skip Capture pin
 - iPin2--;
 - }
 - hr = pEnum->Next(1,&pPin2,&fetched);
 - hr = pGraph->Connect(pPin1,pPin2);
 - if (ppPinout)
 - {
 - *ppPinout = pPin1;
 - }
 - if (!SUCCEEDED(hr))
 - RETAILMSG(1, (TEXT("CamTest: Fail to Connect Pin! %x/r/n"),hr));
 - return hr;
 - }
 - HRESULT BuildGraph()
 - {
 - HRESULT hr;
 - gcap.pGrab = new CSampleGrabber(NULL,&hr,FALSE);
 - gcap.pGrab->AddRef();
 - gcap.pGrab->SetCallback(&Callback);
 - CMediaType mt;
 - mt.SetType(&MEDIATYPE_Video);
 - mt.SetSubtype(&MEDIASUBTYPE_RGB24);
 - gcap.pGrab->SetAcceptedMediaType(&mt);
 - // Create the Filter Graph Manager.
 - hr = CoCreateInstance(CLSID_FilterGraph, NULL,
 - CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&gcap.pGraph);
 - // Create the Capture Graph Builder.
 - hr = CoCreateInstance(CLSID_CaptureGraphBuilder, NULL,
 - CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
 - (void **)&gcap.pBuilder);
 - hr = gcap.pGraph->AddFilter(gcap.pCap,L"Video Capture Source");
 - hr = gcap.pGraph->AddFilter(gcap.pGrab,L"SampleGrabber");
 - gcap.pBuilder->SetFiltergraph(gcap.pGraph);
 - hr = CoCreateInstance(CLSID_VideoRenderer, NULL,
 - CLSCTX_INPROC_SERVER, IID_IBaseFilter,
 - (void **)&gcap.pRenderP);
 - hr = CoCreateInstance(CLSID_VideoRenderer, NULL,
 - CLSCTX_INPROC_SERVER, IID_IBaseFilter,
 - (void **)&gcap.pRenderS);
 - hr = gcap.pGraph->AddFilter(gcap.pRenderP,L"Video Render");
 - hr = gcap.pGraph->AddFilter(gcap.pRenderS,L"Video Render");
 - hr = gcap.pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video, gcap.pCap, NULL, gcap.pRenderP);
 - hr = gcap.pRenderP->QueryInterface(IID_IVideoWindow, (void**)&gcap.pVWP);
 - hr = gcap.pBuilder->RenderStream(&PIN_CATEGORY_STILL,&MEDIATYPE_Video, gcap.pCap, gcap.pGrab, gcap.pRenderS);
 - // Query for video interfaces, which may not be relevant for audio files
 - //hr = gcap.pGraph->QueryInterface(IID_IMediaEventEx, (void **)&gcap.pME);
 - //hr = gcap.pCap->QueryInterface(IID_IAMVideoProcAmp,(void **)&gcap.pVProcAmp);
 - //// Query the output pin for IAMStreamConfig (not shown).
 - //hr = gcap.pBuilder->FindInterface(
 - // &PIN_CATEGORY_PREVIEW, // Preview pin.
 - // 0, // Any media type.
 - // gcap.pCap, // Pointer to the capture filter.
 - // IID_IAMStreamConfig, (void**)&gcap.pConfigP);
 - // Have the graph signal event via window callbacks for performance
 - SetupVideoWindow(gcap.pVWP);
 - gcap.pVWP->put_MessageDrain((OAHWND)g_hWnd);
 - gcap.pVWP->put_Owner((OAHWND)g_hWnd);
 - //hr = gcap.pME->SetNotifyWindow((OAHWND)g_hWnd, WM_GRAPHNOTIFY, 0);
 - return hr;
 - }
 - HRESULT SetCapMode(IBaseFilter *pCap)
 - {
 - HRESULT hr;
 - IPin *pPin = NULL;
 - hr = gcap.pCap->FindPin(L"Still",&pPin);
 - if (SUCCEEDED(hr))
 - {
 - hr = gcap.pCap->QueryInterface(IID_IAMVideoControl,(void **)&gcap.pAMVidControl);
 - hr = gcap.pAMVidControl->SetMode(pPin, VideoControlFlag_Trigger);
 - MessageBox(NULL,L"拍照成功,生成的图片保存在根目录下",L"成功",64);
 - pPin->Release();
 - }
 - else
 - {
 - RETAILMSG(1, (TEXT("CamTest: Fail to Find Pin! %x/r/n"),hr));
 - }
 - return hr;
 - }
 - int WINAPI WinMain( HINSTANCE hInstance,
 - HINSTANCE hPrevInstance,
 - LPTSTR lpCmdLine,
 - int nCmdShow)
 - {
 - MSG msg;
 - HACCEL hAccelTable;
 - //Init COM
 - // Get COM interfaces
 - if(FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
 - {
 - RETAILMSG(1, (TEXT("CoInitialize Failed!/r/n")));
 - return FALSE;
 - }
 - // Perform application initialization:
 - if (!InitInstance (hInstance, nCmdShow))
 - {
 - return FALSE;
 - }
 - hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WCETEST);
 - // Main message loop:
 - while (GetMessage(&msg, NULL, 0, 0))
 - {
 - if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
 - {
 - TranslateMessage(&msg);
 - DispatchMessage(&msg);
 - }
 - }
 - // Finished with COM
 - CoUninitialize();
 - return msg.wParam;
 - }
 - //
 - // FUNCTION: InitInstance(HANDLE, int)
 - //
 - // PURPOSE: Saves instance handle and creates main window
 - //
 - // COMMENTS:
 - //
 - // In this function, we save the instance handle in a global variable and
 - // create and display the main program window.
 - //
 - BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
 - {
 - HRESULT hr;
 - BOOL fActivated;
 - TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
 - TCHAR szWindowClass[MAX_LOADSTRING]; // The window class name
 - g_hInstance = hInstance; // Store instance handle in our global variable
 - // Initialize global strings
 - LoadString(hInstance, IDC_WCETEST, szWindowClass, MAX_LOADSTRING);
 - WNDCLASS wc;
 - wc.style = CS_HREDRAW | CS_VREDRAW;
 - wc.lpfnWndProc = (WNDPROC) WndProc;
 - wc.cbClsExtra = 0;
 - wc.cbWndExtra = 0;
 - wc.hInstance = hInstance;
 - wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WCETEST));
 - wc.hCursor = 0;
 - wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
 - wc.lpszMenuName = 0;
 - wc.lpszClassName = szWindowClass;
 - RegisterClass(&wc);
 - LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
 - if(FAILED(ActivatePreviousInstance(szWindowClass, szTitle, &fActivated)) ||
 - fActivated)
 - {
 - return(0);
 - }
 - g_hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
 - CW_USEDEFAULT, CW_USEDEFAULT, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL);
 - if (!g_hWnd)
 - {
 - return FALSE;
 - }
 - ShowWindow(g_hWnd, nCmdShow);
 - UpdateWindow(g_hWnd);
 - hr = InitCapFilter();
 - if (SUCCEEDED(hr))
 - {
 - BuildGraph();
 - StartPreview();
 - }
 - else
 - {
 - RETAILMSG(1,(TEXT("CamTest: Fail to create Capture filter. /r/n")));
 - }
 - return TRUE;
 - }
 - /**************************************************************************************
 - OnCreate
 - **************************************************************************************/
 - LRESULT OnCreate(
 - HWND hwnd,
 - CREATESTRUCT* lParam
 - )
 - {
 - // create the menu bar
 - SHMENUBARINFO mbi;
 - ZeroMemory(&mbi, sizeof(SHMENUBARINFO));
 - mbi.cbSize = sizeof(SHMENUBARINFO);
 - mbi.hwndParent = hwnd;
 - mbi.nToolBarId = IDM_MENU;
 - mbi.hInstRes = g_hInstance;
 - mbi.dwFlags = SHCMBF_HMENU;
 - if(!SHCreateMenuBar(&mbi))
 - {
 - // Couldn't create the menu bar. Fail creation of the window.
 - return(-1);
 - }
 - return(0); // continue creation of the window
 - }
 - // FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
 - //
 - // PURPOSE: Processes messages for the main window.
 - //
 - // WM_COMMAND - process the application menu
 - // WM_PAINT - Paint the main window
 - // WM_DESTROY - post a quit message and return
 - //
 - //
 - /**************************************************************************************
 - WndProc
 - **************************************************************************************/
 - LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 - {
 - LRESULT lResult = TRUE;
 - switch(message)
 - {
 - case WM_CLOSE:
 - StopPreview();
 - CloseCamera();
 - DestroyWindow(hWnd);
 - break;
 - case WM_CREATE:
 - lResult = OnCreate(hWnd, (CREATESTRUCT*)lParam);
 - break;
 - case WM_COMMAND:
 - switch (wParam)
 - {
 - case ID_CAPTURE:
 - CaptureStillImage();
 - break;
 - }
 - break;
 - case WM_DESTROY:
 - PostQuitMessage(0);
 - break;
 - default:
 - lResult = DefWindowProc(hWnd, message, wParam, lParam);
 - break;
 - }
 - return(lResult);
 - }
 - BOOL WriteBMPToTXT(unsigned char *pStillImageBuffer,long lBufferSize)
 - {
 - TCHAR x[256];
 - const TCHAR *picture_path = TEXT("//My Documents//My Pictures") ;
 - UpdatePictureNumber();
 - wsprintf(x, TEXT("%s//%d.txt"), picture_path, g_PicNumber++);
 - HANDLE hf = CreateFile(x,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,NULL,NULL);
 - if(hf == INVALID_HANDLE_VALUE)
 - return FALSE;
 - DWORD dwWritten=0;
 - if( !WriteFile(hf,pStillImageBuffer,lBufferSize,&dwWritten,NULL) )
 - {
 - return FALSE;
 - }
 - CloseHandle(hf);
 - return TRUE;
 - }
 - BOOL WriteBMPToDisk(unsigned char *pStillImageBuffer,long lBufferSize)//保存为24位的图片
 - {
 - TCHAR x[256];
 - UpdatePictureNumber();
 - wsprintf(x, TEXT("%d.bmp"), g_PicNumber++);
 - HANDLE hf = CreateFile(x,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,NULL,NULL);
 - if(hf == INVALID_HANDLE_VALUE)
 - return FALSE;
 - BITMAPFILEHEADER bfh;
 - memset(&bfh,0,sizeof(bfh));
 - bfh.bfType=0x4D42/*((WORD) ('M' << 8) | 'B')*/;
 - bfh.bfSize=sizeof(bfh)+lBufferSize+sizeof(BITMAPFILEHEADER);
 - bfh.bfOffBits=sizeof(BITMAPINFOHEADER)+sizeof(BITMAPFILEHEADER);
 - DWORD dwWritten=0;
 - WriteFile(hf,&bfh,sizeof(bfh),&dwWritten,NULL);
 - BITMAPINFOHEADER bih;
 - memset(&bih,0,sizeof(bih));
 - bih.biSize=sizeof(bih);
 - bih.biWidth=144;
 - bih.biHeight=176;
 - bih.biPlanes=1;
 - bih.biBitCount=24;
 - if( !WriteFile(hf,&bih,sizeof(bih),&dwWritten,NULL) )
 - {
 - return FALSE;
 - }
 - if( !WriteFile(hf,pStillImageBuffer,lBufferSize,&dwWritten,NULL) )
 - {
 - return FALSE;
 - }
 - CloseHandle(hf);
 - return TRUE;
 - }
 - //
 - //// Look for cam.cfg
 - //// If it doesn't exist, create it, and set picture number to 1.
 - //// If it exists, read the value stored inside, increment the number, and write it back.
 - void UpdatePictureNumber()
 - {
 - DWORD dwSize;
 - HANDLE hFile;
 - char *buffer;
 - buffer = (char *)malloc(1024);
 - hFile = CreateFile(TEXT("//temp//cam.cfg"), GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 - dwSize = 0;
 - if (hFile == INVALID_HANDLE_VALUE)
 - {
 - // File did not exist, so we are going to create it, and initialize the counter.
 - g_PicNumber = 1;
 - hFile = CreateFile(TEXT("//temp//cam.cfg"), GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
 - buffer[0] = g_PicNumber & 0x00FF;
 - buffer[1] = (g_PicNumber & 0xFF00) >> 8;
 - WriteFile(hFile, buffer, 2, &dwSize, NULL);
 - CloseHandle(hFile);
 - } else
 - {
 - dwSize = 0;
 - ReadFile(hFile, buffer, 2, &dwSize, NULL);
 - g_PicNumber = buffer[1];
 - g_PicNumber <<= 8;
 - g_PicNumber |= buffer[0];
 - g_PicNumber++;
 - CloseHandle(hFile);
 - hFile = CreateFile(TEXT("//temp//cam.cfg"), GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 - buffer[0] = g_PicNumber & 0x00FF;
 - buffer[1] = (g_PicNumber & 0xFF00) >> 8;
 - dwSize = 0;
 - WriteFile(hFile, buffer, 2, &dwSize, NULL);
 - CloseHandle(hFile);
 - }
 - free(buffer);
 - }
 - /****************************************************************************
 - ActivatePreviousInstance
 - ****************************************************************************/
 - HRESULT ActivatePreviousInstance(
 - const TCHAR* pszClass,
 - const TCHAR* pszTitle,
 - BOOL* pfActivated
 - )
 - {
 - HRESULT hr = S_OK;
 - int cTries;
 - HANDLE hMutex = NULL;
 - *pfActivated = FALSE;
 - cTries = 5;
 - while(cTries > 0)
 - {
 - hMutex = CreateMutex(NULL, FALSE, pszClass); // NOTE: We don't want to own the object.
 - if(NULL == hMutex)
 - {
 - // Something bad happened, fail.
 - hr = E_FAIL;
 - goto Exit;
 - }
 - if(GetLastError() == ERROR_ALREADY_EXISTS)
 - {
 - HWND hwnd;
 - CloseHandle(hMutex);
 - hMutex = NULL;
 - // There is already an instance of this app
 - // running. Try to bring it to the foreground.
 - hwnd = FindWindow(pszClass, pszTitle);
 - if(NULL == hwnd)
 - {
 - // It's possible that the other window is in the process of being created...
 - Sleep(500);
 - hwnd = FindWindow(pszClass, pszTitle);
 - }
 - if(NULL != hwnd)
 - {
 - // Set the previous instance as the foreground window
 - // The "| 0x01" in the code below activates
 - // the correct owned window of the
 - // previous instance's main window.
 - SetForegroundWindow((HWND) (((ULONG) hwnd) | 0x01));
 - // We are done.
 - *pfActivated = TRUE;
 - break;
 - }
 - // It's possible that the instance we found isn't coming up,
 - // but rather is going down. Try again.
 - cTries--;
 - }
 - else
 - {
 - // We were the first one to create the mutex
 - // so that makes us the main instance. 'leak'
 - // the mutex in this function so it gets cleaned
 - // up by the OS when this instance exits.
 - break;
 - }
 - }
 - if(cTries <= 0)
 - {
 - // Someone else owns the mutex but we cannot find
 - // their main window to activate.
 - hr = E_FAIL;
 - goto Exit;
 - }
 - Exit:
 - return(hr);
 - }
 - void setscreenMetrics(HWND hWnd,int width,int height)
 - {
 - DEVMODE lpDevMode;
 - lpDevMode.dmBitsPerPel=24;
 - lpDevMode.dmPelsWidth=width;
 - lpDevMode.dmPelsHeight=height;
 - lpDevMode.dmSize=sizeof(lpDevMode);
 - lpDevMode.dmFields=DM_PELSWIDTH|DM_PELSHEIGHT;
 - LONG result;
 - result=ChangeDisplaySettingsEx(NULL,&lpDevMode,hWnd,0,NULL);
 - if(result==DISP_CHANGE_SUCCESSFUL)
 - {
 - MessageBoxW(hWnd,_T("success!"),_T("alert"),MB_OK);
 - }
 - else
 - {
 - MessageBoxW(hWnd,_T("failure!"),_T("alert"),MB_OK);
 - }
 - }
 
主要构建Graph的代码:
HRESULT BuildGraph()
{
 HRESULT hr;
 gcap.pGrab = new CSampleGrabber(NULL,&hr,FALSE); 
 gcap.pGrab->AddRef();
 gcap.pGrab->SetCallback(&Callback);
 CMediaType mt;
 mt.SetType(&MEDIATYPE_Video);
 mt.SetSubtype(&MEDIASUBTYPE_RGB24);
 gcap.pGrab->SetAcceptedMediaType(&mt);
 // Create the Filter Graph Manager.
 hr =  CoCreateInstance(CLSID_FilterGraph, NULL,
  CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&gcap.pGraph);
 // Create the Capture Graph Builder.
 hr = CoCreateInstance(CLSID_CaptureGraphBuilder, NULL,
  CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, 
  (void **)&gcap.pBuilder);
 hr = gcap.pGraph->AddFilter(gcap.pCap,L"Video Capture Source"); 
 hr = gcap.pGraph->AddFilter(gcap.pGrab,L"SampleGrabber"); 
gcap.pBuilder->SetFiltergraph(gcap.pGraph);
 hr = CoCreateInstance(CLSID_VideoRenderer, NULL,
  CLSCTX_INPROC_SERVER, IID_IBaseFilter, 
  (void **)&gcap.pRenderP);
 hr = CoCreateInstance(CLSID_VideoRenderer, NULL,
  CLSCTX_INPROC_SERVER, IID_IBaseFilter, 
  (void **)&gcap.pRenderS);
 hr = gcap.pGraph->AddFilter(gcap.pRenderP,L"Video Render");
 hr = gcap.pGraph->AddFilter(gcap.pRenderS,L"Video Render");
 hr = gcap.pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video, gcap.pCap, NULL, gcap.pRenderP);   
 hr = gcap.pRenderP->QueryInterface(IID_IVideoWindow, (void**)&gcap.pVWP);
  hr = gcap.pBuilder->RenderStream(&PIN_CATEGORY_STILL,&MEDIATYPE_Video, gcap.pCap, gcap.pGrab, gcap.pRenderS);   
 // Query for video interfaces, which may not be relevant for audio files
 //hr = gcap.pGraph->QueryInterface(IID_IMediaEventEx, (void **)&gcap.pME);        
 
 //hr = gcap.pCap->QueryInterface(IID_IAMVideoProcAmp,(void **)&gcap.pVProcAmp);
 //// Query the output pin for IAMStreamConfig (not shown).
 //hr = gcap.pBuilder->FindInterface(
 // &PIN_CATEGORY_PREVIEW, // Preview pin.
 // 0,    // Any media type.
 // gcap.pCap, // Pointer to the capture filter.
 // IID_IAMStreamConfig, (void**)&gcap.pConfigP); 
 // Have the graph signal event via window callbacks for performance
 SetupVideoWindow(gcap.pVWP);
 gcap.pVWP->put_MessageDrain((OAHWND)g_hWnd);
 gcap.pVWP->put_Owner((OAHWND)g_hWnd); 
 //hr = gcap.pME->SetNotifyWindow((OAHWND)g_hWnd, WM_GRAPHNOTIFY, 0);    
 return hr;
}
另外SampleGrabber这个filter是要一个transform filter,可以在 directx 的directshow sample里找到,主要代码如下(Grabber.cpp):
- //------------------------------------------------------------------------------
 - // File: Grabber.cpp
 - //
 - // Desc: DirectShow sample code - Implementation file for the SampleGrabber
 - // example filter
 - //
 - // Copyright (c) Microsoft Corporation. All rights reserved.
 - //------------------------------------------------------------------------------
 - #include <streams.h> // Active Movie (includes windows.h)
 - #include <initguid.h> // declares DEFINE_GUID to declare an EXTERN_C const.
 - #include "grabber.h"
 - //#pragma warning(disable: 4800)
 - const AMOVIESETUP_PIN psudSampleGrabberPins[] =
 - { { L"Input" // strName
 - , FALSE // bRendered
 - , FALSE // bOutput
 - , FALSE // bZero
 - , FALSE // bMany
 - , &CLSID_NULL // clsConnectsToFilter
 - , L"" // strConnectsToPin
 - , 0 // nTypes
 - , NULL // lpTypes
 - }
 - , { L"Output" // strName
 - , FALSE // bRendered
 - , TRUE // bOutput
 - , FALSE // bZero
 - , FALSE // bMany
 - , &CLSID_NULL // clsConnectsToFilter
 - , L"" // strConnectsToPin
 - , 0 // nTypes
 - , NULL // lpTypes
 - }
 - };
 - const AMOVIESETUP_FILTER sudSampleGrabber =
 - { &CLSID_GrabberSample // clsID
 - , L"SampleGrabber Example" // strName
 - , MERIT_DO_NOT_USE // dwMerit
 - , 2 // nPins
 - , psudSampleGrabberPins }; // lpPin
 - // Needed for the CreateInstance mechanism
 - CFactoryTemplate g_Templates[]=
 - {
 - { L"Sample Grabber Example"
 - , &CLSID_GrabberSample
 - , CSampleGrabber::CreateInstance
 - , NULL
 - , &sudSampleGrabber }
 - };
 - int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]);
 - ////////////////////////////////////////////////////////////////////////
 - //
 - // Exported entry points for registration and unregistration
 - // (in this case they only call through to default implementations).
 - //
 - ////////////////////////////////////////////////////////////////////////
 - STDAPI DllRegisterServer()
 - {
 - return AMovieDllRegisterServer2(TRUE);
 - }
 - STDAPI DllUnregisterServer()
 - {
 - return AMovieDllRegisterServer2(FALSE);
 - }
 - //
 - // DllMain
 - //
 - extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
 - BOOL WINAPI DllMain(HANDLE hModule,
 - DWORD dwReason,
 - LPVOID lpReserved)
 - {
 - return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
 - }
 - //
 - // CreateInstance
 - //
 - // Provide the way for COM to create a CSampleGrabber object
 - //
 - CUnknown * WINAPI CSampleGrabber::CreateInstance(LPUNKNOWN punk, HRESULT *phr)
 - {
 - ASSERT(phr);
 - // assuming we don't want to modify the data
 - CSampleGrabber *pNewObject = new CSampleGrabber(punk, phr, FALSE);
 - if(pNewObject == NULL) {
 - if (phr)
 - *phr = E_OUTOFMEMORY;
 - }
 - return pNewObject;
 - } // CreateInstance
 - //----------------------------------------------------------------------------
 - //
 - //----------------------------------------------------------------------------
 - CSampleGrabber::CSampleGrabber( IUnknown * pOuter, HRESULT * phr, BOOL ModifiesData )
 - : CTransInPlaceFilter( TEXT("SampleGrabber"), (IUnknown*) pOuter,
 - //CLSID_GrabberSample, phr, (BOOL)ModifiesData )
 - CLSID_GrabberSample, phr)
 - , m_callback( NULL )
 - {
 - // this is used to override the input pin with our own
 - m_pInput = (CTransInPlaceInputPin*) new CSampleGrabberInPin( this, phr );
 - if( !m_pInput )
 - {
 - if (phr)
 - *phr = E_OUTOFMEMORY;
 - }
 - // Ensure that the output pin gets created. This is necessary because our
 - // SetDeliveryBuffer() method assumes that the input/output pins are created, but
 - // the output pin isn't created until GetPin() is called. The
 - // CTransInPlaceFilter::GetPin() method will create the output pin, since we
 - // have not already created one.
 - IPin *pOutput = GetPin(1);
 - // The pointer is not AddRef'ed by GetPin(), so don't release it
 - }
 - STDMETHODIMP CSampleGrabber::NonDelegatingQueryInterface( REFIID riid, void ** ppv)
 - {
 - CheckPointer(ppv,E_POINTER);
 - if(riid == IID_IGrabberSample) {
 - return GetInterface((IGrabberSample *) this, ppv);
 - }
 - else {
 - return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv);
 - }
 - }
 - //----------------------------------------------------------------------------
 - // This is where you force the sample grabber to connect with one type
 - // or the other. What you do here is crucial to what type of data your
 - // app will be dealing with in the sample grabber's callback. For instance,
 - // if you don't enforce right-side-up video in this call, you may not get
 - // right-side-up video in your callback. It all depends on what you do here.
 - //----------------------------------------------------------------------------
 - HRESULT CSampleGrabber::CheckInputType( const CMediaType * pmt )
 - {
 - CheckPointer(pmt,E_POINTER);
 - CAutoLock lock( &m_Lock );
 - // if the major type is not set, then accept anything
 - GUID g = *m_mtAccept.Type( );
 - if( g == GUID_NULL )
 - {
 - return NOERROR;
 - }
 - // if the major type is set, don't accept anything else
 - if( g != *pmt->Type( ) )
 - {
 - return VFW_E_INVALID_MEDIA_TYPE;
 - }
 - // subtypes must match, if set. if not set, accept anything
 - g = *m_mtAccept.Subtype( );
 - if( g == GUID_NULL )
 - {
 - return NOERROR;
 - }
 - if( g != *pmt->Subtype( ) )
 - {
 - return VFW_E_INVALID_MEDIA_TYPE;
 - }
 - // format types must match, if one is set
 - g = *m_mtAccept.FormatType( );
 - if( g == GUID_NULL )
 - {
 - return NOERROR;
 - }
 - if( g != *pmt->FormatType( ) )
 - {
 - return VFW_E_INVALID_MEDIA_TYPE;
 - }
 - // at this point, for this sample code, this is good enough,
 - // but you may want to make it more strict
 - return NOERROR;
 - }
 - //----------------------------------------------------------------------------
 - // This bit is almost straight out of the base classes.
 - // We override this so we can handle Transform( )'s error
 - // result differently.
 - //----------------------------------------------------------------------------
 - HRESULT CSampleGrabber::Receive( IMediaSample * pms )
 - {
 - CheckPointer(pms,E_POINTER);
 - HRESULT hr;
 - AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();
 - RETAILMSG(1, (TEXT("Grabber: Receive! %x/r/n")));
 - if (pProps->dwStreamId != AM_STREAM_MEDIA)
 - {
 - if( m_pOutput->IsConnected() )
 - return m_pOutput->Deliver(pms);
 - else
 - return NOERROR;
 - }
 - /* if (UsingDifferentAllocators())
 - {
 - // We have to copy the data.
 - pms = Copy(pms);
 - if (pms == NULL)
 - {
 - return E_UNEXPECTED;
 - }
 - }
 - */
 - // have the derived class transform the data
 - hr = Transform(pms);
 - if (FAILED(hr))
 - {
 - // DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace")));
 - /* if (UsingDifferentAllocators())
 - {
 - pms->Release();
 - }
 - */
 - return hr;
 - }
 - if (hr == NOERROR)
 - {
 - hr = m_pOutput->Deliver(pms);
 - }
 - // release the output buffer. If the connected pin still needs it,
 - // it will have addrefed it itself.
 - /* if (UsingDifferentAllocators())
 - {
 - pms->Release();
 - }
 - */
 - return hr;
 - }
 - //----------------------------------------------------------------------------
 - // Transform
 - //----------------------------------------------------------------------------
 - HRESULT CSampleGrabber::Transform ( IMediaSample * pms )
 - {
 - CheckPointer(pms,E_POINTER);
 - CAutoLock lock( &m_Lock );
 - RETAILMSG(1, (TEXT("Grabber: Transform! %x/r/n")));
 - if( m_callback )
 - {
 - REFERENCE_TIME StartTime, StopTime;
 - pms->GetTime( &StartTime, &StopTime);
 - StartTime += m_pInput->CurrentStartTime( );
 - StopTime += m_pInput->CurrentStartTime( );
 - BOOL * pTypeChanged = &((CSampleGrabberInPin*) m_pInput)->m_bMediaTypeChanged;
 - HRESULT hr = m_callback( pms, &StartTime, &StopTime, *pTypeChanged );
 - *pTypeChanged = FALSE; // now that we notified user, we can clear it
 - return hr;
 - }
 - return NOERROR;
 - }
 - //----------------------------------------------------------------------------
 - // SetAcceptedMediaType
 - //----------------------------------------------------------------------------
 - STDMETHODIMP CSampleGrabber::SetAcceptedMediaType( const CMediaType * pmt )
 - {
 - CAutoLock lock( &m_Lock );
 - if( !pmt )
 - {
 - m_mtAccept = CMediaType( );
 - return NOERROR;
 - }
 - HRESULT hr = TRUE;
 - CopyMediaType( &m_mtAccept, pmt );
 - return hr;
 - }
 - //----------------------------------------------------------------------------
 - // GetAcceptedMediaType
 - //----------------------------------------------------------------------------
 - STDMETHODIMP CSampleGrabber::GetConnectedMediaType( CMediaType * pmt )
 - {
 - if( !m_pInput || !m_pInput->IsConnected( ) )
 - {
 - return VFW_E_NOT_CONNECTED;
 - }
 - return m_pInput->ConnectionMediaType( pmt );
 - }
 - //----------------------------------------------------------------------------
 - // SetCallback
 - //----------------------------------------------------------------------------
 - STDMETHODIMP CSampleGrabber::SetCallback( SAMPLECALLBACK Callback )
 - {
 - CAutoLock lock( &m_Lock );
 - m_callback = Callback;
 - return NOERROR;
 - }
 - //----------------------------------------------------------------------------
 - // inform the input pin of the allocator buffer we wish to use. See the
 - // input pin's SetDeliverBuffer method for comments.
 - //----------------------------------------------------------------------------
 - STDMETHODIMP CSampleGrabber::SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer )
 - {
 - // have the input/output pins been created?
 - if( !InputPin( ) || !OutputPin( ) )
 - {
 - return E_POINTER;
 - }
 - // they can't be connected if we're going to be changing delivery buffers
 - //
 - if( InputPin( )->IsConnected( ) || OutputPin( )->IsConnected( ) )
 - {
 - return E_INVALIDARG;
 - }
 - return ((CSampleGrabberInPin*)m_pInput)->SetDeliveryBuffer( props, m_pBuffer );
 - }
 - //----------------------------------------------------------------------------
 - // used to help speed input pin connection times. We return a partially
 - // specified media type - only the main type is specified. If we return
 - // anything BUT a major type, some codecs written improperly will crash
 - //----------------------------------------------------------------------------
 - HRESULT CSampleGrabberInPin::GetMediaType( int iPosition, CMediaType * pMediaType )
 - {
 - CheckPointer(pMediaType,E_POINTER);
 - if (iPosition < 0) {
 - return E_INVALIDARG;
 - }
 - if (iPosition > 0) {
 - return VFW_S_NO_MORE_ITEMS;
 - }
 - mt=*pMediaType;
 - *pMediaType = CMediaType( );
 - pMediaType->SetType( ((CSampleGrabber*)m_pFilter)->m_mtAccept.Type());
 - return S_OK;
 - }
 - //----------------------------------------------------------------------------
 - // override the CTransInPlaceInputPin's method, and return a new enumerator
 - // if the input pin is disconnected. This will allow GetMediaType to be
 - // called. If we didn't do this, EnumMediaTypes returns a failure code
 - // and GetMediaType is never called.
 - //----------------------------------------------------------------------------
 - STDMETHODIMP CSampleGrabberInPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )
 - {
 - CheckPointer(ppEnum,E_POINTER);
 - ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *));
 - // if the output pin isn't connected yet, offer the possibly
 - // partially specified media type that has been set by the user
 - if( !((CSampleGrabber*)m_pTIPFilter)->OutputPin( )->IsConnected() )
 - {
 - // Create a new reference counted enumerator
 - *ppEnum = new CEnumMediaTypes( this, NULL );
 - return (*ppEnum) ? NOERROR : E_OUTOFMEMORY;
 - }
 - // if the output pin is connected, offer it's fully qualified media type
 - return ((CSampleGrabber*)m_pTIPFilter)->OutputPin( )->GetConnected()->EnumMediaTypes( ppEnum );
 - }
 - //----------------------------------------------------------------------------
 - //
 - //----------------------------------------------------------------------------
 - STDMETHODIMP CSampleGrabberInPin::NotifyAllocator( IMemAllocator *pAllocator, BOOL bReadOnly )
 - {
 - if( m_pPrivateAllocator )
 - {
 - if( pAllocator != m_pPrivateAllocator )
 - {
 - return E_FAIL;
 - }
 - else
 - {
 - // if the upstream guy wants to be read only and we don't, then that's bad
 - // if the upstream guy doesn't request read only, but we do, that's okay
 - if( bReadOnly && !SampleGrabber( )->IsReadOnly( ) )
 - {
 - return E_FAIL;
 - }
 - }
 - }
 - return CTransInPlaceInputPin::NotifyAllocator( pAllocator, bReadOnly );
 - }
 - //----------------------------------------------------------------------------
 - //
 - //----------------------------------------------------------------------------
 - STDMETHODIMP CSampleGrabberInPin::GetAllocator( IMemAllocator **ppAllocator )
 - {
 - if( m_pPrivateAllocator )
 - {
 - CheckPointer(ppAllocator,E_POINTER);
 - *ppAllocator = m_pPrivateAllocator;
 - m_pPrivateAllocator->AddRef( );
 - return NOERROR;
 - }
 - else
 - {
 - return CTransInPlaceInputPin::GetAllocator( ppAllocator );
 - }
 - }
 - //----------------------------------------------------------------------------
 - // GetAllocatorRequirements: The upstream filter calls this to get our
 - // filter's allocator requirements. If the app has set the buffer, then
 - // we return those props. Otherwise, we use the default TransInPlace behavior.
 - //----------------------------------------------------------------------------
 - HRESULT CSampleGrabberInPin::GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps )
 - {
 - CheckPointer(pProps,E_POINTER);
 - if (m_pPrivateAllocator)
 - {
 - *pProps = m_allocprops;
 - return S_OK;
 - }
 - else
 - {
 - return CTransInPlaceInputPin::GetAllocatorRequirements(pProps);
 - }
 - }
 - //----------------------------------------------------------------------------
 - //
 - //----------------------------------------------------------------------------
 - HRESULT CSampleGrabberInPin::SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * pBuffer )
 - {
 - // don't allow more than one buffer
 - if( props.cBuffers != 1 )
 - {
 - return E_INVALIDARG;
 - }
 - if( !pBuffer )
 - {
 - return E_POINTER;
 - }
 - m_allocprops = props;
 - m_pBuffer = pBuffer;
 - // If there is an existing allocator, make sure that it is released
 - // to prevent a memory leak
 - if (m_pPrivateAllocator)
 - {
 - m_pPrivateAllocator->Release();
 - m_pPrivateAllocator = NULL;
 - }
 - HRESULT hr = S_OK;
 - m_pPrivateAllocator = new CSampleGrabberAllocator( this, &hr );
 - if( !m_pPrivateAllocator )
 - {
 - return E_OUTOFMEMORY;
 - }
 - m_pPrivateAllocator->AddRef( );
 - return hr;
 - }
 - //----------------------------------------------------------------------------
 - //
 - //----------------------------------------------------------------------------
 - HRESULT CSampleGrabberInPin::SetMediaType( const CMediaType *pmt )
 - {
 - m_bMediaTypeChanged = TRUE;
 - return CTransInPlaceInputPin::SetMediaType( pmt );
 - }
 - //----------------------------------------------------------------------------
 - // don't allocate the memory, just use the buffer the app provided
 - //----------------------------------------------------------------------------
 - HRESULT CSampleGrabberAllocator::Alloc( )
 - {
 - // look at the base class code to see where this came from!
 - CAutoLock lck(this);
 - // Check he has called SetProperties
 - HRESULT hr = CBaseAllocator::Alloc();
 - if (FAILED(hr)) {
 - return hr;
 - }
 - // If the requirements haven't changed then don't reallocate
 - if (hr == S_FALSE) {
 - ASSERT(m_pBuffer);
 - return NOERROR;
 - }
 - ASSERT(hr == S_OK); // we use this fact in the loop below
 - // Free the old resources
 - if (m_pBuffer) {
 - ReallyFree();
 - }
 - // Compute the aligned size
 - LONG lAlignedSize = m_lSize + m_lPrefix;
 - if (m_lAlignment > 1)
 - {
 - LONG lRemainder = lAlignedSize % m_lAlignment;
 - if (lRemainder != 0)
 - {
 - lAlignedSize += (m_lAlignment - lRemainder);
 - }
 - }
 - // Create the contiguous memory block for the samples
 - // making sure it's properly aligned (64K should be enough!)
 - ASSERT(lAlignedSize % m_lAlignment == 0);
 - // don't create the buffer - use what was passed to us
 - //
 - m_pBuffer = m_pPin->m_pBuffer;
 - if (m_pBuffer == NULL) {
 - return E_OUTOFMEMORY;
 - }
 - LPBYTE pNext = m_pBuffer;
 - CMediaSample *pSample;
 - ASSERT(m_lAllocated == 0);
 - // Create the new samples - we have allocated m_lSize bytes for each sample
 - // plus m_lPrefix bytes per sample as a prefix. We set the pointer to
 - // the memory after the prefix - so that GetPointer() will return a pointer
 - // to m_lSize bytes.
 - for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize)
 - {
 - pSample = new CMediaSample(
 - NAME("Sample Grabber memory media sample"),
 - this,
 - &hr,
 - pNext + m_lPrefix, // GetPointer() value
 - m_lSize); // not including prefix
 - ASSERT(SUCCEEDED(hr));
 - if (pSample == NULL)
 - return E_OUTOFMEMORY;
 - // This CANNOT fail
 - m_lFree.Add(pSample);
 - }
 - m_bChanged = FALSE;
 - return NOERROR;
 - }
 - //----------------------------------------------------------------------------
 - // don't really free the memory
 - //----------------------------------------------------------------------------
 - void CSampleGrabberAllocator::ReallyFree()
 - {
 - // look at the base class code to see where this came from!
 - // Should never be deleting this unless all buffers are freed
 - ASSERT(m_lAllocated == m_lFree.GetCount());
 - // Free up all the CMediaSamples
 - CMediaSample *pSample;
 - for (;;)
 - {
 - pSample = m_lFree.RemoveHead();
 - if (pSample != NULL)
 - {
 - delete pSample;
 - }
 - else
 - {
 - break;
 - }
 - }
 - m_lAllocated = 0;
 - // don't free the buffer - let the app do it
 - }
 - //----------------------------------------------------------------------------
 - // SetProperties: Called by the upstream filter to set the allocator
 - // properties. The application has already allocated the buffer, so we reject
 - // anything that is not compatible with that, and return the actual props.
 - //----------------------------------------------------------------------------
 - HRESULT CSampleGrabberAllocator::SetProperties(
 - ALLOCATOR_PROPERTIES *pRequest,
 - ALLOCATOR_PROPERTIES *pActual
 - )
 - {
 - HRESULT hr = CMemAllocator::SetProperties(pRequest, pActual);
 - if (FAILED(hr))
 - {
 - return hr;
 - }
 - ALLOCATOR_PROPERTIES *pRequired = &(m_pPin->m_allocprops);
 - if (pRequest->cbAlign != pRequired->cbAlign)
 - {
 - return VFW_E_BADALIGN;
 - }
 - if (pRequest->cbPrefix != pRequired->cbPrefix)
 - {
 - return E_FAIL;
 - }
 - if (pRequest->cbBuffer > pRequired->cbBuffer)
 - {
 - return E_FAIL;
 - }
 - if (pRequest->cBuffers > pRequired->cBuffers)
 - {
 - return E_FAIL;
 - }
 - *pActual = *pRequired;
 - m_lCount = pRequired->cBuffers;
 - m_lSize = pRequired->cbBuffer;
 - m_lAlignment = pRequired->cbAlign;
 - m_lPrefix = pRequired->cbPrefix;
 - return S_OK;
 - }
 
还有个头文件Grabber.h:
- //------------------------------------------------------------------------------
 - // File: Grabber.h
 - //
 - // Desc: DirectShow sample code - Header file for the SampleGrabber
 - // example filter
 - //
 - // Copyright (c) Microsoft Corporation. All rights reserved.
 - //------------------------------------------------------------------------------
 - //------------------------------------------------------------------------------
 - // Define new GUID and IID for the sample grabber example so that they do NOT
 - // conflict with the official DirectX SampleGrabber filter
 - //------------------------------------------------------------------------------
 - // {2FA4F053-6D60-4cb0-9503-8E89234F3F73}
 - DEFINE_GUID(CLSID_GrabberSample,
 - 0x2fa4f053, 0x6d60, 0x4cb0, 0x95, 0x3, 0x8e, 0x89, 0x23, 0x4f, 0x3f, 0x73);
 - DEFINE_GUID(IID_IGrabberSample,
 - 0x6b652fff, 0x11fe, 0x4fce, 0x92, 0xad, 0x02, 0x66, 0xb5, 0xd7, 0xc7, 0x8f);
 - // We define a callback typedef for this example.
 - // Normally, you would make the SampleGrabber support a COM interface,
 - // and in one of its methods you would pass in a pointer to a COM interface
 - // used for calling back. See the DirectX documentation for the SampleGrabber
 - // for more information.
 - typedef HRESULT (*SAMPLECALLBACK) (
 - IMediaSample * pSample,
 - REFERENCE_TIME * StartTime,
 - REFERENCE_TIME * StopTime,
 - BOOL TypeChanged );
 - // We define the interface the app can use to program us
 - MIDL_INTERFACE("6B652FFF-11FE-4FCE-92AD-0266B5D7C78F")
 - IGrabberSample : public IUnknown
 - {
 - public:
 - virtual HRESULT STDMETHODCALLTYPE SetAcceptedMediaType(
 - const CMediaType *pType) = 0;
 - virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType(
 - CMediaType *pType) = 0;
 - virtual HRESULT STDMETHODCALLTYPE SetCallback(
 - SAMPLECALLBACK Callback) = 0;
 - virtual HRESULT STDMETHODCALLTYPE SetDeliveryBuffer(
 - ALLOCATOR_PROPERTIES props,
 - BYTE *pBuffer) = 0;
 - };
 - class CSampleGrabberInPin;
 - class CSampleGrabber;
 - //----------------------------------------------------------------------------
 - // This is a special allocator that KNOWS that the person who is creating it
 - // will only create one of them. It allocates CMediaSamples that only
 - // reference the buffer location that is set in the pin's renderer's
 - // data variable
 - //----------------------------------------------------------------------------
 - class CSampleGrabberAllocator : public CMemAllocator
 - {
 - friend class CSampleGrabberInPin;
 - friend class CSampleGrabber;
 - protected:
 - // our pin who created us
 - //
 - CSampleGrabberInPin * m_pPin;
 - public:
 - CSampleGrabberAllocator( CSampleGrabberInPin * pParent, HRESULT *phr )
 - : CMemAllocator( TEXT("SampleGrabberAllocator/0"), NULL, phr )
 - , m_pPin( pParent )
 - {
 - };
 - ~CSampleGrabberAllocator( )
 - {
 - // wipe out m_pBuffer before we try to delete it. It's not an allocated
 - // buffer, and the default destructor will try to free it!
 - m_pBuffer = NULL;
 - }
 - HRESULT Alloc( );
 - void ReallyFree();
 - // Override this to reject anything that does not match the actual buffer
 - // that was created by the application
 - STDMETHODIMP SetProperties(ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual);
 - };
 - //----------------------------------------------------------------------------
 - // we override the input pin class so we can provide a media type
 - // to speed up connection times. When you try to connect a filesourceasync
 - // to a transform filter, DirectShow will insert a splitter and then
 - // start trying codecs, both audio and video, video codecs first. If
 - // your sample grabber's set to connect to audio, unless we do this, it
 - // will try all the video codecs first. Connection times are sped up x10
 - // for audio with just this minor modification!
 - //----------------------------------------------------------------------------
 - class CSampleGrabberInPin : public CTransInPlaceInputPin
 - {
 - friend class CSampleGrabberAllocator;
 - friend class CSampleGrabber;
 - CSampleGrabberAllocator * m_pPrivateAllocator;
 - ALLOCATOR_PROPERTIES m_allocprops;
 - BYTE * m_pBuffer;
 - BOOL m_bMediaTypeChanged;
 - protected:
 - CSampleGrabber * SampleGrabber( ) { return (CSampleGrabber*) m_pFilter; }
 - HRESULT SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer );
 - public:
 - CMediaType mt;
 - CSampleGrabberInPin( CTransInPlaceFilter * pFilter, HRESULT * pHr )
 - : CTransInPlaceInputPin( TEXT("SampleGrabberInputPin/0"), pFilter, pHr, L"Input/0" )
 - , m_pPrivateAllocator( NULL )
 - , m_pBuffer( NULL )
 - , m_bMediaTypeChanged( FALSE )
 - {
 - memset( &m_allocprops, 0, sizeof( m_allocprops ) );
 - }
 - ~CSampleGrabberInPin( )
 - {
 - if( m_pPrivateAllocator ) delete m_pPrivateAllocator;
 - }
 - // override to provide major media type for fast connects
 - HRESULT GetMediaType( int iPosition, CMediaType *pMediaType );
 - // override this or GetMediaType is never called
 - STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
 - // override this to refuse any allocators besides
 - // the one the user wants, if this is set
 - STDMETHODIMP NotifyAllocator( IMemAllocator *pAllocator, BOOL bReadOnly );
 - // override this so we always return the special allocator, if necessary
 - STDMETHODIMP GetAllocator( IMemAllocator **ppAllocator );
 - HRESULT SetMediaType( const CMediaType *pmt );
 - // we override this to tell whoever's upstream of us what kind of
 - // properties we're going to demand to have
 - //
 - STDMETHODIMP GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps );
 - };
 - //----------------------------------------------------------------------------
 - //
 - //----------------------------------------------------------------------------
 - class CSampleGrabber : public CTransInPlaceFilter,
 - public IGrabberSample
 - {
 - friend class CSampleGrabberInPin;
 - friend class CSampleGrabberAllocator;
 - protected:
 - CMediaType m_mtAccept;
 - BOOL m_bModifiesData;
 - SAMPLECALLBACK m_callback;
 - CCritSec m_Lock; // serialize access to our data
 - BOOL IsReadOnly( ) { return !m_bModifiesData; }
 - // PURE, override this to ensure we get
 - // connected with the right media type
 - HRESULT CheckInputType( const CMediaType * pmt );
 - // PURE, override this to callback
 - // the user when a sample is received
 - HRESULT Transform( IMediaSample * pms );
 - // override this so we can return S_FALSE directly.
 - // The base class CTransInPlace
 - // Transform( ) method is called by it's
 - // Receive( ) method. There is no way
 - // to get Transform( ) to return an S_FALSE value
 - // (which means "stop giving me data"),
 - // to Receive( ) and get Receive( ) to return S_FALSE as well.
 - HRESULT Receive( IMediaSample * pms );
 - public:
 - static CUnknown *WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);
 - // Expose ISampleGrabber
 - STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
 - DECLARE_IUNKNOWN;
 - CSampleGrabber( IUnknown * pOuter, HRESULT * pHr, BOOL ModifiesData );
 - // IGrabberSample
 - STDMETHODIMP SetAcceptedMediaType( const CMediaType * pmt );
 - STDMETHODIMP GetConnectedMediaType( CMediaType * pmt );
 - STDMETHODIMP SetCallback( SAMPLECALLBACK Callback );
 - STDMETHODIMP SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer );
 - };
 
另外还可以自己编译baseclasses里的工程生成mobile下的strmbasd.lib 和 strmbase.lib,当然,windows mobile6是有自己的strmbase.lib的,只有strmbasd.lib没有而已,不过你可以通过AKU目录下的baseclasses来编译生成wm下的baseclasses工程,这样便于调试. 其中strmbasd.lib和strmbase.lib分别用于Debug和Release下的。