diff options
| author | Adonais Romero González <[email protected]> | 2024-05-06 16:21:31 -0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-05-06 16:21:31 -0700 |
| commit | a74a241c664c4e1d7c0838287b34076c19d9858a (patch) | |
| tree | 6ff7562612967b122acf8acf8a69c4dcfd5905db /avstream/sampledevicemft/SampleSocDeviceMFTutils.cpp | |
| parent | def8e8e34ed2b7b1deb2fc9112ac4255f1a0f2ba (diff) | |
| parent | 15477ce52bbb6b42ca591ecdfb484cac089f89ab (diff) | |
Merge develop changes prior to upcoming WDK release (May 2024)
Diffstat (limited to 'avstream/sampledevicemft/SampleSocDeviceMFTutils.cpp')
| -rw-r--r-- | avstream/sampledevicemft/SampleSocDeviceMFTutils.cpp | 1320 |
1 files changed, 1320 insertions, 0 deletions
diff --git a/avstream/sampledevicemft/SampleSocDeviceMFTutils.cpp b/avstream/sampledevicemft/SampleSocDeviceMFTutils.cpp new file mode 100644 index 00000000..1b41496b --- /dev/null +++ b/avstream/sampledevicemft/SampleSocDeviceMFTutils.cpp @@ -0,0 +1,1320 @@ +//*@@@+++@@@@****************************************************************** +// +// Microsoft Windows Media Foundation +// Copyright (C) Microsoft Corporation. All rights reserved. +// +//*@@@---@@@@****************************************************************** +// + +#include "stdafx.h" +#include "common.h" +#include "multipinmft.h" +#include "basepin.h" + +#pragma comment(lib, "d2d1") +#ifdef MF_WPP +#include "multipinmftutils.tmh" //--REF_ANALYZER_DONT_REMOVE-- +#endif + +// Critical sections + +CCritSec::CCritSec() +{ + InitializeCriticalSection(&m_criticalSection); +} + +CCritSec::~CCritSec() +{ + DeleteCriticalSection(&m_criticalSection); +} + +_Requires_lock_not_held_(m_criticalSection) _Acquires_lock_(m_criticalSection) +void CCritSec::Lock() +{ + EnterCriticalSection(&m_criticalSection); +} + +_Requires_lock_held_(m_criticalSection) _Releases_lock_(m_criticalSection) +void CCritSec::Unlock() +{ + LeaveCriticalSection(&m_criticalSection); +} + + +_Acquires_lock_(this->m_pCriticalSection->m_criticalSection) +CAutoLock::CAutoLock(CCritSec& crit) +{ + m_pCriticalSection = &crit; + m_pCriticalSection->Lock(); +} +_Acquires_lock_(this->m_pCriticalSection->m_criticalSection) +CAutoLock::CAutoLock(CCritSec* crit) +{ + m_pCriticalSection = crit; + m_pCriticalSection->Lock(); +} +_Releases_lock_(this->m_pCriticalSection->m_criticalSection) +CAutoLock::~CAutoLock() +{ + m_pCriticalSection->Unlock(); +} + +// +//Some utility functions.. +// + +/*++ + Description: + Used to check if the input and the output Image types are optinmized or not +--*/ + +STDMETHODIMP IsOptimizedPlanarVideoInputImageOutputPair( + _In_ IMFMediaType *inMediaType, + _In_ IMFMediaType *outMediaType, + _Out_ bool *optimized, + _Out_ bool *optimizedxvpneeded ) +{ + HRESULT hr = S_OK; + GUID guidInputSubType = GUID_NULL; + GUID guidOutputSubType = GUID_NULL; + UINT32 uWidthIn = 0, uHeightIn = 0, uWidthOut = 0, uHeightOut = 0; + + + DMFTCHECKHR_GOTO(inMediaType->GetGUID(MF_MT_SUBTYPE, &guidInputSubType), done); + + DMFTCHECKHR_GOTO(outMediaType->GetGUID(MF_MT_SUBTYPE, &guidOutputSubType), done); + + *optimized = false; //Assume we aren't optimized . Optimized = (ip = YU12|NV12 and op = JPEG) + *optimizedxvpneeded = true; //Assume we need xvps + + if (IsEqualGUID(guidInputSubType, MFVideoFormat_YV12) || IsEqualGUID(guidInputSubType, MFVideoFormat_NV12)) + { + if (IsEqualGUID(guidOutputSubType, GUID_ContainerFormatJpeg)) + { + *optimized = true; + } + } + + if (!*optimized) + { + goto done; + } + + DMFTCHECKHR_GOTO(MFGetAttributeSize(inMediaType, MF_MT_FRAME_SIZE, &uWidthIn, &uHeightIn), done); + DMFTCHECKHR_GOTO(MFGetAttributeSize(outMediaType, MF_MT_FRAME_SIZE, &uWidthOut, &uHeightOut), done); + + if ((uWidthIn == uWidthOut) && (uHeightIn == uHeightOut)) + { + *optimizedxvpneeded = false; + } + if (!*optimizedxvpneeded) + { + UINT32 nominalRange; + hr = inMediaType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange); + + if (FAILED(hr) || nominalRange != MFNominalRange_0_255) + { + //XVP needed since nominal range is not 0-255 for YV12 or NV12 fed into WIC + *optimizedxvpneeded = true; + } + hr = S_OK; + } + +done: + return hr; +} + + +/* +Description: + + This is used whenever there is a media type change on an output pin and the + Output queue is being reconfigured. + The possible return values for the function are as follows + + DeviceMftTransformXVPIllegal -> If either of the mediatypes or both are NULL + DeviceMftTransformXVPDisruptiveIn -> If the mediatype at the output pin is greater than the input pin. This will result in change of the media type on the input + DeviceMftTransformXVPDisruptiveOut -> This is a reconfiguration or addition of the XVP in the Output pin queue + DeviceMftTransformXVPCurrent -> No XVP needed at all +*/ +STDMETHODIMP CompareMediaTypesForConverter( + _In_opt_ IMFMediaType *inMediaType, + _In_ IMFMediaType *newMediaType, + _Inout_ PDMFT_conversion_type operation + ) +{ + HRESULT hr = S_OK; + GUID guidTypeA = GUID_NULL; + GUID guidTypeB = GUID_NULL; + + *operation = DeviceMftTransformTypeIllegal; + if ((!inMediaType) || (!newMediaType)) + { + goto done; + } + + if ( SUCCEEDED( inMediaType->GetGUID( MF_MT_MAJOR_TYPE, &guidTypeA ) ) && + SUCCEEDED( newMediaType->GetGUID( MF_MT_MAJOR_TYPE, &guidTypeB ) ) && + IsEqualGUID( guidTypeA, guidTypeB ) ) + { + if ( SUCCEEDED( inMediaType->GetGUID ( MF_MT_SUBTYPE, &guidTypeA ) ) && + SUCCEEDED( newMediaType->GetGUID( MF_MT_SUBTYPE, &guidTypeB ) ) && + IsEqualGUID( guidTypeA, guidTypeB ) ) + { + BOOL passThrough = TRUE; + DMFTCHECKHR_GOTO(CheckPassthroughMediaType(inMediaType, newMediaType, passThrough), done); + *operation = passThrough?DeviceMftTransformTypeEqual: DeviceMftTransformTypeXVP; + } + else + { + //This is a disruptive operation. Actually a decoder operation! + *operation = DeviceMftTransformTypeDecoder; + } + } + done: + return hr; +} + +/*++ +Description: Used to test if the sample passed is a DX sample or not? +--*/ +HRESULT IsInputDxSample( + _In_ IMFSample* pSample, + _Inout_ BOOL *isDxSample + ) +{ + HRESULT hr = S_OK; + ComPtr<IMFMediaBuffer> spBuffer = nullptr; + DMFTCHECKNULL_GOTO( pSample, done, E_INVALIDARG ); + + *isDxSample = false; + if ( SUCCEEDED( pSample->GetBufferByIndex( 0, &spBuffer ) ) ) + { + ComPtr<IMFDXGIBuffer> spDXGIBuffer; + ComPtr<ID3D11Texture2D> spResourceTexture; + if ( SUCCEEDED( spBuffer.As(&spDXGIBuffer ) ) && + SUCCEEDED( spDXGIBuffer-> GetResource( IID_PPV_ARGS( &spResourceTexture ) ) ) ) + { + *isDxSample = true; + } + } +done: + return hr; +} + + +/*++ + Description: + Helper function to return back if the Pin is in stopped stateo or not +--*/ +STDMETHODIMP_(BOOL) IsPinStateInActive( _In_ DeviceStreamState state) +{ + if ((state == DeviceStreamState_Disabled) || + (state == DeviceStreamState_Stop)) + { + return TRUE; + } + return FALSE; +} + +/* +Description: + A Helper function to return if the Mediatype is a compressed video type or not! +*/ +STDMETHODIMP_(BOOL) IsKnownUncompressedVideoType(_In_ GUID guidSubType) +{ + if (guidSubType == MFVideoFormat_ARGB32 || + guidSubType == MFVideoFormat_RGB24 || + guidSubType == MFVideoFormat_RGB555 || + guidSubType == MFVideoFormat_RGB565 || + guidSubType == MFVideoFormat_RGB32 || + guidSubType == MFVideoFormat_RGB8 || + guidSubType == MFVideoFormat_AI44 || + guidSubType == MFVideoFormat_AYUV || + guidSubType == MFVideoFormat_YUY2 || + guidSubType == MFVideoFormat_YVYU || + guidSubType == MFVideoFormat_YVU9 || + guidSubType == MFVideoFormat_UYVY || + guidSubType == MFVideoFormat_NV11 || + guidSubType == MFVideoFormat_NV12 || + guidSubType == MFVideoFormat_YV12 || + guidSubType == MFVideoFormat_I420 || + guidSubType == MFVideoFormat_IYUV || + guidSubType == MFVideoFormat_Y210 || + guidSubType == MFVideoFormat_Y216 || + guidSubType == MFVideoFormat_Y410 || + guidSubType == MFVideoFormat_Y416 || + guidSubType == MFVideoFormat_Y41P || + guidSubType == MFVideoFormat_Y41T || + guidSubType == MFVideoFormat_Y42T || + guidSubType == MFVideoFormat_P210 || + guidSubType == MFVideoFormat_P216 || + guidSubType == MFVideoFormat_P010 || + guidSubType == MFVideoFormat_P016 || + guidSubType == MFVideoFormat_v210 || + guidSubType == MFVideoFormat_v216 || + guidSubType == MFVideoFormat_v410 || + guidSubType == MFVideoFormat_L8 || + guidSubType == MFVideoFormat_L16 || + guidSubType == MFVideoFormat_D16) + { + return( TRUE ); + } + + return( FALSE ); +} + +#ifndef IF_EQUAL_RETURN +#define IF_EQUAL_RETURN(param, val) if(val == param) return #val +#endif + +#define checkAdjustBufferCap(a,len){\ + char* tStore = NULL; \ +if (a && strlen(a) > ((len * 7) / 10)){\ + tStore = a; \ + len *= 2; \ + a = new (std::nothrow) char[len]; \ +if (!a){\ +goto done;}\ + a[0] = 0; \ + strcat_s(a, len, tStore); \ + delete(tStore); }\ +} + + +/*++ +Description: + returns an ascii buffer for the GUID passed. The Caller should release the memory allocated +--*/ +LPSTR DumpGUIDA(_In_ REFGUID guid) +{ + LPOLESTR lpszGuidString = NULL; + char *ansiguidStr = NULL; + if (SUCCEEDED(StringFromCLSID(guid, &lpszGuidString))) + { + int mbGuidLen = 0; + mbGuidLen = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, lpszGuidString, -1, NULL, 0, NULL, NULL); + if (mbGuidLen > 0) + { + mf_assert(mbGuidLen == (int)wcslen(lpszGuidString)); + ansiguidStr = new (std::nothrow) char[mbGuidLen]; + if (ansiguidStr) + { + WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, lpszGuidString, -1, ansiguidStr, mbGuidLen, NULL, NULL); + CoTaskMemFree(lpszGuidString); + ansiguidStr[mbGuidLen - 1] = 0; + } + } + } + return ansiguidStr; +} + +// +//Borrrowed from MDSN sample +// +LPCSTR GetGUIDNameConst(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; +} + + +LPSTR DumpAttribute( _In_ const MF_ATTRIBUTE_TYPE& type, + _In_ REFPROPVARIANT var) +{ + CHAR *tempStr = NULL; + tempStr = new (std::nothrow) CHAR[256]; + switch (type) + { + case MF_ATTRIBUTE_UINT32: + if (var.vt == VT_UI4) + { + sprintf_s(tempStr, 256, "%u", var.ulVal); + } + break; + case MF_ATTRIBUTE_UINT64: + if (var.vt == VT_UI8) + { + sprintf_s(tempStr, 256, "%I64d (high: %d low: %d)", var.uhVal.QuadPart, var.uhVal.HighPart, var.uhVal.LowPart); + } + break; + case MF_ATTRIBUTE_DOUBLE: + if (var.vt == VT_R8) + { + sprintf_s(tempStr, 256, "%.4f", var.dblVal); + } + break; + case MF_ATTRIBUTE_GUID: + if (var.vt == VT_CLSID) + { + return DumpGUIDA(*var.puuid); + } + break; + case MF_ATTRIBUTE_STRING: + if (var.vt == VT_LPWSTR) + { + sprintf_s(tempStr, 256, "%S", var.pwszVal); + } + break; + case MF_ATTRIBUTE_IUNKNOWN: + break; + default: + printf("(Unknown Attribute Type = %d) ", type); + break; + } + return tempStr; +} + +CMediaTypePrinter::CMediaTypePrinter( + _In_ IMFMediaType *_pMediaType ) + : pMediaType(_pMediaType), + m_pBuffer(NULL) +{ +} + +CMediaTypePrinter::~CMediaTypePrinter() +{ + if (m_pBuffer) + { + delete(m_pBuffer); + } +} + +/*++ +Description: +Rudimentary function to print the complete Media type +--*/ +PCHAR CMediaTypePrinter::ToCompleteString( ) +{ + HRESULT hr = S_OK; + UINT32 attrCount = 0; + GUID attrGuid = { 0 }; + char *tempStore = nullptr; + PROPVARIANT var; + LPSTR pTempBaseStr; + MF_ATTRIBUTE_TYPE pType; + + if ( pMediaType && !m_pBuffer ) + { + DMFTCHECKHR_GOTO(pMediaType->GetCount(&attrCount), done); + buffLen = MEDIAPRINTER_STARTLEN; + m_pBuffer = new char[buffLen]; + DMFTCHECKNULL_GOTO(m_pBuffer, done, E_OUTOFMEMORY); + m_pBuffer[0] = 0; + for ( UINT32 ulIndex = 0; ulIndex < attrCount; ulIndex++ ) + { + PropVariantInit( &var ); + checkAdjustBufferCap( m_pBuffer, buffLen ); + DMFTCHECKHR_GOTO( pMediaType->GetItemByIndex( ulIndex, &attrGuid, &var ), done ); + DMFTCHECKHR_GOTO( pMediaType->GetItemType( attrGuid, &pType ), done ); + if ( ulIndex > 0 ) + strcat_s(m_pBuffer, MEDIAPRINTER_STARTLEN, " : "); + strcat_s( m_pBuffer, buffLen, GetGUIDNameConst( attrGuid ) ); + strcat_s( m_pBuffer, buffLen, "=" ); + pTempBaseStr = DumpAttribute( pType, var ); + strcat_s( m_pBuffer, buffLen, pTempBaseStr ); + delete( pTempBaseStr ); + PropVariantClear( &var ); + } + done: + if ( tempStore ) + { + delete( tempStore ); + } + } + return m_pBuffer; +} + +/*++ +Description: +Rudimentary function to print the Media type +--*/ + +PCHAR CMediaTypePrinter::ToString() +{ + // + //Following are the important ones of Mediatype attributes + // + + HRESULT hr = S_OK; + PROPVARIANT var; + LPSTR pTempBaseStr; + MF_ATTRIBUTE_TYPE pType; + GUID attrGuid; + GUID impGuids[] = { + MF_MT_SUBTYPE, + MF_MT_FRAME_SIZE, + MF_MT_SAMPLE_SIZE, + MF_MT_FRAME_RATE, + MF_MT_DEFAULT_STRIDE, + MF_XVP_DISABLE_FRC + }; + + if (pMediaType && !m_pBuffer) + { + buffLen = MEDIAPRINTER_STARTLEN; + m_pBuffer = new (std::nothrow) char[buffLen]; + DMFTCHECKNULL_GOTO(m_pBuffer, done, E_OUTOFMEMORY); + m_pBuffer[0] = 0; + for (UINT32 ulIndex = 0; ulIndex < ARRAYSIZE(impGuids); ulIndex++) + { + PropVariantInit(&var); + checkAdjustBufferCap(m_pBuffer, buffLen); + attrGuid = impGuids[ulIndex]; + DMFTCHECKHR_GOTO(pMediaType->GetItemType(attrGuid, &pType), done); + DMFTCHECKHR_GOTO(pMediaType->GetItem(attrGuid, &var), done); + if (ulIndex > 0) + strcat_s(m_pBuffer, MEDIAPRINTER_STARTLEN, " : "); + strcat_s(m_pBuffer, buffLen, GetGUIDNameConst(attrGuid)); + strcat_s(m_pBuffer, buffLen, "="); + pTempBaseStr = DumpAttribute(pType, var); + strcat_s(m_pBuffer, buffLen, pTempBaseStr); + delete(pTempBaseStr); + PropVariantClear(&var); + } + } +done: + return m_pBuffer; +} +/*++ +Description: + Debug message printer to print the message passed through WPP +--*/ +void printMessageEvent(MFT_MESSAGE_TYPE msg) +{ + switch (msg) + { + case MFT_MESSAGE_COMMAND_FLUSH: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_FLUSH"); + break; + case MFT_MESSAGE_COMMAND_DRAIN: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_DRAIN"); + break; + case MFT_MESSAGE_COMMAND_MARKER: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_MARKER"); + break; + case MFT_MESSAGE_COMMAND_TICK: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_TICK"); + break; + case MFT_MESSAGE_NOTIFY_END_OF_STREAM: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_END_OF_STREAM"); + break; + case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_BEGIN_STREAMING"); + break; + case MFT_MESSAGE_NOTIFY_START_OF_STREAM: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_START_OF_STREAM"); + break; + case MFT_MESSAGE_DROP_SAMPLES: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_DROP_SAMPLES"); + break; + case MFT_MESSAGE_SET_D3D_MANAGER: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_SET_D3D_MANAGER"); + break; + + } +} + +HRESULT GetDXGIAdapterLuid(_In_ IMFDXGIDeviceManager *pDXManager, _Out_ LUID &AdapterLuid) +{ + HRESULT hr = S_OK; + ComPtr<ID3D11Device> spDevice; + ComPtr<IDXGIDevice> spDXGIDevice; + ComPtr<IDXGIAdapter> spDXGIAdapter; + DXGI_ADAPTER_DESC adapterDesc = { 0 }; + HANDLE hDevice = NULL; + + DMFTCHECKNULL_GOTO(pDXManager, done, E_INVALIDARG); + + DMFTCHECKHR_GOTO(pDXManager->OpenDeviceHandle(&hDevice), done); + DMFTCHECKHR_GOTO(pDXManager->GetVideoService(hDevice, IID_PPV_ARGS(&spDevice)), done); + DMFTCHECKHR_GOTO(spDevice->QueryInterface(IID_PPV_ARGS(&spDXGIDevice)), done); + DMFTCHECKHR_GOTO(spDXGIDevice->GetAdapter(&spDXGIAdapter), done); + DMFTCHECKHR_GOTO(spDXGIAdapter->GetDesc(&adapterDesc), done); + + CopyMemory(&AdapterLuid, &adapterDesc.AdapterLuid, sizeof(LUID)); + +done: + if (NULL != hDevice) + { + pDXManager->CloseDeviceHandle(hDevice); + } + + return hr; +} + +HRESULT EnumSWDecoder(_Outptr_ IMFTransform** ppTransform, _In_ GUID subType) +{ + HRESULT hr = S_OK; + IMFActivate** ppActivate = nullptr; + UINT32 count = 0; + ComPtr<IMFTransform> spTransform; + LPWSTR pszFriendlyName = nullptr; + + MFT_REGISTER_TYPE_INFO info = { MFMediaType_Video, subType }; + UINT32 unFlags = MFT_ENUM_FLAG_SYNCMFT | + MFT_ENUM_FLAG_LOCALMFT | + MFT_ENUM_FLAG_SORTANDFILTER; + + DMFTCHECKNULL_GOTO(ppTransform, done, E_INVALIDARG); + *ppTransform = nullptr; + + DMFTCHECKHR_GOTO(MFTEnumEx(MFT_CATEGORY_VIDEO_DECODER, unFlags, + &info, // Input type + NULL, // Output type + &ppActivate, + &count + ), done); + + + if (count == 0) + { + DMFTCHECKHR_GOTO(MF_E_TOPO_CODEC_NOT_FOUND, done); + } + + if (SUCCEEDED(MFGetAttributeString(ppActivate[0], MFT_FRIENDLY_NAME_Attribute, &pszFriendlyName))) + { + // + // Log the friendly name of the decoder + // + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! decoder name: %S ", (pszFriendlyName ? pszFriendlyName : L"UnknownCodec")); + SAFE_COTASKMEMFREE(pszFriendlyName); + } + + DMFTCHECKHR_GOTO(ppActivate[0]->ActivateObject(IID_PPV_ARGS(spTransform.GetAddressOf())), done); + + *ppTransform = spTransform.Detach(); + +done: + if (ppActivate) + { + for (UINT32 uiIndex = 0; uiIndex < count; uiIndex++) + { + ppActivate[uiIndex]->Release(); + } + CoTaskMemFree(ppActivate); + } + return hr; +} +// +// @@@@ README Create the decoder +// +HRESULT CreateDecoderFromLuid( _In_ LUID ullAdapterLuidRunningOn, + _In_ IMFMediaType* pInputType, + _In_ IMFMediaType* pOutputType, + _Inout_ BOOL fHwMft, + _Outptr_ IMFTransform** ppDecoder) +{ + HRESULT hr = S_OK; + ComPtr<IMFAttributes> spAttribs; + ComPtr<IMFTransform> spMJPGDecoder; + IMFActivate **ppActivates = nullptr; + DWORD dwFlags = MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_SORTANDFILTER | MFT_ENUM_FLAG_HARDWARE | 0x10000000 /*Internal attribute*/; + UINT32 cMFTActivate = 0; + MFT_REGISTER_TYPE_INFO InputType; + MFT_REGISTER_TYPE_INFO OutputType; + GUID compressedGUID; + ComPtr<ID3D11Device> spD3D11Device; + + fHwMft = FALSE; + + + DMFTCHECKNULL_GOTO(pInputType, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(pOutputType, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(ppDecoder, done, E_INVALIDARG); + *ppDecoder = nullptr; + DMFTCHECKHR_GOTO(pInputType->GetGUID(MF_MT_SUBTYPE, &compressedGUID), done); + + InputType.guidMajorType = MFMediaType_Video; + InputType.guidSubtype = compressedGUID; + + DMFTCHECKHR_GOTO(pOutputType->GetMajorType(&OutputType.guidMajorType), done); + DMFTCHECKHR_GOTO(pOutputType->GetGUID(MF_MT_SUBTYPE, &OutputType.guidSubtype), done); + + DMFTCHECKHR_GOTO(MFCreateAttributes(&spAttribs, 1), done); + DMFTCHECKHR_GOTO(spAttribs->SetBlob(MFT_ENUM_ADAPTER_LUID, (byte*)&ullAdapterLuidRunningOn, sizeof(ullAdapterLuidRunningOn)), done); + DMFTCHECKHR_GOTO(MFTEnum2(MFT_CATEGORY_VIDEO_DECODER, dwFlags, &InputType, &OutputType, spAttribs.Get(), &ppActivates, &cMFTActivate), done); + + for (DWORD i = 0; i < cMFTActivate; i++) + { + HRESULT hrTemp = ppActivates[i]->ActivateObject(IID_PPV_ARGS(spMJPGDecoder.GetAddressOf())); + fHwMft = (MFT_ENUM_FLAG_HARDWARE & MFGetAttributeUINT32(ppActivates[i], MF_TRANSFORM_FLAGS_Attribute, 0)); + // Pickup the first MFT enumerated. Normally, it should be a HW MFT, if HWMFT is available. + if (SUCCEEDED(hrTemp)) + { + break; + } + else + { + spMJPGDecoder = nullptr; + } + } + if (spMJPGDecoder == nullptr) + { + hr = MF_E_NOT_FOUND; + } + *ppDecoder = spMJPGDecoder.Detach(); +done: + + for (UINT32 i = 0; i < cMFTActivate; i++) + { + if (nullptr != ppActivates[i]) + { + ppActivates[i]->Release(); + } + } + SAFE_COTASKMEMFREE(ppActivates); + return hr; +} + +HRESULT SetDX11BindFlags( _In_ IUnknown *pUnkManager, + _In_ GUID guidPinCategory, + _Inout_ DWORD &dwBindFlags) +{ + HRESULT hr = S_OK; + ComPtr<IUnknown> spDeviceManager; + BOOL fFL10 = FALSE; + + auto + IsFeatureLevel10OrBetter = [&]() -> BOOL + { + ComPtr<IMFDXGIDeviceManager> spDXGIManager; + ComPtr<ID3D11Device> spDevice; + HANDLE hDevice = 0; + BOOL fRet = FALSE; + UINT level = 0, result = 0; + + if (SUCCEEDED(pUnkManager->QueryInterface(IID_PPV_ARGS(&spDXGIManager))) && + SUCCEEDED(spDXGIManager->OpenDeviceHandle(&hDevice)) && + SUCCEEDED(spDXGIManager->LockDevice(hDevice, IID_PPV_ARGS(&spDevice), FALSE))) + { + + level = (UINT)spDevice->GetFeatureLevel(); + fRet = (level >= D3D_FEATURE_LEVEL_10_0); + if (!fRet) + { + if (SUCCEEDED(spDevice->CheckFormatSupport(DXGI_FORMAT_NV12, &result))) + { + fRet = (result & D3D11_FORMAT_SUPPORT_TEXTURE2D) && (result & D3D11_FORMAT_SUPPORT_RENDER_TARGET); + } + } + (void)spDXGIManager->UnlockDevice(hDevice, FALSE); + (void)spDXGIManager->CloseDeviceHandle(hDevice); + } + return fRet; + }; + + DMFTCHECKNULL_GOTO(pUnkManager, done, E_INVALIDARG); + fFL10 = IsFeatureLevel10OrBetter(); + + dwBindFlags |= fFL10 ? D3D11_BIND_SHADER_RESOURCE : 0; + dwBindFlags |= (guidPinCategory != PINNAME_VIDEO_PREVIEW) ? D3D11_BIND_VIDEO_ENCODER : 0; + if ((dwBindFlags != 0) && ((dwBindFlags & ~(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_VIDEO_ENCODER)) == 0)) + { + dwBindFlags |= D3D11_BIND_RENDER_TARGET; + } +done: + return hr; +} + +// @@@@ README: Create the Decoder +HRESULT CreateDecoderHW(_In_ IMFDXGIDeviceManager* pManager, + _In_ IMFMediaType* inType, + _In_ IMFMediaType* outType, + _Outptr_ IMFTransform** ppTransform, + _Inout_ BOOL& fHwMft) +{ + HRESULT hr = S_OK; + LUID luid; + ComPtr<IMFTransform> spTransform; + DMFTCHECKNULL_GOTO(ppTransform, done, E_INVALIDARG); + *ppTransform = nullptr; + + if (pManager) + { + if (SUCCEEDED(hr = GetDXGIAdapterLuid(pManager, luid))) + { + hr = CreateDecoderFromLuid(luid, inType, outType, fHwMft, spTransform.GetAddressOf()); + if (FAILED(hr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Error creating HW Decoder with LUID %d-%d", luid.HighPart, luid.LowPart); + DMFTCHECKHR_GOTO(hr, done); + } + } + } + *ppTransform = spTransform.Detach(); +done: + return hr; +} + +HRESULT +SubtypeToDXGIFormat( + _In_ GUID subType, + _Inout_ DXGI_FORMAT &format +) +{ + HRESULT hr = S_OK; + typedef struct { + GUID subType; + DXGI_FORMAT format; + }DXGIFormatMap; + DXGIFormatMap formatMap[] + { + { MFVideoFormat_NV12, DXGI_FORMAT_NV12 }, + { MFVideoFormat_YUY2, DXGI_FORMAT_YUY2 }, + { MFVideoFormat_RGB32, DXGI_FORMAT_B8G8R8X8_UNORM }, + { MFVideoFormat_ARGB32, DXGI_FORMAT_B8G8R8A8_UNORM }, + { MFVideoFormat_AYUV, DXGI_FORMAT_AYUV }, + { MFVideoFormat_NV11, DXGI_FORMAT_NV11 }, + { MFVideoFormat_AI44, DXGI_FORMAT_AI44 }, + { MFVideoFormat_P010, DXGI_FORMAT_P010 }, + { MFVideoFormat_P016, DXGI_FORMAT_P016 }, + { MFVideoFormat_Y210, DXGI_FORMAT_Y210 }, + { MFVideoFormat_Y216, DXGI_FORMAT_Y216 }, + { MFVideoFormat_Y410, DXGI_FORMAT_Y410 }, + { MFVideoFormat_Y416, DXGI_FORMAT_Y416 }, + }; + format = DXGI_FORMAT_UNKNOWN; + for (UINT32 uiIndex = 0; uiIndex < _countof(formatMap); uiIndex++) + { + if (formatMap[uiIndex].subType == subType) + { + format = formatMap[uiIndex].format; + break; + } + } + // compressed media type or unsupported of the range + hr = (format == DXGI_FORMAT_UNKNOWN) ? E_NOTIMPL : S_OK; + return hr; +} + +HRESULT IsDXFormatSupported( + _In_ IMFDXGIDeviceManager* pDeviceManager , + _In_ GUID subType, + _Outptr_opt_ ID3D11Device** ppDevice, + _In_opt_ PUINT32 pSupportedFormat) +{ + HRESULT hr = S_OK; + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + UINT32 supportedFormat = 0; + HANDLE hDevice = NULL; + ComPtr<ID3D11Device> spDevice; + DMFTCHECKNULL_GOTO(pDeviceManager, done, E_INVALIDARG); + DMFTCHECKHR_GOTO(pDeviceManager->OpenDeviceHandle(&hDevice), done); + DMFTCHECKHR_GOTO(pDeviceManager->GetVideoService(hDevice, IID_PPV_ARGS(&spDevice)), done); + DMFTCHECKHR_GOTO(SubtypeToDXGIFormat(subType, format), done); + DMFTCHECKHR_GOTO(spDevice->CheckFormatSupport(format, &supportedFormat), done); + if (pSupportedFormat) + { + *pSupportedFormat = supportedFormat; + } + if (ppDevice) + { + *ppDevice = spDevice.Detach(); + } +done: + if (hDevice != NULL) + { + pDeviceManager->CloseDeviceHandle(hDevice); + } + return hr; +} + +HRESULT +UpdateAllocatorAttributes( + _In_ IMFAttributes *pAttributes, + _In_ REFGUID guidStreamCategory, + _In_ GUID subType, + _In_ IMFDXGIDeviceManager *pDeviceManager +) +{ + HRESULT hr = S_OK; + UINT32 supportedFormat = 0; + ComPtr<ID3D11Device> spDevice; + DWORD dwBindFlags = 0; + + DMFTCHECKHR_GOTO(IsDXFormatSupported(pDeviceManager,subType, + spDevice.GetAddressOf(),&supportedFormat),done); + + // MF_SA_D3D11_USAGE should be D3D11_USAGE_DEFAULT, same as previous release. + DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_SA_D3D11_USAGE, D3D11_USAGE_DEFAULT), done); + + DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_SA_D3D11_SHARED_WITHOUT_MUTEX, TRUE), done); + DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_SA_D3D11_SHARED_WITH_NTHANDLE_PRIVATE, TRUE), done); + + // Bind Flags + dwBindFlags |= ((supportedFormat & D3D11_FORMAT_SUPPORT_RENDER_TARGET) != 0 ? D3D11_BIND_RENDER_TARGET : 0); + + if (((supportedFormat & D3D11_FORMAT_SUPPORT_VIDEO_ENCODER) != 0) && + (!IsEqualGUID(guidStreamCategory, PINNAME_VIDEO_PREVIEW)) && + IsEqualGUID(subType, MFVideoFormat_NV12)) + { + D3D11_FEATURE_DATA_D3D11_OPTIONS4 Options = { 0 }; + + // "D3D11_BIND_VIDEO_ENCODER + sharing" is only supported on those devices that + // advertise ExtendedNV12SharedTextureSupported. + DMFTCHECKHR_GOTO(spDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS4, &Options, sizeof(Options)), done); + if (Options.ExtendedNV12SharedTextureSupported) + { + dwBindFlags |= D3D11_BIND_VIDEO_ENCODER; + } + } + + // D3D requires one of the flags (D3D11_BIND_RENDER_TARGET, D3D11_PRIVATE_BIND_CAPTURE, or D3D11_BIND_VIDEO_ENCODER) to be set for non-zero bind flags. + if (dwBindFlags != 0) + { + D3D_FEATURE_LEVEL level; + + // D3D11_BIND_SHADER_RESOURCE + level = spDevice->GetFeatureLevel(); + dwBindFlags |= ((level >= D3D_FEATURE_LEVEL_10_0) ? D3D11_BIND_SHADER_RESOURCE : 0); + } + + DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_SA_D3D11_BINDFLAGS, dwBindFlags), done); + +done: + return hr; +} + +const UINT32 ALLOCATOR_MIN_SAMPLES = 10; +const UINT32 ALLOCATOR_MAX_SAMPLES = 50; + +HRESULT ConfigureAllocator( + _In_ IMFMediaType* pOutputMediaType, + _In_ GUID streamCategory, + _In_ IUnknown* pDeviceManagerUnk, + _In_ BOOL &bDxAllocator, + _In_ IMFVideoSampleAllocator* pAllocator) +{ + HRESULT hr = S_OK; + wil::com_ptr_nothrow<IMFVideoSampleAllocatorEx> spPrivateAllocator; +#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)) + wil::com_ptr_nothrow<IMFVideoCaptureSampleAllocator> spDefaultAllocator; +#endif + wil::com_ptr_nothrow<IMFAttributes> spAllocatorAttributes; + GUID guidMajorType = GUID_NULL; + GUID guidSubtype = GUID_NULL; + BOOL fDXAllocator = FALSE; + + RETURN_HR_IF_NULL(E_INVALIDARG, pAllocator ); + RETURN_HR_IF_NULL(E_INVALIDARG, pOutputMediaType ); + + RETURN_IF_FAILED(pOutputMediaType->GetMajorType(&guidMajorType)); + + if (!IsEqualGUID(guidMajorType, MFMediaType_Video)) + { + RETURN_HR(MF_E_INVALIDMEDIATYPE); + } + + RETURN_IF_FAILED(pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &guidSubtype)); + // + // Set Attributes on the allocator we need. First get the Bind Flags. + // + RETURN_IF_FAILED(MFCreateAttributes(&spAllocatorAttributes, 8)); + RETURN_IF_FAILED(spAllocatorAttributes->SetUINT32(MF_SA_BUFFERS_PER_SAMPLE, 1)); + + if (pDeviceManagerUnk != nullptr) + { + if (SUCCEEDED(UpdateAllocatorAttributes(spAllocatorAttributes.get(), streamCategory, guidSubtype, (IMFDXGIDeviceManager*)pDeviceManagerUnk))) + { + fDXAllocator = TRUE; + } + } + + if (fDXAllocator) + { + RETURN_IF_FAILED(pAllocator->SetDirectXManager(pDeviceManagerUnk)); + } + + if (SUCCEEDED(pAllocator->QueryInterface(IID_PPV_ARGS(&spPrivateAllocator)))) + { + RETURN_IF_FAILED(spPrivateAllocator->InitializeSampleAllocatorEx( + ALLOCATOR_MIN_SAMPLES, + ALLOCATOR_MAX_SAMPLES, + spAllocatorAttributes.get(), + pOutputMediaType)); + } +#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB)) + else if (SUCCEEDED(pAllocator->QueryInterface(IID_PPV_ARGS(&spDefaultAllocator)))) + { + RETURN_IF_FAILED(spDefaultAllocator->InitializeCaptureSampleAllocator( + 0, /*use sample size by MediaType*/ + 0, /*metadata size*/ + 0, /*default alignment*/ + ALLOCATOR_MIN_SAMPLES, + spAllocatorAttributes.get(), + pOutputMediaType)); + } +#endif + else + { + hr = E_INVALIDARG; + } + + bDxAllocator = fDXAllocator; + + return hr; +} +// +//@@@@ README: Creating an Allocator.. Please don't allocate samples individually using MFCreateSample as that can lead to fragmentation and is +// extremely inefficent. Instead create an Allocator which will create a fixed number of samples which are recycled when the pipeline returns back +// the buffers. The above has defines will enable to create a circular allocator which will have maximum 20 samples flowing in the pipeline +// This way we can also catch samples leaks if any. +// +HRESULT CreateAllocator( _In_ IMFMediaType* pOutputMediaType, + _In_ GUID streamCategory, + _In_ IUnknown* pDeviceManagerUnk, + _In_ BOOL &bDxAllocator, + _Outptr_ IMFVideoSampleAllocatorEx** ppAllocator ) +{ + HRESULT hr = S_OK; + ComPtr<IMFVideoSampleAllocatorEx> spVideoSampleAllocator; + ComPtr<IMFAttributes> spAllocatorAttributes; + GUID guidMajorType = GUID_NULL; + GUID guidSubtype = GUID_NULL; + BOOL fDXAllocator = FALSE; + + DMFTCHECKNULL_GOTO(ppAllocator, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(pOutputMediaType, done, E_INVALIDARG); + DMFTCHECKHR_GOTO(pOutputMediaType->GetMajorType(&guidMajorType), done); + + *ppAllocator = nullptr; + if (!IsEqualGUID(guidMajorType, MFMediaType_Video)) + { + DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done); + } + + DMFTCHECKHR_GOTO(pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &guidSubtype), done); + // + // Set Attributes on the allocator we need. First get the Bind Flags. + // + DMFTCHECKHR_GOTO(MFCreateAttributes(&spAllocatorAttributes, 8), done); + DMFTCHECKHR_GOTO(spAllocatorAttributes->SetUINT32(MF_SA_BUFFERS_PER_SAMPLE, 1), done); + + if (pDeviceManagerUnk != nullptr) + { + if (SUCCEEDED(UpdateAllocatorAttributes(spAllocatorAttributes.Get(), streamCategory,guidSubtype, (IMFDXGIDeviceManager*)pDeviceManagerUnk))) + { + fDXAllocator = TRUE; + } + } + DMFTCHECKHR_GOTO(MFCreateVideoSampleAllocatorEx(IID_PPV_ARGS(spVideoSampleAllocator.ReleaseAndGetAddressOf())), done); + if (fDXAllocator) + { + DMFTCHECKHR_GOTO(spVideoSampleAllocator->SetDirectXManager(pDeviceManagerUnk), done); + } + + DMFTCHECKHR_GOTO(spVideoSampleAllocator->InitializeSampleAllocatorEx(ALLOCATOR_MIN_SAMPLES, ALLOCATOR_MAX_SAMPLES, spAllocatorAttributes.Get(), pOutputMediaType), done); + + *ppAllocator = spVideoSampleAllocator.Detach(); + bDxAllocator = fDXAllocator; +done: + return hr; +} + +HRESULT CheckPassthroughMediaType(_In_ IMFMediaType *pMediaType1, + _In_ IMFMediaType *pMediaType2, + _Out_ BOOL& pfPassThrough) +{ + HRESULT hr = S_OK; + BOOL fPassThrough = FALSE; + UINT32 uWidth, uHeight; + UINT32 uWidth2, uHeight2; + + // Compare Width/Height. + DMFTCHECKHR_GOTO(MFGetAttributeSize(pMediaType1, MF_MT_FRAME_SIZE, &uWidth, &uHeight), done); + DMFTCHECKHR_GOTO(MFGetAttributeSize(pMediaType2, MF_MT_FRAME_SIZE, &uWidth2, &uHeight2), done); + if ((uWidth != uWidth2) || (uHeight != uHeight2)) + { + goto done; + } + + // Compare rotation + { + UINT32 uRotation; + UINT32 uRotation2; + + uRotation = MFGetAttributeUINT32(pMediaType1, MF_MT_VIDEO_ROTATION, 0); + uRotation2 = MFGetAttributeUINT32(pMediaType2, MF_MT_VIDEO_ROTATION, 0); + if (uRotation != uRotation2) + { + goto done; + } + } + + // Compare Aspect Ratio + { + UINT32 uNumerator = 1, uDenominator = 1; + UINT32 uNumerator2 = 1, uDenominator2 = 1; + + (void)MFGetAttributeRatio(pMediaType1, MF_MT_FRAME_RATE, &uNumerator, &uDenominator); + (void)MFGetAttributeRatio(pMediaType2, MF_MT_FRAME_RATE, &uNumerator2, &uDenominator2); + if ((uNumerator * uDenominator2) != (uNumerator2 * uDenominator)) + { + goto done; + } + } + + // Compare Nominal Range + { + UINT32 uNorminalRange; + UINT32 uNorminalRange2; + + uNorminalRange = MFGetAttributeUINT32(pMediaType1, MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Unknown); + uNorminalRange2 = MFGetAttributeUINT32(pMediaType2, MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_Unknown); + if (uNorminalRange != uNorminalRange2) + { + goto done; + } + } + + // Compare color primaries + { + UINT32 uPrimaries; + UINT32 uPrimaries2; + + uPrimaries = MFGetAttributeUINT32(pMediaType1, MF_MT_VIDEO_PRIMARIES, MFVideoPrimaries_Unknown); + uPrimaries2 = MFGetAttributeUINT32(pMediaType2, MF_MT_VIDEO_PRIMARIES, MFVideoPrimaries_Unknown); + if (uPrimaries != uPrimaries2) + { + goto done; + } + } + + + // Compare InterlaceMode + { + UINT32 uInterlaceMode; + UINT32 uInterlaceMode2; + + uInterlaceMode = MFGetAttributeUINT32(pMediaType1, MF_MT_INTERLACE_MODE, MFVideoInterlace_Unknown); + uInterlaceMode2 = MFGetAttributeUINT32(pMediaType2, MF_MT_INTERLACE_MODE, MFVideoInterlace_Unknown); + if (uInterlaceMode != uInterlaceMode2) + { + goto done; + } + } + + // Compare display aperture + { + MFVideoArea VideoArea = { 0 }; + MFVideoArea VideoArea2 = { 0 }; + UINT32 cbBlobSize = 0; + + if (SUCCEEDED(pMediaType1->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)&VideoArea, sizeof(MFVideoArea), &cbBlobSize))) + { + if ((VideoArea.OffsetX.value == 0 && VideoArea.OffsetX.fract == 0) && + (VideoArea.OffsetY.value == 0 && VideoArea.OffsetY.fract == 0) && + (VideoArea.Area.cx == (LONG)uWidth) && + (VideoArea.Area.cy == (LONG)uHeight)) + { + // If the display aperture is the whole frame size, ignore it. + ZeroMemory(&VideoArea, sizeof(VideoArea)); + } + } + + if (SUCCEEDED(pMediaType2->GetBlob(MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8*)&VideoArea2, sizeof(MFVideoArea), &cbBlobSize))) + { + if ((VideoArea2.OffsetX.value == 0 && VideoArea2.OffsetX.fract == 0) && + (VideoArea2.OffsetY.value == 0 && VideoArea2.OffsetY.fract == 0) && + (VideoArea2.Area.cx == (LONG)uWidth) && + (VideoArea2.Area.cy == (LONG)uHeight)) + { + // If the display aperture is the whole frame size, ignore it. + ZeroMemory(&VideoArea, sizeof(VideoArea)); + } + } + + if (memcmp(&VideoArea, &VideoArea2, sizeof(MFVideoArea)) != 0) + { + goto done; + } + } + + fPassThrough = TRUE; + +done: + pfPassThrough = fPassThrough; + return hr; +} + + +HRESULT MergeSampleAttributes( _In_ IMFSample* pInSample, _Inout_ IMFSample* pOutSample) +{ + HRESULT hr = S_OK; + UINT32 cAttributes = 0; + GUID guidAttribute; + PROPVARIANT varAttribute; + PROPVARIANT varAttributeExists; + PropVariantInit(&varAttribute); + PropVariantInit(&varAttributeExists); + + DMFTCHECKNULL_GOTO(pInSample, done, E_INVALIDARG); + DMFTCHECKNULL_GOTO(pOutSample, done, E_INVALIDARG); + + DMFTCHECKHR_GOTO(pInSample->GetCount(&cAttributes), done); + for (UINT32 i = 0; i < cAttributes; i++) + { + PropVariantClear(&varAttribute); + PropVariantClear(&varAttributeExists); + + DMFTCHECKHR_GOTO(pInSample->GetItemByIndex(i, &guidAttribute, &varAttribute), done); + + if (S_OK == pOutSample->GetItem(guidAttribute, &varAttributeExists)) + { + // Exists.. dont clobber + continue; + } + + DMFTCHECKHR_GOTO(pOutSample->SetItem(guidAttribute, varAttribute), done); + } + +done: + PropVariantClear(&varAttribute); + PropVariantClear(&varAttributeExists); + return hr; +} |
