windows mobile做一个摄象头预览程序

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):

view plain copy to clipboard print ?
  1. #include    
  2. #include    
  3. #include "streams.h"   
  4. #include    
  5. #include    
  6. #include    
  7. #include    
  8. #include "ddcam.h"   
  9. #include "grabber.h"   
  10. #include    
  11.   
  12.   
  13. #define MAX_LOADSTRING 100   
  14. #define WM_GRAPHNOTIFY  WM_APP + 1   
  15. #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }   
  16.   
  17.   
  18. #define CHK( x ) do{ if( FAILED( hr = ( x ))) { goto Cleanup; }} while( FALSE );   
  19. #define ERR( x ) do{ hr = x; goto Cleanup; } while( FALSE );   
  20.   
  21. #define ARRAYSIZE(s) (sizeof(s) / sizeof(s[0]))   
  22.   
  23.   
  24. struct _capstuff  
  25. {  
  26.     TCHAR szCaptureFile[_MAX_PATH];  
  27.     WORD wCapFileSize;    
  28.     ICaptureGraphBuilder2 *pBuilder;  
  29.     IVideoWindow *pVWS, *pVWP;    
  30.     IMediaEventEx *pME;  
  31.     IAMDroppedFrames *pDF;  
  32.     IAMVideoCompression *pVC;  
  33.     IAMVideoControl *pAMVidControl;  
  34.     IAMCameraControl *pCamControl;  
  35.     IAMVideoProcAmp  *pVProcAmp;  
  36.     IAMStreamConfig  *pConfigP; //Preview config   
  37.     IAMStreamConfig *pVSC;      // for video cap   
  38.     IBaseFilter *pRenderS;      //Still render   
  39.     IBaseFilter *pRenderP;      //Preview render   
  40.     IBaseFilter *pCap;  
  41.     IGraphBuilder *pGraph;  
  42.     CSampleGrabber *pGrab;  
  43.     IFileSinkFilter *pSink;      
  44.     BOOL fStillGraphBuilt;  
  45.     BOOL fPreviewGraphBuilt;  
  46.     BOOL fStillCapturing;  
  47.     BOOL fPreviewing;  
  48.   
  49. } gcap;  
  50.   
  51. // Global Variables:   
  52. HINSTANCE           g_hInstance = NULL;         // The current instance   
  53. HWND                g_hWnd;         //The window instance   
  54. HWND                g_hWndMenu;             //Menu handle   
  55. HWND                hWndMenuStill = NULL;  
  56.   
  57.   
  58. // Forward declarations of functions included in this code module:   
  59. ATOM                MyRegisterClass (HINSTANCELPTSTR);  
  60. BOOL                InitInstance    (HINSTANCEint);  
  61. LRESULT CALLBACK    WndProc         (HWNDUINTWPARAMLPARAM);  
  62. LRESULT CALLBACK    About           (HWNDUINTWPARAMLPARAM);  
  63. HRESULT SetCapMode(IBaseFilter *pCap);  
  64. HRESULT OpenCamera(LPCOLESTR lpFile,BOOL bCapture,BOOL bStill,BOOL bPreview);  
  65. BOOL WriteBMPToDisk(unsigned char *pStillImageBuffer,long size);  
  66. void UpdatePictureNumber();  
  67. BOOL WriteBMPToTXT(unsigned char *pStillImageBuffer,long lBufferSize);  
  68. HRESULT ActivatePreviousInstance(const TCHAR* pszClass,const TCHAR* pszTitle,BOOL* pfActivated);  
  69.   
  70. int g_PicNumber=0;  
  71.   
  72. HRESULT Callback( IMediaSample * pSample, REFERENCE_TIME * StartTime, REFERENCE_TIME *   
  73.                  StopTime,BOOL TypeChanged )  
  74. {  
  75.     unsigned char *pbuf;  
  76.     HRESULT  hr = S_OK;  
  77.     // NOTE: We cannot do anything with this sample until we call GetConnectedMediaType    
  78.     // on the filter to find out what format these samples are.    
  79.     RETAILMSG(1, (TEXT("Callback with sample %lx for time %ld"), pSample, long( *StartTime / 10000 )  ) );  
  80.     hr = pSample->GetPointer(&pbuf);  
  81.     LONG lSize = pSample->GetActualDataLength();  
  82.     BOOL bReturn = WriteBMPToDisk(pbuf,lSize);  
  83.     WriteBMPToTXT(pbuf,lSize);  
  84.     if(bReturn == FALSE)  
  85.     {  
  86.         return S_FALSE;  
  87.     }  
  88.     return hr ;  
  89. }  
  90.   
  91.   
  92. BOOL StartPreview()  
  93. {  
  94.     HRESULT hr;  
  95.     IMediaControl *pMC = NULL;  
  96.     hr = gcap.pGraph->QueryInterface(IID_IMediaControl, (void **)&pMC);  
  97.     if(SUCCEEDED(hr))  
  98.     {  
  99.         hr = pMC->Run();  
  100.         if(FAILED(hr))  
  101.         {  
  102.             // stop parts that ran   
  103.             pMC->Stop();  
  104.         }  
  105.         pMC->Release();  
  106.     }  
  107.     if(FAILED(hr))  
  108.     {  
  109.         return FALSE;  
  110.     }  
  111.   
  112.     return TRUE;  
  113. }  
  114.   
  115.   
  116. // stop the preview graph   
  117. //   
  118. BOOL StopPreview()  
  119. {  
  120.     // way ahead of you   
  121.     if(!gcap.fPreviewing)  
  122.     {  
  123.         return FALSE;  
  124.     }  
  125.     // stop the graph   
  126.     IMediaControl *pMC = NULL;  
  127.     HRESULT hr = gcap.pGraph->QueryInterface(IID_IMediaControl, (void **)&pMC);  
  128.     if(SUCCEEDED(hr))  
  129.     {  
  130.         hr = pMC->Stop();  
  131.         pMC->Release();  
  132.     }  
  133.     if(FAILED(hr))  
  134.     {        
  135.         return FALSE;  
  136.     }  
  137.     gcap.fPreviewing = FALSE;  
  138.     return TRUE;  
  139. }  
  140.   
  141.   
  142.   
  143. BOOL CloseCamera()  
  144. {  
  145.     SAFE_RELEASE(gcap.pCap);      
  146.     SAFE_RELEASE(gcap.pConfigP);  
  147.     SAFE_RELEASE(gcap.pVWS);  
  148.     SAFE_RELEASE(gcap.pVWP);  
  149.     SAFE_RELEASE(gcap.pGraph);  
  150.     SAFE_RELEASE(gcap.pBuilder);   
  151.   
  152.     return TRUE;  
  153. }  
  154.   
  155.   
  156. HRESULT CaptureStillImage()  
  157. {  
  158.     HRESULT hr;  
  159.     hr = SetCapMode(gcap.pCap); //Run still pin        
  160.     return hr;  
  161. }  
  162.   
  163.   
  164. HRESULT InitCapFilter()  
  165. {  
  166.     HRESULT hr = S_OK;  
  167.     GUID clsid = DEVCLASS_CAMERA_GUID;  
  168.     IPersistPropertyBag *pPropertyBag = NULL;  
  169.     // Create Capture Filter   
  170.     CHK( hr = CoCreateInstance(CLSID_VideoCapture, NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter,  
  171.         (void **)&gcap.pCap) );  
  172.   
  173.   
  174.   
  175.     DEVMGR_DEVICE_INFORMATION pdi;  
  176.     HANDLE hand = FindFirstDevice(DeviceSearchByGuid,&clsid,&pdi);  
  177.     RETAILMSG(1, (TEXT("CamTest: Find device: %x %x/r/n"),hand,pdi.szDeviceName));  
  178.   
  179.     CHK( hr = gcap.pCap->QueryInterface(IID_IPersistPropertyBag, (void **)&pPropertyBag) );  
  180.     if (!SUCCEEDED(hr))  
  181.     {  
  182.         return hr;  
  183.     }  
  184.     VARIANT varCamName;       
  185.     IPropertyBag *propBag = NULL;  
  186.     varCamName.byref =  L"CAM1:" ;    
  187.     CHK( hr = pPropertyBag->Load(propBag,NULL) );  
  188.     SAFE_RELEASE(pPropertyBag);   
  189.   
  190. Cleanup:  
  191.     if(FAILED(hr))  
  192.     {  
  193.         OutputDebugString(L"Initial Error!");  
  194.         SendMessage(g_hWnd,WM_CLOSE,0,0);  
  195.     }  
  196.     return hr;  
  197. }  
  198.   
  199. HRESULT SetupVideoWindow(IVideoWindow *pVW)  
  200. {  
  201.       
  202.     HRESULT hr = S_OK;  
  203.     if (pVW)  
  204.     {  
  205.         CHK( hr = pVW->SetWindowPosition(0,0,240,268) );   
  206.         CHK( hr = pVW->put_Owner((OAHWND)g_hWnd) );  
  207.         CHK( hr = pVW->put_WindowStyle(WS_CHILD) );   
  208.     }  
  209. Cleanup:  
  210.     if(FAILED(hr))  
  211.     {  
  212.         OutputDebugString(L"Setup window Error!");  
  213.     }  
  214.     return hr;  
  215. }  
  216.   
  217.   
  218. HRESULT ConnectFilters(IGraphBuilder *pGraph,IBaseFilter *pF1, int iPin1,IBaseFilter *pF2,int iPin2,IPin **ppPinout)  
  219. {  
  220.     IPin *pPin1, *pPin2;  
  221.     IEnumPins    *pEnum;      
  222.     unsigned long fetched;  
  223.     HRESULT hr = S_OK;  
  224.   
  225.     hr = pF1->EnumPins(&pEnum);  
  226.     while (iPin1>0)  
  227.     {     
  228.         hr = pEnum->Next(1,&pPin1,&fetched); //Skip Capture  pin   
  229.         iPin1--;  
  230.     }  
  231.     hr = pEnum->Next(1,&pPin1,&fetched);  
  232.   
  233.     hr = pF2->EnumPins(&pEnum);  
  234.     while (iPin2>0)  
  235.     {     
  236.         hr = pEnum->Next(1,&pPin2,&fetched); //Skip Capture  pin   
  237.         iPin2--;  
  238.     }  
  239.     hr = pEnum->Next(1,&pPin2,&fetched);  
  240.   
  241.     hr = pGraph->Connect(pPin1,pPin2);  
  242.     if (ppPinout)  
  243.     {  
  244.         *ppPinout = pPin1;  
  245.     }  
  246.     if (!SUCCEEDED(hr))  
  247.         RETAILMSG(1, (TEXT("CamTest: Fail to Connect Pin! %x/r/n"),hr));  
  248.   
  249.     return hr;  
  250. }  
  251.   
  252.   
  253. HRESULT BuildGraph()  
  254. {  
  255.     HRESULT hr;  
  256.     gcap.pGrab = new CSampleGrabber(NULL,&hr,FALSE);      
  257.     gcap.pGrab->AddRef();  
  258.     gcap.pGrab->SetCallback(&Callback);  
  259.     CMediaType mt;  
  260.     mt.SetType(&MEDIATYPE_Video);  
  261.     mt.SetSubtype(&MEDIASUBTYPE_RGB24);  
  262.     gcap.pGrab->SetAcceptedMediaType(&mt);  
  263.   
  264.     // Create the Filter Graph Manager.   
  265.     hr =  CoCreateInstance(CLSID_FilterGraph, NULL,  
  266.         CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&gcap.pGraph);  
  267.   
  268.     // Create the Capture Graph Builder.   
  269.     hr = CoCreateInstance(CLSID_CaptureGraphBuilder, NULL,  
  270.         CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,   
  271.         (void **)&gcap.pBuilder);  
  272.   
  273.     hr = gcap.pGraph->AddFilter(gcap.pCap,L"Video Capture Source");    
  274.     hr = gcap.pGraph->AddFilter(gcap.pGrab,L"SampleGrabber");      
  275.   
  276.     gcap.pBuilder->SetFiltergraph(gcap.pGraph);  
  277.   
  278.     hr = CoCreateInstance(CLSID_VideoRenderer, NULL,  
  279.         CLSCTX_INPROC_SERVER, IID_IBaseFilter,   
  280.         (void **)&gcap.pRenderP);  
  281.   
  282.     hr = CoCreateInstance(CLSID_VideoRenderer, NULL,  
  283.         CLSCTX_INPROC_SERVER, IID_IBaseFilter,   
  284.         (void **)&gcap.pRenderS);  
  285.   
  286.     hr = gcap.pGraph->AddFilter(gcap.pRenderP,L"Video Render");  
  287.     hr = gcap.pGraph->AddFilter(gcap.pRenderS,L"Video Render");  
  288.   
  289.     hr = gcap.pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video, gcap.pCap, NULL, gcap.pRenderP);              
  290.     hr = gcap.pRenderP->QueryInterface(IID_IVideoWindow, (void**)&gcap.pVWP);  
  291.         hr = gcap.pBuilder->RenderStream(&PIN_CATEGORY_STILL,&MEDIATYPE_Video, gcap.pCap, gcap.pGrab, gcap.pRenderS);              
  292.   
  293.     // Query for video interfaces, which may not be relevant for audio files   
  294.     //hr = gcap.pGraph->QueryInterface(IID_IMediaEventEx, (void **)&gcap.pME);           
  295.       
  296.     //hr = gcap.pCap->QueryInterface(IID_IAMVideoProcAmp,(void **)&gcap.pVProcAmp);   
  297.     //// Query the output pin for IAMStreamConfig (not shown).   
  298.     //hr = gcap.pBuilder->FindInterface(   
  299.     //  &PIN_CATEGORY_PREVIEW, // Preview pin.   
  300.     //  0,    // Any media type.   
  301.     //  gcap.pCap, // Pointer to the capture filter.   
  302.     //  IID_IAMStreamConfig, (void**)&gcap.pConfigP);      
  303.   
  304.     // Have the graph signal event via window callbacks for performance   
  305.     SetupVideoWindow(gcap.pVWP);  
  306.     gcap.pVWP->put_MessageDrain((OAHWND)g_hWnd);  
  307.     gcap.pVWP->put_Owner((OAHWND)g_hWnd);      
  308.     //hr = gcap.pME->SetNotifyWindow((OAHWND)g_hWnd, WM_GRAPHNOTIFY, 0);       
  309.     return hr;  
  310. }  
  311.   
  312.   
  313. HRESULT SetCapMode(IBaseFilter *pCap)  
  314. {  
  315.     HRESULT hr;  
  316.     IPin *pPin = NULL;  
  317.       
  318.     hr = gcap.pCap->FindPin(L"Still",&pPin);  
  319.     if (SUCCEEDED(hr))  
  320.     {       
  321.         hr = gcap.pCap->QueryInterface(IID_IAMVideoControl,(void **)&gcap.pAMVidControl);  
  322.         hr = gcap.pAMVidControl->SetMode(pPin, VideoControlFlag_Trigger);  
  323.         MessageBox(NULL,L"拍照成功,生成的图片保存在根目录下",L"成功",64);  
  324.         pPin->Release();  
  325.     }  
  326.     else  
  327.     {  
  328.         RETAILMSG(1, (TEXT("CamTest: Fail to Find Pin! %x/r/n"),hr));  
  329.     }  
  330.     return hr;  
  331. }  
  332.   
  333. int WINAPI WinMain( HINSTANCE hInstance,  
  334.                    HINSTANCE hPrevInstance,  
  335.                    LPTSTR    lpCmdLine,  
  336.                    int       nCmdShow)  
  337. {  
  338.     MSG msg;  
  339.     HACCEL hAccelTable;  
  340.   
  341.     //Init COM   
  342.     // Get COM interfaces   
  343.   
  344.     if(FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))  
  345.     {  
  346.         RETAILMSG(1, (TEXT("CoInitialize Failed!/r/n")));  
  347.         return FALSE;  
  348.     }  
  349.   
  350.     // Perform application initialization:   
  351.     if (!InitInstance (hInstance, nCmdShow))   
  352.     {  
  353.         return FALSE;  
  354.     }  
  355.   
  356.     hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WCETEST);  
  357.   
  358.     // Main message loop:   
  359.     while (GetMessage(&msg, NULL, 0, 0))   
  360.     {  
  361.         if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))   
  362.         {  
  363.             TranslateMessage(&msg);  
  364.             DispatchMessage(&msg);  
  365.         }  
  366.     }  
  367.   
  368.     // Finished with COM   
  369.     CoUninitialize();  
  370.   
  371.     return msg.wParam;  
  372. }  
  373.   
  374.   
  375. //   
  376. //  FUNCTION: InitInstance(HANDLE, int)   
  377. //   
  378. //  PURPOSE: Saves instance handle and creates main window   
  379. //   
  380. //  COMMENTS:   
  381. //   
  382. //    In this function, we save the instance handle in a global variable and   
  383. //    create and display the main program window.   
  384. //   
  385. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)  
  386. {  
  387.     HRESULT hr;  
  388.     BOOL fActivated;  
  389.     TCHAR   szTitle[MAX_LOADSTRING];            // The title bar text   
  390.     TCHAR   szWindowClass[MAX_LOADSTRING];      // The window class name   
  391.   
  392.     g_hInstance = hInstance;        // Store instance handle in our global variable   
  393.     // Initialize global strings   
  394.     LoadString(hInstance, IDC_WCETEST, szWindowClass, MAX_LOADSTRING);  
  395.     WNDCLASS    wc;  
  396.   
  397.     wc.style            = CS_HREDRAW | CS_VREDRAW;  
  398.     wc.lpfnWndProc      = (WNDPROC) WndProc;  
  399.     wc.cbClsExtra       = 0;  
  400.     wc.cbWndExtra       = 0;  
  401.     wc.hInstance        = hInstance;  
  402.     wc.hIcon            = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WCETEST));  
  403.     wc.hCursor          = 0;  
  404.     wc.hbrBackground    = (HBRUSH) GetStockObject(WHITE_BRUSH);  
  405.     wc.lpszMenuName     = 0;  
  406.     wc.lpszClassName    = szWindowClass;  
  407.   
  408.     RegisterClass(&wc);  
  409.   
  410.     LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);  
  411.   
  412.     if(FAILED(ActivatePreviousInstance(szWindowClass, szTitle, &fActivated)) ||  
  413.         fActivated)  
  414.     {  
  415.         return(0);  
  416.     }  
  417.   
  418.     g_hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,  
  419.         CW_USEDEFAULT, CW_USEDEFAULT, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL);  
  420.   
  421.     if (!g_hWnd)  
  422.     {     
  423.         return FALSE;  
  424.     }  
  425.   
  426.     ShowWindow(g_hWnd, nCmdShow);  
  427.     UpdateWindow(g_hWnd);  
  428.   
  429.     hr = InitCapFilter();  
  430.     if (SUCCEEDED(hr))  
  431.     {     
  432.         BuildGraph();  
  433.         StartPreview();  
  434.               
  435.     }  
  436.     else  
  437.     {  
  438.         RETAILMSG(1,(TEXT("CamTest: Fail to create Capture filter. /r/n")));    
  439.     }  
  440.   
  441.     return TRUE;  
  442. }  
  443.   
  444.   
  445. /************************************************************************************** 
  446.  
  447. OnCreate 
  448.  
  449. **************************************************************************************/  
  450. LRESULT OnCreate(  
  451.                  HWND hwnd,  
  452.                  CREATESTRUCT* lParam  
  453.                  )  
  454. {  
  455.     // create the menu bar   
  456.     SHMENUBARINFO mbi;  
  457.     ZeroMemory(&mbi, sizeof(SHMENUBARINFO));  
  458.     mbi.cbSize = sizeof(SHMENUBARINFO);  
  459.     mbi.hwndParent = hwnd;  
  460.     mbi.nToolBarId = IDM_MENU;  
  461.     mbi.hInstRes = g_hInstance;  
  462.     mbi.dwFlags = SHCMBF_HMENU;  
  463.     if(!SHCreateMenuBar(&mbi))  
  464.     {  
  465.         // Couldn't create the menu bar.  Fail creation of the window.   
  466.         return(-1);  
  467.     }  
  468.     return(0); // continue creation of the window   
  469. }  
  470.   
  471.   
  472. //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)   
  473. //   
  474. //  PURPOSE:  Processes messages for the main window.   
  475. //   
  476. //  WM_COMMAND  - process the application menu   
  477. //  WM_PAINT    - Paint the main window   
  478. //  WM_DESTROY  - post a quit message and return   
  479. //   
  480. //   
  481. /************************************************************************************** 
  482.  
  483. WndProc 
  484.  
  485. **************************************************************************************/  
  486. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
  487. {  
  488.     LRESULT lResult = TRUE;  
  489.     switch(message)  
  490.     {  
  491.     case WM_CLOSE:  
  492.         StopPreview();        
  493.         CloseCamera();  
  494.         DestroyWindow(hWnd);  
  495.         break;  
  496.   
  497.     case WM_CREATE:  
  498.         lResult = OnCreate(hWnd, (CREATESTRUCT*)lParam);  
  499.         break;  
  500.   
  501.     case WM_COMMAND:  
  502.         switch (wParam)  
  503.         {  
  504.         case ID_CAPTURE:                         
  505.             CaptureStillImage();                      
  506.             break;  
  507.         }  
  508.         break;  
  509.   
  510.     case WM_DESTROY:  
  511.         PostQuitMessage(0);  
  512.         break;  
  513.   
  514.     default:  
  515.         lResult = DefWindowProc(hWnd, message, wParam, lParam);  
  516.         break;  
  517.     }  
  518.   
  519.     return(lResult);  
  520. }  
  521.   
  522.   
  523. BOOL WriteBMPToTXT(unsigned char *pStillImageBuffer,long lBufferSize)  
  524. {  
  525.     TCHAR x[256];  
  526.     const TCHAR *picture_path = TEXT("//My Documents//My Pictures") ;  
  527.     UpdatePictureNumber();  
  528.     wsprintf(x, TEXT("%s//%d.txt"), picture_path, g_PicNumber++);  
  529.     HANDLE hf = CreateFile(x,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,NULL,NULL);  
  530.     if(hf == INVALID_HANDLE_VALUE)  
  531.         return FALSE;  
  532.     DWORD dwWritten=0;  
  533.     if( !WriteFile(hf,pStillImageBuffer,lBufferSize,&dwWritten,NULL) )  
  534.     {  
  535.         return FALSE;  
  536.     }  
  537.     CloseHandle(hf);  
  538.     return TRUE;  
  539.   
  540. }  
  541.   
  542. BOOL WriteBMPToDisk(unsigned char *pStillImageBuffer,long lBufferSize)//保存为24位的图片   
  543. {  
  544.     TCHAR x[256];  
  545.     UpdatePictureNumber();  
  546.     wsprintf(x, TEXT("%d.bmp"), g_PicNumber++);  
  547.     HANDLE hf = CreateFile(x,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,NULL,NULL);  
  548.     if(hf == INVALID_HANDLE_VALUE)  
  549.         return FALSE;  
  550.     BITMAPFILEHEADER bfh;  
  551.     memset(&bfh,0,sizeof(bfh));  
  552.     bfh.bfType=0x4D42/*((WORD) ('M' << 8) | 'B')*/;  
  553.     bfh.bfSize=sizeof(bfh)+lBufferSize+sizeof(BITMAPFILEHEADER);  
  554.     bfh.bfOffBits=sizeof(BITMAPINFOHEADER)+sizeof(BITMAPFILEHEADER);  
  555.     DWORD dwWritten=0;  
  556.     WriteFile(hf,&bfh,sizeof(bfh),&dwWritten,NULL);  
  557.     BITMAPINFOHEADER bih;  
  558.     memset(&bih,0,sizeof(bih));  
  559.     bih.biSize=sizeof(bih);  
  560.     bih.biWidth=144;  
  561.     bih.biHeight=176;  
  562.     bih.biPlanes=1;  
  563.     bih.biBitCount=24;  
  564.     if( !WriteFile(hf,&bih,sizeof(bih),&dwWritten,NULL) )  
  565.     {  
  566.         return FALSE;  
  567.     }  
  568.     if( !WriteFile(hf,pStillImageBuffer,lBufferSize,&dwWritten,NULL) )  
  569.     {  
  570.         return FALSE;  
  571.     }  
  572.     CloseHandle(hf);  
  573.     return TRUE;  
  574.   
  575. }  
  576. //   
  577. //// Look for cam.cfg   
  578. //// If it doesn't exist, create it, and set picture number to 1.   
  579. //// If it exists, read the value stored inside, increment the number, and write it back.   
  580. void UpdatePictureNumber()  
  581. {  
  582.     DWORD dwSize;  
  583.     HANDLE hFile;  
  584.     char *buffer;  
  585.     buffer = (char *)malloc(1024);  
  586.     hFile = CreateFile(TEXT("//temp//cam.cfg"), GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);  
  587.     dwSize = 0;  
  588.   
  589.     if (hFile == INVALID_HANDLE_VALUE)  
  590.     {  
  591.         // File did not exist, so we are going to create it, and initialize the counter.   
  592.         g_PicNumber = 1;  
  593.         hFile = CreateFile(TEXT("//temp//cam.cfg"), GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
  594.         buffer[0] = g_PicNumber & 0x00FF;  
  595.         buffer[1] = (g_PicNumber & 0xFF00) >> 8;  
  596.   
  597.         WriteFile(hFile, buffer, 2, &dwSize, NULL);  
  598.         CloseHandle(hFile);  
  599.     } else  
  600.     {  
  601.         dwSize = 0;  
  602.         ReadFile(hFile, buffer, 2, &dwSize, NULL);  
  603.         g_PicNumber = buffer[1];  
  604.         g_PicNumber <<= 8;  
  605.         g_PicNumber |= buffer[0];  
  606.         g_PicNumber++;  
  607.         CloseHandle(hFile);  
  608.         hFile = CreateFile(TEXT("//temp//cam.cfg"), GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);  
  609.         buffer[0] = g_PicNumber & 0x00FF;  
  610.         buffer[1] = (g_PicNumber & 0xFF00) >> 8;  
  611.         dwSize = 0;  
  612.         WriteFile(hFile, buffer, 2, &dwSize, NULL);  
  613.         CloseHandle(hFile);  
  614.     }  
  615.   
  616.     free(buffer);  
  617.   
  618.   
  619.   
  620.   
  621. }  
  622.   
  623.   
  624. /**************************************************************************** 
  625.  
  626. ActivatePreviousInstance 
  627.  
  628. ****************************************************************************/  
  629. HRESULT ActivatePreviousInstance(  
  630.                                  const TCHAR* pszClass,  
  631.                                  const TCHAR* pszTitle,  
  632.                                  BOOL* pfActivated  
  633.                                  )  
  634. {  
  635.     HRESULT hr = S_OK;  
  636.     int cTries;  
  637.     HANDLE hMutex = NULL;  
  638.   
  639.     *pfActivated = FALSE;  
  640.     cTries = 5;  
  641.     while(cTries > 0)  
  642.     {  
  643.         hMutex = CreateMutex(NULL, FALSE, pszClass); // NOTE: We don't want to own the object.   
  644.         if(NULL == hMutex)  
  645.         {  
  646.             // Something bad happened, fail.   
  647.             hr = E_FAIL;  
  648.             goto Exit;  
  649.         }  
  650.   
  651.         if(GetLastError() == ERROR_ALREADY_EXISTS)  
  652.         {  
  653.             HWND hwnd;  
  654.   
  655.             CloseHandle(hMutex);  
  656.             hMutex = NULL;  
  657.   
  658.             // There is already an instance of this app   
  659.             // running.  Try to bring it to the foreground.   
  660.   
  661.             hwnd = FindWindow(pszClass, pszTitle);  
  662.             if(NULL == hwnd)  
  663.             {  
  664.                 // It's possible that the other window is in the process of being created...   
  665.                 Sleep(500);  
  666.                 hwnd = FindWindow(pszClass, pszTitle);  
  667.             }  
  668.   
  669.             if(NULL != hwnd)   
  670.             {  
  671.                 // Set the previous instance as the foreground window   
  672.   
  673.                 // The "| 0x01" in the code below activates   
  674.                 // the correct owned window of the   
  675.                 // previous instance's main window.   
  676.                 SetForegroundWindow((HWND) (((ULONG) hwnd) | 0x01));  
  677.   
  678.                 // We are done.   
  679.                 *pfActivated = TRUE;  
  680.                 break;  
  681.             }  
  682.   
  683.             // It's possible that the instance we found isn't coming up,   
  684.             // but rather is going down.  Try again.   
  685.             cTries--;  
  686.         }  
  687.         else  
  688.         {  
  689.             // We were the first one to create the mutex   
  690.             // so that makes us the main instance.  'leak'   
  691.             // the mutex in this function so it gets cleaned   
  692.             // up by the OS when this instance exits.   
  693.             break;  
  694.         }  
  695.     }  
  696.   
  697.     if(cTries <= 0)  
  698.     {  
  699.         // Someone else owns the mutex but we cannot find   
  700.         // their main window to activate.   
  701.         hr = E_FAIL;  
  702.         goto Exit;  
  703.     }  
  704.   
  705. Exit:  
  706.     return(hr);  
  707. }  
  708.   
  709.   
  710. void setscreenMetrics(HWND hWnd,int width,int height)  
  711. {  
  712.   
  713.     DEVMODE lpDevMode;  
  714.     lpDevMode.dmBitsPerPel=24;  
  715.     lpDevMode.dmPelsWidth=width;  
  716.     lpDevMode.dmPelsHeight=height;  
  717.     lpDevMode.dmSize=sizeof(lpDevMode);  
  718.     lpDevMode.dmFields=DM_PELSWIDTH|DM_PELSHEIGHT;  
  719.     LONG result;  
  720.     result=ChangeDisplaySettingsEx(NULL,&lpDevMode,hWnd,0,NULL);  
  721.     if(result==DISP_CHANGE_SUCCESSFUL)  
  722.     {  
  723.         MessageBoxW(hWnd,_T("success!"),_T("alert"),MB_OK);  
  724.     }  
  725.     else  
  726.     {  
  727.         MessageBoxW(hWnd,_T("failure!"),_T("alert"),MB_OK);  
  728.   
  729.     }  
  730.   
  731.   
  732. }  

#include #include #include "streams.h" #include #include #include #include #include "ddcam.h" #include "grabber.h" #include #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):

view plain copy to clipboard print ?
  1. //------------------------------------------------------------------------------   
  2. // File: Grabber.cpp   
  3. //   
  4. // Desc: DirectShow sample code - Implementation file for the SampleGrabber   
  5. //       example filter   
  6. //   
  7. // Copyright (c) Microsoft Corporation.  All rights reserved.   
  8. //------------------------------------------------------------------------------   
  9.   
  10. #include      // Active Movie (includes windows.h)   
  11. #include     // declares DEFINE_GUID to declare an EXTERN_C const.   
  12. #include "grabber.h"   
  13.   
  14. //#pragma warning(disable: 4800)   
  15.   
  16.   
  17.   
  18. const AMOVIESETUP_PIN psudSampleGrabberPins[] =  
  19. { { L"Input"            // strName   
  20.   , FALSE               // bRendered   
  21.   , FALSE               // bOutput   
  22.   , FALSE               // bZero   
  23.   , FALSE               // bMany   
  24.   , &CLSID_NULL         // clsConnectsToFilter   
  25.   , L""                 // strConnectsToPin   
  26.   , 0                   // nTypes   
  27.   , NULL                // lpTypes   
  28.   }  
  29. , { L"Output"           // strName   
  30.   , FALSE               // bRendered   
  31.   , TRUE                // bOutput   
  32.   , FALSE               // bZero   
  33.   , FALSE               // bMany   
  34.   , &CLSID_NULL         // clsConnectsToFilter   
  35.   , L""                 // strConnectsToPin   
  36.   , 0                   // nTypes   
  37.   , NULL                // lpTypes   
  38.   }  
  39. };  
  40.   
  41. const AMOVIESETUP_FILTER sudSampleGrabber =  
  42. { &CLSID_GrabberSample            // clsID   
  43. , L"SampleGrabber Example"        // strName   
  44. , MERIT_DO_NOT_USE                // dwMerit   
  45. , 2                               // nPins   
  46. , psudSampleGrabberPins };        // lpPin   
  47.   
  48.   
  49. // Needed for the CreateInstance mechanism   
  50. CFactoryTemplate g_Templates[]=  
  51. {  
  52.     { L"Sample Grabber Example"  
  53.         , &CLSID_GrabberSample  
  54.         , CSampleGrabber::CreateInstance  
  55.         , NULL  
  56.         , &sudSampleGrabber }  
  57.   
  58. };  
  59.   
  60. int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]);  
  61.   
  62.   
  63. ////////////////////////////////////////////////////////////////////////   
  64. //   
  65. // Exported entry points for registration and unregistration    
  66. // (in this case they only call through to default implementations).   
  67. //   
  68. ////////////////////////////////////////////////////////////////////////   
  69.   
  70. STDAPI DllRegisterServer()   
  71. {  
  72.     return AMovieDllRegisterServer2(TRUE);  
  73. }  
  74.   
  75. STDAPI DllUnregisterServer()   
  76. {  
  77.     return AMovieDllRegisterServer2(FALSE);  
  78. }  
  79.   
  80. //   
  81. // DllMain   
  82. //   
  83. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCEULONGLPVOID);  
  84.   
  85. BOOL WINAPI DllMain(HANDLE hModule,   
  86.                     DWORD  dwReason,   
  87.                     LPVOID lpReserved)  
  88. {  
  89.     return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);  
  90. }  
  91.   
  92. //   
  93. // CreateInstance   
  94. //   
  95. // Provide the way for COM to create a CSampleGrabber object   
  96. //   
  97. CUnknown * WINAPI CSampleGrabber::CreateInstance(LPUNKNOWN punk, HRESULT *phr)   
  98. {  
  99.     ASSERT(phr);  
  100.       
  101.     // assuming we don't want to modify the data   
  102.     CSampleGrabber *pNewObject = new CSampleGrabber(punk, phr, FALSE);  
  103.   
  104.     if(pNewObject == NULL) {  
  105.         if (phr)  
  106.             *phr = E_OUTOFMEMORY;  
  107.     }  
  108.   
  109.     return pNewObject;     
  110.   
  111. // CreateInstance   
  112.   
  113.   
  114. //----------------------------------------------------------------------------   
  115. //   
  116. //----------------------------------------------------------------------------   
  117.   
  118. CSampleGrabber::CSampleGrabber( IUnknown * pOuter, HRESULT * phr, BOOL ModifiesData )  
  119.                 : CTransInPlaceFilter( TEXT("SampleGrabber"), (IUnknown*) pOuter,   
  120.                                        //CLSID_GrabberSample, phr, (BOOL)ModifiesData )   
  121.                                        CLSID_GrabberSample, phr)  
  122.                 , m_callback( NULL )  
  123. {  
  124.     // this is used to override the input pin with our own      
  125.     m_pInput = (CTransInPlaceInputPin*) new CSampleGrabberInPin( this, phr );  
  126.     if( !m_pInput )  
  127.     {  
  128.         if (phr)  
  129.             *phr = E_OUTOFMEMORY;  
  130.     }  
  131.       
  132.     // Ensure that the output pin gets created.  This is necessary because our   
  133.     // SetDeliveryBuffer() method assumes that the input/output pins are created, but   
  134.     // the output pin isn't created until GetPin() is called.  The    
  135.     // CTransInPlaceFilter::GetPin() method will create the output pin, since we   
  136.     // have not already created one.   
  137.     IPin *pOutput = GetPin(1);  
  138.     // The pointer is not AddRef'ed by GetPin(), so don't release it   
  139. }  
  140.   
  141.   
  142. STDMETHODIMP CSampleGrabber::NonDelegatingQueryInterface( REFIID riid, void ** ppv)   
  143. {  
  144.     CheckPointer(ppv,E_POINTER);  
  145.   
  146.     if(riid == IID_IGrabberSample) {                  
  147.         return GetInterface((IGrabberSample *) this, ppv);  
  148.     }  
  149.     else {  
  150.         return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv);  
  151.     }  
  152. }  
  153.   
  154.   
  155. //----------------------------------------------------------------------------   
  156. // This is where you force the sample grabber to connect with one type   
  157. // or the other. What you do here is crucial to what type of data your   
  158. // app will be dealing with in the sample grabber's callback. For instance,   
  159. // if you don't enforce right-side-up video in this call, you may not get   
  160. // right-side-up video in your callback. It all depends on what you do here.   
  161. //----------------------------------------------------------------------------   
  162.   
  163. HRESULT CSampleGrabber::CheckInputType( const CMediaType * pmt )  
  164. {  
  165.     CheckPointer(pmt,E_POINTER);  
  166.     CAutoLock lock( &m_Lock );  
  167.   
  168.     // if the major type is not set, then accept anything   
  169.   
  170.     GUID g = *m_mtAccept.Type( );  
  171.     if( g == GUID_NULL )  
  172.     {  
  173.         return NOERROR;  
  174.     }  
  175.   
  176.     // if the major type is set, don't accept anything else   
  177.   
  178.     if( g != *pmt->Type( ) )  
  179.     {  
  180.         return VFW_E_INVALID_MEDIA_TYPE;  
  181.     }  
  182.   
  183.     // subtypes must match, if set. if not set, accept anything   
  184.   
  185.     g = *m_mtAccept.Subtype( );  
  186.     if( g == GUID_NULL )  
  187.     {  
  188.         return NOERROR;  
  189.     }  
  190.     if( g != *pmt->Subtype( ) )  
  191.     {  
  192.         return VFW_E_INVALID_MEDIA_TYPE;  
  193.     }  
  194.   
  195.     // format types must match, if one is set   
  196.   
  197.     g = *m_mtAccept.FormatType( );  
  198.     if( g == GUID_NULL )  
  199.     {  
  200.         return NOERROR;  
  201.     }  
  202.     if( g != *pmt->FormatType( ) )  
  203.     {  
  204.         return VFW_E_INVALID_MEDIA_TYPE;  
  205.     }  
  206.   
  207.     // at this point, for this sample code, this is good enough,   
  208.     // but you may want to make it more strict   
  209.   
  210.     return NOERROR;  
  211. }  
  212.   
  213.   
  214. //----------------------------------------------------------------------------   
  215. // This bit is almost straight out of the base classes.   
  216. // We override this so we can handle Transform( )'s error   
  217. // result differently.   
  218. //----------------------------------------------------------------------------   
  219.   
  220. HRESULT CSampleGrabber::Receive( IMediaSample * pms )  
  221. {  
  222.     CheckPointer(pms,E_POINTER);  
  223.   
  224.     HRESULT hr;  
  225.     AM_SAMPLE2_PROPERTIES * const pProps = m_pInput->SampleProps();  
  226.   
  227.     RETAILMSG(1, (TEXT("Grabber: Receive! %x/r/n")));  
  228.     if (pProps->dwStreamId != AM_STREAM_MEDIA)   
  229.     {  
  230.         if( m_pOutput->IsConnected() )  
  231.             return m_pOutput->Deliver(pms);  
  232.         else  
  233.             return NOERROR;  
  234.     }  
  235.   
  236.   
  237. /*  if (UsingDifferentAllocators())  
  238.     { 
  239.         // We have to copy the data. 
  240.  
  241.         pms = Copy(pms); 
  242.  
  243.         if (pms == NULL)  
  244.         { 
  245.             return E_UNEXPECTED; 
  246.         } 
  247.     } 
  248. */  
  249.     // have the derived class transform the data   
  250.     hr = Transform(pms);  
  251.   
  252.     if (FAILED(hr))   
  253.     {  
  254. //       DbgLog((LOG_TRACE, 1, TEXT("Error from TransInPlace")));   
  255. /*      if (UsingDifferentAllocators())  
  256.         { 
  257.             pms->Release(); 
  258.         } 
  259. */  
  260.         return hr;  
  261.     }  
  262.   
  263.     if (hr == NOERROR)   
  264.     {  
  265.         hr = m_pOutput->Deliver(pms);  
  266.     }  
  267.       
  268.     // release the output buffer. If the connected pin still needs it,   
  269.     // it will have addrefed it itself.   
  270. /*  if (UsingDifferentAllocators())  
  271.     { 
  272.         pms->Release(); 
  273.     } 
  274. */  
  275.     return hr;  
  276. }  
  277.   
  278.   
  279. //----------------------------------------------------------------------------   
  280. // Transform   
  281. //----------------------------------------------------------------------------   
  282.   
  283. HRESULT CSampleGrabber::Transform ( IMediaSample * pms )  
  284. {  
  285.     CheckPointer(pms,E_POINTER);  
  286.     CAutoLock lock( &m_Lock );  
  287.   
  288.     RETAILMSG(1, (TEXT("Grabber: Transform! %x/r/n")));  
  289.     if( m_callback )  
  290.     {  
  291.         REFERENCE_TIME StartTime, StopTime;  
  292.         pms->GetTime( &StartTime, &StopTime);  
  293.   
  294.         StartTime += m_pInput->CurrentStartTime( );  
  295.         StopTime  += m_pInput->CurrentStartTime( );  
  296.   
  297.         BOOL * pTypeChanged = &((CSampleGrabberInPin*) m_pInput)->m_bMediaTypeChanged;  
  298.   
  299.         HRESULT hr = m_callback( pms, &StartTime, &StopTime, *pTypeChanged );  
  300.   
  301.         *pTypeChanged = FALSE; // now that we notified user, we can clear it   
  302.   
  303.         return hr;  
  304.     }  
  305.   
  306.     return NOERROR;  
  307. }  
  308.   
  309.   
  310. //----------------------------------------------------------------------------   
  311. // SetAcceptedMediaType   
  312. //----------------------------------------------------------------------------   
  313.   
  314. STDMETHODIMP CSampleGrabber::SetAcceptedMediaType( const CMediaType * pmt )  
  315. {  
  316.     CAutoLock lock( &m_Lock );  
  317.   
  318.     if( !pmt )  
  319.     {  
  320.         m_mtAccept = CMediaType( );  
  321.         return NOERROR;          
  322.     }  
  323.   
  324.     HRESULT hr = TRUE;  
  325.     CopyMediaType( &m_mtAccept, pmt );  
  326.   
  327.     return hr;  
  328. }  
  329.   
  330. //----------------------------------------------------------------------------   
  331. // GetAcceptedMediaType   
  332. //----------------------------------------------------------------------------   
  333.   
  334. STDMETHODIMP CSampleGrabber::GetConnectedMediaType( CMediaType * pmt )  
  335. {  
  336.     if( !m_pInput || !m_pInput->IsConnected( ) )  
  337.     {  
  338.         return VFW_E_NOT_CONNECTED;  
  339.     }  
  340.   
  341.     return m_pInput->ConnectionMediaType( pmt );  
  342. }  
  343.   
  344.   
  345. //----------------------------------------------------------------------------   
  346. // SetCallback   
  347. //----------------------------------------------------------------------------   
  348.   
  349. STDMETHODIMP CSampleGrabber::SetCallback( SAMPLECALLBACK Callback )  
  350. {  
  351.     CAutoLock lock( &m_Lock );  
  352.   
  353.     m_callback = Callback;  
  354.   
  355.     return NOERROR;  
  356. }  
  357.   
  358.   
  359. //----------------------------------------------------------------------------   
  360. // inform the input pin of the allocator buffer we wish to use. See the   
  361. // input pin's SetDeliverBuffer method for comments.    
  362. //----------------------------------------------------------------------------   
  363.   
  364. STDMETHODIMP CSampleGrabber::SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer )  
  365. {  
  366.     // have the input/output pins been created?   
  367.     if( !InputPin( ) || !OutputPin( ) )  
  368.     {  
  369.         return E_POINTER;  
  370.     }  
  371.   
  372.     // they can't be connected if we're going to be changing delivery buffers   
  373.     //   
  374.     if( InputPin( )->IsConnected( ) || OutputPin( )->IsConnected( ) )  
  375.     {  
  376.         return E_INVALIDARG;  
  377.     }  
  378.   
  379.     return ((CSampleGrabberInPin*)m_pInput)->SetDeliveryBuffer( props, m_pBuffer );  
  380. }  
  381.   
  382.   
  383. //----------------------------------------------------------------------------   
  384. // used to help speed input pin connection times. We return a partially   
  385. // specified media type - only the main type is specified. If we return   
  386. // anything BUT a major type, some codecs written improperly will crash   
  387. //----------------------------------------------------------------------------   
  388.   
  389. HRESULT CSampleGrabberInPin::GetMediaType( int iPosition, CMediaType * pMediaType )  
  390. {  
  391.     CheckPointer(pMediaType,E_POINTER);  
  392.   
  393.     if (iPosition < 0) {  
  394.         return E_INVALIDARG;  
  395.     }  
  396.     if (iPosition > 0) {  
  397.         return VFW_S_NO_MORE_ITEMS;  
  398.     }  
  399.     mt=*pMediaType;  
  400.       
  401.   
  402.     *pMediaType = CMediaType( );  
  403.     pMediaType->SetType( ((CSampleGrabber*)m_pFilter)->m_mtAccept.Type());  
  404.   
  405.     return S_OK;  
  406. }  
  407.   
  408.   
  409. //----------------------------------------------------------------------------   
  410. // override the CTransInPlaceInputPin's method, and return a new enumerator   
  411. // if the input pin is disconnected. This will allow GetMediaType to be   
  412. // called. If we didn't do this, EnumMediaTypes returns a failure code   
  413. // and GetMediaType is never called.    
  414. //----------------------------------------------------------------------------   
  415.   
  416. STDMETHODIMP CSampleGrabberInPin::EnumMediaTypes( IEnumMediaTypes **ppEnum )  
  417. {  
  418.     CheckPointer(ppEnum,E_POINTER);  
  419.     ValidateReadWritePtr(ppEnum,sizeof(IEnumMediaTypes *));  
  420.   
  421.     // if the output pin isn't connected yet, offer the possibly    
  422.     // partially specified media type that has been set by the user   
  423.   
  424.     if( !((CSampleGrabber*)m_pTIPFilter)->OutputPin( )->IsConnected() )  
  425.     {  
  426.         // Create a new reference counted enumerator   
  427.   
  428.         *ppEnum = new CEnumMediaTypes( this, NULL );  
  429.   
  430.         return (*ppEnum) ? NOERROR : E_OUTOFMEMORY;  
  431.     }  
  432.   
  433.     // if the output pin is connected, offer it's fully qualified media type   
  434.   
  435.     return ((CSampleGrabber*)m_pTIPFilter)->OutputPin( )->GetConnected()->EnumMediaTypes( ppEnum );  
  436. }  
  437.   
  438.   
  439. //----------------------------------------------------------------------------   
  440. //   
  441. //----------------------------------------------------------------------------   
  442.   
  443. STDMETHODIMP CSampleGrabberInPin::NotifyAllocator( IMemAllocator *pAllocator, BOOL bReadOnly )  
  444. {  
  445.     if( m_pPrivateAllocator )  
  446.     {  
  447.         if( pAllocator != m_pPrivateAllocator )  
  448.         {  
  449.             return E_FAIL;  
  450.         }  
  451.         else  
  452.         {  
  453.             // if the upstream guy wants to be read only and we don't, then that's bad   
  454.             // if the upstream guy doesn't request read only, but we do, that's okay   
  455.             if( bReadOnly && !SampleGrabber( )->IsReadOnly( ) )  
  456.             {  
  457.                 return E_FAIL;  
  458.             }  
  459.         }  
  460.     }  
  461.   
  462.     return CTransInPlaceInputPin::NotifyAllocator( pAllocator, bReadOnly );  
  463. }  
  464.   
  465.   
  466. //----------------------------------------------------------------------------   
  467. //   
  468. //----------------------------------------------------------------------------   
  469.   
  470. STDMETHODIMP CSampleGrabberInPin::GetAllocator( IMemAllocator **ppAllocator )  
  471. {  
  472.     if( m_pPrivateAllocator )  
  473.     {  
  474.         CheckPointer(ppAllocator,E_POINTER);  
  475.   
  476.         *ppAllocator = m_pPrivateAllocator;  
  477.         m_pPrivateAllocator->AddRef( );  
  478.         return NOERROR;  
  479.     }  
  480.     else  
  481.     {  
  482.         return CTransInPlaceInputPin::GetAllocator( ppAllocator );  
  483.     }  
  484. }  
  485.   
  486. //----------------------------------------------------------------------------   
  487. // GetAllocatorRequirements: The upstream filter calls this to get our   
  488. // filter's allocator requirements. If the app has set the buffer, then   
  489. // we return those props. Otherwise, we use the default TransInPlace behavior.   
  490. //----------------------------------------------------------------------------   
  491.   
  492. HRESULT CSampleGrabberInPin::GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps )  
  493. {  
  494.     CheckPointer(pProps,E_POINTER);  
  495.   
  496.     if (m_pPrivateAllocator)  
  497.     {  
  498.         *pProps = m_allocprops;  
  499.         return S_OK;  
  500.     }  
  501.     else  
  502.     {  
  503.         return CTransInPlaceInputPin::GetAllocatorRequirements(pProps);  
  504.     }  
  505. }  
  506.   
  507.   
  508.   
  509.   
  510. //----------------------------------------------------------------------------   
  511. //   
  512. //----------------------------------------------------------------------------   
  513.   
  514. HRESULT CSampleGrabberInPin::SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * pBuffer )  
  515. {  
  516.     // don't allow more than one buffer   
  517.   
  518.     if( props.cBuffers != 1 )  
  519.     {  
  520.         return E_INVALIDARG;  
  521.     }  
  522.     if( !pBuffer )  
  523.     {  
  524.         return E_POINTER;  
  525.     }  
  526.   
  527.     m_allocprops = props;  
  528.     m_pBuffer = pBuffer;  
  529.   
  530.     // If there is an existing allocator, make sure that it is released   
  531.     // to prevent a memory leak   
  532.     if (m_pPrivateAllocator)  
  533.     {  
  534.         m_pPrivateAllocator->Release();  
  535.         m_pPrivateAllocator = NULL;  
  536.     }  
  537.   
  538.     HRESULT hr = S_OK;  
  539.   
  540.     m_pPrivateAllocator = new CSampleGrabberAllocator( this, &hr );  
  541.     if( !m_pPrivateAllocator )  
  542.     {  
  543.         return E_OUTOFMEMORY;  
  544.     }  
  545.   
  546.     m_pPrivateAllocator->AddRef( );  
  547.     return hr;  
  548. }  
  549.   
  550.   
  551. //----------------------------------------------------------------------------   
  552. //   
  553. //----------------------------------------------------------------------------   
  554.   
  555. HRESULT CSampleGrabberInPin::SetMediaType( const CMediaType *pmt )  
  556. {  
  557.     m_bMediaTypeChanged = TRUE;  
  558.   
  559.     return CTransInPlaceInputPin::SetMediaType( pmt );  
  560. }  
  561.   
  562.   
  563. //----------------------------------------------------------------------------   
  564. // don't allocate the memory, just use the buffer the app provided   
  565. //----------------------------------------------------------------------------   
  566.   
  567. HRESULT CSampleGrabberAllocator::Alloc( )  
  568. {  
  569.     // look at the base class code to see where this came from!   
  570.   
  571.     CAutoLock lck(this);  
  572.   
  573.     // Check he has called SetProperties   
  574.     HRESULT hr = CBaseAllocator::Alloc();  
  575.     if (FAILED(hr)) {  
  576.         return hr;  
  577.     }  
  578.   
  579.     // If the requirements haven't changed then don't reallocate   
  580.     if (hr == S_FALSE) {  
  581.         ASSERT(m_pBuffer);  
  582.         return NOERROR;  
  583.     }  
  584.     ASSERT(hr == S_OK); // we use this fact in the loop below   
  585.   
  586.     // Free the old resources   
  587.     if (m_pBuffer) {  
  588.         ReallyFree();  
  589.     }  
  590.   
  591.     // Compute the aligned size   
  592.     LONG lAlignedSize = m_lSize + m_lPrefix;  
  593.     if (m_lAlignment > 1)   
  594.     {  
  595.         LONG lRemainder = lAlignedSize % m_lAlignment;  
  596.         if (lRemainder != 0)   
  597.         {  
  598.             lAlignedSize += (m_lAlignment - lRemainder);  
  599.         }  
  600.     }  
  601.   
  602.     // Create the contiguous memory block for the samples   
  603.     // making sure it's properly aligned (64K should be enough!)   
  604.     ASSERT(lAlignedSize % m_lAlignment == 0);  
  605.   
  606.     // don't create the buffer - use what was passed to us   
  607.     //   
  608.     m_pBuffer = m_pPin->m_pBuffer;  
  609.   
  610.     if (m_pBuffer == NULL) {  
  611.         return E_OUTOFMEMORY;  
  612.     }  
  613.   
  614.     LPBYTE pNext = m_pBuffer;  
  615.     CMediaSample *pSample;  
  616.   
  617.     ASSERT(m_lAllocated == 0);  
  618.   
  619.     // Create the new samples - we have allocated m_lSize bytes for each sample   
  620.     // plus m_lPrefix bytes per sample as a prefix. We set the pointer to   
  621.     // the memory after the prefix - so that GetPointer() will return a pointer   
  622.     // to m_lSize bytes.   
  623.     for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize)   
  624.     {  
  625.         pSample = new CMediaSample(  
  626.                                 NAME("Sample Grabber memory media sample"),  
  627.                                 this,  
  628.                                 &hr,  
  629.                                 pNext + m_lPrefix,      // GetPointer() value   
  630.                                 m_lSize);               // not including prefix   
  631.   
  632.         ASSERT(SUCCEEDED(hr));  
  633.         if (pSample == NULL)  
  634.             return E_OUTOFMEMORY;  
  635.   
  636.         // This CANNOT fail   
  637.         m_lFree.Add(pSample);  
  638.     }  
  639.   
  640.     m_bChanged = FALSE;  
  641.     return NOERROR;  
  642. }  
  643.   
  644.   
  645. //----------------------------------------------------------------------------   
  646. // don't really free the memory   
  647. //----------------------------------------------------------------------------   
  648.   
  649. void CSampleGrabberAllocator::ReallyFree()  
  650. {  
  651.     // look at the base class code to see where this came from!   
  652.   
  653.     // Should never be deleting this unless all buffers are freed   
  654.   
  655.     ASSERT(m_lAllocated == m_lFree.GetCount());  
  656.   
  657.     // Free up all the CMediaSamples   
  658.   
  659.     CMediaSample *pSample;  
  660.     for (;;)   
  661.     {  
  662.         pSample = m_lFree.RemoveHead();  
  663.         if (pSample != NULL)   
  664.         {  
  665.             delete pSample;  
  666.         }   
  667.         else   
  668.         {  
  669.             break;  
  670.         }  
  671.     }  
  672.   
  673.     m_lAllocated = 0;  
  674.   
  675.     // don't free the buffer - let the app do it   
  676. }  
  677.   
  678.   
  679. //----------------------------------------------------------------------------   
  680. // SetProperties: Called by the upstream filter to set the allocator   
  681. // properties. The application has already allocated the buffer, so we reject    
  682. // anything that is not compatible with that, and return the actual props.   
  683. //----------------------------------------------------------------------------   
  684.   
  685. HRESULT CSampleGrabberAllocator::SetProperties(  
  686.     ALLOCATOR_PROPERTIES *pRequest,   
  687.     ALLOCATOR_PROPERTIES *pActual  
  688. )  
  689. {  
  690.     HRESULT hr = CMemAllocator::SetProperties(pRequest, pActual);  
  691.   
  692.     if (FAILED(hr))  
  693.     {  
  694.         return hr;  
  695.     }  
  696.       
  697.     ALLOCATOR_PROPERTIES *pRequired = &(m_pPin->m_allocprops);  
  698.     if (pRequest->cbAlign != pRequired->cbAlign)  
  699.     {  
  700.         return VFW_E_BADALIGN;  
  701.     }  
  702.     if (pRequest->cbPrefix != pRequired->cbPrefix)  
  703.     {  
  704.         return E_FAIL;  
  705.     }  
  706.     if (pRequest->cbBuffer > pRequired->cbBuffer)  
  707.     {  
  708.         return E_FAIL;  
  709.     }  
  710.     if (pRequest->cBuffers > pRequired->cBuffers)  
  711.     {  
  712.         return E_FAIL;  
  713.     }  
  714.   
  715.     *pActual = *pRequired;  
  716.   
  717.     m_lCount = pRequired->cBuffers;  
  718.     m_lSize = pRequired->cbBuffer;  
  719.     m_lAlignment = pRequired->cbAlign;  
  720.     m_lPrefix = pRequired->cbPrefix;  
  721.   
  722.     return S_OK;  
  723. }  

