riched20: Merge the richole object with the text services object.
[wine.git] / dlls / mf / samplegrabber.c
blobf60ce2a84335088f4f616ae29a228d7271279d61
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 IMFMediaType *current_media_type;
76 BOOL is_shut_down;
77 IMFMediaEventQueue *event_queue;
78 IMFMediaEventQueue *stream_event_queue;
79 IMFPresentationClock *clock;
80 IMFTimer *timer;
81 IMFAttributes *sample_attributes;
82 struct list items;
83 IUnknown *cancel_key;
84 UINT32 ignore_clock;
85 UINT64 sample_time_offset;
86 enum sink_state state;
87 CRITICAL_SECTION cs;
90 static IMFSampleGrabberSinkCallback *sample_grabber_get_callback(const struct sample_grabber *sink)
92 return sink->callback2 ? (IMFSampleGrabberSinkCallback *)sink->callback2 : sink->callback;
95 struct sample_grabber_activate_context
97 IMFMediaType *media_type;
98 IMFSampleGrabberSinkCallback *callback;
99 BOOL shut_down;
102 static void sample_grabber_free_private(void *user_context)
104 struct sample_grabber_activate_context *context = user_context;
105 IMFMediaType_Release(context->media_type);
106 IMFSampleGrabberSinkCallback_Release(context->callback);
107 heap_free(context);
110 static struct sample_grabber *impl_from_IMFMediaSink(IMFMediaSink *iface)
112 return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaSink_iface);
115 static struct sample_grabber *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
117 return CONTAINING_RECORD(iface, struct sample_grabber, IMFClockStateSink_iface);
120 static struct sample_grabber *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface)
122 return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaEventGenerator_iface);
125 static struct sample_grabber *impl_from_IMFGetService(IMFGetService *iface)
127 return CONTAINING_RECORD(iface, struct sample_grabber, IMFGetService_iface);
130 static struct sample_grabber *impl_from_IMFRateSupport(IMFRateSupport *iface)
132 return CONTAINING_RECORD(iface, struct sample_grabber, IMFRateSupport_iface);
135 static struct sample_grabber *impl_from_IMFStreamSink(IMFStreamSink *iface)
137 return CONTAINING_RECORD(iface, struct sample_grabber, IMFStreamSink_iface);
140 static struct sample_grabber *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface)
142 return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaTypeHandler_iface);
145 static struct sample_grabber *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
147 return CONTAINING_RECORD(iface, struct sample_grabber, timer_callback);
150 static HRESULT WINAPI sample_grabber_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj)
152 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
154 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
156 if (IsEqualIID(riid, &IID_IMFStreamSink) ||
157 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
158 IsEqualIID(riid, &IID_IUnknown))
160 *obj = &grabber->IMFStreamSink_iface;
162 else if (IsEqualIID(riid, &IID_IMFMediaTypeHandler))
164 *obj = &grabber->IMFMediaTypeHandler_iface;
166 else
168 WARN("Unsupported %s.\n", debugstr_guid(riid));
169 *obj = NULL;
170 return E_NOINTERFACE;
173 IUnknown_AddRef((IUnknown *)*obj);
175 return S_OK;
178 static ULONG WINAPI sample_grabber_stream_AddRef(IMFStreamSink *iface)
180 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
181 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
184 static void stream_release_pending_item(struct scheduled_item *item)
186 list_remove(&item->entry);
187 switch (item->type)
189 case ITEM_TYPE_SAMPLE:
190 IMFSample_Release(item->u.sample);
191 break;
192 case ITEM_TYPE_MARKER:
193 PropVariantClear(&item->u.marker.context);
194 break;
196 heap_free(item);
199 static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface)
201 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
202 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
205 static HRESULT WINAPI sample_grabber_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event)
207 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
209 TRACE("%p, %#x, %p.\n", iface, flags, event);
211 if (grabber->is_shut_down)
212 return MF_E_STREAMSINK_REMOVED;
214 return IMFMediaEventQueue_GetEvent(grabber->stream_event_queue, flags, event);
217 static HRESULT WINAPI sample_grabber_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback,
218 IUnknown *state)
220 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
222 TRACE("%p, %p, %p.\n", iface, callback, state);
224 if (grabber->is_shut_down)
225 return MF_E_STREAMSINK_REMOVED;
227 return IMFMediaEventQueue_BeginGetEvent(grabber->stream_event_queue, callback, state);
230 static HRESULT WINAPI sample_grabber_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result,
231 IMFMediaEvent **event)
233 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
235 TRACE("%p, %p, %p.\n", iface, result, event);
237 if (grabber->is_shut_down)
238 return MF_E_STREAMSINK_REMOVED;
240 return IMFMediaEventQueue_EndGetEvent(grabber->stream_event_queue, result, event);
243 static HRESULT WINAPI sample_grabber_stream_QueueEvent(IMFStreamSink *iface, MediaEventType event_type,
244 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
246 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
248 TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
250 if (grabber->is_shut_down)
251 return MF_E_STREAMSINK_REMOVED;
253 return IMFMediaEventQueue_QueueEventParamVar(grabber->stream_event_queue, event_type, ext_type, hr, value);
256 static HRESULT WINAPI sample_grabber_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink)
258 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
260 TRACE("%p, %p.\n", iface, sink);
262 if (grabber->is_shut_down)
263 return MF_E_STREAMSINK_REMOVED;
265 *sink = &grabber->IMFMediaSink_iface;
266 IMFMediaSink_AddRef(*sink);
268 return S_OK;
271 static HRESULT WINAPI sample_grabber_stream_GetIdentifier(IMFStreamSink *iface, DWORD *identifier)
273 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
275 TRACE("%p, %p.\n", iface, identifier);
277 if (grabber->is_shut_down)
278 return MF_E_STREAMSINK_REMOVED;
280 *identifier = 0;
282 return S_OK;
285 static HRESULT WINAPI sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler)
287 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
289 TRACE("%p, %p.\n", iface, handler);
291 if (!handler)
292 return E_POINTER;
294 if (grabber->is_shut_down)
295 return MF_E_STREAMSINK_REMOVED;
297 *handler = &grabber->IMFMediaTypeHandler_iface;
298 IMFMediaTypeHandler_AddRef(*handler);
300 return S_OK;
303 static HRESULT sample_grabber_report_sample(struct sample_grabber *grabber, IMFSample *sample, BOOL *sample_delivered)
305 LONGLONG sample_time, sample_duration = 0;
306 IMFMediaBuffer *buffer;
307 DWORD flags, size;
308 GUID major_type;
309 BYTE *data;
310 HRESULT hr;
312 *sample_delivered = FALSE;
314 hr = IMFMediaType_GetMajorType(grabber->media_type, &major_type);
316 if (SUCCEEDED(hr))
317 hr = IMFSample_GetSampleTime(sample, &sample_time);
319 if (FAILED(IMFSample_GetSampleDuration(sample, &sample_duration)))
320 sample_duration = 0;
322 if (SUCCEEDED(hr))
323 hr = IMFSample_GetSampleFlags(sample, &flags);
325 if (SUCCEEDED(hr))
327 if (FAILED(IMFSample_ConvertToContiguousBuffer(sample, &buffer)))
328 return E_UNEXPECTED;
330 if (SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, &size)))
332 *sample_delivered = TRUE;
334 if (grabber->callback2)
336 hr = IMFSample_CopyAllItems(sample, grabber->sample_attributes);
337 if (SUCCEEDED(hr))
338 hr = IMFSampleGrabberSinkCallback2_OnProcessSampleEx(grabber->callback2, &major_type, flags,
339 sample_time, sample_duration, data, size, grabber->sample_attributes);
341 else
342 hr = IMFSampleGrabberSinkCallback_OnProcessSample(grabber->callback, &major_type, flags, sample_time,
343 sample_duration, data, size);
344 IMFMediaBuffer_Unlock(buffer);
347 IMFMediaBuffer_Release(buffer);
350 return hr;
353 static HRESULT stream_schedule_sample(struct sample_grabber *grabber, struct scheduled_item *item)
355 LONGLONG sampletime;
356 HRESULT hr;
358 if (grabber->is_shut_down)
359 return MF_E_STREAMSINK_REMOVED;
361 if (FAILED(hr = IMFSample_GetSampleTime(item->u.sample, &sampletime)))
362 return hr;
364 if (grabber->cancel_key)
366 IUnknown_Release(grabber->cancel_key);
367 grabber->cancel_key = NULL;
370 if (FAILED(hr = IMFTimer_SetTimer(grabber->timer, 0, sampletime - grabber->sample_time_offset,
371 &grabber->timer_callback, NULL, &grabber->cancel_key)))
373 grabber->cancel_key = NULL;
376 return hr;
379 static HRESULT stream_queue_sample(struct sample_grabber *grabber, IMFSample *sample)
381 struct scheduled_item *item;
382 LONGLONG sampletime;
383 HRESULT hr;
385 if (FAILED(hr = IMFSample_GetSampleTime(sample, &sampletime)))
386 return hr;
388 if (!(item = heap_alloc_zero(sizeof(*item))))
389 return E_OUTOFMEMORY;
391 item->type = ITEM_TYPE_SAMPLE;
392 item->u.sample = sample;
393 IMFSample_AddRef(item->u.sample);
394 list_init(&item->entry);
395 if (list_empty(&grabber->items))
396 hr = stream_schedule_sample(grabber, item);
398 if (SUCCEEDED(hr))
399 list_add_tail(&grabber->items, &item->entry);
400 else
401 stream_release_pending_item(item);
403 return hr;
406 static void sample_grabber_stream_request_sample(struct sample_grabber *grabber)
408 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL);
411 static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
413 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
414 BOOL sample_delivered;
415 LONGLONG sampletime;
416 HRESULT hr = S_OK;
418 TRACE("%p, %p.\n", iface, sample);
420 if (!sample)
421 return S_OK;
423 EnterCriticalSection(&grabber->cs);
425 if (grabber->is_shut_down)
426 hr = MF_E_STREAMSINK_REMOVED;
427 else if (grabber->state == SINK_STATE_RUNNING)
429 hr = IMFSample_GetSampleTime(sample, &sampletime);
431 if (SUCCEEDED(hr))
433 if (grabber->ignore_clock)
435 /* OnProcessSample() could return error code, which has to be propagated but isn't a blocker.
436 Use additional flag indicating that user callback was called at all. */
437 hr = sample_grabber_report_sample(grabber, sample, &sample_delivered);
438 if (sample_delivered)
439 sample_grabber_stream_request_sample(grabber);
441 else
442 hr = stream_queue_sample(grabber, sample);
446 LeaveCriticalSection(&grabber->cs);
448 return hr;
451 static void sample_grabber_stream_report_marker(struct sample_grabber *grabber, const PROPVARIANT *context,
452 HRESULT hr)
454 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkMarker, &GUID_NULL, hr, context);
457 static HRESULT stream_place_marker(struct sample_grabber *grabber, MFSTREAMSINK_MARKER_TYPE marker_type,
458 const PROPVARIANT *context_value)
460 struct scheduled_item *item;
461 HRESULT hr = S_OK;
463 if (list_empty(&grabber->items))
465 sample_grabber_stream_report_marker(grabber, context_value, S_OK);
466 return S_OK;
469 if (!(item = heap_alloc_zero(sizeof(*item))))
470 return E_OUTOFMEMORY;
472 item->type = ITEM_TYPE_MARKER;
473 item->u.marker.type = marker_type;
474 list_init(&item->entry);
475 PropVariantInit(&item->u.marker.context);
476 if (context_value)
477 hr = PropVariantCopy(&item->u.marker.context, context_value);
478 if (SUCCEEDED(hr))
479 list_add_tail(&grabber->items, &item->entry);
480 else
481 stream_release_pending_item(item);
483 return hr;
486 static HRESULT WINAPI sample_grabber_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
487 const PROPVARIANT *marker_value, const PROPVARIANT *context_value)
489 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
490 HRESULT hr = S_OK;
492 TRACE("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value);
494 EnterCriticalSection(&grabber->cs);
496 if (grabber->is_shut_down)
497 hr = MF_E_STREAMSINK_REMOVED;
498 else if (grabber->state == SINK_STATE_RUNNING)
499 hr = stream_place_marker(grabber, marker_type, context_value);
501 LeaveCriticalSection(&grabber->cs);
503 return hr;
506 static HRESULT WINAPI sample_grabber_stream_Flush(IMFStreamSink *iface)
508 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
509 struct scheduled_item *item, *next_item;
511 TRACE("%p.\n", iface);
513 if (grabber->is_shut_down)
514 return MF_E_STREAMSINK_REMOVED;
516 EnterCriticalSection(&grabber->cs);
518 LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &grabber->items, struct scheduled_item, entry)
520 /* Samples are discarded, markers are processed immediately. */
521 switch (item->type)
523 case ITEM_TYPE_SAMPLE:
524 break;
525 case ITEM_TYPE_MARKER:
526 sample_grabber_stream_report_marker(grabber, &item->u.marker.context, E_ABORT);
527 break;
530 stream_release_pending_item(item);
533 LeaveCriticalSection(&grabber->cs);
535 return S_OK;
538 static const IMFStreamSinkVtbl sample_grabber_stream_vtbl =
540 sample_grabber_stream_QueryInterface,
541 sample_grabber_stream_AddRef,
542 sample_grabber_stream_Release,
543 sample_grabber_stream_GetEvent,
544 sample_grabber_stream_BeginGetEvent,
545 sample_grabber_stream_EndGetEvent,
546 sample_grabber_stream_QueueEvent,
547 sample_grabber_stream_GetMediaSink,
548 sample_grabber_stream_GetIdentifier,
549 sample_grabber_stream_GetMediaTypeHandler,
550 sample_grabber_stream_ProcessSample,
551 sample_grabber_stream_PlaceMarker,
552 sample_grabber_stream_Flush,
555 static HRESULT WINAPI sample_grabber_stream_type_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid,
556 void **obj)
558 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
559 return IMFStreamSink_QueryInterface(&grabber->IMFStreamSink_iface, riid, obj);
562 static ULONG WINAPI sample_grabber_stream_type_handler_AddRef(IMFMediaTypeHandler *iface)
564 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
565 return IMFStreamSink_AddRef(&grabber->IMFStreamSink_iface);
568 static ULONG WINAPI sample_grabber_stream_type_handler_Release(IMFMediaTypeHandler *iface)
570 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
571 return IMFStreamSink_Release(&grabber->IMFStreamSink_iface);
574 static HRESULT sample_grabber_stream_is_media_type_supported(struct sample_grabber *grabber, IMFMediaType *in_type)
576 const DWORD supported_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES |
577 MF_MEDIATYPE_EQUAL_FORMAT_DATA;
578 DWORD flags;
580 if (grabber->is_shut_down)
581 return MF_E_STREAMSINK_REMOVED;
583 if (!in_type)
584 return E_POINTER;
586 if (IMFMediaType_IsEqual(grabber->media_type, in_type, &flags) == S_OK)
587 return S_OK;
589 return (flags & supported_flags) == supported_flags ? S_OK : MF_E_INVALIDMEDIATYPE;
592 static HRESULT WINAPI sample_grabber_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface,
593 IMFMediaType *in_type, IMFMediaType **out_type)
595 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
597 TRACE("%p, %p, %p.\n", iface, in_type, out_type);
599 return sample_grabber_stream_is_media_type_supported(grabber, in_type);
602 static HRESULT WINAPI sample_grabber_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count)
604 TRACE("%p, %p.\n", iface, count);
606 if (!count)
607 return E_POINTER;
609 *count = 0;
611 return S_OK;
614 static HRESULT WINAPI sample_grabber_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index,
615 IMFMediaType **media_type)
617 TRACE("%p, %u, %p.\n", iface, index, media_type);
619 if (!media_type)
620 return E_POINTER;
622 return MF_E_NO_MORE_TYPES;
625 static HRESULT WINAPI sample_grabber_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface,
626 IMFMediaType *media_type)
628 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
629 HRESULT hr;
631 TRACE("%p, %p.\n", iface, media_type);
633 if (FAILED(hr = sample_grabber_stream_is_media_type_supported(grabber, media_type)))
634 return hr;
636 IMFMediaType_Release(grabber->current_media_type);
637 grabber->current_media_type = media_type;
638 IMFMediaType_AddRef(grabber->current_media_type);
640 return S_OK;
643 static HRESULT WINAPI sample_grabber_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface,
644 IMFMediaType **media_type)
646 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
648 TRACE("%p, %p.\n", iface, media_type);
650 if (!media_type)
651 return E_POINTER;
653 if (grabber->is_shut_down)
654 return MF_E_STREAMSINK_REMOVED;
656 *media_type = grabber->current_media_type;
657 IMFMediaType_AddRef(*media_type);
659 return S_OK;
662 static HRESULT WINAPI sample_grabber_stream_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type)
664 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
666 TRACE("%p, %p.\n", iface, type);
668 if (!type)
669 return E_POINTER;
671 if (grabber->is_shut_down)
672 return MF_E_STREAMSINK_REMOVED;
674 return IMFMediaType_GetMajorType(grabber->current_media_type, type);
677 static const IMFMediaTypeHandlerVtbl sample_grabber_stream_type_handler_vtbl =
679 sample_grabber_stream_type_handler_QueryInterface,
680 sample_grabber_stream_type_handler_AddRef,
681 sample_grabber_stream_type_handler_Release,
682 sample_grabber_stream_type_handler_IsMediaTypeSupported,
683 sample_grabber_stream_type_handler_GetMediaTypeCount,
684 sample_grabber_stream_type_handler_GetMediaTypeByIndex,
685 sample_grabber_stream_type_handler_SetCurrentMediaType,
686 sample_grabber_stream_type_handler_GetCurrentMediaType,
687 sample_grabber_stream_type_handler_GetMajorType,
690 static HRESULT WINAPI sample_grabber_stream_timer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid,
691 void **obj)
693 if (IsEqualIID(riid, &IID_IMFAsyncCallback) || IsEqualIID(riid, &IID_IUnknown))
695 *obj = iface;
696 IMFAsyncCallback_AddRef(iface);
697 return S_OK;
700 WARN("Unsupported %s.\n", debugstr_guid(riid));
701 *obj = NULL;
702 return E_NOINTERFACE;
705 static ULONG WINAPI sample_grabber_stream_timer_callback_AddRef(IMFAsyncCallback *iface)
707 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
708 return IMFStreamSink_AddRef(&grabber->IMFStreamSink_iface);
711 static ULONG WINAPI sample_grabber_stream_timer_callback_Release(IMFAsyncCallback *iface)
713 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
714 return IMFStreamSink_Release(&grabber->IMFStreamSink_iface);
717 static HRESULT WINAPI sample_grabber_stream_timer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
718 DWORD *queue)
720 return E_NOTIMPL;
723 static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
725 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
726 BOOL sample_reported = FALSE, sample_delivered = FALSE;
727 struct scheduled_item *item, *item2;
728 HRESULT hr;
730 EnterCriticalSection(&grabber->cs);
732 LIST_FOR_EACH_ENTRY_SAFE(item, item2, &grabber->items, struct scheduled_item, entry)
734 if (item->type == ITEM_TYPE_MARKER)
736 sample_grabber_stream_report_marker(grabber, &item->u.marker.context, S_OK);
737 stream_release_pending_item(item);
739 else if (item->type == ITEM_TYPE_SAMPLE)
741 if (!sample_reported)
743 if (FAILED(hr = sample_grabber_report_sample(grabber, item->u.sample, &sample_delivered)))
744 WARN("Failed to report a sample, hr %#x.\n", hr);
745 stream_release_pending_item(item);
746 sample_reported = TRUE;
748 else
750 if (FAILED(hr = stream_schedule_sample(grabber, item)))
751 WARN("Failed to schedule a sample, hr %#x.\n", hr);
752 break;
756 if (sample_delivered)
757 sample_grabber_stream_request_sample(grabber);
759 LeaveCriticalSection(&grabber->cs);
761 return S_OK;
764 static const IMFAsyncCallbackVtbl sample_grabber_stream_timer_callback_vtbl =
766 sample_grabber_stream_timer_callback_QueryInterface,
767 sample_grabber_stream_timer_callback_AddRef,
768 sample_grabber_stream_timer_callback_Release,
769 sample_grabber_stream_timer_callback_GetParameters,
770 sample_grabber_stream_timer_callback_Invoke,
773 static HRESULT WINAPI sample_grabber_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj)
775 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
777 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
779 if (IsEqualIID(riid, &IID_IMFMediaSink) ||
780 IsEqualIID(riid, &IID_IUnknown))
782 *obj = &grabber->IMFMediaSink_iface;
784 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
786 *obj = &grabber->IMFClockStateSink_iface;
788 else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator))
790 *obj = &grabber->IMFMediaEventGenerator_iface;
792 else if (IsEqualIID(riid, &IID_IMFGetService))
794 *obj = &grabber->IMFGetService_iface;
796 else if (IsEqualIID(riid, &IID_IMFRateSupport))
798 *obj = &grabber->IMFRateSupport_iface;
800 else
802 WARN("Unsupported %s.\n", debugstr_guid(riid));
803 *obj = NULL;
804 return E_NOINTERFACE;
807 IUnknown_AddRef((IUnknown *)*obj);
809 return S_OK;
812 static ULONG WINAPI sample_grabber_sink_AddRef(IMFMediaSink *iface)
814 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
815 ULONG refcount = InterlockedIncrement(&grabber->refcount);
817 TRACE("%p, refcount %u.\n", iface, refcount);
819 return refcount;
822 static void sample_grabber_release_pending_items(struct sample_grabber *grabber)
824 struct scheduled_item *item, *next_item;
826 LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &grabber->items, struct scheduled_item, entry)
828 stream_release_pending_item(item);
832 static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface)
834 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
835 ULONG refcount = InterlockedDecrement(&grabber->refcount);
837 TRACE("%p, refcount %u.\n", iface, refcount);
839 if (!refcount)
841 if (grabber->callback)
842 IMFSampleGrabberSinkCallback_Release(grabber->callback);
843 if (grabber->callback2)
844 IMFSampleGrabberSinkCallback2_Release(grabber->callback2);
845 IMFMediaType_Release(grabber->current_media_type);
846 IMFMediaType_Release(grabber->media_type);
847 if (grabber->event_queue)
848 IMFMediaEventQueue_Release(grabber->event_queue);
849 if (grabber->clock)
850 IMFPresentationClock_Release(grabber->clock);
851 if (grabber->timer)
853 if (grabber->cancel_key)
854 IMFTimer_CancelTimer(grabber->timer, grabber->cancel_key);
855 IMFTimer_Release(grabber->timer);
857 if (grabber->cancel_key)
858 IUnknown_Release(grabber->cancel_key);
859 if (grabber->stream_event_queue)
861 IMFMediaEventQueue_Shutdown(grabber->stream_event_queue);
862 IMFMediaEventQueue_Release(grabber->stream_event_queue);
864 if (grabber->sample_attributes)
865 IMFAttributes_Release(grabber->sample_attributes);
866 sample_grabber_release_pending_items(grabber);
867 DeleteCriticalSection(&grabber->cs);
868 heap_free(grabber);
871 return refcount;
874 static HRESULT WINAPI sample_grabber_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *flags)
876 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
878 TRACE("%p, %p.\n", iface, flags);
880 if (grabber->is_shut_down)
881 return MF_E_SHUTDOWN;
883 *flags = MEDIASINK_FIXED_STREAMS;
884 if (grabber->ignore_clock)
885 *flags |= MEDIASINK_RATELESS;
887 return S_OK;
890 static HRESULT WINAPI sample_grabber_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id,
891 IMFMediaType *media_type, IMFStreamSink **stream_sink)
893 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
895 TRACE("%p, %#x, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink);
897 return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
900 static HRESULT WINAPI sample_grabber_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id)
902 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
904 TRACE("%p, %#x.\n", iface, stream_sink_id);
906 return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
909 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count)
911 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
913 TRACE("%p, %p.\n", iface, count);
915 if (grabber->is_shut_down)
916 return MF_E_SHUTDOWN;
918 *count = 1;
920 return S_OK;
923 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
924 IMFStreamSink **stream)
926 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
927 HRESULT hr = S_OK;
929 TRACE("%p, %u, %p.\n", iface, index, stream);
931 if (grabber->is_shut_down)
932 return MF_E_SHUTDOWN;
934 EnterCriticalSection(&grabber->cs);
936 if (grabber->is_shut_down)
937 hr = MF_E_SHUTDOWN;
938 else if (index > 0)
939 hr = MF_E_INVALIDINDEX;
940 else
942 *stream = &grabber->IMFStreamSink_iface;
943 IMFStreamSink_AddRef(*stream);
946 LeaveCriticalSection(&grabber->cs);
948 return hr;
951 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id,
952 IMFStreamSink **stream)
954 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
955 HRESULT hr = S_OK;
957 TRACE("%p, %#x, %p.\n", iface, stream_sink_id, stream);
959 EnterCriticalSection(&grabber->cs);
961 if (grabber->is_shut_down)
962 hr = MF_E_SHUTDOWN;
963 else if (stream_sink_id > 0)
964 hr = MF_E_INVALIDSTREAMNUMBER;
965 else
967 *stream = &grabber->IMFStreamSink_iface;
968 IMFStreamSink_AddRef(*stream);
971 LeaveCriticalSection(&grabber->cs);
973 return hr;
976 static void sample_grabber_set_presentation_clock(struct sample_grabber *grabber, IMFPresentationClock *clock)
978 if (grabber->clock)
980 IMFPresentationClock_RemoveClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
981 IMFPresentationClock_Release(grabber->clock);
982 if (grabber->timer)
984 IMFTimer_Release(grabber->timer);
985 grabber->timer = NULL;
988 grabber->clock = clock;
989 if (grabber->clock)
991 IMFPresentationClock_AddRef(grabber->clock);
992 IMFPresentationClock_AddClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
993 if (FAILED(IMFPresentationClock_QueryInterface(grabber->clock, &IID_IMFTimer, (void **)&grabber->timer)))
995 WARN("Failed to get IMFTimer interface.\n");
996 grabber->timer = NULL;
1001 static HRESULT WINAPI sample_grabber_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
1003 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1004 HRESULT hr;
1006 TRACE("%p, %p.\n", iface, clock);
1008 EnterCriticalSection(&grabber->cs);
1010 if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber),
1011 clock)))
1013 sample_grabber_set_presentation_clock(grabber, clock);
1016 LeaveCriticalSection(&grabber->cs);
1018 return hr;
1021 static HRESULT WINAPI sample_grabber_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock)
1023 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1024 HRESULT hr = S_OK;
1026 TRACE("%p, %p.\n", iface, clock);
1028 if (!clock)
1029 return E_POINTER;
1031 EnterCriticalSection(&grabber->cs);
1033 if (grabber->clock)
1035 *clock = grabber->clock;
1036 IMFPresentationClock_AddRef(*clock);
1038 else
1039 hr = MF_E_NO_CLOCK;
1041 LeaveCriticalSection(&grabber->cs);
1043 return hr;
1046 static HRESULT WINAPI sample_grabber_sink_Shutdown(IMFMediaSink *iface)
1048 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1049 HRESULT hr;
1051 TRACE("%p.\n", iface);
1053 if (grabber->is_shut_down)
1054 return MF_E_SHUTDOWN;
1056 EnterCriticalSection(&grabber->cs);
1057 grabber->is_shut_down = TRUE;
1058 sample_grabber_release_pending_items(grabber);
1059 if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber))))
1061 sample_grabber_set_presentation_clock(grabber, NULL);
1062 IMFMediaEventQueue_Shutdown(grabber->stream_event_queue);
1063 IMFMediaEventQueue_Shutdown(grabber->event_queue);
1065 LeaveCriticalSection(&grabber->cs);
1067 return hr;
1070 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl =
1072 sample_grabber_sink_QueryInterface,
1073 sample_grabber_sink_AddRef,
1074 sample_grabber_sink_Release,
1075 sample_grabber_sink_GetCharacteristics,
1076 sample_grabber_sink_AddStreamSink,
1077 sample_grabber_sink_RemoveStreamSink,
1078 sample_grabber_sink_GetStreamSinkCount,
1079 sample_grabber_sink_GetStreamSinkByIndex,
1080 sample_grabber_sink_GetStreamSinkById,
1081 sample_grabber_sink_SetPresentationClock,
1082 sample_grabber_sink_GetPresentationClock,
1083 sample_grabber_sink_Shutdown,
1086 static HRESULT WINAPI sample_grabber_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
1088 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1089 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1092 static ULONG WINAPI sample_grabber_clock_sink_AddRef(IMFClockStateSink *iface)
1094 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1095 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1098 static ULONG WINAPI sample_grabber_clock_sink_Release(IMFClockStateSink *iface)
1100 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1101 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1104 static void sample_grabber_set_state(struct sample_grabber *grabber, enum sink_state state)
1106 static const DWORD events[] =
1108 MEStreamSinkStopped, /* SINK_STATE_STOPPED */
1109 MEStreamSinkStarted, /* SINK_STATE_RUNNING */
1111 BOOL set_state = FALSE;
1112 unsigned int i;
1114 EnterCriticalSection(&grabber->cs);
1116 if (!grabber->is_shut_down)
1118 switch (grabber->state)
1120 case SINK_STATE_STOPPED:
1121 set_state = state == SINK_STATE_RUNNING;
1122 break;
1123 case SINK_STATE_RUNNING:
1124 set_state = state == SINK_STATE_STOPPED;
1125 break;
1126 default:
1130 if (set_state)
1132 grabber->state = state;
1133 if (state == SINK_STATE_RUNNING)
1135 /* Every transition to running state sends a bunch requests to build up initial queue. */
1136 for (i = 0; i < 4; ++i)
1137 sample_grabber_stream_request_sample(grabber);
1139 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, events[state], &GUID_NULL, S_OK, NULL);
1143 LeaveCriticalSection(&grabber->cs);
1146 static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
1148 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1150 TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
1152 sample_grabber_set_state(grabber, SINK_STATE_RUNNING);
1154 return IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber), systime, offset);
1157 static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
1159 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1161 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1163 sample_grabber_set_state(grabber, SINK_STATE_STOPPED);
1165 return IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber), systime);
1168 static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
1170 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1172 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1174 return IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber), systime);
1177 static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
1179 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1181 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1183 sample_grabber_set_state(grabber, SINK_STATE_RUNNING);
1185 return IMFSampleGrabberSinkCallback_OnClockRestart(sample_grabber_get_callback(grabber), systime);
1188 static HRESULT WINAPI sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
1190 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1192 TRACE("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
1194 return IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber), systime, rate);
1197 static HRESULT WINAPI sample_grabber_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj)
1199 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1200 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1203 static ULONG WINAPI sample_grabber_events_AddRef(IMFMediaEventGenerator *iface)
1205 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1206 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1209 static ULONG WINAPI sample_grabber_events_Release(IMFMediaEventGenerator *iface)
1211 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1212 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1215 static HRESULT WINAPI sample_grabber_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event)
1217 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1219 TRACE("%p, %#x, %p.\n", iface, flags, event);
1221 return IMFMediaEventQueue_GetEvent(grabber->event_queue, flags, event);
1224 static HRESULT WINAPI sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback,
1225 IUnknown *state)
1227 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1229 TRACE("%p, %p, %p.\n", iface, callback, state);
1231 return IMFMediaEventQueue_BeginGetEvent(grabber->event_queue, callback, state);
1234 static HRESULT WINAPI sample_grabber_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result,
1235 IMFMediaEvent **event)
1237 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1239 TRACE("%p, %p, %p.\n", iface, result, event);
1241 return IMFMediaEventQueue_EndGetEvent(grabber->event_queue, result, event);
1244 static HRESULT WINAPI sample_grabber_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type,
1245 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
1247 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1249 TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1251 return IMFMediaEventQueue_QueueEventParamVar(grabber->event_queue, event_type, ext_type, hr, value);
1254 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl =
1256 sample_grabber_events_QueryInterface,
1257 sample_grabber_events_AddRef,
1258 sample_grabber_events_Release,
1259 sample_grabber_events_GetEvent,
1260 sample_grabber_events_BeginGetEvent,
1261 sample_grabber_events_EndGetEvent,
1262 sample_grabber_events_QueueEvent,
1265 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl =
1267 sample_grabber_clock_sink_QueryInterface,
1268 sample_grabber_clock_sink_AddRef,
1269 sample_grabber_clock_sink_Release,
1270 sample_grabber_clock_sink_OnClockStart,
1271 sample_grabber_clock_sink_OnClockStop,
1272 sample_grabber_clock_sink_OnClockPause,
1273 sample_grabber_clock_sink_OnClockRestart,
1274 sample_grabber_clock_sink_OnClockSetRate,
1277 static HRESULT WINAPI sample_grabber_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1279 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1280 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1283 static ULONG WINAPI sample_grabber_getservice_AddRef(IMFGetService *iface)
1285 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1286 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1289 static ULONG WINAPI sample_grabber_getservice_Release(IMFGetService *iface)
1291 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1292 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1295 static HRESULT WINAPI sample_grabber_getservice_GetService(IMFGetService *iface, REFGUID service,
1296 REFIID riid, void **obj)
1298 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1300 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1302 if (IsEqualIID(riid, &IID_IMFRateSupport))
1303 return IMFGetService_QueryInterface(iface, riid, obj);
1305 return E_NOINTERFACE;
1308 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service), debugstr_guid(riid));
1310 return MF_E_UNSUPPORTED_SERVICE;
1313 static const IMFGetServiceVtbl sample_grabber_getservice_vtbl =
1315 sample_grabber_getservice_QueryInterface,
1316 sample_grabber_getservice_AddRef,
1317 sample_grabber_getservice_Release,
1318 sample_grabber_getservice_GetService,
1321 static HRESULT WINAPI sample_grabber_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1323 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1324 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1327 static ULONG WINAPI sample_grabber_rate_support_AddRef(IMFRateSupport *iface)
1329 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1330 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1333 static ULONG WINAPI sample_grabber_rate_support_Release(IMFRateSupport *iface)
1335 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1336 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1339 static HRESULT WINAPI sample_grabber_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1340 BOOL thin, float *rate)
1342 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1344 *rate = 0.0f;
1346 return S_OK;
1349 static HRESULT WINAPI sample_grabber_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1350 BOOL thin, float *rate)
1352 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1354 *rate = direction == MFRATE_REVERSE ? -FLT_MAX : FLT_MAX;
1356 return S_OK;
1359 static HRESULT WINAPI sample_grabber_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1360 float *ret_rate)
1362 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, ret_rate);
1364 if (ret_rate)
1365 *ret_rate = rate;
1367 return S_OK;
1370 static const IMFRateSupportVtbl sample_grabber_rate_support_vtbl =
1372 sample_grabber_rate_support_QueryInterface,
1373 sample_grabber_rate_support_AddRef,
1374 sample_grabber_rate_support_Release,
1375 sample_grabber_rate_support_GetSlowestRate,
1376 sample_grabber_rate_support_GetFastestRate,
1377 sample_grabber_rate_support_IsRateSupported,
1380 static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
1382 struct sample_grabber_activate_context *context = user_context;
1383 struct sample_grabber *object;
1384 HRESULT hr;
1385 GUID guid;
1387 TRACE("%p, %p, %p.\n", attributes, user_context, obj);
1389 if (context->shut_down)
1390 return MF_E_SHUTDOWN;
1392 /* At least major type is required. */
1393 if (FAILED(IMFMediaType_GetMajorType(context->media_type, &guid)))
1394 return MF_E_INVALIDMEDIATYPE;
1396 object = heap_alloc_zero(sizeof(*object));
1397 if (!object)
1398 return E_OUTOFMEMORY;
1400 object->IMFMediaSink_iface.lpVtbl = &sample_grabber_sink_vtbl;
1401 object->IMFClockStateSink_iface.lpVtbl = &sample_grabber_clock_sink_vtbl;
1402 object->IMFMediaEventGenerator_iface.lpVtbl = &sample_grabber_sink_events_vtbl;
1403 object->IMFGetService_iface.lpVtbl = &sample_grabber_getservice_vtbl;
1404 object->IMFRateSupport_iface.lpVtbl = &sample_grabber_rate_support_vtbl;
1405 object->IMFStreamSink_iface.lpVtbl = &sample_grabber_stream_vtbl;
1406 object->IMFMediaTypeHandler_iface.lpVtbl = &sample_grabber_stream_type_handler_vtbl;
1407 object->timer_callback.lpVtbl = &sample_grabber_stream_timer_callback_vtbl;
1408 object->refcount = 1;
1409 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context->callback, &IID_IMFSampleGrabberSinkCallback2,
1410 (void **)&object->callback2)))
1412 object->callback = context->callback;
1413 IMFSampleGrabberSinkCallback_AddRef(object->callback);
1415 object->media_type = context->media_type;
1416 IMFMediaType_AddRef(object->media_type);
1417 object->current_media_type = context->media_type;
1418 IMFMediaType_AddRef(object->current_media_type);
1419 IMFAttributes_GetUINT32(attributes, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, &object->ignore_clock);
1420 IMFAttributes_GetUINT64(attributes, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET, &object->sample_time_offset);
1421 list_init(&object->items);
1422 InitializeCriticalSection(&object->cs);
1424 if (FAILED(hr = MFCreateEventQueue(&object->stream_event_queue)))
1425 goto failed;
1427 if (FAILED(hr = MFCreateAttributes(&object->sample_attributes, 0)))
1428 goto failed;
1430 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1431 goto failed;
1433 *obj = (IUnknown *)&object->IMFMediaSink_iface;
1435 TRACE("Created %p.\n", *obj);
1437 return S_OK;
1439 failed:
1441 IMFMediaSink_Release(&object->IMFMediaSink_iface);
1443 return hr;
1446 static void sample_grabber_shutdown_object(void *user_context, IUnknown *obj)
1448 struct sample_grabber_activate_context *context = user_context;
1449 context->shut_down = TRUE;
1452 static const struct activate_funcs sample_grabber_activate_funcs =
1454 sample_grabber_create_object,
1455 sample_grabber_shutdown_object,
1456 sample_grabber_free_private,
1459 /***********************************************************************
1460 * MFCreateSampleGrabberSinkActivate (mf.@)
1462 HRESULT WINAPI MFCreateSampleGrabberSinkActivate(IMFMediaType *media_type, IMFSampleGrabberSinkCallback *callback,
1463 IMFActivate **activate)
1465 struct sample_grabber_activate_context *context;
1466 HRESULT hr;
1468 TRACE("%p, %p, %p.\n", media_type, callback, activate);
1470 if (!media_type || !callback || !activate)
1471 return E_POINTER;
1473 context = heap_alloc_zero(sizeof(*context));
1474 if (!context)
1475 return E_OUTOFMEMORY;
1477 context->media_type = media_type;
1478 IMFMediaType_AddRef(context->media_type);
1479 context->callback = callback;
1480 IMFSampleGrabberSinkCallback_AddRef(context->callback);
1482 if (FAILED(hr = create_activation_object(context, &sample_grabber_activate_funcs, activate)))
1483 sample_grabber_free_private(context);
1485 return hr;