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
25 #include "mf_private.h"
27 #include "wine/debug.h"
28 #include "wine/list.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
34 SINK_STATE_STOPPED
= 0,
39 struct sample_grabber
;
41 enum scheduled_item_type
50 enum scheduled_item_type type
;
56 MFSTREAMSINK_MARKER_TYPE type
;
62 #define MAX_SAMPLE_QUEUE_LENGTH 4
66 IMFMediaSink IMFMediaSink_iface
;
67 IMFClockStateSink IMFClockStateSink_iface
;
68 IMFMediaEventGenerator IMFMediaEventGenerator_iface
;
69 IMFGetService IMFGetService_iface
;
70 IMFRateSupport IMFRateSupport_iface
;
71 IMFStreamSink IMFStreamSink_iface
;
72 IMFMediaTypeHandler IMFMediaTypeHandler_iface
;
73 IMFAsyncCallback timer_callback
;
75 IMFSampleGrabberSinkCallback
*callback
;
76 IMFSampleGrabberSinkCallback2
*callback2
;
77 IMFMediaType
*media_type
;
78 IMFMediaType
*current_media_type
;
80 IMFMediaEventQueue
*event_queue
;
81 IMFMediaEventQueue
*stream_event_queue
;
82 IMFPresentationClock
*clock
;
84 IMFAttributes
*sample_attributes
;
88 UINT64 sample_time_offset
;
90 enum sink_state state
;
93 IMFSample
*samples
[MAX_SAMPLE_QUEUE_LENGTH
];
96 static IMFSampleGrabberSinkCallback
*sample_grabber_get_callback(const struct sample_grabber
*sink
)
98 return sink
->callback2
? (IMFSampleGrabberSinkCallback
*)sink
->callback2
: sink
->callback
;
101 struct sample_grabber_activate_context
103 IMFMediaType
*media_type
;
104 IMFSampleGrabberSinkCallback
*callback
;
108 static void sample_grabber_free_private(void *user_context
)
110 struct sample_grabber_activate_context
*context
= user_context
;
111 IMFMediaType_Release(context
->media_type
);
112 IMFSampleGrabberSinkCallback_Release(context
->callback
);
116 static struct sample_grabber
*impl_from_IMFMediaSink(IMFMediaSink
*iface
)
118 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaSink_iface
);
121 static struct sample_grabber
*impl_from_IMFClockStateSink(IMFClockStateSink
*iface
)
123 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFClockStateSink_iface
);
126 static struct sample_grabber
*impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator
*iface
)
128 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaEventGenerator_iface
);
131 static struct sample_grabber
*impl_from_IMFGetService(IMFGetService
*iface
)
133 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFGetService_iface
);
136 static struct sample_grabber
*impl_from_IMFRateSupport(IMFRateSupport
*iface
)
138 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFRateSupport_iface
);
141 static struct sample_grabber
*impl_from_IMFStreamSink(IMFStreamSink
*iface
)
143 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFStreamSink_iface
);
146 static struct sample_grabber
*impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler
*iface
)
148 return CONTAINING_RECORD(iface
, struct sample_grabber
, IMFMediaTypeHandler_iface
);
151 static struct sample_grabber
*impl_from_IMFAsyncCallback(IMFAsyncCallback
*iface
)
153 return CONTAINING_RECORD(iface
, struct sample_grabber
, timer_callback
);
156 static HRESULT WINAPI
sample_grabber_stream_QueryInterface(IMFStreamSink
*iface
, REFIID riid
, void **obj
)
158 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
160 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
162 if (IsEqualIID(riid
, &IID_IMFStreamSink
) ||
163 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
164 IsEqualIID(riid
, &IID_IUnknown
))
166 *obj
= &grabber
->IMFStreamSink_iface
;
168 else if (IsEqualIID(riid
, &IID_IMFMediaTypeHandler
))
170 *obj
= &grabber
->IMFMediaTypeHandler_iface
;
174 WARN("Unsupported %s.\n", debugstr_guid(riid
));
176 return E_NOINTERFACE
;
179 IUnknown_AddRef((IUnknown
*)*obj
);
184 static ULONG WINAPI
sample_grabber_stream_AddRef(IMFStreamSink
*iface
)
186 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
187 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
190 static void stream_release_pending_item(struct scheduled_item
*item
)
192 list_remove(&item
->entry
);
195 case ITEM_TYPE_SAMPLE
:
196 IMFSample_Release(item
->u
.sample
);
198 case ITEM_TYPE_MARKER
:
199 PropVariantClear(&item
->u
.marker
.context
);
205 static ULONG WINAPI
sample_grabber_stream_Release(IMFStreamSink
*iface
)
207 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
208 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
211 static HRESULT WINAPI
sample_grabber_stream_GetEvent(IMFStreamSink
*iface
, DWORD flags
, IMFMediaEvent
**event
)
213 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
215 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
217 if (grabber
->is_shut_down
)
218 return MF_E_STREAMSINK_REMOVED
;
220 return IMFMediaEventQueue_GetEvent(grabber
->stream_event_queue
, flags
, event
);
223 static HRESULT WINAPI
sample_grabber_stream_BeginGetEvent(IMFStreamSink
*iface
, IMFAsyncCallback
*callback
,
226 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
228 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
230 if (grabber
->is_shut_down
)
231 return MF_E_STREAMSINK_REMOVED
;
233 return IMFMediaEventQueue_BeginGetEvent(grabber
->stream_event_queue
, callback
, state
);
236 static HRESULT WINAPI
sample_grabber_stream_EndGetEvent(IMFStreamSink
*iface
, IMFAsyncResult
*result
,
237 IMFMediaEvent
**event
)
239 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
241 TRACE("%p, %p, %p.\n", iface
, result
, event
);
243 if (grabber
->is_shut_down
)
244 return MF_E_STREAMSINK_REMOVED
;
246 return IMFMediaEventQueue_EndGetEvent(grabber
->stream_event_queue
, result
, event
);
249 static HRESULT WINAPI
sample_grabber_stream_QueueEvent(IMFStreamSink
*iface
, MediaEventType event_type
,
250 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
252 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
254 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
256 if (grabber
->is_shut_down
)
257 return MF_E_STREAMSINK_REMOVED
;
259 return IMFMediaEventQueue_QueueEventParamVar(grabber
->stream_event_queue
, event_type
, ext_type
, hr
, value
);
262 static HRESULT WINAPI
sample_grabber_stream_GetMediaSink(IMFStreamSink
*iface
, IMFMediaSink
**sink
)
264 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
266 TRACE("%p, %p.\n", iface
, sink
);
268 if (grabber
->is_shut_down
)
269 return MF_E_STREAMSINK_REMOVED
;
271 *sink
= &grabber
->IMFMediaSink_iface
;
272 IMFMediaSink_AddRef(*sink
);
277 static HRESULT WINAPI
sample_grabber_stream_GetIdentifier(IMFStreamSink
*iface
, DWORD
*identifier
)
279 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
281 TRACE("%p, %p.\n", iface
, identifier
);
283 if (grabber
->is_shut_down
)
284 return MF_E_STREAMSINK_REMOVED
;
291 static HRESULT WINAPI
sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink
*iface
, IMFMediaTypeHandler
**handler
)
293 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
295 TRACE("%p, %p.\n", iface
, handler
);
300 if (grabber
->is_shut_down
)
301 return MF_E_STREAMSINK_REMOVED
;
303 *handler
= &grabber
->IMFMediaTypeHandler_iface
;
304 IMFMediaTypeHandler_AddRef(*handler
);
309 static HRESULT
sample_grabber_report_sample(struct sample_grabber
*grabber
, IMFSample
*sample
, BOOL
*sample_delivered
)
311 LONGLONG sample_time
, sample_duration
= 0;
312 IMFMediaBuffer
*buffer
;
318 *sample_delivered
= FALSE
;
320 hr
= IMFMediaType_GetMajorType(grabber
->media_type
, &major_type
);
323 hr
= IMFSample_GetSampleTime(sample
, &sample_time
);
325 if (FAILED(IMFSample_GetSampleDuration(sample
, &sample_duration
)))
329 hr
= IMFSample_GetSampleFlags(sample
, &flags
);
333 if (FAILED(IMFSample_ConvertToContiguousBuffer(sample
, &buffer
)))
336 if (SUCCEEDED(hr
= IMFMediaBuffer_Lock(buffer
, &data
, NULL
, &size
)))
338 *sample_delivered
= TRUE
;
340 if (grabber
->callback2
)
342 hr
= IMFSample_CopyAllItems(sample
, grabber
->sample_attributes
);
344 hr
= IMFSampleGrabberSinkCallback2_OnProcessSampleEx(grabber
->callback2
, &major_type
, flags
,
345 sample_time
, sample_duration
, data
, size
, grabber
->sample_attributes
);
348 hr
= IMFSampleGrabberSinkCallback_OnProcessSample(grabber
->callback
, &major_type
, flags
, sample_time
,
349 sample_duration
, data
, size
);
350 IMFMediaBuffer_Unlock(buffer
);
353 IMFMediaBuffer_Release(buffer
);
359 static HRESULT
stream_schedule_sample(struct sample_grabber
*grabber
, struct scheduled_item
*item
)
364 if (grabber
->is_shut_down
)
365 return MF_E_STREAMSINK_REMOVED
;
367 if (FAILED(hr
= IMFSample_GetSampleTime(item
->u
.sample
, &sampletime
)))
370 if (grabber
->cancel_key
)
372 IUnknown_Release(grabber
->cancel_key
);
373 grabber
->cancel_key
= NULL
;
376 if (FAILED(hr
= IMFTimer_SetTimer(grabber
->timer
, 0, sampletime
- grabber
->sample_time_offset
,
377 &grabber
->timer_callback
, NULL
, &grabber
->cancel_key
)))
379 grabber
->cancel_key
= NULL
;
385 static HRESULT
stream_queue_sample(struct sample_grabber
*grabber
, IMFSample
*sample
)
387 struct scheduled_item
*item
;
391 if (FAILED(hr
= IMFSample_GetSampleTime(sample
, &sampletime
)))
394 if (!(item
= calloc(1, sizeof(*item
))))
395 return E_OUTOFMEMORY
;
397 item
->type
= ITEM_TYPE_SAMPLE
;
398 item
->u
.sample
= sample
;
399 IMFSample_AddRef(item
->u
.sample
);
400 list_init(&item
->entry
);
401 if (list_empty(&grabber
->items
))
402 hr
= stream_schedule_sample(grabber
, item
);
405 list_add_tail(&grabber
->items
, &item
->entry
);
407 stream_release_pending_item(item
);
412 static void sample_grabber_stream_request_sample(struct sample_grabber
*grabber
)
414 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkRequestSample
, &GUID_NULL
, S_OK
, NULL
);
417 static HRESULT WINAPI
sample_grabber_stream_ProcessSample(IMFStreamSink
*iface
, IMFSample
*sample
)
419 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
420 BOOL sample_delivered
;
424 TRACE("%p, %p.\n", iface
, sample
);
429 EnterCriticalSection(&grabber
->cs
);
431 if (grabber
->is_shut_down
)
432 hr
= MF_E_STREAMSINK_REMOVED
;
433 else if (grabber
->state
== SINK_STATE_RUNNING
|| (grabber
->state
== SINK_STATE_PAUSED
&& grabber
->ignore_clock
))
435 hr
= IMFSample_GetSampleTime(sample
, &sampletime
);
439 if (grabber
->ignore_clock
)
441 /* OnProcessSample() could return error code, which has to be propagated but isn't a blocker.
442 Use additional flag indicating that user callback was called at all. */
443 hr
= sample_grabber_report_sample(grabber
, sample
, &sample_delivered
);
444 if (sample_delivered
)
445 sample_grabber_stream_request_sample(grabber
);
448 hr
= stream_queue_sample(grabber
, sample
);
451 else if (grabber
->state
== SINK_STATE_PAUSED
)
453 if (grabber
->sample_count
< MAX_SAMPLE_QUEUE_LENGTH
)
455 IMFSample_AddRef(sample
);
456 grabber
->samples
[grabber
->sample_count
++] = sample
;
460 LeaveCriticalSection(&grabber
->cs
);
465 static void sample_grabber_stream_report_marker(struct sample_grabber
*grabber
, const PROPVARIANT
*context
,
468 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkMarker
, &GUID_NULL
, hr
, context
);
471 static HRESULT
stream_place_marker(struct sample_grabber
*grabber
, MFSTREAMSINK_MARKER_TYPE marker_type
,
472 const PROPVARIANT
*context_value
)
474 struct scheduled_item
*item
;
477 if (list_empty(&grabber
->items
))
479 sample_grabber_stream_report_marker(grabber
, context_value
, S_OK
);
483 if (!(item
= calloc(1, sizeof(*item
))))
484 return E_OUTOFMEMORY
;
486 item
->type
= ITEM_TYPE_MARKER
;
487 item
->u
.marker
.type
= marker_type
;
488 list_init(&item
->entry
);
489 PropVariantInit(&item
->u
.marker
.context
);
491 hr
= PropVariantCopy(&item
->u
.marker
.context
, context_value
);
493 list_add_tail(&grabber
->items
, &item
->entry
);
495 stream_release_pending_item(item
);
500 static HRESULT WINAPI
sample_grabber_stream_PlaceMarker(IMFStreamSink
*iface
, MFSTREAMSINK_MARKER_TYPE marker_type
,
501 const PROPVARIANT
*marker_value
, const PROPVARIANT
*context_value
)
503 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
506 TRACE("%p, %d, %p, %p.\n", iface
, marker_type
, marker_value
, context_value
);
508 EnterCriticalSection(&grabber
->cs
);
510 if (grabber
->is_shut_down
)
511 hr
= MF_E_STREAMSINK_REMOVED
;
512 else if (grabber
->state
== SINK_STATE_RUNNING
)
513 hr
= stream_place_marker(grabber
, marker_type
, context_value
);
515 LeaveCriticalSection(&grabber
->cs
);
520 static HRESULT WINAPI
sample_grabber_stream_Flush(IMFStreamSink
*iface
)
522 struct sample_grabber
*grabber
= impl_from_IMFStreamSink(iface
);
523 struct scheduled_item
*item
, *next_item
;
526 TRACE("%p.\n", iface
);
528 EnterCriticalSection(&grabber
->cs
);
530 if (grabber
->is_shut_down
)
531 hr
= MF_E_STREAMSINK_REMOVED
;
534 LIST_FOR_EACH_ENTRY_SAFE(item
, next_item
, &grabber
->items
, struct scheduled_item
, entry
)
536 /* Samples are discarded, markers are processed immediately. */
537 if (item
->type
== ITEM_TYPE_MARKER
)
538 sample_grabber_stream_report_marker(grabber
, &item
->u
.marker
.context
, E_ABORT
);
540 stream_release_pending_item(item
);
544 LeaveCriticalSection(&grabber
->cs
);
549 static const IMFStreamSinkVtbl sample_grabber_stream_vtbl
=
551 sample_grabber_stream_QueryInterface
,
552 sample_grabber_stream_AddRef
,
553 sample_grabber_stream_Release
,
554 sample_grabber_stream_GetEvent
,
555 sample_grabber_stream_BeginGetEvent
,
556 sample_grabber_stream_EndGetEvent
,
557 sample_grabber_stream_QueueEvent
,
558 sample_grabber_stream_GetMediaSink
,
559 sample_grabber_stream_GetIdentifier
,
560 sample_grabber_stream_GetMediaTypeHandler
,
561 sample_grabber_stream_ProcessSample
,
562 sample_grabber_stream_PlaceMarker
,
563 sample_grabber_stream_Flush
,
566 static HRESULT WINAPI
sample_grabber_stream_type_handler_QueryInterface(IMFMediaTypeHandler
*iface
, REFIID riid
,
569 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
570 return IMFStreamSink_QueryInterface(&grabber
->IMFStreamSink_iface
, riid
, obj
);
573 static ULONG WINAPI
sample_grabber_stream_type_handler_AddRef(IMFMediaTypeHandler
*iface
)
575 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
576 return IMFStreamSink_AddRef(&grabber
->IMFStreamSink_iface
);
579 static ULONG WINAPI
sample_grabber_stream_type_handler_Release(IMFMediaTypeHandler
*iface
)
581 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
582 return IMFStreamSink_Release(&grabber
->IMFStreamSink_iface
);
585 static HRESULT
sample_grabber_stream_is_media_type_supported(struct sample_grabber
*grabber
, IMFMediaType
*in_type
)
587 const DWORD supported_flags
= MF_MEDIATYPE_EQUAL_MAJOR_TYPES
| MF_MEDIATYPE_EQUAL_FORMAT_TYPES
|
588 MF_MEDIATYPE_EQUAL_FORMAT_DATA
;
591 if (grabber
->is_shut_down
)
592 return MF_E_STREAMSINK_REMOVED
;
597 if (IMFMediaType_IsEqual(grabber
->media_type
, in_type
, &flags
) == S_OK
)
600 return (flags
& supported_flags
) == supported_flags
? S_OK
: MF_E_INVALIDMEDIATYPE
;
603 static HRESULT WINAPI
sample_grabber_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler
*iface
,
604 IMFMediaType
*in_type
, IMFMediaType
**out_type
)
606 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
608 TRACE("%p, %p, %p.\n", iface
, in_type
, out_type
);
610 return sample_grabber_stream_is_media_type_supported(grabber
, in_type
);
613 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler
*iface
, DWORD
*count
)
615 TRACE("%p, %p.\n", iface
, count
);
625 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
*iface
, DWORD index
,
626 IMFMediaType
**media_type
)
628 TRACE("%p, %lu, %p.\n", iface
, index
, media_type
);
633 return MF_E_NO_MORE_TYPES
;
636 static HRESULT WINAPI
sample_grabber_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler
*iface
,
637 IMFMediaType
*media_type
)
639 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
642 TRACE("%p, %p.\n", iface
, media_type
);
644 if (FAILED(hr
= sample_grabber_stream_is_media_type_supported(grabber
, media_type
)))
647 IMFMediaType_Release(grabber
->current_media_type
);
648 grabber
->current_media_type
= media_type
;
649 IMFMediaType_AddRef(grabber
->current_media_type
);
654 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler
*iface
,
655 IMFMediaType
**media_type
)
657 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
660 TRACE("%p, %p.\n", iface
, media_type
);
665 EnterCriticalSection(&grabber
->cs
);
667 if (grabber
->is_shut_down
)
669 hr
= MF_E_STREAMSINK_REMOVED
;
673 *media_type
= grabber
->current_media_type
;
674 IMFMediaType_AddRef(*media_type
);
677 LeaveCriticalSection(&grabber
->cs
);
682 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
684 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
687 TRACE("%p, %p.\n", iface
, type
);
692 EnterCriticalSection(&grabber
->cs
);
694 if (grabber
->is_shut_down
)
695 hr
= MF_E_STREAMSINK_REMOVED
;
697 hr
= IMFMediaType_GetMajorType(grabber
->current_media_type
, type
);
699 LeaveCriticalSection(&grabber
->cs
);
704 static const IMFMediaTypeHandlerVtbl sample_grabber_stream_type_handler_vtbl
=
706 sample_grabber_stream_type_handler_QueryInterface
,
707 sample_grabber_stream_type_handler_AddRef
,
708 sample_grabber_stream_type_handler_Release
,
709 sample_grabber_stream_type_handler_IsMediaTypeSupported
,
710 sample_grabber_stream_type_handler_GetMediaTypeCount
,
711 sample_grabber_stream_type_handler_GetMediaTypeByIndex
,
712 sample_grabber_stream_type_handler_SetCurrentMediaType
,
713 sample_grabber_stream_type_handler_GetCurrentMediaType
,
714 sample_grabber_stream_type_handler_GetMajorType
,
717 static HRESULT WINAPI
sample_grabber_stream_timer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
,
720 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) || IsEqualIID(riid
, &IID_IUnknown
))
723 IMFAsyncCallback_AddRef(iface
);
727 WARN("Unsupported %s.\n", debugstr_guid(riid
));
729 return E_NOINTERFACE
;
732 static ULONG WINAPI
sample_grabber_stream_timer_callback_AddRef(IMFAsyncCallback
*iface
)
734 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
735 return IMFStreamSink_AddRef(&grabber
->IMFStreamSink_iface
);
738 static ULONG WINAPI
sample_grabber_stream_timer_callback_Release(IMFAsyncCallback
*iface
)
740 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
741 return IMFStreamSink_Release(&grabber
->IMFStreamSink_iface
);
744 static HRESULT WINAPI
sample_grabber_stream_timer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
,
750 static HRESULT WINAPI
sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
752 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
753 BOOL sample_reported
= FALSE
, sample_delivered
= FALSE
;
754 struct scheduled_item
*item
, *item2
;
757 EnterCriticalSection(&grabber
->cs
);
759 LIST_FOR_EACH_ENTRY_SAFE(item
, item2
, &grabber
->items
, struct scheduled_item
, entry
)
761 if (item
->type
== ITEM_TYPE_MARKER
)
763 sample_grabber_stream_report_marker(grabber
, &item
->u
.marker
.context
, S_OK
);
764 stream_release_pending_item(item
);
766 else if (item
->type
== ITEM_TYPE_SAMPLE
)
768 if (!sample_reported
)
770 if (FAILED(hr
= sample_grabber_report_sample(grabber
, item
->u
.sample
, &sample_delivered
)))
771 WARN("Failed to report a sample, hr %#lx.\n", hr
);
772 stream_release_pending_item(item
);
773 sample_reported
= TRUE
;
777 if (FAILED(hr
= stream_schedule_sample(grabber
, item
)))
778 WARN("Failed to schedule a sample, hr %#lx.\n", hr
);
783 if (sample_delivered
)
784 sample_grabber_stream_request_sample(grabber
);
786 LeaveCriticalSection(&grabber
->cs
);
791 static const IMFAsyncCallbackVtbl sample_grabber_stream_timer_callback_vtbl
=
793 sample_grabber_stream_timer_callback_QueryInterface
,
794 sample_grabber_stream_timer_callback_AddRef
,
795 sample_grabber_stream_timer_callback_Release
,
796 sample_grabber_stream_timer_callback_GetParameters
,
797 sample_grabber_stream_timer_callback_Invoke
,
800 static HRESULT WINAPI
sample_grabber_sink_QueryInterface(IMFMediaSink
*iface
, REFIID riid
, void **obj
)
802 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
804 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
806 if (IsEqualIID(riid
, &IID_IMFMediaSink
) ||
807 IsEqualIID(riid
, &IID_IUnknown
))
809 *obj
= &grabber
->IMFMediaSink_iface
;
811 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
813 *obj
= &grabber
->IMFClockStateSink_iface
;
815 else if (IsEqualIID(riid
, &IID_IMFMediaEventGenerator
))
817 *obj
= &grabber
->IMFMediaEventGenerator_iface
;
819 else if (IsEqualIID(riid
, &IID_IMFGetService
))
821 *obj
= &grabber
->IMFGetService_iface
;
823 else if (IsEqualIID(riid
, &IID_IMFRateSupport
))
825 *obj
= &grabber
->IMFRateSupport_iface
;
829 WARN("Unsupported %s.\n", debugstr_guid(riid
));
831 return E_NOINTERFACE
;
834 IUnknown_AddRef((IUnknown
*)*obj
);
839 static ULONG WINAPI
sample_grabber_sink_AddRef(IMFMediaSink
*iface
)
841 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
842 ULONG refcount
= InterlockedIncrement(&grabber
->refcount
);
844 TRACE("%p, refcount %lu.\n", iface
, refcount
);
849 static void sample_grabber_release_pending_items(struct sample_grabber
*grabber
)
851 struct scheduled_item
*item
, *next_item
;
853 LIST_FOR_EACH_ENTRY_SAFE(item
, next_item
, &grabber
->items
, struct scheduled_item
, entry
)
855 stream_release_pending_item(item
);
859 static void release_samples(struct sample_grabber
*grabber
)
863 for (i
= 0; i
< MAX_SAMPLE_QUEUE_LENGTH
; ++i
)
865 if (grabber
->samples
[i
])
867 IMFSample_Release(grabber
->samples
[i
]);
868 grabber
->samples
[i
] = NULL
;
873 static ULONG WINAPI
sample_grabber_sink_Release(IMFMediaSink
*iface
)
875 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
876 ULONG refcount
= InterlockedDecrement(&grabber
->refcount
);
878 TRACE("%p, refcount %lu.\n", iface
, refcount
);
882 if (grabber
->callback
)
883 IMFSampleGrabberSinkCallback_Release(grabber
->callback
);
884 if (grabber
->callback2
)
885 IMFSampleGrabberSinkCallback2_Release(grabber
->callback2
);
886 if (grabber
->current_media_type
)
887 IMFMediaType_Release(grabber
->current_media_type
);
888 IMFMediaType_Release(grabber
->media_type
);
889 if (grabber
->event_queue
)
890 IMFMediaEventQueue_Release(grabber
->event_queue
);
892 IMFPresentationClock_Release(grabber
->clock
);
894 IMFTimer_Release(grabber
->timer
);
895 if (grabber
->cancel_key
)
896 IUnknown_Release(grabber
->cancel_key
);
897 if (grabber
->stream_event_queue
)
899 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
900 IMFMediaEventQueue_Release(grabber
->stream_event_queue
);
902 if (grabber
->sample_attributes
)
903 IMFAttributes_Release(grabber
->sample_attributes
);
904 sample_grabber_release_pending_items(grabber
);
905 release_samples(grabber
);
906 DeleteCriticalSection(&grabber
->cs
);
913 static HRESULT WINAPI
sample_grabber_sink_GetCharacteristics(IMFMediaSink
*iface
, DWORD
*flags
)
915 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
917 TRACE("%p, %p.\n", iface
, flags
);
919 if (grabber
->is_shut_down
)
920 return MF_E_SHUTDOWN
;
922 *flags
= MEDIASINK_FIXED_STREAMS
;
923 if (grabber
->ignore_clock
)
924 *flags
|= MEDIASINK_RATELESS
;
929 static HRESULT WINAPI
sample_grabber_sink_AddStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
,
930 IMFMediaType
*media_type
, IMFStreamSink
**stream_sink
)
932 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
934 TRACE("%p, %#lx, %p, %p.\n", iface
, stream_sink_id
, media_type
, stream_sink
);
936 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
939 static HRESULT WINAPI
sample_grabber_sink_RemoveStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
)
941 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
943 TRACE("%p, %#lx.\n", iface
, stream_sink_id
);
945 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
948 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkCount(IMFMediaSink
*iface
, DWORD
*count
)
950 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
952 TRACE("%p, %p.\n", iface
, count
);
954 if (grabber
->is_shut_down
)
955 return MF_E_SHUTDOWN
;
962 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink
*iface
, DWORD index
,
963 IMFStreamSink
**stream
)
965 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
968 TRACE("%p, %lu, %p.\n", iface
, index
, stream
);
970 EnterCriticalSection(&grabber
->cs
);
972 if (grabber
->is_shut_down
)
975 hr
= MF_E_INVALIDINDEX
;
978 *stream
= &grabber
->IMFStreamSink_iface
;
979 IMFStreamSink_AddRef(*stream
);
982 LeaveCriticalSection(&grabber
->cs
);
987 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkById(IMFMediaSink
*iface
, DWORD stream_sink_id
,
988 IMFStreamSink
**stream
)
990 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
993 TRACE("%p, %#lx, %p.\n", iface
, stream_sink_id
, stream
);
995 EnterCriticalSection(&grabber
->cs
);
997 if (grabber
->is_shut_down
)
999 else if (stream_sink_id
> 0)
1000 hr
= MF_E_INVALIDSTREAMNUMBER
;
1003 *stream
= &grabber
->IMFStreamSink_iface
;
1004 IMFStreamSink_AddRef(*stream
);
1007 LeaveCriticalSection(&grabber
->cs
);
1012 static void sample_grabber_cancel_timer(struct sample_grabber
*grabber
)
1014 if (grabber
->timer
&& grabber
->cancel_key
)
1016 IMFTimer_CancelTimer(grabber
->timer
, grabber
->cancel_key
);
1017 IUnknown_Release(grabber
->cancel_key
);
1018 grabber
->cancel_key
= NULL
;
1022 static HRESULT
sample_grabber_set_presentation_clock(struct sample_grabber
*grabber
, IMFPresentationClock
*clock
)
1026 if (FAILED(hr
= IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber
), clock
)))
1031 sample_grabber_cancel_timer(grabber
);
1032 IMFPresentationClock_RemoveClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
1033 IMFPresentationClock_Release(grabber
->clock
);
1036 IMFTimer_Release(grabber
->timer
);
1037 grabber
->timer
= NULL
;
1040 grabber
->clock
= clock
;
1043 IMFPresentationClock_AddRef(grabber
->clock
);
1044 IMFPresentationClock_AddClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
1045 if (FAILED(IMFPresentationClock_QueryInterface(grabber
->clock
, &IID_IMFTimer
, (void **)&grabber
->timer
)))
1047 WARN("Failed to get IMFTimer interface.\n");
1048 grabber
->timer
= NULL
;
1055 static HRESULT WINAPI
sample_grabber_sink_SetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
*clock
)
1057 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1060 TRACE("%p, %p.\n", iface
, clock
);
1062 EnterCriticalSection(&grabber
->cs
);
1064 if (grabber
->is_shut_down
)
1070 hr
= sample_grabber_set_presentation_clock(grabber
, clock
);
1073 LeaveCriticalSection(&grabber
->cs
);
1078 static HRESULT WINAPI
sample_grabber_sink_GetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
**clock
)
1080 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1083 TRACE("%p, %p.\n", iface
, clock
);
1088 EnterCriticalSection(&grabber
->cs
);
1092 *clock
= grabber
->clock
;
1093 IMFPresentationClock_AddRef(*clock
);
1098 LeaveCriticalSection(&grabber
->cs
);
1103 static HRESULT WINAPI
sample_grabber_sink_Shutdown(IMFMediaSink
*iface
)
1105 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1108 TRACE("%p.\n", iface
);
1110 EnterCriticalSection(&grabber
->cs
);
1112 if (grabber
->is_shut_down
)
1116 grabber
->is_shut_down
= TRUE
;
1117 sample_grabber_release_pending_items(grabber
);
1118 if (SUCCEEDED(hr
= sample_grabber_set_presentation_clock(grabber
, NULL
)))
1119 hr
= IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber
));
1122 IMFMediaType_Release(grabber
->current_media_type
);
1123 grabber
->current_media_type
= NULL
;
1124 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
1125 IMFMediaEventQueue_Shutdown(grabber
->event_queue
);
1129 LeaveCriticalSection(&grabber
->cs
);
1134 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl
=
1136 sample_grabber_sink_QueryInterface
,
1137 sample_grabber_sink_AddRef
,
1138 sample_grabber_sink_Release
,
1139 sample_grabber_sink_GetCharacteristics
,
1140 sample_grabber_sink_AddStreamSink
,
1141 sample_grabber_sink_RemoveStreamSink
,
1142 sample_grabber_sink_GetStreamSinkCount
,
1143 sample_grabber_sink_GetStreamSinkByIndex
,
1144 sample_grabber_sink_GetStreamSinkById
,
1145 sample_grabber_sink_SetPresentationClock
,
1146 sample_grabber_sink_GetPresentationClock
,
1147 sample_grabber_sink_Shutdown
,
1150 static HRESULT WINAPI
sample_grabber_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
1152 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1153 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1156 static ULONG WINAPI
sample_grabber_clock_sink_AddRef(IMFClockStateSink
*iface
)
1158 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1159 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1162 static ULONG WINAPI
sample_grabber_clock_sink_Release(IMFClockStateSink
*iface
)
1164 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1165 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1168 static HRESULT
sample_grabber_set_state(struct sample_grabber
*grabber
, enum sink_state state
,
1169 MFTIME systime
, LONGLONG offset
)
1171 static const DWORD events
[] =
1173 MEStreamSinkStopped
, /* SINK_STATE_STOPPED */
1174 MEStreamSinkPaused
, /* SINK_STATE_PAUSED */
1175 MEStreamSinkStarted
, /* SINK_STATE_RUNNING */
1177 BOOL do_callback
= FALSE
;
1181 EnterCriticalSection(&grabber
->cs
);
1183 if (!grabber
->is_shut_down
)
1185 if (state
== SINK_STATE_PAUSED
&& grabber
->state
== SINK_STATE_STOPPED
)
1186 hr
= MF_E_INVALID_STATE_TRANSITION
;
1189 if (state
== SINK_STATE_STOPPED
)
1191 sample_grabber_cancel_timer(grabber
);
1192 release_samples(grabber
);
1193 grabber
->sample_count
= MAX_SAMPLE_QUEUE_LENGTH
;
1196 if (state
== SINK_STATE_RUNNING
&& grabber
->state
!= SINK_STATE_RUNNING
)
1198 /* Every transition to running state sends a bunch requests to build up initial queue. */
1199 for (i
= 0; i
< grabber
->sample_count
; ++i
)
1201 if (grabber
->state
== SINK_STATE_PAUSED
&& offset
== PRESENTATION_CURRENT_POSITION
)
1203 assert(grabber
->samples
[i
]);
1204 stream_queue_sample(grabber
, grabber
->samples
[i
]);
1208 sample_grabber_stream_request_sample(grabber
);
1211 release_samples(grabber
);
1212 grabber
->sample_count
= 0;
1215 do_callback
= state
!= grabber
->state
|| state
!= SINK_STATE_PAUSED
;
1218 if (grabber
->rate
== 0.0f
&& state
== SINK_STATE_RUNNING
)
1219 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkScrubSampleComplete
,
1220 &GUID_NULL
, S_OK
, NULL
);
1222 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, events
[state
], &GUID_NULL
, S_OK
, NULL
);
1224 grabber
->state
= state
;
1228 LeaveCriticalSection(&grabber
->cs
);
1234 case SINK_STATE_STOPPED
:
1235 hr
= IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber
), systime
);
1237 case SINK_STATE_PAUSED
:
1238 hr
= IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber
), systime
);
1240 case SINK_STATE_RUNNING
:
1241 hr
= IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber
), systime
, offset
);
1249 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
1251 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1253 TRACE("%p, %s, %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
1255 return sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
, systime
, offset
);
1258 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
1260 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1262 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1264 return sample_grabber_set_state(grabber
, SINK_STATE_STOPPED
, systime
, 0);
1267 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
1269 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1271 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1273 return sample_grabber_set_state(grabber
, SINK_STATE_PAUSED
, systime
, 0);
1276 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
1278 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1280 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1282 return sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
, systime
, PRESENTATION_CURRENT_POSITION
);
1285 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
1287 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1290 TRACE("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
1292 EnterCriticalSection(&grabber
->cs
);
1294 if (grabber
->is_shut_down
)
1298 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkRateChanged
, &GUID_NULL
, S_OK
, NULL
);
1299 grabber
->rate
= rate
;
1302 LeaveCriticalSection(&grabber
->cs
);
1305 hr
= IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber
), systime
, rate
);
1310 static HRESULT WINAPI
sample_grabber_events_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
1312 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1313 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1316 static ULONG WINAPI
sample_grabber_events_AddRef(IMFMediaEventGenerator
*iface
)
1318 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1319 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1322 static ULONG WINAPI
sample_grabber_events_Release(IMFMediaEventGenerator
*iface
)
1324 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1325 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1328 static HRESULT WINAPI
sample_grabber_events_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1330 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1332 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
1334 return IMFMediaEventQueue_GetEvent(grabber
->event_queue
, flags
, event
);
1337 static HRESULT WINAPI
sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
1340 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1342 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1344 return IMFMediaEventQueue_BeginGetEvent(grabber
->event_queue
, callback
, state
);
1347 static HRESULT WINAPI
sample_grabber_events_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
1348 IMFMediaEvent
**event
)
1350 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1352 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1354 return IMFMediaEventQueue_EndGetEvent(grabber
->event_queue
, result
, event
);
1357 static HRESULT WINAPI
sample_grabber_events_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
1358 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
1360 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1362 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1364 return IMFMediaEventQueue_QueueEventParamVar(grabber
->event_queue
, event_type
, ext_type
, hr
, value
);
1367 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl
=
1369 sample_grabber_events_QueryInterface
,
1370 sample_grabber_events_AddRef
,
1371 sample_grabber_events_Release
,
1372 sample_grabber_events_GetEvent
,
1373 sample_grabber_events_BeginGetEvent
,
1374 sample_grabber_events_EndGetEvent
,
1375 sample_grabber_events_QueueEvent
,
1378 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl
=
1380 sample_grabber_clock_sink_QueryInterface
,
1381 sample_grabber_clock_sink_AddRef
,
1382 sample_grabber_clock_sink_Release
,
1383 sample_grabber_clock_sink_OnClockStart
,
1384 sample_grabber_clock_sink_OnClockStop
,
1385 sample_grabber_clock_sink_OnClockPause
,
1386 sample_grabber_clock_sink_OnClockRestart
,
1387 sample_grabber_clock_sink_OnClockSetRate
,
1390 static HRESULT WINAPI
sample_grabber_getservice_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1392 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1393 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1396 static ULONG WINAPI
sample_grabber_getservice_AddRef(IMFGetService
*iface
)
1398 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1399 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1402 static ULONG WINAPI
sample_grabber_getservice_Release(IMFGetService
*iface
)
1404 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1405 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1408 static HRESULT WINAPI
sample_grabber_getservice_GetService(IMFGetService
*iface
, REFGUID service
,
1409 REFIID riid
, void **obj
)
1411 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1413 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1415 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1416 return IMFGetService_QueryInterface(iface
, riid
, obj
);
1418 return E_NOINTERFACE
;
1421 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service
), debugstr_guid(riid
));
1423 return MF_E_UNSUPPORTED_SERVICE
;
1426 static const IMFGetServiceVtbl sample_grabber_getservice_vtbl
=
1428 sample_grabber_getservice_QueryInterface
,
1429 sample_grabber_getservice_AddRef
,
1430 sample_grabber_getservice_Release
,
1431 sample_grabber_getservice_GetService
,
1434 static HRESULT WINAPI
sample_grabber_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
1436 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1437 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1440 static ULONG WINAPI
sample_grabber_rate_support_AddRef(IMFRateSupport
*iface
)
1442 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1443 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1446 static ULONG WINAPI
sample_grabber_rate_support_Release(IMFRateSupport
*iface
)
1448 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1449 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1452 static HRESULT WINAPI
sample_grabber_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1453 BOOL thin
, float *rate
)
1455 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1462 static HRESULT WINAPI
sample_grabber_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1463 BOOL thin
, float *rate
)
1465 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1467 *rate
= direction
== MFRATE_REVERSE
? -FLT_MAX
: FLT_MAX
;
1472 static HRESULT WINAPI
sample_grabber_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
1475 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, ret_rate
);
1483 static const IMFRateSupportVtbl sample_grabber_rate_support_vtbl
=
1485 sample_grabber_rate_support_QueryInterface
,
1486 sample_grabber_rate_support_AddRef
,
1487 sample_grabber_rate_support_Release
,
1488 sample_grabber_rate_support_GetSlowestRate
,
1489 sample_grabber_rate_support_GetFastestRate
,
1490 sample_grabber_rate_support_IsRateSupported
,
1493 static HRESULT
sample_grabber_create_object(IMFAttributes
*attributes
, void *user_context
, IUnknown
**obj
)
1495 struct sample_grabber_activate_context
*context
= user_context
;
1496 struct sample_grabber
*object
;
1500 TRACE("%p, %p, %p.\n", attributes
, user_context
, obj
);
1502 if (context
->shut_down
)
1503 return MF_E_SHUTDOWN
;
1505 /* At least major type is required. */
1506 if (FAILED(IMFMediaType_GetMajorType(context
->media_type
, &guid
)))
1507 return MF_E_INVALIDMEDIATYPE
;
1509 if (!(object
= calloc(1, sizeof(*object
))))
1510 return E_OUTOFMEMORY
;
1512 object
->IMFMediaSink_iface
.lpVtbl
= &sample_grabber_sink_vtbl
;
1513 object
->IMFClockStateSink_iface
.lpVtbl
= &sample_grabber_clock_sink_vtbl
;
1514 object
->IMFMediaEventGenerator_iface
.lpVtbl
= &sample_grabber_sink_events_vtbl
;
1515 object
->IMFGetService_iface
.lpVtbl
= &sample_grabber_getservice_vtbl
;
1516 object
->IMFRateSupport_iface
.lpVtbl
= &sample_grabber_rate_support_vtbl
;
1517 object
->IMFStreamSink_iface
.lpVtbl
= &sample_grabber_stream_vtbl
;
1518 object
->IMFMediaTypeHandler_iface
.lpVtbl
= &sample_grabber_stream_type_handler_vtbl
;
1519 object
->timer_callback
.lpVtbl
= &sample_grabber_stream_timer_callback_vtbl
;
1520 object
->sample_count
= MAX_SAMPLE_QUEUE_LENGTH
;
1521 object
->refcount
= 1;
1522 object
->rate
= 1.0f
;
1523 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context
->callback
, &IID_IMFSampleGrabberSinkCallback2
,
1524 (void **)&object
->callback2
)))
1526 object
->callback
= context
->callback
;
1527 IMFSampleGrabberSinkCallback_AddRef(object
->callback
);
1529 object
->media_type
= context
->media_type
;
1530 IMFMediaType_AddRef(object
->media_type
);
1531 object
->current_media_type
= context
->media_type
;
1532 IMFMediaType_AddRef(object
->current_media_type
);
1533 IMFAttributes_GetUINT32(attributes
, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK
, &object
->ignore_clock
);
1534 IMFAttributes_GetUINT64(attributes
, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET
, &object
->sample_time_offset
);
1535 list_init(&object
->items
);
1536 InitializeCriticalSection(&object
->cs
);
1538 if (FAILED(hr
= MFCreateEventQueue(&object
->stream_event_queue
)))
1541 if (FAILED(hr
= MFCreateAttributes(&object
->sample_attributes
, 0)))
1544 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1547 *obj
= (IUnknown
*)&object
->IMFMediaSink_iface
;
1549 TRACE("Created %p.\n", *obj
);
1555 IMFMediaSink_Release(&object
->IMFMediaSink_iface
);
1560 static void sample_grabber_shutdown_object(void *user_context
, IUnknown
*obj
)
1562 struct sample_grabber_activate_context
*context
= user_context
;
1563 context
->shut_down
= TRUE
;
1566 static const struct activate_funcs sample_grabber_activate_funcs
=
1568 sample_grabber_create_object
,
1569 sample_grabber_shutdown_object
,
1570 sample_grabber_free_private
,
1573 /***********************************************************************
1574 * MFCreateSampleGrabberSinkActivate (mf.@)
1576 HRESULT WINAPI
MFCreateSampleGrabberSinkActivate(IMFMediaType
*media_type
, IMFSampleGrabberSinkCallback
*callback
,
1577 IMFActivate
**activate
)
1579 struct sample_grabber_activate_context
*context
;
1582 TRACE("%p, %p, %p.\n", media_type
, callback
, activate
);
1584 if (!media_type
|| !callback
|| !activate
)
1587 if (!(context
= calloc(1, sizeof(*context
))))
1588 return E_OUTOFMEMORY
;
1590 context
->media_type
= media_type
;
1591 IMFMediaType_AddRef(context
->media_type
);
1592 context
->callback
= callback
;
1593 IMFSampleGrabberSinkCallback_AddRef(context
->callback
);
1595 if (FAILED(hr
= create_activation_object(context
, &sample_grabber_activate_funcs
, activate
)))
1596 sample_grabber_free_private(context
);