d3d10: Return the read value from read_dword().
[wine.git] / dlls / mf / samplegrabber.c
blobe7d3be68df3ffd2cb0b11b186ff8f8dd1cb2da0c
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/list.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
31 enum sink_state
33 SINK_STATE_STOPPED = 0,
34 SINK_STATE_PAUSED,
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 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 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 = calloc(1, 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 = calloc(1, 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)
852 IMFTimer_Release(grabber->timer);
853 if (grabber->cancel_key)
854 IUnknown_Release(grabber->cancel_key);
855 if (grabber->stream_event_queue)
857 IMFMediaEventQueue_Shutdown(grabber->stream_event_queue);
858 IMFMediaEventQueue_Release(grabber->stream_event_queue);
860 if (grabber->sample_attributes)
861 IMFAttributes_Release(grabber->sample_attributes);
862 sample_grabber_release_pending_items(grabber);
863 DeleteCriticalSection(&grabber->cs);
864 free(grabber);
867 return refcount;
870 static HRESULT WINAPI sample_grabber_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *flags)
872 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
874 TRACE("%p, %p.\n", iface, flags);
876 if (grabber->is_shut_down)
877 return MF_E_SHUTDOWN;
879 *flags = MEDIASINK_FIXED_STREAMS;
880 if (grabber->ignore_clock)
881 *flags |= MEDIASINK_RATELESS;
883 return S_OK;
886 static HRESULT WINAPI sample_grabber_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id,
887 IMFMediaType *media_type, IMFStreamSink **stream_sink)
889 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
891 TRACE("%p, %#x, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink);
893 return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
896 static HRESULT WINAPI sample_grabber_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id)
898 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
900 TRACE("%p, %#x.\n", iface, stream_sink_id);
902 return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
905 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count)
907 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
909 TRACE("%p, %p.\n", iface, count);
911 if (grabber->is_shut_down)
912 return MF_E_SHUTDOWN;
914 *count = 1;
916 return S_OK;
919 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
920 IMFStreamSink **stream)
922 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
923 HRESULT hr = S_OK;
925 TRACE("%p, %u, %p.\n", iface, index, stream);
927 if (grabber->is_shut_down)
928 return MF_E_SHUTDOWN;
930 EnterCriticalSection(&grabber->cs);
932 if (grabber->is_shut_down)
933 hr = MF_E_SHUTDOWN;
934 else if (index > 0)
935 hr = MF_E_INVALIDINDEX;
936 else
938 *stream = &grabber->IMFStreamSink_iface;
939 IMFStreamSink_AddRef(*stream);
942 LeaveCriticalSection(&grabber->cs);
944 return hr;
947 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id,
948 IMFStreamSink **stream)
950 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
951 HRESULT hr = S_OK;
953 TRACE("%p, %#x, %p.\n", iface, stream_sink_id, stream);
955 EnterCriticalSection(&grabber->cs);
957 if (grabber->is_shut_down)
958 hr = MF_E_SHUTDOWN;
959 else if (stream_sink_id > 0)
960 hr = MF_E_INVALIDSTREAMNUMBER;
961 else
963 *stream = &grabber->IMFStreamSink_iface;
964 IMFStreamSink_AddRef(*stream);
967 LeaveCriticalSection(&grabber->cs);
969 return hr;
972 static void sample_grabber_cancel_timer(struct sample_grabber *grabber)
974 if (grabber->timer && grabber->cancel_key)
976 IMFTimer_CancelTimer(grabber->timer, grabber->cancel_key);
977 IUnknown_Release(grabber->cancel_key);
978 grabber->cancel_key = NULL;
982 static void sample_grabber_set_presentation_clock(struct sample_grabber *grabber, IMFPresentationClock *clock)
984 if (grabber->clock)
986 sample_grabber_cancel_timer(grabber);
987 IMFPresentationClock_RemoveClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
988 IMFPresentationClock_Release(grabber->clock);
989 if (grabber->timer)
991 IMFTimer_Release(grabber->timer);
992 grabber->timer = NULL;
995 grabber->clock = clock;
996 if (grabber->clock)
998 IMFPresentationClock_AddRef(grabber->clock);
999 IMFPresentationClock_AddClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
1000 if (FAILED(IMFPresentationClock_QueryInterface(grabber->clock, &IID_IMFTimer, (void **)&grabber->timer)))
1002 WARN("Failed to get IMFTimer interface.\n");
1003 grabber->timer = NULL;
1008 static HRESULT WINAPI sample_grabber_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
1010 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1011 HRESULT hr;
1013 TRACE("%p, %p.\n", iface, clock);
1015 EnterCriticalSection(&grabber->cs);
1017 if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber),
1018 clock)))
1020 sample_grabber_set_presentation_clock(grabber, clock);
1023 LeaveCriticalSection(&grabber->cs);
1025 return hr;
1028 static HRESULT WINAPI sample_grabber_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock)
1030 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1031 HRESULT hr = S_OK;
1033 TRACE("%p, %p.\n", iface, clock);
1035 if (!clock)
1036 return E_POINTER;
1038 EnterCriticalSection(&grabber->cs);
1040 if (grabber->clock)
1042 *clock = grabber->clock;
1043 IMFPresentationClock_AddRef(*clock);
1045 else
1046 hr = MF_E_NO_CLOCK;
1048 LeaveCriticalSection(&grabber->cs);
1050 return hr;
1053 static HRESULT WINAPI sample_grabber_sink_Shutdown(IMFMediaSink *iface)
1055 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1056 HRESULT hr;
1058 TRACE("%p.\n", iface);
1060 if (grabber->is_shut_down)
1061 return MF_E_SHUTDOWN;
1063 EnterCriticalSection(&grabber->cs);
1064 grabber->is_shut_down = TRUE;
1065 sample_grabber_release_pending_items(grabber);
1066 if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber))))
1068 sample_grabber_set_presentation_clock(grabber, NULL);
1069 IMFMediaEventQueue_Shutdown(grabber->stream_event_queue);
1070 IMFMediaEventQueue_Shutdown(grabber->event_queue);
1072 LeaveCriticalSection(&grabber->cs);
1074 return hr;
1077 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl =
1079 sample_grabber_sink_QueryInterface,
1080 sample_grabber_sink_AddRef,
1081 sample_grabber_sink_Release,
1082 sample_grabber_sink_GetCharacteristics,
1083 sample_grabber_sink_AddStreamSink,
1084 sample_grabber_sink_RemoveStreamSink,
1085 sample_grabber_sink_GetStreamSinkCount,
1086 sample_grabber_sink_GetStreamSinkByIndex,
1087 sample_grabber_sink_GetStreamSinkById,
1088 sample_grabber_sink_SetPresentationClock,
1089 sample_grabber_sink_GetPresentationClock,
1090 sample_grabber_sink_Shutdown,
1093 static HRESULT WINAPI sample_grabber_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
1095 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1096 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1099 static ULONG WINAPI sample_grabber_clock_sink_AddRef(IMFClockStateSink *iface)
1101 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1102 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1105 static ULONG WINAPI sample_grabber_clock_sink_Release(IMFClockStateSink *iface)
1107 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1108 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1111 static HRESULT sample_grabber_set_state(struct sample_grabber *grabber, enum sink_state state,
1112 MFTIME systime, LONGLONG offset)
1114 static const DWORD events[] =
1116 MEStreamSinkStopped, /* SINK_STATE_STOPPED */
1117 MEStreamSinkPaused, /* SINK_STATE_PAUSED */
1118 MEStreamSinkStarted, /* SINK_STATE_RUNNING */
1120 BOOL do_callback = FALSE;
1121 HRESULT hr = S_OK;
1122 unsigned int i;
1124 EnterCriticalSection(&grabber->cs);
1126 if (!grabber->is_shut_down)
1128 if (state == SINK_STATE_PAUSED && grabber->state == SINK_STATE_STOPPED)
1129 hr = MF_E_INVALID_STATE_TRANSITION;
1130 else
1132 if (state == SINK_STATE_STOPPED)
1133 sample_grabber_cancel_timer(grabber);
1135 if (state == SINK_STATE_RUNNING && grabber->state == SINK_STATE_STOPPED)
1137 /* Every transition to running state sends a bunch requests to build up initial queue. */
1138 for (i = 0; i < 4; ++i)
1139 sample_grabber_stream_request_sample(grabber);
1141 do_callback = state != grabber->state || state != SINK_STATE_PAUSED;
1142 if (do_callback)
1143 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, events[state], &GUID_NULL, S_OK, NULL);
1144 grabber->state = state;
1148 LeaveCriticalSection(&grabber->cs);
1150 if (do_callback)
1152 switch (state)
1154 case SINK_STATE_STOPPED:
1155 hr = IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber), systime);
1156 break;
1157 case SINK_STATE_PAUSED:
1158 hr = IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber), systime);
1159 break;
1160 case SINK_STATE_RUNNING:
1161 hr = IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber), systime, offset);
1162 break;
1166 return hr;
1169 static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
1171 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1173 TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
1175 return sample_grabber_set_state(grabber, SINK_STATE_RUNNING, systime, offset);
1178 static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
1180 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1182 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1184 return sample_grabber_set_state(grabber, SINK_STATE_STOPPED, systime, 0);
1187 static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
1189 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1191 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1193 return sample_grabber_set_state(grabber, SINK_STATE_PAUSED, systime, 0);
1196 static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
1198 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1200 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1202 return sample_grabber_set_state(grabber, SINK_STATE_RUNNING, systime, PRESENTATION_CURRENT_POSITION);
1205 static HRESULT WINAPI sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
1207 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1209 TRACE("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
1211 return IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber), systime, rate);
1214 static HRESULT WINAPI sample_grabber_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj)
1216 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1217 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1220 static ULONG WINAPI sample_grabber_events_AddRef(IMFMediaEventGenerator *iface)
1222 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1223 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1226 static ULONG WINAPI sample_grabber_events_Release(IMFMediaEventGenerator *iface)
1228 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1229 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1232 static HRESULT WINAPI sample_grabber_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event)
1234 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1236 TRACE("%p, %#x, %p.\n", iface, flags, event);
1238 return IMFMediaEventQueue_GetEvent(grabber->event_queue, flags, event);
1241 static HRESULT WINAPI sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback,
1242 IUnknown *state)
1244 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1246 TRACE("%p, %p, %p.\n", iface, callback, state);
1248 return IMFMediaEventQueue_BeginGetEvent(grabber->event_queue, callback, state);
1251 static HRESULT WINAPI sample_grabber_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result,
1252 IMFMediaEvent **event)
1254 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1256 TRACE("%p, %p, %p.\n", iface, result, event);
1258 return IMFMediaEventQueue_EndGetEvent(grabber->event_queue, result, event);
1261 static HRESULT WINAPI sample_grabber_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type,
1262 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
1264 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1266 TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1268 return IMFMediaEventQueue_QueueEventParamVar(grabber->event_queue, event_type, ext_type, hr, value);
1271 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl =
1273 sample_grabber_events_QueryInterface,
1274 sample_grabber_events_AddRef,
1275 sample_grabber_events_Release,
1276 sample_grabber_events_GetEvent,
1277 sample_grabber_events_BeginGetEvent,
1278 sample_grabber_events_EndGetEvent,
1279 sample_grabber_events_QueueEvent,
1282 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl =
1284 sample_grabber_clock_sink_QueryInterface,
1285 sample_grabber_clock_sink_AddRef,
1286 sample_grabber_clock_sink_Release,
1287 sample_grabber_clock_sink_OnClockStart,
1288 sample_grabber_clock_sink_OnClockStop,
1289 sample_grabber_clock_sink_OnClockPause,
1290 sample_grabber_clock_sink_OnClockRestart,
1291 sample_grabber_clock_sink_OnClockSetRate,
1294 static HRESULT WINAPI sample_grabber_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1296 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1297 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1300 static ULONG WINAPI sample_grabber_getservice_AddRef(IMFGetService *iface)
1302 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1303 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1306 static ULONG WINAPI sample_grabber_getservice_Release(IMFGetService *iface)
1308 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1309 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1312 static HRESULT WINAPI sample_grabber_getservice_GetService(IMFGetService *iface, REFGUID service,
1313 REFIID riid, void **obj)
1315 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1317 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1319 if (IsEqualIID(riid, &IID_IMFRateSupport))
1320 return IMFGetService_QueryInterface(iface, riid, obj);
1322 return E_NOINTERFACE;
1325 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service), debugstr_guid(riid));
1327 return MF_E_UNSUPPORTED_SERVICE;
1330 static const IMFGetServiceVtbl sample_grabber_getservice_vtbl =
1332 sample_grabber_getservice_QueryInterface,
1333 sample_grabber_getservice_AddRef,
1334 sample_grabber_getservice_Release,
1335 sample_grabber_getservice_GetService,
1338 static HRESULT WINAPI sample_grabber_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1340 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1341 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1344 static ULONG WINAPI sample_grabber_rate_support_AddRef(IMFRateSupport *iface)
1346 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1347 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1350 static ULONG WINAPI sample_grabber_rate_support_Release(IMFRateSupport *iface)
1352 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1353 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1356 static HRESULT WINAPI sample_grabber_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1357 BOOL thin, float *rate)
1359 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1361 *rate = 0.0f;
1363 return S_OK;
1366 static HRESULT WINAPI sample_grabber_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1367 BOOL thin, float *rate)
1369 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1371 *rate = direction == MFRATE_REVERSE ? -FLT_MAX : FLT_MAX;
1373 return S_OK;
1376 static HRESULT WINAPI sample_grabber_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1377 float *ret_rate)
1379 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, ret_rate);
1381 if (ret_rate)
1382 *ret_rate = rate;
1384 return S_OK;
1387 static const IMFRateSupportVtbl sample_grabber_rate_support_vtbl =
1389 sample_grabber_rate_support_QueryInterface,
1390 sample_grabber_rate_support_AddRef,
1391 sample_grabber_rate_support_Release,
1392 sample_grabber_rate_support_GetSlowestRate,
1393 sample_grabber_rate_support_GetFastestRate,
1394 sample_grabber_rate_support_IsRateSupported,
1397 static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
1399 struct sample_grabber_activate_context *context = user_context;
1400 struct sample_grabber *object;
1401 HRESULT hr;
1402 GUID guid;
1404 TRACE("%p, %p, %p.\n", attributes, user_context, obj);
1406 if (context->shut_down)
1407 return MF_E_SHUTDOWN;
1409 /* At least major type is required. */
1410 if (FAILED(IMFMediaType_GetMajorType(context->media_type, &guid)))
1411 return MF_E_INVALIDMEDIATYPE;
1413 if (!(object = calloc(1, sizeof(*object))))
1414 return E_OUTOFMEMORY;
1416 object->IMFMediaSink_iface.lpVtbl = &sample_grabber_sink_vtbl;
1417 object->IMFClockStateSink_iface.lpVtbl = &sample_grabber_clock_sink_vtbl;
1418 object->IMFMediaEventGenerator_iface.lpVtbl = &sample_grabber_sink_events_vtbl;
1419 object->IMFGetService_iface.lpVtbl = &sample_grabber_getservice_vtbl;
1420 object->IMFRateSupport_iface.lpVtbl = &sample_grabber_rate_support_vtbl;
1421 object->IMFStreamSink_iface.lpVtbl = &sample_grabber_stream_vtbl;
1422 object->IMFMediaTypeHandler_iface.lpVtbl = &sample_grabber_stream_type_handler_vtbl;
1423 object->timer_callback.lpVtbl = &sample_grabber_stream_timer_callback_vtbl;
1424 object->refcount = 1;
1425 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context->callback, &IID_IMFSampleGrabberSinkCallback2,
1426 (void **)&object->callback2)))
1428 object->callback = context->callback;
1429 IMFSampleGrabberSinkCallback_AddRef(object->callback);
1431 object->media_type = context->media_type;
1432 IMFMediaType_AddRef(object->media_type);
1433 object->current_media_type = context->media_type;
1434 IMFMediaType_AddRef(object->current_media_type);
1435 IMFAttributes_GetUINT32(attributes, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, &object->ignore_clock);
1436 IMFAttributes_GetUINT64(attributes, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET, &object->sample_time_offset);
1437 list_init(&object->items);
1438 InitializeCriticalSection(&object->cs);
1440 if (FAILED(hr = MFCreateEventQueue(&object->stream_event_queue)))
1441 goto failed;
1443 if (FAILED(hr = MFCreateAttributes(&object->sample_attributes, 0)))
1444 goto failed;
1446 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1447 goto failed;
1449 *obj = (IUnknown *)&object->IMFMediaSink_iface;
1451 TRACE("Created %p.\n", *obj);
1453 return S_OK;
1455 failed:
1457 IMFMediaSink_Release(&object->IMFMediaSink_iface);
1459 return hr;
1462 static void sample_grabber_shutdown_object(void *user_context, IUnknown *obj)
1464 struct sample_grabber_activate_context *context = user_context;
1465 context->shut_down = TRUE;
1468 static const struct activate_funcs sample_grabber_activate_funcs =
1470 sample_grabber_create_object,
1471 sample_grabber_shutdown_object,
1472 sample_grabber_free_private,
1475 /***********************************************************************
1476 * MFCreateSampleGrabberSinkActivate (mf.@)
1478 HRESULT WINAPI MFCreateSampleGrabberSinkActivate(IMFMediaType *media_type, IMFSampleGrabberSinkCallback *callback,
1479 IMFActivate **activate)
1481 struct sample_grabber_activate_context *context;
1482 HRESULT hr;
1484 TRACE("%p, %p, %p.\n", media_type, callback, activate);
1486 if (!media_type || !callback || !activate)
1487 return E_POINTER;
1489 if (!(context = calloc(1, sizeof(*context))))
1490 return E_OUTOFMEMORY;
1492 context->media_type = media_type;
1493 IMFMediaType_AddRef(context->media_type);
1494 context->callback = callback;
1495 IMFSampleGrabberSinkCallback_AddRef(context->callback);
1497 if (FAILED(hr = create_activation_object(context, &sample_grabber_activate_funcs, activate)))
1498 sample_grabber_free_private(context);
1500 return hr;