Home | History | Annotate | Download | only in src
      1 #ifdef WINRT
      2 #define ICustomStreamSink StreamSink
      3 #ifndef __cplusplus_winrt
      4 
      5 #define __is_winrt_array(type) (type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt8Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_Int16Array ||\
      6     type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt16Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_Int32Array ||\
      7     type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt32Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_Int64Array ||\
      8     type == ABI::Windows::Foundation::PropertyType::PropertyType_UInt64Array || type == ABI::Windows::Foundation::PropertyType::PropertyType_SingleArray ||\
      9     type == ABI::Windows::Foundation::PropertyType::PropertyType_DoubleArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_Char16Array ||\
     10     type == ABI::Windows::Foundation::PropertyType::PropertyType_BooleanArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_StringArray ||\
     11     type == ABI::Windows::Foundation::PropertyType::PropertyType_InspectableArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_DateTimeArray ||\
     12     type == ABI::Windows::Foundation::PropertyType::PropertyType_TimeSpanArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_GuidArray ||\
     13     type == ABI::Windows::Foundation::PropertyType::PropertyType_PointArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_SizeArray ||\
     14     type == ABI::Windows::Foundation::PropertyType::PropertyType_RectArray || type == ABI::Windows::Foundation::PropertyType::PropertyType_OtherTypeArray)
     15 
     16 template<typename _Type, bool bUnknown = std::is_base_of<IUnknown, _Type>::value>
     17 struct winrt_type
     18 {
     19 };
     20 template<typename _Type>
     21 struct winrt_type<_Type, true>
     22 {
     23     static IUnknown* create(_Type* _ObjInCtx) {
     24         return reinterpret_cast<IUnknown*>(_ObjInCtx);
     25     }
     26     static IID getuuid() { return __uuidof(_Type); }
     27     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_OtherType;
     28 };
     29 template <typename _Type>
     30 struct winrt_type<_Type, false>
     31 {
     32     static IUnknown* create(_Type* _ObjInCtx) {
     33         Microsoft::WRL::ComPtr<IInspectable> _PObj;
     34         Microsoft::WRL::ComPtr<IActivationFactory> objFactory;
     35         HRESULT hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), objFactory.ReleaseAndGetAddressOf());
     36         if (FAILED(hr)) return nullptr;
     37         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> spPropVal;
     38         if (SUCCEEDED(hr))
     39             hr = objFactory.As(&spPropVal);
     40         if (SUCCEEDED(hr)) {
     41             hr = winrt_type<_Type>::create(spPropVal.Get(), _ObjInCtx, _PObj.GetAddressOf());
     42             if (SUCCEEDED(hr))
     43                 return reinterpret_cast<IUnknown*>(_PObj.Detach());
     44         }
     45         return nullptr;
     46     }
     47     static IID getuuid() { return __uuidof(ABI::Windows::Foundation::IPropertyValue); }
     48     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_OtherType;
     49 };
     50 
     51 template<>
     52 struct winrt_type<void>
     53 {
     54     static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, void* _ObjInCtx, IInspectable** ppInsp) {
     55         (void)_ObjInCtx;
     56         return spPropVal->CreateEmpty(ppInsp);
     57     }
     58     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_Empty;
     59 };
     60 #define MAKE_TYPE(Type, Name) template<>\
     61 struct winrt_type<Type>\
     62 {\
     63     static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, Type* _ObjInCtx, IInspectable** ppInsp) {\
     64     return spPropVal->Create##Name(*_ObjInCtx, ppInsp);\
     65 }\
     66     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_##Name;\
     67 };
     68 
     69 template<typename _Type>
     70 struct winrt_array_type
     71 {
     72     static IUnknown* create(_Type* _ObjInCtx, size_t N) {
     73         Microsoft::WRL::ComPtr<IInspectable> _PObj;
     74         Microsoft::WRL::ComPtr<IActivationFactory> objFactory;
     75         HRESULT hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), objFactory.ReleaseAndGetAddressOf());
     76         if (FAILED(hr)) return nullptr;
     77         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValueStatics> spPropVal;
     78         if (SUCCEEDED(hr))
     79             hr = objFactory.As(&spPropVal);
     80         if (SUCCEEDED(hr)) {
     81             hr = winrt_array_type<_Type>::create(spPropVal.Get(), N, _ObjInCtx, _PObj.GetAddressOf());
     82             if (SUCCEEDED(hr))
     83                 return reinterpret_cast<IUnknown*>(_PObj.Detach());
     84         }
     85         return nullptr;
     86     }
     87     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_OtherTypeArray;
     88 };
     89 template<int>
     90 struct winrt_prop_type {};
     91 
     92 template <>
     93 struct winrt_prop_type<ABI::Windows::Foundation::PropertyType_Empty> {
     94     typedef void _Type;
     95 };
     96 
     97 template <>
     98 struct winrt_prop_type<ABI::Windows::Foundation::PropertyType_OtherType> {
     99     typedef void _Type;
    100 };
    101 
    102 template <>
    103 struct winrt_prop_type<ABI::Windows::Foundation::PropertyType_OtherTypeArray> {
    104     typedef void _Type;
    105 };
    106 
    107 #define MAKE_PROP(Prop, Type) template <>\
    108 struct winrt_prop_type<ABI::Windows::Foundation::PropertyType_##Prop> {\
    109     typedef Type _Type;\
    110 };
    111 
    112 #define MAKE_ARRAY_TYPE(Type, Name) MAKE_PROP(Name, Type)\
    113     MAKE_PROP(Name##Array, Type*)\
    114     MAKE_TYPE(Type, Name)\
    115     template<>\
    116 struct winrt_array_type<Type*>\
    117 {\
    118     static HRESULT create(ABI::Windows::Foundation::IPropertyValueStatics* spPropVal, UINT32 __valueSize, Type** _ObjInCtx, IInspectable** ppInsp) {\
    119     return spPropVal->Create##Name##Array(__valueSize, *_ObjInCtx, ppInsp);\
    120 }\
    121     static const ABI::Windows::Foundation::PropertyType _PropType = ABI::Windows::Foundation::PropertyType::PropertyType_##Name##Array;\
    122     static std::vector<Type> PropertyValueToVector(ABI::Windows::Foundation::IPropertyValue* propValue)\
    123 {\
    124     UINT32 uLen = 0;\
    125     Type* pArray = nullptr;\
    126     propValue->Get##Name##Array(&uLen, &pArray);\
    127     return std::vector<Type>(pArray, pArray + uLen);\
    128 }\
    129 };
    130 MAKE_ARRAY_TYPE(BYTE, UInt8)
    131 MAKE_ARRAY_TYPE(INT16, Int16)
    132 MAKE_ARRAY_TYPE(UINT16, UInt16)
    133 MAKE_ARRAY_TYPE(INT32, Int32)
    134 MAKE_ARRAY_TYPE(UINT32, UInt32)
    135 MAKE_ARRAY_TYPE(INT64, Int64)
    136 MAKE_ARRAY_TYPE(UINT64, UInt64)
    137 MAKE_ARRAY_TYPE(FLOAT, Single)
    138 MAKE_ARRAY_TYPE(DOUBLE, Double)
    139 MAKE_ARRAY_TYPE(WCHAR, Char16)
    140 //MAKE_ARRAY_TYPE(boolean, Boolean) //conflict with identical type in C++ of BYTE/UInt8
    141 MAKE_ARRAY_TYPE(HSTRING, String)
    142 MAKE_ARRAY_TYPE(IInspectable*, Inspectable)
    143 MAKE_ARRAY_TYPE(GUID, Guid)
    144 MAKE_ARRAY_TYPE(ABI::Windows::Foundation::DateTime, DateTime)
    145 MAKE_ARRAY_TYPE(ABI::Windows::Foundation::TimeSpan, TimeSpan)
    146 MAKE_ARRAY_TYPE(ABI::Windows::Foundation::Point, Point)
    147 MAKE_ARRAY_TYPE(ABI::Windows::Foundation::Size, Size)
    148 MAKE_ARRAY_TYPE(ABI::Windows::Foundation::Rect, Rect)
    149 
    150 template < typename T >
    151 struct DerefHelper
    152 {
    153     typedef T DerefType;
    154 };
    155 
    156 template < typename T >
    157 struct DerefHelper<T*>
    158 {
    159     typedef T DerefType;
    160 };
    161 
    162 #define __is_valid_winrt_type(_Type) (std::is_void<_Type>::value || \
    163     std::is_same<_Type, BYTE>::value || \
    164     std::is_same<_Type, INT16>::value || \
    165     std::is_same<_Type, UINT16>::value || \
    166     std::is_same<_Type, INT32>::value || \
    167     std::is_same<_Type, UINT32>::value || \
    168     std::is_same<_Type, INT64>::value || \
    169     std::is_same<_Type, UINT64>::value || \
    170     std::is_same<_Type, FLOAT>::value || \
    171     std::is_same<_Type, DOUBLE>::value || \
    172     std::is_same<_Type, WCHAR>::value || \
    173     std::is_same<_Type, boolean>::value || \
    174     std::is_same<_Type, HSTRING>::value || \
    175     std::is_same<_Type, IInspectable *>::value || \
    176     std::is_base_of<Microsoft::WRL::Details::RuntimeClassBase, _Type>::value || \
    177     std::is_base_of<IInspectable, typename DerefHelper<_Type>::DerefType>::value || \
    178     std::is_same<_Type, GUID>::value || \
    179     std::is_same<_Type, ABI::Windows::Foundation::DateTime>::value || \
    180     std::is_same<_Type, ABI::Windows::Foundation::TimeSpan>::value || \
    181     std::is_same<_Type, ABI::Windows::Foundation::Point>::value || \
    182     std::is_same<_Type, ABI::Windows::Foundation::Size>::value || \
    183     std::is_same<_Type, ABI::Windows::Foundation::Rect>::value || \
    184     std::is_same<_Type, BYTE*>::value || \
    185     std::is_same<_Type, INT16*>::value || \
    186     std::is_same<_Type, UINT16*>::value || \
    187     std::is_same<_Type, INT32*>::value || \
    188     std::is_same<_Type, UINT32*>::value || \
    189     std::is_same<_Type, INT64*>::value || \
    190     std::is_same<_Type, UINT64*>::value || \
    191     std::is_same<_Type, FLOAT*>::value || \
    192     std::is_same<_Type, DOUBLE*>::value || \
    193     std::is_same<_Type, WCHAR*>::value || \
    194     std::is_same<_Type, boolean*>::value || \
    195     std::is_same<_Type, HSTRING*>::value || \
    196     std::is_same<_Type, IInspectable **>::value || \
    197     std::is_same<_Type, GUID*>::value || \
    198     std::is_same<_Type, ABI::Windows::Foundation::DateTime*>::value || \
    199     std::is_same<_Type, ABI::Windows::Foundation::TimeSpan*>::value || \
    200     std::is_same<_Type, ABI::Windows::Foundation::Point*>::value || \
    201     std::is_same<_Type, ABI::Windows::Foundation::Size*>::value || \
    202     std::is_same<_Type, ABI::Windows::Foundation::Rect*>::value)
    203 #endif
    204 #else
    205 EXTERN_C const IID IID_ICustomStreamSink;
    206 
    207 class DECLSPEC_UUID("4F8A1939-2FD3-46DB-AE70-DB7E0DD79B73") DECLSPEC_NOVTABLE ICustomStreamSink : public IUnknown
    208 {
    209 public:
    210     virtual HRESULT Initialize() = 0;
    211     virtual HRESULT Shutdown() = 0;
    212     virtual HRESULT Start(MFTIME start) = 0;
    213     virtual HRESULT Pause() = 0;
    214     virtual HRESULT Restart() = 0;
    215     virtual HRESULT Stop() = 0;
    216 };
    217 #endif
    218 
    219 #define MF_PROP_SAMPLEGRABBERCALLBACK L"samplegrabbercallback"
    220 #define MF_PROP_VIDTYPE L"vidtype"
    221 #define MF_PROP_VIDENCPROPS L"videncprops"
    222 
    223 #include <initguid.h>
    224 
    225 // MF_MEDIASINK_SAMPLEGRABBERCALLBACK: {26957AA7-AFF4-464c-BB8B-07BA65CE11DF}
    226 // Type: IUnknown*
    227 DEFINE_GUID(MF_MEDIASINK_SAMPLEGRABBERCALLBACK,
    228             0x26957aa7, 0xaff4, 0x464c, 0xbb, 0x8b, 0x7, 0xba, 0x65, 0xce, 0x11, 0xdf);
    229 
    230 // {4BD133CC-EB9B-496E-8865-0813BFBC6FAA}
    231 DEFINE_GUID(MF_STREAMSINK_ID, 0x4bd133cc, 0xeb9b, 0x496e, 0x88, 0x65, 0x8, 0x13, 0xbf, 0xbc, 0x6f, 0xaa);
    232 
    233 // {C9E22A8C-6A50-4D78-9183-0834A02A3780}
    234 DEFINE_GUID(MF_STREAMSINK_MEDIASINKINTERFACE,
    235     0xc9e22a8c, 0x6a50, 0x4d78, 0x91, 0x83, 0x8, 0x34, 0xa0, 0x2a, 0x37, 0x80);
    236 
    237 // {DABD13AB-26B7-47C2-97C1-4B04C187B838}
    238 DEFINE_GUID(MF_MEDIASINK_PREFERREDTYPE,
    239     0xdabd13ab, 0x26b7, 0x47c2, 0x97, 0xc1, 0x4b, 0x4, 0xc1, 0x87, 0xb8, 0x38);
    240 
    241 #include <utility>
    242 #ifdef _UNICODE
    243 #define MAKE_MAP(e) std::map<e, std::wstring>
    244 #define MAKE_ENUM(e) std::pair<e, std::wstring>
    245 #define MAKE_ENUM_PAIR(e, str) std::pair<e, std::wstring>(str, L#str)
    246 #else
    247 #define MAKE_MAP(e) std::map<e, std::string>
    248 #define MAKE_ENUM(e) std::pair<e, std::string>
    249 #define MAKE_ENUM_PAIR(e, str) std::pair<e, std::string>(str, #str)
    250 #endif
    251 
    252 MAKE_ENUM(MediaEventType) MediaEventTypePairs[] = {
    253     MAKE_ENUM_PAIR(MediaEventType, MEUnknown),
    254     MAKE_ENUM_PAIR(MediaEventType, MEError),
    255     MAKE_ENUM_PAIR(MediaEventType, MEExtendedType),
    256     MAKE_ENUM_PAIR(MediaEventType, MENonFatalError),
    257     MAKE_ENUM_PAIR(MediaEventType, MEGenericV1Anchor),
    258     MAKE_ENUM_PAIR(MediaEventType, MESessionUnknown),
    259     MAKE_ENUM_PAIR(MediaEventType, MESessionTopologySet),
    260     MAKE_ENUM_PAIR(MediaEventType, MESessionTopologiesCleared),
    261     MAKE_ENUM_PAIR(MediaEventType, MESessionStarted),
    262     MAKE_ENUM_PAIR(MediaEventType, MESessionPaused),
    263     MAKE_ENUM_PAIR(MediaEventType, MESessionStopped),
    264     MAKE_ENUM_PAIR(MediaEventType, MESessionClosed),
    265     MAKE_ENUM_PAIR(MediaEventType, MESessionEnded),
    266     MAKE_ENUM_PAIR(MediaEventType, MESessionRateChanged),
    267     MAKE_ENUM_PAIR(MediaEventType, MESessionScrubSampleComplete),
    268     MAKE_ENUM_PAIR(MediaEventType, MESessionCapabilitiesChanged),
    269     MAKE_ENUM_PAIR(MediaEventType, MESessionTopologyStatus),
    270     MAKE_ENUM_PAIR(MediaEventType, MESessionNotifyPresentationTime),
    271     MAKE_ENUM_PAIR(MediaEventType, MENewPresentation),
    272     MAKE_ENUM_PAIR(MediaEventType, MELicenseAcquisitionStart),
    273     MAKE_ENUM_PAIR(MediaEventType, MELicenseAcquisitionCompleted),
    274     MAKE_ENUM_PAIR(MediaEventType, MEIndividualizationStart),
    275     MAKE_ENUM_PAIR(MediaEventType, MEIndividualizationCompleted),
    276     MAKE_ENUM_PAIR(MediaEventType, MEEnablerProgress),
    277     MAKE_ENUM_PAIR(MediaEventType, MEEnablerCompleted),
    278     MAKE_ENUM_PAIR(MediaEventType, MEPolicyError),
    279     MAKE_ENUM_PAIR(MediaEventType, MEPolicyReport),
    280     MAKE_ENUM_PAIR(MediaEventType, MEBufferingStarted),
    281     MAKE_ENUM_PAIR(MediaEventType, MEBufferingStopped),
    282     MAKE_ENUM_PAIR(MediaEventType, MEConnectStart),
    283     MAKE_ENUM_PAIR(MediaEventType, MEConnectEnd),
    284     MAKE_ENUM_PAIR(MediaEventType, MEReconnectStart),
    285     MAKE_ENUM_PAIR(MediaEventType, MEReconnectEnd),
    286     MAKE_ENUM_PAIR(MediaEventType, MERendererEvent),
    287     MAKE_ENUM_PAIR(MediaEventType, MESessionStreamSinkFormatChanged),
    288     MAKE_ENUM_PAIR(MediaEventType, MESessionV1Anchor),
    289     MAKE_ENUM_PAIR(MediaEventType, MESourceUnknown),
    290     MAKE_ENUM_PAIR(MediaEventType, MESourceStarted),
    291     MAKE_ENUM_PAIR(MediaEventType, MEStreamStarted),
    292     MAKE_ENUM_PAIR(MediaEventType, MESourceSeeked),
    293     MAKE_ENUM_PAIR(MediaEventType, MEStreamSeeked),
    294     MAKE_ENUM_PAIR(MediaEventType, MENewStream),
    295     MAKE_ENUM_PAIR(MediaEventType, MEUpdatedStream),
    296     MAKE_ENUM_PAIR(MediaEventType, MESourceStopped),
    297     MAKE_ENUM_PAIR(MediaEventType, MEStreamStopped),
    298     MAKE_ENUM_PAIR(MediaEventType, MESourcePaused),
    299     MAKE_ENUM_PAIR(MediaEventType, MEStreamPaused),
    300     MAKE_ENUM_PAIR(MediaEventType, MEEndOfPresentation),
    301     MAKE_ENUM_PAIR(MediaEventType, MEEndOfStream),
    302     MAKE_ENUM_PAIR(MediaEventType, MEMediaSample),
    303     MAKE_ENUM_PAIR(MediaEventType, MEStreamTick),
    304     MAKE_ENUM_PAIR(MediaEventType, MEStreamThinMode),
    305     MAKE_ENUM_PAIR(MediaEventType, MEStreamFormatChanged),
    306     MAKE_ENUM_PAIR(MediaEventType, MESourceRateChanged),
    307     MAKE_ENUM_PAIR(MediaEventType, MEEndOfPresentationSegment),
    308     MAKE_ENUM_PAIR(MediaEventType, MESourceCharacteristicsChanged),
    309     MAKE_ENUM_PAIR(MediaEventType, MESourceRateChangeRequested),
    310     MAKE_ENUM_PAIR(MediaEventType, MESourceMetadataChanged),
    311     MAKE_ENUM_PAIR(MediaEventType, MESequencerSourceTopologyUpdated),
    312     MAKE_ENUM_PAIR(MediaEventType, MESourceV1Anchor),
    313     MAKE_ENUM_PAIR(MediaEventType, MESinkUnknown),
    314     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkStarted),
    315     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkStopped),
    316     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkPaused),
    317     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkRateChanged),
    318     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkRequestSample),
    319     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkMarker),
    320     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkPrerolled),
    321     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkScrubSampleComplete),
    322     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkFormatChanged),
    323     MAKE_ENUM_PAIR(MediaEventType, MEStreamSinkDeviceChanged),
    324     MAKE_ENUM_PAIR(MediaEventType, MEQualityNotify),
    325     MAKE_ENUM_PAIR(MediaEventType, MESinkInvalidated),
    326     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionNameChanged),
    327     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionVolumeChanged),
    328     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionDeviceRemoved),
    329     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionServerShutdown),
    330     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionGroupingParamChanged),
    331     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionIconChanged),
    332     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionFormatChanged),
    333     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionDisconnected),
    334     MAKE_ENUM_PAIR(MediaEventType, MEAudioSessionExclusiveModeOverride),
    335     MAKE_ENUM_PAIR(MediaEventType, MESinkV1Anchor),
    336 #if (WINVER >= 0x0602) // Available since Win 8
    337     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionVolumeChanged),
    338     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionDeviceRemoved),
    339     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionFormatChanged),
    340     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionDisconnected),
    341     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionExclusiveModeOverride),
    342     MAKE_ENUM_PAIR(MediaEventType, MECaptureAudioSessionServerShutdown),
    343     MAKE_ENUM_PAIR(MediaEventType, MESinkV2Anchor),
    344 #endif
    345     MAKE_ENUM_PAIR(MediaEventType, METrustUnknown),
    346     MAKE_ENUM_PAIR(MediaEventType, MEPolicyChanged),
    347     MAKE_ENUM_PAIR(MediaEventType, MEContentProtectionMessage),
    348     MAKE_ENUM_PAIR(MediaEventType, MEPolicySet),
    349     MAKE_ENUM_PAIR(MediaEventType, METrustV1Anchor),
    350     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseBackupCompleted),
    351     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseBackupProgress),
    352     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseRestoreCompleted),
    353     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseRestoreProgress),
    354     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseAcquisitionCompleted),
    355     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMIndividualizationCompleted),
    356     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMIndividualizationProgress),
    357     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMProximityCompleted),
    358     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMLicenseStoreCleaned),
    359     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMRevocationDownloadCompleted),
    360     MAKE_ENUM_PAIR(MediaEventType, MEWMDRMV1Anchor),
    361     MAKE_ENUM_PAIR(MediaEventType, METransformUnknown),
    362     MAKE_ENUM_PAIR(MediaEventType, METransformNeedInput),
    363     MAKE_ENUM_PAIR(MediaEventType, METransformHaveOutput),
    364     MAKE_ENUM_PAIR(MediaEventType, METransformDrainComplete),
    365     MAKE_ENUM_PAIR(MediaEventType, METransformMarker),
    366 #if (WINVER >= 0x0602) // Available since Win 8
    367     MAKE_ENUM_PAIR(MediaEventType, MEByteStreamCharacteristicsChanged),
    368     MAKE_ENUM_PAIR(MediaEventType, MEVideoCaptureDeviceRemoved),
    369     MAKE_ENUM_PAIR(MediaEventType, MEVideoCaptureDevicePreempted),
    370 #endif
    371     MAKE_ENUM_PAIR(MediaEventType, MEReservedMax)
    372 };
    373 MAKE_MAP(MediaEventType) MediaEventTypeMap(MediaEventTypePairs, MediaEventTypePairs + sizeof(MediaEventTypePairs) / sizeof(MediaEventTypePairs[0]));
    374 
    375 MAKE_ENUM(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypePairs[] = {
    376     MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_DEFAULT),
    377     MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_ENDOFSEGMENT),
    378     MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_TICK),
    379     MAKE_ENUM_PAIR(MFSTREAMSINK_MARKER_TYPE, MFSTREAMSINK_MARKER_EVENT)
    380 };
    381 MAKE_MAP(MFSTREAMSINK_MARKER_TYPE) StreamSinkMarkerTypeMap(StreamSinkMarkerTypePairs, StreamSinkMarkerTypePairs + sizeof(StreamSinkMarkerTypePairs) / sizeof(StreamSinkMarkerTypePairs[0]));
    382 
    383 #ifdef WINRT
    384 
    385 #ifdef __cplusplus_winrt
    386 #define _ContextCallback Concurrency::details::_ContextCallback
    387 #define BEGIN_CALL_IN_CONTEXT(hr, var, ...) hr = S_OK;\
    388     var._CallInContext([__VA_ARGS__]() {
    389 #define END_CALL_IN_CONTEXT(hr) if (FAILED(hr)) throw Platform::Exception::CreateException(hr);\
    390 });
    391 #define END_CALL_IN_CONTEXT_BASE });
    392 #else
    393 #define _ContextCallback Concurrency_winrt::details::_ContextCallback
    394 #define BEGIN_CALL_IN_CONTEXT(hr, var, ...) hr = var._CallInContext([__VA_ARGS__]() -> HRESULT {
    395 #define END_CALL_IN_CONTEXT(hr) return hr;\
    396 });
    397 #define END_CALL_IN_CONTEXT_BASE return S_OK;\
    398 });
    399 #endif
    400 #define GET_CURRENT_CONTEXT _ContextCallback::_CaptureCurrent()
    401 #define SAVE_CURRENT_CONTEXT(var) _ContextCallback var = GET_CURRENT_CONTEXT
    402 
    403 #define COMMA ,
    404 
    405 #ifdef __cplusplus_winrt
    406 #define _Object Platform::Object^
    407 #define _ObjectObj Platform::Object^
    408 #define _String Platform::String^
    409 #define _StringObj Platform::String^
    410 #define _StringReference ref new Platform::String
    411 #define _StringReferenceObj Platform::String^
    412 #define _DeviceInformationCollection Windows::Devices::Enumeration::DeviceInformationCollection
    413 #define _MediaCapture Windows::Media::Capture::MediaCapture
    414 #define _MediaCaptureVideoPreview Windows::Media::Capture::MediaCapture
    415 #define _MediaCaptureInitializationSettings Windows::Media::Capture::MediaCaptureInitializationSettings
    416 #define _VideoDeviceController Windows::Media::Devices::VideoDeviceController
    417 #define _MediaDeviceController Windows::Media::Devices::VideoDeviceController
    418 #define _MediaEncodingProperties Windows::Media::MediaProperties::IMediaEncodingProperties
    419 #define _VideoEncodingProperties Windows::Media::MediaProperties::VideoEncodingProperties
    420 #define _MediaStreamType Windows::Media::Capture::MediaStreamType
    421 #define _AsyncInfo Windows::Foundation::IAsyncInfo
    422 #define _AsyncAction Windows::Foundation::IAsyncAction
    423 #define _AsyncOperation Windows::Foundation::IAsyncOperation
    424 #define _DeviceClass Windows::Devices::Enumeration::DeviceClass
    425 #define _IDeviceInformation Windows::Devices::Enumeration::DeviceInformation
    426 #define _DeviceInformation Windows::Devices::Enumeration::DeviceInformation
    427 #define _DeviceInformationStatics Windows::Devices::Enumeration::DeviceInformation
    428 #define _MediaEncodingProfile Windows::Media::MediaProperties::MediaEncodingProfile
    429 #define _StreamingCaptureMode Windows::Media::Capture::StreamingCaptureMode
    430 #define _PropertySet Windows::Foundation::Collections::PropertySet
    431 #define _Map Windows::Foundation::Collections::PropertySet
    432 #define _PropertyValueStatics Windows::Foundation::PropertyValue
    433 #define _VectorView Windows::Foundation::Collections::IVectorView
    434 #define _StartPreviewToCustomSinkIdAsync StartPreviewToCustomSinkAsync
    435 #define _InitializeWithSettingsAsync InitializeAsync
    436 #define _FindAllAsyncDeviceClass FindAllAsync
    437 #define _MediaExtension Windows::Media::IMediaExtension
    438 #define BEGIN_CREATE_ASYNC(type, ...) (Concurrency::create_async([__VA_ARGS__]() {
    439 #define END_CREATE_ASYNC(hr) if (FAILED(hr)) throw Platform::Exception::CreateException(hr);\
    440 }))
    441 #define DEFINE_TASK Concurrency::task
    442 #define CREATE_TASK Concurrency::create_task
    443 #define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency::task<rettype>()) ? Concurrency::create_task(func) : _task.then([func](rettype) -> rettype { return func(); });
    444 #define DEFINE_RET_VAL(x)
    445 #define DEFINE_RET_TYPE(x)
    446 #define DEFINE_RET_FORMAL(x) x
    447 #define RET_VAL(x) return x;
    448 #define RET_VAL_BASE
    449 #define MAKE_STRING(str) str
    450 #define GET_STL_STRING(str) std::wstring(str->Data())
    451 #define GET_STL_STRING_RAW(str) std::wstring(str->Data())
    452 #define MAKE_WRL_OBJ(x) x^
    453 #define MAKE_WRL_REF(x) x^
    454 #define MAKE_OBJ_REF(x) x^
    455 #define MAKE_WRL_AGILE_REF(x) Platform::Agile<x^>
    456 #define MAKE_PROPERTY_BACKING(Type, PropName) property Type PropName;
    457 #define MAKE_PROPERTY(Type, PropName, PropValue)
    458 #define MAKE_PROPERTY_STRING(Type, PropName, PropValue)
    459 #define MAKE_READONLY_PROPERTY(Type, PropName, PropValue) property Type PropName\
    460 {\
    461     Type get() { return PropValue; }\
    462 }
    463 #define THROW_INVALID_ARG throw ref new Platform::InvalidArgumentException();
    464 #define RELEASE_AGILE_WRL(x) x = nullptr;
    465 #define RELEASE_WRL(x) x = nullptr;
    466 #define GET_WRL_OBJ_FROM_REF(objtype, obj, orig, hr) objtype^ obj = orig;\
    467 hr = S_OK;
    468 #define GET_WRL_OBJ_FROM_OBJ(objtype, obj, orig, hr) objtype^ obj = safe_cast<objtype^>(orig);\
    469 hr = S_OK;
    470 #define WRL_ENUM_GET(obj, prefix, prop) obj::##prop
    471 #define WRL_PROP_GET(obj, prop, arg, hr) arg = obj->##prop;\
    472 hr = S_OK;
    473 #define WRL_PROP_PUT(obj, prop, arg, hr) obj->##prop = arg;\
    474 hr = S_OK;
    475 #define WRL_METHOD_BASE(obj, method, ret, hr) ret = obj->##method();\
    476 hr = S_OK;
    477 #define WRL_METHOD(obj, method, ret, hr, ...) ret = obj->##method(__VA_ARGS__);\
    478 hr = S_OK;
    479 #define WRL_METHOD_NORET_BASE(obj, method, hr) obj->##method();\
    480     hr = S_OK;
    481 #define WRL_METHOD_NORET(obj, method, hr, ...) obj->##method(__VA_ARGS__);\
    482     hr = S_OK;
    483 #define REF_WRL_OBJ(obj) &obj
    484 #define DEREF_WRL_OBJ(obj) obj
    485 #define DEREF_AGILE_WRL_OBJ(obj) obj.Get()
    486 #define DEREF_AS_NATIVE_WRL_OBJ(type, obj) reinterpret_cast<type*>(obj)
    487 #define PREPARE_TRANSFER_WRL_OBJ(obj) obj
    488 #define ACTIVATE_LOCAL_OBJ_BASE(objtype) ref new objtype()
    489 #define ACTIVATE_LOCAL_OBJ(objtype, ...) ref new objtype(__VA_ARGS__)
    490 #define ACTIVATE_EVENT_HANDLER(objtype, ...) ref new objtype(__VA_ARGS__)
    491 #define ACTIVATE_OBJ(rtclass, objtype, obj, hr) MAKE_WRL_OBJ(objtype) obj = ref new objtype();\
    492 hr = S_OK;
    493 #define ACTIVATE_STATIC_OBJ(rtclass, objtype, obj, hr) objtype obj;\
    494 hr = S_OK;
    495 #else
    496 #define _Object IInspectable*
    497 #define _ObjectObj Microsoft::WRL::ComPtr<IInspectable>
    498 #define _String HSTRING
    499 #define _StringObj Microsoft::WRL::Wrappers::HString
    500 #define _StringReference Microsoft::WRL::Wrappers::HStringReference
    501 #define _StringReferenceObj Microsoft::WRL::Wrappers::HStringReference
    502 #define _DeviceInformationCollection ABI::Windows::Devices::Enumeration::DeviceInformationCollection
    503 #define _MediaCapture ABI::Windows::Media::Capture::IMediaCapture
    504 #define _MediaCaptureVideoPreview ABI::Windows::Media::Capture::IMediaCaptureVideoPreview
    505 #define _MediaCaptureInitializationSettings ABI::Windows::Media::Capture::IMediaCaptureInitializationSettings
    506 #define _VideoDeviceController ABI::Windows::Media::Devices::IVideoDeviceController
    507 #define _MediaDeviceController ABI::Windows::Media::Devices::IMediaDeviceController
    508 #define _MediaEncodingProperties ABI::Windows::Media::MediaProperties::IMediaEncodingProperties
    509 #define _VideoEncodingProperties ABI::Windows::Media::MediaProperties::IVideoEncodingProperties
    510 #define _MediaStreamType ABI::Windows::Media::Capture::MediaStreamType
    511 #define _AsyncInfo ABI::Windows::Foundation::IAsyncInfo
    512 #define _AsyncAction ABI::Windows::Foundation::IAsyncAction
    513 #define _AsyncOperation ABI::Windows::Foundation::IAsyncOperation
    514 #define _DeviceClass ABI::Windows::Devices::Enumeration::DeviceClass
    515 #define _IDeviceInformation ABI::Windows::Devices::Enumeration::IDeviceInformation
    516 #define _DeviceInformation ABI::Windows::Devices::Enumeration::DeviceInformation
    517 #define _DeviceInformationStatics ABI::Windows::Devices::Enumeration::IDeviceInformationStatics
    518 #define _MediaEncodingProfile ABI::Windows::Media::MediaProperties::IMediaEncodingProfile
    519 #define _StreamingCaptureMode ABI::Windows::Media::Capture::StreamingCaptureMode
    520 #define _PropertySet ABI::Windows::Foundation::Collections::IPropertySet
    521 #define _Map ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable *>
    522 #define _PropertyValueStatics ABI::Windows::Foundation::IPropertyValueStatics
    523 #define _VectorView ABI::Windows::Foundation::Collections::IVectorView
    524 #define _StartPreviewToCustomSinkIdAsync StartPreviewToCustomSinkIdAsync
    525 #define _InitializeWithSettingsAsync InitializeWithSettingsAsync
    526 #define _FindAllAsyncDeviceClass FindAllAsyncDeviceClass
    527 #define _MediaExtension ABI::Windows::Media::IMediaExtension
    528 #define BEGIN_CREATE_ASYNC(type, ...) Concurrency_winrt::create_async<type>([__VA_ARGS__]() -> HRESULT {
    529 #define END_CREATE_ASYNC(hr) return hr;\
    530 })
    531 #define DEFINE_TASK Concurrency_winrt::task
    532 #define CREATE_TASK Concurrency_winrt::create_task
    533 #define CREATE_OR_CONTINUE_TASK(_task, rettype, func) _task = (_task == Concurrency_winrt::task<rettype>()) ? Concurrency_winrt::create_task<rettype>(func) : _task.then([func](rettype, rettype* retVal) -> HRESULT { return func(retVal); });
    534 #define DEFINE_RET_VAL(x) x* retVal
    535 #define DEFINE_RET_TYPE(x) <x>
    536 #define DEFINE_RET_FORMAL(x) HRESULT
    537 #define RET_VAL(x) *retVal = x;\
    538 return S_OK;
    539 #define RET_VAL_BASE return S_OK;
    540 #define MAKE_STRING(str) Microsoft::WRL::Wrappers::HStringReference(L##str)
    541 #define GET_STL_STRING(str) std::wstring(str.GetRawBuffer(NULL))
    542 #define GET_STL_STRING_RAW(str) WindowsGetStringRawBuffer(str, NULL)
    543 #define MAKE_WRL_OBJ(x) Microsoft::WRL::ComPtr<x>
    544 #define MAKE_WRL_REF(x) x*
    545 #define MAKE_OBJ_REF(x) x
    546 #define MAKE_WRL_AGILE_REF(x) x*
    547 #define MAKE_PROPERTY_BACKING(Type, PropName) Type PropName;
    548 #define MAKE_PROPERTY(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { *pVal = PropValue; } else { return E_INVALIDARG; } return S_OK; }\
    549     STDMETHODIMP put_##PropName(Type Val) { PropValue = Val; return S_OK; }
    550 #define MAKE_PROPERTY_STRING(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { return ::WindowsDuplicateString(PropValue.Get(), pVal); } else { return E_INVALIDARG; } }\
    551     STDMETHODIMP put_##PropName(Type Val) { return PropValue.Set(Val); }
    552 #define MAKE_READONLY_PROPERTY(Type, PropName, PropValue) STDMETHODIMP get_##PropName(Type* pVal) { if (pVal) { *pVal = PropValue; } else { return E_INVALIDARG; } return S_OK; }
    553 #define THROW_INVALID_ARG RoOriginateError(E_INVALIDARG, nullptr);
    554 #define RELEASE_AGILE_WRL(x) if (x) { (x)->Release(); x = nullptr; }
    555 #define RELEASE_WRL(x) if (x) { (x)->Release(); x = nullptr; }
    556 #define GET_WRL_OBJ_FROM_REF(objtype, obj, orig, hr) Microsoft::WRL::ComPtr<objtype> obj;\
    557 hr = orig->QueryInterface(__uuidof(objtype), &obj);
    558 #define GET_WRL_OBJ_FROM_OBJ(objtype, obj, orig, hr) Microsoft::WRL::ComPtr<objtype> obj;\
    559 hr = orig.As(&obj);
    560 #define WRL_ENUM_GET(obj, prefix, prop) obj::prefix##_##prop
    561 #define WRL_PROP_GET(obj, prop, arg, hr) hr = obj->get_##prop(&arg);
    562 #define WRL_PROP_PUT(obj, prop, arg, hr) hr = obj->put_##prop(arg);
    563 #define WRL_METHOD_BASE(obj, method, ret, hr) hr = obj->##method(&ret);
    564 #define WRL_METHOD(obj, method, ret, hr, ...) hr = obj->##method(__VA_ARGS__, &ret);
    565 #define WRL_METHOD_NORET_BASE(obj, method, hr) hr = obj->##method();
    566 #define REF_WRL_OBJ(obj) obj.GetAddressOf()
    567 #define DEREF_WRL_OBJ(obj) obj.Get()
    568 #define DEREF_AGILE_WRL_OBJ(obj) obj
    569 #define DEREF_AS_NATIVE_WRL_OBJ(type, obj) obj.Get()
    570 #define PREPARE_TRANSFER_WRL_OBJ(obj) obj.Detach()
    571 #define ACTIVATE_LOCAL_OBJ_BASE(objtype) Microsoft::WRL::Make<objtype>()
    572 #define ACTIVATE_LOCAL_OBJ(objtype, ...) Microsoft::WRL::Make<objtype>(__VA_ARGS__)
    573 #define ACTIVATE_EVENT_HANDLER(objtype, ...) Microsoft::WRL::Callback<objtype>(__VA_ARGS__).Get()
    574 #define ACTIVATE_OBJ(rtclass, objtype, obj, hr) MAKE_WRL_OBJ(objtype) obj;\
    575 {\
    576     Microsoft::WRL::ComPtr<IActivationFactory> objFactory;\
    577     hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(rtclass).Get(), objFactory.ReleaseAndGetAddressOf());\
    578     if (SUCCEEDED(hr)) {\
    579         Microsoft::WRL::ComPtr<IInspectable> pInsp;\
    580         hr = objFactory->ActivateInstance(pInsp.GetAddressOf());\
    581         if (SUCCEEDED(hr)) hr = pInsp.As(&obj);\
    582     }\
    583 }
    584 #define ACTIVATE_STATIC_OBJ(rtclass, objtype, obj, hr) objtype obj;\
    585 {\
    586     Microsoft::WRL::ComPtr<IActivationFactory> objFactory;\
    587     hr = Windows::Foundation::GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(rtclass).Get(), objFactory.ReleaseAndGetAddressOf());\
    588     if (SUCCEEDED(hr)) {\
    589         if (SUCCEEDED(hr)) hr = objFactory.As(&obj);\
    590     }\
    591 }
    592 #endif
    593 
    594 #define _ComPtr Microsoft::WRL::ComPtr
    595 #else
    596 
    597 #define _COM_SMARTPTR_DECLARE(T,var) T ## Ptr var
    598 
    599 template <class T>
    600 class ComPtr
    601 {
    602 public:
    603     ComPtr() throw()
    604     {
    605     }
    606     ComPtr(T* lp) throw()
    607     {
    608         p = lp;
    609     }
    610     ComPtr(_In_ const ComPtr<T>& lp) throw()
    611     {
    612         p = lp.p;
    613     }
    614     virtual ~ComPtr()
    615     {
    616     }
    617 
    618     T** operator&() throw()
    619     {
    620         assert(p == NULL);
    621         return p.operator&();
    622     }
    623     T* operator->() const throw()
    624     {
    625         assert(p != NULL);
    626         return p.operator->();
    627     }
    628     bool operator!() const throw()
    629     {
    630         return p.operator==(NULL);
    631     }
    632     bool operator==(_In_opt_ T* pT) const throw()
    633     {
    634         return p.operator==(pT);
    635     }
    636     bool operator!=(_In_opt_ T* pT) const throw()
    637     {
    638         return p.operator!=(pT);
    639     }
    640     operator bool()
    641     {
    642         return p.operator!=(NULL);
    643     }
    644 
    645     T* const* GetAddressOf() const throw()
    646     {
    647         return &p;
    648     }
    649 
    650     T** GetAddressOf() throw()
    651     {
    652         return &p;
    653     }
    654 
    655     T** ReleaseAndGetAddressOf() throw()
    656     {
    657         p.Release();
    658         return &p;
    659     }
    660 
    661     T* Get() const throw()
    662     {
    663         return p;
    664     }
    665 
    666     // Attach to an existing interface (does not AddRef)
    667     void Attach(_In_opt_ T* p2) throw()
    668     {
    669         p.Attach(p2);
    670     }
    671     // Detach the interface (does not Release)
    672     T* Detach() throw()
    673     {
    674         return p.Detach();
    675     }
    676     _Check_return_ HRESULT CopyTo(_Deref_out_opt_ T** ppT) throw()
    677     {
    678         assert(ppT != NULL);
    679         if (ppT == NULL)
    680             return E_POINTER;
    681         *ppT = p;
    682         if (p != NULL)
    683             p->AddRef();
    684         return S_OK;
    685     }
    686 
    687     void Reset()
    688     {
    689         p.Release();
    690     }
    691 
    692     // query for U interface
    693     template<typename U>
    694     HRESULT As(_Inout_ U** lp) const throw()
    695     {
    696         return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>(lp));
    697     }
    698     // query for U interface
    699     template<typename U>
    700     HRESULT As(_Out_ ComPtr<U>* lp) const throw()
    701     {
    702         return p->QueryInterface(__uuidof(U), reinterpret_cast<void**>(lp->ReleaseAndGetAddressOf()));
    703     }
    704 private:
    705     _COM_SMARTPTR_TYPEDEF(T, __uuidof(T));
    706     _COM_SMARTPTR_DECLARE(T, p);
    707 };
    708 
    709 #define _ComPtr ComPtr
    710 #endif
    711 
    712 template <class TBase=IMFAttributes>
    713 class CBaseAttributes : public TBase
    714 {
    715 protected:
    716     // This version of the constructor does not initialize the
    717     // attribute store. The derived class must call Initialize() in
    718     // its own constructor.
    719     CBaseAttributes()
    720     {
    721     }
    722 
    723     // This version of the constructor initializes the attribute
    724     // store, but the derived class must pass an HRESULT parameter
    725     // to the constructor.
    726 
    727     CBaseAttributes(HRESULT& hr, UINT32 cInitialSize = 0)
    728     {
    729         hr = Initialize(cInitialSize);
    730     }
    731 
    732     // The next version of the constructor uses a caller-provided
    733     // implementation of IMFAttributes.
    734 
    735     // (Sometimes you want to delegate IMFAttributes calls to some
    736     // other object that implements IMFAttributes, rather than using
    737     // MFCreateAttributes.)
    738 
    739     CBaseAttributes(HRESULT& hr, IUnknown *pUnk)
    740     {
    741         hr = Initialize(pUnk);
    742     }
    743 
    744     virtual ~CBaseAttributes()
    745     {
    746     }
    747 
    748     // Initializes the object by creating the standard Media Foundation attribute store.
    749     HRESULT Initialize(UINT32 cInitialSize = 0)
    750     {
    751         if (_spAttributes.Get() == nullptr)
    752         {
    753             return MFCreateAttributes(&_spAttributes, cInitialSize);
    754         }
    755         else
    756         {
    757             return S_OK;
    758         }
    759     }
    760 
    761     // Initializes this object from a caller-provided attribute store.
    762     // pUnk: Pointer to an object that exposes IMFAttributes.
    763     HRESULT Initialize(IUnknown *pUnk)
    764     {
    765         if (_spAttributes)
    766         {
    767             _spAttributes.Reset();
    768             _spAttributes = nullptr;
    769         }
    770 
    771 
    772         return pUnk->QueryInterface(IID_PPV_ARGS(&_spAttributes));
    773     }
    774 
    775 public:
    776 
    777     // IMFAttributes methods
    778 
    779     STDMETHODIMP GetItem(REFGUID guidKey, PROPVARIANT* pValue)
    780     {
    781         assert(_spAttributes);
    782         return _spAttributes->GetItem(guidKey, pValue);
    783     }
    784 
    785     STDMETHODIMP GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType)
    786     {
    787         assert(_spAttributes);
    788         return _spAttributes->GetItemType(guidKey, pType);
    789     }
    790 
    791     STDMETHODIMP CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult)
    792     {
    793         assert(_spAttributes);
    794         return _spAttributes->CompareItem(guidKey, Value, pbResult);
    795     }
    796 
    797     STDMETHODIMP Compare(
    798         IMFAttributes* pTheirs,
    799         MF_ATTRIBUTES_MATCH_TYPE MatchType,
    800         BOOL* pbResult
    801         )
    802     {
    803         assert(_spAttributes);
    804         return _spAttributes->Compare(pTheirs, MatchType, pbResult);
    805     }
    806 
    807     STDMETHODIMP GetUINT32(REFGUID guidKey, UINT32* punValue)
    808     {
    809         assert(_spAttributes);
    810         return _spAttributes->GetUINT32(guidKey, punValue);
    811     }
    812 
    813     STDMETHODIMP GetUINT64(REFGUID guidKey, UINT64* punValue)
    814     {
    815         assert(_spAttributes);
    816         return _spAttributes->GetUINT64(guidKey, punValue);
    817     }
    818 
    819     STDMETHODIMP GetDouble(REFGUID guidKey, double* pfValue)
    820     {
    821         assert(_spAttributes);
    822         return _spAttributes->GetDouble(guidKey, pfValue);
    823     }
    824 
    825     STDMETHODIMP GetGUID(REFGUID guidKey, GUID* pguidValue)
    826     {
    827         assert(_spAttributes);
    828         return _spAttributes->GetGUID(guidKey, pguidValue);
    829     }
    830 
    831     STDMETHODIMP GetStringLength(REFGUID guidKey, UINT32* pcchLength)
    832     {
    833         assert(_spAttributes);
    834         return _spAttributes->GetStringLength(guidKey, pcchLength);
    835     }
    836 
    837     STDMETHODIMP GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength)
    838     {
    839         assert(_spAttributes);
    840         return _spAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
    841     }
    842 
    843     STDMETHODIMP GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength)
    844     {
    845         assert(_spAttributes);
    846         return _spAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
    847     }
    848 
    849     STDMETHODIMP GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize)
    850     {
    851         assert(_spAttributes);
    852         return _spAttributes->GetBlobSize(guidKey, pcbBlobSize);
    853     }
    854 
    855     STDMETHODIMP GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize)
    856     {
    857         assert(_spAttributes);
    858         return _spAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
    859     }
    860 
    861     STDMETHODIMP GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize)
    862     {
    863         assert(_spAttributes);
    864         return _spAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
    865     }
    866 
    867     STDMETHODIMP GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv)
    868     {
    869         assert(_spAttributes);
    870         return _spAttributes->GetUnknown(guidKey, riid, ppv);
    871     }
    872 
    873     STDMETHODIMP SetItem(REFGUID guidKey, REFPROPVARIANT Value)
    874     {
    875         assert(_spAttributes);
    876         return _spAttributes->SetItem(guidKey, Value);
    877     }
    878 
    879     STDMETHODIMP DeleteItem(REFGUID guidKey)
    880     {
    881         assert(_spAttributes);
    882         return _spAttributes->DeleteItem(guidKey);
    883     }
    884 
    885     STDMETHODIMP DeleteAllItems()
    886     {
    887         assert(_spAttributes);
    888         return _spAttributes->DeleteAllItems();
    889     }
    890 
    891     STDMETHODIMP SetUINT32(REFGUID guidKey, UINT32 unValue)
    892     {
    893         assert(_spAttributes);
    894         return _spAttributes->SetUINT32(guidKey, unValue);
    895     }
    896 
    897     STDMETHODIMP SetUINT64(REFGUID guidKey,UINT64 unValue)
    898     {
    899         assert(_spAttributes);
    900         return _spAttributes->SetUINT64(guidKey, unValue);
    901     }
    902 
    903     STDMETHODIMP SetDouble(REFGUID guidKey, double fValue)
    904     {
    905         assert(_spAttributes);
    906         return _spAttributes->SetDouble(guidKey, fValue);
    907     }
    908 
    909     STDMETHODIMP SetGUID(REFGUID guidKey, REFGUID guidValue)
    910     {
    911         assert(_spAttributes);
    912         return _spAttributes->SetGUID(guidKey, guidValue);
    913     }
    914 
    915     STDMETHODIMP SetString(REFGUID guidKey, LPCWSTR wszValue)
    916     {
    917         assert(_spAttributes);
    918         return _spAttributes->SetString(guidKey, wszValue);
    919     }
    920 
    921     STDMETHODIMP SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize)
    922     {
    923         assert(_spAttributes);
    924         return _spAttributes->SetBlob(guidKey, pBuf, cbBufSize);
    925     }
    926 
    927     STDMETHODIMP SetUnknown(REFGUID guidKey, IUnknown* pUnknown)
    928     {
    929         assert(_spAttributes);
    930         return _spAttributes->SetUnknown(guidKey, pUnknown);
    931     }
    932 
    933     STDMETHODIMP LockStore()
    934     {
    935         assert(_spAttributes);
    936         return _spAttributes->LockStore();
    937     }
    938 
    939     STDMETHODIMP UnlockStore()
    940     {
    941         assert(_spAttributes);
    942         return _spAttributes->UnlockStore();
    943     }
    944 
    945     STDMETHODIMP GetCount(UINT32* pcItems)
    946     {
    947         assert(_spAttributes);
    948         return _spAttributes->GetCount(pcItems);
    949     }
    950 
    951     STDMETHODIMP GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue)
    952     {
    953         assert(_spAttributes);
    954         return _spAttributes->GetItemByIndex(unIndex, pguidKey, pValue);
    955     }
    956 
    957     STDMETHODIMP CopyAllItems(IMFAttributes* pDest)
    958     {
    959         assert(_spAttributes);
    960         return _spAttributes->CopyAllItems(pDest);
    961     }
    962 
    963     // Helper functions
    964 
    965     HRESULT SerializeToStream(DWORD dwOptions, IStream* pStm)
    966         // dwOptions: Flags from MF_ATTRIBUTE_SERIALIZE_OPTIONS
    967     {
    968         assert(_spAttributes);
    969         return MFSerializeAttributesToStream(_spAttributes.Get(), dwOptions, pStm);
    970     }
    971 
    972     HRESULT DeserializeFromStream(DWORD dwOptions, IStream* pStm)
    973     {
    974         assert(_spAttributes);
    975         return MFDeserializeAttributesFromStream(_spAttributes.Get(), dwOptions, pStm);
    976     }
    977 
    978     // SerializeToBlob: Stores the attributes in a byte array.
    979     //
    980     // ppBuf: Receives a pointer to the byte array.
    981     // pcbSize: Receives the size of the byte array.
    982     //
    983     // The caller must free the array using CoTaskMemFree.
    984     HRESULT SerializeToBlob(UINT8 **ppBuffer, UINT *pcbSize)
    985     {
    986         assert(_spAttributes);
    987 
    988         if (ppBuffer == NULL)
    989         {
    990             return E_POINTER;
    991         }
    992         if (pcbSize == NULL)
    993         {
    994             return E_POINTER;
    995         }
    996 
    997         HRESULT hr = S_OK;
    998         UINT32 cbSize = 0;
    999         BYTE *pBuffer = NULL;
   1000 
   1001         CHECK_HR(hr = MFGetAttributesAsBlobSize(_spAttributes.Get(), &cbSize));
   1002 
   1003         pBuffer = (BYTE*)CoTaskMemAlloc(cbSize);
   1004         if (pBuffer == NULL)
   1005         {
   1006             CHECK_HR(hr = E_OUTOFMEMORY);
   1007         }
   1008 
   1009         CHECK_HR(hr = MFGetAttributesAsBlob(_spAttributes.Get(), pBuffer, cbSize));
   1010 
   1011         *ppBuffer = pBuffer;
   1012         *pcbSize = cbSize;
   1013 
   1014 done:
   1015         if (FAILED(hr))
   1016         {
   1017             *ppBuffer = NULL;
   1018             *pcbSize = 0;
   1019             CoTaskMemFree(pBuffer);
   1020         }
   1021         return hr;
   1022     }
   1023 
   1024     HRESULT DeserializeFromBlob(const UINT8* pBuffer, UINT cbSize)
   1025     {
   1026         assert(_spAttributes);
   1027         return MFInitAttributesFromBlob(_spAttributes.Get(), pBuffer, cbSize);
   1028     }
   1029 
   1030     HRESULT GetRatio(REFGUID guidKey, UINT32* pnNumerator, UINT32* punDenominator)
   1031     {
   1032         assert(_spAttributes);
   1033         return MFGetAttributeRatio(_spAttributes.Get(), guidKey, pnNumerator, punDenominator);
   1034     }
   1035 
   1036     HRESULT SetRatio(REFGUID guidKey, UINT32 unNumerator, UINT32 unDenominator)
   1037     {
   1038         assert(_spAttributes);
   1039         return MFSetAttributeRatio(_spAttributes.Get(), guidKey, unNumerator, unDenominator);
   1040     }
   1041 
   1042     // Gets an attribute whose value represents the size of something (eg a video frame).
   1043     HRESULT GetSize(REFGUID guidKey, UINT32* punWidth, UINT32* punHeight)
   1044     {
   1045         assert(_spAttributes);
   1046         return MFGetAttributeSize(_spAttributes.Get(), guidKey, punWidth, punHeight);
   1047     }
   1048 
   1049     // Sets an attribute whose value represents the size of something (eg a video frame).
   1050     HRESULT SetSize(REFGUID guidKey, UINT32 unWidth, UINT32 unHeight)
   1051     {
   1052         assert(_spAttributes);
   1053         return MFSetAttributeSize (_spAttributes.Get(), guidKey, unWidth, unHeight);
   1054     }
   1055 
   1056 protected:
   1057     _ComPtr<IMFAttributes> _spAttributes;
   1058 };
   1059 
   1060 class StreamSink :
   1061 #ifdef WINRT
   1062     public Microsoft::WRL::RuntimeClass<
   1063     Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::ClassicCom>,
   1064     IMFStreamSink,
   1065     IMFMediaEventGenerator,
   1066     IMFMediaTypeHandler,
   1067     CBaseAttributes<> >
   1068 #else
   1069     public IMFStreamSink,
   1070     public IMFMediaTypeHandler,
   1071     public CBaseAttributes<>,
   1072     public ICustomStreamSink
   1073 #endif
   1074 {
   1075 public:
   1076     // IUnknown methods
   1077 #if defined(_MSC_VER) && _MSC_VER >= 1700  // '_Outptr_result_nullonfailure_' SAL is avaialable since VS 2012
   1078     STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppv)
   1079 #else
   1080     STDMETHOD(QueryInterface)(REFIID riid, void **ppv)
   1081 #endif
   1082     {
   1083         if (ppv == nullptr) {
   1084             return E_POINTER;
   1085         }
   1086         (*ppv) = nullptr;
   1087         HRESULT hr = S_OK;
   1088         if (riid == IID_IMarshal) {
   1089             return MarshalQI(riid, ppv);
   1090         } else {
   1091 #ifdef WINRT
   1092             hr = RuntimeClassT::QueryInterface(riid, ppv);
   1093 #else
   1094             if (riid == IID_IUnknown || riid == IID_IMFStreamSink) {
   1095                 *ppv = static_cast<IMFStreamSink*>(this);
   1096                 AddRef();
   1097             } else if (riid == IID_IMFMediaEventGenerator) {
   1098                 *ppv = static_cast<IMFMediaEventGenerator*>(this);
   1099                 AddRef();
   1100             } else if (riid == IID_IMFMediaTypeHandler) {
   1101                 *ppv = static_cast<IMFMediaTypeHandler*>(this);
   1102                 AddRef();
   1103             } else if (riid == IID_IMFAttributes) {
   1104                 *ppv = static_cast<IMFAttributes*>(this);
   1105                 AddRef();
   1106             } else if (riid == IID_ICustomStreamSink) {
   1107                 *ppv = static_cast<ICustomStreamSink*>(this);
   1108                 AddRef();
   1109             } else
   1110                 hr = E_NOINTERFACE;
   1111 #endif
   1112         }
   1113 
   1114         return hr;
   1115     }
   1116 
   1117 #ifdef WINRT
   1118     STDMETHOD(RuntimeClassInitialize)() { return S_OK; }
   1119 #else
   1120     ULONG STDMETHODCALLTYPE AddRef()
   1121     {
   1122         return InterlockedIncrement(&m_cRef);
   1123     }
   1124     ULONG STDMETHODCALLTYPE Release()
   1125     {
   1126         ULONG cRef = InterlockedDecrement(&m_cRef);
   1127         if (cRef == 0)
   1128         {
   1129             delete this;
   1130         }
   1131         return cRef;
   1132     }
   1133 #endif
   1134     HRESULT MarshalQI(REFIID riid, LPVOID* ppv)
   1135     {
   1136         HRESULT hr = S_OK;
   1137         if (m_spFTM == nullptr) {
   1138             EnterCriticalSection(&m_critSec);
   1139             if (m_spFTM == nullptr) {
   1140                 hr = CoCreateFreeThreadedMarshaler((IMFStreamSink*)this, &m_spFTM);
   1141             }
   1142             LeaveCriticalSection(&m_critSec);
   1143         }
   1144 
   1145         if (SUCCEEDED(hr)) {
   1146             if (m_spFTM == nullptr) {
   1147                 hr = E_UNEXPECTED;
   1148             }
   1149             else {
   1150                 hr = m_spFTM.Get()->QueryInterface(riid, ppv);
   1151             }
   1152         }
   1153         return hr;
   1154     }
   1155     enum State
   1156     {
   1157         State_TypeNotSet = 0,    // No media type is set
   1158         State_Ready,             // Media type is set, Start has never been called.
   1159         State_Started,
   1160         State_Stopped,
   1161         State_Paused,
   1162         State_Count              // Number of states
   1163     };
   1164     StreamSink() : m_IsShutdown(false),
   1165         m_StartTime(0), m_fGetStartTimeFromSample(false), m_fWaitingForFirstSample(false),
   1166         m_state(State_TypeNotSet), m_pParent(nullptr),
   1167         m_imageWidthInPixels(0), m_imageHeightInPixels(0) {
   1168 #ifdef WINRT
   1169         m_token.value = 0;
   1170 #else
   1171         m_bConnected = false;
   1172 #endif
   1173         InitializeCriticalSectionEx(&m_critSec, 3000, 0);
   1174         ZeroMemory(&m_guiCurrentSubtype, sizeof(m_guiCurrentSubtype));
   1175         CBaseAttributes::Initialize(0U);
   1176         DebugPrintOut(L"StreamSink::StreamSink\n");
   1177     }
   1178     virtual ~StreamSink() {
   1179         DeleteCriticalSection(&m_critSec);
   1180         assert(m_IsShutdown);
   1181         DebugPrintOut(L"StreamSink::~StreamSink\n");
   1182     }
   1183 
   1184     HRESULT Initialize()
   1185     {
   1186         HRESULT hr;
   1187         // Create the event queue helper.
   1188         hr = MFCreateEventQueue(&m_spEventQueue);
   1189         if (SUCCEEDED(hr))
   1190         {
   1191             _ComPtr<IMFMediaSink> pMedSink;
   1192             hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf());
   1193             assert(pMedSink.Get() != NULL);
   1194             if (SUCCEEDED(hr)) {
   1195                 hr = pMedSink.Get()->QueryInterface(IID_PPV_ARGS(&m_pParent));
   1196             }
   1197         }
   1198         return hr;
   1199     }
   1200 
   1201     HRESULT CheckShutdown() const
   1202     {
   1203         if (m_IsShutdown)
   1204         {
   1205             return MF_E_SHUTDOWN;
   1206         }
   1207         else
   1208         {
   1209             return S_OK;
   1210         }
   1211     }
   1212     // Called when the presentation clock starts.
   1213     HRESULT Start(MFTIME start)
   1214     {
   1215         HRESULT hr = S_OK;
   1216         EnterCriticalSection(&m_critSec);
   1217         if (m_state != State_TypeNotSet) {
   1218             if (start != PRESENTATION_CURRENT_POSITION)
   1219             {
   1220                 m_StartTime = start;        // Cache the start time.
   1221                 m_fGetStartTimeFromSample = false;
   1222             }
   1223             else
   1224             {
   1225                 m_fGetStartTimeFromSample = true;
   1226             }
   1227             m_state = State_Started;
   1228             GUID guiMajorType;
   1229             m_fWaitingForFirstSample = SUCCEEDED(m_spCurrentType->GetMajorType(&guiMajorType)) && (guiMajorType == MFMediaType_Video);
   1230             hr = QueueEvent(MEStreamSinkStarted, GUID_NULL, hr, NULL);
   1231             if (SUCCEEDED(hr)) {
   1232                 hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, hr, NULL);
   1233             }
   1234         }
   1235         else hr = MF_E_NOT_INITIALIZED;
   1236         LeaveCriticalSection(&m_critSec);
   1237         return hr;
   1238     }
   1239 
   1240     // Called when the presentation clock pauses.
   1241     HRESULT Pause()
   1242     {
   1243         EnterCriticalSection(&m_critSec);
   1244 
   1245         HRESULT hr = S_OK;
   1246 
   1247         if (m_state != State_Stopped && m_state != State_TypeNotSet) {
   1248             m_state = State_Paused;
   1249             hr = QueueEvent(MEStreamSinkPaused, GUID_NULL, hr, NULL);
   1250         } else if (hr == State_TypeNotSet)
   1251             hr = MF_E_NOT_INITIALIZED;
   1252         else
   1253             hr = MF_E_INVALIDREQUEST;
   1254         LeaveCriticalSection(&m_critSec);
   1255         return hr;
   1256     }
   1257     // Called when the presentation clock restarts.
   1258     HRESULT Restart()
   1259     {
   1260         EnterCriticalSection(&m_critSec);
   1261 
   1262         HRESULT hr = S_OK;
   1263 
   1264         if (m_state == State_Paused) {
   1265             m_state = State_Started;
   1266             hr = QueueEvent(MEStreamSinkStarted, GUID_NULL, hr, NULL);
   1267             if (SUCCEEDED(hr)) {
   1268                 hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, hr, NULL);
   1269             }
   1270         } else if (hr == State_TypeNotSet)
   1271             hr = MF_E_NOT_INITIALIZED;
   1272         else
   1273             hr = MF_E_INVALIDREQUEST;
   1274         LeaveCriticalSection(&m_critSec);
   1275         return hr;
   1276     }
   1277     // Called when the presentation clock stops.
   1278     HRESULT Stop()
   1279     {
   1280         EnterCriticalSection(&m_critSec);
   1281 
   1282         HRESULT hr = S_OK;
   1283         if (m_state != State_TypeNotSet) {
   1284             m_state = State_Stopped;
   1285             hr = QueueEvent(MEStreamSinkStopped, GUID_NULL, hr, NULL);
   1286         }
   1287         else hr = MF_E_NOT_INITIALIZED;
   1288         LeaveCriticalSection(&m_critSec);
   1289         return hr;
   1290     }
   1291 
   1292     // Shuts down the stream sink.
   1293     HRESULT Shutdown()
   1294     {
   1295         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
   1296         HRESULT hr = S_OK;
   1297         assert(!m_IsShutdown);
   1298         hr = m_pParent->GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
   1299         if (SUCCEEDED(hr)) {
   1300             hr = pSampleCallback->OnShutdown();
   1301         }
   1302 
   1303         if (m_spEventQueue) {
   1304             hr = m_spEventQueue->Shutdown();
   1305         }
   1306         if (m_pParent)
   1307             m_pParent->Release();
   1308         m_spCurrentType.Reset();
   1309         m_IsShutdown = TRUE;
   1310 
   1311         return hr;
   1312     }
   1313 
   1314     //IMFStreamSink
   1315     HRESULT STDMETHODCALLTYPE GetMediaSink(
   1316     /* [out] */ __RPC__deref_out_opt IMFMediaSink **ppMediaSink) {
   1317         if (ppMediaSink == NULL)
   1318         {
   1319             return E_INVALIDARG;
   1320         }
   1321 
   1322         EnterCriticalSection(&m_critSec);
   1323 
   1324         HRESULT hr = CheckShutdown();
   1325 
   1326         if (SUCCEEDED(hr))
   1327         {
   1328             _ComPtr<IMFMediaSink> pMedSink;
   1329             hr = CBaseAttributes<>::GetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, __uuidof(IMFMediaSink), (LPVOID*)pMedSink.GetAddressOf());
   1330             if (SUCCEEDED(hr)) {
   1331                 *ppMediaSink = pMedSink.Detach();
   1332             }
   1333         }
   1334 
   1335         LeaveCriticalSection(&m_critSec);
   1336         DebugPrintOut(L"StreamSink::GetMediaSink: HRESULT=%i\n", hr);
   1337         return hr;
   1338     }
   1339 
   1340     HRESULT STDMETHODCALLTYPE GetIdentifier(
   1341         /* [out] */ __RPC__out DWORD *pdwIdentifier) {
   1342         if (pdwIdentifier == NULL)
   1343         {
   1344             return E_INVALIDARG;
   1345         }
   1346 
   1347         EnterCriticalSection(&m_critSec);
   1348 
   1349         HRESULT hr = CheckShutdown();
   1350 
   1351         if (SUCCEEDED(hr))
   1352         {
   1353             hr = GetUINT32(MF_STREAMSINK_ID, (UINT32*)pdwIdentifier);
   1354         }
   1355 
   1356         LeaveCriticalSection(&m_critSec);
   1357         DebugPrintOut(L"StreamSink::GetIdentifier: HRESULT=%i\n", hr);
   1358         return hr;
   1359     }
   1360 
   1361     HRESULT STDMETHODCALLTYPE GetMediaTypeHandler(
   1362         /* [out] */ __RPC__deref_out_opt IMFMediaTypeHandler **ppHandler) {
   1363         if (ppHandler == NULL)
   1364         {
   1365             return E_INVALIDARG;
   1366         }
   1367 
   1368         EnterCriticalSection(&m_critSec);
   1369 
   1370         HRESULT hr = CheckShutdown();
   1371 
   1372         // This stream object acts as its own type handler, so we QI ourselves.
   1373         if (SUCCEEDED(hr))
   1374         {
   1375             hr = QueryInterface(IID_IMFMediaTypeHandler, (void**)ppHandler);
   1376         }
   1377 
   1378         LeaveCriticalSection(&m_critSec);
   1379         DebugPrintOut(L"StreamSink::GetMediaTypeHandler: HRESULT=%i\n", hr);
   1380         return hr;
   1381     }
   1382 
   1383     HRESULT STDMETHODCALLTYPE ProcessSample(IMFSample *pSample) {
   1384         _ComPtr<IMFMediaBuffer> pInput;
   1385         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
   1386         BYTE *pSrc = NULL;          // Source buffer.
   1387         // Stride if the buffer does not support IMF2DBuffer
   1388         LONGLONG hnsTime = 0;
   1389         LONGLONG hnsDuration = 0;
   1390         DWORD cbMaxLength;
   1391         DWORD cbCurrentLength = 0;
   1392         GUID guidMajorType;
   1393         if (pSample == NULL)
   1394         {
   1395             return E_INVALIDARG;
   1396         }
   1397         HRESULT hr = S_OK;
   1398 
   1399         EnterCriticalSection(&m_critSec);
   1400 
   1401         if (m_state != State_Started && m_state != State_Paused) {
   1402             if (m_state == State_TypeNotSet)
   1403                 hr = MF_E_NOT_INITIALIZED;
   1404             else
   1405                 hr = MF_E_INVALIDREQUEST;
   1406         }
   1407         if (SUCCEEDED(hr))
   1408             hr = CheckShutdown();
   1409         if (SUCCEEDED(hr)) {
   1410             hr = pSample->ConvertToContiguousBuffer(&pInput);
   1411             if (SUCCEEDED(hr)) {
   1412                 hr = pSample->GetSampleTime(&hnsTime);
   1413             }
   1414             if (SUCCEEDED(hr)) {
   1415                 hr = pSample->GetSampleDuration(&hnsDuration);
   1416             }
   1417             if (SUCCEEDED(hr)) {
   1418                 hr = GetMajorType(&guidMajorType);
   1419             }
   1420             if (SUCCEEDED(hr)) {
   1421                 hr = m_pParent->GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
   1422             }
   1423             if (SUCCEEDED(hr)) {
   1424                 hr = pInput->Lock(&pSrc, &cbMaxLength, &cbCurrentLength);
   1425             }
   1426             if (SUCCEEDED(hr)) {
   1427                 hr = pSampleCallback->OnProcessSample(guidMajorType, 0, hnsTime, hnsDuration, pSrc, cbCurrentLength);
   1428                 pInput->Unlock();
   1429             }
   1430             if (SUCCEEDED(hr)) {
   1431                 hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
   1432             }
   1433         }
   1434         LeaveCriticalSection(&m_critSec);
   1435         return hr;
   1436     }
   1437 
   1438     HRESULT STDMETHODCALLTYPE PlaceMarker(
   1439         /* [in] */ MFSTREAMSINK_MARKER_TYPE eMarkerType,
   1440         /* [in] */ __RPC__in const PROPVARIANT * /*pvarMarkerValue*/,
   1441         /* [in] */ __RPC__in const PROPVARIANT * /*pvarContextValue*/) {
   1442         eMarkerType;
   1443         EnterCriticalSection(&m_critSec);
   1444 
   1445         HRESULT hr = S_OK;
   1446         if (m_state == State_TypeNotSet)
   1447             hr = MF_E_NOT_INITIALIZED;
   1448 
   1449         if (SUCCEEDED(hr))
   1450             hr = CheckShutdown();
   1451 
   1452         if (SUCCEEDED(hr))
   1453         {
   1454             //at shutdown will receive MFSTREAMSINK_MARKER_ENDOFSEGMENT
   1455             hr = QueueEvent(MEStreamSinkRequestSample, GUID_NULL, S_OK, NULL);
   1456         }
   1457 
   1458         LeaveCriticalSection(&m_critSec);
   1459         DebugPrintOut(L"StreamSink::PlaceMarker: HRESULT=%i %s\n", hr, StreamSinkMarkerTypeMap.at(eMarkerType).c_str());
   1460         return hr;
   1461     }
   1462 
   1463     HRESULT STDMETHODCALLTYPE Flush(void) {
   1464         EnterCriticalSection(&m_critSec);
   1465 
   1466         HRESULT hr = CheckShutdown();
   1467 
   1468         if (SUCCEEDED(hr))
   1469         {
   1470         }
   1471 
   1472         LeaveCriticalSection(&m_critSec);
   1473         DebugPrintOut(L"StreamSink::Flush: HRESULT=%i\n", hr);
   1474         return hr;
   1475     }
   1476 
   1477     //IMFMediaEventGenerator
   1478     HRESULT STDMETHODCALLTYPE GetEvent(
   1479         DWORD dwFlags, IMFMediaEvent **ppEvent) {
   1480         // NOTE:
   1481         // GetEvent can block indefinitely, so we don't hold the lock.
   1482         // This requires some juggling with the event queue pointer.
   1483 
   1484         HRESULT hr = S_OK;
   1485 
   1486         _ComPtr<IMFMediaEventQueue> pQueue;
   1487 
   1488         {
   1489             EnterCriticalSection(&m_critSec);
   1490 
   1491             // Check shutdown
   1492             hr = CheckShutdown();
   1493 
   1494             // Get the pointer to the event queue.
   1495             if (SUCCEEDED(hr))
   1496             {
   1497                 pQueue = m_spEventQueue.Get();
   1498             }
   1499             LeaveCriticalSection(&m_critSec);
   1500         }
   1501 
   1502         // Now get the event.
   1503         if (SUCCEEDED(hr))
   1504         {
   1505             hr = pQueue->GetEvent(dwFlags, ppEvent);
   1506         }
   1507         MediaEventType meType = MEUnknown;
   1508         if (SUCCEEDED(hr) && SUCCEEDED((*ppEvent)->GetType(&meType)) && meType == MEStreamSinkStopped) {
   1509         }
   1510         HRESULT hrStatus = S_OK;
   1511         if (SUCCEEDED(hr))
   1512             hr = (*ppEvent)->GetStatus(&hrStatus);
   1513         if (SUCCEEDED(hr))
   1514             DebugPrintOut(L"StreamSink::GetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str());
   1515         else
   1516             DebugPrintOut(L"StreamSink::GetEvent: HRESULT=%i\n", hr);
   1517         return hr;
   1518     }
   1519 
   1520     HRESULT STDMETHODCALLTYPE BeginGetEvent(
   1521         IMFAsyncCallback *pCallback, IUnknown *punkState) {
   1522         HRESULT hr = S_OK;
   1523 
   1524         EnterCriticalSection(&m_critSec);
   1525 
   1526         hr = CheckShutdown();
   1527 
   1528         if (SUCCEEDED(hr))
   1529         {
   1530             hr = m_spEventQueue->BeginGetEvent(pCallback, punkState);
   1531         }
   1532         LeaveCriticalSection(&m_critSec);
   1533         DebugPrintOut(L"StreamSink::BeginGetEvent: HRESULT=%i\n", hr);
   1534         return hr;
   1535     }
   1536 
   1537     HRESULT STDMETHODCALLTYPE EndGetEvent(
   1538         IMFAsyncResult *pResult, IMFMediaEvent **ppEvent) {
   1539         HRESULT hr = S_OK;
   1540 
   1541         EnterCriticalSection(&m_critSec);
   1542 
   1543         hr = CheckShutdown();
   1544 
   1545         if (SUCCEEDED(hr))
   1546         {
   1547             hr = m_spEventQueue->EndGetEvent(pResult, ppEvent);
   1548         }
   1549 
   1550         MediaEventType meType = MEUnknown;
   1551         if (SUCCEEDED(hr) && SUCCEEDED((*ppEvent)->GetType(&meType)) && meType == MEStreamSinkStopped) {
   1552         }
   1553 
   1554         LeaveCriticalSection(&m_critSec);
   1555         HRESULT hrStatus = S_OK;
   1556         if (SUCCEEDED(hr))
   1557             hr = (*ppEvent)->GetStatus(&hrStatus);
   1558         if (SUCCEEDED(hr))
   1559             DebugPrintOut(L"StreamSink::EndGetEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(meType).c_str());
   1560         else
   1561             DebugPrintOut(L"StreamSink::EndGetEvent: HRESULT=%i\n", hr);
   1562         return hr;
   1563     }
   1564 
   1565     HRESULT STDMETHODCALLTYPE QueueEvent(
   1566         MediaEventType met, REFGUID guidExtendedType,
   1567         HRESULT hrStatus, const PROPVARIANT *pvValue) {
   1568         HRESULT hr = S_OK;
   1569 
   1570         EnterCriticalSection(&m_critSec);
   1571 
   1572         hr = CheckShutdown();
   1573 
   1574         if (SUCCEEDED(hr))
   1575         {
   1576             hr = m_spEventQueue->QueueEventParamVar(met, guidExtendedType, hrStatus, pvValue);
   1577         }
   1578 
   1579         LeaveCriticalSection(&m_critSec);
   1580         DebugPrintOut(L"StreamSink::QueueEvent: HRESULT=%i %s\n", hrStatus, MediaEventTypeMap.at(met).c_str());
   1581         DebugPrintOut(L"StreamSink::QueueEvent: HRESULT=%i\n", hr);
   1582         return hr;
   1583     }
   1584 
   1585     /// IMFMediaTypeHandler methods
   1586 
   1587     // Check if a media type is supported.
   1588     STDMETHODIMP IsMediaTypeSupported(
   1589         /* [in] */ IMFMediaType *pMediaType,
   1590         /* [out] */ IMFMediaType **ppMediaType)
   1591     {
   1592         if (pMediaType == nullptr)
   1593         {
   1594             return E_INVALIDARG;
   1595         }
   1596 
   1597         EnterCriticalSection(&m_critSec);
   1598 
   1599         GUID majorType = GUID_NULL;
   1600 
   1601         HRESULT hr = CheckShutdown();
   1602 
   1603         if (SUCCEEDED(hr))
   1604         {
   1605             hr = pMediaType->GetGUID(MF_MT_MAJOR_TYPE, &majorType);
   1606         }
   1607 
   1608         // First make sure it's video or audio type.
   1609         if (SUCCEEDED(hr))
   1610         {
   1611             if (majorType != MFMediaType_Video && majorType != MFMediaType_Audio)
   1612             {
   1613                 hr = MF_E_INVALIDTYPE;
   1614             }
   1615         }
   1616 
   1617         if (SUCCEEDED(hr) && m_spCurrentType != nullptr)
   1618         {
   1619             GUID guiNewSubtype;
   1620             if (FAILED(pMediaType->GetGUID(MF_MT_SUBTYPE, &guiNewSubtype)) ||
   1621                 guiNewSubtype != m_guiCurrentSubtype)
   1622             {
   1623                 hr = MF_E_INVALIDTYPE;
   1624             }
   1625         }
   1626         // We don't return any "close match" types.
   1627         if (ppMediaType)
   1628         {
   1629             *ppMediaType = nullptr;
   1630         }
   1631 
   1632         if (ppMediaType && SUCCEEDED(hr)) {
   1633             _ComPtr<IMFMediaType> pType;
   1634             hr = MFCreateMediaType(ppMediaType);
   1635             if (SUCCEEDED(hr)) {
   1636                 hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType);
   1637             }
   1638             if (SUCCEEDED(hr)) {
   1639                 hr = pType->LockStore();
   1640             }
   1641             bool bLocked = false;
   1642             if (SUCCEEDED(hr)) {
   1643                 bLocked = true;
   1644                 UINT32 uiCount;
   1645                 UINT32 uiTotal;
   1646                 hr = pType->GetCount(&uiTotal);
   1647                 for (uiCount = 0; SUCCEEDED(hr) && uiCount < uiTotal; uiCount++) {
   1648                     GUID guid;
   1649                     PROPVARIANT propval;
   1650                     hr = pType->GetItemByIndex(uiCount, &guid, &propval);
   1651                     if (SUCCEEDED(hr) && (guid == MF_MT_FRAME_SIZE || guid == MF_MT_MAJOR_TYPE || guid == MF_MT_PIXEL_ASPECT_RATIO ||
   1652                         guid == MF_MT_ALL_SAMPLES_INDEPENDENT || guid == MF_MT_INTERLACE_MODE || guid == MF_MT_SUBTYPE)) {
   1653                         hr = (*ppMediaType)->SetItem(guid, propval);
   1654                         PropVariantClear(&propval);
   1655                     }
   1656                 }
   1657             }
   1658             if (bLocked) {
   1659                 hr = pType->UnlockStore();
   1660             }
   1661         }
   1662         LeaveCriticalSection(&m_critSec);
   1663         DebugPrintOut(L"StreamSink::IsMediaTypeSupported: HRESULT=%i\n", hr);
   1664         return hr;
   1665     }
   1666 
   1667 
   1668     // Return the number of preferred media types.
   1669     STDMETHODIMP GetMediaTypeCount(DWORD *pdwTypeCount)
   1670     {
   1671         if (pdwTypeCount == nullptr)
   1672         {
   1673             return E_INVALIDARG;
   1674         }
   1675 
   1676         EnterCriticalSection(&m_critSec);
   1677 
   1678         HRESULT hr = CheckShutdown();
   1679 
   1680         if (SUCCEEDED(hr))
   1681         {
   1682             // We've got only one media type
   1683             *pdwTypeCount = 1;
   1684         }
   1685 
   1686         LeaveCriticalSection(&m_critSec);
   1687         DebugPrintOut(L"StreamSink::GetMediaTypeCount: HRESULT=%i\n", hr);
   1688         return hr;
   1689     }
   1690 
   1691 
   1692     // Return a preferred media type by index.
   1693     STDMETHODIMP GetMediaTypeByIndex(
   1694         /* [in] */ DWORD dwIndex,
   1695         /* [out] */ IMFMediaType **ppType)
   1696     {
   1697         if (ppType == NULL) {
   1698             return E_INVALIDARG;
   1699         }
   1700 
   1701         EnterCriticalSection(&m_critSec);
   1702 
   1703         HRESULT hr = CheckShutdown();
   1704 
   1705         if (dwIndex > 0)
   1706         {
   1707             hr = MF_E_NO_MORE_TYPES;
   1708         } else {
   1709             //return preferred type based on media capture library 6 elements preferred preview type
   1710             //hr = m_spCurrentType.CopyTo(ppType);
   1711             if (SUCCEEDED(hr)) {
   1712                 _ComPtr<IMFMediaType> pType;
   1713                 hr = MFCreateMediaType(ppType);
   1714                 if (SUCCEEDED(hr)) {
   1715                     hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType);
   1716                 }
   1717                 if (SUCCEEDED(hr)) {
   1718                     hr = pType->LockStore();
   1719                 }
   1720                 bool bLocked = false;
   1721                 if (SUCCEEDED(hr)) {
   1722                     bLocked = true;
   1723                     UINT32 uiCount;
   1724                     UINT32 uiTotal;
   1725                     hr = pType->GetCount(&uiTotal);
   1726                     for (uiCount = 0; SUCCEEDED(hr) && uiCount < uiTotal; uiCount++) {
   1727                         GUID guid;
   1728                         PROPVARIANT propval;
   1729                         hr = pType->GetItemByIndex(uiCount, &guid, &propval);
   1730                         if (SUCCEEDED(hr) && (guid == MF_MT_FRAME_SIZE || guid == MF_MT_MAJOR_TYPE || guid == MF_MT_PIXEL_ASPECT_RATIO ||
   1731                             guid == MF_MT_ALL_SAMPLES_INDEPENDENT || guid == MF_MT_INTERLACE_MODE || guid == MF_MT_SUBTYPE)) {
   1732                             hr = (*ppType)->SetItem(guid, propval);
   1733                             PropVariantClear(&propval);
   1734                         }
   1735                     }
   1736                 }
   1737                 if (bLocked) {
   1738                     hr = pType->UnlockStore();
   1739                 }
   1740             }
   1741         }
   1742 
   1743         LeaveCriticalSection(&m_critSec);
   1744         DebugPrintOut(L"StreamSink::GetMediaTypeByIndex: HRESULT=%i\n", hr);
   1745         return hr;
   1746     }
   1747 
   1748 
   1749     // Set the current media type.
   1750     STDMETHODIMP SetCurrentMediaType(IMFMediaType *pMediaType)
   1751     {
   1752         if (pMediaType == NULL) {
   1753             return E_INVALIDARG;
   1754         }
   1755         EnterCriticalSection(&m_critSec);
   1756 
   1757         HRESULT hr = S_OK;
   1758         if (m_state != State_TypeNotSet && m_state != State_Ready)
   1759             hr = MF_E_INVALIDREQUEST;
   1760         if (SUCCEEDED(hr))
   1761             hr = CheckShutdown();
   1762 
   1763         // We don't allow format changes after streaming starts.
   1764 
   1765         // We set media type already
   1766         if (m_state >= State_Ready)
   1767         {
   1768             if (SUCCEEDED(hr))
   1769             {
   1770                 hr = IsMediaTypeSupported(pMediaType, NULL);
   1771             }
   1772         }
   1773 
   1774         if (SUCCEEDED(hr))
   1775         {
   1776             hr = MFCreateMediaType(m_spCurrentType.ReleaseAndGetAddressOf());
   1777             if (SUCCEEDED(hr))
   1778             {
   1779                 hr = pMediaType->CopyAllItems(m_spCurrentType.Get());
   1780             }
   1781             if (SUCCEEDED(hr))
   1782             {
   1783                 hr = m_spCurrentType->GetGUID(MF_MT_SUBTYPE, &m_guiCurrentSubtype);
   1784             }
   1785             GUID guid;
   1786             if (SUCCEEDED(hr)) {
   1787                 hr = m_spCurrentType->GetMajorType(&guid);
   1788             }
   1789             if (SUCCEEDED(hr) && guid == MFMediaType_Video) {
   1790                 hr = MFGetAttributeSize(m_spCurrentType.Get(), MF_MT_FRAME_SIZE, &m_imageWidthInPixels, &m_imageHeightInPixels);
   1791             }
   1792             if (SUCCEEDED(hr))
   1793             {
   1794                 m_state = State_Ready;
   1795             }
   1796         }
   1797 
   1798         LeaveCriticalSection(&m_critSec);
   1799         DebugPrintOut(L"StreamSink::SetCurrentMediaType: HRESULT=%i\n", hr);
   1800         return hr;
   1801     }
   1802 
   1803     // Return the current media type, if any.
   1804     STDMETHODIMP GetCurrentMediaType(IMFMediaType **ppMediaType)
   1805     {
   1806         if (ppMediaType == NULL) {
   1807             return E_INVALIDARG;
   1808         }
   1809 
   1810         EnterCriticalSection(&m_critSec);
   1811 
   1812         HRESULT hr = CheckShutdown();
   1813 
   1814         if (SUCCEEDED(hr)) {
   1815             if (m_spCurrentType == nullptr) {
   1816                 hr = MF_E_NOT_INITIALIZED;
   1817             }
   1818         }
   1819 
   1820         if (SUCCEEDED(hr)) {
   1821             hr = m_spCurrentType.CopyTo(ppMediaType);
   1822         }
   1823 
   1824         LeaveCriticalSection(&m_critSec);
   1825         DebugPrintOut(L"StreamSink::GetCurrentMediaType: HRESULT=%i\n", hr);
   1826         return hr;
   1827     }
   1828 
   1829 
   1830     // Return the major type GUID.
   1831     STDMETHODIMP GetMajorType(GUID *pguidMajorType)
   1832     {
   1833         HRESULT hr;
   1834         if (pguidMajorType == nullptr) {
   1835             return E_INVALIDARG;
   1836         }
   1837 
   1838         _ComPtr<IMFMediaType> pType;
   1839         hr = m_pParent->GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)&pType);
   1840         if (SUCCEEDED(hr)) {
   1841             hr = pType->GetMajorType(pguidMajorType);
   1842         }
   1843         DebugPrintOut(L"StreamSink::GetMajorType: HRESULT=%i\n", hr);
   1844         return hr;
   1845     }
   1846 private:
   1847 #ifdef WINRT
   1848     EventRegistrationToken m_token;
   1849 #else
   1850     bool m_bConnected;
   1851 #endif
   1852 
   1853     bool m_IsShutdown;                // Flag to indicate if Shutdown() method was called.
   1854     CRITICAL_SECTION m_critSec;
   1855 #ifndef WINRT
   1856     long m_cRef;
   1857 #endif
   1858     IMFAttributes*        m_pParent;
   1859     _ComPtr<IMFMediaType>        m_spCurrentType;
   1860     _ComPtr<IMFMediaEventQueue>  m_spEventQueue;              // Event queue
   1861 
   1862     _ComPtr<IUnknown>            m_spFTM;
   1863     State                       m_state;
   1864     bool                        m_fGetStartTimeFromSample;
   1865     bool                        m_fWaitingForFirstSample;
   1866     MFTIME                      m_StartTime;                 // Presentation time when the clock started.
   1867     GUID                        m_guiCurrentSubtype;
   1868     UINT32                      m_imageWidthInPixels;
   1869     UINT32                      m_imageHeightInPixels;
   1870 };
   1871 
   1872 // Notes:
   1873 //
   1874 // The List class template implements a simple double-linked list.
   1875 // It uses STL's copy semantics.
   1876 
   1877 // There are two versions of the Clear() method:
   1878 //  Clear(void) clears the list w/out cleaning up the object.
   1879 //  Clear(FN fn) takes a functor object that releases the objects, if they need cleanup.
   1880 
   1881 // The List class supports enumeration. Example of usage:
   1882 //
   1883 // List<T>::POSIITON pos = list.GetFrontPosition();
   1884 // while (pos != list.GetEndPosition())
   1885 // {
   1886 //     T item;
   1887 //     hr = list.GetItemPos(&item);
   1888 //     pos = list.Next(pos);
   1889 // }
   1890 
   1891 // The ComPtrList class template derives from List<> and implements a list of COM pointers.
   1892 
   1893 template <class T>
   1894 struct NoOp
   1895 {
   1896     void operator()(T& /*t*/)
   1897     {
   1898     }
   1899 };
   1900 
   1901 template <class T>
   1902 class List
   1903 {
   1904 protected:
   1905 
   1906     // Nodes in the linked list
   1907     struct Node
   1908     {
   1909         Node *prev;
   1910         Node *next;
   1911         T    item;
   1912 
   1913         Node() : prev(nullptr), next(nullptr)
   1914         {
   1915         }
   1916 
   1917         Node(T item) : prev(nullptr), next(nullptr)
   1918         {
   1919             this->item = item;
   1920         }
   1921 
   1922         T Item() const { return item; }
   1923     };
   1924 
   1925 public:
   1926 
   1927     // Object for enumerating the list.
   1928     class POSITION
   1929     {
   1930         friend class List<T>;
   1931 
   1932     public:
   1933         POSITION() : pNode(nullptr)
   1934         {
   1935         }
   1936 
   1937         bool operator==(const POSITION &p) const
   1938         {
   1939             return pNode == p.pNode;
   1940         }
   1941 
   1942         bool operator!=(const POSITION &p) const
   1943         {
   1944             return pNode != p.pNode;
   1945         }
   1946 
   1947     private:
   1948         const Node *pNode;
   1949 
   1950         POSITION(Node *p) : pNode(p)
   1951         {
   1952         }
   1953     };
   1954 
   1955 protected:
   1956     Node    m_anchor;  // Anchor node for the linked list.
   1957     DWORD   m_count;   // Number of items in the list.
   1958 
   1959     Node* Front() const
   1960     {
   1961         return m_anchor.next;
   1962     }
   1963 
   1964     Node* Back() const
   1965     {
   1966         return m_anchor.prev;
   1967     }
   1968 
   1969     virtual HRESULT InsertAfter(T item, Node *pBefore)
   1970     {
   1971         if (pBefore == nullptr)
   1972         {
   1973             return E_POINTER;
   1974         }
   1975 
   1976         Node *pNode = new Node(item);
   1977         if (pNode == nullptr)
   1978         {
   1979             return E_OUTOFMEMORY;
   1980         }
   1981 
   1982         Node *pAfter = pBefore->next;
   1983 
   1984         pBefore->next = pNode;
   1985         pAfter->prev = pNode;
   1986 
   1987         pNode->prev = pBefore;
   1988         pNode->next = pAfter;
   1989 
   1990         m_count++;
   1991 
   1992         return S_OK;
   1993     }
   1994 
   1995     virtual HRESULT GetItem(const Node *pNode, T* ppItem)
   1996     {
   1997         if (pNode == nullptr || ppItem == nullptr)
   1998         {
   1999             return E_POINTER;
   2000         }
   2001 
   2002         *ppItem = pNode->item;
   2003         return S_OK;
   2004     }
   2005 
   2006     // RemoveItem:
   2007     // Removes a node and optionally returns the item.
   2008     // ppItem can be nullptr.
   2009     virtual HRESULT RemoveItem(Node *pNode, T *ppItem)
   2010     {
   2011         if (pNode == nullptr)
   2012         {
   2013             return E_POINTER;
   2014         }
   2015 
   2016         assert(pNode != &m_anchor); // We should never try to remove the anchor node.
   2017         if (pNode == &m_anchor)
   2018         {
   2019             return E_INVALIDARG;
   2020         }
   2021 
   2022 
   2023         T item;
   2024 
   2025         // The next node's previous is this node's previous.
   2026         pNode->next->prev = pNode->prev;
   2027 
   2028         // The previous node's next is this node's next.
   2029         pNode->prev->next = pNode->next;
   2030 
   2031         item = pNode->item;
   2032         delete pNode;
   2033 
   2034         m_count--;
   2035 
   2036         if (ppItem)
   2037         {
   2038             *ppItem = item;
   2039         }
   2040 
   2041         return S_OK;
   2042     }
   2043 
   2044 public:
   2045 
   2046     List()
   2047     {
   2048         m_anchor.next = &m_anchor;
   2049         m_anchor.prev = &m_anchor;
   2050 
   2051         m_count = 0;
   2052     }
   2053 
   2054     virtual ~List()
   2055     {
   2056         Clear();
   2057     }
   2058 
   2059     // Insertion functions
   2060     HRESULT InsertBack(T item)
   2061     {
   2062         return InsertAfter(item, m_anchor.prev);
   2063     }
   2064 
   2065 
   2066     HRESULT InsertFront(T item)
   2067     {
   2068         return InsertAfter(item, &m_anchor);
   2069     }
   2070 
   2071     HRESULT InsertPos(POSITION pos, T item)
   2072     {
   2073         if (pos.pNode == nullptr)
   2074         {
   2075             return InsertBack(item);
   2076         }
   2077 
   2078         return InsertAfter(item, pos.pNode->prev);
   2079     }
   2080 
   2081     // RemoveBack: Removes the tail of the list and returns the value.
   2082     // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.)
   2083     HRESULT RemoveBack(T *ppItem)
   2084     {
   2085         if (IsEmpty())
   2086         {
   2087             return E_FAIL;
   2088         }
   2089         else
   2090         {
   2091             return RemoveItem(Back(), ppItem);
   2092         }
   2093     }
   2094 
   2095     // RemoveFront: Removes the head of the list and returns the value.
   2096     // ppItem can be nullptr if you don't want the item back. (But the method does not release the item.)
   2097     HRESULT RemoveFront(T *ppItem)
   2098     {
   2099         if (IsEmpty())
   2100         {
   2101             return E_FAIL;
   2102         }
   2103         else
   2104         {
   2105             return RemoveItem(Front(), ppItem);
   2106         }
   2107     }
   2108 
   2109     // GetBack: Gets the tail item.
   2110     HRESULT GetBack(T *ppItem)
   2111     {
   2112         if (IsEmpty())
   2113         {
   2114             return E_FAIL;
   2115         }
   2116         else
   2117         {
   2118             return GetItem(Back(), ppItem);
   2119         }
   2120     }
   2121 
   2122     // GetFront: Gets the front item.
   2123     HRESULT GetFront(T *ppItem)
   2124     {
   2125         if (IsEmpty())
   2126         {
   2127             return E_FAIL;
   2128         }
   2129         else
   2130         {
   2131             return GetItem(Front(), ppItem);
   2132         }
   2133     }
   2134 
   2135 
   2136     // GetCount: Returns the number of items in the list.
   2137     DWORD GetCount() const { return m_count; }
   2138 
   2139     bool IsEmpty() const
   2140     {
   2141         return (GetCount() == 0);
   2142     }
   2143 
   2144     // Clear: Takes a functor object whose operator()
   2145     // frees the object on the list.
   2146     template <class FN>
   2147     void Clear(FN& clear_fn)
   2148     {
   2149         Node *n = m_anchor.next;
   2150 
   2151         // Delete the nodes
   2152         while (n != &m_anchor)
   2153         {
   2154             clear_fn(n->item);
   2155 
   2156             Node *tmp = n->next;
   2157             delete n;
   2158             n = tmp;
   2159         }
   2160 
   2161         // Reset the anchor to point at itself
   2162         m_anchor.next = &m_anchor;
   2163         m_anchor.prev = &m_anchor;
   2164 
   2165         m_count = 0;
   2166     }
   2167 
   2168     // Clear: Clears the list. (Does not delete or release the list items.)
   2169     virtual void Clear()
   2170     {
   2171         NoOp<T> clearOp;
   2172         Clear<>(clearOp);
   2173     }
   2174 
   2175 
   2176     // Enumerator functions
   2177 
   2178     POSITION FrontPosition()
   2179     {
   2180         if (IsEmpty())
   2181         {
   2182             return POSITION(nullptr);
   2183         }
   2184         else
   2185         {
   2186             return POSITION(Front());
   2187         }
   2188     }
   2189 
   2190     POSITION EndPosition() const
   2191     {
   2192         return POSITION();
   2193     }
   2194 
   2195     HRESULT GetItemPos(POSITION pos, T *ppItem)
   2196     {
   2197         if (pos.pNode)
   2198         {
   2199             return GetItem(pos.pNode, ppItem);
   2200         }
   2201         else
   2202         {
   2203             return E_FAIL;
   2204         }
   2205     }
   2206 
   2207     POSITION Next(const POSITION pos)
   2208     {
   2209         if (pos.pNode && (pos.pNode->next != &m_anchor))
   2210         {
   2211             return POSITION(pos.pNode->next);
   2212         }
   2213         else
   2214         {
   2215             return POSITION(nullptr);
   2216         }
   2217     }
   2218 
   2219     // Remove an item at a position.
   2220     // The item is returns in ppItem, unless ppItem is nullptr.
   2221     // NOTE: This method invalidates the POSITION object.
   2222     HRESULT Remove(POSITION& pos, T *ppItem)
   2223     {
   2224         if (pos.pNode)
   2225         {
   2226             // Remove const-ness temporarily...
   2227             Node *pNode = const_cast<Node*>(pos.pNode);
   2228 
   2229             pos = POSITION();
   2230 
   2231             return RemoveItem(pNode, ppItem);
   2232         }
   2233         else
   2234         {
   2235             return E_INVALIDARG;
   2236         }
   2237     }
   2238 
   2239 };
   2240 
   2241 
   2242 
   2243 // Typical functors for Clear method.
   2244 
   2245 // ComAutoRelease: Releases COM pointers.
   2246 // MemDelete: Deletes pointers to new'd memory.
   2247 
   2248 class ComAutoRelease
   2249 {
   2250 public:
   2251     void operator()(IUnknown *p)
   2252     {
   2253         if (p)
   2254         {
   2255             p->Release();
   2256         }
   2257     }
   2258 };
   2259 
   2260 class MemDelete
   2261 {
   2262 public:
   2263     void operator()(void *p)
   2264     {
   2265         if (p)
   2266         {
   2267             delete p;
   2268         }
   2269     }
   2270 };
   2271 
   2272 
   2273 // ComPtrList class
   2274 // Derived class that makes it safer to store COM pointers in the List<> class.
   2275 // It automatically AddRef's the pointers that are inserted onto the list
   2276 // (unless the insertion method fails).
   2277 //
   2278 // T must be a COM interface type.
   2279 // example: ComPtrList<IUnknown>
   2280 //
   2281 // NULLABLE: If true, client can insert nullptr pointers. This means GetItem can
   2282 // succeed but return a nullptr pointer. By default, the list does not allow nullptr
   2283 // pointers.
   2284 
   2285 #ifdef _MSC_VER
   2286 #pragma warning(push)
   2287 #pragma warning(disable: 4127) // constant expression
   2288 #endif
   2289 
   2290 template <class T, bool NULLABLE = FALSE>
   2291 class ComPtrList : public List<T*>
   2292 {
   2293 public:
   2294 
   2295     typedef T* Ptr;
   2296 
   2297     void Clear()
   2298     {
   2299         ComAutoRelease car;
   2300         List<Ptr>::Clear(car);
   2301     }
   2302 
   2303     ~ComPtrList()
   2304     {
   2305         Clear();
   2306     }
   2307 
   2308 protected:
   2309     HRESULT InsertAfter(Ptr item, Node *pBefore)
   2310     {
   2311         // Do not allow nullptr item pointers unless NULLABLE is true.
   2312         if (item == nullptr && !NULLABLE)
   2313         {
   2314             return E_POINTER;
   2315         }
   2316 
   2317         if (item)
   2318         {
   2319             item->AddRef();
   2320         }
   2321 
   2322         HRESULT hr = List<Ptr>::InsertAfter(item, pBefore);
   2323         if (FAILED(hr) && item != nullptr)
   2324         {
   2325             item->Release();
   2326         }
   2327         return hr;
   2328     }
   2329 
   2330     HRESULT GetItem(const Node *pNode, Ptr* ppItem)
   2331     {
   2332         Ptr pItem = nullptr;
   2333 
   2334         // The base class gives us the pointer without AddRef'ing it.
   2335         // If we return the pointer to the caller, we must AddRef().
   2336         HRESULT hr = List<Ptr>::GetItem(pNode, &pItem);
   2337         if (SUCCEEDED(hr))
   2338         {
   2339             assert(pItem || NULLABLE);
   2340             if (pItem)
   2341             {
   2342                 *ppItem = pItem;
   2343                 (*ppItem)->AddRef();
   2344             }
   2345         }
   2346         return hr;
   2347     }
   2348 
   2349     HRESULT RemoveItem(Node *pNode, Ptr *ppItem)
   2350     {
   2351         // ppItem can be nullptr, but we need to get the
   2352         // item so that we can release it.
   2353 
   2354         // If ppItem is not nullptr, we will AddRef it on the way out.
   2355 
   2356         Ptr pItem = nullptr;
   2357 
   2358         HRESULT hr = List<Ptr>::RemoveItem(pNode, &pItem);
   2359 
   2360         if (SUCCEEDED(hr))
   2361         {
   2362             assert(pItem || NULLABLE);
   2363             if (ppItem && pItem)
   2364             {
   2365                 *ppItem = pItem;
   2366                 (*ppItem)->AddRef();
   2367             }
   2368 
   2369             if (pItem)
   2370             {
   2371                 pItem->Release();
   2372                 pItem = nullptr;
   2373             }
   2374         }
   2375 
   2376         return hr;
   2377     }
   2378 };
   2379 
   2380 #ifdef _MSC_VER
   2381 #pragma warning(pop)
   2382 #endif
   2383 
   2384 /* Be sure to declare webcam device capability in manifest
   2385   For better media capture support, add the following snippet with correct module name to the project manifest
   2386     (videoio needs DLL activation class factoryentry points):
   2387   <Extensions>
   2388     <Extension Category="windows.activatableClass.inProcessServer">
   2389       <InProcessServer>
   2390         <Path>modulename</Path>
   2391         <ActivatableClass ActivatableClassId="cv.MediaSink" ThreadingModel="both" />
   2392       </InProcessServer>
   2393     </Extension>
   2394   </Extensions>*/
   2395 
   2396 extern const __declspec(selectany) WCHAR RuntimeClass_CV_MediaSink[] = L"cv.MediaSink";
   2397 
   2398 class MediaSink :
   2399 #ifdef WINRT
   2400     public Microsoft::WRL::RuntimeClass<
   2401     Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >,
   2402     Microsoft::WRL::Implements<ABI::Windows::Media::IMediaExtension>,
   2403     IMFMediaSink,
   2404     IMFClockStateSink,
   2405     Microsoft::WRL::FtmBase,
   2406     CBaseAttributes<>>
   2407 #else
   2408     public IMFMediaSink, public IMFClockStateSink, public CBaseAttributes<>
   2409 #endif
   2410 {
   2411 #ifdef WINRT
   2412     InspectableClass(RuntimeClass_CV_MediaSink, BaseTrust)
   2413 public:
   2414 #else
   2415 public:
   2416     ULONG STDMETHODCALLTYPE AddRef()
   2417     {
   2418         return InterlockedIncrement(&m_cRef);
   2419     }
   2420     ULONG STDMETHODCALLTYPE Release()
   2421     {
   2422         ULONG cRef = InterlockedDecrement(&m_cRef);
   2423         if (cRef == 0)
   2424         {
   2425             delete this;
   2426         }
   2427         return cRef;
   2428     }
   2429 #if defined(_MSC_VER) && _MSC_VER >= 1700  // '_Outptr_result_nullonfailure_' SAL is avaialable since VS 2012
   2430     STDMETHOD(QueryInterface)(REFIID riid, _Outptr_result_nullonfailure_ void **ppv)
   2431 #else
   2432     STDMETHOD(QueryInterface)(REFIID riid, void **ppv)
   2433 #endif
   2434     {
   2435         if (ppv == nullptr) {
   2436             return E_POINTER;
   2437         }
   2438         (*ppv) = nullptr;
   2439         HRESULT hr = S_OK;
   2440         if (riid == IID_IUnknown ||
   2441             riid == IID_IMFMediaSink) {
   2442             (*ppv) = static_cast<IMFMediaSink*>(this);
   2443             AddRef();
   2444         } else if (riid == IID_IMFClockStateSink) {
   2445             (*ppv) = static_cast<IMFClockStateSink*>(this);
   2446             AddRef();
   2447         } else if (riid == IID_IMFAttributes) {
   2448             (*ppv) = static_cast<IMFAttributes*>(this);
   2449             AddRef();
   2450         } else {
   2451             hr = E_NOINTERFACE;
   2452         }
   2453 
   2454         return hr;
   2455     }
   2456 #endif
   2457     MediaSink() : m_IsShutdown(false), m_llStartTime(0) {
   2458         CBaseAttributes<>::Initialize(0U);
   2459         InitializeCriticalSectionEx(&m_critSec, 3000, 0);
   2460         DebugPrintOut(L"MediaSink::MediaSink\n");
   2461     }
   2462 
   2463     virtual ~MediaSink() {
   2464         DebugPrintOut(L"MediaSink::~MediaSink\n");
   2465         DeleteCriticalSection(&m_critSec);
   2466         assert(m_IsShutdown);
   2467     }
   2468     HRESULT CheckShutdown() const
   2469     {
   2470         if (m_IsShutdown)
   2471         {
   2472             return MF_E_SHUTDOWN;
   2473         }
   2474         else
   2475         {
   2476             return S_OK;
   2477         }
   2478     }
   2479 #ifdef WINRT
   2480     STDMETHODIMP SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration)
   2481     {
   2482         HRESULT hr = S_OK;
   2483         if (pConfiguration) {
   2484             Microsoft::WRL::ComPtr<IInspectable> spInsp;
   2485             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IMap<HSTRING, IInspectable *>> spSetting;
   2486             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValue> spPropVal;
   2487             Microsoft::WRL::ComPtr<ABI::Windows::Media::MediaProperties::IMediaEncodingProperties> pMedEncProps;
   2488             UINT32 uiType = ABI::Windows::Media::Capture::MediaStreamType_VideoPreview;
   2489 
   2490             hr = pConfiguration->QueryInterface(IID_PPV_ARGS(&spSetting));
   2491             if (FAILED(hr)) {
   2492                 hr = E_FAIL;
   2493             }
   2494 
   2495             if (SUCCEEDED(hr)) {
   2496                 hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_SAMPLEGRABBERCALLBACK).Get(), spInsp.ReleaseAndGetAddressOf());
   2497                 if (FAILED(hr)) {
   2498                     hr = E_INVALIDARG;
   2499                 }
   2500                 if (SUCCEEDED(hr)) {
   2501                     hr = SetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, spInsp.Get());
   2502                 }
   2503             }
   2504             if (SUCCEEDED(hr)) {
   2505                 hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_VIDTYPE).Get(), spInsp.ReleaseAndGetAddressOf());
   2506                 if (FAILED(hr)) {
   2507                     hr = E_INVALIDARG;
   2508                 }
   2509                 if (SUCCEEDED(hr)) {
   2510                     if (SUCCEEDED(hr = spInsp.As(&spPropVal))) {
   2511                         hr = spPropVal->GetUInt32(&uiType);
   2512                     }
   2513                 }
   2514             }
   2515             if (SUCCEEDED(hr)) {
   2516                 hr = spSetting->Lookup(Microsoft::WRL::Wrappers::HStringReference(MF_PROP_VIDENCPROPS).Get(), spInsp.ReleaseAndGetAddressOf());
   2517                 if (FAILED(hr)) {
   2518                     hr = E_INVALIDARG;
   2519                 }
   2520                 if (SUCCEEDED(hr)) {
   2521                     hr = spInsp.As(&pMedEncProps);
   2522                 }
   2523             }
   2524             if (SUCCEEDED(hr)) {
   2525                 hr = SetMediaStreamProperties((ABI::Windows::Media::Capture::MediaStreamType)uiType, pMedEncProps.Get());
   2526             }
   2527         }
   2528 
   2529         return hr;
   2530     }
   2531     static DWORD GetStreamId(ABI::Windows::Media::Capture::MediaStreamType mediaStreamType)
   2532     {
   2533         return 3 - mediaStreamType;
   2534     }
   2535     static HRESULT AddAttribute(_In_ GUID guidKey, _In_ ABI::Windows::Foundation::IPropertyValue *pValue, _In_ IMFAttributes* pAttr)
   2536     {
   2537         HRESULT hr = S_OK;
   2538         PROPVARIANT var;
   2539         ABI::Windows::Foundation::PropertyType type;
   2540         hr = pValue->get_Type(&type);
   2541         ZeroMemory(&var, sizeof(var));
   2542 
   2543         if (SUCCEEDED(hr))
   2544         {
   2545             switch (type)
   2546             {
   2547             case ABI::Windows::Foundation::PropertyType_UInt8Array:
   2548             {
   2549                                                                       UINT32 cbBlob;
   2550                                                                       BYTE *pbBlog = nullptr;
   2551                                                                       hr = pValue->GetUInt8Array(&cbBlob, &pbBlog);
   2552                                                                       if (SUCCEEDED(hr))
   2553                                                                       {
   2554                                                                           if (pbBlog == nullptr)
   2555                                                                           {
   2556                                                                               hr = E_INVALIDARG;
   2557                                                                           }
   2558                                                                           else
   2559                                                                           {
   2560                                                                               hr = pAttr->SetBlob(guidKey, pbBlog, cbBlob);
   2561                                                                           }
   2562                                                                       }
   2563                                                                       CoTaskMemFree(pbBlog);
   2564             }
   2565                 break;
   2566 
   2567             case ABI::Windows::Foundation::PropertyType_Double:
   2568             {
   2569                                                                   DOUBLE value;
   2570                                                                   hr = pValue->GetDouble(&value);
   2571                                                                   if (SUCCEEDED(hr))
   2572                                                                   {
   2573                                                                       hr = pAttr->SetDouble(guidKey, value);
   2574                                                                   }
   2575             }
   2576                 break;
   2577 
   2578             case ABI::Windows::Foundation::PropertyType_Guid:
   2579             {
   2580                                                                 GUID value;
   2581                                                                 hr = pValue->GetGuid(&value);
   2582                                                                 if (SUCCEEDED(hr))
   2583                                                                 {
   2584                                                                     hr = pAttr->SetGUID(guidKey, value);
   2585                                                                 }
   2586             }
   2587                 break;
   2588 
   2589             case ABI::Windows::Foundation::PropertyType_String:
   2590             {
   2591                         Microsoft::WRL::Wrappers::HString value;
   2592                         hr = pValue->GetString(value.GetAddressOf());
   2593                                                                   if (SUCCEEDED(hr))
   2594                                                                   {
   2595                                                                       UINT32 len = 0;
   2596                             LPCWSTR szValue = WindowsGetStringRawBuffer(value.Get(), &len);
   2597                                                                       hr = pAttr->SetString(guidKey, szValue);
   2598                                                                   }
   2599             }
   2600                 break;
   2601 
   2602             case ABI::Windows::Foundation::PropertyType_UInt32:
   2603             {
   2604                                                                   UINT32 value;
   2605                                                                   hr = pValue->GetUInt32(&value);
   2606                                                                   if (SUCCEEDED(hr))
   2607                                                                   {
   2608                                                                       pAttr->SetUINT32(guidKey, value);
   2609                                                                   }
   2610             }
   2611                 break;
   2612 
   2613             case ABI::Windows::Foundation::PropertyType_UInt64:
   2614             {
   2615                                                                   UINT64 value;
   2616                                                                   hr = pValue->GetUInt64(&value);
   2617                                                                   if (SUCCEEDED(hr))
   2618                                                                   {
   2619                                                                       hr = pAttr->SetUINT64(guidKey, value);
   2620                                                                   }
   2621             }
   2622                 break;
   2623 
   2624             case ABI::Windows::Foundation::PropertyType_Inspectable:
   2625             {
   2626                                                                        Microsoft::WRL::ComPtr<IInspectable> value;
   2627                                                                        hr = TYPE_E_TYPEMISMATCH;
   2628                                                                        if (SUCCEEDED(hr))
   2629                                                                        {
   2630                                                                            pAttr->SetUnknown(guidKey, value.Get());
   2631                                                                        }
   2632             }
   2633                 break;
   2634 
   2635                 // ignore unknown values
   2636             }
   2637         }
   2638 
   2639         return hr;
   2640     }
   2641     static HRESULT ConvertPropertiesToMediaType(_In_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *pMEP, _Outptr_ IMFMediaType **ppMT)
   2642     {
   2643         HRESULT hr = S_OK;
   2644         _ComPtr<IMFMediaType> spMT;
   2645         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IMap<GUID, IInspectable*>> spMap;
   2646         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IIterable<ABI::Windows::Foundation::Collections::IKeyValuePair<GUID, IInspectable*>*>> spIterable;
   2647         Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IIterator<ABI::Windows::Foundation::Collections::IKeyValuePair<GUID, IInspectable*>*>> spIterator;
   2648 
   2649         if (pMEP == nullptr || ppMT == nullptr)
   2650         {
   2651             return E_INVALIDARG;
   2652         }
   2653         *ppMT = nullptr;
   2654 
   2655                 hr = pMEP->get_Properties(spMap.GetAddressOf());
   2656 
   2657         if (SUCCEEDED(hr))
   2658         {
   2659             hr = spMap.As(&spIterable);
   2660         }
   2661         if (SUCCEEDED(hr))
   2662         {
   2663             hr = spIterable->First(&spIterator);
   2664         }
   2665         if (SUCCEEDED(hr))
   2666         {
   2667             MFCreateMediaType(spMT.ReleaseAndGetAddressOf());
   2668         }
   2669 
   2670         boolean hasCurrent = false;
   2671         if (SUCCEEDED(hr))
   2672         {
   2673             hr = spIterator->get_HasCurrent(&hasCurrent);
   2674         }
   2675 
   2676         while (hasCurrent)
   2677         {
   2678             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IKeyValuePair<GUID, IInspectable*> > spKeyValuePair;
   2679             Microsoft::WRL::ComPtr<IInspectable> spValue;
   2680             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValue> spPropValue;
   2681             GUID guidKey;
   2682 
   2683             hr = spIterator->get_Current(&spKeyValuePair);
   2684             if (FAILED(hr))
   2685             {
   2686                 break;
   2687             }
   2688             hr = spKeyValuePair->get_Key(&guidKey);
   2689             if (FAILED(hr))
   2690             {
   2691                 break;
   2692             }
   2693             hr = spKeyValuePair->get_Value(&spValue);
   2694             if (FAILED(hr))
   2695             {
   2696                 break;
   2697             }
   2698             hr = spValue.As(&spPropValue);
   2699             if (FAILED(hr))
   2700             {
   2701                 break;
   2702             }
   2703             hr = AddAttribute(guidKey, spPropValue.Get(), spMT.Get());
   2704             if (FAILED(hr))
   2705             {
   2706                 break;
   2707             }
   2708 
   2709             hr = spIterator->MoveNext(&hasCurrent);
   2710             if (FAILED(hr))
   2711             {
   2712                 break;
   2713             }
   2714         }
   2715 
   2716 
   2717         if (SUCCEEDED(hr))
   2718         {
   2719             Microsoft::WRL::ComPtr<IInspectable> spValue;
   2720             Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IPropertyValue> spPropValue;
   2721             GUID guiMajorType;
   2722 
   2723             hr = spMap->Lookup(MF_MT_MAJOR_TYPE, spValue.GetAddressOf());
   2724 
   2725             if (SUCCEEDED(hr))
   2726             {
   2727                 hr = spValue.As(&spPropValue);
   2728             }
   2729             if (SUCCEEDED(hr))
   2730             {
   2731                 hr = spPropValue->GetGuid(&guiMajorType);
   2732             }
   2733             if (SUCCEEDED(hr))
   2734             {
   2735                 if (guiMajorType != MFMediaType_Video && guiMajorType != MFMediaType_Audio)
   2736                 {
   2737                     hr = E_UNEXPECTED;
   2738                 }
   2739             }
   2740         }
   2741 
   2742         if (SUCCEEDED(hr))
   2743         {
   2744             *ppMT = spMT.Detach();
   2745         }
   2746 
   2747         return hr;
   2748     }
   2749             //this should be passed through SetProperties!
   2750             HRESULT SetMediaStreamProperties(ABI::Windows::Media::Capture::MediaStreamType MediaStreamType,
   2751         _In_opt_ ABI::Windows::Media::MediaProperties::IMediaEncodingProperties *mediaEncodingProperties)
   2752     {
   2753         HRESULT hr = S_OK;
   2754         _ComPtr<IMFMediaType> spMediaType;
   2755 
   2756         if (MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_VideoPreview &&
   2757             MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_VideoRecord &&
   2758             MediaStreamType != ABI::Windows::Media::Capture::MediaStreamType_Audio)
   2759         {
   2760             return E_INVALIDARG;
   2761         }
   2762 
   2763         RemoveStreamSink(GetStreamId(MediaStreamType));
   2764 
   2765         if (mediaEncodingProperties != nullptr)
   2766         {
   2767             _ComPtr<IMFStreamSink> spStreamSink;
   2768             hr = ConvertPropertiesToMediaType(mediaEncodingProperties, &spMediaType);
   2769             if (SUCCEEDED(hr))
   2770             {
   2771                 hr = AddStreamSink(GetStreamId(MediaStreamType), nullptr, spStreamSink.GetAddressOf());
   2772             }
   2773             if (SUCCEEDED(hr)) {
   2774                 hr = SetUnknown(MF_MEDIASINK_PREFERREDTYPE, spMediaType.Detach());
   2775             }
   2776         }
   2777 
   2778         return hr;
   2779     }
   2780 #endif
   2781     //IMFMediaSink
   2782     HRESULT STDMETHODCALLTYPE GetCharacteristics(
   2783         /* [out] */ __RPC__out DWORD *pdwCharacteristics) {
   2784         HRESULT hr;
   2785         if (pdwCharacteristics == NULL) return E_INVALIDARG;
   2786         EnterCriticalSection(&m_critSec);
   2787         if (SUCCEEDED(hr = CheckShutdown())) {
   2788                     //if had an activation object for the sink, shut down would be managed and MF_STREAM_SINK_SUPPORTS_ROTATION appears to be setable to TRUE
   2789                     *pdwCharacteristics = MEDIASINK_FIXED_STREAMS;// | MEDIASINK_REQUIRE_REFERENCE_MEDIATYPE;
   2790         }
   2791         LeaveCriticalSection(&m_critSec);
   2792         DebugPrintOut(L"MediaSink::GetCharacteristics: HRESULT=%i\n", hr);
   2793         return hr;
   2794     }
   2795 
   2796     HRESULT STDMETHODCALLTYPE AddStreamSink(
   2797         DWORD dwStreamSinkIdentifier, IMFMediaType * /*pMediaType*/, IMFStreamSink **ppStreamSink) {
   2798         _ComPtr<IMFStreamSink> spMFStream;
   2799         _ComPtr<ICustomStreamSink> pStream;
   2800         EnterCriticalSection(&m_critSec);
   2801         HRESULT hr = CheckShutdown();
   2802 
   2803         if (SUCCEEDED(hr))
   2804         {
   2805             hr = GetStreamSinkById(dwStreamSinkIdentifier, &spMFStream);
   2806         }
   2807 
   2808         if (SUCCEEDED(hr))
   2809         {
   2810             hr = MF_E_STREAMSINK_EXISTS;
   2811         }
   2812         else
   2813         {
   2814             hr = S_OK;
   2815         }
   2816 
   2817         if (SUCCEEDED(hr))
   2818         {
   2819 #ifdef WINRT
   2820             pStream = Microsoft::WRL::Make<StreamSink>();
   2821             if (pStream == nullptr) {
   2822                 hr = E_OUTOFMEMORY;
   2823             }
   2824             if (SUCCEEDED(hr))
   2825                 hr = pStream.As<IMFStreamSink>(&spMFStream);
   2826 #else
   2827             StreamSink* pSink = new StreamSink();
   2828             if (pSink) {
   2829                 hr = pSink->QueryInterface(IID_IMFStreamSink, (void**)spMFStream.GetAddressOf());
   2830                 if (SUCCEEDED(hr)) {
   2831                     hr = spMFStream.As(&pStream);
   2832                 }
   2833                 if (FAILED(hr)) delete pSink;
   2834             }
   2835 #endif
   2836         }
   2837 
   2838         // Initialize the stream.
   2839         _ComPtr<IMFAttributes> pAttr;
   2840         if (SUCCEEDED(hr)) {
   2841             hr = pStream.As(&pAttr);
   2842         }
   2843         if (SUCCEEDED(hr)) {
   2844             hr = pAttr->SetUINT32(MF_STREAMSINK_ID, dwStreamSinkIdentifier);
   2845             if (SUCCEEDED(hr)) {
   2846                 hr = pAttr->SetUnknown(MF_STREAMSINK_MEDIASINKINTERFACE, (IMFMediaSink*)this);
   2847             }
   2848         }
   2849         if (SUCCEEDED(hr)) {
   2850             hr = pStream->Initialize();
   2851         }
   2852 
   2853         if (SUCCEEDED(hr))
   2854         {
   2855             ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
   2856             ComPtrList<IMFStreamSink>::POSITION posEnd = m_streams.EndPosition();
   2857 
   2858             // Insert in proper position
   2859             for (; pos != posEnd; pos = m_streams.Next(pos))
   2860             {
   2861                 DWORD dwCurrId;
   2862                 _ComPtr<IMFStreamSink> spCurr;
   2863                 hr = m_streams.GetItemPos(pos, &spCurr);
   2864                 if (FAILED(hr))
   2865                 {
   2866                     break;
   2867                 }
   2868                 hr = spCurr->GetIdentifier(&dwCurrId);
   2869                 if (FAILED(hr))
   2870                 {
   2871                     break;
   2872                 }
   2873 
   2874                 if (dwCurrId > dwStreamSinkIdentifier)
   2875                 {
   2876                     break;
   2877                 }
   2878             }
   2879 
   2880             if (SUCCEEDED(hr))
   2881             {
   2882                 hr = m_streams.InsertPos(pos, spMFStream.Get());
   2883             }
   2884         }
   2885 
   2886         if (SUCCEEDED(hr))
   2887         {
   2888             *ppStreamSink = spMFStream.Detach();
   2889         }
   2890         LeaveCriticalSection(&m_critSec);
   2891         DebugPrintOut(L"MediaSink::AddStreamSink: HRESULT=%i\n", hr);
   2892         return hr;
   2893     }
   2894 
   2895     HRESULT STDMETHODCALLTYPE RemoveStreamSink(DWORD dwStreamSinkIdentifier) {
   2896         EnterCriticalSection(&m_critSec);
   2897         HRESULT hr = CheckShutdown();
   2898         ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
   2899         ComPtrList<IMFStreamSink>::POSITION endPos = m_streams.EndPosition();
   2900         _ComPtr<IMFStreamSink> spStream;
   2901 
   2902         if (SUCCEEDED(hr))
   2903         {
   2904             for (; pos != endPos; pos = m_streams.Next(pos))
   2905             {
   2906                 hr = m_streams.GetItemPos(pos, &spStream);
   2907                 DWORD dwId;
   2908 
   2909                 if (FAILED(hr))
   2910                 {
   2911                     break;
   2912                 }
   2913 
   2914                 hr = spStream->GetIdentifier(&dwId);
   2915                 if (FAILED(hr) || dwId == dwStreamSinkIdentifier)
   2916                 {
   2917                     break;
   2918                 }
   2919             }
   2920 
   2921             if (pos == endPos)
   2922             {
   2923                 hr = MF_E_INVALIDSTREAMNUMBER;
   2924             }
   2925         }
   2926 
   2927         if (SUCCEEDED(hr))
   2928         {
   2929             hr = m_streams.Remove(pos, nullptr);
   2930                     _ComPtr<ICustomStreamSink> spCustomSink;
   2931 #ifdef WINRT
   2932                     spCustomSink = static_cast<StreamSink*>(spStream.Get());
   2933                     hr = S_OK;
   2934 #else
   2935                     hr = spStream.As(&spCustomSink);
   2936 #endif
   2937                     if (SUCCEEDED(hr))
   2938                         hr = spCustomSink->Shutdown();
   2939         }
   2940         LeaveCriticalSection(&m_critSec);
   2941         DebugPrintOut(L"MediaSink::RemoveStreamSink: HRESULT=%i\n", hr);
   2942         return hr;
   2943     }
   2944 
   2945     HRESULT STDMETHODCALLTYPE GetStreamSinkCount(DWORD *pStreamSinkCount) {
   2946         if (pStreamSinkCount == NULL)
   2947         {
   2948             return E_INVALIDARG;
   2949         }
   2950 
   2951         EnterCriticalSection(&m_critSec);
   2952 
   2953         HRESULT hr = CheckShutdown();
   2954 
   2955         if (SUCCEEDED(hr))
   2956         {
   2957             *pStreamSinkCount = m_streams.GetCount();
   2958         }
   2959 
   2960         LeaveCriticalSection(&m_critSec);
   2961         DebugPrintOut(L"MediaSink::GetStreamSinkCount: HRESULT=%i\n", hr);
   2962         return hr;
   2963     }
   2964 
   2965     HRESULT STDMETHODCALLTYPE GetStreamSinkByIndex(
   2966         DWORD dwIndex, IMFStreamSink **ppStreamSink) {
   2967         if (ppStreamSink == NULL)
   2968         {
   2969             return E_INVALIDARG;
   2970         }
   2971 
   2972         _ComPtr<IMFStreamSink> spStream;
   2973         EnterCriticalSection(&m_critSec);
   2974         DWORD cStreams = m_streams.GetCount();
   2975 
   2976         if (dwIndex >= cStreams)
   2977         {
   2978             return MF_E_INVALIDINDEX;
   2979         }
   2980 
   2981         HRESULT hr = CheckShutdown();
   2982 
   2983         if (SUCCEEDED(hr))
   2984         {
   2985             ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
   2986             ComPtrList<IMFStreamSink>::POSITION endPos = m_streams.EndPosition();
   2987             DWORD dwCurrent = 0;
   2988 
   2989             for (; pos != endPos && dwCurrent < dwIndex; pos = m_streams.Next(pos), ++dwCurrent)
   2990             {
   2991                 // Just move to proper position
   2992             }
   2993 
   2994             if (pos == endPos)
   2995             {
   2996                 hr = MF_E_UNEXPECTED;
   2997             }
   2998             else
   2999             {
   3000                 hr = m_streams.GetItemPos(pos, &spStream);
   3001             }
   3002         }
   3003 
   3004         if (SUCCEEDED(hr))
   3005         {
   3006             *ppStreamSink = spStream.Detach();
   3007         }
   3008         LeaveCriticalSection(&m_critSec);
   3009         DebugPrintOut(L"MediaSink::GetStreamSinkByIndex: HRESULT=%i\n", hr);
   3010         return hr;
   3011     }
   3012 
   3013     HRESULT STDMETHODCALLTYPE GetStreamSinkById(
   3014         DWORD dwStreamSinkIdentifier, IMFStreamSink **ppStreamSink) {
   3015         if (ppStreamSink == NULL)
   3016         {
   3017             return E_INVALIDARG;
   3018         }
   3019 
   3020         EnterCriticalSection(&m_critSec);
   3021         HRESULT hr = CheckShutdown();
   3022         _ComPtr<IMFStreamSink> spResult;
   3023 
   3024         if (SUCCEEDED(hr))
   3025         {
   3026             ComPtrList<IMFStreamSink>::POSITION pos = m_streams.FrontPosition();
   3027             ComPtrList<IMFStreamSink>::POSITION endPos = m_streams.EndPosition();
   3028 
   3029             for (; pos != endPos; pos = m_streams.Next(pos))
   3030             {
   3031                 _ComPtr<IMFStreamSink> spStream;
   3032                 hr = m_streams.GetItemPos(pos, &spStream);
   3033                 DWORD dwId;
   3034 
   3035                 if (FAILED(hr))
   3036                 {
   3037                     break;
   3038                 }
   3039 
   3040                 hr = spStream->GetIdentifier(&dwId);
   3041                 if (FAILED(hr))
   3042                 {
   3043                     break;
   3044                 }
   3045                 else if (dwId == dwStreamSinkIdentifier)
   3046                 {
   3047                     spResult = spStream;
   3048                     break;
   3049                 }
   3050             }
   3051 
   3052             if (pos == endPos)
   3053             {
   3054                 hr = MF_E_INVALIDSTREAMNUMBER;
   3055             }
   3056         }
   3057 
   3058         if (SUCCEEDED(hr))
   3059         {
   3060             assert(spResult);
   3061             *ppStreamSink = spResult.Detach();
   3062         }
   3063         LeaveCriticalSection(&m_critSec);
   3064         DebugPrintOut(L"MediaSink::GetStreamSinkById: HRESULT=%i\n", hr);
   3065         return hr;
   3066     }
   3067 
   3068     HRESULT STDMETHODCALLTYPE SetPresentationClock(
   3069         IMFPresentationClock *pPresentationClock) {
   3070         EnterCriticalSection(&m_critSec);
   3071 
   3072         HRESULT hr = CheckShutdown();
   3073 
   3074         // If we already have a clock, remove ourselves from that clock's
   3075         // state notifications.
   3076         if (SUCCEEDED(hr)) {
   3077             if (m_spClock) {
   3078                 hr = m_spClock->RemoveClockStateSink(this);
   3079             }
   3080         }
   3081 
   3082         // Register ourselves to get state notifications from the new clock.
   3083         if (SUCCEEDED(hr)) {
   3084             if (pPresentationClock) {
   3085                 hr = pPresentationClock->AddClockStateSink(this);
   3086             }
   3087         }
   3088 
   3089         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
   3090         if (SUCCEEDED(hr)) {
   3091             // Release the pointer to the old clock.
   3092             // Store the pointer to the new clock.
   3093             m_spClock = pPresentationClock;
   3094             hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
   3095         }
   3096         LeaveCriticalSection(&m_critSec);
   3097         if (SUCCEEDED(hr))
   3098             hr = pSampleCallback->OnSetPresentationClock(pPresentationClock);
   3099         DebugPrintOut(L"MediaSink::SetPresentationClock: HRESULT=%i\n", hr);
   3100         return hr;
   3101     }
   3102 
   3103     HRESULT STDMETHODCALLTYPE GetPresentationClock(
   3104         IMFPresentationClock **ppPresentationClock) {
   3105         if (ppPresentationClock == NULL) {
   3106             return E_INVALIDARG;
   3107         }
   3108 
   3109         EnterCriticalSection(&m_critSec);
   3110 
   3111         HRESULT hr = CheckShutdown();
   3112 
   3113         if (SUCCEEDED(hr)) {
   3114             if (!m_spClock) {
   3115                 hr = MF_E_NO_CLOCK; // There is no presentation clock.
   3116             } else {
   3117                 // Return the pointer to the caller.
   3118                 hr = m_spClock.CopyTo(ppPresentationClock);
   3119             }
   3120         }
   3121         LeaveCriticalSection(&m_critSec);
   3122         DebugPrintOut(L"MediaSink::GetPresentationClock: HRESULT=%i\n", hr);
   3123         return hr;
   3124     }
   3125 
   3126     HRESULT STDMETHODCALLTYPE Shutdown(void) {
   3127         EnterCriticalSection(&m_critSec);
   3128 
   3129         HRESULT hr = CheckShutdown();
   3130 
   3131         if (SUCCEEDED(hr)) {
   3132             ForEach(m_streams, ShutdownFunc());
   3133             m_streams.Clear();
   3134             m_spClock.ReleaseAndGetAddressOf();
   3135 
   3136                     _ComPtr<IMFMediaType> pType;
   3137                     hr = CBaseAttributes<>::GetUnknown(MF_MEDIASINK_PREFERREDTYPE, __uuidof(IMFMediaType), (LPVOID*)pType.GetAddressOf());
   3138                     if (SUCCEEDED(hr)) {
   3139             hr = DeleteItem(MF_MEDIASINK_PREFERREDTYPE);
   3140                     }
   3141             m_IsShutdown = true;
   3142         }
   3143 
   3144         LeaveCriticalSection(&m_critSec);
   3145         DebugPrintOut(L"MediaSink::Shutdown: HRESULT=%i\n", hr);
   3146         return hr;
   3147     }
   3148     class ShutdownFunc
   3149     {
   3150     public:
   3151         HRESULT operator()(IMFStreamSink *pStream) const
   3152         {
   3153                     _ComPtr<ICustomStreamSink> spCustomSink;
   3154                     HRESULT hr;
   3155 #ifdef WINRT
   3156                     spCustomSink = static_cast<StreamSink*>(pStream);
   3157 #else
   3158                     hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf()));
   3159                     if (FAILED(hr)) return hr;
   3160 #endif
   3161                     hr = spCustomSink->Shutdown();
   3162                     return hr;
   3163         }
   3164     };
   3165 
   3166     class StartFunc
   3167     {
   3168     public:
   3169         StartFunc(LONGLONG llStartTime)
   3170             : _llStartTime(llStartTime)
   3171         {
   3172         }
   3173 
   3174         HRESULT operator()(IMFStreamSink *pStream) const
   3175         {
   3176                     _ComPtr<ICustomStreamSink> spCustomSink;
   3177                     HRESULT hr;
   3178 #ifdef WINRT
   3179                     spCustomSink = static_cast<StreamSink*>(pStream);
   3180 #else
   3181                     hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf()));
   3182                     if (FAILED(hr)) return hr;
   3183 #endif
   3184                     hr = spCustomSink->Start(_llStartTime);
   3185                     return hr;
   3186         }
   3187 
   3188         LONGLONG _llStartTime;
   3189     };
   3190 
   3191     class StopFunc
   3192     {
   3193     public:
   3194         HRESULT operator()(IMFStreamSink *pStream) const
   3195         {
   3196                     _ComPtr<ICustomStreamSink> spCustomSink;
   3197                     HRESULT hr;
   3198 #ifdef WINRT
   3199                     spCustomSink = static_cast<StreamSink*>(pStream);
   3200 #else
   3201                     hr = pStream->QueryInterface(IID_PPV_ARGS(spCustomSink.GetAddressOf()));
   3202                     if (FAILED(hr)) return hr;
   3203 #endif
   3204                     hr = spCustomSink->Stop();
   3205                     return hr;
   3206         }
   3207     };
   3208 
   3209     template <class T, class TFunc>
   3210     HRESULT ForEach(ComPtrList<T> &col, TFunc fn)
   3211     {
   3212         ComPtrList<T>::POSITION pos = col.FrontPosition();
   3213         ComPtrList<T>::POSITION endPos = col.EndPosition();
   3214         HRESULT hr = S_OK;
   3215 
   3216         for (; pos != endPos; pos = col.Next(pos))
   3217         {
   3218             _ComPtr<T> spStream;
   3219 
   3220             hr = col.GetItemPos(pos, &spStream);
   3221             if (FAILED(hr))
   3222             {
   3223                 break;
   3224             }
   3225 
   3226             hr = fn(spStream.Get());
   3227         }
   3228 
   3229         return hr;
   3230     }
   3231     //IMFClockStateSink
   3232     HRESULT STDMETHODCALLTYPE OnClockStart(
   3233         MFTIME hnsSystemTime,
   3234         LONGLONG llClockStartOffset) {
   3235         EnterCriticalSection(&m_critSec);
   3236         HRESULT hr = CheckShutdown();
   3237 
   3238         if (SUCCEEDED(hr))
   3239         {
   3240             // Start each stream.
   3241             m_llStartTime = llClockStartOffset;
   3242             hr = ForEach(m_streams, StartFunc(llClockStartOffset));
   3243         }
   3244         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
   3245         if (SUCCEEDED(hr))
   3246             hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
   3247         LeaveCriticalSection(&m_critSec);
   3248         if (SUCCEEDED(hr))
   3249             hr = pSampleCallback->OnClockStart(hnsSystemTime, llClockStartOffset);
   3250         DebugPrintOut(L"MediaSink::OnClockStart: HRESULT=%i\n", hr);
   3251         return hr;
   3252     }
   3253 
   3254     HRESULT STDMETHODCALLTYPE OnClockStop(
   3255         MFTIME hnsSystemTime) {
   3256         EnterCriticalSection(&m_critSec);
   3257         HRESULT hr = CheckShutdown();
   3258 
   3259         if (SUCCEEDED(hr))
   3260         {
   3261             // Stop each stream
   3262             hr = ForEach(m_streams, StopFunc());
   3263         }
   3264         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
   3265         if (SUCCEEDED(hr))
   3266             hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
   3267         LeaveCriticalSection(&m_critSec);
   3268         if (SUCCEEDED(hr))
   3269             hr = pSampleCallback->OnClockStop(hnsSystemTime);
   3270         DebugPrintOut(L"MediaSink::OnClockStop: HRESULT=%i\n", hr);
   3271         return hr;
   3272     }
   3273 
   3274     HRESULT STDMETHODCALLTYPE OnClockPause(
   3275         MFTIME hnsSystemTime) {
   3276         HRESULT hr;
   3277         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
   3278         hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
   3279         if (SUCCEEDED(hr))
   3280             hr = pSampleCallback->OnClockPause(hnsSystemTime);
   3281         DebugPrintOut(L"MediaSink::OnClockPause: HRESULT=%i\n", hr);
   3282         return hr;
   3283     }
   3284 
   3285     HRESULT STDMETHODCALLTYPE OnClockRestart(
   3286         MFTIME hnsSystemTime) {
   3287            HRESULT hr;
   3288         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
   3289         hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
   3290         if (SUCCEEDED(hr))
   3291             hr = pSampleCallback->OnClockRestart(hnsSystemTime);
   3292         DebugPrintOut(L"MediaSink::OnClockRestart: HRESULT=%i\n", hr);
   3293         return hr;
   3294     }
   3295 
   3296     HRESULT STDMETHODCALLTYPE OnClockSetRate(
   3297         MFTIME hnsSystemTime,
   3298         float flRate) {
   3299            HRESULT hr;
   3300         _ComPtr<IMFSampleGrabberSinkCallback> pSampleCallback;
   3301         hr = GetUnknown(MF_MEDIASINK_SAMPLEGRABBERCALLBACK, IID_IMFSampleGrabberSinkCallback, (LPVOID*)pSampleCallback.GetAddressOf());
   3302         if (SUCCEEDED(hr))
   3303             hr = pSampleCallback->OnClockSetRate(hnsSystemTime, flRate);
   3304         DebugPrintOut(L"MediaSink::OnClockSetRate: HRESULT=%i\n", hr);
   3305         return hr;
   3306     }
   3307 private:
   3308 #ifndef WINRT
   3309     long m_cRef;
   3310 #endif
   3311     CRITICAL_SECTION            m_critSec;
   3312     bool                        m_IsShutdown;
   3313     ComPtrList<IMFStreamSink>    m_streams;
   3314     _ComPtr<IMFPresentationClock>    m_spClock;
   3315     LONGLONG                        m_llStartTime;
   3316 };
   3317 
   3318 #ifdef WINRT
   3319 ActivatableClass(MediaSink);
   3320 #endif
   3321