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 IMFGetService IMFGetService_iface
;
67 IMFRateSupport IMFRateSupport_iface
;
68 IMFStreamSink IMFStreamSink_iface
;
69 IMFMediaTypeHandler IMFMediaTypeHandler_iface
;
70 IMFAsyncCallback timer_callback
;
72 IMFSampleGrabberSinkCallback
*callback
;
73 IMFSampleGrabberSinkCallback2
*callback2
;
74 IMFMediaType
*media_type
;
75 IMFMediaType
*current_media_type
;
77 IMFMediaEventQueue
*event_queue
;
78 IMFMediaEventQueue
*stream_event_queue
;
79 IMFPresentationClock
*clock
;
81 IMFAttributes
*sample_attributes
;
85 UINT64 sample_time_offset
;
86 enum sink_state state
;
90 static IMFSampleGrabberSinkCallback
*sample_grabber_get_callback(const struct sample_grabber
*sink
)
92 return sink
->callback2
? (IMFSampleGrabberSinkCallback
*)sink
->callback2
: sink
->callback
;
95 struct sample_grabber_activate_context
97 IMFMediaType
*media_type
;
98 IMFSampleGrabberSinkCallback
*callback
;
102 static void sample_grabber_free_private(void *user_context
)
104 struct sample_grabber_activate_context
*context
= user_context
;
105 IMFMediaType_Release(context
->media_type
);
106 IMFSampleGrabberSinkCallback_Release(context
->callback
);
110 static struct sample_grabber
*impl_from_IMFMediaSink(IMFMediaSink
*iface
)
112 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaSink_iface
);
115 static struct sample_grabber
*impl_from_IMFClockStateSink(IMFClockStateSink
*iface
)
117 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFClockStateSink_iface
);
120 static struct sample_grabber
*impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator
*iface
)
122 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaEventGenerator_iface
);
125 static struct sample_grabber
*impl_from_IMFGetService(IMFGetService
*iface
)
127 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFGetService_iface
);
130 static struct sample_grabber
*impl_from_IMFRateSupport(IMFRateSupport
*iface
)
132 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFRateSupport_iface
);
135 static struct sample_grabber
*impl_from_IMFStreamSink(IMFStreamSink
*iface
)
137 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFStreamSink_iface
);
140 static struct sample_grabber
*impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler
*iface
)
142 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaTypeHandler_iface
);
145 static struct sample_grabber
*impl_from_IMFAsyncCallback(IMFAsyncCallback
*iface
)
147 return CONTAINING_RECORD(iface
, struct sample_grabber
, timer_callback
);
150 static HRESULT WINAPI
sample_grabber_stream_QueryInterface(IMFStreamSink
*iface
, REFIID riid
, void **obj
)
152 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
154 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
156 if (IsEqualIID(riid
, &IID_IMFStreamSink
) ||
157 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
158 IsEqualIID(riid
, &IID_IUnknown
))
160 *obj
= &grabber
->IMFStreamSink_iface
;
162 else if (IsEqualIID(riid
, &IID_IMFMediaTypeHandler
))
164 *obj
= &grabber
->IMFMediaTypeHandler_iface
;
168 WARN("Unsupported %s.\n", debugstr_guid(riid
));
170 return E_NOINTERFACE
;
173 IUnknown_AddRef((IUnknown
*)*obj
);
178 static ULONG WINAPI
sample_grabber_stream_AddRef(IMFStreamSink
*iface
)
180 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
181 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
184 static void stream_release_pending_item(struct scheduled_item
*item
)
186 list_remove(&item
->entry
);
189 case ITEM_TYPE_SAMPLE
:
190 IMFSample_Release(item
->u
.sample
);
192 case ITEM_TYPE_MARKER
:
193 PropVariantClear(&item
->u
.marker
.context
);
199 static ULONG WINAPI
sample_grabber_stream_Release(IMFStreamSink
*iface
)
201 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
202 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
205 static HRESULT WINAPI
sample_grabber_stream_GetEvent(IMFStreamSink
*iface
, DWORD flags
, IMFMediaEvent
**event
)
207 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
209 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
211 if (grabber
->is_shut_down
)
212 return MF_E_STREAMSINK_REMOVED
;
214 return IMFMediaEventQueue_GetEvent(grabber
->stream_event_queue
, flags
, event
);
217 static HRESULT WINAPI
sample_grabber_stream_BeginGetEvent(IMFStreamSink
*iface
, IMFAsyncCallback
*callback
,
220 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
222 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
224 if (grabber
->is_shut_down
)
225 return MF_E_STREAMSINK_REMOVED
;
227 return IMFMediaEventQueue_BeginGetEvent(grabber
->stream_event_queue
, callback
, state
);
230 static HRESULT WINAPI
sample_grabber_stream_EndGetEvent(IMFStreamSink
*iface
, IMFAsyncResult
*result
,
231 IMFMediaEvent
**event
)
233 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
235 TRACE("%p, %p, %p.\n", iface
, result
, event
);
237 if (grabber
->is_shut_down
)
238 return MF_E_STREAMSINK_REMOVED
;
240 return IMFMediaEventQueue_EndGetEvent(grabber
->stream_event_queue
, result
, event
);
243 static HRESULT WINAPI
sample_grabber_stream_QueueEvent(IMFStreamSink
*iface
, MediaEventType event_type
,
244 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
246 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
248 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
250 if (grabber
->is_shut_down
)
251 return MF_E_STREAMSINK_REMOVED
;
253 return IMFMediaEventQueue_QueueEventParamVar(grabber
->stream_event_queue
, event_type
, ext_type
, hr
, value
);
256 static HRESULT WINAPI
sample_grabber_stream_GetMediaSink(IMFStreamSink
*iface
, IMFMediaSink
**sink
)
258 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
260 TRACE("%p, %p.\n", iface
, sink
);
262 if (grabber
->is_shut_down
)
263 return MF_E_STREAMSINK_REMOVED
;
265 *sink
= &grabber
->IMFMediaSink_iface
;
266 IMFMediaSink_AddRef(*sink
);
271 static HRESULT WINAPI
sample_grabber_stream_GetIdentifier(IMFStreamSink
*iface
, DWORD
*identifier
)
273 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
275 TRACE("%p, %p.\n", iface
, identifier
);
277 if (grabber
->is_shut_down
)
278 return MF_E_STREAMSINK_REMOVED
;
285 static HRESULT WINAPI
sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink
*iface
, IMFMediaTypeHandler
**handler
)
287 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
289 TRACE("%p, %p.\n", iface
, handler
);
294 if (grabber
->is_shut_down
)
295 return MF_E_STREAMSINK_REMOVED
;
297 *handler
= &grabber
->IMFMediaTypeHandler_iface
;
298 IMFMediaTypeHandler_AddRef(*handler
);
303 static HRESULT
sample_grabber_report_sample(struct sample_grabber
*grabber
, IMFSample
*sample
, BOOL
*sample_delivered
)
305 LONGLONG sample_time
, sample_duration
= 0;
306 IMFMediaBuffer
*buffer
;
312 *sample_delivered
= FALSE
;
314 hr
= IMFMediaType_GetMajorType(grabber
->media_type
, &major_type
);
317 hr
= IMFSample_GetSampleTime(sample
, &sample_time
);
319 if (FAILED(IMFSample_GetSampleDuration(sample
, &sample_duration
)))
323 hr
= IMFSample_GetSampleFlags(sample
, &flags
);
327 if (FAILED(IMFSample_ConvertToContiguousBuffer(sample
, &buffer
)))
330 if (SUCCEEDED(hr
= IMFMediaBuffer_Lock(buffer
, &data
, NULL
, &size
)))
332 *sample_delivered
= TRUE
;
334 if (grabber
->callback2
)
336 hr
= IMFSample_CopyAllItems(sample
, grabber
->sample_attributes
);
338 hr
= IMFSampleGrabberSinkCallback2_OnProcessSampleEx(grabber
->callback2
, &major_type
, flags
,
339 sample_time
, sample_duration
, data
, size
, grabber
->sample_attributes
);
342 hr
= IMFSampleGrabberSinkCallback_OnProcessSample(grabber
->callback
, &major_type
, flags
, sample_time
,
343 sample_duration
, data
, size
);
344 IMFMediaBuffer_Unlock(buffer
);
347 IMFMediaBuffer_Release(buffer
);
353 static HRESULT
stream_schedule_sample(struct sample_grabber
*grabber
, struct scheduled_item
*item
)
358 if (grabber
->is_shut_down
)
359 return MF_E_STREAMSINK_REMOVED
;
361 if (FAILED(hr
= IMFSample_GetSampleTime(item
->u
.sample
, &sampletime
)))
364 if (grabber
->cancel_key
)
366 IUnknown_Release(grabber
->cancel_key
);
367 grabber
->cancel_key
= NULL
;
370 if (FAILED(hr
= IMFTimer_SetTimer(grabber
->timer
, 0, sampletime
- grabber
->sample_time_offset
,
371 &grabber
->timer_callback
, NULL
, &grabber
->cancel_key
)))
373 grabber
->cancel_key
= NULL
;
379 static HRESULT
stream_queue_sample(struct sample_grabber
*grabber
, IMFSample
*sample
)
381 struct scheduled_item
*item
;
385 if (FAILED(hr
= IMFSample_GetSampleTime(sample
, &sampletime
)))
388 if (!(item
= heap_alloc_zero(sizeof(*item
))))
389 return E_OUTOFMEMORY
;
391 item
->type
= ITEM_TYPE_SAMPLE
;
392 item
->u
.sample
= sample
;
393 IMFSample_AddRef(item
->u
.sample
);
394 list_init(&item
->entry
);
395 if (list_empty(&grabber
->items
))
396 hr
= stream_schedule_sample(grabber
, item
);
399 list_add_tail(&grabber
->items
, &item
->entry
);
401 stream_release_pending_item(item
);
406 static void sample_grabber_stream_request_sample(struct sample_grabber
*grabber
)
408 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
411 static HRESULT WINAPI
sample_grabber_stream_ProcessSample(IMFStreamSink
*iface
, IMFSample
*sample
)
413 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
414 BOOL sample_delivered
;
418 TRACE("%p, %p.\n", iface
, sample
);
423 EnterCriticalSection(&grabber
->cs
);
425 if (grabber
->is_shut_down
)
426 hr
= MF_E_STREAMSINK_REMOVED
;
427 else if (grabber
->state
== SINK_STATE_RUNNING
)
429 hr
= IMFSample_GetSampleTime(sample
, &sampletime
);
433 if (grabber
->ignore_clock
)
435 /* OnProcessSample() could return error code, which has to be propagated but isn't a blocker.
436 Use additional flag indicating that user callback was called at all. */
437 hr
= sample_grabber_report_sample(grabber
, sample
, &sample_delivered
);
438 if (sample_delivered
)
439 sample_grabber_stream_request_sample(grabber
);
442 hr
= stream_queue_sample(grabber
, sample
);
446 LeaveCriticalSection(&grabber
->cs
);
451 static void sample_grabber_stream_report_marker(struct sample_grabber
*grabber
, const PROPVARIANT
*context
,
454 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkMarker
, &GUID_NULL
, hr
, context
);
457 static HRESULT
stream_place_marker(struct sample_grabber
*grabber
, MFSTREAMSINK_MARKER_TYPE marker_type
,
458 const PROPVARIANT
*context_value
)
460 struct scheduled_item
*item
;
463 if (list_empty(&grabber
->items
))
465 sample_grabber_stream_report_marker(grabber
, context_value
, S_OK
);
469 if (!(item
= heap_alloc_zero(sizeof(*item
))))
470 return E_OUTOFMEMORY
;
472 item
->type
= ITEM_TYPE_MARKER
;
473 item
->u
.marker
.type
= marker_type
;
474 list_init(&item
->entry
);
475 PropVariantInit(&item
->u
.marker
.context
);
477 hr
= PropVariantCopy(&item
->u
.marker
.context
, context_value
);
479 list_add_tail(&grabber
->items
, &item
->entry
);
481 stream_release_pending_item(item
);
486 static HRESULT WINAPI
sample_grabber_stream_PlaceMarker(IMFStreamSink
*iface
, MFSTREAMSINK_MARKER_TYPE marker_type
,
487 const PROPVARIANT
*marker_value
, const PROPVARIANT
*context_value
)
489 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
492 TRACE("%p, %d, %p, %p.\n", iface
, marker_type
, marker_value
, context_value
);
494 EnterCriticalSection(&grabber
->cs
);
496 if (grabber
->is_shut_down
)
497 hr
= MF_E_STREAMSINK_REMOVED
;
498 else if (grabber
->state
== SINK_STATE_RUNNING
)
499 hr
= stream_place_marker(grabber
, marker_type
, context_value
);
501 LeaveCriticalSection(&grabber
->cs
);
506 static HRESULT WINAPI
sample_grabber_stream_Flush(IMFStreamSink
*iface
)
508 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
509 struct scheduled_item
*item
, *next_item
;
511 TRACE("%p.\n", iface
);
513 if (grabber
->is_shut_down
)
514 return MF_E_STREAMSINK_REMOVED
;
516 EnterCriticalSection(&grabber
->cs
);
518 LIST_FOR_EACH_ENTRY_SAFE(item
, next_item
, &grabber
->items
, struct scheduled_item
, entry
)
520 /* Samples are discarded, markers are processed immediately. */
523 case ITEM_TYPE_SAMPLE
:
525 case ITEM_TYPE_MARKER
:
526 sample_grabber_stream_report_marker(grabber
, &item
->u
.marker
.context
, E_ABORT
);
530 stream_release_pending_item(item
);
533 LeaveCriticalSection(&grabber
->cs
);
538 static const IMFStreamSinkVtbl sample_grabber_stream_vtbl
=
540 sample_grabber_stream_QueryInterface
,
541 sample_grabber_stream_AddRef
,
542 sample_grabber_stream_Release
,
543 sample_grabber_stream_GetEvent
,
544 sample_grabber_stream_BeginGetEvent
,
545 sample_grabber_stream_EndGetEvent
,
546 sample_grabber_stream_QueueEvent
,
547 sample_grabber_stream_GetMediaSink
,
548 sample_grabber_stream_GetIdentifier
,
549 sample_grabber_stream_GetMediaTypeHandler
,
550 sample_grabber_stream_ProcessSample
,
551 sample_grabber_stream_PlaceMarker
,
552 sample_grabber_stream_Flush
,
555 static HRESULT WINAPI
sample_grabber_stream_type_handler_QueryInterface(IMFMediaTypeHandler
*iface
, REFIID riid
,
558 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
559 return IMFStreamSink_QueryInterface(&grabber
->IMFStreamSink_iface
, riid
, obj
);
562 static ULONG WINAPI
sample_grabber_stream_type_handler_AddRef(IMFMediaTypeHandler
*iface
)
564 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
565 return IMFStreamSink_AddRef(&grabber
->IMFStreamSink_iface
);
568 static ULONG WINAPI
sample_grabber_stream_type_handler_Release(IMFMediaTypeHandler
*iface
)
570 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
571 return IMFStreamSink_Release(&grabber
->IMFStreamSink_iface
);
574 static HRESULT
sample_grabber_stream_is_media_type_supported(struct sample_grabber
*grabber
, IMFMediaType
*in_type
)
576 const DWORD supported_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_TYPES
|
577 MF_MEDIATYPE_EQUAL_FORMAT_DATA
;
580 if (grabber
->is_shut_down
)
581 return MF_E_STREAMSINK_REMOVED
;
586 if (IMFMediaType_IsEqual(grabber
->media_type
, in_type
, &flags
) == S_OK
)
589 return (flags
& supported_flags
) == supported_flags
? S_OK
: MF_E_INVALIDMEDIATYPE
;
592 static HRESULT WINAPI
sample_grabber_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler
*iface
,
593 IMFMediaType
*in_type
, IMFMediaType
**out_type
)
595 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
597 TRACE("%p, %p, %p.\n", iface
, in_type
, out_type
);
599 return sample_grabber_stream_is_media_type_supported(grabber
, in_type
);
602 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler
*iface
, DWORD
*count
)
604 TRACE("%p, %p.\n", iface
, count
);
614 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
*iface
, DWORD index
,
615 IMFMediaType
**media_type
)
617 TRACE("%p, %u, %p.\n", iface
, index
, media_type
);
622 return MF_E_NO_MORE_TYPES
;
625 static HRESULT WINAPI
sample_grabber_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler
*iface
,
626 IMFMediaType
*media_type
)
628 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
631 TRACE("%p, %p.\n", iface
, media_type
);
633 if (FAILED(hr
= sample_grabber_stream_is_media_type_supported(grabber
, media_type
)))
636 IMFMediaType_Release(grabber
->current_media_type
);
637 grabber
->current_media_type
= media_type
;
638 IMFMediaType_AddRef(grabber
->current_media_type
);
643 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler
*iface
,
644 IMFMediaType
**media_type
)
646 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
648 TRACE("%p, %p.\n", iface
, media_type
);
653 if (grabber
->is_shut_down
)
654 return MF_E_STREAMSINK_REMOVED
;
656 *media_type
= grabber
->current_media_type
;
657 IMFMediaType_AddRef(*media_type
);
662 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
664 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
666 TRACE("%p, %p.\n", iface
, type
);
671 if (grabber
->is_shut_down
)
672 return MF_E_STREAMSINK_REMOVED
;
674 return IMFMediaType_GetMajorType(grabber
->current_media_type
, type
);
677 static const IMFMediaTypeHandlerVtbl sample_grabber_stream_type_handler_vtbl
=
679 sample_grabber_stream_type_handler_QueryInterface
,
680 sample_grabber_stream_type_handler_AddRef
,
681 sample_grabber_stream_type_handler_Release
,
682 sample_grabber_stream_type_handler_IsMediaTypeSupported
,
683 sample_grabber_stream_type_handler_GetMediaTypeCount
,
684 sample_grabber_stream_type_handler_GetMediaTypeByIndex
,
685 sample_grabber_stream_type_handler_SetCurrentMediaType
,
686 sample_grabber_stream_type_handler_GetCurrentMediaType
,
687 sample_grabber_stream_type_handler_GetMajorType
,
690 static HRESULT WINAPI
sample_grabber_stream_timer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
,
693 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) || IsEqualIID(riid
, &IID_IUnknown
))
696 IMFAsyncCallback_AddRef(iface
);
700 WARN("Unsupported %s.\n", debugstr_guid(riid
));
702 return E_NOINTERFACE
;
705 static ULONG WINAPI
sample_grabber_stream_timer_callback_AddRef(IMFAsyncCallback
*iface
)
707 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
708 return IMFStreamSink_AddRef(&grabber
->IMFStreamSink_iface
);
711 static ULONG WINAPI
sample_grabber_stream_timer_callback_Release(IMFAsyncCallback
*iface
)
713 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
714 return IMFStreamSink_Release(&grabber
->IMFStreamSink_iface
);
717 static HRESULT WINAPI
sample_grabber_stream_timer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
,
723 static HRESULT WINAPI
sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
725 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
726 BOOL sample_reported
= FALSE
, sample_delivered
= FALSE
;
727 struct scheduled_item
*item
, *item2
;
730 EnterCriticalSection(&grabber
->cs
);
732 LIST_FOR_EACH_ENTRY_SAFE(item
, item2
, &grabber
->items
, struct scheduled_item
, entry
)
734 if (item
->type
== ITEM_TYPE_MARKER
)
736 sample_grabber_stream_report_marker(grabber
, &item
->u
.marker
.context
, S_OK
);
737 stream_release_pending_item(item
);
739 else if (item
->type
== ITEM_TYPE_SAMPLE
)
741 if (!sample_reported
)
743 if (FAILED(hr
= sample_grabber_report_sample(grabber
, item
->u
.sample
, &sample_delivered
)))
744 WARN("Failed to report a sample, hr %#x.\n", hr
);
745 stream_release_pending_item(item
);
746 sample_reported
= TRUE
;
750 if (FAILED(hr
= stream_schedule_sample(grabber
, item
)))
751 WARN("Failed to schedule a sample, hr %#x.\n", hr
);
756 if (sample_delivered
)
757 sample_grabber_stream_request_sample(grabber
);
759 LeaveCriticalSection(&grabber
->cs
);
764 static const IMFAsyncCallbackVtbl sample_grabber_stream_timer_callback_vtbl
=
766 sample_grabber_stream_timer_callback_QueryInterface
,
767 sample_grabber_stream_timer_callback_AddRef
,
768 sample_grabber_stream_timer_callback_Release
,
769 sample_grabber_stream_timer_callback_GetParameters
,
770 sample_grabber_stream_timer_callback_Invoke
,
773 static HRESULT WINAPI
sample_grabber_sink_QueryInterface(IMFMediaSink
*iface
, REFIID riid
, void **obj
)
775 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
777 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
779 if (IsEqualIID(riid
, &IID_IMFMediaSink
) ||
780 IsEqualIID(riid
, &IID_IUnknown
))
782 *obj
= &grabber
->IMFMediaSink_iface
;
784 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
786 *obj
= &grabber
->IMFClockStateSink_iface
;
788 else if (IsEqualIID(riid
, &IID_IMFMediaEventGenerator
))
790 *obj
= &grabber
->IMFMediaEventGenerator_iface
;
792 else if (IsEqualIID(riid
, &IID_IMFGetService
))
794 *obj
= &grabber
->IMFGetService_iface
;
796 else if (IsEqualIID(riid
, &IID_IMFRateSupport
))
798 *obj
= &grabber
->IMFRateSupport_iface
;
802 WARN("Unsupported %s.\n", debugstr_guid(riid
));
804 return E_NOINTERFACE
;
807 IUnknown_AddRef((IUnknown
*)*obj
);
812 static ULONG WINAPI
sample_grabber_sink_AddRef(IMFMediaSink
*iface
)
814 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
815 ULONG refcount
= InterlockedIncrement(&grabber
->refcount
);
817 TRACE("%p, refcount %u.\n", iface
, refcount
);
822 static void sample_grabber_release_pending_items(struct sample_grabber
*grabber
)
824 struct scheduled_item
*item
, *next_item
;
826 LIST_FOR_EACH_ENTRY_SAFE(item
, next_item
, &grabber
->items
, struct scheduled_item
, entry
)
828 stream_release_pending_item(item
);
832 static ULONG WINAPI
sample_grabber_sink_Release(IMFMediaSink
*iface
)
834 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
835 ULONG refcount
= InterlockedDecrement(&grabber
->refcount
);
837 TRACE("%p, refcount %u.\n", iface
, refcount
);
841 if (grabber
->callback
)
842 IMFSampleGrabberSinkCallback_Release(grabber
->callback
);
843 if (grabber
->callback2
)
844 IMFSampleGrabberSinkCallback2_Release(grabber
->callback2
);
845 IMFMediaType_Release(grabber
->current_media_type
);
846 IMFMediaType_Release(grabber
->media_type
);
847 if (grabber
->event_queue
)
848 IMFMediaEventQueue_Release(grabber
->event_queue
);
850 IMFPresentationClock_Release(grabber
->clock
);
853 if (grabber
->cancel_key
)
854 IMFTimer_CancelTimer(grabber
->timer
, grabber
->cancel_key
);
855 IMFTimer_Release(grabber
->timer
);
857 if (grabber
->cancel_key
)
858 IUnknown_Release(grabber
->cancel_key
);
859 if (grabber
->stream_event_queue
)
861 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
862 IMFMediaEventQueue_Release(grabber
->stream_event_queue
);
864 if (grabber
->sample_attributes
)
865 IMFAttributes_Release(grabber
->sample_attributes
);
866 sample_grabber_release_pending_items(grabber
);
867 DeleteCriticalSection(&grabber
->cs
);
874 static HRESULT WINAPI
sample_grabber_sink_GetCharacteristics(IMFMediaSink
*iface
, DWORD
*flags
)
876 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
878 TRACE("%p, %p.\n", iface
, flags
);
880 if (grabber
->is_shut_down
)
881 return MF_E_SHUTDOWN
;
883 *flags
= MEDIASINK_FIXED_STREAMS
;
884 if (grabber
->ignore_clock
)
885 *flags
|= MEDIASINK_RATELESS
;
890 static HRESULT WINAPI
sample_grabber_sink_AddStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
,
891 IMFMediaType
*media_type
, IMFStreamSink
**stream_sink
)
893 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
895 TRACE("%p, %#x, %p, %p.\n", iface
, stream_sink_id
, media_type
, stream_sink
);
897 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
900 static HRESULT WINAPI
sample_grabber_sink_RemoveStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
)
902 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
904 TRACE("%p, %#x.\n", iface
, stream_sink_id
);
906 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
909 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkCount(IMFMediaSink
*iface
, DWORD
*count
)
911 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
913 TRACE("%p, %p.\n", iface
, count
);
915 if (grabber
->is_shut_down
)
916 return MF_E_SHUTDOWN
;
923 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink
*iface
, DWORD index
,
924 IMFStreamSink
**stream
)
926 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
929 TRACE("%p, %u, %p.\n", iface
, index
, stream
);
931 if (grabber
->is_shut_down
)
932 return MF_E_SHUTDOWN
;
934 EnterCriticalSection(&grabber
->cs
);
936 if (grabber
->is_shut_down
)
939 hr
= MF_E_INVALIDINDEX
;
942 *stream
= &grabber
->IMFStreamSink_iface
;
943 IMFStreamSink_AddRef(*stream
);
946 LeaveCriticalSection(&grabber
->cs
);
951 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkById(IMFMediaSink
*iface
, DWORD stream_sink_id
,
952 IMFStreamSink
**stream
)
954 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
957 TRACE("%p, %#x, %p.\n", iface
, stream_sink_id
, stream
);
959 EnterCriticalSection(&grabber
->cs
);
961 if (grabber
->is_shut_down
)
963 else if (stream_sink_id
> 0)
964 hr
= MF_E_INVALIDSTREAMNUMBER
;
967 *stream
= &grabber
->IMFStreamSink_iface
;
968 IMFStreamSink_AddRef(*stream
);
971 LeaveCriticalSection(&grabber
->cs
);
976 static void sample_grabber_set_presentation_clock(struct sample_grabber
*grabber
, IMFPresentationClock
*clock
)
980 IMFPresentationClock_RemoveClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
981 IMFPresentationClock_Release(grabber
->clock
);
984 IMFTimer_Release(grabber
->timer
);
985 grabber
->timer
= NULL
;
988 grabber
->clock
= clock
;
991 IMFPresentationClock_AddRef(grabber
->clock
);
992 IMFPresentationClock_AddClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
993 if (FAILED(IMFPresentationClock_QueryInterface(grabber
->clock
, &IID_IMFTimer
, (void **)&grabber
->timer
)))
995 WARN("Failed to get IMFTimer interface.\n");
996 grabber
->timer
= NULL
;
1001 static HRESULT WINAPI
sample_grabber_sink_SetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
*clock
)
1003 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1006 TRACE("%p, %p.\n", iface
, clock
);
1008 EnterCriticalSection(&grabber
->cs
);
1010 if (SUCCEEDED(hr
= IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber
),
1013 sample_grabber_set_presentation_clock(grabber
, clock
);
1016 LeaveCriticalSection(&grabber
->cs
);
1021 static HRESULT WINAPI
sample_grabber_sink_GetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
**clock
)
1023 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1026 TRACE("%p, %p.\n", iface
, clock
);
1031 EnterCriticalSection(&grabber
->cs
);
1035 *clock
= grabber
->clock
;
1036 IMFPresentationClock_AddRef(*clock
);
1041 LeaveCriticalSection(&grabber
->cs
);
1046 static HRESULT WINAPI
sample_grabber_sink_Shutdown(IMFMediaSink
*iface
)
1048 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1051 TRACE("%p.\n", iface
);
1053 if (grabber
->is_shut_down
)
1054 return MF_E_SHUTDOWN
;
1056 EnterCriticalSection(&grabber
->cs
);
1057 grabber
->is_shut_down
= TRUE
;
1058 sample_grabber_release_pending_items(grabber
);
1059 if (SUCCEEDED(hr
= IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber
))))
1061 sample_grabber_set_presentation_clock(grabber
, NULL
);
1062 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
1063 IMFMediaEventQueue_Shutdown(grabber
->event_queue
);
1065 LeaveCriticalSection(&grabber
->cs
);
1070 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl
=
1072 sample_grabber_sink_QueryInterface
,
1073 sample_grabber_sink_AddRef
,
1074 sample_grabber_sink_Release
,
1075 sample_grabber_sink_GetCharacteristics
,
1076 sample_grabber_sink_AddStreamSink
,
1077 sample_grabber_sink_RemoveStreamSink
,
1078 sample_grabber_sink_GetStreamSinkCount
,
1079 sample_grabber_sink_GetStreamSinkByIndex
,
1080 sample_grabber_sink_GetStreamSinkById
,
1081 sample_grabber_sink_SetPresentationClock
,
1082 sample_grabber_sink_GetPresentationClock
,
1083 sample_grabber_sink_Shutdown
,
1086 static HRESULT WINAPI
sample_grabber_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
1088 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1089 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1092 static ULONG WINAPI
sample_grabber_clock_sink_AddRef(IMFClockStateSink
*iface
)
1094 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1095 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1098 static ULONG WINAPI
sample_grabber_clock_sink_Release(IMFClockStateSink
*iface
)
1100 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1101 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1104 static void sample_grabber_set_state(struct sample_grabber
*grabber
, enum sink_state state
)
1106 static const DWORD events
[] =
1108 MEStreamSinkStopped
, /* SINK_STATE_STOPPED */
1109 MEStreamSinkStarted
, /* SINK_STATE_RUNNING */
1111 BOOL set_state
= FALSE
;
1114 EnterCriticalSection(&grabber
->cs
);
1116 if (!grabber
->is_shut_down
)
1118 switch (grabber
->state
)
1120 case SINK_STATE_STOPPED
:
1121 set_state
= state
== SINK_STATE_RUNNING
;
1123 case SINK_STATE_RUNNING
:
1124 set_state
= state
== SINK_STATE_STOPPED
;
1132 grabber
->state
= state
;
1133 if (state
== SINK_STATE_RUNNING
)
1135 /* Every transition to running state sends a bunch requests to build up initial queue. */
1136 for (i
= 0; i
< 4; ++i
)
1137 sample_grabber_stream_request_sample(grabber
);
1139 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, events
[state
], &GUID_NULL
, S_OK
, NULL
);
1143 LeaveCriticalSection(&grabber
->cs
);
1146 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
1148 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1150 TRACE("%p, %s, %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
1152 sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
);
1154 return IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber
), systime
, offset
);
1157 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
1159 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1161 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1163 sample_grabber_set_state(grabber
, SINK_STATE_STOPPED
);
1165 return IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber
), systime
);
1168 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
1170 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1172 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1174 return IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber
), systime
);
1177 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
1179 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1181 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1183 sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
);
1185 return IMFSampleGrabberSinkCallback_OnClockRestart(sample_grabber_get_callback(grabber
), systime
);
1188 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
1190 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1192 TRACE("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
1194 return IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber
), systime
, rate
);
1197 static HRESULT WINAPI
sample_grabber_events_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
1199 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1200 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1203 static ULONG WINAPI
sample_grabber_events_AddRef(IMFMediaEventGenerator
*iface
)
1205 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1206 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1209 static ULONG WINAPI
sample_grabber_events_Release(IMFMediaEventGenerator
*iface
)
1211 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1212 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1215 static HRESULT WINAPI
sample_grabber_events_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1217 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1219 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1221 return IMFMediaEventQueue_GetEvent(grabber
->event_queue
, flags
, event
);
1224 static HRESULT WINAPI
sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
1227 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1229 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1231 return IMFMediaEventQueue_BeginGetEvent(grabber
->event_queue
, callback
, state
);
1234 static HRESULT WINAPI
sample_grabber_events_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
1235 IMFMediaEvent
**event
)
1237 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1239 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1241 return IMFMediaEventQueue_EndGetEvent(grabber
->event_queue
, result
, event
);
1244 static HRESULT WINAPI
sample_grabber_events_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
1245 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
1247 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1249 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1251 return IMFMediaEventQueue_QueueEventParamVar(grabber
->event_queue
, event_type
, ext_type
, hr
, value
);
1254 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl
=
1256 sample_grabber_events_QueryInterface
,
1257 sample_grabber_events_AddRef
,
1258 sample_grabber_events_Release
,
1259 sample_grabber_events_GetEvent
,
1260 sample_grabber_events_BeginGetEvent
,
1261 sample_grabber_events_EndGetEvent
,
1262 sample_grabber_events_QueueEvent
,
1265 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl
=
1267 sample_grabber_clock_sink_QueryInterface
,
1268 sample_grabber_clock_sink_AddRef
,
1269 sample_grabber_clock_sink_Release
,
1270 sample_grabber_clock_sink_OnClockStart
,
1271 sample_grabber_clock_sink_OnClockStop
,
1272 sample_grabber_clock_sink_OnClockPause
,
1273 sample_grabber_clock_sink_OnClockRestart
,
1274 sample_grabber_clock_sink_OnClockSetRate
,
1277 static HRESULT WINAPI
sample_grabber_getservice_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1279 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1280 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1283 static ULONG WINAPI
sample_grabber_getservice_AddRef(IMFGetService
*iface
)
1285 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1286 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1289 static ULONG WINAPI
sample_grabber_getservice_Release(IMFGetService
*iface
)
1291 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1292 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1295 static HRESULT WINAPI
sample_grabber_getservice_GetService(IMFGetService
*iface
, REFGUID service
,
1296 REFIID riid
, void **obj
)
1298 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1300 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1302 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1303 return IMFGetService_QueryInterface(iface
, riid
, obj
);
1305 return E_NOINTERFACE
;
1308 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service
), debugstr_guid(riid
));
1310 return MF_E_UNSUPPORTED_SERVICE
;
1313 static const IMFGetServiceVtbl sample_grabber_getservice_vtbl
=
1315 sample_grabber_getservice_QueryInterface
,
1316 sample_grabber_getservice_AddRef
,
1317 sample_grabber_getservice_Release
,
1318 sample_grabber_getservice_GetService
,
1321 static HRESULT WINAPI
sample_grabber_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
1323 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1324 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1327 static ULONG WINAPI
sample_grabber_rate_support_AddRef(IMFRateSupport
*iface
)
1329 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1330 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1333 static ULONG WINAPI
sample_grabber_rate_support_Release(IMFRateSupport
*iface
)
1335 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1336 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1339 static HRESULT WINAPI
sample_grabber_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1340 BOOL thin
, float *rate
)
1342 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1349 static HRESULT WINAPI
sample_grabber_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1350 BOOL thin
, float *rate
)
1352 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1354 *rate
= direction
== MFRATE_REVERSE
? -FLT_MAX
: FLT_MAX
;
1359 static HRESULT WINAPI
sample_grabber_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
1362 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, ret_rate
);
1370 static const IMFRateSupportVtbl sample_grabber_rate_support_vtbl
=
1372 sample_grabber_rate_support_QueryInterface
,
1373 sample_grabber_rate_support_AddRef
,
1374 sample_grabber_rate_support_Release
,
1375 sample_grabber_rate_support_GetSlowestRate
,
1376 sample_grabber_rate_support_GetFastestRate
,
1377 sample_grabber_rate_support_IsRateSupported
,
1380 static HRESULT
sample_grabber_create_object(IMFAttributes
*attributes
, void *user_context
, IUnknown
**obj
)
1382 struct sample_grabber_activate_context
*context
= user_context
;
1383 struct sample_grabber
*object
;
1387 TRACE("%p, %p, %p.\n", attributes
, user_context
, obj
);
1389 if (context
->shut_down
)
1390 return MF_E_SHUTDOWN
;
1392 /* At least major type is required. */
1393 if (FAILED(IMFMediaType_GetMajorType(context
->media_type
, &guid
)))
1394 return MF_E_INVALIDMEDIATYPE
;
1396 object
= heap_alloc_zero(sizeof(*object
));
1398 return E_OUTOFMEMORY
;
1400 object
->IMFMediaSink_iface
.lpVtbl
= &sample_grabber_sink_vtbl
;
1401 object
->IMFClockStateSink_iface
.lpVtbl
= &sample_grabber_clock_sink_vtbl
;
1402 object
->IMFMediaEventGenerator_iface
.lpVtbl
= &sample_grabber_sink_events_vtbl
;
1403 object
->IMFGetService_iface
.lpVtbl
= &sample_grabber_getservice_vtbl
;
1404 object
->IMFRateSupport_iface
.lpVtbl
= &sample_grabber_rate_support_vtbl
;
1405 object
->IMFStreamSink_iface
.lpVtbl
= &sample_grabber_stream_vtbl
;
1406 object
->IMFMediaTypeHandler_iface
.lpVtbl
= &sample_grabber_stream_type_handler_vtbl
;
1407 object
->timer_callback
.lpVtbl
= &sample_grabber_stream_timer_callback_vtbl
;
1408 object
->refcount
= 1;
1409 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context
->callback
, &IID_IMFSampleGrabberSinkCallback2
,
1410 (void **)&object
->callback2
)))
1412 object
->callback
= context
->callback
;
1413 IMFSampleGrabberSinkCallback_AddRef(object
->callback
);
1415 object
->media_type
= context
->media_type
;
1416 IMFMediaType_AddRef(object
->media_type
);
1417 object
->current_media_type
= context
->media_type
;
1418 IMFMediaType_AddRef(object
->current_media_type
);
1419 IMFAttributes_GetUINT32(attributes
, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK
, &object
->ignore_clock
);
1420 IMFAttributes_GetUINT64(attributes
, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET
, &object
->sample_time_offset
);
1421 list_init(&object
->items
);
1422 InitializeCriticalSection(&object
->cs
);
1424 if (FAILED(hr
= MFCreateEventQueue(&object
->stream_event_queue
)))
1427 if (FAILED(hr
= MFCreateAttributes(&object
->sample_attributes
, 0)))
1430 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1433 *obj
= (IUnknown
*)&object
->IMFMediaSink_iface
;
1435 TRACE("Created %p.\n", *obj
);
1441 IMFMediaSink_Release(&object
->IMFMediaSink_iface
);
1446 static void sample_grabber_shutdown_object(void *user_context
, IUnknown
*obj
)
1448 struct sample_grabber_activate_context
*context
= user_context
;
1449 context
->shut_down
= TRUE
;
1452 static const struct activate_funcs sample_grabber_activate_funcs
=
1454 sample_grabber_create_object
,
1455 sample_grabber_shutdown_object
,
1456 sample_grabber_free_private
,
1459 /***********************************************************************
1460 * MFCreateSampleGrabberSinkActivate (mf.@)
1462 HRESULT WINAPI
MFCreateSampleGrabberSinkActivate(IMFMediaType
*media_type
, IMFSampleGrabberSinkCallback
*callback
,
1463 IMFActivate
**activate
)
1465 struct sample_grabber_activate_context
*context
;
1468 TRACE("%p, %p, %p.\n", media_type
, callback
, activate
);
1470 if (!media_type
|| !callback
|| !activate
)
1473 context
= heap_alloc_zero(sizeof(*context
));
1475 return E_OUTOFMEMORY
;
1477 context
->media_type
= media_type
;
1478 IMFMediaType_AddRef(context
->media_type
);
1479 context
->callback
= callback
;
1480 IMFSampleGrabberSinkCallback_AddRef(context
->callback
);
1482 if (FAILED(hr
= create_activation_object(context
, &sample_grabber_activate_funcs
, activate
)))
1483 sample_grabber_free_private(context
);