标签:des style blog http color os io strong
Sample source code: http://pan.baidu.com/s/1o60VAEA
Foword from: http://www.dreamincode.net/forums/topic/347938-a-new-webcam-api-tutorial-in-c-for-windows/page__st__0%26
Well,
#include "resource.h" #include "windows.h" ///////////////////////////////////////////////////////////////////////////// // // Menu // IDR_MENU1 MENU BEGIN POPUP "&File" BEGIN MENUITEM "Choose &Device", ID_FILE_CHOOSEDEVICE MENUITEM "Capture Image", ID_FILE_CAPTURE END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_CHOOSE_DEVICE DIALOGEX 0, 0, 186, 90 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Select Device" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "OK",IDOK,129,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 LISTBOX IDC_DEVICE_LIST,7,7,110,76,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END /////////////////////////////////////////////// // //Images // IMAGE RCDATA "text.png"
#define IDR_MENU1 101 #define IDD_CHOOSE_DEVICE 102 #define IDC_LIST1 1001 #define IDC_DEVICE_LIST 1002 #define ID_FILE_CHOOSEDEVICE 40001 #define ID_FILE_CAPTURE 50001 #define IDC_STATIC -1 #define IMAGE 301
#include <d3d9.h> #include <Windows.h> #include <WindowsX.h> #include <mfapi.h> #include <mfidl.h> #include <mfreadwrite.h> #include <mferror.h> #include <assert.h> #include <d3dx9.h> #include <ks.h> #include <ksmedia.h> #include <Dbt.h> #include <tchar.h> #include <strsafe.h> #include <AclAPI.h> template <class T> void SafeRelease(T **ppT) { if (*ppT) { (*ppT)->Release(); *ppT = NULL; } } #define BREAK_ON_FAIL(value) if(FAILED(value)) break; #define BREAK_ON_NULL(value, newHr) if(value == NULL) { hr = newHr; break; } #include "resource.h" #include "Device.h" #include "Preview.h"Basically all the headers we need in one file kept this way for simplicity‘s sake..
#if defined(UNICODE) && !defined(_UNICODE) #define _UNICODE #elif defined(_UNICODE) && !defined(UNICODE) #define UNICODE #endif // Include the v6 common controls in the manifest #pragma comment(linker, "\"/manifestdependency:type='Win32' " "name='Microsoft.Windows.Common-Controls' " "version='6.0.0.0' " "processorArchitecture='*' " "publicKeyToken='6595b64144ccf1df' " "language='*'\"") #include "Common.h" #include "resource.h" #pragma comment(lib,"mfplat.lib") #pragma message("linking with Microsoft's Media Foundation mfplat library ...") #pragma comment(lib,"mf.lib") #pragma message("linking with Microsoft's Media Foundation mf library ...") #pragma comment(lib,"mfreadwrite.lib") #pragma message("linking with Microsoft's Media Foundation mfreadwrite library ...") #pragma comment(lib,"mfuuid.lib") #pragma message("linking with Microsoft's Media Foundation mfuuid library ...") #pragma comment(lib,"d3d9.lib") #pragma message("linking with Microsoft's DirectX 3D 9 library ...") #pragma comment(lib,"shlwapi.lib") #pragma message("linking with Microsoft's shlwapi library ...") #pragma comment(lib,"D3dx9.lib") #pragma message("linking with Microsoft's DirectX 3DX 9 library ...") #pragma comment(lib,"Advapi32.lib") #pragma message("linking with Microsoft's Advapi32 library ...") // // ChooseDeviceParam structure // // Holds an array of IMFActivate pointers that represent video // capture devices. // struct ChooseDeviceParam { IMFActivate **ppDevices; // Array of IMFActivate pointers. UINT32 count; // Number of elements in the array. UINT32 selection; // Selected device, by array index. }; BOOL InitializeApplication(); BOOL InitializeWindow(HWND *pHwnd); void CleanUp(); INT MessageLoop(HWND hwnd); INT_PTR CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void ShowErrorMessage(PCWSTR format, HRESULT hr); // Window message handlers BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct); void OnClose(HWND hwnd); void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify); void OnSize(HWND hwnd, UINT state, int cx, int cy); void OnDeviceChange(HWND hwnd, DEV_BROADCAST_HDR *pHdr); // Command handlers void OnChooseDevice(HWND hwnd, bool bPrompt); // Global variables CPreview *mf_Preview = NULL; HDEVNOTIFY g_hdevnotify = NULL; /* Declare Windows procedure */ LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); /* Make the class name into a global variable */ TCHAR szClassName[ ] = L"WebCam Capture"; /* Make the window name into a global variable */ TCHAR szWindowName[ ] = L"Snoopy's WMF Webcam Capture."; int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) { HWND hwnd= NULL; /* This is the handle for our window */ if (InitializeApplication() && InitializeWindow(&hwnd)) { MessageLoop(hwnd); } CleanUp(); /* The program return-value is 0 - The value that PostQuitMessage() gave */ return 0; } /* This function is called by the Windows function DispatchMessage() */ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) /* handle the messages */ { HANDLE_MSG(hwnd, WM_CREATE, OnCreate); HANDLE_MSG(hwnd, WM_CLOSE, OnClose); HANDLE_MSG(hwnd, WM_COMMAND, OnCommand); HANDLE_MSG(hwnd, WM_SIZE, OnSize); case WM_APP_PREVIEW_ERROR: ShowErrorMessage(L"Error", (HRESULT)wParam); break; case WM_DEVICECHANGE: OnDeviceChange(hwnd, (PDEV_BROADCAST_HDR)lParam); break; case WM_ERASEBKGND: return 1; default: /* for messages that we don't deal with */ return DefWindowProc (hwnd, message, wParam, lParam); } return 0; } BOOL InitializeApplication() { HRESULT hr = S_OK; hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); if (SUCCEEDED(hr)) { hr = MFStartup(MF_VERSION); } return (SUCCEEDED(hr)); } //------------------------------------------------------------------- // CleanUp // // Releases resources. //------------------------------------------------------------------- void CleanUp() { if (g_hdevnotify) { UnregisterDeviceNotification(g_hdevnotify); } if (mf_Preview) { mf_Preview->CloseDevice(); } SafeRelease(&mf_Preview); MFShutdown(); CoUninitialize(); } //------------------------------------------------------------------- // InitializeWindow // // Creates the application window. //------------------------------------------------------------------- BOOL InitializeWindow(HWND *pHwnd) { WNDCLASS wc = {0}; wc.lpfnWndProc = WindowProcedure; wc.hInstance = GetModuleHandle(NULL); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = szClassName; wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); if (!RegisterClass(&wc)) { return FALSE; } HWND hwnd = CreateWindow( szClassName, szWindowName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL ); if (!hwnd) { return FALSE; } ShowWindow(hwnd, SW_SHOWDEFAULT); UpdateWindow(hwnd); *pHwnd = hwnd; return TRUE; } //------------------------------------------------------------------- // MessageLoop // // Implements the window message loop. //------------------------------------------------------------------- INT MessageLoop(HWND hwnd) { MSG msg = {0}; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } DestroyWindow(hwnd); return INT(msg.wParam); } //------------------------------------------------------------------- // OnCreate // // Handles the WM_CREATE message. //------------------------------------------------------------------- BOOL OnCreate(HWND hwnd, LPCREATESTRUCT) { HRESULT hr = S_OK; SetSecurityInfo(GetModuleHandle(NULL),SE_FILE_OBJECT,OWNER_SECURITY_INFORMATION,NULL,NULL,NULL,NULL); // Register this window to get device notification messages. DEV_BROADCAST_DEVICEINTERFACE di = { 0 }; di.dbcc_size = sizeof(di); di.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; di.dbcc_classguid = KSCATEGORY_CAPTURE; g_hdevnotify = RegisterDeviceNotification( hwnd, &di, DEVICE_NOTIFY_WINDOW_HANDLE ); if (g_hdevnotify == NULL) { ShowErrorMessage(L"RegisterDeviceNotification failed.", HRESULT_FROM_WIN32(GetLastError())); return FALSE; } // Create the object that manages video preview. hr = CPreview::CreateInstance(hwnd, hwnd, &mf_Preview); if (FAILED(hr)) { ShowErrorMessage(L"CPreview::CreateInstance failed.", hr); CleanUp(); return FALSE; } // Select the first available device (if any). OnChooseDevice(hwnd, true); SetWindowPos(hwnd,HWND_TOP,0,0,mf_Preview->m_draw.width,mf_Preview->m_draw.height,NULL); return TRUE; } //------------------------------------------------------------------- // OnClose // // Handles WM_CLOSE messages. //------------------------------------------------------------------- void OnClose(HWND /*hwnd*/) { CleanUp(); PostQuitMessage(0); } //------------------------------------------------------------------- // OnSize // // Handles WM_SIZE messages. //------------------------------------------------------------------- void OnSize(HWND hwnd, UINT /*state */, int cx, int cy) { if (mf_Preview) { mf_Preview->ResizeVideo((WORD)cx, (WORD)cy); InvalidateRect(hwnd, NULL, FALSE); } } //------------------------------------------------------------------- // OnCommand // // Handles WM_COMMAND messages //------------------------------------------------------------------- void OnCommand(HWND hwnd, int id, HWND /*hwndCtl*/, UINT /*codeNotify*/) { switch (id) { case ID_FILE_CHOOSEDEVICE: OnChooseDevice(hwnd, TRUE); break; case ID_FILE_CAPTURE: mf_Preview->m_draw.saveframe= true; break; } } //------------------------------------------------------------------- // OnChooseDevice // // Select a video capture device. // // hwnd: A handle to the application window. /// bPrompt: If TRUE, prompt to user to select the device. Otherwise, // select the first device in the list. //------------------------------------------------------------------- void OnChooseDevice(HWND hwnd, bool bPrompt) { HRESULT hr = S_OK; ChooseDeviceParam param = { 0 }; UINT iDevice = 0; // Index into the array of devices BOOL bCancel = FALSE; IMFAttributes *pAttributes = NULL; // Initialize an attribute store to specify enumeration parameters. hr = MFCreateAttributes(&pAttributes, 1); if (FAILED(hr)) { CleanUp(); } // Ask for source type = video capture devices. hr = pAttributes->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID ); if (FAILED(hr)) { CleanUp(); } // Enumerate devices. hr = MFEnumDeviceSources(pAttributes, & param.ppDevices, & param.count); if (FAILED(hr)) { CleanUp(); } // NOTE: param.count might be zero. if (bPrompt) { // Ask the user to select a device. INT_PTR result = DialogBoxParam( GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CHOOSE_DEVICE), hwnd, DlgProc, (LPARAM)& param ); if (result == IDOK) { iDevice = param.selection; } else { bCancel = true; // User cancelled PostQuitMessage(0); } } if (!bCancel && (param.count > 0)) { // Give this source to the CPlayer object for preview. hr = mf_Preview->SetDevice( param.ppDevices[iDevice] ); if (FAILED(hr)) { ShowErrorMessage(L"Cannot create a video capture device", hr); SafeRelease(&pAttributes); for (DWORD i = 0; i < param.count; i++) { SafeRelease(& param.ppDevices[i]); } CoTaskMemFree(param.ppDevices); } } else { CleanUp(); hr = -1; } SetWindowPos(hwnd,HWND_TOP,0,0,mf_Preview->m_draw.m_width-60,mf_Preview->m_draw.m_height,SWP_SHOWWINDOW); SafeRelease(&pAttributes); for (DWORD i = 0; i < param.count; i++) { SafeRelease(& param.ppDevices[i]); } CoTaskMemFree(param.ppDevices); if (FAILED(hr)) { ShowErrorMessage(L"Cannot create a video capture device", hr); } } //------------------------------------------------------------------- // OnDeviceChange // // Handles WM_DEVICECHANGE messages. //------------------------------------------------------------------- void OnDeviceChange(HWND hwnd, DEV_BROADCAST_HDR *pHdr) { if (mf_Preview == NULL || pHdr == NULL) { return; } HRESULT hr = S_OK; BOOL bDeviceLost = FALSE; // Check if the current device was lost. hr = mf_Preview->CheckDeviceLost(pHdr, &bDeviceLost); if (FAILED(hr) || bDeviceLost) { mf_Preview->CloseDevice(); MessageBox(hwnd, L"Lost the capture device.", szWindowName, MB_OK); } } ///////////////////////////////////////////////////////////////////// // Dialog functions void OnInitDialog(HWND hwnd, ChooseDeviceParam *pParam); HRESULT OnOK(HWND hwnd, ChooseDeviceParam *pParam); //------------------------------------------------------------------- // DlgProc // // Dialog procedure for the "Select Device" dialog. //------------------------------------------------------------------- INT_PTR CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static ChooseDeviceParam *pParam = NULL; switch (msg) { case WM_INITDIALOG: pParam = (ChooseDeviceParam*)lParam; OnInitDialog(hwnd, pParam); return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: OnOK(hwnd, pParam); EndDialog(hwnd, LOWORD(wParam)); return TRUE; case IDCANCEL: EndDialog(hwnd, LOWORD(wParam)); return TRUE; } break; } return FALSE; } //------------------------------------------------------------------- // OnInitDialog // // Handles the WM_INITDIALOG message. //------------------------------------------------------------------- void OnInitDialog(HWND hwnd, ChooseDeviceParam *pParam) { HRESULT hr = S_OK; // Populate the list with the friendly names of the devices. HWND hList = GetDlgItem(hwnd, IDC_DEVICE_LIST); for (DWORD i = 0; i < pParam->count; i++) { WCHAR *szFriendlyName = NULL; hr = pParam->ppDevices[i]->GetAllocatedString( MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &szFriendlyName, NULL ); if (FAILED(hr)) { break; } int index = ListBox_AddString(hList, szFriendlyName); ListBox_SetItemData(hList, index, i); CoTaskMemFree(szFriendlyName); } // Assume no selection for now. pParam->selection = (UINT32)-1; if (pParam->count == 0) { // If there are no devices, disable the "OK" button. EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); } } HRESULT OnOK(HWND hwnd, ChooseDeviceParam *pParam) { HWND hList = GetDlgItem(hwnd, IDC_DEVICE_LIST); int sel = ListBox_GetCurSel(hList); if (sel != LB_ERR) { pParam->selection = (UINT32)ListBox_GetItemData(hList, sel); } return S_OK; } void ShowErrorMessage(PCWSTR format, HRESULT hrErr) { HRESULT hr = S_OK; WCHAR msg[MAX_PATH]; hr = StringCbPrintf(msg, sizeof(msg), L"%s ",hrErr); if (SUCCEEDED(hr)) { MessageBox(NULL, msg, L"Error", MB_OK); } else { DebugBreak(); } }
#pragma once //------------------------------------------------------------------- // VideoBufferLock class // // Locks a video buffer that might or might not support IMF2DBuffer. // //------------------------------------------------------------------- class VideoBufferLock { public: VideoBufferLock(IMFMediaBuffer *pBuffer) : m_p2DBuffer(NULL), m_bLocked(FALSE) { m_pBuffer = pBuffer; m_pBuffer->AddRef(); // Query for the 2-D buffer interface. OK if this fails. (void)m_pBuffer->QueryInterface(IID_PPV_ARGS(&m_p2DBuffer)); } ~VideoBufferLock() { UnlockBuffer(); SafeRelease(&m_pBuffer); SafeRelease(&m_p2DBuffer); } //------------------------------------------------------------------- // LockBuffer // // Locks the buffer. Returns a pointer to scan line 0 and returns the stride. // // The caller must provide the default stride as an input parameter, in case // the buffer does not expose IMF2DBuffer. You can calculate the default stride // from the media type. //------------------------------------------------------------------- HRESULT LockBuffer( LONG lDefaultStride, // Minimum stride (with no padding). DWORD dwHeightInPixels, // Height of the image, in pixels. BYTE **ppbScanLine0, // Receives a pointer to the start of scan line 0. LONG *plStride // Receives the actual stride. ) { HRESULT hr = S_OK; // Use the 2-D version if available. if (m_p2DBuffer) { hr = m_p2DBuffer->Lock2D(ppbScanLine0, plStride); } else { // Use non-2D version. BYTE *pData = NULL; hr = m_pBuffer->Lock(&pData, NULL, NULL); if (SUCCEEDED(hr)) { *plStride = lDefaultStride; if (lDefaultStride < 0) { // Bottom-up orientation. Return a pointer to the start of the // last row *in memory* which is the top row of the image. *ppbScanLine0 = pData + abs(lDefaultStride) * (dwHeightInPixels - 1); } else { // Top-down orientation. Return a pointer to the start of the // buffer. *ppbScanLine0 = pData; } } } m_bLocked = (SUCCEEDED(hr)); return hr; } //------------------------------------------------------------------- // UnlockBuffer // // Unlocks the buffer. Called automatically by the destructor. //------------------------------------------------------------------- void UnlockBuffer() { if (m_bLocked) { if (m_p2DBuffer) { (void)m_p2DBuffer->Unlock2D(); } else { (void)m_pBuffer->Unlock(); } m_bLocked = FALSE; } } private: IMFMediaBuffer *m_pBuffer; IMF2DBuffer *m_p2DBuffer; BOOL m_bLocked; };
This class locks a video buffer so an image can be extracted from the video stream.
#pragma once const UINT WM_APP_PREVIEW_ERROR = WM_APP + 1; // wparam = HRESULT class CPreview : public IMFSourceReaderCallback { public: DrawDevice m_draw; // Manages the Direct3D device. static HRESULT CreateInstance( HWND hVideo, HWND hEvent, CPreview **ppPlayer ); // IUnknown methods STDMETHODIMP QueryInterface(REFIID iid, void** ppv); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); // IMFSourceReaderCallback methods STDMETHODIMP OnReadSample( HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample ); STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *) { return S_OK; } STDMETHODIMP OnFlush(DWORD) { return S_OK; } HRESULT SetDevice(IMFActivate *pActivate); HRESULT CloseDevice(); HRESULT ResizeVideo(WORD width, WORD height); HRESULT CheckDeviceLost(DEV_BROADCAST_HDR *pHdr, BOOL *pbDeviceLost); protected: // Constructor is private. Use static CreateInstance method to create. CPreview(HWND hVideo, HWND hEvent); // Destructor is private. Caller should call Release. virtual ~CPreview(); HRESULT Initialize(); void NotifyError(HRESULT hr) { PostMessage(m_hwndEvent, WM_APP_PREVIEW_ERROR, (WPARAM)hr, 0L); } HRESULT TryMediaType(IMFMediaType *pType); long m_nRefCount; // Reference count. CRITICAL_SECTION m_critsec; HWND m_hwndVideo; // Video window. HWND m_hwndEvent; // Application window to receive events. IMFSourceReader *m_pReader; WCHAR *m_pwszSymbolicLink; UINT32 m_cchSymbolicLink; };
#include "Common.h" #include <shlwapi.h> //------------------------------------------------------------------- // CreateInstance // // Static class method to create the CPreview object. //------------------------------------------------------------------- HRESULT CPreview::CreateInstance( HWND hVideo, // Handle to the video window. HWND hEvent, // Handle to the window to receive notifications. CPreview **ppPlayer // Receives a pointer to the CPreview object. ) { assert(hVideo != NULL); assert(hEvent != NULL); if (ppPlayer == NULL) { return E_POINTER; } CPreview *pPlayer = new CPreview(hVideo, hEvent); // The CPlayer constructor sets the ref count to 1. if (pPlayer == NULL) { return E_OUTOFMEMORY; } HRESULT hr = pPlayer->Initialize(); if (SUCCEEDED(hr)) { *ppPlayer = pPlayer; (*ppPlayer)->AddRef(); } SafeRelease(&pPlayer); return hr; } //------------------------------------------------------------------- // constructor //------------------------------------------------------------------- CPreview::CPreview(HWND hVideo, HWND hEvent) : m_pReader(NULL), m_hwndVideo(hVideo), m_hwndEvent(hEvent), m_nRefCount(1), m_pwszSymbolicLink(NULL), m_cchSymbolicLink(0) { InitializeCriticalSection(&m_critsec); } //------------------------------------------------------------------- // destructor //------------------------------------------------------------------- CPreview::~CPreview() { CloseDevice(); m_draw.DestroyDevice(); DeleteCriticalSection(&m_critsec); } //------------------------------------------------------------------- // Initialize // // Initializes the object. //------------------------------------------------------------------- HRESULT CPreview::Initialize() { HRESULT hr = S_OK; hr = m_draw.CreateDevice(m_hwndVideo); return hr; } //------------------------------------------------------------------- // CloseDevice // // Releases all resources held by this object. //------------------------------------------------------------------- HRESULT CPreview::CloseDevice() { EnterCriticalSection(&m_critsec); SafeRelease(&m_pReader); CoTaskMemFree(m_pwszSymbolicLink); m_pwszSymbolicLink = NULL; m_cchSymbolicLink = 0; LeaveCriticalSection(&m_critsec); return S_OK; } /////////////// IUnknown methods /////////////// //------------------------------------------------------------------- // AddRef //------------------------------------------------------------------- ULONG CPreview::AddRef() { return InterlockedIncrement(&m_nRefCount); } //------------------------------------------------------------------- // Release //------------------------------------------------------------------- ULONG CPreview::Release() { ULONG uCount = InterlockedDecrement(&m_nRefCount); if (uCount == 0) { delete this; } // For thread safety, return a temporary variable. return uCount; } //------------------------------------------------------------------- // QueryInterface //------------------------------------------------------------------- HRESULT CPreview::QueryInterface(REFIID riid, void** ppv) { static const QITAB qit[] = { QITABENT(CPreview, IMFSourceReaderCallback), { 0 }, }; return QISearch(this, qit, riid, ppv); } /////////////// IMFSourceReaderCallback methods /////////////// //------------------------------------------------------------------- // OnReadSample // // Called when the IMFMediaSource::ReadSample method completes. //------------------------------------------------------------------- HRESULT CPreview::OnReadSample( HRESULT hrStatus, DWORD /* dwStreamIndex */, DWORD /* dwStreamFlags */, LONGLONG /* llTimestamp */, IMFSample *pSample // Can be NULL ) { HRESULT hr = S_OK; IMFMediaBuffer *pBuffer = NULL; EnterCriticalSection(&m_critsec); if (FAILED(hrStatus)) { hr = hrStatus; } if (SUCCEEDED(hr)) { if (pSample) { // Get the video frame buffer from the sample. hr = pSample->GetBufferByIndex(0, &pBuffer); // Draw the frame. if (SUCCEEDED(hr)) { hr = m_draw.DrawFrame(pBuffer); } } } // Request the next frame. if (SUCCEEDED(hr)) { hr = m_pReader->ReadSample( (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, // actual NULL, // flags NULL, // timestamp NULL // sample ); } if (FAILED(hr)) { NotifyError(hr); } SafeRelease(&pBuffer); LeaveCriticalSection(&m_critsec); return hr; } //------------------------------------------------------------------- // TryMediaType // // Test a proposed video format. //------------------------------------------------------------------- HRESULT CPreview::TryMediaType(IMFMediaType *pType) { HRESULT hr = S_OK; BOOL bFound = FALSE; GUID subtype = { 0 }; hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); if (FAILED(hr)) { return hr; } // Do we support this type directly? if (m_draw.IsFormatSupported(subtype)) { bFound = TRUE; } else { // Can we decode this media type to one of our supported // output formats? for (DWORD i = 0; ; i++) { // Get the i'th format. m_draw.GetFormat(i, &subtype); hr = pType->SetGUID(MF_MT_SUBTYPE, subtype); if (FAILED(hr)) { break; } // Try to set this type on the source reader. hr = m_pReader->SetCurrentMediaType( (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, pType ); if (SUCCEEDED(hr)) { bFound = TRUE; break; } } } if (bFound) { hr = m_draw.SetVideoType(pType); } return hr; } //------------------------------------------------------------------- // SetDevice // // Set up preview for a specified video capture device. //------------------------------------------------------------------- HRESULT CPreview::SetDevice(IMFActivate *pActivate) { HRESULT hr = S_OK; IMFMediaSource *pSource = NULL; IMFAttributes *pAttributes = NULL; IMFMediaType *pType = NULL; EnterCriticalSection(&m_critsec); // Release the current device, if any. hr = CloseDevice(); // Create the media source for the device. if (SUCCEEDED(hr)) { hr = pActivate->ActivateObject( __uuidof(IMFMediaSource), (void**)&pSource ); } // Get the symbolic link. if (SUCCEEDED(hr)) { hr = pActivate->GetAllocatedString( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &m_pwszSymbolicLink, &m_cchSymbolicLink ); } // // Create the source reader. // // Create an attribute store to hold initialization settings. if (SUCCEEDED(hr)) { hr = MFCreateAttributes(&pAttributes, 2); } if (SUCCEEDED(hr)) { hr = pAttributes->SetUINT32(MF_READWRITE_DISABLE_CONVERTERS, TRUE); } // Set the callback pointer. if (SUCCEEDED(hr)) { hr = pAttributes->SetUnknown( MF_SOURCE_READER_ASYNC_CALLBACK, this ); } if (SUCCEEDED(hr)) { hr = MFCreateSourceReaderFromMediaSource( pSource, pAttributes, &m_pReader ); } // Try to find a suitable output type. if (SUCCEEDED(hr)) { for (DWORD i = 0; ; i++) { hr = m_pReader->GetNativeMediaType( (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, i, &pType ); if (FAILED(hr)) { break; } hr = TryMediaType(pType); SafeRelease(&pType); if (SUCCEEDED(hr)) { // Found an output type. break; } } } if (SUCCEEDED(hr)) { // Ask for the first sample. hr = m_pReader->ReadSample( (DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL ); } if (FAILED(hr)) { if (pSource) { pSource->Shutdown(); // NOTE: The source reader shuts down the media source // by default, but we might not have gotten that far. } CloseDevice(); } SafeRelease(&pSource); SafeRelease(&pAttributes); SafeRelease(&pType); LeaveCriticalSection(&m_critsec); return hr; } //------------------------------------------------------------------- // ResizeVideo // Resizes the video rectangle. // // The application should call this method if the size of the video // window changes; e.g., when the application receives WM_SIZE. //------------------------------------------------------------------- HRESULT CPreview::ResizeVideo(WORD /*width*/, WORD /*height*/) { HRESULT hr = S_OK; EnterCriticalSection(&m_critsec); hr = m_draw.ResetDevice(); if (FAILED(hr)) { MessageBox(NULL, L"ResetDevice failed!", NULL, MB_OK); } LeaveCriticalSection(&m_critsec); return hr; } //------------------------------------------------------------------- // CheckDeviceLost // Checks whether the current device has been lost. // // The application should call this method in response to a // WM_DEVICECHANGE message. (The application must register for // device notification to receive this message.) //------------------------------------------------------------------- HRESULT CPreview::CheckDeviceLost(DEV_BROADCAST_HDR *pHdr, BOOL *pbDeviceLost) { DEV_BROADCAST_DEVICEINTERFACE *pDi = NULL; if (pbDeviceLost == NULL) { return E_POINTER; } *pbDeviceLost = FALSE; if (pHdr == NULL) { return S_OK; } if (pHdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) { return S_OK; } pDi = (DEV_BROADCAST_DEVICEINTERFACE*)pHdr; EnterCriticalSection(&m_critsec); if (m_pwszSymbolicLink) { if (_wcsicmp(m_pwszSymbolicLink, pDi->dbcc_name) == 0) { *pbDeviceLost = TRUE; } } LeaveCriticalSection(&m_critsec); return S_OK; }
#pragma once // Function pointer for the function that transforms the image. typedef void (*IMAGE_TRANSFORM_FN)( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ); // DrawDevice class class DrawDevice { private: HWND m_hwnd; HDC *phdc; IDirect3D9 *m_pD3D; IDirect3DDevice9 *m_pDevice; IDirect3DSwapChain9 *m_pSwapChain; D3DPRESENT_PARAMETERS m_d3dpp; ID3DXSprite *textSprite; // Format information D3DFORMAT m_format; LONG m_lDefaultStride; MFRatio m_PixelAR; MFVideoInterlaceMode m_interlace; RECT m_rcDest; // Destination rectangle // Drawing IMAGE_TRANSFORM_FN m_convertFn; // Function to convert the video to RGB32 private: HRESULT TestCooperativeLevel(); HRESULT SetConversionFunction(REFGUID subtype); HRESULT CreateSwapChains(); void UpdateDestinationRect(); public: bool saveframe; UINT m_width; UINT m_height; UINT width; UINT height; DrawDevice(); virtual ~DrawDevice(); HRESULT CreateDevice(HWND hwnd); HRESULT ResetDevice(); void DestroyDevice(); HRESULT SetVideoType(IMFMediaType *pType); HRESULT DrawFrame(IMFMediaBuffer *pBuffer); // What video formats we accept BOOL IsFormatSupported(REFGUID subtype) const; HRESULT GetFormat(DWORD index, GUID *pSubtype) const; };
|
HRESULT TestCooperativeLevel(); HRESULT SetConversionFunction(REFGUID subtype); HRESULT CreateSwapChains(); void UpdateDestinationRect();
|
HRESULT CreateDevice(HWND hwnd); HRESULT ResetDevice(); void DestroyDevice(); HRESULT SetVideoType(IMFMediaType *pType); HRESULT DrawFrame(IMFMediaBuffer *pBuffer); BOOL IsFormatSupported(REFGUID subtype) const; HRESULT GetFormat(DWORD index, GUID *pSubtype) const;
|
#include "Common.h" #include "BufferLock.h" const DWORD NUM_BACK_BUFFERS = 2; void TransformImage_RGB24( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ); void TransformImage_RGB32( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ); void TransformImage_YUY2( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ); void TransformImage_NV12( BYTE* pDst, LONG dstStride, const BYTE* pSrc, LONG srcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ); RECT LetterBoxRect(const RECT& rcSrc, const RECT& rcDst); RECT CorrectAspectRatio(const RECT& src, const MFRatio& srcPAR); HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride); inline LONG Width(const RECT& r) { return r.right - r.left; } inline LONG Height(const RECT& r) { return r.bottom - r.top; } // Static table of output formats and conversion functions. struct ConversionFunction { GUID subtype; IMAGE_TRANSFORM_FN xform; }; ConversionFunction g_FormatConversions[] = { { MFVideoFormat_RGB32, TransformImage_RGB32 }, { MFVideoFormat_RGB24, TransformImage_RGB24 }, { MFVideoFormat_YUY2, TransformImage_YUY2 }, { MFVideoFormat_NV12, TransformImage_NV12 } }; const DWORD g_cFormats = ARRAYSIZE(g_FormatConversions); //------------------------------------------------------------------- // Constructor //------------------------------------------------------------------- DrawDevice::DrawDevice() : m_hwnd(NULL), m_pD3D(NULL), m_pDevice(NULL), m_pSwapChain(NULL), m_format(D3DFMT_UNKNOWN), m_width(0), m_height(0), m_lDefaultStride(0), m_interlace(MFVideoInterlace_Unknown), m_convertFn(NULL) { m_PixelAR.Denominator = m_PixelAR.Numerator = 1; ZeroMemory(&m_d3dpp, sizeof(m_d3dpp)); } //------------------------------------------------------------------- // Destructor //------------------------------------------------------------------- DrawDevice::~DrawDevice() { DestroyDevice(); } //------------------------------------------------------------------- // GetFormat // // Get a supported output format by index. //------------------------------------------------------------------- HRESULT DrawDevice::GetFormat(DWORD index, GUID *pSubtype) const { if (index < g_cFormats) { *pSubtype = g_FormatConversions[index].subtype; return S_OK; } return MF_E_NO_MORE_TYPES; } //------------------------------------------------------------------- // IsFormatSupported // // Query if a format is supported. //------------------------------------------------------------------- BOOL DrawDevice::IsFormatSupported(REFGUID subtype) const { for (DWORD i = 0; i < g_cFormats; i++) { if (subtype == g_FormatConversions[i].subtype) { return TRUE; } } return FALSE; } //------------------------------------------------------------------- // CreateDevice // // Create the Direct3D device. //------------------------------------------------------------------- HRESULT DrawDevice::CreateDevice(HWND hwnd) { if (m_pDevice) { return S_OK; } // Create the Direct3D object. if (m_pD3D == NULL) { m_pD3D = Direct3DCreate9(D3D_SDK_VERSION); if (m_pD3D == NULL) { return E_FAIL; } } HRESULT hr = S_OK; D3DPRESENT_PARAMETERS pp = { 0 }; D3DDISPLAYMODE mode = { 0 }; hr = m_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &mode ); if (FAILED(hr)) { return hr; } hr = m_pD3D->CheckDeviceType( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mode.Format, D3DFMT_X8R8G8B8, TRUE // windowed ); if (FAILED(hr)) { return hr; } pp.BackBufferFormat = D3DFMT_X8R8G8B8; pp.SwapEffect = D3DSWAPEFFECT_COPY; pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; pp.Windowed = TRUE; pp.hDeviceWindow = hwnd; hr = m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &pp, &m_pDevice ); if (FAILED(hr)) { return hr; } m_hwnd = hwnd; m_d3dpp = pp; return hr; } //------------------------------------------------------------------- // SetConversionFunction // // Set the conversion function for the specified video format. //------------------------------------------------------------------- HRESULT DrawDevice::SetConversionFunction(REFGUID subtype) { m_convertFn = NULL; for (DWORD i = 0; i < g_cFormats; i++) { if (g_FormatConversions[i].subtype == subtype) { m_convertFn = g_FormatConversions[i].xform; return S_OK; } } return MF_E_INVALIDMEDIATYPE; } //------------------------------------------------------------------- // SetVideoType // // Set the video format. //------------------------------------------------------------------- HRESULT DrawDevice::SetVideoType(IMFMediaType *pType) { HRESULT hr = S_OK; GUID subtype = { 0 }; MFRatio PAR = { 0 }; // Find the video subtype. hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); if (FAILED(hr)) { m_format = D3DFMT_UNKNOWN; m_convertFn = NULL; return hr; } // Choose a conversion function. // (This also validates the format type.) hr = SetConversionFunction(subtype); if (FAILED(hr)) { m_format = D3DFMT_UNKNOWN; m_convertFn = NULL; return hr; } // // Get some video attributes. // // Get the frame size. hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &m_width, &m_height); if (FAILED(hr)) { m_format = D3DFMT_UNKNOWN; m_convertFn = NULL; return hr; } // Get the interlace mode. Default: assume progressive. m_interlace = (MFVideoInterlaceMode)MFGetAttributeUINT32( pType, MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive ); // Get the image stride. hr = GetDefaultStride(pType, &m_lDefaultStride); if (FAILED(hr)) { m_format = D3DFMT_UNKNOWN; m_convertFn = NULL; return hr; } // Get the pixel aspect ratio. Default: Assume square pixels (1:1) hr = MFGetAttributeRatio( pType, MF_MT_PIXEL_ASPECT_RATIO, (UINT32*)&PAR.Numerator, (UINT32*)&PAR.Denominator ); if (SUCCEEDED(hr)) { m_PixelAR = PAR; } else { m_PixelAR.Numerator = m_PixelAR.Denominator = 1; } m_format = (D3DFORMAT)subtype.Data1; // Create Direct3D swap chains. hr = CreateSwapChains(); if (FAILED(hr)) { m_format = D3DFMT_UNKNOWN; m_convertFn = NULL; return hr; } // Update the destination rectangle for the correct // aspect ratio. UpdateDestinationRect(); return hr; } //------------------------------------------------------------------- // UpdateDestinationRect // // Update the destination rectangle for the current window size. // The destination rectangle is letterboxed to preserve the // aspect ratio of the video image. //------------------------------------------------------------------- void DrawDevice::UpdateDestinationRect() { RECT rcClient; RECT rcSrc = { 0, 0, m_width, m_height }; GetClientRect(m_hwnd, &rcClient); rcSrc = CorrectAspectRatio(rcSrc, m_PixelAR); m_rcDest = LetterBoxRect(rcSrc, rcClient); width=Width(m_rcDest)-60; height=Height(m_rcDest); } //------------------------------------------------------------------- // CreateSwapChains // // Create Direct3D swap chains. //------------------------------------------------------------------- HRESULT DrawDevice::CreateSwapChains() { HRESULT hr = S_OK; D3DPRESENT_PARAMETERS pp = { 0 }; SafeRelease(&m_pSwapChain); pp.BackBufferWidth = m_width; pp.BackBufferHeight = m_height; pp.Windowed = TRUE; pp.SwapEffect = D3DSWAPEFFECT_FLIP; pp.hDeviceWindow = m_hwnd; pp.BackBufferFormat = D3DFMT_X8R8G8B8; pp.Flags = D3DPRESENTFLAG_VIDEO | D3DPRESENTFLAG_DEVICECLIP | D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; pp.BackBufferCount = NUM_BACK_BUFFERS; hr = m_pDevice->CreateAdditionalSwapChain(&pp, &m_pSwapChain); return hr; } //------------------------------------------------------------------- // DrawFrame // // Draw the video frame. //------------------------------------------------------------------- HRESULT DrawDevice::DrawFrame(IMFMediaBuffer *pBuffer) { if (m_convertFn == NULL) { return MF_E_INVALIDREQUEST; } HRESULT hr = S_OK; BYTE *pbScanline0 = NULL; LONG lStride = 0; D3DLOCKED_RECT lr; IDirect3DSurface9 *pSurf = NULL; IDirect3DSurface9 *pBB = NULL; if (m_pDevice == NULL || m_pSwapChain == NULL) { return S_OK; } VideoBufferLock buffer(pBuffer); // Helper object to lock the video buffer. hr = TestCooperativeLevel(); if (FAILED(hr)) { SafeRelease(&pBB); SafeRelease(&pSurf); return hr; } // Lock the video buffer. This method returns a pointer to the first scan // line in the image, and the stride in bytes. hr = buffer.LockBuffer(m_lDefaultStride, m_height, &pbScanline0, &lStride); if (FAILED(hr)) { SafeRelease(&pBB); SafeRelease(&pSurf); return hr; } // Get the swap-chain surface. hr = m_pSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pSurf); if (FAILED(hr)) { SafeRelease(&pBB); SafeRelease(&pSurf); return hr; } // Lock the swap-chain surface. hr = pSurf->LockRect(&lr, NULL, D3DLOCK_NOSYSLOCK ); if (FAILED(hr)) { SafeRelease(&pBB); SafeRelease(&pSurf); return hr; } // Convert the frame. This also copies it to the Direct3D surface. m_convertFn( (BYTE*)lr.pBits, lr.Pitch, pbScanline0, lStride, m_width, m_height ); hr = pSurf->UnlockRect(); if (FAILED(hr)) { SafeRelease(&pBB); SafeRelease(&pSurf); return hr; } // Color fill the back buffer. hr = m_pDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBB); if (FAILED(hr)) { SafeRelease(&pBB); SafeRelease(&pSurf); return hr; } hr = m_pDevice->ColorFill(pBB, NULL, D3DCOLOR_XRGB(0, 0,0x80 )); if (FAILED(hr)) { SafeRelease(&pBB); SafeRelease(&pSurf); return hr; } IDirect3DSurface9* pRenderTarget; LPDIRECT3DTEXTURE9 imagetex; //texture our image will be loaded into D3DXVECTOR3 imagepos; //vector for the position of the sprite m_pDevice->CreateOffscreenPlainSurface(1040,690,D3DFMT_A8R8G8B8,D3DPOOL_SYSTEMMEM ,&pRenderTarget,0); RECT rect; rect.bottom = 1040; rect.left = 0; rect.right = 690; rect.top = 0; m_pDevice->BeginScene(); D3DXCreateSprite(m_pDevice,&textSprite); D3DXCreateTexture(m_pDevice,1040,690,0,D3DUSAGE_RENDERTARGET,D3DFMT_X8R8G8B8,D3DPOOL_SYSTEMMEM,&imagetex); D3DXCreateTextureFromResource(m_pDevice,GetModuleHandle(NULL),MAKEINTRESOURCE(IMAGE),&imagetex); // Use the DrawText method of the D3D render target interface to draw. textSprite->Begin(D3DXSPRITE_ALPHABLEND); imagepos.x=0.0f; //coord x of our sprite imagepos.y=18.0f; //coord y of out sprite imagepos.z=0.0f; //coord z of out sprite textSprite->Draw(imagetex,NULL,NULL,&imagepos,0xFFFFFFFF); textSprite->End(); m_pDevice->SetRenderTarget(0,pSurf); POINT p; p.x=0; p.y=0; // then use UpdateSurface to copy the drawn text surface to the texture's surface m_pDevice->EndScene(); m_pDevice->UpdateSurface(pRenderTarget,&rect,pSurf,&p); // release the render surface because you don't need it anymore if (pRenderTarget) { pRenderTarget->Release(); pRenderTarget = 0; } // save the frame if(saveframe == true) { D3DXSaveSurfaceToFile(L"Capture.jpg", D3DXIFF_JPG, pSurf, nullptr, nullptr); saveframe= false; } // Blit the frame. hr = m_pDevice->StretchRect(pSurf, NULL, pBB, &m_rcDest, D3DTEXF_LINEAR); if (FAILED(hr)) { SafeRelease(&pBB); SafeRelease(&pSurf); return hr; } // Present the frame. hr = m_pDevice->Present(NULL, NULL, NULL, NULL); SafeRelease(&pBB); SafeRelease(&pSurf); return hr; } //------------------------------------------------------------------- // TestCooperativeLevel // // Test the cooperative-level status of the Direct3D device. //------------------------------------------------------------------- HRESULT DrawDevice::TestCooperativeLevel() { if (m_pDevice == NULL) { return E_FAIL; } HRESULT hr = S_OK; // Check the current status of D3D9 device. hr = m_pDevice->TestCooperativeLevel(); switch (hr) { case D3D_OK: break; case D3DERR_DEVICELOST: hr = S_OK; case D3DERR_DEVICENOTRESET: hr = ResetDevice(); break; default: // Some other failure. break; } return hr; } //------------------------------------------------------------------- // ResetDevice // // Resets the Direct3D device. //------------------------------------------------------------------- HRESULT DrawDevice::ResetDevice() { HRESULT hr = S_OK; if (m_pDevice) { D3DPRESENT_PARAMETERS d3dpp = m_d3dpp; hr = m_pDevice->Reset(&d3dpp); if (FAILED(hr)) { DestroyDevice(); } } if (m_pDevice == NULL) { hr = CreateDevice(m_hwnd); if (FAILED(hr)) { goto done; } } if ((m_pSwapChain == NULL) && (m_format != D3DFMT_UNKNOWN)) { hr = CreateSwapChains(); if (FAILED(hr)) { goto done; } UpdateDestinationRect(); } done: return hr; } //------------------------------------------------------------------- // DestroyDevice // // Release all Direct3D resources. //------------------------------------------------------------------- void DrawDevice::DestroyDevice() { SafeRelease(&m_pSwapChain); SafeRelease(&m_pDevice); SafeRelease(&m_pD3D); } //------------------------------------------------------------------- // // Conversion functions // //------------------------------------------------------------------- __forceinline BYTE Clip(int clr) { return (BYTE)(clr < 0 ? 0 : ( clr > 255 ? 255 : clr )); } __forceinline RGBQUAD ConvertYCrCbToRGB( int y, int cr, int cb ) { RGBQUAD rgbq; int c = y - 16; int d = cb - 128; int e = cr - 128; rgbq.rgbRed = Clip(( 298 * c + 409 * e + 128) >> 8); rgbq.rgbGreen = Clip(( 298 * c - 100 * d - 208 * e + 128) >> 8); rgbq.rgbBlue = Clip(( 298 * c + 516 * d + 128) >> 8); return rgbq; } //------------------------------------------------------------------- // TransformImage_RGB24 // // RGB-24 to RGB-32 //------------------------------------------------------------------- void TransformImage_RGB24( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ) { for (DWORD y = 0; y < dwHeightInPixels; y++) { RGBTRIPLE *pSrcPel = (RGBTRIPLE*)pSrc; DWORD *pDestPel = (DWORD*)pDest; for (DWORD x = 0; x < dwWidthInPixels; x++) { pDestPel[x] = D3DCOLOR_XRGB( pSrcPel[x].rgbtRed, pSrcPel[x].rgbtGreen, pSrcPel[x].rgbtBlue ); } pSrc += lSrcStride; pDest += lDestStride; } } //------------------------------------------------------------------- // TransformImage_RGB32 // // RGB-32 to RGB-32 // // Note: This function is needed to copy the image from system // memory to the Direct3D surface. //------------------------------------------------------------------- void TransformImage_RGB32( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ) { MFCopyImage(pDest, lDestStride, pSrc, lSrcStride, dwWidthInPixels * 4, dwHeightInPixels); } //------------------------------------------------------------------- // TransformImage_YUY2 // // YUY2 to RGB-32 //------------------------------------------------------------------- void TransformImage_YUY2( BYTE* pDest, LONG lDestStride, const BYTE* pSrc, LONG lSrcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ) { for (DWORD y = 0; y < dwHeightInPixels; y++) { RGBQUAD *pDestPel = (RGBQUAD*)pDest; WORD *pSrcPel = (WORD*)pSrc; for (DWORD x = 0; x < dwWidthInPixels; x += 2) { // Byte order is U0 Y0 V0 Y1 int y0 = (int)LOBYTE(pSrcPel[x]); int u0 = (int)HIBYTE(pSrcPel[x]); int y1 = (int)LOBYTE(pSrcPel[x + 1]); int v0 = (int)HIBYTE(pSrcPel[x + 1]); pDestPel[x] = ConvertYCrCbToRGB(y0, v0, u0); pDestPel[x + 1] = ConvertYCrCbToRGB(y1, v0, u0); } pSrc += lSrcStride; pDest += lDestStride; } } //------------------------------------------------------------------- // TransformImage_NV12 // // NV12 to RGB-32 //------------------------------------------------------------------- void TransformImage_NV12( BYTE* pDst, LONG dstStride, const BYTE* pSrc, LONG srcStride, DWORD dwWidthInPixels, DWORD dwHeightInPixels ) { const BYTE* lpBitsY = pSrc; const BYTE* lpBitsCb = lpBitsY + (dwHeightInPixels * srcStride);; const BYTE* lpBitsCr = lpBitsCb + 1; for (UINT y = 0; y < dwHeightInPixels; y += 2) { const BYTE* lpLineY1 = lpBitsY; const BYTE* lpLineY2 = lpBitsY + srcStride; const BYTE* lpLineCr = lpBitsCr; const BYTE* lpLineCb = lpBitsCb; LPBYTE lpDibLine1 = pDst; LPBYTE lpDibLine2 = pDst + dstStride; for (UINT x = 0; x < dwWidthInPixels; x += 2) { int y0 = (int)lpLineY1[0]; int y1 = (int)lpLineY1[1]; int y2 = (int)lpLineY2[0]; int y3 = (int)lpLineY2[1]; int cb = (int)lpLineCb[0]; int cr = (int)lpLineCr[0]; RGBQUAD r = ConvertYCrCbToRGB(y0, cr, cb); lpDibLine1[0] = r.rgbBlue; lpDibLine1[1] = r.rgbGreen; lpDibLine1[2] = r.rgbRed; lpDibLine1[3] = 0; // Alpha r = ConvertYCrCbToRGB(y1, cr, cb); lpDibLine1[4] = r.rgbBlue; lpDibLine1[5] = r.rgbGreen; lpDibLine1[6] = r.rgbRed; lpDibLine1[7] = 0; // Alpha r = ConvertYCrCbToRGB(y2, cr, cb); lpDibLine2[0] = r.rgbBlue; lpDibLine2[1] = r.rgbGreen; lpDibLine2[2] = r.rgbRed; lpDibLine2[3] = 0; // Alpha r = ConvertYCrCbToRGB(y3, cr, cb); lpDibLine2[4] = r.rgbBlue; lpDibLine2[5] = r.rgbGreen; lpDibLine2[6] = r.rgbRed; lpDibLine2[7] = 0; // Alpha lpLineY1 += 2; lpLineY2 += 2; lpLineCr += 2; lpLineCb += 2; lpDibLine1 += 8; lpDibLine2 += 8; } pDst += (2 * dstStride); lpBitsY += (2 * srcStride); lpBitsCr += srcStride; lpBitsCb += srcStride; } } //------------------------------------------------------------------- // LetterBoxDstRect // // Takes a src rectangle and constructs the largest possible // destination rectangle within the specifed destination rectangle // such thatthe video maintains its current shape. // // This function assumes that pels are the same shape within both the // source and destination rectangles. // //------------------------------------------------------------------- RECT LetterBoxRect(const RECT& rcSrc, const RECT& rcDst) { // figure out src/dest scale ratios int iSrcWidth = Width(rcSrc); int iSrcHeight = Height(rcSrc); int iDstWidth = Width(rcDst); int iDstHeight = Height(rcDst); int iDstLBWidth; int iDstLBHeight; if (MulDiv(iSrcWidth, iDstHeight, iSrcHeight) <= iDstWidth) { // Column letter boxing ("pillar box") iDstLBWidth = MulDiv(iDstHeight, iSrcWidth, iSrcHeight); iDstLBHeight = iDstHeight; } else { // Row letter boxing. iDstLBWidth = iDstWidth; iDstLBHeight = MulDiv(iDstWidth, iSrcHeight, iSrcWidth); } // Create a centered rectangle within the current destination rect RECT rc; LONG left = rcDst.left + ((iDstWidth - iDstLBWidth) / 2); LONG top = rcDst.top + ((iDstHeight - iDstLBHeight) / 2); SetRect(&rc, left, top, left + iDstLBWidth, top + iDstLBHeight); return rc; } //----------------------------------------------------------------------------- // CorrectAspectRatio // // Converts a rectangle from the source's pixel aspect ratio (PAR) to 1:1 PAR. // Returns the corrected rectangle. // // For example, a 720 x 486 rect with a PAR of 9:10, when converted to 1x1 PAR, // is stretched to 720 x 540. //----------------------------------------------------------------------------- RECT CorrectAspectRatio(const RECT& src, const MFRatio& srcPAR) { // Start with a rectangle the same size as src, but offset to the origin (0,0). RECT rc = {0, 0, src.right - src.left, src.bottom - src.top}; if ((srcPAR.Numerator != 1) || (srcPAR.Denominator != 1)) { // Correct for the source's PAR. if (srcPAR.Numerator > srcPAR.Denominator) { // The source has "wide" pixels, so stretch the width. rc.right = MulDiv(rc.right, srcPAR.Numerator, srcPAR.Denominator); } else if (srcPAR.Numerator < srcPAR.Denominator) { // The source has "tall" pixels, so stretch the height. rc.bottom = MulDiv(rc.bottom, srcPAR.Denominator, srcPAR.Numerator); } // else: PAR is 1:1, which is a no-op. } return rc; } //----------------------------------------------------------------------------- // GetDefaultStride // // Gets the default stride for a video frame, assuming no extra padding bytes. // //----------------------------------------------------------------------------- HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride) { LONG lStride = 0; // Try to get the default stride from the media type. HRESULT hr = pType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride); if (FAILED(hr)) { // Attribute not set. Try to calculate the default stride. GUID subtype = GUID_NULL; UINT32 width = 0; UINT32 height = 0; // Get the subtype and the image size. hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype); if (SUCCEEDED(hr)) { hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height); } if (SUCCEEDED(hr)) { hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &lStride); } // Set the attribute for later reference. if (SUCCEEDED(hr)) { (void)pType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride)); } } if (SUCCEEDED(hr)) { *plStride = lStride; } return hr; }
Snoopy.
from another code;
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); MFStartup(MF_VERSION); IMFMediaSource *src; IMFAttributes *attr; IMFActivate **devices; UINT32 count = 0; IMFAttributes *attributes = nullptr; attributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID); MFEnumDeviceSources(attributes, &devices, &count); IMFSourceReader *reader; IMFMediaSource *source = nullptr; devices[0]->ActivateObject( __uuidof(IMFMediaSource), (void**)&source); MFCreateSourceReaderFromMediaSource(source, NULL, &reader); IMFSample *sample; reader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, &sample); if(sample) { IMFMediaBuffer* buffer; BYTE* data; DWORD max, current; sample->GetBufferByIndex(0, &buffer); buffer->Lock(&data, &max, &cur); buffer->UnLock(); SafeRelease(&buffer); } SafeRelease(&sample); SafeRelease(&source); MFShutdown(); CoUninitialize();
a new Webcam Api Tutorial in C++ for Windows(Windows Media Foundation)--WMF,布布扣,bubuko.com
a new Webcam Api Tutorial in C++ for Windows(Windows Media Foundation)--WMF
标签:des style blog http color os io strong
原文地址:http://blog.csdn.net/tody_guo/article/details/38497709