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