267 lines
6.7 KiB
C++
267 lines
6.7 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
#ifndef CAPTURE_H
|
|
#define CAPTURE_H
|
|
|
|
#ifndef UNICODE
|
|
#define UNICODE
|
|
#endif
|
|
|
|
#if !defined( NTDDI_VERSION )
|
|
#define NTDDI_VERSION NTDDI_WIN8
|
|
#endif
|
|
|
|
#if !defined( _WIN32_WINNT )
|
|
#define _WIN32_WINNT _WIN32_WINNT_WIN8
|
|
#endif
|
|
|
|
#include <new>
|
|
#include <windows.h>
|
|
#include <windowsx.h>
|
|
#include <mfapi.h>
|
|
#include <mfidl.h>
|
|
#include <mferror.h>
|
|
#include <mfcaptureengine.h>
|
|
#include <shlwapi.h>
|
|
#include <strsafe.h>
|
|
#include <commctrl.h>
|
|
#include <d3d11.h>
|
|
|
|
const UINT WM_APP_CAPTURE_EVENT = WM_APP + 1;
|
|
|
|
HWND CreatePreviewWindow(HINSTANCE hInstance, HWND hParent);
|
|
HWND CreateMainWindow(HINSTANCE hInstance);
|
|
void SetMenuItemText(HMENU hMenu, UINT uItem, _In_ PWSTR pszText);
|
|
void ShowError(HWND hwnd, PCWSTR szMessage, HRESULT hr);
|
|
void ShowError(HWND hwnd, UINT id, HRESULT hr);
|
|
HRESULT CloneVideoMediaType(IMFMediaType *pSrcMediaType, REFGUID guidSubType, IMFMediaType **ppNewMediaType);
|
|
HRESULT CreatePhotoMediaType(IMFMediaType *pSrcMediaType, IMFMediaType **ppPhotoMediaType);
|
|
|
|
// DXGI DevManager support
|
|
extern IMFDXGIDeviceManager* g_pDXGIMan;
|
|
extern ID3D11Device* g_pDX11Device;
|
|
extern UINT g_ResetToken;
|
|
|
|
#ifdef _DEBUG
|
|
#define DBGMSG(x) { DbgPrint x;}
|
|
#else
|
|
#define DBGMSG(x)
|
|
#endif
|
|
|
|
VOID DbgPrint(PCTSTR format, ...);
|
|
|
|
|
|
template <class T> void SafeRelease(T **ppT)
|
|
{
|
|
if (*ppT)
|
|
{
|
|
(*ppT)->Release();
|
|
*ppT = NULL;
|
|
}
|
|
}
|
|
|
|
// Gets an interface pointer from a Media Foundation collection.
|
|
template <class IFACE>
|
|
HRESULT GetCollectionObject(IMFCollection *pCollection, DWORD index, IFACE **ppObject)
|
|
{
|
|
IUnknown *pUnk;
|
|
HRESULT hr = pCollection->GetElement(index, &pUnk);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pUnk->QueryInterface(IID_PPV_ARGS(ppObject));
|
|
pUnk->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
struct ChooseDeviceParam
|
|
{
|
|
ChooseDeviceParam() : ppDevices(NULL), count(0)
|
|
{
|
|
}
|
|
~ChooseDeviceParam()
|
|
{
|
|
for (DWORD i = 0; i < count; i++)
|
|
{
|
|
SafeRelease(&ppDevices[i]);
|
|
}
|
|
CoTaskMemFree(ppDevices);
|
|
}
|
|
|
|
IMFActivate **ppDevices;
|
|
UINT32 count;
|
|
UINT32 selection;
|
|
};
|
|
|
|
|
|
|
|
// CaptureManager class
|
|
// Wraps the capture engine and implements the event callback.
|
|
|
|
class CaptureManager
|
|
{
|
|
// The event callback object.
|
|
class CaptureEngineCB : public IMFCaptureEngineOnEventCallback
|
|
{
|
|
long m_cRef;
|
|
HWND m_hwnd;
|
|
|
|
public:
|
|
CaptureEngineCB(HWND hwnd) : m_cRef(1), m_hwnd(hwnd), m_fSleeping(false), m_pManager(NULL) {}
|
|
|
|
// IUnknown
|
|
STDMETHODIMP QueryInterface(REFIID riid, void** ppv);
|
|
STDMETHODIMP_(ULONG) AddRef();
|
|
STDMETHODIMP_(ULONG) Release();
|
|
|
|
// IMFCaptureEngineOnEventCallback
|
|
STDMETHODIMP OnEvent( _In_ IMFMediaEvent* pEvent);
|
|
|
|
bool m_fSleeping;
|
|
CaptureManager* m_pManager;
|
|
};
|
|
|
|
HWND m_hwndEvent;
|
|
HWND m_hwndPreview;
|
|
|
|
IMFCaptureEngine *m_pEngine;
|
|
IMFCapturePreviewSink *m_pPreview;
|
|
|
|
CaptureEngineCB *m_pCallback;
|
|
|
|
bool m_bPreviewing;
|
|
bool m_bRecording;
|
|
bool m_bPhotoPending;
|
|
|
|
UINT m_errorID;
|
|
HANDLE m_hEvent;
|
|
HANDLE m_hpwrRequest;
|
|
bool m_fPowerRequestSet;
|
|
|
|
CaptureManager(HWND hwnd) :
|
|
m_hwndEvent(hwnd), m_hwndPreview(NULL), m_pEngine(NULL), m_pPreview(NULL),
|
|
m_pCallback(NULL), m_bRecording(false), m_bPreviewing(false), m_bPhotoPending(false), m_errorID(0),m_hEvent(NULL)
|
|
,m_hpwrRequest(INVALID_HANDLE_VALUE)
|
|
,m_fPowerRequestSet(false)
|
|
{
|
|
REASON_CONTEXT pwrCtxt;
|
|
|
|
pwrCtxt.Version = POWER_REQUEST_CONTEXT_VERSION;
|
|
pwrCtxt.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
|
|
pwrCtxt.Reason.SimpleReasonString = L"CaptureEngine is recording!";
|
|
|
|
m_hpwrRequest = PowerCreateRequest(&pwrCtxt);
|
|
}
|
|
|
|
void SetErrorID(HRESULT hr, UINT id)
|
|
{
|
|
m_errorID = SUCCEEDED(hr) ? 0 : id;
|
|
}
|
|
|
|
// Capture Engine Event Handlers
|
|
void OnCaptureEngineInitialized(HRESULT& hrStatus);
|
|
void OnPreviewStarted(HRESULT& hrStatus);
|
|
void OnPreviewStopped(HRESULT& hrStatus);
|
|
void OnRecordStarted(HRESULT& hrStatus);
|
|
void OnRecordStopped(HRESULT& hrStatus);
|
|
void WaitForResult()
|
|
{
|
|
WaitForSingleObject(m_hEvent, INFINITE);
|
|
}
|
|
public:
|
|
~CaptureManager()
|
|
{
|
|
DestroyCaptureEngine();
|
|
}
|
|
|
|
static HRESULT CreateInstance(HWND hwndEvent, CaptureManager **ppEngine)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
*ppEngine = NULL;
|
|
|
|
CaptureManager *pEngine = new (std::nothrow) CaptureManager(hwndEvent);
|
|
if (pEngine == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
*ppEngine = pEngine;
|
|
pEngine = NULL;
|
|
|
|
Exit:
|
|
if (NULL != pEngine)
|
|
{
|
|
delete pEngine;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT InitializeCaptureManager(HWND hwndPreview, IUnknown* pUnk);
|
|
void DestroyCaptureEngine()
|
|
{
|
|
if (NULL != m_hEvent)
|
|
{
|
|
CloseHandle(m_hEvent);
|
|
m_hEvent = NULL;
|
|
}
|
|
SafeRelease(&m_pPreview);
|
|
SafeRelease(&m_pEngine);
|
|
SafeRelease(&m_pCallback);
|
|
|
|
if(g_pDXGIMan)
|
|
{
|
|
g_pDXGIMan->ResetDevice(g_pDX11Device, g_ResetToken);
|
|
}
|
|
SafeRelease(&g_pDX11Device);
|
|
SafeRelease(&g_pDXGIMan);
|
|
|
|
m_bPreviewing = false;
|
|
m_bRecording = false;
|
|
m_bPhotoPending = false;
|
|
m_errorID = 0;
|
|
}
|
|
|
|
|
|
|
|
bool IsPreviewing() const { return m_bPreviewing; }
|
|
bool IsRecording() const { return m_bRecording; }
|
|
bool IsPhotoPending() const { return m_bPhotoPending; }
|
|
UINT ErrorID() const { return m_errorID; }
|
|
|
|
HRESULT OnCaptureEvent(WPARAM wParam, LPARAM lParam);
|
|
HRESULT SetVideoDevice(IUnknown *pUnk);
|
|
HRESULT StartPreview();
|
|
HRESULT StopPreview();
|
|
HRESULT StartRecord(PCWSTR pszDestinationFile);
|
|
HRESULT StopRecord();
|
|
HRESULT TakePhoto(PCWSTR pszFileName);
|
|
|
|
void SleepState(bool fSleeping)
|
|
{
|
|
if (NULL != m_pCallback)
|
|
{
|
|
m_pCallback->m_fSleeping = fSleeping;
|
|
}
|
|
}
|
|
|
|
HRESULT UpdateVideo()
|
|
{
|
|
if (m_pPreview)
|
|
{
|
|
return m_pPreview->UpdateVideo(NULL, NULL, NULL);
|
|
}
|
|
else
|
|
{
|
|
return S_OK;
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif CAPTURE_H
|