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
);
659 TRACE("%p, %p.\n", iface
, media_type
);
664 if (grabber
->is_shut_down
)
665 return MF_E_STREAMSINK_REMOVED
;
667 *media_type
= grabber
->current_media_type
;
668 IMFMediaType_AddRef(*media_type
);
673 static HRESULT WINAPI
sample_grabber_stream_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
675 struct sample_grabber
*grabber
= impl_from_IMFMediaTypeHandler(iface
);
677 TRACE("%p, %p.\n", iface
, type
);
682 if (grabber
->is_shut_down
)
683 return MF_E_STREAMSINK_REMOVED
;
685 return IMFMediaType_GetMajorType(grabber
->current_media_type
, type
);
688 static const IMFMediaTypeHandlerVtbl sample_grabber_stream_type_handler_vtbl
=
690 sample_grabber_stream_type_handler_QueryInterface
,
691 sample_grabber_stream_type_handler_AddRef
,
692 sample_grabber_stream_type_handler_Release
,
693 sample_grabber_stream_type_handler_IsMediaTypeSupported
,
694 sample_grabber_stream_type_handler_GetMediaTypeCount
,
695 sample_grabber_stream_type_handler_GetMediaTypeByIndex
,
696 sample_grabber_stream_type_handler_SetCurrentMediaType
,
697 sample_grabber_stream_type_handler_GetCurrentMediaType
,
698 sample_grabber_stream_type_handler_GetMajorType
,
701 static HRESULT WINAPI
sample_grabber_stream_timer_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
,
704 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) || IsEqualIID(riid
, &IID_IUnknown
))
707 IMFAsyncCallback_AddRef(iface
);
711 WARN("Unsupported %s.\n", debugstr_guid(riid
));
713 return E_NOINTERFACE
;
716 static ULONG WINAPI
sample_grabber_stream_timer_callback_AddRef(IMFAsyncCallback
*iface
)
718 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
719 return IMFStreamSink_AddRef(&grabber
->IMFStreamSink_iface
);
722 static ULONG WINAPI
sample_grabber_stream_timer_callback_Release(IMFAsyncCallback
*iface
)
724 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
725 return IMFStreamSink_Release(&grabber
->IMFStreamSink_iface
);
728 static HRESULT WINAPI
sample_grabber_stream_timer_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
,
734 static HRESULT WINAPI
sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
736 struct sample_grabber
*grabber
= impl_from_IMFAsyncCallback(iface
);
737 BOOL sample_reported
= FALSE
, sample_delivered
= FALSE
;
738 struct scheduled_item
*item
, *item2
;
741 EnterCriticalSection(&grabber
->cs
);
743 LIST_FOR_EACH_ENTRY_SAFE(item
, item2
, &grabber
->items
, struct scheduled_item
, entry
)
745 if (item
->type
== ITEM_TYPE_MARKER
)
747 sample_grabber_stream_report_marker(grabber
, &item
->u
.marker
.context
, S_OK
);
748 stream_release_pending_item(item
);
750 else if (item
->type
== ITEM_TYPE_SAMPLE
)
752 if (!sample_reported
)
754 if (FAILED(hr
= sample_grabber_report_sample(grabber
, item
->u
.sample
, &sample_delivered
)))
755 WARN("Failed to report a sample, hr %#lx.\n", hr
);
756 stream_release_pending_item(item
);
757 sample_reported
= TRUE
;
761 if (FAILED(hr
= stream_schedule_sample(grabber
, item
)))
762 WARN("Failed to schedule a sample, hr %#lx.\n", hr
);
767 if (sample_delivered
)
768 sample_grabber_stream_request_sample(grabber
);
770 LeaveCriticalSection(&grabber
->cs
);
775 static const IMFAsyncCallbackVtbl sample_grabber_stream_timer_callback_vtbl
=
777 sample_grabber_stream_timer_callback_QueryInterface
,
778 sample_grabber_stream_timer_callback_AddRef
,
779 sample_grabber_stream_timer_callback_Release
,
780 sample_grabber_stream_timer_callback_GetParameters
,
781 sample_grabber_stream_timer_callback_Invoke
,
784 static HRESULT WINAPI
sample_grabber_sink_QueryInterface(IMFMediaSink
*iface
, REFIID riid
, void **obj
)
786 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
788 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
790 if (IsEqualIID(riid
, &IID_IMFMediaSink
) ||
791 IsEqualIID(riid
, &IID_IUnknown
))
793 *obj
= &grabber
->IMFMediaSink_iface
;
795 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
797 *obj
= &grabber
->IMFClockStateSink_iface
;
799 else if (IsEqualIID(riid
, &IID_IMFMediaEventGenerator
))
801 *obj
= &grabber
->IMFMediaEventGenerator_iface
;
803 else if (IsEqualIID(riid
, &IID_IMFGetService
))
805 *obj
= &grabber
->IMFGetService_iface
;
807 else if (IsEqualIID(riid
, &IID_IMFRateSupport
))
809 *obj
= &grabber
->IMFRateSupport_iface
;
813 WARN("Unsupported %s.\n", debugstr_guid(riid
));
815 return E_NOINTERFACE
;
818 IUnknown_AddRef((IUnknown
*)*obj
);
823 static ULONG WINAPI
sample_grabber_sink_AddRef(IMFMediaSink
*iface
)
825 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
826 ULONG refcount
= InterlockedIncrement(&grabber
->refcount
);
828 TRACE("%p, refcount %lu.\n", iface
, refcount
);
833 static void sample_grabber_release_pending_items(struct sample_grabber
*grabber
)
835 struct scheduled_item
*item
, *next_item
;
837 LIST_FOR_EACH_ENTRY_SAFE(item
, next_item
, &grabber
->items
, struct scheduled_item
, entry
)
839 stream_release_pending_item(item
);
843 static void release_samples(struct sample_grabber
*grabber
)
847 for (i
= 0; i
< MAX_SAMPLE_QUEUE_LENGTH
; ++i
)
849 if (grabber
->samples
[i
])
851 IMFSample_Release(grabber
->samples
[i
]);
852 grabber
->samples
[i
] = NULL
;
857 static ULONG WINAPI
sample_grabber_sink_Release(IMFMediaSink
*iface
)
859 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
860 ULONG refcount
= InterlockedDecrement(&grabber
->refcount
);
862 TRACE("%p, refcount %lu.\n", iface
, refcount
);
866 if (grabber
->callback
)
867 IMFSampleGrabberSinkCallback_Release(grabber
->callback
);
868 if (grabber
->callback2
)
869 IMFSampleGrabberSinkCallback2_Release(grabber
->callback2
);
870 IMFMediaType_Release(grabber
->current_media_type
);
871 IMFMediaType_Release(grabber
->media_type
);
872 if (grabber
->event_queue
)
873 IMFMediaEventQueue_Release(grabber
->event_queue
);
875 IMFPresentationClock_Release(grabber
->clock
);
877 IMFTimer_Release(grabber
->timer
);
878 if (grabber
->cancel_key
)
879 IUnknown_Release(grabber
->cancel_key
);
880 if (grabber
->stream_event_queue
)
882 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
883 IMFMediaEventQueue_Release(grabber
->stream_event_queue
);
885 if (grabber
->sample_attributes
)
886 IMFAttributes_Release(grabber
->sample_attributes
);
887 sample_grabber_release_pending_items(grabber
);
888 release_samples(grabber
);
889 DeleteCriticalSection(&grabber
->cs
);
896 static HRESULT WINAPI
sample_grabber_sink_GetCharacteristics(IMFMediaSink
*iface
, DWORD
*flags
)
898 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
900 TRACE("%p, %p.\n", iface
, flags
);
902 if (grabber
->is_shut_down
)
903 return MF_E_SHUTDOWN
;
905 *flags
= MEDIASINK_FIXED_STREAMS
;
906 if (grabber
->ignore_clock
)
907 *flags
|= MEDIASINK_RATELESS
;
912 static HRESULT WINAPI
sample_grabber_sink_AddStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
,
913 IMFMediaType
*media_type
, IMFStreamSink
**stream_sink
)
915 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
917 TRACE("%p, %#lx, %p, %p.\n", iface
, stream_sink_id
, media_type
, stream_sink
);
919 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
922 static HRESULT WINAPI
sample_grabber_sink_RemoveStreamSink(IMFMediaSink
*iface
, DWORD stream_sink_id
)
924 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
926 TRACE("%p, %#lx.\n", iface
, stream_sink_id
);
928 return grabber
->is_shut_down
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
931 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkCount(IMFMediaSink
*iface
, DWORD
*count
)
933 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
935 TRACE("%p, %p.\n", iface
, count
);
937 if (grabber
->is_shut_down
)
938 return MF_E_SHUTDOWN
;
945 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink
*iface
, DWORD index
,
946 IMFStreamSink
**stream
)
948 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
951 TRACE("%p, %lu, %p.\n", iface
, index
, stream
);
953 EnterCriticalSection(&grabber
->cs
);
955 if (grabber
->is_shut_down
)
958 hr
= MF_E_INVALIDINDEX
;
961 *stream
= &grabber
->IMFStreamSink_iface
;
962 IMFStreamSink_AddRef(*stream
);
965 LeaveCriticalSection(&grabber
->cs
);
970 static HRESULT WINAPI
sample_grabber_sink_GetStreamSinkById(IMFMediaSink
*iface
, DWORD stream_sink_id
,
971 IMFStreamSink
**stream
)
973 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
976 TRACE("%p, %#lx, %p.\n", iface
, stream_sink_id
, stream
);
978 EnterCriticalSection(&grabber
->cs
);
980 if (grabber
->is_shut_down
)
982 else if (stream_sink_id
> 0)
983 hr
= MF_E_INVALIDSTREAMNUMBER
;
986 *stream
= &grabber
->IMFStreamSink_iface
;
987 IMFStreamSink_AddRef(*stream
);
990 LeaveCriticalSection(&grabber
->cs
);
995 static void sample_grabber_cancel_timer(struct sample_grabber
*grabber
)
997 if (grabber
->timer
&& grabber
->cancel_key
)
999 IMFTimer_CancelTimer(grabber
->timer
, grabber
->cancel_key
);
1000 IUnknown_Release(grabber
->cancel_key
);
1001 grabber
->cancel_key
= NULL
;
1005 static void sample_grabber_set_presentation_clock(struct sample_grabber
*grabber
, IMFPresentationClock
*clock
)
1009 sample_grabber_cancel_timer(grabber
);
1010 IMFPresentationClock_RemoveClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
1011 IMFPresentationClock_Release(grabber
->clock
);
1014 IMFTimer_Release(grabber
->timer
);
1015 grabber
->timer
= NULL
;
1018 grabber
->clock
= clock
;
1021 IMFPresentationClock_AddRef(grabber
->clock
);
1022 IMFPresentationClock_AddClockStateSink(grabber
->clock
, &grabber
->IMFClockStateSink_iface
);
1023 if (FAILED(IMFPresentationClock_QueryInterface(grabber
->clock
, &IID_IMFTimer
, (void **)&grabber
->timer
)))
1025 WARN("Failed to get IMFTimer interface.\n");
1026 grabber
->timer
= NULL
;
1031 static HRESULT WINAPI
sample_grabber_sink_SetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
*clock
)
1033 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1036 TRACE("%p, %p.\n", iface
, clock
);
1038 EnterCriticalSection(&grabber
->cs
);
1040 if (SUCCEEDED(hr
= IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber
),
1043 sample_grabber_set_presentation_clock(grabber
, clock
);
1046 LeaveCriticalSection(&grabber
->cs
);
1051 static HRESULT WINAPI
sample_grabber_sink_GetPresentationClock(IMFMediaSink
*iface
, IMFPresentationClock
**clock
)
1053 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1056 TRACE("%p, %p.\n", iface
, clock
);
1061 EnterCriticalSection(&grabber
->cs
);
1065 *clock
= grabber
->clock
;
1066 IMFPresentationClock_AddRef(*clock
);
1071 LeaveCriticalSection(&grabber
->cs
);
1076 static HRESULT WINAPI
sample_grabber_sink_Shutdown(IMFMediaSink
*iface
)
1078 struct sample_grabber
*grabber
= impl_from_IMFMediaSink(iface
);
1081 TRACE("%p.\n", iface
);
1083 EnterCriticalSection(&grabber
->cs
);
1085 if (grabber
->is_shut_down
)
1089 grabber
->is_shut_down
= TRUE
;
1090 sample_grabber_release_pending_items(grabber
);
1091 if (SUCCEEDED(hr
= IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber
))))
1093 sample_grabber_set_presentation_clock(grabber
, NULL
);
1094 IMFMediaEventQueue_Shutdown(grabber
->stream_event_queue
);
1095 IMFMediaEventQueue_Shutdown(grabber
->event_queue
);
1099 LeaveCriticalSection(&grabber
->cs
);
1104 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl
=
1106 sample_grabber_sink_QueryInterface
,
1107 sample_grabber_sink_AddRef
,
1108 sample_grabber_sink_Release
,
1109 sample_grabber_sink_GetCharacteristics
,
1110 sample_grabber_sink_AddStreamSink
,
1111 sample_grabber_sink_RemoveStreamSink
,
1112 sample_grabber_sink_GetStreamSinkCount
,
1113 sample_grabber_sink_GetStreamSinkByIndex
,
1114 sample_grabber_sink_GetStreamSinkById
,
1115 sample_grabber_sink_SetPresentationClock
,
1116 sample_grabber_sink_GetPresentationClock
,
1117 sample_grabber_sink_Shutdown
,
1120 static HRESULT WINAPI
sample_grabber_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
1122 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1123 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1126 static ULONG WINAPI
sample_grabber_clock_sink_AddRef(IMFClockStateSink
*iface
)
1128 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1129 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1132 static ULONG WINAPI
sample_grabber_clock_sink_Release(IMFClockStateSink
*iface
)
1134 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1135 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1138 static HRESULT
sample_grabber_set_state(struct sample_grabber
*grabber
, enum sink_state state
,
1139 MFTIME systime
, LONGLONG offset
)
1141 static const DWORD events
[] =
1143 MEStreamSinkStopped
, /* SINK_STATE_STOPPED */
1144 MEStreamSinkPaused
, /* SINK_STATE_PAUSED */
1145 MEStreamSinkStarted
, /* SINK_STATE_RUNNING */
1147 BOOL do_callback
= FALSE
;
1151 EnterCriticalSection(&grabber
->cs
);
1153 if (!grabber
->is_shut_down
)
1155 if (state
== SINK_STATE_PAUSED
&& grabber
->state
== SINK_STATE_STOPPED
)
1156 hr
= MF_E_INVALID_STATE_TRANSITION
;
1159 if (state
== SINK_STATE_STOPPED
)
1161 sample_grabber_cancel_timer(grabber
);
1162 release_samples(grabber
);
1163 grabber
->sample_count
= MAX_SAMPLE_QUEUE_LENGTH
;
1166 if (state
== SINK_STATE_RUNNING
&& grabber
->state
!= SINK_STATE_RUNNING
)
1168 /* Every transition to running state sends a bunch requests to build up initial queue. */
1169 for (i
= 0; i
< grabber
->sample_count
; ++i
)
1171 if (grabber
->state
== SINK_STATE_PAUSED
&& offset
== PRESENTATION_CURRENT_POSITION
)
1173 assert(grabber
->samples
[i
]);
1174 stream_queue_sample(grabber
, grabber
->samples
[i
]);
1178 sample_grabber_stream_request_sample(grabber
);
1181 release_samples(grabber
);
1182 grabber
->sample_count
= 0;
1185 do_callback
= state
!= grabber
->state
|| state
!= SINK_STATE_PAUSED
;
1188 if (grabber
->rate
== 0.0f
&& state
== SINK_STATE_RUNNING
)
1189 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkScrubSampleComplete
,
1190 &GUID_NULL
, S_OK
, NULL
);
1192 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, events
[state
], &GUID_NULL
, S_OK
, NULL
);
1194 grabber
->state
= state
;
1198 LeaveCriticalSection(&grabber
->cs
);
1204 case SINK_STATE_STOPPED
:
1205 hr
= IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber
), systime
);
1207 case SINK_STATE_PAUSED
:
1208 hr
= IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber
), systime
);
1210 case SINK_STATE_RUNNING
:
1211 hr
= IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber
), systime
, offset
);
1219 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
1221 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1223 TRACE("%p, %s, %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
1225 return sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
, systime
, offset
);
1228 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
1230 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1232 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1234 return sample_grabber_set_state(grabber
, SINK_STATE_STOPPED
, systime
, 0);
1237 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
1239 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1241 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1243 return sample_grabber_set_state(grabber
, SINK_STATE_PAUSED
, systime
, 0);
1246 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
1248 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1250 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
1252 return sample_grabber_set_state(grabber
, SINK_STATE_RUNNING
, systime
, PRESENTATION_CURRENT_POSITION
);
1255 static HRESULT WINAPI
sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
1257 struct sample_grabber
*grabber
= impl_from_IMFClockStateSink(iface
);
1260 TRACE("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
1262 EnterCriticalSection(&grabber
->cs
);
1264 if (grabber
->is_shut_down
)
1268 IMFStreamSink_QueueEvent(&grabber
->IMFStreamSink_iface
, MEStreamSinkRateChanged
, &GUID_NULL
, S_OK
, NULL
);
1269 grabber
->rate
= rate
;
1272 LeaveCriticalSection(&grabber
->cs
);
1275 hr
= IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber
), systime
, rate
);
1280 static HRESULT WINAPI
sample_grabber_events_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
1282 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1283 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1286 static ULONG WINAPI
sample_grabber_events_AddRef(IMFMediaEventGenerator
*iface
)
1288 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1289 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1292 static ULONG WINAPI
sample_grabber_events_Release(IMFMediaEventGenerator
*iface
)
1294 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1295 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1298 static HRESULT WINAPI
sample_grabber_events_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1300 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1302 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
1304 return IMFMediaEventQueue_GetEvent(grabber
->event_queue
, flags
, event
);
1307 static HRESULT WINAPI
sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
1310 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1312 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1314 return IMFMediaEventQueue_BeginGetEvent(grabber
->event_queue
, callback
, state
);
1317 static HRESULT WINAPI
sample_grabber_events_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
1318 IMFMediaEvent
**event
)
1320 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1322 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1324 return IMFMediaEventQueue_EndGetEvent(grabber
->event_queue
, result
, event
);
1327 static HRESULT WINAPI
sample_grabber_events_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
1328 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
1330 struct sample_grabber
*grabber
= impl_from_IMFMediaEventGenerator(iface
);
1332 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1334 return IMFMediaEventQueue_QueueEventParamVar(grabber
->event_queue
, event_type
, ext_type
, hr
, value
);
1337 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl
=
1339 sample_grabber_events_QueryInterface
,
1340 sample_grabber_events_AddRef
,
1341 sample_grabber_events_Release
,
1342 sample_grabber_events_GetEvent
,
1343 sample_grabber_events_BeginGetEvent
,
1344 sample_grabber_events_EndGetEvent
,
1345 sample_grabber_events_QueueEvent
,
1348 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl
=
1350 sample_grabber_clock_sink_QueryInterface
,
1351 sample_grabber_clock_sink_AddRef
,
1352 sample_grabber_clock_sink_Release
,
1353 sample_grabber_clock_sink_OnClockStart
,
1354 sample_grabber_clock_sink_OnClockStop
,
1355 sample_grabber_clock_sink_OnClockPause
,
1356 sample_grabber_clock_sink_OnClockRestart
,
1357 sample_grabber_clock_sink_OnClockSetRate
,
1360 static HRESULT WINAPI
sample_grabber_getservice_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1362 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1363 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1366 static ULONG WINAPI
sample_grabber_getservice_AddRef(IMFGetService
*iface
)
1368 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1369 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1372 static ULONG WINAPI
sample_grabber_getservice_Release(IMFGetService
*iface
)
1374 struct sample_grabber
*grabber
= impl_from_IMFGetService(iface
);
1375 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1378 static HRESULT WINAPI
sample_grabber_getservice_GetService(IMFGetService
*iface
, REFGUID service
,
1379 REFIID riid
, void **obj
)
1381 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1383 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1385 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1386 return IMFGetService_QueryInterface(iface
, riid
, obj
);
1388 return E_NOINTERFACE
;
1391 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service
), debugstr_guid(riid
));
1393 return MF_E_UNSUPPORTED_SERVICE
;
1396 static const IMFGetServiceVtbl sample_grabber_getservice_vtbl
=
1398 sample_grabber_getservice_QueryInterface
,
1399 sample_grabber_getservice_AddRef
,
1400 sample_grabber_getservice_Release
,
1401 sample_grabber_getservice_GetService
,
1404 static HRESULT WINAPI
sample_grabber_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
1406 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1407 return IMFMediaSink_QueryInterface(&grabber
->IMFMediaSink_iface
, riid
, obj
);
1410 static ULONG WINAPI
sample_grabber_rate_support_AddRef(IMFRateSupport
*iface
)
1412 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1413 return IMFMediaSink_AddRef(&grabber
->IMFMediaSink_iface
);
1416 static ULONG WINAPI
sample_grabber_rate_support_Release(IMFRateSupport
*iface
)
1418 struct sample_grabber
*grabber
= impl_from_IMFRateSupport(iface
);
1419 return IMFMediaSink_Release(&grabber
->IMFMediaSink_iface
);
1422 static HRESULT WINAPI
sample_grabber_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1423 BOOL thin
, float *rate
)
1425 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1432 static HRESULT WINAPI
sample_grabber_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
,
1433 BOOL thin
, float *rate
)
1435 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1437 *rate
= direction
== MFRATE_REVERSE
? -FLT_MAX
: FLT_MAX
;
1442 static HRESULT WINAPI
sample_grabber_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
1445 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, ret_rate
);
1453 static const IMFRateSupportVtbl sample_grabber_rate_support_vtbl
=
1455 sample_grabber_rate_support_QueryInterface
,
1456 sample_grabber_rate_support_AddRef
,
1457 sample_grabber_rate_support_Release
,
1458 sample_grabber_rate_support_GetSlowestRate
,
1459 sample_grabber_rate_support_GetFastestRate
,
1460 sample_grabber_rate_support_IsRateSupported
,
1463 static HRESULT
sample_grabber_create_object(IMFAttributes
*attributes
, void *user_context
, IUnknown
**obj
)
1465 struct sample_grabber_activate_context
*context
= user_context
;
1466 struct sample_grabber
*object
;
1470 TRACE("%p, %p, %p.\n", attributes
, user_context
, obj
);
1472 if (context
->shut_down
)
1473 return MF_E_SHUTDOWN
;
1475 /* At least major type is required. */
1476 if (FAILED(IMFMediaType_GetMajorType(context
->media_type
, &guid
)))
1477 return MF_E_INVALIDMEDIATYPE
;
1479 if (!(object
= calloc(1, sizeof(*object
))))
1480 return E_OUTOFMEMORY
;
1482 object
->IMFMediaSink_iface
.lpVtbl
= &sample_grabber_sink_vtbl
;
1483 object
->IMFClockStateSink_iface
.lpVtbl
= &sample_grabber_clock_sink_vtbl
;
1484 object
->IMFMediaEventGenerator_iface
.lpVtbl
= &sample_grabber_sink_events_vtbl
;
1485 object
->IMFGetService_iface
.lpVtbl
= &sample_grabber_getservice_vtbl
;
1486 object
->IMFRateSupport_iface
.lpVtbl
= &sample_grabber_rate_support_vtbl
;
1487 object
->IMFStreamSink_iface
.lpVtbl
= &sample_grabber_stream_vtbl
;
1488 object
->IMFMediaTypeHandler_iface
.lpVtbl
= &sample_grabber_stream_type_handler_vtbl
;
1489 object
->timer_callback
.lpVtbl
= &sample_grabber_stream_timer_callback_vtbl
;
1490 object
->sample_count
= MAX_SAMPLE_QUEUE_LENGTH
;
1491 object
->refcount
= 1;
1492 object
->rate
= 1.0f
;
1493 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context
->callback
, &IID_IMFSampleGrabberSinkCallback2
,
1494 (void **)&object
->callback2
)))
1496 object
->callback
= context
->callback
;
1497 IMFSampleGrabberSinkCallback_AddRef(object
->callback
);
1499 object
->media_type
= context
->media_type
;
1500 IMFMediaType_AddRef(object
->media_type
);
1501 object
->current_media_type
= context
->media_type
;
1502 IMFMediaType_AddRef(object
->current_media_type
);
1503 IMFAttributes_GetUINT32(attributes
, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK
, &object
->ignore_clock
);
1504 IMFAttributes_GetUINT64(attributes
, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET
, &object
->sample_time_offset
);
1505 list_init(&object
->items
);
1506 InitializeCriticalSection(&object
->cs
);
1508 if (FAILED(hr
= MFCreateEventQueue(&object
->stream_event_queue
)))
1511 if (FAILED(hr
= MFCreateAttributes(&object
->sample_attributes
, 0)))
1514 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1517 *obj
= (IUnknown
*)&object
->IMFMediaSink_iface
;
1519 TRACE("Created %p.\n", *obj
);
1525 IMFMediaSink_Release(&object
->IMFMediaSink_iface
);
1530 static void sample_grabber_shutdown_object(void *user_context
, IUnknown
*obj
)
1532 struct sample_grabber_activate_context
*context
= user_context
;
1533 context
->shut_down
= TRUE
;
1536 static const struct activate_funcs sample_grabber_activate_funcs
=
1538 sample_grabber_create_object
,
1539 sample_grabber_shutdown_object
,
1540 sample_grabber_free_private
,
1543 /***********************************************************************
1544 * MFCreateSampleGrabberSinkActivate (mf.@)
1546 HRESULT WINAPI
MFCreateSampleGrabberSinkActivate(IMFMediaType
*media_type
, IMFSampleGrabberSinkCallback
*callback
,
1547 IMFActivate
**activate
)
1549 struct sample_grabber_activate_context
*context
;
1552 TRACE("%p, %p, %p.\n", media_type
, callback
, activate
);
1554 if (!media_type
|| !callback
|| !activate
)
1557 if (!(context
= calloc(1, sizeof(*context
))))
1558 return E_OUTOFMEMORY
;
1560 context
->media_type
= media_type
;
1561 IMFMediaType_AddRef(context
->media_type
);
1562 context
->callback
= callback
;
1563 IMFSampleGrabberSinkCallback_AddRef(context
->callback
);
1565 if (FAILED(hr
= create_activation_object(context
, &sample_grabber_activate_funcs
, activate
)))
1566 sample_grabber_free_private(context
);