2 * Copyright 2019 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "mf_private.h"
26 #include "wine/debug.h"
27 #include "wine/heap.h"
28 #include "wine/list.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
34 SINK_STATE_STOPPED
= 0,
38 struct sample_grabber
;
40 enum scheduled_item_type
49 enum scheduled_item_type type
;
55 MFSTREAMSINK_MARKER_TYPE type
;
63 IMFMediaSink IMFMediaSink_iface
;
64 IMFClockStateSink IMFClockStateSink_iface
;
65 IMFMediaEventGenerator IMFMediaEventGenerator_iface
;
66 IMFStreamSink IMFStreamSink_iface
;
67 IMFMediaTypeHandler IMFMediaTypeHandler_iface
;
68 IMFAsyncCallback timer_callback
;
70 IMFSampleGrabberSinkCallback
*callback
;
71 IMFSampleGrabberSinkCallback2
*callback2
;
72 IMFMediaType
*media_type
;
74 IMFMediaEventQueue
*event_queue
;
75 IMFMediaEventQueue
*stream_event_queue
;
76 IMFPresentationClock
*clock
;
78 IMFAttributes
*sample_attributes
;
82 UINT64 sample_time_offset
;
83 enum sink_state state
;
87 static IMFSampleGrabberSinkCallback
*sample_grabber_get_callback(const struct sample_grabber
*sink
)
89 return sink
->callback2
? (IMFSampleGrabberSinkCallback
*)sink
->callback2
: sink
->callback
;
92 struct sample_grabber_activate_context
94 IMFMediaType
*media_type
;
95 IMFSampleGrabberSinkCallback
*callback
;
99 static void sample_grabber_free_private(void *user_context
)
101 struct sample_grabber_activate_context
*context
= user_context
;
102 IMFMediaType_Release(context
->media_type
);
103 IMFSampleGrabberSinkCallback_Release(context
->callback
);
107 static struct sample_grabber
*impl_from_IMFMediaSink(IMFMediaSink
*iface
)
109 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaSink_iface
);
112 static struct sample_grabber
*impl_from_IMFClockStateSink(IMFClockStateSink
*iface
)
114 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFClockStateSink_iface
);
117 static struct sample_grabber
*impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator
*iface
)
119 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaEventGenerator_iface
);
122 static struct sample_grabber
*impl_from_IMFStreamSink(IMFStreamSink
*iface
)
124 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFStreamSink_iface
);
127 static struct sample_grabber
*impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler
*iface
)
129 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaTypeHandler_iface
);
132 static struct sample_grabber
*impl_from_IMFAsyncCallback(IMFAsyncCallback
*iface
)
134 return CONTAINING_RECORD(iface
, struct sample_grabber
, timer_callback
);
137 static HRESULT WINAPI
sample_grabber_stream_QueryInterface(IMFStreamSink
*iface
, REFIID riid
, void **obj
)
139 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
141 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
143 if (IsEqualIID(riid
, &IID_IMFStreamSink
) ||
144 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
145 IsEqualIID(riid
, &IID_IUnknown
))
147 *obj
= &grabber
->IMFStreamSink_iface
;
149 else if (IsEqualIID(riid
, &IID_IMFMediaTypeHandler
))
151 *obj
= &grabber
->IMFMediaTypeHandler_iface
;
155 WARN("Unsupported %s.\n", debugstr_guid(riid
));
157 return E_NOINTERFACE
;
160 IUnknown_AddRef((IUnknown
*)*obj
);
165 static ULONG WINAPI
sample_grabber_stream_AddRef(IMFStreamSink
*iface
)
167 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
168 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
171 static void stream_release_pending_item(struct scheduled_item
*item
)
173 list_remove(&item
->entry
);
176 case ITEM_TYPE_SAMPLE
:
177 IMFSample_Release(item
->u
.sample
);
179 case ITEM_TYPE_MARKER
:
180 PropVariantClear(&item
->u
.marker
.context
);
186 static ULONG WINAPI
sample_grabber_stream_Release(IMFStreamSink
*iface
)
188 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
189 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
192 static HRESULT WINAPI
sample_grabber_stream_GetEvent(IMFStreamSink
*iface
, DWORD flags
, IMFMediaEvent
**event
)
194 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
196 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
198 if (grabber
->is_shut_down
)
199 return MF_E_STREAMSINK_REMOVED
;
201 return IMFMediaEventQueue_GetEvent(grabber
->stream_event_queue
, flags
, event
);
204 static HRESULT WINAPI
sample_grabber_stream_BeginGetEvent(IMFStreamSink
*iface
, IMFAsyncCallback
*callback
,
207 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
209 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
211 if (grabber
->is_shut_down
)
212 return MF_E_STREAMSINK_REMOVED
;
214 return IMFMediaEventQueue_BeginGetEvent(grabber
->stream_event_queue
, callback
, state
);
217 static HRESULT WINAPI
sample_grabber_stream_EndGetEvent(IMFStreamSink
*iface
, IMFAsyncResult
*result
,
218 IMFMediaEvent
**event
)
220 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
222 TRACE("%p, %p, %p.\n", iface
, result
, event
);
224 if (grabber
->is_shut_down
)
225 return MF_E_STREAMSINK_REMOVED
;
227 return IMFMediaEventQueue_EndGetEvent(grabber
->stream_event_queue
, result
, event
);
230 static HRESULT WINAPI
sample_grabber_stream_QueueEvent(IMFStreamSink
*iface
, MediaEventType event_type
,
231 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
233 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
235 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
237 if (grabber
->is_shut_down
)
238 return MF_E_STREAMSINK_REMOVED
;
240 return IMFMediaEventQueue_QueueEventParamVar(grabber
->stream_event_queue
, event_type
, ext_type
, hr
, value
);
243 static HRESULT WINAPI
sample_grabber_stream_GetMediaSink(IMFStreamSink
*iface
, IMFMediaSink
**sink
)
245 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
247 TRACE("%p, %p.\n", iface
, sink
);
249 if (grabber
->is_shut_down
)
250 return MF_E_STREAMSINK_REMOVED
;
252 *sink
= &grabber
->IMFMediaSink_iface
;
253 IMFMediaSink_AddRef(*sink
);
258 static HRESULT WINAPI
sample_grabber_stream_GetIdentifier(IMFStreamSink
*iface
, DWORD
*identifier
)
260 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
262 TRACE("%p, %p.\n", iface
, identifier
);
264 if (grabber
->is_shut_down
)
265 return MF_E_STREAMSINK_REMOVED
;
272 static HRESULT WINAPI
sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink
*iface
, IMFMediaTypeHandler
**handler
)
274 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
276 TRACE("%p, %p.\n", iface
, handler
);
281 if (grabber
->is_shut_down
)
282 return MF_E_STREAMSINK_REMOVED
;
284 *handler
= &grabber
->IMFMediaTypeHandler_iface
;
285 IMFMediaTypeHandler_AddRef(*handler
);
290 static HRESULT
sample_grabber_report_sample(struct sample_grabber
*grabber
, IMFSample
*sample
, BOOL
*sample_delivered
)
292 LONGLONG sample_time
, sample_duration
= 0;
293 IMFMediaBuffer
*buffer
;
299 *sample_delivered
= FALSE
;
301 hr
= IMFMediaType_GetMajorType(grabber
->media_type
, &major_type
);
304 hr
= IMFSample_GetSampleTime(sample
, &sample_time
);
306 if (FAILED(IMFSample_GetSampleDuration(sample
, &sample_duration
)))
310 hr
= IMFSample_GetSampleFlags(sample
, &flags
);
314 if (FAILED(IMFSample_ConvertToContiguousBuffer(sample
, &buffer
)))
317 if (SUCCEEDED(hr
= IMFMediaBuffer_Lock(buffer
, &data
, NULL
, &size
)))
319 *sample_delivered
= TRUE
;
321 if (grabber
->callback2
)
323 hr
= IMFSample_CopyAllItems(sample
, grabber
->sample_attributes
);
325 hr
= IMFSampleGrabberSinkCallback2_OnProcessSampleEx(grabber
->callback2
, &major_type
, flags
,
326 sample_time
, sample_duration
, data
, size
, grabber
->sample_attributes
);
329 hr
= IMFSampleGrabberSinkCallback_OnProcessSample(grabber
->callback
, &major_type
, flags
, sample_time
,
330 sample_duration
, data
, size
);
331 IMFMediaBuffer_Unlock(buffer
);
334 IMFMediaBuffer_Release(buffer
);
340 static HRESULT
stream_schedule_sample(struct sample_grabber
*grabber
, struct scheduled_item
*item
)
345 if (grabber
->is_shut_down
)
346 return MF_E_STREAMSINK_REMOVED
;
348 if (FAILED(hr
= IMFSample_GetSampleTime(item
->u
.sample
, &sampletime
)))
351 if (grabber
->cancel_key
)
353 IUnknown_Release(grabber
->cancel_key
);
354 grabber
->cancel_key
= NULL
;
357 if (FAILED(hr
= IMFTimer_SetTimer(grabber
->timer
, 0, sampletime
- grabber
->sample_time_offset
,
358 &grabber
->timer_callback
, NULL
, &grabber
->cancel_key
)))
360 grabber
->cancel_key
= NULL
;
366 static HRESULT
stream_queue_sample(struct sample_grabber
*grabber
, IMFSample
*sample
)
368 struct scheduled_item
*item
;
372 if (FAILED(hr
= IMFSample_GetSampleTime(sample
, &sampletime
)))
375 if (!(item
= heap_alloc_zero(sizeof(*item
))))
376 return E_OUTOFMEMORY
;
378 item
->type
= ITEM_TYPE_SAMPLE
;
379 item
->u
.sample
= sample
;
380 IMFSample_AddRef(item
->u
.sample
);
381 list_init(&item
->entry
);
382 if (list_empty(&grabber
->items
))
383 hr
= stream_schedule_sample(grabber
, item
);
386 list_add_tail(&grabber
->items
, &item
->entry
);
388 stream_release_pending_item(item
);
393 static void sample_grabber_stream_request_sample(struct sample_grabber
*grabber
)
395 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
398 static HRESULT WINAPI
sample_grabber_stream_ProcessSample(IMFStreamSink
*iface
, IMFSample
*sample
)
400 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
401 BOOL sample_delivered
;
405 TRACE("%p, %p.\n", iface
, sample
);
410 EnterCriticalSection(&grabber
->cs
);
412 if (grabber
->is_shut_down
)
413 hr
= MF_E_STREAMSINK_REMOVED
;
414 else if (grabber
->state
== SINK_STATE_RUNNING
)
416 hr
= IMFSample_GetSampleTime(sample
, &sampletime
);
420 if (grabber
->ignore_clock
)
422 /* OnProcessSample() could return error code, which has to be propagated but isn't a blocker.
423 Use additional flag indicating that user callback was called at all. */
424 hr
= sample_grabber_report_sample(grabber
, sample
, &sample_delivered
);
425 if (sample_delivered
)
426 sample_grabber_stream_request_sample(grabber
);
429 hr
= stream_queue_sample(grabber
, sample
);
433 LeaveCriticalSection(&grabber
->cs
);
438 static void sample_grabber_stream_report_marker(struct sample_grabber
*grabber
, const PROPVARIANT
*context
,
441 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkMarker
, &GUID_NULL
, hr
, context
);
444 static HRESULT
stream_place_marker(struct sample_grabber
*grabber
, MFSTREAMSINK_MARKER_TYPE marker_type
,
445 const PROPVARIANT
*context_value
)
447 struct scheduled_item
*item
;
450 if (list_empty(&grabber
->items
))
452 sample_grabber_stream_report_marker(grabber
, context_value
, S_OK
);
456 if (!(item
= heap_alloc_zero(sizeof(*item
))))
457 return E_OUTOFMEMORY
;
459 item
->type
= ITEM_TYPE_MARKER
;
460 item
->u
.marker
.type
= marker_type
;
461 list_init(&item
->entry
);
462 PropVariantInit(&item
->u
.marker
.context
);
464 hr
= PropVariantCopy(&item
->u
.marker
.context
, context_value
);
466 list_add_tail(&grabber
->items
, &item
->entry
);
468 stream_release_pending_item(item
);
473 static HRESULT WINAPI
sample_grabber_stream_PlaceMarker(IMFStreamSink
*iface
, MFSTREAMSINK_MARKER_TYPE marker_type
,
474 const PROPVARIANT
*marker_value
, const PROPVARIANT
*context_value
)
476 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
479 TRACE("%p, %d, %p, %p.\n", iface
, marker_type
, marker_value
, context_value
);
481 EnterCriticalSection(&grabber
->cs
);
483 if (grabber
->is_shut_down
)
484 hr
= MF_E_STREAMSINK_REMOVED
;
485 else if (grabber
->state
== SINK_STATE_RUNNING
)
486 hr
= stream_place_marker(grabber
, marker_type
, context_value
);
488 LeaveCriticalSection(&grabber
->cs
);
493 static HRESULT WINAPI
sample_grabber_stream_Flush(IMFStreamSink
*iface
)
495 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
496 struct scheduled_item
*item
, *next_item
;
498 TRACE("%p.\n", iface
);
500 if (grabber
->is_shut_down
)
501 return MF_E_STREAMSINK_REMOVED
;
503 EnterCriticalSection(&grabber
->cs
);
505 LIST_FOR_EACH_ENTRY_SAFE(item
, next_item
, &grabber
->items
, struct scheduled_item
, entry
)
507 /* Samples are discarded, markers are processed immediately. */
510 case ITEM_TYPE_SAMPLE
:
512 case ITEM_TYPE_MARKER
:
513 sample_grabber_stream_report_marker(grabber
, &item
->u
.marker
.context
, E_ABORT
);
517 stream_release_pending_item(item
);
520 LeaveCriticalSection(&grabber
->cs
);
525 static const IMFStreamSinkVtbl sample_grabber_stream_vtbl
=
527 sample_grabber_stream_QueryInterface
,
528 sample_grabber_stream_AddRef
,
529 sample_grabber_stream_Release
,
530 sample_grabber_stream_GetEvent
,
531 sample_grabber_stream_BeginGetEvent
,
532 sample_grabber_stream_EndGetEvent
,
533 sample_grabber_stream_QueueEvent
,
534 sample_grabber_stream_GetMediaSink
,
535 sample_grabber_stream_GetIdentifier
,
536 sample_grabber_stream_GetMediaTypeHandler
,
537 sample_grabber_stream_ProcessSample
,
538 sample_grabber_stream_PlaceMarker
,
539 sample_grabber_stream_Flush
,
542 static HRESULT WINAPI
sample_grabber_stream_type_handler_QueryInterface(IMFMediaTypeHandler
*iface
, REFIID riid
,
545 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
546 return IMFStreamSink_QueryInterface(&grabber
->IMFStreamSink_iface
, riid
, obj
);
549 static ULONG WINAPI
sample_grabber_stream_type_handler_AddRef(IMFMediaTypeHandler
*iface
)
551 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
552 return IMFStreamSink_AddRef(&grabber
->IMFStreamSink_iface
);
555 static ULONG WINAPI
sample_grabber_stream_type_handler_Release(IMFMediaTypeHandler
*iface
)
557 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
558 return IMFStreamSink_Release(&grabber
->IMFStreamSink_iface
);
561 static HRESULT
sample_grabber_stream_is_media_type_supported(struct sample_grabber
*grabber
, IMFMediaType
*in_type
)
563 const DWORD supported_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_TYPES
;
566 if (grabber
->is_shut_down
)
567 return MF_E_STREAMSINK_REMOVED
;
572 if (IMFMediaType_IsEqual(grabber
->media_type
, in_type
, &flags
) == S_OK
)
575 return (flags
& supported_flags
) == supported_flags
? S_OK
: MF_E_INVALIDMEDIATYPE
;
578 static HRESULT WINAPI
sample_grabber_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler
*iface
,
579 IMFMediaType
*in_type
, IMFMediaType
**out_type
)
581 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
583 TRACE("%p, %p, %p.\n", iface
, in_type
, out_type
);
585 return sample_grabber_stream_is_media_type_supported(grabber
, in_type
);
588 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler
*iface
, DWORD
*count
)
590 TRACE("%p, %p.\n", iface
, count
);
600 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
*iface
, DWORD index
,
601 IMFMediaType
**media_type
)
603 TRACE("%p, %u, %p.\n", iface
, index
, media_type
);
608 return MF_E_NO_MORE_TYPES
;
611 static HRESULT WINAPI
sample_grabber_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler
*iface
,
612 IMFMediaType
*media_type
)
614 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
617 TRACE("%p, %p.\n", iface
, media_type
);
619 if (FAILED(hr
= sample_grabber_stream_is_media_type_supported(grabber
, media_type
)))
622 IMFMediaType_Release(grabber
->media_type
);
623 grabber
->media_type
= media_type
;
624 IMFMediaType_AddRef(grabber
->media_type
);
629 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler
*iface
,
630 IMFMediaType
**media_type
)
632 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
634 TRACE("%p, %p.\n", iface
, media_type
);
639 if (grabber
->is_shut_down
)
640 return MF_E_STREAMSINK_REMOVED
;
642 *media_type
= grabber
->media_type
;
643 IMFMediaType_AddRef(*media_type
);
648 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
650 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
652 TRACE("%p, %p.\n", iface
, type
);
657 if (grabber
->is_shut_down
)
658 return MF_E_STREAMSINK_REMOVED
;
660 return IMFMediaType_GetMajorType(grabber
->media_type
, type
);
663 static const IMFMediaTypeHandlerVtbl sample_grabber_stream_type_handler_vtbl
=
665 sample_grabber_stream_type_handler_QueryInterface
,
666 sample_grabber_stream_type_handler_AddRef
,
667 sample_grabber_stream_type_handler_Release
,
668 sample_grabber_stream_type_handler_IsMediaTypeSupported
,
669 sample_grabber_stream_type_handler_GetMediaTypeCount
,
670 sample_grabber_stream_type_handler_GetMediaTypeByIndex
,
671 sample_grabber_stream_type_handler_SetCurrentMediaType
,
672 sample_grabber_stream_type_handler_GetCurrentMediaType
,
673 sample_grabber_stream_type_handler_GetMajorType
,
676 static HRESULT WINAPI
sample_grabber_stream_timer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
,
679 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) || IsEqualIID(riid
, &IID_IUnknown
))
682 IMFAsyncCallback_AddRef(iface
);
686 WARN("Unsupported %s.\n", debugstr_guid(riid
));
688 return E_NOINTERFACE
;
691 static ULONG WINAPI
sample_grabber_stream_timer_callback_AddRef(IMFAsyncCallback
*iface
)
693 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
694 return IMFStreamSink_AddRef(&grabber
->IMFStreamSink_iface
);
697 static ULONG WINAPI
sample_grabber_stream_timer_callback_Release(IMFAsyncCallback
*iface
)
699 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
700 return IMFStreamSink_Release(&grabber
->IMFStreamSink_iface
);
703 static HRESULT WINAPI
sample_grabber_stream_timer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
,
709 static HRESULT WINAPI
sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
711 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
712 BOOL sample_reported
= FALSE
, sample_delivered
= FALSE
;
713 struct scheduled_item
*item
, *item2
;
716 EnterCriticalSection(&grabber
->cs
);
718 LIST_FOR_EACH_ENTRY_SAFE(item
, item2
, &grabber
->items
, struct scheduled_item
, entry
)
720 if (item
->type
== ITEM_TYPE_MARKER
)
722 sample_grabber_stream_report_marker(grabber
, &item
->u
.marker
.context
, S_OK
);
723 stream_release_pending_item(item
);
725 else if (item
->type
== ITEM_TYPE_SAMPLE
)
727 if (!sample_reported
)
729 if (FAILED(hr
= sample_grabber_report_sample(grabber
, item
->u
.sample
, &sample_delivered
)))
730 WARN("Failed to report a sample, hr %#x.\n", hr
);
731 stream_release_pending_item(item
);
732 sample_reported
= TRUE
;
736 if (FAILED(hr
= stream_schedule_sample(grabber
, item
)))
737 WARN("Failed to schedule a sample, hr %#x.\n", hr
);
742 if (sample_delivered
)
743 sample_grabber_stream_request_sample(grabber
);
745 LeaveCriticalSection(&grabber
->cs
);
750 static const IMFAsyncCallbackVtbl sample_grabber_stream_timer_callback_vtbl
=
752 sample_grabber_stream_timer_callback_QueryInterface
,
753 sample_grabber_stream_timer_callback_AddRef
,
754 sample_grabber_stream_timer_callback_Release
,
755 sample_grabber_stream_timer_callback_GetParameters
,
756 sample_grabber_stream_timer_callback_Invoke
,
759 static HRESULT WINAPI
sample_grabber_sink_QueryInterface(IMFMediaSink
*iface
, REFIID riid
, void **obj
)
761 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
763 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
765 if (IsEqualIID(riid
, &IID_IMFMediaSink
) ||
766 IsEqualIID(riid
, &IID_IUnknown
))
768 *obj
= &grabber
->IMFMediaSink_iface
;
770 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
772 *obj
= &grabber
->IMFClockStateSink_iface
;
774 else if (IsEqualIID(riid
, &IID_IMFMediaEventGenerator
))
776 *obj
= &grabber
->IMFMediaEventGenerator_iface
;
780 WARN("Unsupported %s.\n", debugstr_guid(riid
));
782 return E_NOINTERFACE
;
785 IUnknown_AddRef((IUnknown
*)*obj
);
790 static ULONG WINAPI
sample_grabber_sink_AddRef(IMFMediaSink
*iface
)
792 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
793 ULONG refcount
= InterlockedIncrement(&grabber
->refcount
);
795 TRACE("%p, refcount %u.\n", iface
, refcount
);
800 static void sample_grabber_release_pending_items(struct sample_grabber
*grabber
)
802 struct scheduled_item
*item
, *next_item
;
804 LIST_FOR_EACH_ENTRY_SAFE(item
, next_item
, &grabber
->items
, struct scheduled_item
, entry
)
806 stream_release_pending_item(item
);
810 static ULONG WINAPI
sample_grabber_sink_Release(IMFMediaSink
*iface
)
812 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
813 ULONG refcount
= InterlockedDecrement(&grabber
->refcount
);
815 TRACE("%p, refcount %u.\n", iface
, refcount
);
819 if (grabber
->callback
)
820 IMFSampleGrabberSinkCallback_Release(grabber
->callback
);
821 if (grabber
->callback2
)
822 IMFSampleGrabberSinkCallback2_Release(grabber
->callback2
);
823 IMFMediaType_Release(grabber
->media_type
);
824 if (grabber
->event_queue
)
825 IMFMediaEventQueue_Release(grabber
->event_queue
);
827 IMFPresentationClock_Release(grabber
->clock
);
830 if (grabber
->cancel_key
)
831 IMFTimer_CancelTimer(grabber
->timer
, grabber
->cancel_key
);
832 IMFTimer_Release(grabber
->timer
);
834 if (grabber
->cancel_key
)
835 IUnknown_Release(grabber
->cancel_key
);
836 if (grabber
->stream_event_queue
)
838 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
839 IMFMediaEventQueue_Release(grabber
->stream_event_queue
);
841 if (grabber
->sample_attributes
)
842 IMFAttributes_Release(grabber
->sample_attributes
);
843 sample_grabber_release_pending_items(grabber
);
844 DeleteCriticalSection(&grabber
->cs
);
851 static HRESULT WINAPI
sample_grabber_sink_GetCharacteristics(IMFMediaSink
*iface
, DWORD
*flags
)
853 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
855 TRACE("%p, %p.\n", iface
, flags
);
857 if (grabber
->is_shut_down
)
858 return MF_E_SHUTDOWN
;
860 *flags
= MEDIASINK_FIXED_STREAMS
;
861 if (grabber
->ignore_clock
)
862 *flags
|= MEDIASINK_RATELESS
;
867 static HRESULT WINAPI
sample_grabber_sink_AddStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
,
868 IMFMediaType
*media_type
, IMFStreamSink
**stream_sink
)
870 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
872 TRACE("%p, %#x, %p, %p.\n", iface
, stream_sink_id
, media_type
, stream_sink
);
874 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
877 static HRESULT WINAPI
sample_grabber_sink_RemoveStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
)
879 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
881 TRACE("%p, %#x.\n", iface
, stream_sink_id
);
883 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
886 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkCount(IMFMediaSink
*iface
, DWORD
*count
)
888 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
890 TRACE("%p, %p.\n", iface
, count
);
892 if (grabber
->is_shut_down
)
893 return MF_E_SHUTDOWN
;
900 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink
*iface
, DWORD index
,
901 IMFStreamSink
**stream
)
903 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
906 TRACE("%p, %u, %p.\n", iface
, index
, stream
);
908 if (grabber
->is_shut_down
)
909 return MF_E_SHUTDOWN
;
911 EnterCriticalSection(&grabber
->cs
);
913 if (grabber
->is_shut_down
)
916 hr
= MF_E_INVALIDINDEX
;
919 *stream
= &grabber
->IMFStreamSink_iface
;
920 IMFStreamSink_AddRef(*stream
);
923 LeaveCriticalSection(&grabber
->cs
);
928 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkById(IMFMediaSink
*iface
, DWORD stream_sink_id
,
929 IMFStreamSink
**stream
)
931 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
934 TRACE("%p, %#x, %p.\n", iface
, stream_sink_id
, stream
);
936 EnterCriticalSection(&grabber
->cs
);
938 if (grabber
->is_shut_down
)
940 else if (stream_sink_id
> 0)
941 hr
= MF_E_INVALIDSTREAMNUMBER
;
944 *stream
= &grabber
->IMFStreamSink_iface
;
945 IMFStreamSink_AddRef(*stream
);
948 LeaveCriticalSection(&grabber
->cs
);
953 static void sample_grabber_set_presentation_clock(struct sample_grabber
*grabber
, IMFPresentationClock
*clock
)
957 IMFPresentationClock_RemoveClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
958 IMFPresentationClock_Release(grabber
->clock
);
961 IMFTimer_Release(grabber
->timer
);
962 grabber
->timer
= NULL
;
965 grabber
->clock
= clock
;
968 IMFPresentationClock_AddRef(grabber
->clock
);
969 IMFPresentationClock_AddClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
970 if (FAILED(IMFPresentationClock_QueryInterface(grabber
->clock
, &IID_IMFTimer
, (void **)&grabber
->timer
)))
972 WARN("Failed to get IMFTimer interface.\n");
973 grabber
->timer
= NULL
;
978 static HRESULT WINAPI
sample_grabber_sink_SetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
*clock
)
980 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
983 TRACE("%p, %p.\n", iface
, clock
);
985 EnterCriticalSection(&grabber
->cs
);
987 if (SUCCEEDED(hr
= IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber
),
990 sample_grabber_set_presentation_clock(grabber
, clock
);
993 LeaveCriticalSection(&grabber
->cs
);
998 static HRESULT WINAPI
sample_grabber_sink_GetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
**clock
)
1000 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1003 TRACE("%p, %p.\n", iface
, clock
);
1008 EnterCriticalSection(&grabber
->cs
);
1012 *clock
= grabber
->clock
;
1013 IMFPresentationClock_AddRef(*clock
);
1018 LeaveCriticalSection(&grabber
->cs
);
1023 static HRESULT WINAPI
sample_grabber_sink_Shutdown(IMFMediaSink
*iface
)
1025 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1028 TRACE("%p.\n", iface
);
1030 if (grabber
->is_shut_down
)
1031 return MF_E_SHUTDOWN
;
1033 EnterCriticalSection(&grabber
->cs
);
1034 grabber
->is_shut_down
= TRUE
;
1035 sample_grabber_release_pending_items(grabber
);
1036 if (SUCCEEDED(hr
= IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber
))))
1038 sample_grabber_set_presentation_clock(grabber
, NULL
);
1039 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
1040 IMFMediaEventQueue_Shutdown(grabber
->event_queue
);
1042 LeaveCriticalSection(&grabber
->cs
);
1047 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl
=
1049 sample_grabber_sink_QueryInterface
,
1050 sample_grabber_sink_AddRef
,
1051 sample_grabber_sink_Release
,
1052 sample_grabber_sink_GetCharacteristics
,
1053 sample_grabber_sink_AddStreamSink
,
1054 sample_grabber_sink_RemoveStreamSink
,
1055 sample_grabber_sink_GetStreamSinkCount
,
1056 sample_grabber_sink_GetStreamSinkByIndex
,
1057 sample_grabber_sink_GetStreamSinkById
,
1058 sample_grabber_sink_SetPresentationClock
,
1059 sample_grabber_sink_GetPresentationClock
,
1060 sample_grabber_sink_Shutdown
,
1063 static HRESULT WINAPI
sample_grabber_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
1065 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1066 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1069 static ULONG WINAPI
sample_grabber_clock_sink_AddRef(IMFClockStateSink
*iface
)
1071 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1072 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1075 static ULONG WINAPI
sample_grabber_clock_sink_Release(IMFClockStateSink
*iface
)
1077 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1078 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1081 static void sample_grabber_set_state(struct sample_grabber
*grabber
, enum sink_state state
)
1083 static const DWORD events
[] =
1085 MEStreamSinkStopped
, /* SINK_STATE_STOPPED */
1086 MEStreamSinkStarted
, /* SINK_STATE_RUNNING */
1088 BOOL set_state
= FALSE
;
1091 EnterCriticalSection(&grabber
->cs
);
1093 if (!grabber
->is_shut_down
)
1095 switch (grabber
->state
)
1097 case SINK_STATE_STOPPED
:
1098 set_state
= state
== SINK_STATE_RUNNING
;
1100 case SINK_STATE_RUNNING
:
1101 set_state
= state
== SINK_STATE_STOPPED
;
1109 grabber
->state
= state
;
1110 if (state
== SINK_STATE_RUNNING
)
1112 /* Every transition to running state sends a bunch requests to build up initial queue. */
1113 for (i
= 0; i
< 4; ++i
)
1114 sample_grabber_stream_request_sample(grabber
);
1116 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, events
[state
], &GUID_NULL
, S_OK
, NULL
);
1120 LeaveCriticalSection(&grabber
->cs
);
1123 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
1125 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1127 TRACE("%p, %s, %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
1129 sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
);
1131 return IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber
), systime
, offset
);
1134 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
1136 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1138 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1140 sample_grabber_set_state(grabber
, SINK_STATE_STOPPED
);
1142 return IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber
), systime
);
1145 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
1147 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1149 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1151 return IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber
), systime
);
1154 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
1156 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1158 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1160 sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
);
1162 return IMFSampleGrabberSinkCallback_OnClockRestart(sample_grabber_get_callback(grabber
), systime
);
1165 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
1167 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1169 TRACE("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
1171 return IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber
), systime
, rate
);
1174 static HRESULT WINAPI
sample_grabber_events_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
1176 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1177 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1180 static ULONG WINAPI
sample_grabber_events_AddRef(IMFMediaEventGenerator
*iface
)
1182 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1183 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1186 static ULONG WINAPI
sample_grabber_events_Release(IMFMediaEventGenerator
*iface
)
1188 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1189 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1192 static HRESULT WINAPI
sample_grabber_events_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1194 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1196 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1198 return IMFMediaEventQueue_GetEvent(grabber
->event_queue
, flags
, event
);
1201 static HRESULT WINAPI
sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
1204 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1206 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1208 return IMFMediaEventQueue_BeginGetEvent(grabber
->event_queue
, callback
, state
);
1211 static HRESULT WINAPI
sample_grabber_events_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
1212 IMFMediaEvent
**event
)
1214 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1216 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1218 return IMFMediaEventQueue_EndGetEvent(grabber
->event_queue
, result
, event
);
1221 static HRESULT WINAPI
sample_grabber_events_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
1222 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
1224 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1226 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1228 return IMFMediaEventQueue_QueueEventParamVar(grabber
->event_queue
, event_type
, ext_type
, hr
, value
);
1231 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl
=
1233 sample_grabber_events_QueryInterface
,
1234 sample_grabber_events_AddRef
,
1235 sample_grabber_events_Release
,
1236 sample_grabber_events_GetEvent
,
1237 sample_grabber_events_BeginGetEvent
,
1238 sample_grabber_events_EndGetEvent
,
1239 sample_grabber_events_QueueEvent
,
1242 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl
=
1244 sample_grabber_clock_sink_QueryInterface
,
1245 sample_grabber_clock_sink_AddRef
,
1246 sample_grabber_clock_sink_Release
,
1247 sample_grabber_clock_sink_OnClockStart
,
1248 sample_grabber_clock_sink_OnClockStop
,
1249 sample_grabber_clock_sink_OnClockPause
,
1250 sample_grabber_clock_sink_OnClockRestart
,
1251 sample_grabber_clock_sink_OnClockSetRate
,
1254 static HRESULT
sample_grabber_create_object(IMFAttributes
*attributes
, void *user_context
, IUnknown
**obj
)
1256 struct sample_grabber_activate_context
*context
= user_context
;
1257 struct sample_grabber
*object
;
1261 TRACE("%p, %p, %p.\n", attributes
, user_context
, obj
);
1263 if (context
->shut_down
)
1264 return MF_E_SHUTDOWN
;
1266 /* At least major type is required. */
1267 if (FAILED(IMFMediaType_GetMajorType(context
->media_type
, &guid
)))
1268 return MF_E_INVALIDMEDIATYPE
;
1270 object
= heap_alloc_zero(sizeof(*object
));
1272 return E_OUTOFMEMORY
;
1274 object
->IMFMediaSink_iface
.lpVtbl
= &sample_grabber_sink_vtbl
;
1275 object
->IMFClockStateSink_iface
.lpVtbl
= &sample_grabber_clock_sink_vtbl
;
1276 object
->IMFMediaEventGenerator_iface
.lpVtbl
= &sample_grabber_sink_events_vtbl
;
1277 object
->IMFStreamSink_iface
.lpVtbl
= &sample_grabber_stream_vtbl
;
1278 object
->IMFMediaTypeHandler_iface
.lpVtbl
= &sample_grabber_stream_type_handler_vtbl
;
1279 object
->timer_callback
.lpVtbl
= &sample_grabber_stream_timer_callback_vtbl
;
1280 object
->refcount
= 1;
1281 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context
->callback
, &IID_IMFSampleGrabberSinkCallback2
,
1282 (void **)&object
->callback2
)))
1284 object
->callback
= context
->callback
;
1285 IMFSampleGrabberSinkCallback_AddRef(object
->callback
);
1287 object
->media_type
= context
->media_type
;
1288 IMFMediaType_AddRef(object
->media_type
);
1289 IMFAttributes_GetUINT32(attributes
, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK
, &object
->ignore_clock
);
1290 IMFAttributes_GetUINT64(attributes
, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET
, &object
->sample_time_offset
);
1291 list_init(&object
->items
);
1292 InitializeCriticalSection(&object
->cs
);
1294 if (FAILED(hr
= MFCreateEventQueue(&object
->stream_event_queue
)))
1297 if (FAILED(hr
= MFCreateAttributes(&object
->sample_attributes
, 0)))
1300 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1303 *obj
= (IUnknown
*)&object
->IMFMediaSink_iface
;
1305 TRACE("Created %p.\n", *obj
);
1311 IMFMediaSink_Release(&object
->IMFMediaSink_iface
);
1316 static void sample_grabber_shutdown_object(void *user_context
, IUnknown
*obj
)
1318 struct sample_grabber_activate_context
*context
= user_context
;
1319 context
->shut_down
= TRUE
;
1322 static const struct activate_funcs sample_grabber_activate_funcs
=
1324 sample_grabber_create_object
,
1325 sample_grabber_shutdown_object
,
1326 sample_grabber_free_private
,
1329 /***********************************************************************
1330 * MFCreateSampleGrabberSinkActivate (mf.@)
1332 HRESULT WINAPI
MFCreateSampleGrabberSinkActivate(IMFMediaType
*media_type
, IMFSampleGrabberSinkCallback
*callback
,
1333 IMFActivate
**activate
)
1335 struct sample_grabber_activate_context
*context
;
1338 TRACE("%p, %p, %p.\n", media_type
, callback
, activate
);
1340 if (!media_type
|| !callback
|| !activate
)
1343 context
= heap_alloc_zero(sizeof(*context
));
1345 return E_OUTOFMEMORY
;
1347 context
->media_type
= media_type
;
1348 IMFMediaType_AddRef(context
->media_type
);
1349 context
->callback
= callback
;
1350 IMFSampleGrabberSinkCallback_AddRef(context
->callback
);
1352 if (FAILED(hr
= create_activation_object(context
, &sample_grabber_activate_funcs
, activate
)))
1353 sample_grabber_free_private(context
);