This commit is contained in:
2025-05-13 02:46:21 +03:00
parent 143e16692e
commit 86914b7fcc
610 changed files with 92343 additions and 2 deletions
+225
View File
@@ -0,0 +1,225 @@
#include "WebCamera.h"
#include "../Utils.h"
#include "../log/NLog.h"
#include "../Com.h"
namespace LifeCore {
class WinWebCameraDescription : public WebCameraDescription {
public:
friend class WebCamera;
WinWebCameraDescription(IMFActivate* act, int id)
: activate(act), deviceId(id)
{
if(activate != nullptr)
activate->AddRef();
}
~WinWebCameraDescription() {
SafeRelease(&activate);
}
std::wstring GetName() override{
if(activate == nullptr)
return std::wstring(L"");
WCHAR *szFriendlyName = NULL;
UINT32 cchName;
auto hr = activate->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &szFriendlyName, &cchName);
if(hr != S_OK)
return std::wstring(L"");
std::wstring result(szFriendlyName);
CoTaskMemFree(szFriendlyName);
return result;
}
int deviceId;
protected:
IMFActivate* activate;
};
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;
};
class WinWebCamCallback : IMFCaptureEngineOnEventCallback {
public:
WinWebCamCallback(WebCamera* cam)
: m_cRef(1), camera(cam), sleeping(false)
{
}
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) {
static const QITAB qit[] = {
QITABENT(WinWebCamCallback, IMFCaptureEngineOnEventCallback), { 0 }
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) AddRef() {
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) Release() {
LONG cRef = InterlockedDecrement(&m_cRef);
if(cRef == 0) {
delete this;
}
return cRef;
}
// IMFCaptureEngineOnEventCallback
STDMETHODIMP OnEvent(_In_ IMFMediaEvent* pEvent) {
if(sleeping && camera != nullptr) {
// We're about to fall asleep, that means we've just asked the CE to stop the preview
// and record. We need to handle it here since our message pump may be gone.
GUID guidType;
HRESULT hrStatus;
HRESULT hr = pEvent->GetStatus(&hrStatus);
if(FAILED(hr)) {
hrStatus = hr;
}
hr = pEvent->GetExtendedType(&guidType);
if(SUCCEEDED(hr)) {
if(guidType == MF_CAPTURE_ENGINE_PREVIEW_STOPPED) {
LogInfo() << "Preview stopped";
//m_pManager->OnPreviewStopped(hrStatus);
// SetEvent(m_pManager->m_hEvent);
} else if(guidType == MF_CAPTURE_ENGINE_RECORD_STOPPED) {
LogInfo() << "Engine stopped";
//m_pManager->OnRecordStopped(hrStatus);
//SetEvent(m_pManager->m_hEvent);
} else {
// This is an event we don't know about, we don't really care and there's
// no clean way to report the error so just set the event and fall through.
//SetEvent(m_pManager->m_hEvent);
}
}
return S_OK;
} else {
LogInfo() << "Capture event";
pEvent->AddRef(); // The application will release the pointer when it handles the message.
camera->OnCaptureEvent(pEvent);
//PostMessage(m_hwnd, WM_APP_CAPTURE_EVENT, (WPARAM)pEvent, 0L);
}
return S_OK;
}
protected:
bool sleeping;
long m_cRef;
WebCamera* camera;
};
WebCamera::WebCamera(webcam_desc_ptr desc)
: description(desc), FrameNumber(0), pSource(nullptr), grabber(nullptr)
{
callback = new WinWebCamCallback(this);
}
void WebCamera::OnCaptureEvent(IMFMediaEvent* pEvent) {
HRESULT hrStatus;
GUID eventType;
pEvent->GetStatus(&hrStatus);
pEvent->GetExtendedType(&eventType);
}
RawBuffer<uint8>* WebCamera::GetImage() {
return grabber->GetImage();
}
void WebCamera::OnImageGrabbed(WinMfImageGrabber* grabber, RawBuffer<uint8>* image) {
FrameNumber++;
Event_ImageCapture.Call(this, image);
}
bool WebCamera::Open() {
IMFActivate* pActivate = dynamic_cast<WinWebCameraDescription*>(description.get())->activate;
HRESULT hr = pActivate->ActivateObject(__uuidof(IMFMediaSource), (void**)&pSource);
if(FAILED(hr)) {
LogInfo() << "Failed to activate camera!";
return false;
}
grabber = new WinMfImageGrabber(this);
if(FAILED(grabber->initImageGrabber(pSource, MFVideoFormat_RGB24)) || FAILED(grabber->startGrabbing())) {
LogInfo() << "Failed to init camera grabber";
pActivate->ShutdownObject();
FINAL_RELEASE(grabber);
FINAL_RELEASE(pSource);
return false;
}
return true;
}
void WebCamera::Close() {
IMFActivate* pActivate = dynamic_cast<WinWebCameraDescription*>(description.get())->activate;
if(grabber != nullptr)
grabber->stopGrabbing();
FINAL_RELEASE(grabber);
FINAL_RELEASE(pSource);
pActivate->ShutdownObject();
pActivate->AddRef();
auto val = pActivate->Release();
LogInfo() << "Initial 2 pActivate refCount = " << val;
FrameNumber = 0;
}
int2 WebCamera::GetSize() {
return int2();
}
int32 WebCamera::GetBpp() {
return -1;
}
bool WebCamera::Read(int2 size, uint8* buffer) {
return false;
}
void WebCamera::Update() {
grabber->processGrabbing();
}
std::vector<webcam_desc_ptr> WebCamera::GetConnectedDevices() {
std::vector<webcam_desc_ptr> result;
IMFAttributes *pAttributes = NULL;
ChooseDeviceParam param;
HRESULT hr = MFCreateAttributes(&pAttributes, 1);
if(FAILED(hr)) {
printf("Failed\n");
goto Exit;
}
// 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)) {
printf("Failed\n");
goto Exit;
}
// Enumerate devices.
hr = MFEnumDeviceSources(pAttributes, &param.ppDevices, &param.count);
if(FAILED(hr)) {
printf("Failed\n");
goto Exit;
}
for(UINT32 i = 0; i < param.count; ++i) {
result.push_back(webcam_desc_ptr(new WinWebCameraDescription(param.ppDevices[i], i)));
}
Exit:
if(NULL != pAttributes) {
pAttributes->Release();
pAttributes = NULL;
}
return result;
}
}
+54
View File
@@ -0,0 +1,54 @@
#ifndef WebCamera_h__
#define WebCamera_h__
#include "../ICamera.h"
#include "../IImage.h"
#include <mfapi.h>
#include <mfidl.h>
#include <mferror.h>
#include <mfcaptureengine.h>
#include "WinMfImageGrabber.h"
#include <shlwapi.h>
#pragma comment(lib, "mf.lib")
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfuuid.lib")
#pragma comment(lib, "shlwapi.lib")
#include <memory>
#include <vector>
#include "../Delegate.h"
namespace LifeCore {
class WebCameraDescription {
public:
virtual ~WebCameraDescription() {}
virtual std::wstring GetName() = 0;
};
typedef std::shared_ptr<WebCameraDescription> webcam_desc_ptr;
class WebCamera : public ICamera, public IImage
{
public:
Delegate<WebCamera*, RawBuffer<uint8>*> Event_ImageCapture;
WebCamera(webcam_desc_ptr desc);
int2 GetSize();
int32 GetBpp();
bool Read(int2 size, uint8* buffer);
static std::vector<webcam_desc_ptr> GetConnectedDevices();
bool Open();
void Close();
void OnImageGrabbed(WinMfImageGrabber* grabber, RawBuffer<uint8>* image);
void OnCaptureEvent(IMFMediaEvent* pEvent);
void Update();
RawBuffer<uint8>* GetImage();
int FrameNumber;
private:
webcam_desc_ptr description;
WinMfImageGrabber* grabber;
IMFMediaSource *pSource;
void* callback;
};
}
#endif // WebCamera_h__
+461
View File
@@ -0,0 +1,461 @@
#include "WinMfFormatReader.h"
#include "Strsafe.h"
#include <Mfapi.h>
#include <mfobjects.h>
namespace LifeCore {
LPCWSTR GetGUIDNameConstNew(const GUID& guid);
HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz);
HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index);
HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, WinMfMediaType &out);
unsigned int *GetParametr(GUID guid, WinMfMediaType &out) {
if(guid == MF_MT_YUV_MATRIX)
return &(out.MF_MT_YUV_MATRIX);
if(guid == MF_MT_VIDEO_LIGHTING)
return &(out.MF_MT_VIDEO_LIGHTING);
if(guid == MF_MT_DEFAULT_STRIDE)
return &(out.MF_MT_DEFAULT_STRIDE);
if(guid == MF_MT_VIDEO_CHROMA_SITING)
return &(out.MF_MT_VIDEO_CHROMA_SITING);
if(guid == MF_MT_VIDEO_NOMINAL_RANGE)
return &(out.MF_MT_VIDEO_NOMINAL_RANGE);
if(guid == MF_MT_ALL_SAMPLES_INDEPENDENT)
return &(out.MF_MT_ALL_SAMPLES_INDEPENDENT);
if(guid == MF_MT_FIXED_SIZE_SAMPLES)
return &(out.MF_MT_FIXED_SIZE_SAMPLES);
if(guid == MF_MT_SAMPLE_SIZE)
return &(out.MF_MT_SAMPLE_SIZE);
if(guid == MF_MT_VIDEO_PRIMARIES)
return &(out.MF_MT_VIDEO_PRIMARIES);
if(guid == MF_MT_INTERLACE_MODE)
return &(out.MF_MT_INTERLACE_MODE);
return NULL;
}
HRESULT LogAttributeValueByIndexNew(IMFAttributes *pAttr, DWORD index, WinMfMediaType &out) {
WCHAR *pGuidName = NULL;
WCHAR *pGuidValName = NULL;
GUID guid = { 0 };
PROPVARIANT var;
PropVariantInit(&var);
HRESULT hr = pAttr->GetItemByIndex(index, &guid, &var);
if(FAILED(hr)) {
goto done;
}
hr = GetGUIDNameNew(guid, &pGuidName);
if(FAILED(hr)) {
goto done;
}
hr = SpecialCaseAttributeValueNew(guid, var, out);
unsigned int *p;
if(FAILED(hr)) {
goto done;
}
if(hr == S_FALSE) {
switch(var.vt) {
case VT_UI4:
p = GetParametr(guid, out);
if(p) {
*p = var.ulVal;
}
break;
case VT_UI8:
break;
case VT_R8:
break;
case VT_CLSID:
if(guid == MF_MT_AM_FORMAT_TYPE) {
hr = GetGUIDNameNew(*var.puuid, &pGuidValName);
if(SUCCEEDED(hr)) {
out.MF_MT_AM_FORMAT_TYPE = MF_MT_AM_FORMAT_TYPE;
out.pMF_MT_AM_FORMAT_TYPEName = pGuidValName;
pGuidValName = NULL;
}
}
if(guid == MF_MT_MAJOR_TYPE) {
hr = GetGUIDNameNew(*var.puuid, &pGuidValName);
if(SUCCEEDED(hr)) {
out.MF_MT_MAJOR_TYPE = MF_MT_MAJOR_TYPE;
out.pMF_MT_MAJOR_TYPEName = pGuidValName;
pGuidValName = NULL;
}
}
if(guid == MF_MT_SUBTYPE) {
hr = GetGUIDNameNew(*var.puuid, &pGuidValName);
if(SUCCEEDED(hr)) {
out.MF_MT_SUBTYPE = MF_MT_SUBTYPE;
out.pMF_MT_SUBTYPEName = pGuidValName;
pGuidValName = NULL;
}
}
break;
case VT_LPWSTR:
break;
case VT_VECTOR | VT_UI1:
break;
case VT_UNKNOWN:
break;
default:
break;
}
}
done:
CoTaskMemFree(pGuidName);
CoTaskMemFree(pGuidValName);
PropVariantClear(&var);
return hr;
}
HRESULT GetGUIDNameNew(const GUID& guid, WCHAR **ppwsz) {
HRESULT hr = S_OK;
WCHAR *pName = NULL;
LPCWSTR pcwsz = GetGUIDNameConstNew(guid);
if(pcwsz) {
size_t cchLength = 0;
hr = StringCchLengthW(pcwsz, STRSAFE_MAX_CCH, &cchLength);
if(FAILED(hr)) {
goto done;
}
pName = (WCHAR*)CoTaskMemAlloc((cchLength + 1) * sizeof(WCHAR));
if(pName == NULL) {
hr = E_OUTOFMEMORY;
goto done;
}
hr = StringCchCopyW(pName, cchLength + 1, pcwsz);
if(FAILED(hr)) {
goto done;
}
} else {
hr = StringFromCLSID(guid, &pName);
}
done:
if(FAILED(hr)) {
*ppwsz = NULL;
CoTaskMemFree(pName);
} else {
*ppwsz = pName;
}
return hr;
}
void LogUINT32AsUINT64New(const PROPVARIANT& var, UINT32 &uHigh, UINT32 &uLow) {
Unpack2UINT32AsUINT64(var.uhVal.QuadPart, &uHigh, &uLow);
}
float OffsetToFloatNew(const MFOffset& offset) {
return offset.value + (static_cast<float>(offset.fract) / 65536.0f);
}
HRESULT LogVideoAreaNew(const PROPVARIANT& var) {
if(var.caub.cElems < sizeof(MFVideoArea)) {
return S_OK;
}
MFVideoArea *pArea = (MFVideoArea*)var.caub.pElems;
return S_OK;
}
HRESULT SpecialCaseAttributeValueNew(GUID guid, const PROPVARIANT& var, WinMfMediaType &out) {
if(guid == MF_MT_FRAME_SIZE) {
UINT32 uHigh = 0, uLow = 0;
LogUINT32AsUINT64New(var, uHigh, uLow);
out.width = uHigh;
out.height = uLow;
out.MF_MT_FRAME_SIZE = out.width * out.height;
} else
if(guid == MF_MT_FRAME_RATE) {
UINT32 uHigh = 0, uLow = 0;
LogUINT32AsUINT64New(var, uHigh, uLow);
out.MF_MT_FRAME_RATE = uHigh;
out.MF_MT_FRAME_RATE_low = uLow;
} else
if(guid == MF_MT_FRAME_RATE_RANGE_MAX) {
UINT32 uHigh = 0, uLow = 0;
LogUINT32AsUINT64New(var, uHigh, uLow);
out.MF_MT_FRAME_RATE_RANGE_MAX = uHigh;
out.MF_MT_FRAME_RATE_RANGE_MAX_low = uLow;
} else
if(guid == MF_MT_FRAME_RATE_RANGE_MIN) {
UINT32 uHigh = 0, uLow = 0;
LogUINT32AsUINT64New(var, uHigh, uLow);
out.MF_MT_FRAME_RATE_RANGE_MIN = uHigh;
out.MF_MT_FRAME_RATE_RANGE_MIN_low = uLow;
} else
if(guid == MF_MT_PIXEL_ASPECT_RATIO) {
UINT32 uHigh = 0, uLow = 0;
LogUINT32AsUINT64New(var, uHigh, uLow);
out.MF_MT_PIXEL_ASPECT_RATIO = uHigh;
out.MF_MT_PIXEL_ASPECT_RATIO_low = uLow;
} else {
return S_FALSE;
}
return S_OK;
}
#ifndef IF_EQUAL_RETURN
#define IF_EQUAL_RETURN(param, val) if(val == param) return L#val
#endif
LPCWSTR GetGUIDNameConstNew(const GUID& guid) {
IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE);
IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE);
IF_EQUAL_RETURN(guid, MF_MT_SUBTYPE);
IF_EQUAL_RETURN(guid, MF_MT_ALL_SAMPLES_INDEPENDENT);
IF_EQUAL_RETURN(guid, MF_MT_FIXED_SIZE_SAMPLES);
IF_EQUAL_RETURN(guid, MF_MT_COMPRESSED);
IF_EQUAL_RETURN(guid, MF_MT_SAMPLE_SIZE);
IF_EQUAL_RETURN(guid, MF_MT_WRAPPED_TYPE);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_NUM_CHANNELS);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_SECOND);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_AVG_BYTES_PER_SECOND);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BLOCK_ALIGNMENT);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BITS_PER_SAMPLE);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_VALID_BITS_PER_SAMPLE);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_BLOCK);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_CHANNEL_MASK);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FOLDDOWN_MATRIX);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKREF);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKTARGET);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGREF);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGTARGET);
IF_EQUAL_RETURN(guid, MF_MT_AUDIO_PREFER_WAVEFORMATEX);
IF_EQUAL_RETURN(guid, MF_MT_AAC_PAYLOAD_TYPE);
IF_EQUAL_RETURN(guid, MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION);
IF_EQUAL_RETURN(guid, MF_MT_FRAME_SIZE);
IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE);
IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MAX);
IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MIN);
IF_EQUAL_RETURN(guid, MF_MT_PIXEL_ASPECT_RATIO);
IF_EQUAL_RETURN(guid, MF_MT_DRM_FLAGS);
IF_EQUAL_RETURN(guid, MF_MT_PAD_CONTROL_FLAGS);
IF_EQUAL_RETURN(guid, MF_MT_SOURCE_CONTENT_HINT);
IF_EQUAL_RETURN(guid, MF_MT_VIDEO_CHROMA_SITING);
IF_EQUAL_RETURN(guid, MF_MT_INTERLACE_MODE);
IF_EQUAL_RETURN(guid, MF_MT_TRANSFER_FUNCTION);
IF_EQUAL_RETURN(guid, MF_MT_VIDEO_PRIMARIES);
IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES);
IF_EQUAL_RETURN(guid, MF_MT_YUV_MATRIX);
IF_EQUAL_RETURN(guid, MF_MT_VIDEO_LIGHTING);
IF_EQUAL_RETURN(guid, MF_MT_VIDEO_NOMINAL_RANGE);
IF_EQUAL_RETURN(guid, MF_MT_GEOMETRIC_APERTURE);
IF_EQUAL_RETURN(guid, MF_MT_MINIMUM_DISPLAY_APERTURE);
IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_APERTURE);
IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_ENABLED);
IF_EQUAL_RETURN(guid, MF_MT_AVG_BITRATE);
IF_EQUAL_RETURN(guid, MF_MT_AVG_BIT_ERROR_RATE);
IF_EQUAL_RETURN(guid, MF_MT_MAX_KEYFRAME_SPACING);
IF_EQUAL_RETURN(guid, MF_MT_DEFAULT_STRIDE);
IF_EQUAL_RETURN(guid, MF_MT_PALETTE);
IF_EQUAL_RETURN(guid, MF_MT_USER_DATA);
IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE);
IF_EQUAL_RETURN(guid, MF_MT_MPEG_START_TIME_CODE);
IF_EQUAL_RETURN(guid, MF_MT_MPEG2_PROFILE);
IF_EQUAL_RETURN(guid, MF_MT_MPEG2_LEVEL);
IF_EQUAL_RETURN(guid, MF_MT_MPEG2_FLAGS);
IF_EQUAL_RETURN(guid, MF_MT_MPEG_SEQUENCE_HEADER);
IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_0);
IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_0);
IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_1);
IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_1);
IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_SRC_PACK);
IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_CTRL_PACK);
IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER);
IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_FORMAT);
IF_EQUAL_RETURN(guid, MF_MT_IMAGE_LOSS_TOLERANT);
IF_EQUAL_RETURN(guid, MF_MT_MPEG4_SAMPLE_DESCRIPTION);
IF_EQUAL_RETURN(guid, MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY);
IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_4CC);
IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_WAVE_FORMAT_TAG);
// Media types
IF_EQUAL_RETURN(guid, MFMediaType_Audio);
IF_EQUAL_RETURN(guid, MFMediaType_Video);
IF_EQUAL_RETURN(guid, MFMediaType_Protected);
IF_EQUAL_RETURN(guid, MFMediaType_SAMI);
IF_EQUAL_RETURN(guid, MFMediaType_Script);
IF_EQUAL_RETURN(guid, MFMediaType_Image);
IF_EQUAL_RETURN(guid, MFMediaType_HTML);
IF_EQUAL_RETURN(guid, MFMediaType_Binary);
IF_EQUAL_RETURN(guid, MFMediaType_FileTransfer);
IF_EQUAL_RETURN(guid, MFVideoFormat_AI44); // FCC('AI44')
IF_EQUAL_RETURN(guid, MFVideoFormat_ARGB32); // D3DFMT_A8R8G8B8
IF_EQUAL_RETURN(guid, MFVideoFormat_AYUV); // FCC('AYUV')
IF_EQUAL_RETURN(guid, MFVideoFormat_DV25); // FCC('dv25')
IF_EQUAL_RETURN(guid, MFVideoFormat_DV50); // FCC('dv50')
IF_EQUAL_RETURN(guid, MFVideoFormat_DVH1); // FCC('dvh1')
IF_EQUAL_RETURN(guid, MFVideoFormat_DVSD); // FCC('dvsd')
IF_EQUAL_RETURN(guid, MFVideoFormat_DVSL); // FCC('dvsl')
IF_EQUAL_RETURN(guid, MFVideoFormat_H264); // FCC('H264')
IF_EQUAL_RETURN(guid, MFVideoFormat_I420); // FCC('I420')
IF_EQUAL_RETURN(guid, MFVideoFormat_IYUV); // FCC('IYUV')
IF_EQUAL_RETURN(guid, MFVideoFormat_M4S2); // FCC('M4S2')
IF_EQUAL_RETURN(guid, MFVideoFormat_MJPG);
IF_EQUAL_RETURN(guid, MFVideoFormat_MP43); // FCC('MP43')
IF_EQUAL_RETURN(guid, MFVideoFormat_MP4S); // FCC('MP4S')
IF_EQUAL_RETURN(guid, MFVideoFormat_MP4V); // FCC('MP4V')
IF_EQUAL_RETURN(guid, MFVideoFormat_MPG1); // FCC('MPG1')
IF_EQUAL_RETURN(guid, MFVideoFormat_MSS1); // FCC('MSS1')
IF_EQUAL_RETURN(guid, MFVideoFormat_MSS2); // FCC('MSS2')
IF_EQUAL_RETURN(guid, MFVideoFormat_NV11); // FCC('NV11')
IF_EQUAL_RETURN(guid, MFVideoFormat_NV12); // FCC('NV12')
IF_EQUAL_RETURN(guid, MFVideoFormat_P010); // FCC('P010')
IF_EQUAL_RETURN(guid, MFVideoFormat_P016); // FCC('P016')
IF_EQUAL_RETURN(guid, MFVideoFormat_P210); // FCC('P210')
IF_EQUAL_RETURN(guid, MFVideoFormat_P216); // FCC('P216')
IF_EQUAL_RETURN(guid, MFVideoFormat_RGB24); // D3DFMT_R8G8B8
IF_EQUAL_RETURN(guid, MFVideoFormat_RGB32); // D3DFMT_X8R8G8B8
IF_EQUAL_RETURN(guid, MFVideoFormat_RGB555); // D3DFMT_X1R5G5B5
IF_EQUAL_RETURN(guid, MFVideoFormat_RGB565); // D3DFMT_R5G6B5
IF_EQUAL_RETURN(guid, MFVideoFormat_RGB8);
IF_EQUAL_RETURN(guid, MFVideoFormat_UYVY); // FCC('UYVY')
IF_EQUAL_RETURN(guid, MFVideoFormat_v210); // FCC('v210')
IF_EQUAL_RETURN(guid, MFVideoFormat_v410); // FCC('v410')
IF_EQUAL_RETURN(guid, MFVideoFormat_WMV1); // FCC('WMV1')
IF_EQUAL_RETURN(guid, MFVideoFormat_WMV2); // FCC('WMV2')
IF_EQUAL_RETURN(guid, MFVideoFormat_WMV3); // FCC('WMV3')
IF_EQUAL_RETURN(guid, MFVideoFormat_WVC1); // FCC('WVC1')
IF_EQUAL_RETURN(guid, MFVideoFormat_Y210); // FCC('Y210')
IF_EQUAL_RETURN(guid, MFVideoFormat_Y216); // FCC('Y216')
IF_EQUAL_RETURN(guid, MFVideoFormat_Y410); // FCC('Y410')
IF_EQUAL_RETURN(guid, MFVideoFormat_Y416); // FCC('Y416')
IF_EQUAL_RETURN(guid, MFVideoFormat_Y41P);
IF_EQUAL_RETURN(guid, MFVideoFormat_Y41T);
IF_EQUAL_RETURN(guid, MFVideoFormat_YUY2); // FCC('YUY2')
IF_EQUAL_RETURN(guid, MFVideoFormat_YV12); // FCC('YV12')
IF_EQUAL_RETURN(guid, MFVideoFormat_YVYU);
IF_EQUAL_RETURN(guid, MFAudioFormat_PCM); // WAVE_FORMAT_PCM
IF_EQUAL_RETURN(guid, MFAudioFormat_Float); // WAVE_FORMAT_IEEE_FLOAT
IF_EQUAL_RETURN(guid, MFAudioFormat_DTS); // WAVE_FORMAT_DTS
IF_EQUAL_RETURN(guid, MFAudioFormat_Dolby_AC3_SPDIF); // WAVE_FORMAT_DOLBY_AC3_SPDIF
IF_EQUAL_RETURN(guid, MFAudioFormat_DRM); // WAVE_FORMAT_DRM
IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV8); // WAVE_FORMAT_WMAUDIO2
IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV9); // WAVE_FORMAT_WMAUDIO3
IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS
IF_EQUAL_RETURN(guid, MFAudioFormat_WMASPDIF); // WAVE_FORMAT_WMASPDIF
IF_EQUAL_RETURN(guid, MFAudioFormat_MSP1); // WAVE_FORMAT_WMAVOICE9
IF_EQUAL_RETURN(guid, MFAudioFormat_MP3); // WAVE_FORMAT_MPEGLAYER3
IF_EQUAL_RETURN(guid, MFAudioFormat_MPEG); // WAVE_FORMAT_MPEG
IF_EQUAL_RETURN(guid, MFAudioFormat_AAC); // WAVE_FORMAT_MPEG_HEAAC
IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC
return NULL;
}
WinMfFormatReader::WinMfFormatReader(void) {}
WinMfMediaType WinMfFormatReader::Read(IMFMediaType *pType) {
UINT32 count = 0;
HRESULT hr = S_OK;
WinMfMediaType out;
hr = pType->LockStore();
if(FAILED(hr)) {
return out;
}
hr = pType->GetCount(&count);
if(FAILED(hr)) {
return out;
}
for(UINT32 i = 0; i < count; i++) {
hr = LogAttributeValueByIndexNew(pType, i, out);
if(FAILED(hr)) {
break;
}
}
hr = pType->UnlockStore();
if(FAILED(hr)) {
return out;
}
return out;
}
WinMfFormatReader::~WinMfFormatReader(void) {}
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef WinMfFormatReader_h__
#define WinMfFormatReader_h__
#include <guiddef.h>
#include "WinMfMediaType.h"
struct IMFMediaType;
namespace LifeCore {
/// Class for parsing info from IMFMediaType into the local MediaType
class WinMfFormatReader {
public:
static WinMfMediaType Read(IMFMediaType *pType);
~WinMfFormatReader(void);
private:
WinMfFormatReader(void);
};
}
#endif // WinMfFormatReader_h__
+342
View File
@@ -0,0 +1,342 @@
#include "WinMfImageGrabber.h"
#include <mfapi.h>
#include "../log/NLog.h"
#include "../Utils.h"
#include "WinMfFormatReader.h"
#include "WinMfMediaType.h"
#include <shlwapi.h>
#include "WebCamera.h"
#include "../Com.h"
namespace LifeCore {
WinMfImageGrabber::WinMfImageGrabber(WebCamera* cam)
: m_cRef(1), ig_pSession(nullptr), camera(cam)
{
}
WinMfImageGrabber::~WinMfImageGrabber() {
LogInfo() << "~WinMfImageGrabber ";
/*if(ig_pSession) {
LogInfo() << "~WinMfImageGrabber shutdown session";
ig_pSession->Shutdown();
}*/
}
HRESULT WinMfImageGrabber::initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat) {
IMFActivate *pSinkActivate = NULL;/**/
IMFMediaType *pType = NULL;/**/
IMFPresentationDescriptor *pPD = NULL;/**/
IMFStreamDescriptor *pSD = NULL;/**/
IMFMediaTypeHandler *pHandler = NULL;/**/
IMFMediaType *pCurrentType = NULL;/**/
WinMfMediaType MT;
auto hr = pSource->CreatePresentationDescriptor(&pPD);
if(FAILED(hr)) {
LogError() << "Failed to create presentation descriptor!";
goto err;
}
BOOL fSelected;
hr = pPD->GetStreamDescriptorByIndex(0, &fSelected, &pSD);
if(FAILED(hr)) {
goto err;
}
hr = pSD->GetMediaTypeHandler(&pHandler);
if(FAILED(hr)) {
goto err;
}
DWORD cTypes = 0;
hr = pHandler->GetMediaTypeCount(&cTypes);
if(FAILED(hr)) {
goto err;
}
if(cTypes > 0) {
hr = pHandler->GetCurrentMediaType(&pCurrentType);
if(FAILED(hr)) {
goto err;
}
MT = WinMfFormatReader::Read(pCurrentType);
}
err:
SafeRelease(&pPD);
SafeRelease(&pSD);
SafeRelease(&pHandler);
SafeRelease(&pCurrentType);
unsigned int sizeRawImage = 0;
if(VideoFormat == MFVideoFormat_RGB24) {
sizeRawImage = MT.MF_MT_FRAME_SIZE * 3;
} else if(VideoFormat == MFVideoFormat_RGB32) {
sizeRawImage = MT.MF_MT_FRAME_SIZE * 4;
}
buffer_first = new RawBuffer<uint8>(sizeRawImage, MT);
buffer_second = new RawBuffer<uint8>(sizeRawImage, MT);
buffer_active = buffer_second;
hr = MFCreateMediaType(&pType);
hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
hr = pType->SetGUID(MF_MT_SUBTYPE, VideoFormat);
// Create the sample grabber sink.
hr = MFCreateSampleGrabberSinkActivate(pType, this, &pSinkActivate);
// To run as fast as possible, set this attribute (requires Windows 7):
hr = pSinkActivate->SetUINT32(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, TRUE);
// Create the Media Session.
hr = MFCreateMediaSession(NULL, &ig_pSession);
// Create the topology.
hr = CreateTopology(pSource, pSinkActivate, &ig_pTopology);
SafeRelease(&pSinkActivate);
SafeRelease(&pType);
return S_OK;
}
RawBuffer<uint8>* WinMfImageGrabber::GetImage() {
return buffer_active;
}
#define CHECK_HR(x) if (FAILED(x)) { goto done; }
HRESULT WinMfImageGrabber::CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo) {
IMFTopology *pTopology = NULL;
IMFPresentationDescriptor *pPD = NULL;
IMFStreamDescriptor *pSD = NULL;
IMFMediaTypeHandler *pHandler = NULL;
IMFTopologyNode *pNode1 = NULL;
IMFTopologyNode *pNode2 = NULL;
HRESULT hr = S_OK;
DWORD cStreams = 0;
CHECK_HR(hr = MFCreateTopology(&pTopology));
CHECK_HR(hr = pSource->CreatePresentationDescriptor(&pPD));
CHECK_HR(hr = pPD->GetStreamDescriptorCount(&cStreams));
for(DWORD i = 0; i < cStreams; i++) {
// In this example, we look for audio streams and connect them to the sink.
BOOL fSelected = FALSE;
GUID majorType;
CHECK_HR(hr = pPD->GetStreamDescriptorByIndex(i, &fSelected, &pSD));
CHECK_HR(hr = pSD->GetMediaTypeHandler(&pHandler));
CHECK_HR(hr = pHandler->GetMajorType(&majorType));
if(majorType == MFMediaType_Video && fSelected) {
CHECK_HR(hr = AddSourceNode(pTopology, pSource, pPD, pSD, &pNode1));
CHECK_HR(hr = AddOutputNode(pTopology, pSinkActivate, 0, &pNode2));
CHECK_HR(hr = pNode1->ConnectOutput(0, pNode2, 0));
break;
} else {
CHECK_HR(hr = pPD->DeselectStream(i));
}
SafeRelease(&pSD);
SafeRelease(&pHandler);
}
*ppTopo = pTopology;
(*ppTopo)->AddRef();
done:
SAFE_RELEASE(pTopology);
SAFE_RELEASE(pNode1);
SAFE_RELEASE(pNode2);
SAFE_RELEASE(pPD);
SAFE_RELEASE(pSD);
SAFE_RELEASE(pHandler);
return hr;
}
HRESULT WinMfImageGrabber::AddSourceNode(
IMFTopology *pTopology, // Topology.
IMFMediaSource *pSource, // Media source.
IMFPresentationDescriptor *pPD, // Presentation descriptor.
IMFStreamDescriptor *pSD, // Stream descriptor.
IMFTopologyNode **ppNode) // Receives the node pointer.
{
IMFTopologyNode *pNode = NULL;
HRESULT hr = S_OK;
CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &pNode));
CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_SOURCE, pSource));
CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, pPD));
CHECK_HR(hr = pNode->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, pSD));
CHECK_HR(hr = pTopology->AddNode(pNode));
// Return the pointer to the caller.
*ppNode = pNode;
(*ppNode)->AddRef();
done:
SafeRelease(&pNode);
return hr;
}
HRESULT WinMfImageGrabber::AddOutputNode(
IMFTopology *pTopology, // Topology.
IMFActivate *pActivate, // Media sink activation object.
DWORD dwId, // Identifier of the stream sink.
IMFTopologyNode **ppNode) // Receives the node pointer.
{
IMFTopologyNode *pNode = NULL;
HRESULT hr = S_OK;
CHECK_HR(hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pNode));
CHECK_HR(hr = pNode->SetObject(pActivate));
CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_STREAMID, dwId));
CHECK_HR(hr = pNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE));
CHECK_HR(hr = pTopology->AddNode(pNode));
// Return the pointer to the caller.
*ppNode = pNode;
(*ppNode)->AddRef();
done:
SafeRelease(&pNode);
return hr;
}
HRESULT WinMfImageGrabber::startGrabbing(void) {
PROPVARIANT var;
PropVariantInit(&var);
HRESULT hr = S_OK;
hr = ig_pSession->SetTopology(0, ig_pTopology);
hr = ig_pSession->Start(&GUID_NULL, &var);
return hr;
}
bool WinMfImageGrabber::processGrabbing() {
HRESULT hrStatus = S_OK;
MediaEventType met;
HRESULT hr;
IMFMediaEvent *pEvent = NULL;
if(!ig_pSession) return false;
hr = ig_pSession->GetEvent(0, &pEvent);
if(!SUCCEEDED(hr)) {
hr = S_OK;
return false;
}
hr = pEvent->GetStatus(&hrStatus);
if(!SUCCEEDED(hr)) {
hr = S_OK;
return false;
}
hr = pEvent->GetType(&met);
if(!SUCCEEDED(hr)) {
hr = S_OK;
return false;
}
if(met == MESessionEnded) {
LogInfo() << "IMAGEGRABBER VIDEODEVICE %i: MESessionEnded ";
ig_pSession->Stop();
return false;
}
if(met == MESessionStopped) {
LogInfo() << "IMAGEGRABBER VIDEODEVICE %i: MESessionStopped";
return false;
}
if(met == MEVideoCaptureDeviceRemoved) {
LogInfo() << "IMAGEGRABBER VIDEODEVICE %i: MEVideoCaptureDeviceRemoved";
return false;
}
SafeRelease(&pEvent);
return true;
}
void WinMfImageGrabber::stopGrabbing() {
if(ig_pSession) {
ig_pSession->Stop();
ig_pSession->Shutdown();
SAFE_RELEASE(ig_pSession);
SAFE_RELEASE(ig_pTopology);
}
/*IMFMediaSource *ig_pSource;
IMFMediaSession *ig_pSession;
IMFTopology *ig_pTopology;*/
}
// IUnknown methods
STDMETHODIMP WinMfImageGrabber::QueryInterface(REFIID iid, void** ppv) {
// Creation tab of shifting interfaces from start of this class
static const QITAB qit[] = {
QITABENT(WinMfImageGrabber, IMFSampleGrabberSinkCallback),
QITABENT(WinMfImageGrabber, IMFClockStateSink), { 0 }
};
return QISearch(this, qit, iid, ppv);
}
STDMETHODIMP_(ULONG) WinMfImageGrabber::AddRef() {
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) WinMfImageGrabber::Release() {
ULONG cRef = InterlockedDecrement(&m_cRef);
if(cRef == 0) {
delete this;
}
return cRef;
}
// IMFClockStateSink methods
STDMETHODIMP WinMfImageGrabber::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset) {
return S_OK;
}
STDMETHODIMP WinMfImageGrabber::OnClockStop(MFTIME hnsSystemTime) {
return S_OK;
}
STDMETHODIMP WinMfImageGrabber::OnClockPause(MFTIME hnsSystemTime) {
return S_OK;
}
STDMETHODIMP WinMfImageGrabber::OnClockRestart(MFTIME hnsSystemTime) {
return S_OK;
}
STDMETHODIMP WinMfImageGrabber::OnClockSetRate(MFTIME hnsSystemTime, float flRate) {
return S_OK;
}
// IMFSampleGrabberSinkCallback methods
STDMETHODIMP WinMfImageGrabber::OnSetPresentationClock(IMFPresentationClock* pClock) {
return S_OK;
}
STDMETHODIMP WinMfImageGrabber::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer,
DWORD dwSampleSize)
{
LogInfo() << "Process sample";
buffer_active->SetData((void*)pSampleBuffer);
camera->OnImageGrabbed(this, buffer_active);
return 0;
}
STDMETHODIMP WinMfImageGrabber::OnShutdown() {
return S_OK;
}
}
+65
View File
@@ -0,0 +1,65 @@
#ifndef WinMfImageGrabber_h__
#define WinMfImageGrabber_h__
#include <mfidl.h>
#include "../RawBuffer.h"
#include "../Types.h"
namespace LifeCore {
class WebCamera;
class WinMfImageGrabber : IMFSampleGrabberSinkCallback {
public:
WinMfImageGrabber(WebCamera* cam);
~WinMfImageGrabber();
HRESULT initImageGrabber(IMFMediaSource *pSource, GUID VideoFormat);
HRESULT startGrabbing(void);
void stopGrabbing();
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IMFClockStateSink methods
STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset);
STDMETHODIMP OnClockStop(MFTIME hnsSystemTime);
STDMETHODIMP OnClockPause(MFTIME hnsSystemTime);
STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime);
STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate);
// IMFSampleGrabberSinkCallback methods
STDMETHODIMP OnSetPresentationClock(IMFPresentationClock* pClock);
STDMETHODIMP OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer,
DWORD dwSampleSize);
STDMETHODIMP OnShutdown();
bool processGrabbing();
RawBuffer<uint8>* GetImage();
private:
WebCamera* camera;
long m_cRef;
//IMFMediaSource *ig_pSource;
IMFMediaSession *ig_pSession;
IMFTopology *ig_pTopology;
RawBuffer<uint8>* buffer_first;
RawBuffer<uint8>* buffer_second;
RawBuffer<uint8>* buffer_active;
HRESULT CreateTopology(IMFMediaSource *pSource, IMFActivate *pSinkActivate, IMFTopology **ppTopo);
HRESULT AddSourceNode(
IMFTopology *pTopology,
IMFMediaSource *pSource,
IMFPresentationDescriptor *pPD,
IMFStreamDescriptor *pSD,
IMFTopologyNode **ppNode);
HRESULT AddOutputNode(
IMFTopology *pTopology,
IMFActivate *pActivate,
DWORD dwId,
IMFTopologyNode **ppNode);
};
}
#endif // WinMfImageGrabber_h__
+129
View File
@@ -0,0 +1,129 @@
#ifndef WinMfMediaType_h__
#define WinMfMediaType_h__
#include <guiddef.h>
namespace LifeCore {
// Structure for collecting info about types of video, which are supported by current video device
struct WinMfMediaType {
unsigned int MF_MT_FRAME_SIZE;
unsigned int height;
unsigned int width;
unsigned int MF_MT_YUV_MATRIX;
unsigned int MF_MT_VIDEO_LIGHTING;
unsigned int MF_MT_DEFAULT_STRIDE;
unsigned int MF_MT_VIDEO_CHROMA_SITING;
GUID MF_MT_AM_FORMAT_TYPE;
wchar_t *pMF_MT_AM_FORMAT_TYPEName;
unsigned int MF_MT_FIXED_SIZE_SAMPLES;
unsigned int MF_MT_VIDEO_NOMINAL_RANGE;
unsigned int MF_MT_FRAME_RATE;
unsigned int MF_MT_FRAME_RATE_low;
unsigned int MF_MT_PIXEL_ASPECT_RATIO;
unsigned int MF_MT_PIXEL_ASPECT_RATIO_low;
unsigned int MF_MT_ALL_SAMPLES_INDEPENDENT;
unsigned int MF_MT_FRAME_RATE_RANGE_MIN;
unsigned int MF_MT_FRAME_RATE_RANGE_MIN_low;
unsigned int MF_MT_SAMPLE_SIZE;
unsigned int MF_MT_VIDEO_PRIMARIES;
unsigned int MF_MT_INTERLACE_MODE;
unsigned int MF_MT_FRAME_RATE_RANGE_MAX;
unsigned int MF_MT_FRAME_RATE_RANGE_MAX_low;
GUID MF_MT_MAJOR_TYPE;
wchar_t *pMF_MT_MAJOR_TYPEName;
GUID MF_MT_SUBTYPE;
wchar_t *pMF_MT_SUBTYPEName;
WinMfMediaType() {
pMF_MT_AM_FORMAT_TYPEName = NULL;
pMF_MT_MAJOR_TYPEName = NULL;
pMF_MT_SUBTYPEName = NULL;
Clear();
}
~WinMfMediaType() {
Clear();
}
void Clear() {
MF_MT_FRAME_SIZE = 0;
height = 0;
width = 0;
MF_MT_YUV_MATRIX = 0;
MF_MT_VIDEO_LIGHTING = 0;
MF_MT_DEFAULT_STRIDE = 0;
MF_MT_VIDEO_CHROMA_SITING = 0;
MF_MT_FIXED_SIZE_SAMPLES = 0;
MF_MT_VIDEO_NOMINAL_RANGE = 0;
MF_MT_FRAME_RATE = 0;
MF_MT_FRAME_RATE_low = 0;
MF_MT_PIXEL_ASPECT_RATIO = 0;
MF_MT_PIXEL_ASPECT_RATIO_low = 0;
MF_MT_ALL_SAMPLES_INDEPENDENT = 0;
MF_MT_FRAME_RATE_RANGE_MIN = 0;
MF_MT_FRAME_RATE_RANGE_MIN_low = 0;
MF_MT_SAMPLE_SIZE = 0;
MF_MT_VIDEO_PRIMARIES = 0;
MF_MT_INTERLACE_MODE = 0;
MF_MT_FRAME_RATE_RANGE_MAX = 0;
MF_MT_FRAME_RATE_RANGE_MAX_low = 0;
memset(&MF_MT_MAJOR_TYPE, 0, sizeof(GUID));
memset(&MF_MT_AM_FORMAT_TYPE, 0, sizeof(GUID));
memset(&MF_MT_SUBTYPE, 0, sizeof(GUID));
}
};
}
#endif // WinMfMediaType_h__