quartz/tests: Add some more tests for IMediaSeeking return value handling.
[wine.git] / dlls / mf / samplegrabber.c
blob54e28b466c5669863b4c7973a5e854969b1caf76
1 /*
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
19 #define COBJMACROS
21 #include <float.h>
23 #include "mfidl.h"
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);
32 enum sink_state
34 SINK_STATE_STOPPED = 0,
35 SINK_STATE_RUNNING,
38 struct sample_grabber;
40 enum scheduled_item_type
42 ITEM_TYPE_SAMPLE,
43 ITEM_TYPE_MARKER,
46 struct scheduled_item
48 struct list entry;
49 enum scheduled_item_type type;
50 union
52 IMFSample *sample;
53 struct
55 MFSTREAMSINK_MARKER_TYPE type;
56 PROPVARIANT context;
57 } marker;
58 } u;
61 struct sample_grabber
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;
71 LONG refcount;
72 IMFSampleGrabberSinkCallback *callback;
73 IMFSampleGrabberSinkCallback2 *callback2;
74 IMFMediaType *media_type;
75 BOOL is_shut_down;
76 IMFMediaEventQueue *event_queue;
77 IMFMediaEventQueue *stream_event_queue;
78 IMFPresentationClock *clock;
79 IMFTimer *timer;
80 IMFAttributes *sample_attributes;
81 struct list items;
82 IUnknown *cancel_key;
83 UINT32 ignore_clock;
84 UINT64 sample_time_offset;
85 enum sink_state state;
86 CRITICAL_SECTION cs;
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;
98 BOOL shut_down;
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);
106 heap_free(context);
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;
165 else
167 WARN("Unsupported %s.\n", debugstr_guid(riid));
168 *obj = NULL;
169 return E_NOINTERFACE;
172 IUnknown_AddRef((IUnknown *)*obj);
174 return S_OK;
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);
186 switch (item->type)
188 case ITEM_TYPE_SAMPLE:
189 IMFSample_Release(item->u.sample);
190 break;
191 case ITEM_TYPE_MARKER:
192 PropVariantClear(&item->u.marker.context);
193 break;
195 heap_free(item);
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,
217 IUnknown *state)
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);
267 return S_OK;
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;
279 *identifier = 0;
281 return S_OK;
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);
290 if (!handler)
291 return E_POINTER;
293 if (grabber->is_shut_down)
294 return MF_E_STREAMSINK_REMOVED;
296 *handler = &grabber->IMFMediaTypeHandler_iface;
297 IMFMediaTypeHandler_AddRef(*handler);
299 return S_OK;
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;
306 DWORD flags, size;
307 GUID major_type;
308 BYTE *data;
309 HRESULT hr;
311 *sample_delivered = FALSE;
313 hr = IMFMediaType_GetMajorType(grabber->media_type, &major_type);
315 if (SUCCEEDED(hr))
316 hr = IMFSample_GetSampleTime(sample, &sample_time);
318 if (FAILED(IMFSample_GetSampleDuration(sample, &sample_duration)))
319 sample_duration = 0;
321 if (SUCCEEDED(hr))
322 hr = IMFSample_GetSampleFlags(sample, &flags);
324 if (SUCCEEDED(hr))
326 if (FAILED(IMFSample_ConvertToContiguousBuffer(sample, &buffer)))
327 return E_UNEXPECTED;
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);
336 if (SUCCEEDED(hr))
337 hr = IMFSampleGrabberSinkCallback2_OnProcessSampleEx(grabber->callback2, &major_type, flags,
338 sample_time, sample_duration, data, size, grabber->sample_attributes);
340 else
341 hr = IMFSampleGrabberSinkCallback_OnProcessSample(grabber->callback, &major_type, flags, sample_time,
342 sample_duration, data, size);
343 IMFMediaBuffer_Unlock(buffer);
346 IMFMediaBuffer_Release(buffer);
349 return hr;
352 static HRESULT stream_schedule_sample(struct sample_grabber *grabber, struct scheduled_item *item)
354 LONGLONG sampletime;
355 HRESULT hr;
357 if (grabber->is_shut_down)
358 return MF_E_STREAMSINK_REMOVED;
360 if (FAILED(hr = IMFSample_GetSampleTime(item->u.sample, &sampletime)))
361 return hr;
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;
375 return hr;
378 static HRESULT stream_queue_sample(struct sample_grabber *grabber, IMFSample *sample)
380 struct scheduled_item *item;
381 LONGLONG sampletime;
382 HRESULT hr;
384 if (FAILED(hr = IMFSample_GetSampleTime(sample, &sampletime)))
385 return hr;
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);
397 if (SUCCEEDED(hr))
398 list_add_tail(&grabber->items, &item->entry);
399 else
400 stream_release_pending_item(item);
402 return hr;
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;
414 LONGLONG sampletime;
415 HRESULT hr = S_OK;
417 TRACE("%p, %p.\n", iface, sample);
419 if (!sample)
420 return S_OK;
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);
430 if (SUCCEEDED(hr))
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);
440 else
441 hr = stream_queue_sample(grabber, sample);
445 LeaveCriticalSection(&grabber->cs);
447 return hr;
450 static void sample_grabber_stream_report_marker(struct sample_grabber *grabber, const PROPVARIANT *context,
451 HRESULT hr)
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;
460 HRESULT hr = S_OK;
462 if (list_empty(&grabber->items))
464 sample_grabber_stream_report_marker(grabber, context_value, S_OK);
465 return 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);
475 if (context_value)
476 hr = PropVariantCopy(&item->u.marker.context, context_value);
477 if (SUCCEEDED(hr))
478 list_add_tail(&grabber->items, &item->entry);
479 else
480 stream_release_pending_item(item);
482 return hr;
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);
489 HRESULT hr = S_OK;
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);
502 return hr;
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. */
520 switch (item->type)
522 case ITEM_TYPE_SAMPLE:
523 break;
524 case ITEM_TYPE_MARKER:
525 sample_grabber_stream_report_marker(grabber, &item->u.marker.context, E_ABORT);
526 break;
529 stream_release_pending_item(item);
532 LeaveCriticalSection(&grabber->cs);
534 return S_OK;
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,
555 void **obj)
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;
576 DWORD flags;
578 if (grabber->is_shut_down)
579 return MF_E_STREAMSINK_REMOVED;
581 if (!in_type)
582 return E_POINTER;
584 if (IMFMediaType_IsEqual(grabber->media_type, in_type, &flags) == S_OK)
585 return 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);
604 if (!count)
605 return E_POINTER;
607 *count = 0;
609 return S_OK;
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);
617 if (!media_type)
618 return E_POINTER;
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);
627 HRESULT hr;
629 TRACE("%p, %p.\n", iface, media_type);
631 if (FAILED(hr = sample_grabber_stream_is_media_type_supported(grabber, media_type)))
632 return hr;
634 IMFMediaType_Release(grabber->media_type);
635 grabber->media_type = media_type;
636 IMFMediaType_AddRef(grabber->media_type);
638 return S_OK;
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);
648 if (!media_type)
649 return E_POINTER;
651 if (grabber->is_shut_down)
652 return MF_E_STREAMSINK_REMOVED;
654 *media_type = grabber->media_type;
655 IMFMediaType_AddRef(*media_type);
657 return S_OK;
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);
666 if (!type)
667 return E_POINTER;
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,
689 void **obj)
691 if (IsEqualIID(riid, &IID_IMFAsyncCallback) || IsEqualIID(riid, &IID_IUnknown))
693 *obj = iface;
694 IMFAsyncCallback_AddRef(iface);
695 return S_OK;
698 WARN("Unsupported %s.\n", debugstr_guid(riid));
699 *obj = NULL;
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,
716 DWORD *queue)
718 return E_NOTIMPL;
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;
726 HRESULT hr;
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;
746 else
748 if (FAILED(hr = stream_schedule_sample(grabber, item)))
749 WARN("Failed to schedule a sample, hr %#x.\n", hr);
750 break;
754 if (sample_delivered)
755 sample_grabber_stream_request_sample(grabber);
757 LeaveCriticalSection(&grabber->cs);
759 return S_OK;
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;
798 else
800 WARN("Unsupported %s.\n", debugstr_guid(riid));
801 *obj = NULL;
802 return E_NOINTERFACE;
805 IUnknown_AddRef((IUnknown *)*obj);
807 return S_OK;
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);
817 return 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);
837 if (!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);
846 if (grabber->clock)
847 IMFPresentationClock_Release(grabber->clock);
848 if (grabber->timer)
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);
865 heap_free(grabber);
868 return refcount;
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;
884 return S_OK;
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;
915 *count = 1;
917 return S_OK;
920 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
921 IMFStreamSink **stream)
923 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
924 HRESULT hr = S_OK;
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)
934 hr = MF_E_SHUTDOWN;
935 else if (index > 0)
936 hr = MF_E_INVALIDINDEX;
937 else
939 *stream = &grabber->IMFStreamSink_iface;
940 IMFStreamSink_AddRef(*stream);
943 LeaveCriticalSection(&grabber->cs);
945 return hr;
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);
952 HRESULT hr = S_OK;
954 TRACE("%p, %#x, %p.\n", iface, stream_sink_id, stream);
956 EnterCriticalSection(&grabber->cs);
958 if (grabber->is_shut_down)
959 hr = MF_E_SHUTDOWN;
960 else if (stream_sink_id > 0)
961 hr = MF_E_INVALIDSTREAMNUMBER;
962 else
964 *stream = &grabber->IMFStreamSink_iface;
965 IMFStreamSink_AddRef(*stream);
968 LeaveCriticalSection(&grabber->cs);
970 return hr;
973 static void sample_grabber_set_presentation_clock(struct sample_grabber *grabber, IMFPresentationClock *clock)
975 if (grabber->clock)
977 IMFPresentationClock_RemoveClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
978 IMFPresentationClock_Release(grabber->clock);
979 if (grabber->timer)
981 IMFTimer_Release(grabber->timer);
982 grabber->timer = NULL;
985 grabber->clock = clock;
986 if (grabber->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);
1001 HRESULT hr;
1003 TRACE("%p, %p.\n", iface, clock);
1005 EnterCriticalSection(&grabber->cs);
1007 if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber),
1008 clock)))
1010 sample_grabber_set_presentation_clock(grabber, clock);
1013 LeaveCriticalSection(&grabber->cs);
1015 return hr;
1018 static HRESULT WINAPI sample_grabber_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock)
1020 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1021 HRESULT hr = S_OK;
1023 TRACE("%p, %p.\n", iface, clock);
1025 if (!clock)
1026 return E_POINTER;
1028 EnterCriticalSection(&grabber->cs);
1030 if (grabber->clock)
1032 *clock = grabber->clock;
1033 IMFPresentationClock_AddRef(*clock);
1035 else
1036 hr = MF_E_NO_CLOCK;
1038 LeaveCriticalSection(&grabber->cs);
1040 return hr;
1043 static HRESULT WINAPI sample_grabber_sink_Shutdown(IMFMediaSink *iface)
1045 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1046 HRESULT hr;
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);
1064 return hr;
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;
1109 unsigned int i;
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;
1119 break;
1120 case SINK_STATE_RUNNING:
1121 set_state = state == SINK_STATE_STOPPED;
1122 break;
1123 default:
1127 if (set_state)
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,
1222 IUnknown *state)
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);
1341 *rate = 0.0f;
1343 return S_OK;
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;
1353 return S_OK;
1356 static HRESULT WINAPI sample_grabber_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1357 float *ret_rate)
1359 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, ret_rate);
1361 if (ret_rate)
1362 *ret_rate = rate;
1364 return S_OK;
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;
1381 HRESULT hr;
1382 GUID guid;
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));
1394 if (!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)))
1420 goto failed;
1422 if (FAILED(hr = MFCreateAttributes(&object->sample_attributes, 0)))
1423 goto failed;
1425 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1426 goto failed;
1428 *obj = (IUnknown *)&object->IMFMediaSink_iface;
1430 TRACE("Created %p.\n", *obj);
1432 return S_OK;
1434 failed:
1436 IMFMediaSink_Release(&object->IMFMediaSink_iface);
1438 return hr;
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;
1461 HRESULT hr;
1463 TRACE("%p, %p, %p.\n", media_type, callback, activate);
1465 if (!media_type || !callback || !activate)
1466 return E_POINTER;
1468 context = heap_alloc_zero(sizeof(*context));
1469 if (!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);
1480 return hr;