ntdll: Connect syscall frames across user callbacks on x86-64.
[wine.git] / dlls / mf / samplegrabber.c
blobde599139736a7291a63329e0c3e40189b0ec4b0b
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);
658 HRESULT hr = S_OK;
660 TRACE("%p, %p.\n", iface, media_type);
662 if (!media_type)
663 return E_POINTER;
665 EnterCriticalSection(&grabber->cs);
667 if (grabber->is_shut_down)
669 hr = MF_E_STREAMSINK_REMOVED;
671 else
673 *media_type = grabber->current_media_type;
674 IMFMediaType_AddRef(*media_type);
677 LeaveCriticalSection(&grabber->cs);
679 return hr;
682 static HRESULT WINAPI sample_grabber_stream_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type)
684 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
685 HRESULT hr;
687 TRACE("%p, %p.\n", iface, type);
689 if (!type)
690 return E_POINTER;
692 EnterCriticalSection(&grabber->cs);
694 if (grabber->is_shut_down)
695 hr = MF_E_STREAMSINK_REMOVED;
696 else
697 hr = IMFMediaType_GetMajorType(grabber->current_media_type, type);
699 LeaveCriticalSection(&grabber->cs);
701 return hr;
704 static const IMFMediaTypeHandlerVtbl sample_grabber_stream_type_handler_vtbl =
706 sample_grabber_stream_type_handler_QueryInterface,
707 sample_grabber_stream_type_handler_AddRef,
708 sample_grabber_stream_type_handler_Release,
709 sample_grabber_stream_type_handler_IsMediaTypeSupported,
710 sample_grabber_stream_type_handler_GetMediaTypeCount,
711 sample_grabber_stream_type_handler_GetMediaTypeByIndex,
712 sample_grabber_stream_type_handler_SetCurrentMediaType,
713 sample_grabber_stream_type_handler_GetCurrentMediaType,
714 sample_grabber_stream_type_handler_GetMajorType,
717 static HRESULT WINAPI sample_grabber_stream_timer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid,
718 void **obj)
720 if (IsEqualIID(riid, &IID_IMFAsyncCallback) || IsEqualIID(riid, &IID_IUnknown))
722 *obj = iface;
723 IMFAsyncCallback_AddRef(iface);
724 return S_OK;
727 WARN("Unsupported %s.\n", debugstr_guid(riid));
728 *obj = NULL;
729 return E_NOINTERFACE;
732 static ULONG WINAPI sample_grabber_stream_timer_callback_AddRef(IMFAsyncCallback *iface)
734 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
735 return IMFStreamSink_AddRef(&grabber->IMFStreamSink_iface);
738 static ULONG WINAPI sample_grabber_stream_timer_callback_Release(IMFAsyncCallback *iface)
740 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
741 return IMFStreamSink_Release(&grabber->IMFStreamSink_iface);
744 static HRESULT WINAPI sample_grabber_stream_timer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
745 DWORD *queue)
747 return E_NOTIMPL;
750 static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
752 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
753 BOOL sample_reported = FALSE, sample_delivered = FALSE;
754 struct scheduled_item *item, *item2;
755 HRESULT hr;
757 EnterCriticalSection(&grabber->cs);
759 LIST_FOR_EACH_ENTRY_SAFE(item, item2, &grabber->items, struct scheduled_item, entry)
761 if (item->type == ITEM_TYPE_MARKER)
763 sample_grabber_stream_report_marker(grabber, &item->u.marker.context, S_OK);
764 stream_release_pending_item(item);
766 else if (item->type == ITEM_TYPE_SAMPLE)
768 if (!sample_reported)
770 if (FAILED(hr = sample_grabber_report_sample(grabber, item->u.sample, &sample_delivered)))
771 WARN("Failed to report a sample, hr %#lx.\n", hr);
772 stream_release_pending_item(item);
773 sample_reported = TRUE;
775 else
777 if (FAILED(hr = stream_schedule_sample(grabber, item)))
778 WARN("Failed to schedule a sample, hr %#lx.\n", hr);
779 break;
783 if (sample_delivered)
784 sample_grabber_stream_request_sample(grabber);
786 LeaveCriticalSection(&grabber->cs);
788 return S_OK;
791 static const IMFAsyncCallbackVtbl sample_grabber_stream_timer_callback_vtbl =
793 sample_grabber_stream_timer_callback_QueryInterface,
794 sample_grabber_stream_timer_callback_AddRef,
795 sample_grabber_stream_timer_callback_Release,
796 sample_grabber_stream_timer_callback_GetParameters,
797 sample_grabber_stream_timer_callback_Invoke,
800 static HRESULT WINAPI sample_grabber_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj)
802 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
804 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
806 if (IsEqualIID(riid, &IID_IMFMediaSink) ||
807 IsEqualIID(riid, &IID_IUnknown))
809 *obj = &grabber->IMFMediaSink_iface;
811 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
813 *obj = &grabber->IMFClockStateSink_iface;
815 else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator))
817 *obj = &grabber->IMFMediaEventGenerator_iface;
819 else if (IsEqualIID(riid, &IID_IMFGetService))
821 *obj = &grabber->IMFGetService_iface;
823 else if (IsEqualIID(riid, &IID_IMFRateSupport))
825 *obj = &grabber->IMFRateSupport_iface;
827 else
829 WARN("Unsupported %s.\n", debugstr_guid(riid));
830 *obj = NULL;
831 return E_NOINTERFACE;
834 IUnknown_AddRef((IUnknown *)*obj);
836 return S_OK;
839 static ULONG WINAPI sample_grabber_sink_AddRef(IMFMediaSink *iface)
841 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
842 ULONG refcount = InterlockedIncrement(&grabber->refcount);
844 TRACE("%p, refcount %lu.\n", iface, refcount);
846 return refcount;
849 static void sample_grabber_release_pending_items(struct sample_grabber *grabber)
851 struct scheduled_item *item, *next_item;
853 LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &grabber->items, struct scheduled_item, entry)
855 stream_release_pending_item(item);
859 static void release_samples(struct sample_grabber *grabber)
861 unsigned int i;
863 for (i = 0; i < MAX_SAMPLE_QUEUE_LENGTH; ++i)
865 if (grabber->samples[i])
867 IMFSample_Release(grabber->samples[i]);
868 grabber->samples[i] = NULL;
873 static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface)
875 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
876 ULONG refcount = InterlockedDecrement(&grabber->refcount);
878 TRACE("%p, refcount %lu.\n", iface, refcount);
880 if (!refcount)
882 if (grabber->callback)
883 IMFSampleGrabberSinkCallback_Release(grabber->callback);
884 if (grabber->callback2)
885 IMFSampleGrabberSinkCallback2_Release(grabber->callback2);
886 if (grabber->current_media_type)
887 IMFMediaType_Release(grabber->current_media_type);
888 IMFMediaType_Release(grabber->media_type);
889 if (grabber->event_queue)
890 IMFMediaEventQueue_Release(grabber->event_queue);
891 if (grabber->clock)
892 IMFPresentationClock_Release(grabber->clock);
893 if (grabber->timer)
894 IMFTimer_Release(grabber->timer);
895 if (grabber->cancel_key)
896 IUnknown_Release(grabber->cancel_key);
897 if (grabber->stream_event_queue)
899 IMFMediaEventQueue_Shutdown(grabber->stream_event_queue);
900 IMFMediaEventQueue_Release(grabber->stream_event_queue);
902 if (grabber->sample_attributes)
903 IMFAttributes_Release(grabber->sample_attributes);
904 sample_grabber_release_pending_items(grabber);
905 release_samples(grabber);
906 DeleteCriticalSection(&grabber->cs);
907 free(grabber);
910 return refcount;
913 static HRESULT WINAPI sample_grabber_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *flags)
915 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
917 TRACE("%p, %p.\n", iface, flags);
919 if (grabber->is_shut_down)
920 return MF_E_SHUTDOWN;
922 *flags = MEDIASINK_FIXED_STREAMS;
923 if (grabber->ignore_clock)
924 *flags |= MEDIASINK_RATELESS;
926 return S_OK;
929 static HRESULT WINAPI sample_grabber_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id,
930 IMFMediaType *media_type, IMFStreamSink **stream_sink)
932 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
934 TRACE("%p, %#lx, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink);
936 return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
939 static HRESULT WINAPI sample_grabber_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id)
941 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
943 TRACE("%p, %#lx.\n", iface, stream_sink_id);
945 return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
948 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count)
950 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
952 TRACE("%p, %p.\n", iface, count);
954 if (grabber->is_shut_down)
955 return MF_E_SHUTDOWN;
957 *count = 1;
959 return S_OK;
962 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
963 IMFStreamSink **stream)
965 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
966 HRESULT hr = S_OK;
968 TRACE("%p, %lu, %p.\n", iface, index, stream);
970 EnterCriticalSection(&grabber->cs);
972 if (grabber->is_shut_down)
973 hr = MF_E_SHUTDOWN;
974 else if (index > 0)
975 hr = MF_E_INVALIDINDEX;
976 else
978 *stream = &grabber->IMFStreamSink_iface;
979 IMFStreamSink_AddRef(*stream);
982 LeaveCriticalSection(&grabber->cs);
984 return hr;
987 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id,
988 IMFStreamSink **stream)
990 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
991 HRESULT hr = S_OK;
993 TRACE("%p, %#lx, %p.\n", iface, stream_sink_id, stream);
995 EnterCriticalSection(&grabber->cs);
997 if (grabber->is_shut_down)
998 hr = MF_E_SHUTDOWN;
999 else if (stream_sink_id > 0)
1000 hr = MF_E_INVALIDSTREAMNUMBER;
1001 else
1003 *stream = &grabber->IMFStreamSink_iface;
1004 IMFStreamSink_AddRef(*stream);
1007 LeaveCriticalSection(&grabber->cs);
1009 return hr;
1012 static void sample_grabber_cancel_timer(struct sample_grabber *grabber)
1014 if (grabber->timer && grabber->cancel_key)
1016 IMFTimer_CancelTimer(grabber->timer, grabber->cancel_key);
1017 IUnknown_Release(grabber->cancel_key);
1018 grabber->cancel_key = NULL;
1022 static HRESULT sample_grabber_set_presentation_clock(struct sample_grabber *grabber, IMFPresentationClock *clock)
1024 HRESULT hr;
1026 if (FAILED(hr = IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber), clock)))
1027 return hr;
1029 if (grabber->clock)
1031 sample_grabber_cancel_timer(grabber);
1032 IMFPresentationClock_RemoveClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
1033 IMFPresentationClock_Release(grabber->clock);
1034 if (grabber->timer)
1036 IMFTimer_Release(grabber->timer);
1037 grabber->timer = NULL;
1040 grabber->clock = clock;
1041 if (grabber->clock)
1043 IMFPresentationClock_AddRef(grabber->clock);
1044 IMFPresentationClock_AddClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
1045 if (FAILED(IMFPresentationClock_QueryInterface(grabber->clock, &IID_IMFTimer, (void **)&grabber->timer)))
1047 WARN("Failed to get IMFTimer interface.\n");
1048 grabber->timer = NULL;
1052 return hr;
1055 static HRESULT WINAPI sample_grabber_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
1057 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1058 HRESULT hr;
1060 TRACE("%p, %p.\n", iface, clock);
1062 EnterCriticalSection(&grabber->cs);
1064 if (grabber->is_shut_down)
1066 hr = MF_E_SHUTDOWN;
1068 else
1070 hr = sample_grabber_set_presentation_clock(grabber, clock);
1073 LeaveCriticalSection(&grabber->cs);
1075 return hr;
1078 static HRESULT WINAPI sample_grabber_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock)
1080 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1081 HRESULT hr = S_OK;
1083 TRACE("%p, %p.\n", iface, clock);
1085 if (!clock)
1086 return E_POINTER;
1088 EnterCriticalSection(&grabber->cs);
1090 if (grabber->clock)
1092 *clock = grabber->clock;
1093 IMFPresentationClock_AddRef(*clock);
1095 else
1096 hr = MF_E_NO_CLOCK;
1098 LeaveCriticalSection(&grabber->cs);
1100 return hr;
1103 static HRESULT WINAPI sample_grabber_sink_Shutdown(IMFMediaSink *iface)
1105 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1106 HRESULT hr;
1108 TRACE("%p.\n", iface);
1110 EnterCriticalSection(&grabber->cs);
1112 if (grabber->is_shut_down)
1113 hr = MF_E_SHUTDOWN;
1114 else
1116 grabber->is_shut_down = TRUE;
1117 sample_grabber_release_pending_items(grabber);
1118 if (SUCCEEDED(hr = sample_grabber_set_presentation_clock(grabber, NULL)))
1119 hr = IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber));
1120 if (SUCCEEDED(hr))
1122 IMFMediaType_Release(grabber->current_media_type);
1123 grabber->current_media_type = NULL;
1124 IMFMediaEventQueue_Shutdown(grabber->stream_event_queue);
1125 IMFMediaEventQueue_Shutdown(grabber->event_queue);
1129 LeaveCriticalSection(&grabber->cs);
1131 return hr;
1134 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl =
1136 sample_grabber_sink_QueryInterface,
1137 sample_grabber_sink_AddRef,
1138 sample_grabber_sink_Release,
1139 sample_grabber_sink_GetCharacteristics,
1140 sample_grabber_sink_AddStreamSink,
1141 sample_grabber_sink_RemoveStreamSink,
1142 sample_grabber_sink_GetStreamSinkCount,
1143 sample_grabber_sink_GetStreamSinkByIndex,
1144 sample_grabber_sink_GetStreamSinkById,
1145 sample_grabber_sink_SetPresentationClock,
1146 sample_grabber_sink_GetPresentationClock,
1147 sample_grabber_sink_Shutdown,
1150 static HRESULT WINAPI sample_grabber_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
1152 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1153 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1156 static ULONG WINAPI sample_grabber_clock_sink_AddRef(IMFClockStateSink *iface)
1158 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1159 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1162 static ULONG WINAPI sample_grabber_clock_sink_Release(IMFClockStateSink *iface)
1164 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1165 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1168 static HRESULT sample_grabber_set_state(struct sample_grabber *grabber, enum sink_state state,
1169 MFTIME systime, LONGLONG offset)
1171 static const DWORD events[] =
1173 MEStreamSinkStopped, /* SINK_STATE_STOPPED */
1174 MEStreamSinkPaused, /* SINK_STATE_PAUSED */
1175 MEStreamSinkStarted, /* SINK_STATE_RUNNING */
1177 BOOL do_callback = FALSE;
1178 HRESULT hr = S_OK;
1179 unsigned int i;
1181 EnterCriticalSection(&grabber->cs);
1183 if (!grabber->is_shut_down)
1185 if (state == SINK_STATE_PAUSED && grabber->state == SINK_STATE_STOPPED)
1186 hr = MF_E_INVALID_STATE_TRANSITION;
1187 else
1189 if (state == SINK_STATE_STOPPED)
1191 sample_grabber_cancel_timer(grabber);
1192 release_samples(grabber);
1193 grabber->sample_count = MAX_SAMPLE_QUEUE_LENGTH;
1196 if (state == SINK_STATE_RUNNING && grabber->state != SINK_STATE_RUNNING)
1198 /* Every transition to running state sends a bunch requests to build up initial queue. */
1199 for (i = 0; i < grabber->sample_count; ++i)
1201 if (grabber->state == SINK_STATE_PAUSED && offset == PRESENTATION_CURRENT_POSITION)
1203 assert(grabber->samples[i]);
1204 stream_queue_sample(grabber, grabber->samples[i]);
1206 else
1208 sample_grabber_stream_request_sample(grabber);
1211 release_samples(grabber);
1212 grabber->sample_count = 0;
1215 do_callback = state != grabber->state || state != SINK_STATE_PAUSED;
1216 if (do_callback)
1218 if (grabber->rate == 0.0f && state == SINK_STATE_RUNNING)
1219 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkScrubSampleComplete,
1220 &GUID_NULL, S_OK, NULL);
1222 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, events[state], &GUID_NULL, S_OK, NULL);
1224 grabber->state = state;
1228 LeaveCriticalSection(&grabber->cs);
1230 if (do_callback)
1232 switch (state)
1234 case SINK_STATE_STOPPED:
1235 hr = IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber), systime);
1236 break;
1237 case SINK_STATE_PAUSED:
1238 hr = IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber), systime);
1239 break;
1240 case SINK_STATE_RUNNING:
1241 hr = IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber), systime, offset);
1242 break;
1246 return hr;
1249 static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
1251 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1253 TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
1255 return sample_grabber_set_state(grabber, SINK_STATE_RUNNING, systime, offset);
1258 static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
1260 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1262 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1264 return sample_grabber_set_state(grabber, SINK_STATE_STOPPED, systime, 0);
1267 static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
1269 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1271 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1273 return sample_grabber_set_state(grabber, SINK_STATE_PAUSED, systime, 0);
1276 static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
1278 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1280 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1282 return sample_grabber_set_state(grabber, SINK_STATE_RUNNING, systime, PRESENTATION_CURRENT_POSITION);
1285 static HRESULT WINAPI sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
1287 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1288 HRESULT hr = S_OK;
1290 TRACE("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
1292 EnterCriticalSection(&grabber->cs);
1294 if (grabber->is_shut_down)
1295 hr = MF_E_SHUTDOWN;
1296 else
1298 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkRateChanged, &GUID_NULL, S_OK, NULL);
1299 grabber->rate = rate;
1302 LeaveCriticalSection(&grabber->cs);
1304 if (SUCCEEDED(hr))
1305 hr = IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber), systime, rate);
1307 return hr;
1310 static HRESULT WINAPI sample_grabber_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj)
1312 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1313 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1316 static ULONG WINAPI sample_grabber_events_AddRef(IMFMediaEventGenerator *iface)
1318 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1319 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1322 static ULONG WINAPI sample_grabber_events_Release(IMFMediaEventGenerator *iface)
1324 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1325 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1328 static HRESULT WINAPI sample_grabber_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event)
1330 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1332 TRACE("%p, %#lx, %p.\n", iface, flags, event);
1334 return IMFMediaEventQueue_GetEvent(grabber->event_queue, flags, event);
1337 static HRESULT WINAPI sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback,
1338 IUnknown *state)
1340 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1342 TRACE("%p, %p, %p.\n", iface, callback, state);
1344 return IMFMediaEventQueue_BeginGetEvent(grabber->event_queue, callback, state);
1347 static HRESULT WINAPI sample_grabber_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result,
1348 IMFMediaEvent **event)
1350 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1352 TRACE("%p, %p, %p.\n", iface, result, event);
1354 return IMFMediaEventQueue_EndGetEvent(grabber->event_queue, result, event);
1357 static HRESULT WINAPI sample_grabber_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type,
1358 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
1360 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1362 TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1364 return IMFMediaEventQueue_QueueEventParamVar(grabber->event_queue, event_type, ext_type, hr, value);
1367 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl =
1369 sample_grabber_events_QueryInterface,
1370 sample_grabber_events_AddRef,
1371 sample_grabber_events_Release,
1372 sample_grabber_events_GetEvent,
1373 sample_grabber_events_BeginGetEvent,
1374 sample_grabber_events_EndGetEvent,
1375 sample_grabber_events_QueueEvent,
1378 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl =
1380 sample_grabber_clock_sink_QueryInterface,
1381 sample_grabber_clock_sink_AddRef,
1382 sample_grabber_clock_sink_Release,
1383 sample_grabber_clock_sink_OnClockStart,
1384 sample_grabber_clock_sink_OnClockStop,
1385 sample_grabber_clock_sink_OnClockPause,
1386 sample_grabber_clock_sink_OnClockRestart,
1387 sample_grabber_clock_sink_OnClockSetRate,
1390 static HRESULT WINAPI sample_grabber_getservice_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1392 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1393 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1396 static ULONG WINAPI sample_grabber_getservice_AddRef(IMFGetService *iface)
1398 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1399 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1402 static ULONG WINAPI sample_grabber_getservice_Release(IMFGetService *iface)
1404 struct sample_grabber *grabber = impl_from_IMFGetService(iface);
1405 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1408 static HRESULT WINAPI sample_grabber_getservice_GetService(IMFGetService *iface, REFGUID service,
1409 REFIID riid, void **obj)
1411 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1413 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1415 if (IsEqualIID(riid, &IID_IMFRateSupport))
1416 return IMFGetService_QueryInterface(iface, riid, obj);
1418 return E_NOINTERFACE;
1421 FIXME("Unsupported service %s, riid %s.\n", debugstr_guid(service), debugstr_guid(riid));
1423 return MF_E_UNSUPPORTED_SERVICE;
1426 static const IMFGetServiceVtbl sample_grabber_getservice_vtbl =
1428 sample_grabber_getservice_QueryInterface,
1429 sample_grabber_getservice_AddRef,
1430 sample_grabber_getservice_Release,
1431 sample_grabber_getservice_GetService,
1434 static HRESULT WINAPI sample_grabber_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1436 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1437 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1440 static ULONG WINAPI sample_grabber_rate_support_AddRef(IMFRateSupport *iface)
1442 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1443 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1446 static ULONG WINAPI sample_grabber_rate_support_Release(IMFRateSupport *iface)
1448 struct sample_grabber *grabber = impl_from_IMFRateSupport(iface);
1449 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1452 static HRESULT WINAPI sample_grabber_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1453 BOOL thin, float *rate)
1455 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1457 *rate = 0.0f;
1459 return S_OK;
1462 static HRESULT WINAPI sample_grabber_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction,
1463 BOOL thin, float *rate)
1465 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1467 *rate = direction == MFRATE_REVERSE ? -FLT_MAX : FLT_MAX;
1469 return S_OK;
1472 static HRESULT WINAPI sample_grabber_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1473 float *ret_rate)
1475 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, ret_rate);
1477 if (ret_rate)
1478 *ret_rate = rate;
1480 return S_OK;
1483 static const IMFRateSupportVtbl sample_grabber_rate_support_vtbl =
1485 sample_grabber_rate_support_QueryInterface,
1486 sample_grabber_rate_support_AddRef,
1487 sample_grabber_rate_support_Release,
1488 sample_grabber_rate_support_GetSlowestRate,
1489 sample_grabber_rate_support_GetFastestRate,
1490 sample_grabber_rate_support_IsRateSupported,
1493 static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
1495 struct sample_grabber_activate_context *context = user_context;
1496 struct sample_grabber *object;
1497 HRESULT hr;
1498 GUID guid;
1500 TRACE("%p, %p, %p.\n", attributes, user_context, obj);
1502 if (context->shut_down)
1503 return MF_E_SHUTDOWN;
1505 /* At least major type is required. */
1506 if (FAILED(IMFMediaType_GetMajorType(context->media_type, &guid)))
1507 return MF_E_INVALIDMEDIATYPE;
1509 if (!(object = calloc(1, sizeof(*object))))
1510 return E_OUTOFMEMORY;
1512 object->IMFMediaSink_iface.lpVtbl = &sample_grabber_sink_vtbl;
1513 object->IMFClockStateSink_iface.lpVtbl = &sample_grabber_clock_sink_vtbl;
1514 object->IMFMediaEventGenerator_iface.lpVtbl = &sample_grabber_sink_events_vtbl;
1515 object->IMFGetService_iface.lpVtbl = &sample_grabber_getservice_vtbl;
1516 object->IMFRateSupport_iface.lpVtbl = &sample_grabber_rate_support_vtbl;
1517 object->IMFStreamSink_iface.lpVtbl = &sample_grabber_stream_vtbl;
1518 object->IMFMediaTypeHandler_iface.lpVtbl = &sample_grabber_stream_type_handler_vtbl;
1519 object->timer_callback.lpVtbl = &sample_grabber_stream_timer_callback_vtbl;
1520 object->sample_count = MAX_SAMPLE_QUEUE_LENGTH;
1521 object->refcount = 1;
1522 object->rate = 1.0f;
1523 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context->callback, &IID_IMFSampleGrabberSinkCallback2,
1524 (void **)&object->callback2)))
1526 object->callback = context->callback;
1527 IMFSampleGrabberSinkCallback_AddRef(object->callback);
1529 object->media_type = context->media_type;
1530 IMFMediaType_AddRef(object->media_type);
1531 object->current_media_type = context->media_type;
1532 IMFMediaType_AddRef(object->current_media_type);
1533 IMFAttributes_GetUINT32(attributes, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, &object->ignore_clock);
1534 IMFAttributes_GetUINT64(attributes, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET, &object->sample_time_offset);
1535 list_init(&object->items);
1536 InitializeCriticalSection(&object->cs);
1538 if (FAILED(hr = MFCreateEventQueue(&object->stream_event_queue)))
1539 goto failed;
1541 if (FAILED(hr = MFCreateAttributes(&object->sample_attributes, 0)))
1542 goto failed;
1544 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1545 goto failed;
1547 *obj = (IUnknown *)&object->IMFMediaSink_iface;
1549 TRACE("Created %p.\n", *obj);
1551 return S_OK;
1553 failed:
1555 IMFMediaSink_Release(&object->IMFMediaSink_iface);
1557 return hr;
1560 static void sample_grabber_shutdown_object(void *user_context, IUnknown *obj)
1562 struct sample_grabber_activate_context *context = user_context;
1563 context->shut_down = TRUE;
1566 static const struct activate_funcs sample_grabber_activate_funcs =
1568 sample_grabber_create_object,
1569 sample_grabber_shutdown_object,
1570 sample_grabber_free_private,
1573 /***********************************************************************
1574 * MFCreateSampleGrabberSinkActivate (mf.@)
1576 HRESULT WINAPI MFCreateSampleGrabberSinkActivate(IMFMediaType *media_type, IMFSampleGrabberSinkCallback *callback,
1577 IMFActivate **activate)
1579 struct sample_grabber_activate_context *context;
1580 HRESULT hr;
1582 TRACE("%p, %p, %p.\n", media_type, callback, activate);
1584 if (!media_type || !callback || !activate)
1585 return E_POINTER;
1587 if (!(context = calloc(1, sizeof(*context))))
1588 return E_OUTOFMEMORY;
1590 context->media_type = media_type;
1591 IMFMediaType_AddRef(context->media_type);
1592 context->callback = callback;
1593 IMFSampleGrabberSinkCallback_AddRef(context->callback);
1595 if (FAILED(hr = create_activation_object(context, &sample_grabber_activate_funcs, activate)))
1596 sample_grabber_free_private(context);
1598 return hr;