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 #include "MediaStreamSink.hpp"
24 #include "MFIncludes.hpp"
25
26 using namespace Media;
27 using namespace Microsoft::WRL;
28 using namespace Platform;
29 using namespace Windows::Foundation;
30
31 MediaStreamSink::MediaStreamSink(
32 __in const MW::ComPtr<IMFMediaSink>& sink,
33 __in DWORD id,
34 __in const MW::ComPtr<IMFMediaType>& mt,
35 __in MediaSampleHandler^ sampleHandler
36 )
37 : _shutdown(false)
38 , _id(-1)
39 , _width(0)
40 , _height(0)
41 {
42 CHK(MFCreateEventQueue(&_eventQueue));
43 CHK(MFCreateMediaType(&_curMT));
44
45 _UpdateMediaType(mt);
46
47 _sink = sink;
48 _id = id;
49 _sampleHandler = sampleHandler;
50 }
51
GetMediaSink(__deref_out IMFMediaSink ** sink)52 HRESULT MediaStreamSink::GetMediaSink(__deref_out IMFMediaSink **sink)
53 {
54 return ExceptionBoundary([this, sink]()
55 {
56 auto lock = _lock.LockExclusive();
57
58 CHKNULL(sink);
59 *sink = nullptr;
60
61 _VerifyNotShutdown();
62
63 CHK(_sink.CopyTo(sink));
64 });
65 }
66
GetIdentifier(__out DWORD * identifier)67 HRESULT MediaStreamSink::GetIdentifier(__out DWORD *identifier)
68 {
69 return ExceptionBoundary([this, identifier]()
70 {
71 auto lock = _lock.LockExclusive();
72
73 CHKNULL(identifier);
74
75 _VerifyNotShutdown();
76
77 *identifier = _id;
78 });
79 }
80
GetMediaTypeHandler(__deref_out IMFMediaTypeHandler ** handler)81 HRESULT MediaStreamSink::GetMediaTypeHandler(__deref_out IMFMediaTypeHandler **handler)
82 {
83 return ExceptionBoundary([this, handler]()
84 {
85 auto lock = _lock.LockExclusive();
86
87 CHKNULL(handler);
88 *handler = nullptr;
89
90 _VerifyNotShutdown();
91
92 *handler = this;
93 this->AddRef();
94
95 });
96 }
97
RequestSample()98 void MediaStreamSink::RequestSample()
99 {
100 auto lock = _lock.LockExclusive();
101
102 _VerifyNotShutdown();
103
104 CHK(_eventQueue->QueueEventParamVar(MEStreamSinkRequestSample, GUID_NULL, S_OK, nullptr));
105 }
106
ProcessSample(__in_opt IMFSample * sample)107 HRESULT MediaStreamSink::ProcessSample(__in_opt IMFSample *sample)
108 {
109 return ExceptionBoundary([this, sample]()
110 {
111 MediaSampleHandler^ sampleHandler;
112 auto mediaSample = ref new MediaSample();
113
114 {
115 auto lock = _lock.LockExclusive();
116
117 _VerifyNotShutdown();
118
119 if (sample == nullptr)
120 {
121 return;
122 }
123
124 mediaSample->Sample = sample;
125 sampleHandler = _sampleHandler;
126 }
127
128 // Call back without the lock taken to avoid deadlocks
129 sampleHandler(mediaSample);
130 });
131 }
132
PlaceMarker(__in MFSTREAMSINK_MARKER_TYPE,__in const PROPVARIANT *,__in const PROPVARIANT * contextValue)133 HRESULT MediaStreamSink::PlaceMarker(__in MFSTREAMSINK_MARKER_TYPE /*markerType*/, __in const PROPVARIANT * /*markerValue*/, __in const PROPVARIANT * contextValue)
134 {
135 return ExceptionBoundary([this, contextValue]()
136 {
137 auto lock = _lock.LockExclusive();
138 CHKNULL(contextValue);
139
140 _VerifyNotShutdown();
141
142 CHK(_eventQueue->QueueEventParamVar(MEStreamSinkMarker, GUID_NULL, S_OK, contextValue));
143 });
144 }
145
Flush()146 HRESULT MediaStreamSink::Flush()
147 {
148 return ExceptionBoundary([this]()
149 {
150 auto lock = _lock.LockExclusive();
151
152 _VerifyNotShutdown();
153 });
154 }
155
GetEvent(__in DWORD flags,__deref_out IMFMediaEvent ** event)156 HRESULT MediaStreamSink::GetEvent(__in DWORD flags, __deref_out IMFMediaEvent **event)
157 {
158 return ExceptionBoundary([this, flags, event]()
159 {
160 CHKNULL(event);
161 *event = nullptr;
162
163 ComPtr<IMFMediaEventQueue> eventQueue;
164
165 {
166 auto lock = _lock.LockExclusive();
167
168 _VerifyNotShutdown();
169
170 eventQueue = _eventQueue;
171 }
172
173 // May block for a while
174 CHK(eventQueue->GetEvent(flags, event));
175 });
176 }
177
BeginGetEvent(__in IMFAsyncCallback * callback,__in_opt IUnknown * state)178 HRESULT MediaStreamSink::BeginGetEvent(__in IMFAsyncCallback *callback, __in_opt IUnknown *state)
179 {
180 return ExceptionBoundary([this, callback, state]()
181 {
182 auto lock = _lock.LockExclusive();
183
184 _VerifyNotShutdown();
185
186 CHK(_eventQueue->BeginGetEvent(callback, state));
187 });
188 }
189
190
EndGetEvent(__in IMFAsyncResult * result,__deref_out IMFMediaEvent ** event)191 HRESULT MediaStreamSink::EndGetEvent(__in IMFAsyncResult *result, __deref_out IMFMediaEvent **event)
192 {
193 return ExceptionBoundary([this, result, event]()
194 {
195 auto lock = _lock.LockExclusive();
196
197 CHKNULL(event);
198 *event = nullptr;
199
200 _VerifyNotShutdown();
201
202 CHK(_eventQueue->EndGetEvent(result, event));
203 });
204 }
205
QueueEvent(__in MediaEventType met,__in REFGUID extendedType,__in HRESULT status,__in_opt const PROPVARIANT * value)206 HRESULT MediaStreamSink::QueueEvent(
207 __in MediaEventType met,
208 __in REFGUID extendedType,
209 __in HRESULT status,
210 __in_opt const PROPVARIANT *value
211 )
212 {
213 return ExceptionBoundary([this, met, extendedType, status, value]()
214 {
215 auto lock = _lock.LockExclusive();
216
217 _VerifyNotShutdown();
218
219 CHK(_eventQueue->QueueEventParamVar(met, extendedType, status, value));
220 });
221 }
222
IsMediaTypeSupported(__in IMFMediaType * mediaType,__deref_out_opt IMFMediaType ** closestMediaType)223 HRESULT MediaStreamSink::IsMediaTypeSupported(__in IMFMediaType *mediaType, __deref_out_opt IMFMediaType **closestMediaType)
224 {
225 bool supported = false;
226
227 HRESULT hr = ExceptionBoundary([this, mediaType, closestMediaType, &supported]()
228 {
229 auto lock = _lock.LockExclusive();
230
231 if (closestMediaType != nullptr)
232 {
233 *closestMediaType = nullptr;
234 }
235
236 CHKNULL(mediaType);
237
238 _VerifyNotShutdown();
239
240 supported = _IsMediaTypeSupported(mediaType);
241 });
242
243 // Avoid throwing an exception to return MF_E_INVALIDMEDIATYPE as this is not a exceptional case
244 return FAILED(hr) ? hr : supported ? S_OK : MF_E_INVALIDMEDIATYPE;
245 }
246
GetMediaTypeCount(__out DWORD * typeCount)247 HRESULT MediaStreamSink::GetMediaTypeCount(__out DWORD *typeCount)
248 {
249 return ExceptionBoundary([this, typeCount]()
250 {
251 auto lock = _lock.LockExclusive();
252
253 CHKNULL(typeCount);
254
255 _VerifyNotShutdown();
256
257 // No media type provided by default (app needs to specify it)
258 *typeCount = 0;
259 });
260 }
261
GetMediaTypeByIndex(__in DWORD,__deref_out IMFMediaType ** mediaType)262 HRESULT MediaStreamSink::GetMediaTypeByIndex(__in DWORD /*index*/, __deref_out IMFMediaType **mediaType)
263 {
264 HRESULT hr = ExceptionBoundary([this, mediaType]()
265 {
266 auto lock = _lock.LockExclusive();
267
268 CHKNULL(mediaType);
269 *mediaType = nullptr;
270
271 _VerifyNotShutdown();
272 });
273
274 // Avoid throwing an exception to return MF_E_NO_MORE_TYPES as this is not a exceptional case
275 return FAILED(hr) ? hr : MF_E_NO_MORE_TYPES;
276 }
277
SetCurrentMediaType(__in IMFMediaType * mediaType)278 HRESULT MediaStreamSink::SetCurrentMediaType(__in IMFMediaType *mediaType)
279 {
280 return ExceptionBoundary([this, mediaType]()
281 {
282 auto lock = _lock.LockExclusive();
283
284 CHKNULL(mediaType);
285
286 _VerifyNotShutdown();
287
288 if (!_IsMediaTypeSupported(mediaType))
289 {
290 CHK(MF_E_INVALIDMEDIATYPE);
291 }
292
293 _UpdateMediaType(mediaType);
294 });
295 }
296
GetCurrentMediaType(__deref_out_opt IMFMediaType ** mediaType)297 HRESULT MediaStreamSink::GetCurrentMediaType(__deref_out_opt IMFMediaType **mediaType)
298 {
299 return ExceptionBoundary([this, mediaType]()
300 {
301 auto lock = _lock.LockExclusive();
302
303 CHKNULL(mediaType);
304 *mediaType = nullptr;
305
306 _VerifyNotShutdown();
307
308 ComPtr<IMFMediaType> mt;
309 CHK(MFCreateMediaType(&mt));
310 CHK(_curMT->CopyAllItems(mt.Get()));
311 *mediaType = mt.Detach();
312 });
313 }
314
GetMajorType(__out GUID * majorType)315 HRESULT MediaStreamSink::GetMajorType(__out GUID *majorType)
316 {
317 return ExceptionBoundary([this, majorType]()
318 {
319 auto lock = _lock.LockExclusive();
320
321 CHKNULL(majorType);
322
323 _VerifyNotShutdown();
324
325 *majorType = _majorType;
326 });
327 }
328
InternalSetCurrentMediaType(__in const ComPtr<IMFMediaType> & mediaType)329 void MediaStreamSink::InternalSetCurrentMediaType(__in const ComPtr<IMFMediaType>& mediaType)
330 {
331 auto lock = _lock.LockExclusive();
332
333 CHKNULL(mediaType);
334
335 _VerifyNotShutdown();
336
337 _UpdateMediaType(mediaType);
338 }
339
Shutdown()340 void MediaStreamSink::Shutdown()
341 {
342 auto lock = _lock.LockExclusive();
343
344 if (_shutdown)
345 {
346 return;
347 }
348 _shutdown = true;
349
350 (void)_eventQueue->Shutdown();
351 _eventQueue = nullptr;
352
353 _curMT = nullptr;
354 _sink = nullptr;
355 _sampleHandler = nullptr;
356 }
357
_IsMediaTypeSupported(__in const ComPtr<IMFMediaType> & mt) const358 bool MediaStreamSink::_IsMediaTypeSupported(__in const ComPtr<IMFMediaType>& mt) const
359 {
360 GUID majorType;
361 GUID subType;
362 if (SUCCEEDED(mt->GetGUID(MF_MT_MAJOR_TYPE, &majorType)) &&
363 SUCCEEDED(mt->GetGUID(MF_MT_SUBTYPE, &subType)) &&
364 (majorType == _majorType) &&
365 (subType == _subType))
366 {
367 return true;
368 }
369
370 return false;
371 }
372
_UpdateMediaType(__in const ComPtr<IMFMediaType> & mt)373 void MediaStreamSink::_UpdateMediaType(__in const ComPtr<IMFMediaType>& mt)
374 {
375 CHK(mt->GetGUID(MF_MT_MAJOR_TYPE, &_majorType));
376 CHK(mt->GetGUID(MF_MT_SUBTYPE, &_subType));
377
378 if (_majorType == MFMediaType_Video)
379 {
380 CHK(MFGetAttributeSize(mt.Get(), MF_MT_FRAME_SIZE, &_width, &_height));
381 }
382
383 CHK(mt->CopyAllItems(_curMT.Get()));
384 }