Remove unused NONAMELESS defines.
[wine.git] / dlls / mf / samplegrabber.c
blobdeb1ce09a55f10ed7cceff197d91e22e56e846d0
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>
22 #include <assert.h>
24 #include "mfidl.h"
25 #include "mf_private.h"
27 #include "wine/debug.h"
28 #include "wine/list.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
32 enum sink_state
34 SINK_STATE_STOPPED = 0,
35 SINK_STATE_PAUSED,
36 SINK_STATE_RUNNING,
39 struct sample_grabber;
41 enum scheduled_item_type
43 ITEM_TYPE_SAMPLE,
44 ITEM_TYPE_MARKER,
47 struct scheduled_item
49 struct list entry;
50 enum scheduled_item_type type;
51 union
53 IMFSample *sample;
54 struct
56 MFSTREAMSINK_MARKER_TYPE type;
57 PROPVARIANT context;
58 } marker;
59 } u;
62 #define MAX_SAMPLE_QUEUE_LENGTH 4
64 struct sample_grabber
66 IMFMediaSink IMFMediaSink_iface;
67 IMFClockStateSink IMFClockStateSink_iface;
68 IMFMediaEventGenerator IMFMediaEventGenerator_iface;
69 IMFGetService IMFGetService_iface;
70 IMFRateSupport IMFRateSupport_iface;
71 IMFStreamSink IMFStreamSink_iface;
72 IMFMediaTypeHandler IMFMediaTypeHandler_iface;
73 IMFAsyncCallback timer_callback;
74 LONG refcount;
75 IMFSampleGrabberSinkCallback *callback;
76 IMFSampleGrabberSinkCallback2 *callback2;
77 IMFMediaType *media_type;
78 IMFMediaType *current_media_type;
79 BOOL is_shut_down;
80 IMFMediaEventQueue *event_queue;
81 IMFMediaEventQueue *stream_event_queue;
82 IMFPresentationClock *clock;
83 IMFTimer *timer;
84 IMFAttributes *sample_attributes;
85 struct list items;
86 IUnknown *cancel_key;
87 UINT32 ignore_clock;
88 UINT64 sample_time_offset;
89 float rate;
90 enum sink_state state;
91 CRITICAL_SECTION cs;
92 UINT32 sample_count;
93 IMFSample *samples[MAX_SAMPLE_QUEUE_LENGTH];
96 static IMFSampleGrabberSinkCallback *sample_grabber_get_callback(const struct sample_grabber *sink)
98 return sink->callback2 ? (IMFSampleGrabberSinkCallback *)sink->callback2 : sink->callback;
101 struct sample_grabber_activate_context
103 IMFMediaType *media_type;
104 IMFSampleGrabberSinkCallback *callback;
105 BOOL shut_down;
108 static void sample_grabber_free_private(void *user_context)
110 struct sample_grabber_activate_context *context = user_context;
111 IMFMediaType_Release(context->media_type);
112 IMFSampleGrabberSinkCallback_Release(context->callback);
113 free(context);
116 static struct sample_grabber *impl_from_IMFMediaSink(IMFMediaSink *iface)
118 return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaSink_iface);
121 static struct sample_grabber *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
123 return CONTAINING_RECORD(iface, struct sample_grabber, IMFClockStateSink_iface);
126 static struct sample_grabber *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface)
128 return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaEventGenerator_iface);
131 static struct sample_grabber *impl_from_IMFGetService(IMFGetService *iface)
133 return CONTAINING_RECORD(iface, struct sample_grabber, IMFGetService_iface);
136 static struct sample_grabber *impl_from_IMFRateSupport(IMFRateSupport *iface)
138 return CONTAINING_RECORD(iface, struct sample_grabber, IMFRateSupport_iface);
141 static struct sample_grabber *impl_from_IMFStreamSink(IMFStreamSink *iface)
143 return CONTAINING_RECORD(iface, struct sample_grabber, IMFStreamSink_iface);
146 static struct sample_grabber *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface)
148 return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaTypeHandler_iface);
151 static struct sample_grabber *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
153 return CONTAINING_RECORD(iface, struct sample_grabber, timer_callback);
156 static HRESULT WINAPI sample_grabber_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj)
158 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
160 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
162 if (IsEqualIID(riid, &IID_IMFStreamSink) ||
163 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
164 IsEqualIID(riid, &IID_IUnknown))
166 *obj = &grabber->IMFStreamSink_iface;
168 else if (IsEqualIID(riid, &IID_IMFMediaTypeHandler))
170 *obj = &grabber->IMFMediaTypeHandler_iface;
172 else
174 WARN("Unsupported %s.\n", debugstr_guid(riid));
175 *obj = NULL;
176 return E_NOINTERFACE;
179 IUnknown_AddRef((IUnknown *)*obj);
181 return S_OK;
184 static ULONG WINAPI sample_grabber_stream_AddRef(IMFStreamSink *iface)
186 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
187 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
190 static void stream_release_pending_item(struct scheduled_item *item)
192 list_remove(&item->entry);
193 switch (item->type)
195 case ITEM_TYPE_SAMPLE:
196 IMFSample_Release(item->u.sample);
197 break;
198 case ITEM_TYPE_MARKER:
199 PropVariantClear(&item->u.marker.context);
200 break;
202 free(item);
205 static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface)
207 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
208 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
211 static HRESULT WINAPI sample_grabber_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event)
213 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
215 TRACE("%p, %#lx, %p.\n", iface, flags, event);
217 if (grabber->is_shut_down)
218 return MF_E_STREAMSINK_REMOVED;
220 return IMFMediaEventQueue_GetEvent(grabber->stream_event_queue, flags, event);
223 static HRESULT WINAPI sample_grabber_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback,
224 IUnknown *state)
226 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
228 TRACE("%p, %p, %p.\n", iface, callback, state);
230 if (grabber->is_shut_down)
231 return MF_E_STREAMSINK_REMOVED;
233 return IMFMediaEventQueue_BeginGetEvent(grabber->stream_event_queue, callback, state);
236 static HRESULT WINAPI sample_grabber_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result,
237 IMFMediaEvent **event)
239 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
241 TRACE("%p, %p, %p.\n", iface, result, event);
243 if (grabber->is_shut_down)
244 return MF_E_STREAMSINK_REMOVED;
246 return IMFMediaEventQueue_EndGetEvent(grabber->stream_event_queue, result, event);
249 static HRESULT WINAPI sample_grabber_stream_QueueEvent(IMFStreamSink *iface, MediaEventType event_type,
250 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
252 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
254 TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
256 if (grabber->is_shut_down)
257 return MF_E_STREAMSINK_REMOVED;
259 return IMFMediaEventQueue_QueueEventParamVar(grabber->stream_event_queue, event_type, ext_type, hr, value);
262 static HRESULT WINAPI sample_grabber_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink)
264 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
266 TRACE("%p, %p.\n", iface, sink);
268 if (grabber->is_shut_down)
269 return MF_E_STREAMSINK_REMOVED;
271 *sink = &grabber->IMFMediaSink_iface;
272 IMFMediaSink_AddRef(*sink);
274 return S_OK;
277 static HRESULT WINAPI sample_grabber_stream_GetIdentifier(IMFStreamSink *iface, DWORD *identifier)
279 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
281 TRACE("%p, %p.\n", iface, identifier);
283 if (grabber->is_shut_down)
284 return MF_E_STREAMSINK_REMOVED;
286 *identifier = 0;
288 return S_OK;
291 static HRESULT WINAPI sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler)
293 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
295 TRACE("%p, %p.\n", iface, handler);
297 if (!handler)
298 return E_POINTER;
300 if (grabber->is_shut_down)
301 return MF_E_STREAMSINK_REMOVED;
303 *handler = &grabber->IMFMediaTypeHandler_iface;
304 IMFMediaTypeHandler_AddRef(*handler);
306 return S_OK;
309 static HRESULT sample_grabber_report_sample(struct sample_grabber *grabber, IMFSample *sample, BOOL *sample_delivered)
311 LONGLONG sample_time, sample_duration = 0;
312 IMFMediaBuffer *buffer;
313 DWORD flags, size;
314 GUID major_type;
315 BYTE *data;
316 HRESULT hr;
318 *sample_delivered = FALSE;
320 hr = IMFMediaType_GetMajorType(grabber->media_type, &major_type);
322 if (SUCCEEDED(hr))
323 hr = IMFSample_GetSampleTime(sample, &sample_time);
325 if (FAILED(IMFSample_GetSampleDuration(sample, &sample_duration)))
326 sample_duration = 0;
328 if (SUCCEEDED(hr))
329 hr = IMFSample_GetSampleFlags(sample, &flags);
331 if (SUCCEEDED(hr))
333 if (FAILED(IMFSample_ConvertToContiguousBuffer(sample, &buffer)))
334 return E_UNEXPECTED;
336 if (SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, &size)))
338 *sample_delivered = TRUE;
340 if (grabber->callback2)
342 hr = IMFSample_CopyAllItems(sample, grabber->sample_attributes);
343 if (SUCCEEDED(hr))
344 hr = IMFSampleGrabberSinkCallback2_OnProcessSampleEx(grabber->callback2, &major_type, flags,
345 sample_time, sample_duration, data, size, grabber->sample_attributes);
347 else
348 hr = IMFSampleGrabberSinkCallback_OnProcessSample(grabber->callback, &major_type, flags, sample_time,
349 sample_duration, data, size);
350 IMFMediaBuffer_Unlock(buffer);
353 IMFMediaBuffer_Release(buffer);
356 return hr;
359 static HRESULT stream_schedule_sample(struct sample_grabber *grabber, struct scheduled_item *item)
361 LONGLONG sampletime;
362 HRESULT hr;
364 if (grabber->is_shut_down)
365 return MF_E_STREAMSINK_REMOVED;
367 if (FAILED(hr = IMFSample_GetSampleTime(item->u.sample, &sampletime)))
368 return hr;
370 if (grabber->cancel_key)
372 IUnknown_Release(grabber->cancel_key);
373 grabber->cancel_key = NULL;
376 if (FAILED(hr = IMFTimer_SetTimer(grabber->timer, 0, sampletime - grabber->sample_time_offset,
377 &grabber->timer_callback, NULL, &grabber->cancel_key)))
379 grabber->cancel_key = NULL;
382 return hr;
385 static HRESULT stream_queue_sample(struct sample_grabber *grabber, IMFSample *sample)
387 struct scheduled_item *item;
388 LONGLONG sampletime;
389 HRESULT hr;
391 if (FAILED(hr = IMFSample_GetSampleTime(sample, &sampletime)))
392 return hr;
394 if (!(item = calloc(1, sizeof(*item))))
395 return E_OUTOFMEMORY;
397 item->type = ITEM_TYPE_SAMPLE;
398 item->u.sample = sample;
399 IMFSample_AddRef(item->u.sample);
400 list_init(&item->entry);
401 if (list_empty(&grabber->items))
402 hr = stream_schedule_sample(grabber, item);
404 if (SUCCEEDED(hr))
405 list_add_tail(&grabber->items, &item->entry);
406 else
407 stream_release_pending_item(item);
409 return hr;
412 static void sample_grabber_stream_request_sample(struct sample_grabber *grabber)
414 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL);
417 static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
419 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
420 BOOL sample_delivered;
421 LONGLONG sampletime;
422 HRESULT hr = S_OK;
424 TRACE("%p, %p.\n", iface, sample);
426 if (!sample)
427 return S_OK;
429 EnterCriticalSection(&grabber->cs);
431 if (grabber->is_shut_down)
432 hr = MF_E_STREAMSINK_REMOVED;
433 else if (grabber->state == SINK_STATE_RUNNING || (grabber->state == SINK_STATE_PAUSED && grabber->ignore_clock))
435 hr = IMFSample_GetSampleTime(sample, &sampletime);
437 if (SUCCEEDED(hr))
439 if (grabber->ignore_clock)
441 /* OnProcessSample() could return error code, which has to be propagated but isn't a blocker.
442 Use additional flag indicating that user callback was called at all. */
443 hr = sample_grabber_report_sample(grabber, sample, &sample_delivered);
444 if (sample_delivered)
445 sample_grabber_stream_request_sample(grabber);
447 else
448 hr = stream_queue_sample(grabber, sample);
451 else if (grabber->state == SINK_STATE_PAUSED)
453 if (grabber->sample_count < MAX_SAMPLE_QUEUE_LENGTH)
455 IMFSample_AddRef(sample);
456 grabber->samples[grabber->sample_count++] = sample;
460 LeaveCriticalSection(&grabber->cs);
462 return hr;
465 static void sample_grabber_stream_report_marker(struct sample_grabber *grabber, const PROPVARIANT *context,
466 HRESULT hr)
468 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkMarker, &GUID_NULL, hr, context);
471 static HRESULT stream_place_marker(struct sample_grabber *grabber, MFSTREAMSINK_MARKER_TYPE marker_type,
472 const PROPVARIANT *context_value)
474 struct scheduled_item *item;
475 HRESULT hr = S_OK;
477 if (list_empty(&grabber->items))
479 sample_grabber_stream_report_marker(grabber, context_value, S_OK);
480 return S_OK;
483 if (!(item = calloc(1, sizeof(*item))))
484 return E_OUTOFMEMORY;
486 item->type = ITEM_TYPE_MARKER;
487 item->u.marker.type = marker_type;
488 list_init(&item->entry);
489 PropVariantInit(&item->u.marker.context);
490 if (context_value)
491 hr = PropVariantCopy(&item->u.marker.context, context_value);
492 if (SUCCEEDED(hr))
493 list_add_tail(&grabber->items, &item->entry);
494 else
495 stream_release_pending_item(item);
497 return hr;
500 static HRESULT WINAPI sample_grabber_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
501 const PROPVARIANT *marker_value, const PROPVARIANT *context_value)
503 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
504 HRESULT hr = S_OK;
506 TRACE("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value);
508 EnterCriticalSection(&grabber->cs);
510 if (grabber->is_shut_down)
511 hr = MF_E_STREAMSINK_REMOVED;
512 else if (grabber->state == SINK_STATE_RUNNING)
513 hr = stream_place_marker(grabber, marker_type, context_value);
515 LeaveCriticalSection(&grabber->cs);
517 return hr;
520 static HRESULT WINAPI sample_grabber_stream_Flush(IMFStreamSink *iface)
522 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
523 struct scheduled_item *item, *next_item;
524 HRESULT hr = S_OK;
526 TRACE("%p.\n", iface);
528 EnterCriticalSection(&grabber->cs);
530 if (grabber->is_shut_down)
531 hr = MF_E_STREAMSINK_REMOVED;
532 else
534 LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &grabber->items, struct scheduled_item, entry)
536 /* Samples are discarded, markers are processed immediately. */
537 if (item->type == ITEM_TYPE_MARKER)
538 sample_grabber_stream_report_marker(grabber, &item->u.marker.context, E_ABORT);
540 stream_release_pending_item(item);
544 LeaveCriticalSection(&grabber->cs);
546 return hr;
549 static const IMFStreamSinkVtbl sample_grabber_stream_vtbl =
551 sample_grabber_stream_QueryInterface,
552 sample_grabber_stream_AddRef,
553 sample_grabber_stream_Release,
554 sample_grabber_stream_GetEvent,
555 sample_grabber_stream_BeginGetEvent,
556 sample_grabber_stream_EndGetEvent,
557 sample_grabber_stream_QueueEvent,
558 sample_grabber_stream_GetMediaSink,
559 sample_grabber_stream_GetIdentifier,
560 sample_grabber_stream_GetMediaTypeHandler,
561 sample_grabber_stream_ProcessSample,
562 sample_grabber_stream_PlaceMarker,
563 sample_grabber_stream_Flush,
566 static HRESULT WINAPI sample_grabber_stream_type_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid,
567 void **obj)
569 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
570 return IMFStreamSink_QueryInterface(&grabber->IMFStreamSink_iface, riid, obj);
573 static ULONG WINAPI sample_grabber_stream_type_handler_AddRef(IMFMediaTypeHandler *iface)
575 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
576 return IMFStreamSink_AddRef(&grabber->IMFStreamSink_iface);
579 static ULONG WINAPI sample_grabber_stream_type_handler_Release(IMFMediaTypeHandler *iface)
581 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
582 return IMFStreamSink_Release(&grabber->IMFStreamSink_iface);
585 static HRESULT sample_grabber_stream_is_media_type_supported(struct sample_grabber *grabber, IMFMediaType *in_type)
587 const DWORD supported_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES |
588 MF_MEDIATYPE_EQUAL_FORMAT_DATA;
589 DWORD flags;
591 if (grabber->is_shut_down)
592 return MF_E_STREAMSINK_REMOVED;
594 if (!in_type)
595 return E_POINTER;
597 if (IMFMediaType_IsEqual(grabber->media_type, in_type, &flags) == S_OK)
598 return S_OK;
600 return (flags & supported_flags) == supported_flags ? S_OK : MF_E_INVALIDMEDIATYPE;
603 static HRESULT WINAPI sample_grabber_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface,
604 IMFMediaType *in_type, IMFMediaType **out_type)
606 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
608 TRACE("%p, %p, %p.\n", iface, in_type, out_type);
610 return sample_grabber_stream_is_media_type_supported(grabber, in_type);
613 static HRESULT WINAPI sample_grabber_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count)
615 TRACE("%p, %p.\n", iface, count);
617 if (!count)
618 return E_POINTER;
620 *count = 0;
622 return S_OK;
625 static HRESULT WINAPI sample_grabber_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index,
626 IMFMediaType **media_type)
628 TRACE("%p, %lu, %p.\n", iface, index, media_type);
630 if (!media_type)
631 return E_POINTER;
633 return MF_E_NO_MORE_TYPES;
636 static HRESULT WINAPI sample_grabber_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface,
637 IMFMediaType *media_type)
639 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
640 HRESULT hr;
642 TRACE("%p, %p.\n", iface, media_type);
644 if (FAILED(hr = sample_grabber_stream_is_media_type_supported(grabber, media_type)))
645 return hr;
647 IMFMediaType_Release(grabber->current_media_type);
648 grabber->current_media_type = media_type;
649 IMFMediaType_AddRef(grabber->current_media_type);
651 return S_OK;
654 static HRESULT WINAPI sample_grabber_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface,
655 IMFMediaType **media_type)
657 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
659 TRACE("%p, %p.\n", iface, media_type);
661 if (!media_type)
662 return E_POINTER;
664 if (grabber->is_shut_down)
665 return MF_E_STREAMSINK_REMOVED;
667 *media_type = grabber->current_media_type;
668 IMFMediaType_AddRef(*media_type);
670 return S_OK;
673 static HRESULT WINAPI sample_grabber_stream_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type)
675 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
677 TRACE("%p, %p.\n", iface, type);
679 if (!type)
680 return E_POINTER;
682 if (grabber->is_shut_down)
683 return MF_E_STREAMSINK_REMOVED;
685 return IMFMediaType_GetMajorType(grabber->current_media_type, type);
688 static const IMFMediaTypeHandlerVtbl sample_grabber_stream_type_handler_vtbl =
690 sample_grabber_stream_type_handler_QueryInterface,
691 sample_grabber_stream_type_handler_AddRef,
692 sample_grabber_stream_type_handler_Release,
693 sample_grabber_stream_type_handler_IsMediaTypeSupported,
694 sample_grabber_stream_type_handler_GetMediaTypeCount,
695 sample_grabber_stream_type_handler_GetMediaTypeByIndex,
696 sample_grabber_stream_type_handler_SetCurrentMediaType,
697 sample_grabber_stream_type_handler_GetCurrentMediaType,
698 sample_grabber_stream_type_handler_GetMajorType,
701 static HRESULT WINAPI sample_grabber_stream_timer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid,
702 void **obj)
704 if (IsEqualIID(riid, &IID_IMFAsyncCallback) || IsEqualIID(riid, &IID_IUnknown))
706 *obj = iface;
707 IMFAsyncCallback_AddRef(iface);
708 return S_OK;
711 WARN("Unsupported %s.\n", debugstr_guid(riid));
712 *obj = NULL;
713 return E_NOINTERFACE;
716 static ULONG WINAPI sample_grabber_stream_timer_callback_AddRef(IMFAsyncCallback *iface)
718 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
719 return IMFStreamSink_AddRef(&grabber->IMFStreamSink_iface);
722 static ULONG WINAPI sample_grabber_stream_timer_callback_Release(IMFAsyncCallback *iface)
724 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
725 return IMFStreamSink_Release(&grabber->IMFStreamSink_iface);
728 static HRESULT WINAPI sample_grabber_stream_timer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
729 DWORD *queue)
731 return E_NOTIMPL;
734 static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
736 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
737 BOOL sample_reported = FALSE, sample_delivered = FALSE;
738 struct scheduled_item *item, *item2;
739 HRESULT hr;
741 EnterCriticalSection(&grabber->cs);
743 LIST_FOR_EACH_ENTRY_SAFE(item, item2, &grabber->items, struct scheduled_item, entry)
745 if (item->type == ITEM_TYPE_MARKER)
747 sample_grabber_stream_report_marker(grabber, &item->u.marker.context, S_OK);
748 stream_release_pending_item(item);
750 else if (item->type == ITEM_TYPE_SAMPLE)
752 if (!sample_reported)
754 if (FAILED(hr = sample_grabber_report_sample(grabber, item->u.sample, &sample_delivered)))
755 WARN("Failed to report a sample, hr %#lx.\n", hr);
756 stream_release_pending_item(item);
757 sample_reported = TRUE;
759 else
761 if (FAILED(hr = stream_schedule_sample(grabber, item)))
762 WARN("Failed to schedule a sample, hr %#lx.\n", hr);
763 break;
767 if (sample_delivered)
768 sample_grabber_stream_request_sample(grabber);
770 LeaveCriticalSection(&grabber->cs);
772 return S_OK;
775 static const IMFAsyncCallbackVtbl sample_grabber_stream_timer_callback_vtbl =
777 sample_grabber_stream_timer_callback_QueryInterface,
778 sample_grabber_stream_timer_callback_AddRef,
779 sample_grabber_stream_timer_callback_Release,
780 sample_grabber_stream_timer_callback_GetParameters,
781 sample_grabber_stream_timer_callback_Invoke,
784 static HRESULT WINAPI sample_grabber_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj)
786 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
788 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
790 if (IsEqualIID(riid, &IID_IMFMediaSink) ||
791 IsEqualIID(riid, &IID_IUnknown))
793 *obj = &grabber->IMFMediaSink_iface;
795 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
797 *obj = &grabber->IMFClockStateSink_iface;
799 else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator))
801 *obj = &grabber->IMFMediaEventGenerator_iface;
803 else if (IsEqualIID(riid, &IID_IMFGetService))
805 *obj = &grabber->IMFGetService_iface;
807 else if (IsEqualIID(riid, &IID_IMFRateSupport))
809 *obj = &grabber->IMFRateSupport_iface;
811 else
813 WARN("Unsupported %s.\n", debugstr_guid(riid));
814 *obj = NULL;
815 return E_NOINTERFACE;
818 IUnknown_AddRef((IUnknown *)*obj);
820 return S_OK;
823 static ULONG WINAPI sample_grabber_sink_AddRef(IMFMediaSink *iface)
825 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
826 ULONG refcount = InterlockedIncrement(&grabber->refcount);
828 TRACE("%p, refcount %lu.\n", iface, refcount);
830 return refcount;
833 static void sample_grabber_release_pending_items(struct sample_grabber *grabber)
835 struct scheduled_item *item, *next_item;
837 LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &grabber->items, struct scheduled_item, entry)
839 stream_release_pending_item(item);
843 static void release_samples(struct sample_grabber *grabber)
845 unsigned int i;
847 for (i = 0; i < MAX_SAMPLE_QUEUE_LENGTH; ++i)
849 if (grabber->samples[i])
851 IMFSample_Release(grabber->samples[i]);
852 grabber->samples[i] = NULL;
857 static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface)
859 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
860 ULONG refcount = InterlockedDecrement(&grabber->refcount);
862 TRACE("%p, refcount %lu.\n", iface, refcount);
864 if (!refcount)
866 if (grabber->callback)
867 IMFSampleGrabberSinkCallback_Release(grabber->callback);
868 if (grabber->callback2)
869 IMFSampleGrabberSinkCallback2_Release(grabber->callback2);
870 IMFMediaType_Release(grabber->current_media_type);
871 IMFMediaType_Release(grabber->media_type);
872 if (grabber->event_queue)
873 IMFMediaEventQueue_Release(grabber->event_queue);
874 if (grabber->clock)
875 IMFPresentationClock_Release(grabber->clock);
876 if (grabber->timer)
877 IMFTimer_Release(grabber->timer);
878 if (grabber->cancel_key)
879 IUnknown_Release(grabber->cancel_key);
880 if (grabber->stream_event_queue)
882 IMFMediaEventQueue_Shutdown(grabber->stream_event_queue);
883 IMFMediaEventQueue_Release(grabber->stream_event_queue);
885 if (grabber->sample_attributes)
886 IMFAttributes_Release(grabber->sample_attributes);
887 sample_grabber_release_pending_items(grabber);
888 release_samples(grabber);
889 DeleteCriticalSection(&grabber->cs);
890 free(grabber);
893 return refcount;
896 static HRESULT WINAPI sample_grabber_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *flags)
898 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
900 TRACE("%p, %p.\n", iface, flags);
902 if (grabber->is_shut_down)
903 return MF_E_SHUTDOWN;
905 *flags = MEDIASINK_FIXED_STREAMS;
906 if (grabber->ignore_clock)
907 *flags |= MEDIASINK_RATELESS;
909 return S_OK;
912 static HRESULT WINAPI sample_grabber_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id,
913 IMFMediaType *media_type, IMFStreamSink **stream_sink)
915 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
917 TRACE("%p, %#lx, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink);
919 return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
922 static HRESULT WINAPI sample_grabber_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id)
924 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
926 TRACE("%p, %#lx.\n", iface, stream_sink_id);
928 return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
931 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count)
933 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
935 TRACE("%p, %p.\n", iface, count);
937 if (grabber->is_shut_down)
938 return MF_E_SHUTDOWN;
940 *count = 1;
942 return S_OK;
945 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
946 IMFStreamSink **stream)
948 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
949 HRESULT hr = S_OK;
951 TRACE("%p, %lu, %p.\n", iface, index, stream);
953 EnterCriticalSection(&grabber->cs);
955 if (grabber->is_shut_down)
956 hr = MF_E_SHUTDOWN;
957 else if (index > 0)
958 hr = MF_E_INVALIDINDEX;
959 else
961 *stream = &grabber->IMFStreamSink_iface;
962 IMFStreamSink_AddRef(*stream);
965 LeaveCriticalSection(&grabber->cs);
967 return hr;
970 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id,
971 IMFStreamSink **stream)
973 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
974 HRESULT hr = S_OK;
976 TRACE("%p, %#lx, %p.\n", iface, stream_sink_id, stream);
978 EnterCriticalSection(&grabber->cs);
980 if (grabber->is_shut_down)
981 hr = MF_E_SHUTDOWN;
982 else if (stream_sink_id > 0)
983 hr = MF_E_INVALIDSTREAMNUMBER;
984 else
986 *stream = &grabber->IMFStreamSink_iface;
987 IMFStreamSink_AddRef(*stream);
990 LeaveCriticalSection(&grabber->cs);
992 return hr;
995 static void sample_grabber_cancel_timer(struct sample_grabber *grabber)
997 if (grabber->timer && grabber->cancel_key)
999 IMFTimer_CancelTimer(grabber->timer, grabber->cancel_key);
1000 IUnknown_Release(grabber->cancel_key);
1001 grabber->cancel_key = NULL;
1005 static void sample_grabber_set_presentation_clock(struct sample_grabber *grabber, IMFPresentationClock *clock)
1007 if (grabber->clock)
1009 sample_grabber_cancel_timer(grabber);
1010 IMFPresentationClock_RemoveClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
1011 IMFPresentationClock_Release(grabber->clock);
1012 if (grabber->timer)
1014 IMFTimer_Release(grabber->timer);
1015 grabber->timer = NULL;
1018 grabber->clock = clock;
1019 if (grabber->clock)
1021 IMFPresentationClock_AddRef(grabber->clock);
1022 IMFPresentationClock_AddClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
1023 if (FAILED(IMFPresentationClock_QueryInterface(grabber->clock, &IID_IMFTimer, (void **)&grabber->timer)))
1025 WARN("Failed to get IMFTimer interface.\n");
1026 grabber->timer = NULL;
1031 static HRESULT WINAPI sample_grabber_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
1033 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1034 HRESULT hr;
1036 TRACE("%p, %p.\n", iface, clock);
1038 EnterCriticalSection(&grabber->cs);
1040 if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber),
1041 clock)))
1043 sample_grabber_set_presentation_clock(grabber, clock);
1046 LeaveCriticalSection(&grabber->cs);
1048 return hr;
1051 static HRESULT WINAPI sample_grabber_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock)
1053 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1054 HRESULT hr = S_OK;
1056 TRACE("%p, %p.\n", iface, clock);
1058 if (!clock)
1059 return E_POINTER;
1061 EnterCriticalSection(&grabber->cs);
1063 if (grabber->clock)
1065 *clock = grabber->clock;
1066 IMFPresentationClock_AddRef(*clock);
1068 else
1069 hr = MF_E_NO_CLOCK;
1071 LeaveCriticalSection(&grabber->cs);
1073 return hr;
1076 static HRESULT WINAPI sample_grabber_sink_Shutdown(IMFMediaSink *iface)
1078 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1079 HRESULT hr;
1081 TRACE("%p.\n", iface);
1083 EnterCriticalSection(&grabber->cs);
1085 if (grabber->is_shut_down)
1086 hr = MF_E_SHUTDOWN;
1087 else
1089 grabber->is_shut_down = TRUE;
1090 sample_grabber_release_pending_items(grabber);
1091 if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber))))
1093 sample_grabber_set_presentation_clock(grabber, NULL);
1094 IMFMediaEventQueue_Shutdown(grabber->stream_event_queue);
1095 IMFMediaEventQueue_Shutdown(grabber->event_queue);
1099 LeaveCriticalSection(&grabber->cs);
1101 return hr;
1104 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl =
1106 sample_grabber_sink_QueryInterface,
1107 sample_grabber_sink_AddRef,
1108 sample_grabber_sink_Release,
1109 sample_grabber_sink_GetCharacteristics,
1110 sample_grabber_sink_AddStreamSink,
1111 sample_grabber_sink_RemoveStreamSink,
1112 sample_grabber_sink_GetStreamSinkCount,
1113 sample_grabber_sink_GetStreamSinkByIndex,
1114 sample_grabber_sink_GetStreamSinkById,
1115 sample_grabber_sink_SetPresentationClock,
1116 sample_grabber_sink_GetPresentationClock,
1117 sample_grabber_sink_Shutdown,
1120 static HRESULT WINAPI sample_grabber_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
1122 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1123 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1126 static ULONG WINAPI sample_grabber_clock_sink_AddRef(IMFClockStateSink *iface)
1128 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1129 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1132 static ULONG WINAPI sample_grabber_clock_sink_Release(IMFClockStateSink *iface)
1134 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1135 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1138 static HRESULT sample_grabber_set_state(struct sample_grabber *grabber, enum sink_state state,
1139 MFTIME systime, LONGLONG offset)
1141 static const DWORD events[] =
1143 MEStreamSinkStopped, /* SINK_STATE_STOPPED */
1144 MEStreamSinkPaused, /* SINK_STATE_PAUSED */
1145 MEStreamSinkStarted, /* SINK_STATE_RUNNING */
1147 BOOL do_callback = FALSE;
1148 HRESULT hr = S_OK;
1149 unsigned int i;
1151 EnterCriticalSection(&grabber->cs);
1153 if (!grabber->is_shut_down)
1155 if (state == SINK_STATE_PAUSED && grabber->state == SINK_STATE_STOPPED)
1156 hr = MF_E_INVALID_STATE_TRANSITION;
1157 else
1159 if (state == SINK_STATE_STOPPED)
1161 sample_grabber_cancel_timer(grabber);
1162 release_samples(grabber);
1163 grabber->sample_count = MAX_SAMPLE_QUEUE_LENGTH;
1166 if (state == SINK_STATE_RUNNING && grabber->state != SINK_STATE_RUNNING)
1168 /* Every transition to running state sends a bunch requests to build up initial queue. */
1169 for (i = 0; i < grabber->sample_count; ++i)
1171 if (grabber->state == SINK_STATE_PAUSED && offset == PRESENTATION_CURRENT_POSITION)
1173 assert(grabber->samples[i]);
1174 stream_queue_sample(grabber, grabber->samples[i]);
1176 else
1178 sample_grabber_stream_request_sample(grabber);
1181 release_samples(grabber);
1182 grabber->sample_count = 0;
1185 do_callback = state != grabber->state || state != SINK_STATE_PAUSED;
1186 if (do_callback)
1188 if (grabber->rate == 0.0f && state == SINK_STATE_RUNNING)
1189 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkScrubSampleComplete,
1190 &GUID_NULL, S_OK, NULL);
1192 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, events[state], &GUID_NULL, S_OK, NULL);
1194 grabber->state = state;
1198 LeaveCriticalSection(&grabber->cs);
1200 if (do_callback)
1202 switch (state)
1204 case SINK_STATE_STOPPED:
1205 hr = IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber), systime);
1206 break;
1207 case SINK_STATE_PAUSED:
1208 hr = IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber), systime);
1209 break;
1210 case SINK_STATE_RUNNING:
1211 hr = IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber), systime, offset);
1212 break;
1216 return hr;
1219 static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
1221 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1223 TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
1225 return sample_grabber_set_state(grabber, SINK_STATE_RUNNING, systime, offset);
1228 static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
1230 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1232 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1234 return sample_grabber_set_state(grabber, SINK_STATE_STOPPED, systime, 0);
1237 static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
1239 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1241 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1243 return sample_grabber_set_state(grabber, SINK_STATE_PAUSED, systime, 0);
1246 static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
1248 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1250 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1252 return sample_grabber_set_state(grabber, SINK_STATE_RUNNING, systime, PRESENTATION_CURRENT_POSITION);
1255 static HRESULT WINAPI sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
1257 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1258 HRESULT hr = S_OK;
1260 TRACE("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
1262 EnterCriticalSection(&grabber->cs);
1264 if (grabber->is_shut_down)
1265 hr = MF_E_SHUTDOWN;
1266 else
1268 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkRateChanged, &GUID_NULL, S_OK, NULL);
1269 grabber->rate = rate;
1272 LeaveCriticalSection(&grabber->cs);
1274 if (SUCCEEDED(hr))
1275 hr = IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber), systime, rate);
1277 return hr;
1280 static HRESULT WINAPI sample_grabber_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj)
1282 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1283 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1286 static ULONG WINAPI sample_grabber_events_AddRef(IMFMediaEventGenerator *iface)
1288 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1289 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1292 static ULONG WINAPI sample_grabber_events_Release(IMFMediaEventGenerator *iface)
1294 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1295 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1298 static HRESULT WINAPI sample_grabber_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event)
1300 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1302 TRACE("%p, %#lx, %p.\n", iface, flags, event);
1304 return IMFMediaEventQueue_GetEvent(grabber->event_queue, flags, event);
1307 static HRESULT WINAPI sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback,
1308 IUnknown *state)
1310 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1312 TRACE("%p, %p, %p.\n", iface, callback, state);
1314 return IMFMediaEventQueue_BeginGetEvent(grabber->event_queue, callback, state);
1317 static HRESULT WINAPI sample_grabber_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result,
1318 IMFMediaEvent **event)
1320 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1322 TRACE("%p, %p, %p.\n", iface, result, event);
1324 return IMFMediaEventQueue_EndGetEvent(grabber->event_queue, result, event);
1327 static HRESULT WINAPI sample_grabber_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type,
1328 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
1330 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1332 TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1334 return IMFMediaEventQueue_QueueEventParamVar(grabber->event_queue, event_type, ext_type, hr, value);
1337 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl =
1339 sample_grabber_events_QueryInterface,
1340 sample_grabber_events_AddRef,
1341 sample_grabber_events_Release,
1342 sample_grabber_events_GetEvent,
1343 sample_grabber_events_BeginGetEvent,
1344 sample_grabber_events_EndGetEvent,
1345 sample_grabber_events_QueueEvent,
1348 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl =
1350 sample_grabber_clock_sink_QueryInterface,
1351 sample_grabber_clock_sink_AddRef,
1352 sample_grabber_clock_sink_Release,
1353 sample_grabber_clock_sink_OnClockStart,
1354 sample_grabber_clock_sink_OnClockStop,
1355 sample_grabber_clock_sink_OnClockPause,
1356 sample_grabber_clock_sink_OnClockRestart,
1357 sample_grabber_clock_sink_OnClockSetRate,
1360 static HRESULT WINAPI sample_grabber_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1362 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1363 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1366 static ULONG WINAPI sample_grabber_getservice_AddRef(IMFGetService *iface)
1368 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1369 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1372 static ULONG WINAPI sample_grabber_getservice_Release(IMFGetService *iface)
1374 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1375 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1378 static HRESULT WINAPI sample_grabber_getservice_GetService(IMFGetService *iface, REFGUID service,
1379 REFIID riid, void **obj)
1381 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1383 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1385 if (IsEqualIID(riid, &IID_IMFRateSupport))
1386 return IMFGetService_QueryInterface(iface, riid, obj);
1388 return E_NOINTERFACE;
1391 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service), debugstr_guid(riid));
1393 return MF_E_UNSUPPORTED_SERVICE;
1396 static const IMFGetServiceVtbl sample_grabber_getservice_vtbl =
1398 sample_grabber_getservice_QueryInterface,
1399 sample_grabber_getservice_AddRef,
1400 sample_grabber_getservice_Release,
1401 sample_grabber_getservice_GetService,
1404 static HRESULT WINAPI sample_grabber_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1406 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1407 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1410 static ULONG WINAPI sample_grabber_rate_support_AddRef(IMFRateSupport *iface)
1412 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1413 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1416 static ULONG WINAPI sample_grabber_rate_support_Release(IMFRateSupport *iface)
1418 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1419 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1422 static HRESULT WINAPI sample_grabber_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1423 BOOL thin, float *rate)
1425 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1427 *rate = 0.0f;
1429 return S_OK;
1432 static HRESULT WINAPI sample_grabber_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1433 BOOL thin, float *rate)
1435 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1437 *rate = direction == MFRATE_REVERSE ? -FLT_MAX : FLT_MAX;
1439 return S_OK;
1442 static HRESULT WINAPI sample_grabber_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1443 float *ret_rate)
1445 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, ret_rate);
1447 if (ret_rate)
1448 *ret_rate = rate;
1450 return S_OK;
1453 static const IMFRateSupportVtbl sample_grabber_rate_support_vtbl =
1455 sample_grabber_rate_support_QueryInterface,
1456 sample_grabber_rate_support_AddRef,
1457 sample_grabber_rate_support_Release,
1458 sample_grabber_rate_support_GetSlowestRate,
1459 sample_grabber_rate_support_GetFastestRate,
1460 sample_grabber_rate_support_IsRateSupported,
1463 static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
1465 struct sample_grabber_activate_context *context = user_context;
1466 struct sample_grabber *object;
1467 HRESULT hr;
1468 GUID guid;
1470 TRACE("%p, %p, %p.\n", attributes, user_context, obj);
1472 if (context->shut_down)
1473 return MF_E_SHUTDOWN;
1475 /* At least major type is required. */
1476 if (FAILED(IMFMediaType_GetMajorType(context->media_type, &guid)))
1477 return MF_E_INVALIDMEDIATYPE;
1479 if (!(object = calloc(1, sizeof(*object))))
1480 return E_OUTOFMEMORY;
1482 object->IMFMediaSink_iface.lpVtbl = &sample_grabber_sink_vtbl;
1483 object->IMFClockStateSink_iface.lpVtbl = &sample_grabber_clock_sink_vtbl;
1484 object->IMFMediaEventGenerator_iface.lpVtbl = &sample_grabber_sink_events_vtbl;
1485 object->IMFGetService_iface.lpVtbl = &sample_grabber_getservice_vtbl;
1486 object->IMFRateSupport_iface.lpVtbl = &sample_grabber_rate_support_vtbl;
1487 object->IMFStreamSink_iface.lpVtbl = &sample_grabber_stream_vtbl;
1488 object->IMFMediaTypeHandler_iface.lpVtbl = &sample_grabber_stream_type_handler_vtbl;
1489 object->timer_callback.lpVtbl = &sample_grabber_stream_timer_callback_vtbl;
1490 object->sample_count = MAX_SAMPLE_QUEUE_LENGTH;
1491 object->refcount = 1;
1492 object->rate = 1.0f;
1493 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context->callback, &IID_IMFSampleGrabberSinkCallback2,
1494 (void **)&object->callback2)))
1496 object->callback = context->callback;
1497 IMFSampleGrabberSinkCallback_AddRef(object->callback);
1499 object->media_type = context->media_type;
1500 IMFMediaType_AddRef(object->media_type);
1501 object->current_media_type = context->media_type;
1502 IMFMediaType_AddRef(object->current_media_type);
1503 IMFAttributes_GetUINT32(attributes, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, &object->ignore_clock);
1504 IMFAttributes_GetUINT64(attributes, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET, &object->sample_time_offset);
1505 list_init(&object->items);
1506 InitializeCriticalSection(&object->cs);
1508 if (FAILED(hr = MFCreateEventQueue(&object->stream_event_queue)))
1509 goto failed;
1511 if (FAILED(hr = MFCreateAttributes(&object->sample_attributes, 0)))
1512 goto failed;
1514 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1515 goto failed;
1517 *obj = (IUnknown *)&object->IMFMediaSink_iface;
1519 TRACE("Created %p.\n", *obj);
1521 return S_OK;
1523 failed:
1525 IMFMediaSink_Release(&object->IMFMediaSink_iface);
1527 return hr;
1530 static void sample_grabber_shutdown_object(void *user_context, IUnknown *obj)
1532 struct sample_grabber_activate_context *context = user_context;
1533 context->shut_down = TRUE;
1536 static const struct activate_funcs sample_grabber_activate_funcs =
1538 sample_grabber_create_object,
1539 sample_grabber_shutdown_object,
1540 sample_grabber_free_private,
1543 /***********************************************************************
1544 * MFCreateSampleGrabberSinkActivate (mf.@)
1546 HRESULT WINAPI MFCreateSampleGrabberSinkActivate(IMFMediaType *media_type, IMFSampleGrabberSinkCallback *callback,
1547 IMFActivate **activate)
1549 struct sample_grabber_activate_context *context;
1550 HRESULT hr;
1552 TRACE("%p, %p, %p.\n", media_type, callback, activate);
1554 if (!media_type || !callback || !activate)
1555 return E_POINTER;
1557 if (!(context = calloc(1, sizeof(*context))))
1558 return E_OUTOFMEMORY;
1560 context->media_type = media_type;
1561 IMFMediaType_AddRef(context->media_type);
1562 context->callback = callback;
1563 IMFSampleGrabberSinkCallback_AddRef(context->callback);
1565 if (FAILED(hr = create_activation_object(context, &sample_grabber_activate_funcs, activate)))
1566 sample_grabber_free_private(context);
1568 return hr;