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
;
76 IMFMediaEventQueue
*event_queue
;
77 IMFMediaEventQueue
*stream_event_queue
;
78 IMFPresentationClock
*clock
;
80 IMFAttributes
*sample_attributes
;
84 UINT64 sample_time_offset
;
85 enum sink_state state
;
89 static IMFSampleGrabberSinkCallback
*sample_grabber_get_callback(const struct sample_grabber
*sink
)
91 return sink
->callback2
? (IMFSampleGrabberSinkCallback
*)sink
->callback2
: sink
->callback
;
94 struct sample_grabber_activate_context
96 IMFMediaType
*media_type
;
97 IMFSampleGrabberSinkCallback
*callback
;
101 static void sample_grabber_free_private(void *user_context
)
103 struct sample_grabber_activate_context
*context
= user_context
;
104 IMFMediaType_Release(context
->media_type
);
105 IMFSampleGrabberSinkCallback_Release(context
->callback
);
109 static struct sample_grabber
*impl_from_IMFMediaSink(IMFMediaSink
*iface
)
111 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaSink_iface
);
114 static struct sample_grabber
*impl_from_IMFClockStateSink(IMFClockStateSink
*iface
)
116 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFClockStateSink_iface
);
119 static struct sample_grabber
*impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator
*iface
)
121 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaEventGenerator_iface
);
124 static struct sample_grabber
*impl_from_IMFGetService(IMFGetService
*iface
)
126 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFGetService_iface
);
129 static struct sample_grabber
*impl_from_IMFRateSupport(IMFRateSupport
*iface
)
131 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFRateSupport_iface
);
134 static struct sample_grabber
*impl_from_IMFStreamSink(IMFStreamSink
*iface
)
136 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFStreamSink_iface
);
139 static struct sample_grabber
*impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler
*iface
)
141 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaTypeHandler_iface
);
144 static struct sample_grabber
*impl_from_IMFAsyncCallback(IMFAsyncCallback
*iface
)
146 return CONTAINING_RECORD(iface
, struct sample_grabber
, timer_callback
);
149 static HRESULT WINAPI
sample_grabber_stream_QueryInterface(IMFStreamSink
*iface
, REFIID riid
, void **obj
)
151 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
153 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
155 if (IsEqualIID(riid
, &IID_IMFStreamSink
) ||
156 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
157 IsEqualIID(riid
, &IID_IUnknown
))
159 *obj
= &grabber
->IMFStreamSink_iface
;
161 else if (IsEqualIID(riid
, &IID_IMFMediaTypeHandler
))
163 *obj
= &grabber
->IMFMediaTypeHandler_iface
;
167 WARN("Unsupported %s.\n", debugstr_guid(riid
));
169 return E_NOINTERFACE
;
172 IUnknown_AddRef((IUnknown
*)*obj
);
177 static ULONG WINAPI
sample_grabber_stream_AddRef(IMFStreamSink
*iface
)
179 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
180 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
183 static void stream_release_pending_item(struct scheduled_item
*item
)
185 list_remove(&item
->entry
);
188 case ITEM_TYPE_SAMPLE
:
189 IMFSample_Release(item
->u
.sample
);
191 case ITEM_TYPE_MARKER
:
192 PropVariantClear(&item
->u
.marker
.context
);
198 static ULONG WINAPI
sample_grabber_stream_Release(IMFStreamSink
*iface
)
200 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
201 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
204 static HRESULT WINAPI
sample_grabber_stream_GetEvent(IMFStreamSink
*iface
, DWORD flags
, IMFMediaEvent
**event
)
206 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
208 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
210 if (grabber
->is_shut_down
)
211 return MF_E_STREAMSINK_REMOVED
;
213 return IMFMediaEventQueue_GetEvent(grabber
->stream_event_queue
, flags
, event
);
216 static HRESULT WINAPI
sample_grabber_stream_BeginGetEvent(IMFStreamSink
*iface
, IMFAsyncCallback
*callback
,
219 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
221 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
223 if (grabber
->is_shut_down
)
224 return MF_E_STREAMSINK_REMOVED
;
226 return IMFMediaEventQueue_BeginGetEvent(grabber
->stream_event_queue
, callback
, state
);
229 static HRESULT WINAPI
sample_grabber_stream_EndGetEvent(IMFStreamSink
*iface
, IMFAsyncResult
*result
,
230 IMFMediaEvent
**event
)
232 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
234 TRACE("%p, %p, %p.\n", iface
, result
, event
);
236 if (grabber
->is_shut_down
)
237 return MF_E_STREAMSINK_REMOVED
;
239 return IMFMediaEventQueue_EndGetEvent(grabber
->stream_event_queue
, result
, event
);
242 static HRESULT WINAPI
sample_grabber_stream_QueueEvent(IMFStreamSink
*iface
, MediaEventType event_type
,
243 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
245 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
247 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
249 if (grabber
->is_shut_down
)
250 return MF_E_STREAMSINK_REMOVED
;
252 return IMFMediaEventQueue_QueueEventParamVar(grabber
->stream_event_queue
, event_type
, ext_type
, hr
, value
);
255 static HRESULT WINAPI
sample_grabber_stream_GetMediaSink(IMFStreamSink
*iface
, IMFMediaSink
**sink
)
257 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
259 TRACE("%p, %p.\n", iface
, sink
);
261 if (grabber
->is_shut_down
)
262 return MF_E_STREAMSINK_REMOVED
;
264 *sink
= &grabber
->IMFMediaSink_iface
;
265 IMFMediaSink_AddRef(*sink
);
270 static HRESULT WINAPI
sample_grabber_stream_GetIdentifier(IMFStreamSink
*iface
, DWORD
*identifier
)
272 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
274 TRACE("%p, %p.\n", iface
, identifier
);
276 if (grabber
->is_shut_down
)
277 return MF_E_STREAMSINK_REMOVED
;
284 static HRESULT WINAPI
sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink
*iface
, IMFMediaTypeHandler
**handler
)
286 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
288 TRACE("%p, %p.\n", iface
, handler
);
293 if (grabber
->is_shut_down
)
294 return MF_E_STREAMSINK_REMOVED
;
296 *handler
= &grabber
->IMFMediaTypeHandler_iface
;
297 IMFMediaTypeHandler_AddRef(*handler
);
302 static HRESULT
sample_grabber_report_sample(struct sample_grabber
*grabber
, IMFSample
*sample
, BOOL
*sample_delivered
)
304 LONGLONG sample_time
, sample_duration
= 0;
305 IMFMediaBuffer
*buffer
;
311 *sample_delivered
= FALSE
;
313 hr
= IMFMediaType_GetMajorType(grabber
->media_type
, &major_type
);
316 hr
= IMFSample_GetSampleTime(sample
, &sample_time
);
318 if (FAILED(IMFSample_GetSampleDuration(sample
, &sample_duration
)))
322 hr
= IMFSample_GetSampleFlags(sample
, &flags
);
326 if (FAILED(IMFSample_ConvertToContiguousBuffer(sample
, &buffer
)))
329 if (SUCCEEDED(hr
= IMFMediaBuffer_Lock(buffer
, &data
, NULL
, &size
)))
331 *sample_delivered
= TRUE
;
333 if (grabber
->callback2
)
335 hr
= IMFSample_CopyAllItems(sample
, grabber
->sample_attributes
);
337 hr
= IMFSampleGrabberSinkCallback2_OnProcessSampleEx(grabber
->callback2
, &major_type
, flags
,
338 sample_time
, sample_duration
, data
, size
, grabber
->sample_attributes
);
341 hr
= IMFSampleGrabberSinkCallback_OnProcessSample(grabber
->callback
, &major_type
, flags
, sample_time
,
342 sample_duration
, data
, size
);
343 IMFMediaBuffer_Unlock(buffer
);
346 IMFMediaBuffer_Release(buffer
);
352 static HRESULT
stream_schedule_sample(struct sample_grabber
*grabber
, struct scheduled_item
*item
)
357 if (grabber
->is_shut_down
)
358 return MF_E_STREAMSINK_REMOVED
;
360 if (FAILED(hr
= IMFSample_GetSampleTime(item
->u
.sample
, &sampletime
)))
363 if (grabber
->cancel_key
)
365 IUnknown_Release(grabber
->cancel_key
);
366 grabber
->cancel_key
= NULL
;
369 if (FAILED(hr
= IMFTimer_SetTimer(grabber
->timer
, 0, sampletime
- grabber
->sample_time_offset
,
370 &grabber
->timer_callback
, NULL
, &grabber
->cancel_key
)))
372 grabber
->cancel_key
= NULL
;
378 static HRESULT
stream_queue_sample(struct sample_grabber
*grabber
, IMFSample
*sample
)
380 struct scheduled_item
*item
;
384 if (FAILED(hr
= IMFSample_GetSampleTime(sample
, &sampletime
)))
387 if (!(item
= heap_alloc_zero(sizeof(*item
))))
388 return E_OUTOFMEMORY
;
390 item
->type
= ITEM_TYPE_SAMPLE
;
391 item
->u
.sample
= sample
;
392 IMFSample_AddRef(item
->u
.sample
);
393 list_init(&item
->entry
);
394 if (list_empty(&grabber
->items
))
395 hr
= stream_schedule_sample(grabber
, item
);
398 list_add_tail(&grabber
->items
, &item
->entry
);
400 stream_release_pending_item(item
);
405 static void sample_grabber_stream_request_sample(struct sample_grabber
*grabber
)
407 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
410 static HRESULT WINAPI
sample_grabber_stream_ProcessSample(IMFStreamSink
*iface
, IMFSample
*sample
)
412 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
413 BOOL sample_delivered
;
417 TRACE("%p, %p.\n", iface
, sample
);
422 EnterCriticalSection(&grabber
->cs
);
424 if (grabber
->is_shut_down
)
425 hr
= MF_E_STREAMSINK_REMOVED
;
426 else if (grabber
->state
== SINK_STATE_RUNNING
)
428 hr
= IMFSample_GetSampleTime(sample
, &sampletime
);
432 if (grabber
->ignore_clock
)
434 /* OnProcessSample() could return error code, which has to be propagated but isn't a blocker.
435 Use additional flag indicating that user callback was called at all. */
436 hr
= sample_grabber_report_sample(grabber
, sample
, &sample_delivered
);
437 if (sample_delivered
)
438 sample_grabber_stream_request_sample(grabber
);
441 hr
= stream_queue_sample(grabber
, sample
);
445 LeaveCriticalSection(&grabber
->cs
);
450 static void sample_grabber_stream_report_marker(struct sample_grabber
*grabber
, const PROPVARIANT
*context
,
453 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkMarker
, &GUID_NULL
, hr
, context
);
456 static HRESULT
stream_place_marker(struct sample_grabber
*grabber
, MFSTREAMSINK_MARKER_TYPE marker_type
,
457 const PROPVARIANT
*context_value
)
459 struct scheduled_item
*item
;
462 if (list_empty(&grabber
->items
))
464 sample_grabber_stream_report_marker(grabber
, context_value
, S_OK
);
468 if (!(item
= heap_alloc_zero(sizeof(*item
))))
469 return E_OUTOFMEMORY
;
471 item
->type
= ITEM_TYPE_MARKER
;
472 item
->u
.marker
.type
= marker_type
;
473 list_init(&item
->entry
);
474 PropVariantInit(&item
->u
.marker
.context
);
476 hr
= PropVariantCopy(&item
->u
.marker
.context
, context_value
);
478 list_add_tail(&grabber
->items
, &item
->entry
);
480 stream_release_pending_item(item
);
485 static HRESULT WINAPI
sample_grabber_stream_PlaceMarker(IMFStreamSink
*iface
, MFSTREAMSINK_MARKER_TYPE marker_type
,
486 const PROPVARIANT
*marker_value
, const PROPVARIANT
*context_value
)
488 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
491 TRACE("%p, %d, %p, %p.\n", iface
, marker_type
, marker_value
, context_value
);
493 EnterCriticalSection(&grabber
->cs
);
495 if (grabber
->is_shut_down
)
496 hr
= MF_E_STREAMSINK_REMOVED
;
497 else if (grabber
->state
== SINK_STATE_RUNNING
)
498 hr
= stream_place_marker(grabber
, marker_type
, context_value
);
500 LeaveCriticalSection(&grabber
->cs
);
505 static HRESULT WINAPI
sample_grabber_stream_Flush(IMFStreamSink
*iface
)
507 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
508 struct scheduled_item
*item
, *next_item
;
510 TRACE("%p.\n", iface
);
512 if (grabber
->is_shut_down
)
513 return MF_E_STREAMSINK_REMOVED
;
515 EnterCriticalSection(&grabber
->cs
);
517 LIST_FOR_EACH_ENTRY_SAFE(item
, next_item
, &grabber
->items
, struct scheduled_item
, entry
)
519 /* Samples are discarded, markers are processed immediately. */
522 case ITEM_TYPE_SAMPLE
:
524 case ITEM_TYPE_MARKER
:
525 sample_grabber_stream_report_marker(grabber
, &item
->u
.marker
.context
, E_ABORT
);
529 stream_release_pending_item(item
);
532 LeaveCriticalSection(&grabber
->cs
);
537 static const IMFStreamSinkVtbl sample_grabber_stream_vtbl
=
539 sample_grabber_stream_QueryInterface
,
540 sample_grabber_stream_AddRef
,
541 sample_grabber_stream_Release
,
542 sample_grabber_stream_GetEvent
,
543 sample_grabber_stream_BeginGetEvent
,
544 sample_grabber_stream_EndGetEvent
,
545 sample_grabber_stream_QueueEvent
,
546 sample_grabber_stream_GetMediaSink
,
547 sample_grabber_stream_GetIdentifier
,
548 sample_grabber_stream_GetMediaTypeHandler
,
549 sample_grabber_stream_ProcessSample
,
550 sample_grabber_stream_PlaceMarker
,
551 sample_grabber_stream_Flush
,
554 static HRESULT WINAPI
sample_grabber_stream_type_handler_QueryInterface(IMFMediaTypeHandler
*iface
, REFIID riid
,
557 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
558 return IMFStreamSink_QueryInterface(&grabber
->IMFStreamSink_iface
, riid
, obj
);
561 static ULONG WINAPI
sample_grabber_stream_type_handler_AddRef(IMFMediaTypeHandler
*iface
)
563 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
564 return IMFStreamSink_AddRef(&grabber
->IMFStreamSink_iface
);
567 static ULONG WINAPI
sample_grabber_stream_type_handler_Release(IMFMediaTypeHandler
*iface
)
569 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
570 return IMFStreamSink_Release(&grabber
->IMFStreamSink_iface
);
573 static HRESULT
sample_grabber_stream_is_media_type_supported(struct sample_grabber
*grabber
, IMFMediaType
*in_type
)
575 const DWORD supported_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_TYPES
;
578 if (grabber
->is_shut_down
)
579 return MF_E_STREAMSINK_REMOVED
;
584 if (IMFMediaType_IsEqual(grabber
->media_type
, in_type
, &flags
) == S_OK
)
587 return (flags
& supported_flags
) == supported_flags
? S_OK
: MF_E_INVALIDMEDIATYPE
;
590 static HRESULT WINAPI
sample_grabber_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler
*iface
,
591 IMFMediaType
*in_type
, IMFMediaType
**out_type
)
593 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
595 TRACE("%p, %p, %p.\n", iface
, in_type
, out_type
);
597 return sample_grabber_stream_is_media_type_supported(grabber
, in_type
);
600 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler
*iface
, DWORD
*count
)
602 TRACE("%p, %p.\n", iface
, count
);
612 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
*iface
, DWORD index
,
613 IMFMediaType
**media_type
)
615 TRACE("%p, %u, %p.\n", iface
, index
, media_type
);
620 return MF_E_NO_MORE_TYPES
;
623 static HRESULT WINAPI
sample_grabber_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler
*iface
,
624 IMFMediaType
*media_type
)
626 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
629 TRACE("%p, %p.\n", iface
, media_type
);
631 if (FAILED(hr
= sample_grabber_stream_is_media_type_supported(grabber
, media_type
)))
634 IMFMediaType_Release(grabber
->media_type
);
635 grabber
->media_type
= media_type
;
636 IMFMediaType_AddRef(grabber
->media_type
);
641 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler
*iface
,
642 IMFMediaType
**media_type
)
644 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
646 TRACE("%p, %p.\n", iface
, media_type
);
651 if (grabber
->is_shut_down
)
652 return MF_E_STREAMSINK_REMOVED
;
654 *media_type
= grabber
->media_type
;
655 IMFMediaType_AddRef(*media_type
);
660 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
662 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
664 TRACE("%p, %p.\n", iface
, type
);
669 if (grabber
->is_shut_down
)
670 return MF_E_STREAMSINK_REMOVED
;
672 return IMFMediaType_GetMajorType(grabber
->media_type
, type
);
675 static const IMFMediaTypeHandlerVtbl sample_grabber_stream_type_handler_vtbl
=
677 sample_grabber_stream_type_handler_QueryInterface
,
678 sample_grabber_stream_type_handler_AddRef
,
679 sample_grabber_stream_type_handler_Release
,
680 sample_grabber_stream_type_handler_IsMediaTypeSupported
,
681 sample_grabber_stream_type_handler_GetMediaTypeCount
,
682 sample_grabber_stream_type_handler_GetMediaTypeByIndex
,
683 sample_grabber_stream_type_handler_SetCurrentMediaType
,
684 sample_grabber_stream_type_handler_GetCurrentMediaType
,
685 sample_grabber_stream_type_handler_GetMajorType
,
688 static HRESULT WINAPI
sample_grabber_stream_timer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
,
691 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) || IsEqualIID(riid
, &IID_IUnknown
))
694 IMFAsyncCallback_AddRef(iface
);
698 WARN("Unsupported %s.\n", debugstr_guid(riid
));
700 return E_NOINTERFACE
;
703 static ULONG WINAPI
sample_grabber_stream_timer_callback_AddRef(IMFAsyncCallback
*iface
)
705 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
706 return IMFStreamSink_AddRef(&grabber
->IMFStreamSink_iface
);
709 static ULONG WINAPI
sample_grabber_stream_timer_callback_Release(IMFAsyncCallback
*iface
)
711 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
712 return IMFStreamSink_Release(&grabber
->IMFStreamSink_iface
);
715 static HRESULT WINAPI
sample_grabber_stream_timer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
,
721 static HRESULT WINAPI
sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
723 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
724 BOOL sample_reported
= FALSE
, sample_delivered
= FALSE
;
725 struct scheduled_item
*item
, *item2
;
728 EnterCriticalSection(&grabber
->cs
);
730 LIST_FOR_EACH_ENTRY_SAFE(item
, item2
, &grabber
->items
, struct scheduled_item
, entry
)
732 if (item
->type
== ITEM_TYPE_MARKER
)
734 sample_grabber_stream_report_marker(grabber
, &item
->u
.marker
.context
, S_OK
);
735 stream_release_pending_item(item
);
737 else if (item
->type
== ITEM_TYPE_SAMPLE
)
739 if (!sample_reported
)
741 if (FAILED(hr
= sample_grabber_report_sample(grabber
, item
->u
.sample
, &sample_delivered
)))
742 WARN("Failed to report a sample, hr %#x.\n", hr
);
743 stream_release_pending_item(item
);
744 sample_reported
= TRUE
;
748 if (FAILED(hr
= stream_schedule_sample(grabber
, item
)))
749 WARN("Failed to schedule a sample, hr %#x.\n", hr
);
754 if (sample_delivered
)
755 sample_grabber_stream_request_sample(grabber
);
757 LeaveCriticalSection(&grabber
->cs
);
762 static const IMFAsyncCallbackVtbl sample_grabber_stream_timer_callback_vtbl
=
764 sample_grabber_stream_timer_callback_QueryInterface
,
765 sample_grabber_stream_timer_callback_AddRef
,
766 sample_grabber_stream_timer_callback_Release
,
767 sample_grabber_stream_timer_callback_GetParameters
,
768 sample_grabber_stream_timer_callback_Invoke
,
771 static HRESULT WINAPI
sample_grabber_sink_QueryInterface(IMFMediaSink
*iface
, REFIID riid
, void **obj
)
773 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
775 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
777 if (IsEqualIID(riid
, &IID_IMFMediaSink
) ||
778 IsEqualIID(riid
, &IID_IUnknown
))
780 *obj
= &grabber
->IMFMediaSink_iface
;
782 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
784 *obj
= &grabber
->IMFClockStateSink_iface
;
786 else if (IsEqualIID(riid
, &IID_IMFMediaEventGenerator
))
788 *obj
= &grabber
->IMFMediaEventGenerator_iface
;
790 else if (IsEqualIID(riid
, &IID_IMFGetService
))
792 *obj
= &grabber
->IMFGetService_iface
;
794 else if (IsEqualIID(riid
, &IID_IMFRateSupport
))
796 *obj
= &grabber
->IMFRateSupport_iface
;
800 WARN("Unsupported %s.\n", debugstr_guid(riid
));
802 return E_NOINTERFACE
;
805 IUnknown_AddRef((IUnknown
*)*obj
);
810 static ULONG WINAPI
sample_grabber_sink_AddRef(IMFMediaSink
*iface
)
812 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
813 ULONG refcount
= InterlockedIncrement(&grabber
->refcount
);
815 TRACE("%p, refcount %u.\n", iface
, refcount
);
820 static void sample_grabber_release_pending_items(struct sample_grabber
*grabber
)
822 struct scheduled_item
*item
, *next_item
;
824 LIST_FOR_EACH_ENTRY_SAFE(item
, next_item
, &grabber
->items
, struct scheduled_item
, entry
)
826 stream_release_pending_item(item
);
830 static ULONG WINAPI
sample_grabber_sink_Release(IMFMediaSink
*iface
)
832 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
833 ULONG refcount
= InterlockedDecrement(&grabber
->refcount
);
835 TRACE("%p, refcount %u.\n", iface
, refcount
);
839 if (grabber
->callback
)
840 IMFSampleGrabberSinkCallback_Release(grabber
->callback
);
841 if (grabber
->callback2
)
842 IMFSampleGrabberSinkCallback2_Release(grabber
->callback2
);
843 IMFMediaType_Release(grabber
->media_type
);
844 if (grabber
->event_queue
)
845 IMFMediaEventQueue_Release(grabber
->event_queue
);
847 IMFPresentationClock_Release(grabber
->clock
);
850 if (grabber
->cancel_key
)
851 IMFTimer_CancelTimer(grabber
->timer
, grabber
->cancel_key
);
852 IMFTimer_Release(grabber
->timer
);
854 if (grabber
->cancel_key
)
855 IUnknown_Release(grabber
->cancel_key
);
856 if (grabber
->stream_event_queue
)
858 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
859 IMFMediaEventQueue_Release(grabber
->stream_event_queue
);
861 if (grabber
->sample_attributes
)
862 IMFAttributes_Release(grabber
->sample_attributes
);
863 sample_grabber_release_pending_items(grabber
);
864 DeleteCriticalSection(&grabber
->cs
);
871 static HRESULT WINAPI
sample_grabber_sink_GetCharacteristics(IMFMediaSink
*iface
, DWORD
*flags
)
873 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
875 TRACE("%p, %p.\n", iface
, flags
);
877 if (grabber
->is_shut_down
)
878 return MF_E_SHUTDOWN
;
880 *flags
= MEDIASINK_FIXED_STREAMS
;
881 if (grabber
->ignore_clock
)
882 *flags
|= MEDIASINK_RATELESS
;
887 static HRESULT WINAPI
sample_grabber_sink_AddStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
,
888 IMFMediaType
*media_type
, IMFStreamSink
**stream_sink
)
890 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
892 TRACE("%p, %#x, %p, %p.\n", iface
, stream_sink_id
, media_type
, stream_sink
);
894 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
897 static HRESULT WINAPI
sample_grabber_sink_RemoveStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
)
899 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
901 TRACE("%p, %#x.\n", iface
, stream_sink_id
);
903 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
906 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkCount(IMFMediaSink
*iface
, DWORD
*count
)
908 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
910 TRACE("%p, %p.\n", iface
, count
);
912 if (grabber
->is_shut_down
)
913 return MF_E_SHUTDOWN
;
920 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink
*iface
, DWORD index
,
921 IMFStreamSink
**stream
)
923 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
926 TRACE("%p, %u, %p.\n", iface
, index
, stream
);
928 if (grabber
->is_shut_down
)
929 return MF_E_SHUTDOWN
;
931 EnterCriticalSection(&grabber
->cs
);
933 if (grabber
->is_shut_down
)
936 hr
= MF_E_INVALIDINDEX
;
939 *stream
= &grabber
->IMFStreamSink_iface
;
940 IMFStreamSink_AddRef(*stream
);
943 LeaveCriticalSection(&grabber
->cs
);
948 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkById(IMFMediaSink
*iface
, DWORD stream_sink_id
,
949 IMFStreamSink
**stream
)
951 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
954 TRACE("%p, %#x, %p.\n", iface
, stream_sink_id
, stream
);
956 EnterCriticalSection(&grabber
->cs
);
958 if (grabber
->is_shut_down
)
960 else if (stream_sink_id
> 0)
961 hr
= MF_E_INVALIDSTREAMNUMBER
;
964 *stream
= &grabber
->IMFStreamSink_iface
;
965 IMFStreamSink_AddRef(*stream
);
968 LeaveCriticalSection(&grabber
->cs
);
973 static void sample_grabber_set_presentation_clock(struct sample_grabber
*grabber
, IMFPresentationClock
*clock
)
977 IMFPresentationClock_RemoveClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
978 IMFPresentationClock_Release(grabber
->clock
);
981 IMFTimer_Release(grabber
->timer
);
982 grabber
->timer
= NULL
;
985 grabber
->clock
= clock
;
988 IMFPresentationClock_AddRef(grabber
->clock
);
989 IMFPresentationClock_AddClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
990 if (FAILED(IMFPresentationClock_QueryInterface(grabber
->clock
, &IID_IMFTimer
, (void **)&grabber
->timer
)))
992 WARN("Failed to get IMFTimer interface.\n");
993 grabber
->timer
= NULL
;
998 static HRESULT WINAPI
sample_grabber_sink_SetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
*clock
)
1000 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1003 TRACE("%p, %p.\n", iface
, clock
);
1005 EnterCriticalSection(&grabber
->cs
);
1007 if (SUCCEEDED(hr
= IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber
),
1010 sample_grabber_set_presentation_clock(grabber
, clock
);
1013 LeaveCriticalSection(&grabber
->cs
);
1018 static HRESULT WINAPI
sample_grabber_sink_GetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
**clock
)
1020 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1023 TRACE("%p, %p.\n", iface
, clock
);
1028 EnterCriticalSection(&grabber
->cs
);
1032 *clock
= grabber
->clock
;
1033 IMFPresentationClock_AddRef(*clock
);
1038 LeaveCriticalSection(&grabber
->cs
);
1043 static HRESULT WINAPI
sample_grabber_sink_Shutdown(IMFMediaSink
*iface
)
1045 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1048 TRACE("%p.\n", iface
);
1050 if (grabber
->is_shut_down
)
1051 return MF_E_SHUTDOWN
;
1053 EnterCriticalSection(&grabber
->cs
);
1054 grabber
->is_shut_down
= TRUE
;
1055 sample_grabber_release_pending_items(grabber
);
1056 if (SUCCEEDED(hr
= IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber
))))
1058 sample_grabber_set_presentation_clock(grabber
, NULL
);
1059 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
1060 IMFMediaEventQueue_Shutdown(grabber
->event_queue
);
1062 LeaveCriticalSection(&grabber
->cs
);
1067 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl
=
1069 sample_grabber_sink_QueryInterface
,
1070 sample_grabber_sink_AddRef
,
1071 sample_grabber_sink_Release
,
1072 sample_grabber_sink_GetCharacteristics
,
1073 sample_grabber_sink_AddStreamSink
,
1074 sample_grabber_sink_RemoveStreamSink
,
1075 sample_grabber_sink_GetStreamSinkCount
,
1076 sample_grabber_sink_GetStreamSinkByIndex
,
1077 sample_grabber_sink_GetStreamSinkById
,
1078 sample_grabber_sink_SetPresentationClock
,
1079 sample_grabber_sink_GetPresentationClock
,
1080 sample_grabber_sink_Shutdown
,
1083 static HRESULT WINAPI
sample_grabber_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
1085 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1086 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1089 static ULONG WINAPI
sample_grabber_clock_sink_AddRef(IMFClockStateSink
*iface
)
1091 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1092 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1095 static ULONG WINAPI
sample_grabber_clock_sink_Release(IMFClockStateSink
*iface
)
1097 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1098 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1101 static void sample_grabber_set_state(struct sample_grabber
*grabber
, enum sink_state state
)
1103 static const DWORD events
[] =
1105 MEStreamSinkStopped
, /* SINK_STATE_STOPPED */
1106 MEStreamSinkStarted
, /* SINK_STATE_RUNNING */
1108 BOOL set_state
= FALSE
;
1111 EnterCriticalSection(&grabber
->cs
);
1113 if (!grabber
->is_shut_down
)
1115 switch (grabber
->state
)
1117 case SINK_STATE_STOPPED
:
1118 set_state
= state
== SINK_STATE_RUNNING
;
1120 case SINK_STATE_RUNNING
:
1121 set_state
= state
== SINK_STATE_STOPPED
;
1129 grabber
->state
= state
;
1130 if (state
== SINK_STATE_RUNNING
)
1132 /* Every transition to running state sends a bunch requests to build up initial queue. */
1133 for (i
= 0; i
< 4; ++i
)
1134 sample_grabber_stream_request_sample(grabber
);
1136 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, events
[state
], &GUID_NULL
, S_OK
, NULL
);
1140 LeaveCriticalSection(&grabber
->cs
);
1143 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
1145 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1147 TRACE("%p, %s, %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
1149 sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
);
1151 return IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber
), systime
, offset
);
1154 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStop(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_STOPPED
);
1162 return IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber
), systime
);
1165 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
1167 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1169 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1171 return IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber
), systime
);
1174 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
1176 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1178 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1180 sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
);
1182 return IMFSampleGrabberSinkCallback_OnClockRestart(sample_grabber_get_callback(grabber
), systime
);
1185 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
1187 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1189 TRACE("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
1191 return IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber
), systime
, rate
);
1194 static HRESULT WINAPI
sample_grabber_events_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
1196 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1197 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1200 static ULONG WINAPI
sample_grabber_events_AddRef(IMFMediaEventGenerator
*iface
)
1202 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1203 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1206 static ULONG WINAPI
sample_grabber_events_Release(IMFMediaEventGenerator
*iface
)
1208 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1209 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1212 static HRESULT WINAPI
sample_grabber_events_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1214 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1216 TRACE("%p, %#x, %p.\n", iface
, flags
, event
);
1218 return IMFMediaEventQueue_GetEvent(grabber
->event_queue
, flags
, event
);
1221 static HRESULT WINAPI
sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
1224 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1226 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1228 return IMFMediaEventQueue_BeginGetEvent(grabber
->event_queue
, callback
, state
);
1231 static HRESULT WINAPI
sample_grabber_events_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
1232 IMFMediaEvent
**event
)
1234 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1236 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1238 return IMFMediaEventQueue_EndGetEvent(grabber
->event_queue
, result
, event
);
1241 static HRESULT WINAPI
sample_grabber_events_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
1242 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
1244 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1246 TRACE("%p, %u, %s, %#x, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1248 return IMFMediaEventQueue_QueueEventParamVar(grabber
->event_queue
, event_type
, ext_type
, hr
, value
);
1251 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl
=
1253 sample_grabber_events_QueryInterface
,
1254 sample_grabber_events_AddRef
,
1255 sample_grabber_events_Release
,
1256 sample_grabber_events_GetEvent
,
1257 sample_grabber_events_BeginGetEvent
,
1258 sample_grabber_events_EndGetEvent
,
1259 sample_grabber_events_QueueEvent
,
1262 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl
=
1264 sample_grabber_clock_sink_QueryInterface
,
1265 sample_grabber_clock_sink_AddRef
,
1266 sample_grabber_clock_sink_Release
,
1267 sample_grabber_clock_sink_OnClockStart
,
1268 sample_grabber_clock_sink_OnClockStop
,
1269 sample_grabber_clock_sink_OnClockPause
,
1270 sample_grabber_clock_sink_OnClockRestart
,
1271 sample_grabber_clock_sink_OnClockSetRate
,
1274 static HRESULT WINAPI
sample_grabber_getservice_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1276 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1277 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1280 static ULONG WINAPI
sample_grabber_getservice_AddRef(IMFGetService
*iface
)
1282 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1283 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1286 static ULONG WINAPI
sample_grabber_getservice_Release(IMFGetService
*iface
)
1288 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1289 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1292 static HRESULT WINAPI
sample_grabber_getservice_GetService(IMFGetService
*iface
, REFGUID service
,
1293 REFIID riid
, void **obj
)
1295 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1297 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1299 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1300 return IMFGetService_QueryInterface(iface
, riid
, obj
);
1302 return E_NOINTERFACE
;
1305 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service
), debugstr_guid(riid
));
1307 return MF_E_UNSUPPORTED_SERVICE
;
1310 static const IMFGetServiceVtbl sample_grabber_getservice_vtbl
=
1312 sample_grabber_getservice_QueryInterface
,
1313 sample_grabber_getservice_AddRef
,
1314 sample_grabber_getservice_Release
,
1315 sample_grabber_getservice_GetService
,
1318 static HRESULT WINAPI
sample_grabber_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
1320 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1321 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1324 static ULONG WINAPI
sample_grabber_rate_support_AddRef(IMFRateSupport
*iface
)
1326 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1327 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1330 static ULONG WINAPI
sample_grabber_rate_support_Release(IMFRateSupport
*iface
)
1332 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1333 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1336 static HRESULT WINAPI
sample_grabber_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1337 BOOL thin
, float *rate
)
1339 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1346 static HRESULT WINAPI
sample_grabber_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1347 BOOL thin
, float *rate
)
1349 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1351 *rate
= direction
== MFRATE_REVERSE
? -FLT_MAX
: FLT_MAX
;
1356 static HRESULT WINAPI
sample_grabber_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
1359 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, ret_rate
);
1367 static const IMFRateSupportVtbl sample_grabber_rate_support_vtbl
=
1369 sample_grabber_rate_support_QueryInterface
,
1370 sample_grabber_rate_support_AddRef
,
1371 sample_grabber_rate_support_Release
,
1372 sample_grabber_rate_support_GetSlowestRate
,
1373 sample_grabber_rate_support_GetFastestRate
,
1374 sample_grabber_rate_support_IsRateSupported
,
1377 static HRESULT
sample_grabber_create_object(IMFAttributes
*attributes
, void *user_context
, IUnknown
**obj
)
1379 struct sample_grabber_activate_context
*context
= user_context
;
1380 struct sample_grabber
*object
;
1384 TRACE("%p, %p, %p.\n", attributes
, user_context
, obj
);
1386 if (context
->shut_down
)
1387 return MF_E_SHUTDOWN
;
1389 /* At least major type is required. */
1390 if (FAILED(IMFMediaType_GetMajorType(context
->media_type
, &guid
)))
1391 return MF_E_INVALIDMEDIATYPE
;
1393 object
= heap_alloc_zero(sizeof(*object
));
1395 return E_OUTOFMEMORY
;
1397 object
->IMFMediaSink_iface
.lpVtbl
= &sample_grabber_sink_vtbl
;
1398 object
->IMFClockStateSink_iface
.lpVtbl
= &sample_grabber_clock_sink_vtbl
;
1399 object
->IMFMediaEventGenerator_iface
.lpVtbl
= &sample_grabber_sink_events_vtbl
;
1400 object
->IMFGetService_iface
.lpVtbl
= &sample_grabber_getservice_vtbl
;
1401 object
->IMFRateSupport_iface
.lpVtbl
= &sample_grabber_rate_support_vtbl
;
1402 object
->IMFStreamSink_iface
.lpVtbl
= &sample_grabber_stream_vtbl
;
1403 object
->IMFMediaTypeHandler_iface
.lpVtbl
= &sample_grabber_stream_type_handler_vtbl
;
1404 object
->timer_callback
.lpVtbl
= &sample_grabber_stream_timer_callback_vtbl
;
1405 object
->refcount
= 1;
1406 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context
->callback
, &IID_IMFSampleGrabberSinkCallback2
,
1407 (void **)&object
->callback2
)))
1409 object
->callback
= context
->callback
;
1410 IMFSampleGrabberSinkCallback_AddRef(object
->callback
);
1412 object
->media_type
= context
->media_type
;
1413 IMFMediaType_AddRef(object
->media_type
);
1414 IMFAttributes_GetUINT32(attributes
, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK
, &object
->ignore_clock
);
1415 IMFAttributes_GetUINT64(attributes
, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET
, &object
->sample_time_offset
);
1416 list_init(&object
->items
);
1417 InitializeCriticalSection(&object
->cs
);
1419 if (FAILED(hr
= MFCreateEventQueue(&object
->stream_event_queue
)))
1422 if (FAILED(hr
= MFCreateAttributes(&object
->sample_attributes
, 0)))
1425 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1428 *obj
= (IUnknown
*)&object
->IMFMediaSink_iface
;
1430 TRACE("Created %p.\n", *obj
);
1436 IMFMediaSink_Release(&object
->IMFMediaSink_iface
);
1441 static void sample_grabber_shutdown_object(void *user_context
, IUnknown
*obj
)
1443 struct sample_grabber_activate_context
*context
= user_context
;
1444 context
->shut_down
= TRUE
;
1447 static const struct activate_funcs sample_grabber_activate_funcs
=
1449 sample_grabber_create_object
,
1450 sample_grabber_shutdown_object
,
1451 sample_grabber_free_private
,
1454 /***********************************************************************
1455 * MFCreateSampleGrabberSinkActivate (mf.@)
1457 HRESULT WINAPI
MFCreateSampleGrabberSinkActivate(IMFMediaType
*media_type
, IMFSampleGrabberSinkCallback
*callback
,
1458 IMFActivate
**activate
)
1460 struct sample_grabber_activate_context
*context
;
1463 TRACE("%p, %p, %p.\n", media_type
, callback
, activate
);
1465 if (!media_type
|| !callback
|| !activate
)
1468 context
= heap_alloc_zero(sizeof(*context
));
1470 return E_OUTOFMEMORY
;
1472 context
->media_type
= media_type
;
1473 IMFMediaType_AddRef(context
->media_type
);
1474 context
->callback
= callback
;
1475 IMFSampleGrabberSinkCallback_AddRef(context
->callback
);
1477 if (FAILED(hr
= create_activation_object(context
, &sample_grabber_activate_funcs
, activate
)))
1478 sample_grabber_free_private(context
);