//------------------------------------------------------------------------------ // File: Grabber.cpp // // Desc: DirectShow sample code - Implementation file for the SampleGrabber // example filter // // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ #include // Active Movie (includes windows.h) #include // 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:

view plain copy to clipboard print ?
  1. //------------------------------------------------------------------------------   
  2. // File: Grabber.h   
  3. //   
  4. // Desc: DirectShow sample code - Header file for the SampleGrabber   
  5. //       example filter   
  6. //   
  7. // Copyright (c) Microsoft Corporation.  All rights reserved.   
  8. //------------------------------------------------------------------------------   
  9.   
  10. //------------------------------------------------------------------------------   
  11. // Define new GUID and IID for the sample grabber example so that they do NOT   
  12. // conflict with the official DirectX SampleGrabber filter   
  13. //------------------------------------------------------------------------------   
  14. // {2FA4F053-6D60-4cb0-9503-8E89234F3F73}   
  15. DEFINE_GUID(CLSID_GrabberSample,   
  16. 0x2fa4f053, 0x6d60, 0x4cb0, 0x95, 0x3, 0x8e, 0x89, 0x23, 0x4f, 0x3f, 0x73);  
  17.   
  18. DEFINE_GUID(IID_IGrabberSample,   
  19. 0x6b652fff, 0x11fe, 0x4fce, 0x92, 0xad, 0x02, 0x66, 0xb5, 0xd7, 0xc7, 0x8f);  
  20.   
  21.   
  22. // We define a callback typedef for this example.    
  23. // Normally, you would make the SampleGrabber support a COM interface,    
  24. // and in one of its methods you would pass in a pointer to a COM interface    
  25. // used for calling back. See the DirectX documentation for the SampleGrabber   
  26. // for more information.   
  27.   
  28. typedef HRESULT (*SAMPLECALLBACK) (  
  29.     IMediaSample * pSample,   
  30.     REFERENCE_TIME * StartTime,   
  31.     REFERENCE_TIME * StopTime,  
  32.     BOOL TypeChanged );  
  33.   
  34.   
  35. // We define the interface the app can use to program us   
  36. MIDL_INTERFACE("6B652FFF-11FE-4FCE-92AD-0266B5D7C78F")  
  37. IGrabberSample : public IUnknown  
  38. {  
  39.     public:  
  40.           
  41.         virtual HRESULT STDMETHODCALLTYPE SetAcceptedMediaType(   
  42.             const CMediaType *pType) = 0;  
  43.           
  44.         virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType(   
  45.             CMediaType *pType) = 0;  
  46.           
  47.         virtual HRESULT STDMETHODCALLTYPE SetCallback(   
  48.             SAMPLECALLBACK Callback) = 0;  
  49.           
  50.         virtual HRESULT STDMETHODCALLTYPE SetDeliveryBuffer(   
  51.             ALLOCATOR_PROPERTIES props,  
  52.             BYTE *pBuffer) = 0;  
  53. };  
  54.           
  55.   
  56. class CSampleGrabberInPin;  
  57. class CSampleGrabber;  
  58.   
  59. //----------------------------------------------------------------------------   
  60. // This is a special allocator that KNOWS that the person who is creating it   
  61. // will only create one of them. It allocates CMediaSamples that only    
  62. // reference the buffer location that is set in the pin's renderer's   
  63. // data variable   
  64. //----------------------------------------------------------------------------   
  65.   
  66. class CSampleGrabberAllocator : public CMemAllocator  
  67. {  
  68.     friend class CSampleGrabberInPin;  
  69.     friend class CSampleGrabber;  
  70.   
  71. protected:  
  72.   
  73.     // our pin who created us   
  74.     //   
  75.     CSampleGrabberInPin * m_pPin;  
  76.   
  77. public:  
  78.   
  79.     CSampleGrabberAllocator( CSampleGrabberInPin * pParent, HRESULT *phr )   
  80.         : CMemAllocator( TEXT("SampleGrabberAllocator/0"), NULL, phr )   
  81.         , m_pPin( pParent )  
  82.     {  
  83.     };  
  84.   
  85.     ~CSampleGrabberAllocator( )  
  86.     {  
  87.         // wipe out m_pBuffer before we try to delete it. It's not an allocated   
  88.         // buffer, and the default destructor will try to free it!   
  89.         m_pBuffer = NULL;  
  90.     }  
  91.   
  92.     HRESULT Alloc( );  
  93.   
  94.     void ReallyFree();  
  95.   
  96.     // Override this to reject anything that does not match the actual buffer   
  97.     // that was created by the application   
  98.     STDMETHODIMP SetProperties(ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual);  
  99.   
  100. };  
  101.   
  102. //----------------------------------------------------------------------------   
  103. // we override the input pin class so we can provide a media type   
  104. // to speed up connection times. When you try to connect a filesourceasync   
  105. // to a transform filter, DirectShow will insert a splitter and then   
  106. // start trying codecs, both audio and video, video codecs first. If   
  107. // your sample grabber's set to connect to audio, unless we do this, it   
  108. // will try all the video codecs first. Connection times are sped up x10   
  109. // for audio with just this minor modification!   
  110. //----------------------------------------------------------------------------   
  111.   
  112. class CSampleGrabberInPin : public CTransInPlaceInputPin  
  113. {  
  114.     friend class CSampleGrabberAllocator;  
  115.     friend class CSampleGrabber;  
  116.   
  117.     CSampleGrabberAllocator * m_pPrivateAllocator;  
  118.     ALLOCATOR_PROPERTIES m_allocprops;  
  119.     BYTE * m_pBuffer;  
  120.     BOOL m_bMediaTypeChanged;  
  121.   
  122. protected:  
  123.   
  124.     CSampleGrabber * SampleGrabber( ) { return (CSampleGrabber*) m_pFilter; }  
  125.     HRESULT SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer );  
  126.   
  127. public:  
  128.   
  129.     CMediaType mt;  
  130.     CSampleGrabberInPin( CTransInPlaceFilter * pFilter, HRESULT * pHr )   
  131.         : CTransInPlaceInputPin( TEXT("SampleGrabberInputPin/0"), pFilter, pHr, L"Input/0" )  
  132.         , m_pPrivateAllocator( NULL )  
  133.         , m_pBuffer( NULL )  
  134.         , m_bMediaTypeChanged( FALSE )  
  135.     {  
  136.         memset( &m_allocprops, 0, sizeof( m_allocprops ) );  
  137.     }  
  138.   
  139.     ~CSampleGrabberInPin( )  
  140.     {  
  141.         if( m_pPrivateAllocator ) delete m_pPrivateAllocator;  
  142.     }  
  143.   
  144.     // override to provide major media type for fast connects   
  145.   
  146.     HRESULT GetMediaType( int iPosition, CMediaType *pMediaType );  
  147.   
  148.     // override this or GetMediaType is never called   
  149.   
  150.     STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );  
  151.   
  152.     // override this to refuse any allocators besides   
  153.     // the one the user wants, if this is set   
  154.   
  155.     STDMETHODIMP NotifyAllocator( IMemAllocator *pAllocator, BOOL bReadOnly );  
  156.   
  157.     // override this so we always return the special allocator, if necessary   
  158.   
  159.     STDMETHODIMP GetAllocator( IMemAllocator **ppAllocator );  
  160.   
  161.     HRESULT SetMediaType( const CMediaType *pmt );  
  162.   
  163.     // we override this to tell whoever's upstream of us what kind of   
  164.     // properties we're going to demand to have   
  165.     //   
  166.     STDMETHODIMP GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps );  
  167.   
  168.   
  169.   
  170. };  
  171.   
  172. //----------------------------------------------------------------------------   
  173. //   
  174. //----------------------------------------------------------------------------   
  175.   
  176. class CSampleGrabber : public CTransInPlaceFilter,  
  177.                        public IGrabberSample  
  178. {  
  179.     friend class CSampleGrabberInPin;  
  180.     friend class CSampleGrabberAllocator;  
  181.   
  182. protected:  
  183.   
  184.     CMediaType m_mtAccept;  
  185.     BOOL m_bModifiesData;  
  186.     SAMPLECALLBACK m_callback;  
  187.     CCritSec m_Lock; // serialize access to our data   
  188.   
  189.     BOOL IsReadOnly( ) { return !m_bModifiesData; }  
  190.   
  191.     // PURE, override this to ensure we get    
  192.     // connected with the right media type   
  193.     HRESULT CheckInputType( const CMediaType * pmt );  
  194.   
  195.     // PURE, override this to callback    
  196.     // the user when a sample is received   
  197.     HRESULT Transform( IMediaSample * pms );  
  198.   
  199.     // override this so we can return S_FALSE directly.    
  200.     // The base class CTransInPlace   
  201.     // Transform( ) method is called by it's    
  202.     // Receive( ) method. There is no way   
  203.     // to get Transform( ) to return an S_FALSE value    
  204.     // (which means "stop giving me data"),   
  205.     // to Receive( ) and get Receive( ) to return S_FALSE as well.   
  206.   
  207.     HRESULT Receive( IMediaSample * pms );  
  208.   
  209. public:  
  210.   
  211.     static CUnknown *WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);  
  212.   
  213.     // Expose ISampleGrabber   
  214.     STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);  
  215.     DECLARE_IUNKNOWN;  
  216.   
  217.     CSampleGrabber( IUnknown * pOuter, HRESULT * pHr, BOOL ModifiesData );  
  218.   
  219.     // IGrabberSample   
  220.     STDMETHODIMP SetAcceptedMediaType( const CMediaType * pmt );  
  221.     STDMETHODIMP GetConnectedMediaType( CMediaType * pmt );  
  222.     STDMETHODIMP SetCallback( SAMPLECALLBACK Callback );  
  223.     STDMETHODIMP SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer );  
  224. };  

//------------------------------------------------------------------------------ // 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下的。

转载于:https://www.cnblogs.com/aspxnets/archive/2011/08/04/2126832.html

你可能感兴趣的:(windows mobile做一个摄象头预览程序)