1 // Copyright (c) Microsoft. All rights reserved. 2 // 3 // The MIT License (MIT) 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files(the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions : 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 #pragma once 24 25 #include "MediaStreamSink.hpp" 26 #include "MFIncludes.hpp" 27 28 namespace Media { 29 30 const unsigned int c_audioStreamSinkId = 0; 31 const unsigned int c_videoStreamSinkId = 1; 32 33 class MediaSink WrlSealed 34 : public MW::RuntimeClass< 35 MW::RuntimeClassFlags< 36 MW::RuntimeClassType::WinRtClassicComMix> 37 , AWM::IMediaExtension 38 , IMFMediaSink 39 , IMFClockStateSink 40 , MW::FtmBase 41 > 42 { 43 InspectableClass(L"MediaSink", BaseTrust) 44 45 public: 46 47 MediaSink( 48 _In_opt_ WMMp::AudioEncodingProperties^ audioProps, 49 _In_opt_ WMMp::VideoEncodingProperties^ videoProps, 50 _In_opt_ MediaSampleHandler^ audioSampleHandler, 51 _In_opt_ MediaSampleHandler^ videoSampleHandler 52 ) 53 : _shutdown(false) 54 { 55 MW::ComPtr<IMFMediaType> audioMT; 56 if (audioProps != nullptr) 57 { 58 CHK(MFCreateMediaTypeFromProperties(As<IUnknown>(audioProps).Get(), &audioMT)); 59 _audioStreamSink = MW::Make<MediaStreamSink>( 60 this, 61 c_audioStreamSinkId, 62 audioMT, 63 audioSampleHandler 64 ); 65 } 66 67 MW::ComPtr<IMFMediaType> videoMT; 68 if (videoProps != nullptr) 69 { 70 CHK(MFCreateMediaTypeFromProperties(As<IUnknown>(videoProps).Get(), &videoMT)); 71 _videoStreamSink = MW::Make<MediaStreamSink>( 72 this, 73 c_videoStreamSinkId, 74 videoMT, 75 videoSampleHandler 76 ); 77 } 78 } 79 RequestAudioSample()80 void RequestAudioSample() 81 { 82 auto lock = _lock.LockExclusive(); 83 84 _VerifyNotShutdown(); 85 86 _audioStreamSink->RequestSample(); 87 } 88 RequestVideoSample()89 void RequestVideoSample() 90 { 91 auto lock = _lock.LockExclusive(); 92 93 _VerifyNotShutdown(); 94 95 _videoStreamSink->RequestSample(); 96 } 97 SetCurrentAudioMediaType(_In_ IMFMediaType * mt)98 void SetCurrentAudioMediaType(_In_ IMFMediaType* mt) 99 { 100 auto lock = _lock.LockExclusive(); 101 102 _VerifyNotShutdown(); 103 104 _audioStreamSink->InternalSetCurrentMediaType(mt); 105 } 106 SetCurrentVideoMediaType(_In_ IMFMediaType * mt)107 void SetCurrentVideoMediaType(_In_ IMFMediaType* mt) 108 { 109 auto lock = _lock.LockExclusive(); 110 111 _VerifyNotShutdown(); 112 113 _videoStreamSink->InternalSetCurrentMediaType(mt); 114 } 115 116 // 117 // IMediaExtension 118 // 119 SetProperties(_In_ AWFC::IPropertySet *)120 IFACEMETHODIMP SetProperties(_In_ AWFC::IPropertySet * /*configuration*/) 121 { 122 return ExceptionBoundary([this]() 123 { 124 auto lock = _lock.LockExclusive(); 125 126 _VerifyNotShutdown(); 127 }); 128 } 129 130 // 131 // IMFMediaSink 132 // 133 GetCharacteristics(_Out_ DWORD * characteristics)134 IFACEMETHODIMP GetCharacteristics(_Out_ DWORD *characteristics) 135 { 136 return ExceptionBoundary([this, characteristics]() 137 { 138 _VerifyNotShutdown(); 139 140 CHKNULL(characteristics); 141 *characteristics = MEDIASINK_RATELESS | MEDIASINK_FIXED_STREAMS; 142 }); 143 } 144 AddStreamSink(DWORD,_In_ IMFMediaType *,_COM_Outptr_ IMFStreamSink ** streamSink)145 IFACEMETHODIMP AddStreamSink( 146 DWORD /*streamSinkIdentifier*/, 147 _In_ IMFMediaType * /*mediaType*/, 148 _COM_Outptr_ IMFStreamSink **streamSink 149 ) 150 { 151 return ExceptionBoundary([this, streamSink]() 152 { 153 _VerifyNotShutdown(); 154 155 CHKNULL(streamSink); 156 *streamSink = nullptr; 157 158 CHK(MF_E_STREAMSINKS_FIXED); 159 }); 160 } 161 RemoveStreamSink(DWORD)162 IFACEMETHODIMP RemoveStreamSink(DWORD /*streamSinkIdentifier*/) 163 { 164 return ExceptionBoundary([this]() 165 { 166 _VerifyNotShutdown(); 167 168 CHK(MF_E_STREAMSINKS_FIXED); 169 }); 170 } 171 GetStreamSinkCount(_Out_ DWORD * streamSinkCount)172 IFACEMETHODIMP GetStreamSinkCount(_Out_ DWORD *streamSinkCount) 173 { 174 return ExceptionBoundary([this, streamSinkCount]() 175 { 176 CHKNULL(streamSinkCount); 177 178 _VerifyNotShutdown(); 179 180 *streamSinkCount = (_audioStreamSink != nullptr) + (_videoStreamSink != nullptr); 181 }); 182 } 183 GetStreamSinkByIndex(DWORD index,_COM_Outptr_ IMFStreamSink ** streamSink)184 IFACEMETHODIMP GetStreamSinkByIndex(DWORD index, _COM_Outptr_ IMFStreamSink **streamSink) 185 { 186 return ExceptionBoundary([this, index, streamSink]() 187 { 188 auto lock = _lock.LockExclusive(); 189 190 CHKNULL(streamSink); 191 *streamSink = nullptr; 192 193 _VerifyNotShutdown(); 194 195 switch (index) 196 { 197 case 0: 198 if (_audioStreamSink != nullptr) 199 { 200 CHK(_audioStreamSink.CopyTo(streamSink)); 201 } 202 else 203 { 204 CHK(_videoStreamSink.CopyTo(streamSink)); 205 } 206 break; 207 208 case 1: 209 if ((_audioStreamSink != nullptr) && (_videoStreamSink != nullptr)) 210 { 211 CHK(_videoStreamSink.CopyTo(streamSink)); 212 } 213 else 214 { 215 CHK(E_INVALIDARG); 216 } 217 break; 218 219 default: 220 CHK(E_INVALIDARG); 221 } 222 }); 223 } 224 GetStreamSinkById(DWORD identifier,_COM_Outptr_ IMFStreamSink ** streamSink)225 IFACEMETHODIMP GetStreamSinkById(DWORD identifier, _COM_Outptr_ IMFStreamSink **streamSink) 226 { 227 return ExceptionBoundary([this, identifier, streamSink]() 228 { 229 auto lock = _lock.LockExclusive(); 230 231 CHKNULL(streamSink); 232 *streamSink = nullptr; 233 234 _VerifyNotShutdown(); 235 236 if ((identifier == 0) && (_audioStreamSink != nullptr)) 237 { 238 CHK(_audioStreamSink.CopyTo(streamSink)); 239 } 240 else if ((identifier == 1) && (_videoStreamSink != nullptr)) 241 { 242 CHK(_videoStreamSink.CopyTo(streamSink)); 243 } 244 else 245 { 246 CHK(E_INVALIDARG); 247 } 248 }); 249 } 250 SetPresentationClock(_In_ IMFPresentationClock * clock)251 IFACEMETHODIMP SetPresentationClock(_In_ IMFPresentationClock *clock) 252 { 253 return ExceptionBoundary([this, clock]() 254 { 255 auto lock = _lock.LockExclusive(); 256 257 _VerifyNotShutdown(); 258 259 if (_clock != nullptr) 260 { 261 CHK(_clock->RemoveClockStateSink(this)); 262 _clock = nullptr; 263 } 264 265 if (clock != nullptr) 266 { 267 CHK(clock->AddClockStateSink(this)); 268 _clock = clock; 269 } 270 }); 271 } 272 GetPresentationClock(_COM_Outptr_ IMFPresentationClock ** clock)273 IFACEMETHODIMP GetPresentationClock(_COM_Outptr_ IMFPresentationClock **clock) 274 { 275 return ExceptionBoundary([this, clock]() 276 { 277 auto lock = _lock.LockExclusive(); 278 279 CHKNULL(clock); 280 *clock = nullptr; 281 282 _VerifyNotShutdown(); 283 284 if (_clock != nullptr) 285 { 286 CHK(_clock.CopyTo(clock)) 287 } 288 }); 289 } 290 Shutdown()291 IFACEMETHODIMP Shutdown() 292 { 293 return ExceptionBoundary([this]() 294 { 295 auto lock = _lock.LockExclusive(); 296 297 if (_shutdown) 298 { 299 return; 300 } 301 _shutdown = true; 302 303 if (_audioStreamSink != nullptr) 304 { 305 _audioStreamSink->Shutdown(); 306 _audioStreamSink = nullptr; 307 } 308 309 if (_videoStreamSink != nullptr) 310 { 311 _videoStreamSink->Shutdown(); 312 _videoStreamSink = nullptr; 313 } 314 315 if (_clock != nullptr) 316 { 317 (void)_clock->RemoveClockStateSink(this); 318 _clock = nullptr; 319 } 320 }); 321 } 322 323 // 324 // IMFClockStateSink methods 325 // 326 OnClockStart(MFTIME,LONGLONG)327 IFACEMETHODIMP OnClockStart(MFTIME /*hnsSystemTime*/, LONGLONG /*llClockStartOffset*/) 328 { 329 return ExceptionBoundary([this]() 330 { 331 auto lock = _lock.LockExclusive(); 332 333 _VerifyNotShutdown(); 334 }); 335 } 336 OnClockStop(MFTIME)337 IFACEMETHODIMP OnClockStop(MFTIME /*hnsSystemTime*/) 338 { 339 return ExceptionBoundary([this]() 340 { 341 auto lock = _lock.LockExclusive(); 342 343 _VerifyNotShutdown(); 344 }); 345 } 346 OnClockPause(MFTIME)347 IFACEMETHODIMP OnClockPause(MFTIME /*hnsSystemTime*/) 348 { 349 return ExceptionBoundary([this]() 350 { 351 auto lock = _lock.LockExclusive(); 352 353 _VerifyNotShutdown(); 354 }); 355 } 356 OnClockRestart(MFTIME)357 IFACEMETHODIMP OnClockRestart(MFTIME /*hnsSystemTime*/) 358 { 359 return ExceptionBoundary([this]() 360 { 361 auto lock = _lock.LockExclusive(); 362 363 _VerifyNotShutdown(); 364 }); 365 } 366 OnClockSetRate(MFTIME,float)367 IFACEMETHODIMP OnClockSetRate(MFTIME /*hnsSystemTime*/, float /*flRate*/) 368 { 369 return ExceptionBoundary([this]() 370 { 371 auto lock = _lock.LockExclusive(); 372 373 _VerifyNotShutdown(); 374 }); 375 } 376 377 private: 378 379 bool _shutdown; 380 _VerifyNotShutdown()381 void _VerifyNotShutdown() 382 { 383 if (_shutdown) 384 { 385 CHK(MF_E_SHUTDOWN); 386 } 387 } 388 389 MW::ComPtr<MediaStreamSink> _audioStreamSink; 390 MW::ComPtr<MediaStreamSink> _videoStreamSink; 391 MW::ComPtr<IMFPresentationClock> _clock; 392 393 MWW::SRWLock _lock; 394 }; 395 396 }