标签: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