amstream: Implement AMAudioStream::NewSegment.
[wine/zf.git] / dlls / mf / samplegrabber.c
blob92330abc9fe192e6f30865dbfd50cb7da4a5f996
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 "mfapi.h"
22 #include "mfidl.h"
23 #include "mferror.h"
24 #include "mf_private.h"
26 #include "wine/debug.h"
27 #include "wine/heap.h"
28 #include "wine/list.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
32 enum sink_state
34 SINK_STATE_STOPPED = 0,
35 SINK_STATE_RUNNING,
38 struct sample_grabber;
40 enum scheduled_item_type
42 ITEM_TYPE_SAMPLE,
43 ITEM_TYPE_MARKER,
46 struct scheduled_item
48 struct list entry;
49 enum scheduled_item_type type;
50 union
52 IMFSample *sample;
53 struct
55 MFSTREAMSINK_MARKER_TYPE type;
56 PROPVARIANT context;
57 } marker;
58 } u;
61 struct sample_grabber
63 IMFMediaSink IMFMediaSink_iface;
64 IMFClockStateSink IMFClockStateSink_iface;
65 IMFMediaEventGenerator IMFMediaEventGenerator_iface;
66 IMFStreamSink IMFStreamSink_iface;
67 IMFMediaTypeHandler IMFMediaTypeHandler_iface;
68 IMFAsyncCallback timer_callback;
69 LONG refcount;
70 IMFSampleGrabberSinkCallback *callback;
71 IMFSampleGrabberSinkCallback2 *callback2;
72 IMFMediaType *media_type;
73 BOOL is_shut_down;
74 IMFMediaEventQueue *event_queue;
75 IMFMediaEventQueue *stream_event_queue;
76 IMFPresentationClock *clock;
77 IMFTimer *timer;
78 IMFAttributes *sample_attributes;
79 struct list items;
80 IUnknown *cancel_key;
81 UINT32 ignore_clock;
82 UINT64 sample_time_offset;
83 enum sink_state state;
84 CRITICAL_SECTION cs;
87 static IMFSampleGrabberSinkCallback *sample_grabber_get_callback(const struct sample_grabber *sink)
89 return sink->callback2 ? (IMFSampleGrabberSinkCallback *)sink->callback2 : sink->callback;
92 struct sample_grabber_activate_context
94 IMFMediaType *media_type;
95 IMFSampleGrabberSinkCallback *callback;
96 BOOL shut_down;
99 static void sample_grabber_free_private(void *user_context)
101 struct sample_grabber_activate_context *context = user_context;
102 IMFMediaType_Release(context->media_type);
103 IMFSampleGrabberSinkCallback_Release(context->callback);
104 heap_free(context);
107 static struct sample_grabber *impl_from_IMFMediaSink(IMFMediaSink *iface)
109 return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaSink_iface);
112 static struct sample_grabber *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
114 return CONTAINING_RECORD(iface, struct sample_grabber, IMFClockStateSink_iface);
117 static struct sample_grabber *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface)
119 return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaEventGenerator_iface);
122 static struct sample_grabber *impl_from_IMFStreamSink(IMFStreamSink *iface)
124 return CONTAINING_RECORD(iface, struct sample_grabber, IMFStreamSink_iface);
127 static struct sample_grabber *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface)
129 return CONTAINING_RECORD(iface, struct sample_grabber, IMFMediaTypeHandler_iface);
132 static struct sample_grabber *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
134 return CONTAINING_RECORD(iface, struct sample_grabber, timer_callback);
137 static HRESULT WINAPI sample_grabber_stream_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj)
139 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
141 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
143 if (IsEqualIID(riid, &IID_IMFStreamSink) ||
144 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
145 IsEqualIID(riid, &IID_IUnknown))
147 *obj = &grabber->IMFStreamSink_iface;
149 else if (IsEqualIID(riid, &IID_IMFMediaTypeHandler))
151 *obj = &grabber->IMFMediaTypeHandler_iface;
153 else
155 WARN("Unsupported %s.\n", debugstr_guid(riid));
156 *obj = NULL;
157 return E_NOINTERFACE;
160 IUnknown_AddRef((IUnknown *)*obj);
162 return S_OK;
165 static ULONG WINAPI sample_grabber_stream_AddRef(IMFStreamSink *iface)
167 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
168 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
171 static void stream_release_pending_item(struct scheduled_item *item)
173 list_remove(&item->entry);
174 switch (item->type)
176 case ITEM_TYPE_SAMPLE:
177 IMFSample_Release(item->u.sample);
178 break;
179 case ITEM_TYPE_MARKER:
180 PropVariantClear(&item->u.marker.context);
181 break;
183 heap_free(item);
186 static ULONG WINAPI sample_grabber_stream_Release(IMFStreamSink *iface)
188 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
189 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
192 static HRESULT WINAPI sample_grabber_stream_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event)
194 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
196 TRACE("%p, %#x, %p.\n", iface, flags, event);
198 if (grabber->is_shut_down)
199 return MF_E_STREAMSINK_REMOVED;
201 return IMFMediaEventQueue_GetEvent(grabber->stream_event_queue, flags, event);
204 static HRESULT WINAPI sample_grabber_stream_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback,
205 IUnknown *state)
207 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
209 TRACE("%p, %p, %p.\n", iface, callback, state);
211 if (grabber->is_shut_down)
212 return MF_E_STREAMSINK_REMOVED;
214 return IMFMediaEventQueue_BeginGetEvent(grabber->stream_event_queue, callback, state);
217 static HRESULT WINAPI sample_grabber_stream_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result,
218 IMFMediaEvent **event)
220 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
222 TRACE("%p, %p, %p.\n", iface, result, event);
224 if (grabber->is_shut_down)
225 return MF_E_STREAMSINK_REMOVED;
227 return IMFMediaEventQueue_EndGetEvent(grabber->stream_event_queue, result, event);
230 static HRESULT WINAPI sample_grabber_stream_QueueEvent(IMFStreamSink *iface, MediaEventType event_type,
231 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
233 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
235 TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
237 if (grabber->is_shut_down)
238 return MF_E_STREAMSINK_REMOVED;
240 return IMFMediaEventQueue_QueueEventParamVar(grabber->stream_event_queue, event_type, ext_type, hr, value);
243 static HRESULT WINAPI sample_grabber_stream_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **sink)
245 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
247 TRACE("%p, %p.\n", iface, sink);
249 if (grabber->is_shut_down)
250 return MF_E_STREAMSINK_REMOVED;
252 *sink = &grabber->IMFMediaSink_iface;
253 IMFMediaSink_AddRef(*sink);
255 return S_OK;
258 static HRESULT WINAPI sample_grabber_stream_GetIdentifier(IMFStreamSink *iface, DWORD *identifier)
260 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
262 TRACE("%p, %p.\n", iface, identifier);
264 if (grabber->is_shut_down)
265 return MF_E_STREAMSINK_REMOVED;
267 *identifier = 0;
269 return S_OK;
272 static HRESULT WINAPI sample_grabber_stream_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler)
274 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
276 TRACE("%p, %p.\n", iface, handler);
278 if (!handler)
279 return E_POINTER;
281 if (grabber->is_shut_down)
282 return MF_E_STREAMSINK_REMOVED;
284 *handler = &grabber->IMFMediaTypeHandler_iface;
285 IMFMediaTypeHandler_AddRef(*handler);
287 return S_OK;
290 static HRESULT sample_grabber_report_sample(struct sample_grabber *grabber, IMFSample *sample, BOOL *sample_delivered)
292 LONGLONG sample_time, sample_duration = 0;
293 IMFMediaBuffer *buffer;
294 DWORD flags, size;
295 GUID major_type;
296 BYTE *data;
297 HRESULT hr;
299 *sample_delivered = FALSE;
301 hr = IMFMediaType_GetMajorType(grabber->media_type, &major_type);
303 if (SUCCEEDED(hr))
304 hr = IMFSample_GetSampleTime(sample, &sample_time);
306 if (FAILED(IMFSample_GetSampleDuration(sample, &sample_duration)))
307 sample_duration = 0;
309 if (SUCCEEDED(hr))
310 hr = IMFSample_GetSampleFlags(sample, &flags);
312 if (SUCCEEDED(hr))
314 if (FAILED(IMFSample_ConvertToContiguousBuffer(sample, &buffer)))
315 return E_UNEXPECTED;
317 if (SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, &size)))
319 *sample_delivered = TRUE;
321 if (grabber->callback2)
323 hr = IMFSample_CopyAllItems(sample, grabber->sample_attributes);
324 if (SUCCEEDED(hr))
325 hr = IMFSampleGrabberSinkCallback2_OnProcessSampleEx(grabber->callback2, &major_type, flags,
326 sample_time, sample_duration, data, size, grabber->sample_attributes);
328 else
329 hr = IMFSampleGrabberSinkCallback_OnProcessSample(grabber->callback, &major_type, flags, sample_time,
330 sample_duration, data, size);
331 IMFMediaBuffer_Unlock(buffer);
334 IMFMediaBuffer_Release(buffer);
337 return hr;
340 static HRESULT stream_schedule_sample(struct sample_grabber *grabber, struct scheduled_item *item)
342 LONGLONG sampletime;
343 HRESULT hr;
345 if (grabber->is_shut_down)
346 return MF_E_STREAMSINK_REMOVED;
348 if (FAILED(hr = IMFSample_GetSampleTime(item->u.sample, &sampletime)))
349 return hr;
351 if (grabber->cancel_key)
353 IUnknown_Release(grabber->cancel_key);
354 grabber->cancel_key = NULL;
357 if (FAILED(hr = IMFTimer_SetTimer(grabber->timer, 0, sampletime - grabber->sample_time_offset,
358 &grabber->timer_callback, NULL, &grabber->cancel_key)))
360 grabber->cancel_key = NULL;
363 return hr;
366 static HRESULT stream_queue_sample(struct sample_grabber *grabber, IMFSample *sample)
368 struct scheduled_item *item;
369 LONGLONG sampletime;
370 HRESULT hr;
372 if (FAILED(hr = IMFSample_GetSampleTime(sample, &sampletime)))
373 return hr;
375 if (!(item = heap_alloc_zero(sizeof(*item))))
376 return E_OUTOFMEMORY;
378 item->type = ITEM_TYPE_SAMPLE;
379 item->u.sample = sample;
380 IMFSample_AddRef(item->u.sample);
381 list_init(&item->entry);
382 if (list_empty(&grabber->items))
383 hr = stream_schedule_sample(grabber, item);
385 if (SUCCEEDED(hr))
386 list_add_tail(&grabber->items, &item->entry);
387 else
388 stream_release_pending_item(item);
390 return hr;
393 static void sample_grabber_stream_request_sample(struct sample_grabber *grabber)
395 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkRequestSample, &GUID_NULL, S_OK, NULL);
398 static HRESULT WINAPI sample_grabber_stream_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
400 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
401 BOOL sample_delivered;
402 LONGLONG sampletime;
403 HRESULT hr = S_OK;
405 TRACE("%p, %p.\n", iface, sample);
407 if (!sample)
408 return S_OK;
410 EnterCriticalSection(&grabber->cs);
412 if (grabber->is_shut_down)
413 hr = MF_E_STREAMSINK_REMOVED;
414 else if (grabber->state == SINK_STATE_RUNNING)
416 hr = IMFSample_GetSampleTime(sample, &sampletime);
418 if (SUCCEEDED(hr))
420 if (grabber->ignore_clock)
422 /* OnProcessSample() could return error code, which has to be propagated but isn't a blocker.
423 Use additional flag indicating that user callback was called at all. */
424 hr = sample_grabber_report_sample(grabber, sample, &sample_delivered);
425 if (sample_delivered)
426 sample_grabber_stream_request_sample(grabber);
428 else
429 hr = stream_queue_sample(grabber, sample);
433 LeaveCriticalSection(&grabber->cs);
435 return hr;
438 static void sample_grabber_stream_report_marker(struct sample_grabber *grabber, const PROPVARIANT *context,
439 HRESULT hr)
441 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, MEStreamSinkMarker, &GUID_NULL, hr, context);
444 static HRESULT stream_place_marker(struct sample_grabber *grabber, MFSTREAMSINK_MARKER_TYPE marker_type,
445 const PROPVARIANT *context_value)
447 struct scheduled_item *item;
448 HRESULT hr = S_OK;
450 if (list_empty(&grabber->items))
452 sample_grabber_stream_report_marker(grabber, context_value, S_OK);
453 return S_OK;
456 if (!(item = heap_alloc_zero(sizeof(*item))))
457 return E_OUTOFMEMORY;
459 item->type = ITEM_TYPE_MARKER;
460 item->u.marker.type = marker_type;
461 list_init(&item->entry);
462 PropVariantInit(&item->u.marker.context);
463 if (context_value)
464 hr = PropVariantCopy(&item->u.marker.context, context_value);
465 if (SUCCEEDED(hr))
466 list_add_tail(&grabber->items, &item->entry);
467 else
468 stream_release_pending_item(item);
470 return hr;
473 static HRESULT WINAPI sample_grabber_stream_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
474 const PROPVARIANT *marker_value, const PROPVARIANT *context_value)
476 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
477 HRESULT hr = S_OK;
479 TRACE("%p, %d, %p, %p.\n", iface, marker_type, marker_value, context_value);
481 EnterCriticalSection(&grabber->cs);
483 if (grabber->is_shut_down)
484 hr = MF_E_STREAMSINK_REMOVED;
485 else if (grabber->state == SINK_STATE_RUNNING)
486 hr = stream_place_marker(grabber, marker_type, context_value);
488 LeaveCriticalSection(&grabber->cs);
490 return hr;
493 static HRESULT WINAPI sample_grabber_stream_Flush(IMFStreamSink *iface)
495 struct sample_grabber *grabber = impl_from_IMFStreamSink(iface);
496 struct scheduled_item *item, *next_item;
498 TRACE("%p.\n", iface);
500 if (grabber->is_shut_down)
501 return MF_E_STREAMSINK_REMOVED;
503 EnterCriticalSection(&grabber->cs);
505 LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &grabber->items, struct scheduled_item, entry)
507 /* Samples are discarded, markers are processed immediately. */
508 switch (item->type)
510 case ITEM_TYPE_SAMPLE:
511 break;
512 case ITEM_TYPE_MARKER:
513 sample_grabber_stream_report_marker(grabber, &item->u.marker.context, E_ABORT);
514 break;
517 stream_release_pending_item(item);
520 LeaveCriticalSection(&grabber->cs);
522 return S_OK;
525 static const IMFStreamSinkVtbl sample_grabber_stream_vtbl =
527 sample_grabber_stream_QueryInterface,
528 sample_grabber_stream_AddRef,
529 sample_grabber_stream_Release,
530 sample_grabber_stream_GetEvent,
531 sample_grabber_stream_BeginGetEvent,
532 sample_grabber_stream_EndGetEvent,
533 sample_grabber_stream_QueueEvent,
534 sample_grabber_stream_GetMediaSink,
535 sample_grabber_stream_GetIdentifier,
536 sample_grabber_stream_GetMediaTypeHandler,
537 sample_grabber_stream_ProcessSample,
538 sample_grabber_stream_PlaceMarker,
539 sample_grabber_stream_Flush,
542 static HRESULT WINAPI sample_grabber_stream_type_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid,
543 void **obj)
545 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
546 return IMFStreamSink_QueryInterface(&grabber->IMFStreamSink_iface, riid, obj);
549 static ULONG WINAPI sample_grabber_stream_type_handler_AddRef(IMFMediaTypeHandler *iface)
551 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
552 return IMFStreamSink_AddRef(&grabber->IMFStreamSink_iface);
555 static ULONG WINAPI sample_grabber_stream_type_handler_Release(IMFMediaTypeHandler *iface)
557 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
558 return IMFStreamSink_Release(&grabber->IMFStreamSink_iface);
561 static HRESULT sample_grabber_stream_is_media_type_supported(struct sample_grabber *grabber, IMFMediaType *in_type)
563 const DWORD supported_flags = MF_MEDIATYPE_EQUAL_MAJOR_TYPES | MF_MEDIATYPE_EQUAL_FORMAT_TYPES;
564 DWORD flags;
566 if (grabber->is_shut_down)
567 return MF_E_STREAMSINK_REMOVED;
569 if (!in_type)
570 return E_POINTER;
572 if (IMFMediaType_IsEqual(grabber->media_type, in_type, &flags) == S_OK)
573 return S_OK;
575 return (flags & supported_flags) == supported_flags ? S_OK : MF_E_INVALIDMEDIATYPE;
578 static HRESULT WINAPI sample_grabber_stream_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface,
579 IMFMediaType *in_type, IMFMediaType **out_type)
581 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
583 TRACE("%p, %p, %p.\n", iface, in_type, out_type);
585 return sample_grabber_stream_is_media_type_supported(grabber, in_type);
588 static HRESULT WINAPI sample_grabber_stream_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count)
590 TRACE("%p, %p.\n", iface, count);
592 if (!count)
593 return E_POINTER;
595 *count = 0;
597 return S_OK;
600 static HRESULT WINAPI sample_grabber_stream_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index,
601 IMFMediaType **media_type)
603 TRACE("%p, %u, %p.\n", iface, index, media_type);
605 if (!media_type)
606 return E_POINTER;
608 return MF_E_NO_MORE_TYPES;
611 static HRESULT WINAPI sample_grabber_stream_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface,
612 IMFMediaType *media_type)
614 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
615 HRESULT hr;
617 TRACE("%p, %p.\n", iface, media_type);
619 if (FAILED(hr = sample_grabber_stream_is_media_type_supported(grabber, media_type)))
620 return hr;
622 IMFMediaType_Release(grabber->media_type);
623 grabber->media_type = media_type;
624 IMFMediaType_AddRef(grabber->media_type);
626 return S_OK;
629 static HRESULT WINAPI sample_grabber_stream_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface,
630 IMFMediaType **media_type)
632 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
634 TRACE("%p, %p.\n", iface, media_type);
636 if (!media_type)
637 return E_POINTER;
639 if (grabber->is_shut_down)
640 return MF_E_STREAMSINK_REMOVED;
642 *media_type = grabber->media_type;
643 IMFMediaType_AddRef(*media_type);
645 return S_OK;
648 static HRESULT WINAPI sample_grabber_stream_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type)
650 struct sample_grabber *grabber = impl_from_IMFMediaTypeHandler(iface);
652 TRACE("%p, %p.\n", iface, type);
654 if (!type)
655 return E_POINTER;
657 if (grabber->is_shut_down)
658 return MF_E_STREAMSINK_REMOVED;
660 return IMFMediaType_GetMajorType(grabber->media_type, type);
663 static const IMFMediaTypeHandlerVtbl sample_grabber_stream_type_handler_vtbl =
665 sample_grabber_stream_type_handler_QueryInterface,
666 sample_grabber_stream_type_handler_AddRef,
667 sample_grabber_stream_type_handler_Release,
668 sample_grabber_stream_type_handler_IsMediaTypeSupported,
669 sample_grabber_stream_type_handler_GetMediaTypeCount,
670 sample_grabber_stream_type_handler_GetMediaTypeByIndex,
671 sample_grabber_stream_type_handler_SetCurrentMediaType,
672 sample_grabber_stream_type_handler_GetCurrentMediaType,
673 sample_grabber_stream_type_handler_GetMajorType,
676 static HRESULT WINAPI sample_grabber_stream_timer_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid,
677 void **obj)
679 if (IsEqualIID(riid, &IID_IMFAsyncCallback) || IsEqualIID(riid, &IID_IUnknown))
681 *obj = iface;
682 IMFAsyncCallback_AddRef(iface);
683 return S_OK;
686 WARN("Unsupported %s.\n", debugstr_guid(riid));
687 *obj = NULL;
688 return E_NOINTERFACE;
691 static ULONG WINAPI sample_grabber_stream_timer_callback_AddRef(IMFAsyncCallback *iface)
693 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
694 return IMFStreamSink_AddRef(&grabber->IMFStreamSink_iface);
697 static ULONG WINAPI sample_grabber_stream_timer_callback_Release(IMFAsyncCallback *iface)
699 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
700 return IMFStreamSink_Release(&grabber->IMFStreamSink_iface);
703 static HRESULT WINAPI sample_grabber_stream_timer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
704 DWORD *queue)
706 return E_NOTIMPL;
709 static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
711 struct sample_grabber *grabber = impl_from_IMFAsyncCallback(iface);
712 BOOL sample_reported = FALSE, sample_delivered = FALSE;
713 struct scheduled_item *item, *item2;
714 HRESULT hr;
716 EnterCriticalSection(&grabber->cs);
718 LIST_FOR_EACH_ENTRY_SAFE(item, item2, &grabber->items, struct scheduled_item, entry)
720 if (item->type == ITEM_TYPE_MARKER)
722 sample_grabber_stream_report_marker(grabber, &item->u.marker.context, S_OK);
723 stream_release_pending_item(item);
725 else if (item->type == ITEM_TYPE_SAMPLE)
727 if (!sample_reported)
729 if (FAILED(hr = sample_grabber_report_sample(grabber, item->u.sample, &sample_delivered)))
730 WARN("Failed to report a sample, hr %#x.\n", hr);
731 stream_release_pending_item(item);
732 sample_reported = TRUE;
734 else
736 if (FAILED(hr = stream_schedule_sample(grabber, item)))
737 WARN("Failed to schedule a sample, hr %#x.\n", hr);
738 break;
742 if (sample_delivered)
743 sample_grabber_stream_request_sample(grabber);
745 LeaveCriticalSection(&grabber->cs);
747 return S_OK;
750 static const IMFAsyncCallbackVtbl sample_grabber_stream_timer_callback_vtbl =
752 sample_grabber_stream_timer_callback_QueryInterface,
753 sample_grabber_stream_timer_callback_AddRef,
754 sample_grabber_stream_timer_callback_Release,
755 sample_grabber_stream_timer_callback_GetParameters,
756 sample_grabber_stream_timer_callback_Invoke,
759 static HRESULT WINAPI sample_grabber_sink_QueryInterface(IMFMediaSink *iface, REFIID riid, void **obj)
761 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
763 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
765 if (IsEqualIID(riid, &IID_IMFMediaSink) ||
766 IsEqualIID(riid, &IID_IUnknown))
768 *obj = &grabber->IMFMediaSink_iface;
770 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
772 *obj = &grabber->IMFClockStateSink_iface;
774 else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator))
776 *obj = &grabber->IMFMediaEventGenerator_iface;
778 else
780 WARN("Unsupported %s.\n", debugstr_guid(riid));
781 *obj = NULL;
782 return E_NOINTERFACE;
785 IUnknown_AddRef((IUnknown *)*obj);
787 return S_OK;
790 static ULONG WINAPI sample_grabber_sink_AddRef(IMFMediaSink *iface)
792 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
793 ULONG refcount = InterlockedIncrement(&grabber->refcount);
795 TRACE("%p, refcount %u.\n", iface, refcount);
797 return refcount;
800 static void sample_grabber_release_pending_items(struct sample_grabber *grabber)
802 struct scheduled_item *item, *next_item;
804 LIST_FOR_EACH_ENTRY_SAFE(item, next_item, &grabber->items, struct scheduled_item, entry)
806 stream_release_pending_item(item);
810 static ULONG WINAPI sample_grabber_sink_Release(IMFMediaSink *iface)
812 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
813 ULONG refcount = InterlockedDecrement(&grabber->refcount);
815 TRACE("%p, refcount %u.\n", iface, refcount);
817 if (!refcount)
819 if (grabber->callback)
820 IMFSampleGrabberSinkCallback_Release(grabber->callback);
821 if (grabber->callback2)
822 IMFSampleGrabberSinkCallback2_Release(grabber->callback2);
823 IMFMediaType_Release(grabber->media_type);
824 if (grabber->event_queue)
825 IMFMediaEventQueue_Release(grabber->event_queue);
826 if (grabber->clock)
827 IMFPresentationClock_Release(grabber->clock);
828 if (grabber->timer)
830 if (grabber->cancel_key)
831 IMFTimer_CancelTimer(grabber->timer, grabber->cancel_key);
832 IMFTimer_Release(grabber->timer);
834 if (grabber->cancel_key)
835 IUnknown_Release(grabber->cancel_key);
836 if (grabber->stream_event_queue)
838 IMFMediaEventQueue_Shutdown(grabber->stream_event_queue);
839 IMFMediaEventQueue_Release(grabber->stream_event_queue);
841 if (grabber->sample_attributes)
842 IMFAttributes_Release(grabber->sample_attributes);
843 sample_grabber_release_pending_items(grabber);
844 DeleteCriticalSection(&grabber->cs);
845 heap_free(grabber);
848 return refcount;
851 static HRESULT WINAPI sample_grabber_sink_GetCharacteristics(IMFMediaSink *iface, DWORD *flags)
853 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
855 TRACE("%p, %p.\n", iface, flags);
857 if (grabber->is_shut_down)
858 return MF_E_SHUTDOWN;
860 *flags = MEDIASINK_FIXED_STREAMS;
861 if (grabber->ignore_clock)
862 *flags |= MEDIASINK_RATELESS;
864 return S_OK;
867 static HRESULT WINAPI sample_grabber_sink_AddStreamSink(IMFMediaSink *iface, DWORD stream_sink_id,
868 IMFMediaType *media_type, IMFStreamSink **stream_sink)
870 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
872 TRACE("%p, %#x, %p, %p.\n", iface, stream_sink_id, media_type, stream_sink);
874 return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
877 static HRESULT WINAPI sample_grabber_sink_RemoveStreamSink(IMFMediaSink *iface, DWORD stream_sink_id)
879 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
881 TRACE("%p, %#x.\n", iface, stream_sink_id);
883 return grabber->is_shut_down ? MF_E_SHUTDOWN : MF_E_STREAMSINKS_FIXED;
886 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkCount(IMFMediaSink *iface, DWORD *count)
888 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
890 TRACE("%p, %p.\n", iface, count);
892 if (grabber->is_shut_down)
893 return MF_E_SHUTDOWN;
895 *count = 1;
897 return S_OK;
900 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkByIndex(IMFMediaSink *iface, DWORD index,
901 IMFStreamSink **stream)
903 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
904 HRESULT hr = S_OK;
906 TRACE("%p, %u, %p.\n", iface, index, stream);
908 if (grabber->is_shut_down)
909 return MF_E_SHUTDOWN;
911 EnterCriticalSection(&grabber->cs);
913 if (grabber->is_shut_down)
914 hr = MF_E_SHUTDOWN;
915 else if (index > 0)
916 hr = MF_E_INVALIDINDEX;
917 else
919 *stream = &grabber->IMFStreamSink_iface;
920 IMFStreamSink_AddRef(*stream);
923 LeaveCriticalSection(&grabber->cs);
925 return hr;
928 static HRESULT WINAPI sample_grabber_sink_GetStreamSinkById(IMFMediaSink *iface, DWORD stream_sink_id,
929 IMFStreamSink **stream)
931 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
932 HRESULT hr = S_OK;
934 TRACE("%p, %#x, %p.\n", iface, stream_sink_id, stream);
936 EnterCriticalSection(&grabber->cs);
938 if (grabber->is_shut_down)
939 hr = MF_E_SHUTDOWN;
940 else if (stream_sink_id > 0)
941 hr = MF_E_INVALIDSTREAMNUMBER;
942 else
944 *stream = &grabber->IMFStreamSink_iface;
945 IMFStreamSink_AddRef(*stream);
948 LeaveCriticalSection(&grabber->cs);
950 return hr;
953 static void sample_grabber_set_presentation_clock(struct sample_grabber *grabber, IMFPresentationClock *clock)
955 if (grabber->clock)
957 IMFPresentationClock_RemoveClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
958 IMFPresentationClock_Release(grabber->clock);
959 if (grabber->timer)
961 IMFTimer_Release(grabber->timer);
962 grabber->timer = NULL;
965 grabber->clock = clock;
966 if (grabber->clock)
968 IMFPresentationClock_AddRef(grabber->clock);
969 IMFPresentationClock_AddClockStateSink(grabber->clock, &grabber->IMFClockStateSink_iface);
970 if (FAILED(IMFPresentationClock_QueryInterface(grabber->clock, &IID_IMFTimer, (void **)&grabber->timer)))
972 WARN("Failed to get IMFTimer interface.\n");
973 grabber->timer = NULL;
978 static HRESULT WINAPI sample_grabber_sink_SetPresentationClock(IMFMediaSink *iface, IMFPresentationClock *clock)
980 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
981 HRESULT hr;
983 TRACE("%p, %p.\n", iface, clock);
985 EnterCriticalSection(&grabber->cs);
987 if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnSetPresentationClock(sample_grabber_get_callback(grabber),
988 clock)))
990 sample_grabber_set_presentation_clock(grabber, clock);
993 LeaveCriticalSection(&grabber->cs);
995 return hr;
998 static HRESULT WINAPI sample_grabber_sink_GetPresentationClock(IMFMediaSink *iface, IMFPresentationClock **clock)
1000 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1001 HRESULT hr = S_OK;
1003 TRACE("%p, %p.\n", iface, clock);
1005 if (!clock)
1006 return E_POINTER;
1008 EnterCriticalSection(&grabber->cs);
1010 if (grabber->clock)
1012 *clock = grabber->clock;
1013 IMFPresentationClock_AddRef(*clock);
1015 else
1016 hr = MF_E_NO_CLOCK;
1018 LeaveCriticalSection(&grabber->cs);
1020 return hr;
1023 static HRESULT WINAPI sample_grabber_sink_Shutdown(IMFMediaSink *iface)
1025 struct sample_grabber *grabber = impl_from_IMFMediaSink(iface);
1026 HRESULT hr;
1028 TRACE("%p.\n", iface);
1030 if (grabber->is_shut_down)
1031 return MF_E_SHUTDOWN;
1033 EnterCriticalSection(&grabber->cs);
1034 grabber->is_shut_down = TRUE;
1035 sample_grabber_release_pending_items(grabber);
1036 if (SUCCEEDED(hr = IMFSampleGrabberSinkCallback_OnShutdown(sample_grabber_get_callback(grabber))))
1038 sample_grabber_set_presentation_clock(grabber, NULL);
1039 IMFMediaEventQueue_Shutdown(grabber->stream_event_queue);
1040 IMFMediaEventQueue_Shutdown(grabber->event_queue);
1042 LeaveCriticalSection(&grabber->cs);
1044 return hr;
1047 static const IMFMediaSinkVtbl sample_grabber_sink_vtbl =
1049 sample_grabber_sink_QueryInterface,
1050 sample_grabber_sink_AddRef,
1051 sample_grabber_sink_Release,
1052 sample_grabber_sink_GetCharacteristics,
1053 sample_grabber_sink_AddStreamSink,
1054 sample_grabber_sink_RemoveStreamSink,
1055 sample_grabber_sink_GetStreamSinkCount,
1056 sample_grabber_sink_GetStreamSinkByIndex,
1057 sample_grabber_sink_GetStreamSinkById,
1058 sample_grabber_sink_SetPresentationClock,
1059 sample_grabber_sink_GetPresentationClock,
1060 sample_grabber_sink_Shutdown,
1063 static HRESULT WINAPI sample_grabber_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
1065 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1066 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1069 static ULONG WINAPI sample_grabber_clock_sink_AddRef(IMFClockStateSink *iface)
1071 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1072 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1075 static ULONG WINAPI sample_grabber_clock_sink_Release(IMFClockStateSink *iface)
1077 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1078 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1081 static void sample_grabber_set_state(struct sample_grabber *grabber, enum sink_state state)
1083 static const DWORD events[] =
1085 MEStreamSinkStopped, /* SINK_STATE_STOPPED */
1086 MEStreamSinkStarted, /* SINK_STATE_RUNNING */
1088 BOOL set_state = FALSE;
1089 unsigned int i;
1091 EnterCriticalSection(&grabber->cs);
1093 if (!grabber->is_shut_down)
1095 switch (grabber->state)
1097 case SINK_STATE_STOPPED:
1098 set_state = state == SINK_STATE_RUNNING;
1099 break;
1100 case SINK_STATE_RUNNING:
1101 set_state = state == SINK_STATE_STOPPED;
1102 break;
1103 default:
1107 if (set_state)
1109 grabber->state = state;
1110 if (state == SINK_STATE_RUNNING)
1112 /* Every transition to running state sends a bunch requests to build up initial queue. */
1113 for (i = 0; i < 4; ++i)
1114 sample_grabber_stream_request_sample(grabber);
1116 IMFStreamSink_QueueEvent(&grabber->IMFStreamSink_iface, events[state], &GUID_NULL, S_OK, NULL);
1120 LeaveCriticalSection(&grabber->cs);
1123 static HRESULT WINAPI sample_grabber_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
1125 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1127 TRACE("%p, %s, %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
1129 sample_grabber_set_state(grabber, SINK_STATE_RUNNING);
1131 return IMFSampleGrabberSinkCallback_OnClockStart(sample_grabber_get_callback(grabber), systime, offset);
1134 static HRESULT WINAPI sample_grabber_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
1136 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1138 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1140 sample_grabber_set_state(grabber, SINK_STATE_STOPPED);
1142 return IMFSampleGrabberSinkCallback_OnClockStop(sample_grabber_get_callback(grabber), systime);
1145 static HRESULT WINAPI sample_grabber_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
1147 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1149 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1151 return IMFSampleGrabberSinkCallback_OnClockPause(sample_grabber_get_callback(grabber), systime);
1154 static HRESULT WINAPI sample_grabber_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
1156 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1158 TRACE("%p, %s.\n", iface, debugstr_time(systime));
1160 sample_grabber_set_state(grabber, SINK_STATE_RUNNING);
1162 return IMFSampleGrabberSinkCallback_OnClockRestart(sample_grabber_get_callback(grabber), systime);
1165 static HRESULT WINAPI sample_grabber_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
1167 struct sample_grabber *grabber = impl_from_IMFClockStateSink(iface);
1169 TRACE("%p, %s, %f.\n", iface, debugstr_time(systime), rate);
1171 return IMFSampleGrabberSinkCallback_OnClockSetRate(sample_grabber_get_callback(grabber), systime, rate);
1174 static HRESULT WINAPI sample_grabber_events_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj)
1176 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1177 return IMFMediaSink_QueryInterface(&grabber->IMFMediaSink_iface, riid, obj);
1180 static ULONG WINAPI sample_grabber_events_AddRef(IMFMediaEventGenerator *iface)
1182 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1183 return IMFMediaSink_AddRef(&grabber->IMFMediaSink_iface);
1186 static ULONG WINAPI sample_grabber_events_Release(IMFMediaEventGenerator *iface)
1188 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1189 return IMFMediaSink_Release(&grabber->IMFMediaSink_iface);
1192 static HRESULT WINAPI sample_grabber_events_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event)
1194 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1196 TRACE("%p, %#x, %p.\n", iface, flags, event);
1198 return IMFMediaEventQueue_GetEvent(grabber->event_queue, flags, event);
1201 static HRESULT WINAPI sample_grabber_events_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback,
1202 IUnknown *state)
1204 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1206 TRACE("%p, %p, %p.\n", iface, callback, state);
1208 return IMFMediaEventQueue_BeginGetEvent(grabber->event_queue, callback, state);
1211 static HRESULT WINAPI sample_grabber_events_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result,
1212 IMFMediaEvent **event)
1214 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1216 TRACE("%p, %p, %p.\n", iface, result, event);
1218 return IMFMediaEventQueue_EndGetEvent(grabber->event_queue, result, event);
1221 static HRESULT WINAPI sample_grabber_events_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type,
1222 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
1224 struct sample_grabber *grabber = impl_from_IMFMediaEventGenerator(iface);
1226 TRACE("%p, %u, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1228 return IMFMediaEventQueue_QueueEventParamVar(grabber->event_queue, event_type, ext_type, hr, value);
1231 static const IMFMediaEventGeneratorVtbl sample_grabber_sink_events_vtbl =
1233 sample_grabber_events_QueryInterface,
1234 sample_grabber_events_AddRef,
1235 sample_grabber_events_Release,
1236 sample_grabber_events_GetEvent,
1237 sample_grabber_events_BeginGetEvent,
1238 sample_grabber_events_EndGetEvent,
1239 sample_grabber_events_QueueEvent,
1242 static const IMFClockStateSinkVtbl sample_grabber_clock_sink_vtbl =
1244 sample_grabber_clock_sink_QueryInterface,
1245 sample_grabber_clock_sink_AddRef,
1246 sample_grabber_clock_sink_Release,
1247 sample_grabber_clock_sink_OnClockStart,
1248 sample_grabber_clock_sink_OnClockStop,
1249 sample_grabber_clock_sink_OnClockPause,
1250 sample_grabber_clock_sink_OnClockRestart,
1251 sample_grabber_clock_sink_OnClockSetRate,
1254 static HRESULT sample_grabber_create_object(IMFAttributes *attributes, void *user_context, IUnknown **obj)
1256 struct sample_grabber_activate_context *context = user_context;
1257 struct sample_grabber *object;
1258 HRESULT hr;
1259 GUID guid;
1261 TRACE("%p, %p, %p.\n", attributes, user_context, obj);
1263 if (context->shut_down)
1264 return MF_E_SHUTDOWN;
1266 /* At least major type is required. */
1267 if (FAILED(IMFMediaType_GetMajorType(context->media_type, &guid)))
1268 return MF_E_INVALIDMEDIATYPE;
1270 object = heap_alloc_zero(sizeof(*object));
1271 if (!object)
1272 return E_OUTOFMEMORY;
1274 object->IMFMediaSink_iface.lpVtbl = &sample_grabber_sink_vtbl;
1275 object->IMFClockStateSink_iface.lpVtbl = &sample_grabber_clock_sink_vtbl;
1276 object->IMFMediaEventGenerator_iface.lpVtbl = &sample_grabber_sink_events_vtbl;
1277 object->IMFStreamSink_iface.lpVtbl = &sample_grabber_stream_vtbl;
1278 object->IMFMediaTypeHandler_iface.lpVtbl = &sample_grabber_stream_type_handler_vtbl;
1279 object->timer_callback.lpVtbl = &sample_grabber_stream_timer_callback_vtbl;
1280 object->refcount = 1;
1281 if (FAILED(IMFSampleGrabberSinkCallback_QueryInterface(context->callback, &IID_IMFSampleGrabberSinkCallback2,
1282 (void **)&object->callback2)))
1284 object->callback = context->callback;
1285 IMFSampleGrabberSinkCallback_AddRef(object->callback);
1287 object->media_type = context->media_type;
1288 IMFMediaType_AddRef(object->media_type);
1289 IMFAttributes_GetUINT32(attributes, &MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, &object->ignore_clock);
1290 IMFAttributes_GetUINT64(attributes, &MF_SAMPLEGRABBERSINK_SAMPLE_TIME_OFFSET, &object->sample_time_offset);
1291 list_init(&object->items);
1292 InitializeCriticalSection(&object->cs);
1294 if (FAILED(hr = MFCreateEventQueue(&object->stream_event_queue)))
1295 goto failed;
1297 if (FAILED(hr = MFCreateAttributes(&object->sample_attributes, 0)))
1298 goto failed;
1300 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1301 goto failed;
1303 *obj = (IUnknown *)&object->IMFMediaSink_iface;
1305 TRACE("Created %p.\n", *obj);
1307 return S_OK;
1309 failed:
1311 IMFMediaSink_Release(&object->IMFMediaSink_iface);
1313 return hr;
1316 static void sample_grabber_shutdown_object(void *user_context, IUnknown *obj)
1318 struct sample_grabber_activate_context *context = user_context;
1319 context->shut_down = TRUE;
1322 static const struct activate_funcs sample_grabber_activate_funcs =
1324 sample_grabber_create_object,
1325 sample_grabber_shutdown_object,
1326 sample_grabber_free_private,
1329 /***********************************************************************
1330 * MFCreateSampleGrabberSinkActivate (mf.@)
1332 HRESULT WINAPI MFCreateSampleGrabberSinkActivate(IMFMediaType *media_type, IMFSampleGrabberSinkCallback *callback,
1333 IMFActivate **activate)
1335 struct sample_grabber_activate_context *context;
1336 HRESULT hr;
1338 TRACE("%p, %p, %p.\n", media_type, callback, activate);
1340 if (!media_type || !callback || !activate)
1341 return E_POINTER;
1343 context = heap_alloc_zero(sizeof(*context));
1344 if (!context)
1345 return E_OUTOFMEMORY;
1347 context->media_type = media_type;
1348 IMFMediaType_AddRef(context->media_type);
1349 context->callback = callback;
1350 IMFSampleGrabberSinkCallback_AddRef(context->callback);
1352 if (FAILED(hr = create_activation_object(context, &sample_grabber_activate_funcs, activate)))
1353 sample_grabber_free_private(context);
1355 return hr;