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/list.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
33 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
= calloc(1, 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
= calloc(1, 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
);
852 IMFTimer_Release(grabber
->timer
);
853 if (grabber
->cancel_key
)
854 IUnknown_Release(grabber
->cancel_key
);
855 if (grabber
->stream_event_queue
)
857 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
858 IMFMediaEventQueue_Release(grabber
->stream_event_queue
);
860 if (grabber
->sample_attributes
)
861 IMFAttributes_Release(grabber
->sample_attributes
);
862 sample_grabber_release_pending_items(grabber
);
863 DeleteCriticalSection(&grabber
->cs
);
870 static HRESULT WINAPI
sample_grabber_sink_GetCharacteristics(IMFMediaSink
*iface
, DWORD
*flags
)
872 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
874 TRACE("%p, %p.\n", iface
, flags
);
876 if (grabber
->is_shut_down
)
877 return MF_E_SHUTDOWN
;
879 *flags
= MEDIASINK_FIXED_STREAMS
;
880 if (grabber
->ignore_clock
)
881 *flags
|= MEDIASINK_RATELESS
;
886 static HRESULT WINAPI
sample_grabber_sink_AddStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
,
887 IMFMediaType
*media_type
, IMFStreamSink
**stream_sink
)
889 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
891 TRACE("%p, %#x, %p, %p.\n", iface
, stream_sink_id
, media_type
, stream_sink
);
893 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
896 static HRESULT WINAPI
sample_grabber_sink_RemoveStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
)
898 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
900 TRACE("%p, %#x.\n", iface
, stream_sink_id
);
902 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
905 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkCount(IMFMediaSink
*iface
, DWORD
*count
)
907 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
909 TRACE("%p, %p.\n", iface
, count
);
911 if (grabber
->is_shut_down
)
912 return MF_E_SHUTDOWN
;
919 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink
*iface
, DWORD index
,
920 IMFStreamSink
**stream
)
922 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
925 TRACE("%p, %u, %p.\n", iface
, index
, stream
);
927 if (grabber
->is_shut_down
)
928 return MF_E_SHUTDOWN
;
930 EnterCriticalSection(&grabber
->cs
);
932 if (grabber
->is_shut_down
)
935 hr
= MF_E_INVALIDINDEX
;
938 *stream
= &grabber
->IMFStreamSink_iface
;
939 IMFStreamSink_AddRef(*stream
);
942 LeaveCriticalSection(&grabber
->cs
);
947 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkById(IMFMediaSink
*iface
, DWORD stream_sink_id
,
948 IMFStreamSink
**stream
)
950 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
953 TRACE("%p, %#x, %p.\n", iface
, stream_sink_id
, stream
);
955 EnterCriticalSection(&grabber
->cs
);
957 if (grabber
->is_shut_down
)
959 else if (stream_sink_id
> 0)
960 hr
= MF_E_INVALIDSTREAMNUMBER
;
963 *stream
= &grabber
->IMFStreamSink_iface
;
964 IMFStreamSink_AddRef(*stream
);
967 LeaveCriticalSection(&grabber
->cs
);
972 static void sample_grabber_cancel_timer(struct sample_grabber
*grabber
)
974 if (grabber
->timer
&& grabber
->cancel_key
)
976 IMFTimer_CancelTimer(grabber
->timer
, grabber
->cancel_key
);
977 IUnknown_Release(grabber
->cancel_key
);
978 grabber
->cancel_key
= NULL
;
982 static void sample_grabber_set_presentation_clock(struct sample_grabber
*grabber
, IMFPresentationClock
*clock
)
986 sample_grabber_cancel_timer(grabber
);
987 IMFPresentationClock_RemoveClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
988 IMFPresentationClock_Release(grabber
->clock
);
991 IMFTimer_Release(grabber
->timer
);
992 grabber
->timer
= NULL
;
995 grabber
->clock
= clock
;
998 IMFPresentationClock_AddRef(grabber
->clock
);
999 IMFPresentationClock_AddClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
1000 if (FAILED(IMFPresentationClock_QueryInterface(grabber
->clock
, &IID_IMFTimer
, (void **)&grabber
->timer
)))
1002 WARN("Failed to get IMFTimer interface.\n");
1003 grabber
->timer
= NULL
;
1008 static HRESULT WINAPI
sample_grabber_sink_SetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
*clock
)
1010 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1013 TRACE("%p, %p.\n", iface
, clock
);
1015 EnterCriticalSection(&grabber
->cs
);
1017 if (SUCCEEDED(hr
= IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber
),
1020 sample_grabber_set_presentation_clock(grabber
, clock
);
1023 LeaveCriticalSection(&grabber
->cs
);
1028 static HRESULT WINAPI
sample_grabber_sink_GetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
**clock
)
1030 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1033 TRACE("%p, %p.\n", iface
, clock
);
1038 EnterCriticalSection(&grabber
->cs
);
1042 *clock
= grabber
->clock
;
1043 IMFPresentationClock_AddRef(*clock
);
1048 LeaveCriticalSection(&grabber
->cs
);
1053 static HRESULT WINAPI
sample_grabber_sink_Shutdown(IMFMediaSink
*iface
)
1055 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1058 TRACE("%p.\n", iface
);
1060 if (grabber
->is_shut_down
)
1061 return MF_E_SHUTDOWN
;
1063 EnterCriticalSection(&grabber
->cs
);
1064 grabber
->is_shut_down
= TRUE
;
1065 sample_grabber_release_pending_items(grabber
);
1066 if (SUCCEEDED(hr
= IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber
))))
1068 sample_grabber_set_presentation_clock(grabber
, NULL
);
1069 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
1070 IMFMediaEventQueue_Shutdown(grabber
->event_queue
);
1072 LeaveCriticalSection(&grabber
->cs
);
1077 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl
=
1079 sample_grabber_sink_QueryInterface
,
1080 sample_grabber_sink_AddRef
,
1081 sample_grabber_sink_Release
,
1082 sample_grabber_sink_GetCharacteristics
,
1083 sample_grabber_sink_AddStreamSink
,
1084 sample_grabber_sink_RemoveStreamSink
,
1085 sample_grabber_sink_GetStreamSinkCount
,
1086 sample_grabber_sink_GetStreamSinkByIndex
,
1087 sample_grabber_sink_GetStreamSinkById
,
1088 sample_grabber_sink_SetPresentationClock
,
1089 sample_grabber_sink_GetPresentationClock
,
1090 sample_grabber_sink_Shutdown
,
1093 static HRESULT WINAPI
sample_grabber_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
1095 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1096 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1099 static ULONG WINAPI
sample_grabber_clock_sink_AddRef(IMFClockStateSink
*iface
)
1101 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1102 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1105 static ULONG WINAPI
sample_grabber_clock_sink_Release(IMFClockStateSink
*iface
)
1107 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1108 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1111 static HRESULT
sample_grabber_set_state(struct sample_grabber
*grabber
, enum sink_state state
,
1112 MFTIME systime
, LONGLONG offset
)
1114 static const DWORD events
[] =
1116 MEStreamSinkStopped
, /* SINK_STATE_STOPPED */
1117 MEStreamSinkPaused
, /* SINK_STATE_PAUSED */
1118 MEStreamSinkStarted
, /* SINK_STATE_RUNNING */
1120 BOOL do_callback
= FALSE
;
1124 EnterCriticalSection(&grabber
->cs
);
1126 if (!grabber
->is_shut_down
)
1128 if (state
== SINK_STATE_PAUSED
&& grabber
->state
== SINK_STATE_STOPPED
)
1129 hr
= MF_E_INVALID_STATE_TRANSITION
;
1132 if (state
== SINK_STATE_STOPPED
)
1133 sample_grabber_cancel_timer(grabber
);
1135 if (state
== SINK_STATE_RUNNING
&& grabber
->state
== SINK_STATE_STOPPED
)
1137 /* Every transition to running state sends a bunch requests to build up initial queue. */
1138 for (i
= 0; i
< 4; ++i
)
1139 sample_grabber_stream_request_sample(grabber
);
1141 do_callback
= state
!= grabber
->state
|| state
!= SINK_STATE_PAUSED
;
1143 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, events
[state
], &GUID_NULL
, S_OK
, NULL
);
1144 grabber
->state
= state
;
1148 LeaveCriticalSection(&grabber
->cs
);
1154 case SINK_STATE_STOPPED
:
1155 hr
= IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber
), systime
);
1157 case SINK_STATE_PAUSED
:
1158 hr
= IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber
), systime
);
1160 case SINK_STATE_RUNNING
:
1161 hr
= IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber
), systime
, offset
);
1169 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
1171 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1173 TRACE("%p, %s, %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
1175 return sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
, systime
, offset
);
1178 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
1180 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1182 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1184 return sample_grabber_set_state(grabber
, SINK_STATE_STOPPED
, systime
, 0);
1187 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
1189 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1191 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1193 return sample_grabber_set_state(grabber
, SINK_STATE_PAUSED
, systime
, 0);
1196 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
1198 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1200 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1202 return sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
, systime
, PRESENTATION_CURRENT_POSITION
);
1205 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
1207 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1209 TRACE("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
1211 return IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber
), systime
, rate
);
1214 static HRESULT WINAPI
sample_grabber_events_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
1216 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1217 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1220 static ULONG WINAPI
sample_grabber_events_AddRef(IMFMediaEventGenerator
*iface
)
1222 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1223 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1226 static ULONG WINAPI
sample_grabber_events_Release(IMFMediaEventGenerator
*iface
)
1228 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1229 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1232 static HRESULT WINAPI
sample_grabber_events_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1234 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1236 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1238 return IMFMediaEventQueue_GetEvent(grabber
->event_queue
, flags
, event
);
1241 static HRESULT WINAPI
sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
1244 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1246 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1248 return IMFMediaEventQueue_BeginGetEvent(grabber
->event_queue
, callback
, state
);
1251 static HRESULT WINAPI
sample_grabber_events_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
1252 IMFMediaEvent
**event
)
1254 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1256 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1258 return IMFMediaEventQueue_EndGetEvent(grabber
->event_queue
, result
, event
);
1261 static HRESULT WINAPI
sample_grabber_events_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
1262 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
1264 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1266 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1268 return IMFMediaEventQueue_QueueEventParamVar(grabber
->event_queue
, event_type
, ext_type
, hr
, value
);
1271 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl
=
1273 sample_grabber_events_QueryInterface
,
1274 sample_grabber_events_AddRef
,
1275 sample_grabber_events_Release
,
1276 sample_grabber_events_GetEvent
,
1277 sample_grabber_events_BeginGetEvent
,
1278 sample_grabber_events_EndGetEvent
,
1279 sample_grabber_events_QueueEvent
,
1282 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl
=
1284 sample_grabber_clock_sink_QueryInterface
,
1285 sample_grabber_clock_sink_AddRef
,
1286 sample_grabber_clock_sink_Release
,
1287 sample_grabber_clock_sink_OnClockStart
,
1288 sample_grabber_clock_sink_OnClockStop
,
1289 sample_grabber_clock_sink_OnClockPause
,
1290 sample_grabber_clock_sink_OnClockRestart
,
1291 sample_grabber_clock_sink_OnClockSetRate
,
1294 static HRESULT WINAPI
sample_grabber_getservice_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1296 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1297 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1300 static ULONG WINAPI
sample_grabber_getservice_AddRef(IMFGetService
*iface
)
1302 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1303 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1306 static ULONG WINAPI
sample_grabber_getservice_Release(IMFGetService
*iface
)
1308 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1309 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1312 static HRESULT WINAPI
sample_grabber_getservice_GetService(IMFGetService
*iface
, REFGUID service
,
1313 REFIID riid
, void **obj
)
1315 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1317 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1319 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1320 return IMFGetService_QueryInterface(iface
, riid
, obj
);
1322 return E_NOINTERFACE
;
1325 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service
), debugstr_guid(riid
));
1327 return MF_E_UNSUPPORTED_SERVICE
;
1330 static const IMFGetServiceVtbl sample_grabber_getservice_vtbl
=
1332 sample_grabber_getservice_QueryInterface
,
1333 sample_grabber_getservice_AddRef
,
1334 sample_grabber_getservice_Release
,
1335 sample_grabber_getservice_GetService
,
1338 static HRESULT WINAPI
sample_grabber_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
1340 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1341 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1344 static ULONG WINAPI
sample_grabber_rate_support_AddRef(IMFRateSupport
*iface
)
1346 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1347 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1350 static ULONG WINAPI
sample_grabber_rate_support_Release(IMFRateSupport
*iface
)
1352 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1353 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1356 static HRESULT WINAPI
sample_grabber_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1357 BOOL thin
, float *rate
)
1359 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1366 static HRESULT WINAPI
sample_grabber_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1367 BOOL thin
, float *rate
)
1369 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1371 *rate
= direction
== MFRATE_REVERSE
? -FLT_MAX
: FLT_MAX
;
1376 static HRESULT WINAPI
sample_grabber_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
1379 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, ret_rate
);
1387 static const IMFRateSupportVtbl sample_grabber_rate_support_vtbl
=
1389 sample_grabber_rate_support_QueryInterface
,
1390 sample_grabber_rate_support_AddRef
,
1391 sample_grabber_rate_support_Release
,
1392 sample_grabber_rate_support_GetSlowestRate
,
1393 sample_grabber_rate_support_GetFastestRate
,
1394 sample_grabber_rate_support_IsRateSupported
,
1397 static HRESULT
sample_grabber_create_object(IMFAttributes
*attributes
, void *user_context
, IUnknown
**obj
)
1399 struct sample_grabber_activate_context
*context
= user_context
;
1400 struct sample_grabber
*object
;
1404 TRACE("%p, %p, %p.\n", attributes
, user_context
, obj
);
1406 if (context
->shut_down
)
1407 return MF_E_SHUTDOWN
;
1409 /* At least major type is required. */
1410 if (FAILED(IMFMediaType_GetMajorType(context
->media_type
, &guid
)))
1411 return MF_E_INVALIDMEDIATYPE
;
1413 if (!(object
= calloc(1, sizeof(*object
))))
1414 return E_OUTOFMEMORY
;
1416 object
->IMFMediaSink_iface
.lpVtbl
= &sample_grabber_sink_vtbl
;
1417 object
->IMFClockStateSink_iface
.lpVtbl
= &sample_grabber_clock_sink_vtbl
;
1418 object
->IMFMediaEventGenerator_iface
.lpVtbl
= &sample_grabber_sink_events_vtbl
;
1419 object
->IMFGetService_iface
.lpVtbl
= &sample_grabber_getservice_vtbl
;
1420 object
->IMFRateSupport_iface
.lpVtbl
= &sample_grabber_rate_support_vtbl
;
1421 object
->IMFStreamSink_iface
.lpVtbl
= &sample_grabber_stream_vtbl
;
1422 object
->IMFMediaTypeHandler_iface
.lpVtbl
= &sample_grabber_stream_type_handler_vtbl
;
1423 object
->timer_callback
.lpVtbl
= &sample_grabber_stream_timer_callback_vtbl
;
1424 object
->refcount
= 1;
1425 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context
->callback
, &IID_IMFSampleGrabberSinkCallback2
,
1426 (void **)&object
->callback2
)))
1428 object
->callback
= context
->callback
;
1429 IMFSampleGrabberSinkCallback_AddRef(object
->callback
);
1431 object
->media_type
= context
->media_type
;
1432 IMFMediaType_AddRef(object
->media_type
);
1433 object
->current_media_type
= context
->media_type
;
1434 IMFMediaType_AddRef(object
->current_media_type
);
1435 IMFAttributes_GetUINT32(attributes
, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK
, &object
->ignore_clock
);
1436 IMFAttributes_GetUINT64(attributes
, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET
, &object
->sample_time_offset
);
1437 list_init(&object
->items
);
1438 InitializeCriticalSection(&object
->cs
);
1440 if (FAILED(hr
= MFCreateEventQueue(&object
->stream_event_queue
)))
1443 if (FAILED(hr
= MFCreateAttributes(&object
->sample_attributes
, 0)))
1446 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1449 *obj
= (IUnknown
*)&object
->IMFMediaSink_iface
;
1451 TRACE("Created %p.\n", *obj
);
1457 IMFMediaSink_Release(&object
->IMFMediaSink_iface
);
1462 static void sample_grabber_shutdown_object(void *user_context
, IUnknown
*obj
)
1464 struct sample_grabber_activate_context
*context
= user_context
;
1465 context
->shut_down
= TRUE
;
1468 static const struct activate_funcs sample_grabber_activate_funcs
=
1470 sample_grabber_create_object
,
1471 sample_grabber_shutdown_object
,
1472 sample_grabber_free_private
,
1475 /***********************************************************************
1476 * MFCreateSampleGrabberSinkActivate (mf.@)
1478 HRESULT WINAPI
MFCreateSampleGrabberSinkActivate(IMFMediaType
*media_type
, IMFSampleGrabberSinkCallback
*callback
,
1479 IMFActivate
**activate
)
1481 struct sample_grabber_activate_context
*context
;
1484 TRACE("%p, %p, %p.\n", media_type
, callback
, activate
);
1486 if (!media_type
|| !callback
|| !activate
)
1489 if (!(context
= calloc(1, sizeof(*context
))))
1490 return E_OUTOFMEMORY
;
1492 context
->media_type
= media_type
;
1493 IMFMediaType_AddRef(context
->media_type
);
1494 context
->callback
= callback
;
1495 IMFSampleGrabberSinkCallback_AddRef(context
->callback
);
1497 if (FAILED(hr
= create_activation_object(context
, &sample_grabber_activate_funcs
, activate
)))
1498 sample_grabber_free_private(context
);