zdirectshow的原理大概大家都知道,基本就是用微软封装的接口来实现硬件无关性,但是最终调用的接口都要在驱动层有对应的实现:
为了更清楚地演示directshow的数据传输过程,我必须说明的这个程序的基本流程。我采用的是vs2005 + windows mobile 6。0 professional 仿真模拟器,驱动层传出的是176*144格式的rgb565的数据,最后我将保存图片为RGB24的bmppdf图片。
说明:source filter从驱动层获取数据后一般分成两个pin将数据传出,一个是still pin用于传输静态数据,一帧的数据,一个是capture pin用于传出连续的视频数据,用RenderStream的方式gcap.pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video, gcap.pCap, NULL, gcap.pRenderP);默认会产生Smart Tee这个filter,这个filter将接收到的数据分成两份,同样也是分成两个pin传出,本例中我只用到smartTee传出的preview这个pin,连接到Render Filter以显示图象数据.
以下是主要程序部分(DDCam.cpp):
- #include
- #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);
- }
- }
#include
主要构建Graph的代码:
HRESULT BuildGraph()
{
HRESULT hr;
gcap.pGrab = new CSampleGrabber(NULL,&hr,FALSE);
gcap.pGrab->AddRef();
gcap.pGrab->SetCallback(&Callback);
CMediaType mt;
mt.SetType(&MEDIATYPE_Video);
mt.SetSubtype(&MEDIASUBTYPE_RGB24);
gcap.pGrab->SetAcceptedMediaType(&mt);
// Create the Filter Graph Manager.
hr = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&gcap.pGraph);
// Create the Capture Graph Builder.
hr = CoCreateInstance(CLSID_CaptureGraphBuilder, NULL,
CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
(void **)&gcap.pBuilder);
hr = gcap.pGraph->AddFilter(gcap.pCap,L"Video Capture Source");
hr = gcap.pGraph->AddFilter(gcap.pGrab,L"SampleGrabber");
gcap.pBuilder->SetFiltergraph(gcap.pGraph);
hr = CoCreateInstance(CLSID_VideoRenderer, NULL,
CLSCTX_INPROC_SERVER, IID_IBaseFilter,
(void **)&gcap.pRenderP);
hr = CoCreateInstance(CLSID_VideoRenderer, NULL,
CLSCTX_INPROC_SERVER, IID_IBaseFilter,
(void **)&gcap.pRenderS);
hr = gcap.pGraph->AddFilter(gcap.pRenderP,L"Video Render");
hr = gcap.pGraph->AddFilter(gcap.pRenderS,L"Video Render");
hr = gcap.pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video, gcap.pCap, NULL, gcap.pRenderP);
hr = gcap.pRenderP->QueryInterface(IID_IVideoWindow, (void**)&gcap.pVWP);
hr = gcap.pBuilder->RenderStream(&PIN_CATEGORY_STILL,&MEDIATYPE_Video, gcap.pCap, gcap.pGrab, gcap.pRenderS);
// Query for video interfaces, which may not be relevant for audio files
//hr = gcap.pGraph->QueryInterface(IID_IMediaEventEx, (void **)&gcap.pME);
//hr = gcap.pCap->QueryInterface(IID_IAMVideoProcAmp,(void **)&gcap.pVProcAmp);
//// Query the output pin for IAMStreamConfig (not shown).
//hr = gcap.pBuilder->FindInterface(
// &PIN_CATEGORY_PREVIEW, // Preview pin.
// 0, // Any media type.
// gcap.pCap, // Pointer to the capture filter.
// IID_IAMStreamConfig, (void**)&gcap.pConfigP);
// Have the graph signal event via window callbacks for performance
SetupVideoWindow(gcap.pVWP);
gcap.pVWP->put_MessageDrain((OAHWND)g_hWnd);
gcap.pVWP->put_Owner((OAHWND)g_hWnd);
//hr = gcap.pME->SetNotifyWindow((OAHWND)g_hWnd, WM_GRAPHNOTIFY, 0);
return hr;
}
另外SampleGrabber这个filter是要一个transform filter,可以在 directx 的directshow sample里找到,主要代码如下(Grabber.cpp):
- //------------------------------------------------------------------------------
- // File: Grabber.cpp
- //
- // Desc: DirectShow sample code - Implementation file for the SampleGrabber
- // example filter
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------------------------
- #include
// 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;
- }
//------------------------------------------------------------------------------ // File: Grabber.cpp // // Desc: DirectShow sample code - Implementation file for the SampleGrabber // example filter // // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ #include
还有个头文件Grabber.h:
- //------------------------------------------------------------------------------
- // File: Grabber.h
- //
- // Desc: DirectShow sample code - Header file for the SampleGrabber
- // example filter
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- // Define new GUID and IID for the sample grabber example so that they do NOT
- // conflict with the official DirectX SampleGrabber filter
- //------------------------------------------------------------------------------
- // {2FA4F053-6D60-4cb0-9503-8E89234F3F73}
- DEFINE_GUID(CLSID_GrabberSample,
- 0x2fa4f053, 0x6d60, 0x4cb0, 0x95, 0x3, 0x8e, 0x89, 0x23, 0x4f, 0x3f, 0x73);
- DEFINE_GUID(IID_IGrabberSample,
- 0x6b652fff, 0x11fe, 0x4fce, 0x92, 0xad, 0x02, 0x66, 0xb5, 0xd7, 0xc7, 0x8f);
- // We define a callback typedef for this example.
- // Normally, you would make the SampleGrabber support a COM interface,
- // and in one of its methods you would pass in a pointer to a COM interface
- // used for calling back. See the DirectX documentation for the SampleGrabber
- // for more information.
- typedef HRESULT (*SAMPLECALLBACK) (
- IMediaSample * pSample,
- REFERENCE_TIME * StartTime,
- REFERENCE_TIME * StopTime,
- BOOL TypeChanged );
- // We define the interface the app can use to program us
- MIDL_INTERFACE("6B652FFF-11FE-4FCE-92AD-0266B5D7C78F")
- IGrabberSample : public IUnknown
- {
- public:
- virtual HRESULT STDMETHODCALLTYPE SetAcceptedMediaType(
- const CMediaType *pType) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType(
- CMediaType *pType) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetCallback(
- SAMPLECALLBACK Callback) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetDeliveryBuffer(
- ALLOCATOR_PROPERTIES props,
- BYTE *pBuffer) = 0;
- };
- class CSampleGrabberInPin;
- class CSampleGrabber;
- //----------------------------------------------------------------------------
- // This is a special allocator that KNOWS that the person who is creating it
- // will only create one of them. It allocates CMediaSamples that only
- // reference the buffer location that is set in the pin's renderer's
- // data variable
- //----------------------------------------------------------------------------
- class CSampleGrabberAllocator : public CMemAllocator
- {
- friend class CSampleGrabberInPin;
- friend class CSampleGrabber;
- protected:
- // our pin who created us
- //
- CSampleGrabberInPin * m_pPin;
- public:
- CSampleGrabberAllocator( CSampleGrabberInPin * pParent, HRESULT *phr )
- : CMemAllocator( TEXT("SampleGrabberAllocator/0"), NULL, phr )
- , m_pPin( pParent )
- {
- };
- ~CSampleGrabberAllocator( )
- {
- // wipe out m_pBuffer before we try to delete it. It's not an allocated
- // buffer, and the default destructor will try to free it!
- m_pBuffer = NULL;
- }
- HRESULT Alloc( );
- void ReallyFree();
- // Override this to reject anything that does not match the actual buffer
- // that was created by the application
- STDMETHODIMP SetProperties(ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual);
- };
- //----------------------------------------------------------------------------
- // we override the input pin class so we can provide a media type
- // to speed up connection times. When you try to connect a filesourceasync
- // to a transform filter, DirectShow will insert a splitter and then
- // start trying codecs, both audio and video, video codecs first. If
- // your sample grabber's set to connect to audio, unless we do this, it
- // will try all the video codecs first. Connection times are sped up x10
- // for audio with just this minor modification!
- //----------------------------------------------------------------------------
- class CSampleGrabberInPin : public CTransInPlaceInputPin
- {
- friend class CSampleGrabberAllocator;
- friend class CSampleGrabber;
- CSampleGrabberAllocator * m_pPrivateAllocator;
- ALLOCATOR_PROPERTIES m_allocprops;
- BYTE * m_pBuffer;
- BOOL m_bMediaTypeChanged;
- protected:
- CSampleGrabber * SampleGrabber( ) { return (CSampleGrabber*) m_pFilter; }
- HRESULT SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer );
- public:
- CMediaType mt;
- CSampleGrabberInPin( CTransInPlaceFilter * pFilter, HRESULT * pHr )
- : CTransInPlaceInputPin( TEXT("SampleGrabberInputPin/0"), pFilter, pHr, L"Input/0" )
- , m_pPrivateAllocator( NULL )
- , m_pBuffer( NULL )
- , m_bMediaTypeChanged( FALSE )
- {
- memset( &m_allocprops, 0, sizeof( m_allocprops ) );
- }
- ~CSampleGrabberInPin( )
- {
- if( m_pPrivateAllocator ) delete m_pPrivateAllocator;
- }
- // override to provide major media type for fast connects
- HRESULT GetMediaType( int iPosition, CMediaType *pMediaType );
- // override this or GetMediaType is never called
- STDMETHODIMP EnumMediaTypes( IEnumMediaTypes **ppEnum );
- // override this to refuse any allocators besides
- // the one the user wants, if this is set
- STDMETHODIMP NotifyAllocator( IMemAllocator *pAllocator, BOOL bReadOnly );
- // override this so we always return the special allocator, if necessary
- STDMETHODIMP GetAllocator( IMemAllocator **ppAllocator );
- HRESULT SetMediaType( const CMediaType *pmt );
- // we override this to tell whoever's upstream of us what kind of
- // properties we're going to demand to have
- //
- STDMETHODIMP GetAllocatorRequirements( ALLOCATOR_PROPERTIES *pProps );
- };
- //----------------------------------------------------------------------------
- //
- //----------------------------------------------------------------------------
- class CSampleGrabber : public CTransInPlaceFilter,
- public IGrabberSample
- {
- friend class CSampleGrabberInPin;
- friend class CSampleGrabberAllocator;
- protected:
- CMediaType m_mtAccept;
- BOOL m_bModifiesData;
- SAMPLECALLBACK m_callback;
- CCritSec m_Lock; // serialize access to our data
- BOOL IsReadOnly( ) { return !m_bModifiesData; }
- // PURE, override this to ensure we get
- // connected with the right media type
- HRESULT CheckInputType( const CMediaType * pmt );
- // PURE, override this to callback
- // the user when a sample is received
- HRESULT Transform( IMediaSample * pms );
- // override this so we can return S_FALSE directly.
- // The base class CTransInPlace
- // Transform( ) method is called by it's
- // Receive( ) method. There is no way
- // to get Transform( ) to return an S_FALSE value
- // (which means "stop giving me data"),
- // to Receive( ) and get Receive( ) to return S_FALSE as well.
- HRESULT Receive( IMediaSample * pms );
- public:
- static CUnknown *WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);
- // Expose ISampleGrabber
- STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
- DECLARE_IUNKNOWN;
- CSampleGrabber( IUnknown * pOuter, HRESULT * pHr, BOOL ModifiesData );
- // IGrabberSample
- STDMETHODIMP SetAcceptedMediaType( const CMediaType * pmt );
- STDMETHODIMP GetConnectedMediaType( CMediaType * pmt );
- STDMETHODIMP SetCallback( SAMPLECALLBACK Callback );
- STDMETHODIMP SetDeliveryBuffer( ALLOCATOR_PROPERTIES props, BYTE * m_pBuffer );
- };
//------------------------------------------------------------------------------ // 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下的。