1 /* Gstreamer Media Sink
3 * Copyright 2023 Ziqing Hui for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "gst_private.h"
24 #include "wine/debug.h"
25 #include "wine/list.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
38 IUnknown IUnknown_iface
;
46 IMFStreamSink IMFStreamSink_iface
;
47 IMFMediaTypeHandler IMFMediaTypeHandler_iface
;
52 IMFFinalizableMediaSink
*media_sink
;
53 IMFMediaEventQueue
*event_queue
;
60 IMFFinalizableMediaSink IMFFinalizableMediaSink_iface
;
61 IMFMediaEventGenerator IMFMediaEventGenerator_iface
;
62 IMFClockStateSink IMFClockStateSink_iface
;
63 IMFAsyncCallback async_callback
;
76 IMFByteStream
*bytestream
;
77 IMFMediaEventQueue
*event_queue
;
79 struct list stream_sinks
;
82 static struct stream_sink
*impl_from_IMFStreamSink(IMFStreamSink
*iface
)
84 return CONTAINING_RECORD(iface
, struct stream_sink
, IMFStreamSink_iface
);
87 static struct stream_sink
*impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler
*iface
)
89 return CONTAINING_RECORD(iface
, struct stream_sink
, IMFMediaTypeHandler_iface
);
92 static struct media_sink
*impl_from_IMFFinalizableMediaSink(IMFFinalizableMediaSink
*iface
)
94 return CONTAINING_RECORD(iface
, struct media_sink
, IMFFinalizableMediaSink_iface
);
97 static struct media_sink
*impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator
*iface
)
99 return CONTAINING_RECORD(iface
, struct media_sink
, IMFMediaEventGenerator_iface
);
102 static struct media_sink
*impl_from_IMFClockStateSink(IMFClockStateSink
*iface
)
104 return CONTAINING_RECORD(iface
, struct media_sink
, IMFClockStateSink_iface
);
107 static struct media_sink
*impl_from_async_callback(IMFAsyncCallback
*iface
)
109 return CONTAINING_RECORD(iface
, struct media_sink
, async_callback
);
112 static struct async_command
*impl_from_async_command_IUnknown(IUnknown
*iface
)
114 return CONTAINING_RECORD(iface
, struct async_command
, IUnknown_iface
);
117 static HRESULT WINAPI
async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
119 if (IsEqualIID(riid
, &IID_IUnknown
))
122 IUnknown_AddRef(iface
);
126 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
128 return E_NOINTERFACE
;
131 static ULONG WINAPI
async_command_AddRef(IUnknown
*iface
)
133 struct async_command
*command
= impl_from_async_command_IUnknown(iface
);
134 return InterlockedIncrement(&command
->refcount
);
137 static ULONG WINAPI
async_command_Release(IUnknown
*iface
)
139 struct async_command
*command
= impl_from_async_command_IUnknown(iface
);
140 ULONG refcount
= InterlockedDecrement(&command
->refcount
);
148 static const IUnknownVtbl async_command_vtbl
=
150 async_command_QueryInterface
,
151 async_command_AddRef
,
152 async_command_Release
,
155 static HRESULT
async_command_create(enum async_op op
, struct async_command
**out
)
157 struct async_command
*command
;
159 if (!(command
= calloc(1, sizeof(*command
))))
160 return E_OUTOFMEMORY
;
162 command
->IUnknown_iface
.lpVtbl
= &async_command_vtbl
;
163 command
->refcount
= 1;
166 TRACE("Created async command %p.\n", command
);
172 static HRESULT WINAPI
stream_sink_QueryInterface(IMFStreamSink
*iface
, REFIID riid
, void **obj
)
174 struct stream_sink
*stream_sink
= impl_from_IMFStreamSink(iface
);
176 TRACE("iface %p, riid %s, obj %p.\n", iface
, debugstr_guid(riid
), obj
);
178 if (IsEqualIID(riid
, &IID_IMFStreamSink
) ||
179 IsEqualGUID(riid
, &IID_IMFMediaEventGenerator
) ||
180 IsEqualIID(riid
, &IID_IUnknown
))
182 *obj
= &stream_sink
->IMFStreamSink_iface
;
184 else if (IsEqualIID(riid
, &IID_IMFMediaTypeHandler
))
186 *obj
= &stream_sink
->IMFMediaTypeHandler_iface
;
190 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
192 return E_NOINTERFACE
;
195 IUnknown_AddRef((IUnknown
*)*obj
);
200 static ULONG WINAPI
stream_sink_AddRef(IMFStreamSink
*iface
)
202 struct stream_sink
*stream_sink
= impl_from_IMFStreamSink(iface
);
203 ULONG refcount
= InterlockedIncrement(&stream_sink
->refcount
);
204 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
208 static ULONG WINAPI
stream_sink_Release(IMFStreamSink
*iface
)
210 struct stream_sink
*stream_sink
= impl_from_IMFStreamSink(iface
);
211 ULONG refcount
= InterlockedDecrement(&stream_sink
->refcount
);
213 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
217 IMFMediaEventQueue_Release(stream_sink
->event_queue
);
218 IMFFinalizableMediaSink_Release(stream_sink
->media_sink
);
219 if (stream_sink
->type
)
220 IMFMediaType_Release(stream_sink
->type
);
227 static HRESULT WINAPI
stream_sink_GetEvent(IMFStreamSink
*iface
, DWORD flags
, IMFMediaEvent
**event
)
229 struct stream_sink
*stream_sink
= impl_from_IMFStreamSink(iface
);
231 TRACE("iface %p, flags %#lx, event %p.\n", iface
, flags
, event
);
233 return IMFMediaEventQueue_GetEvent(stream_sink
->event_queue
, flags
, event
);
236 static HRESULT WINAPI
stream_sink_BeginGetEvent(IMFStreamSink
*iface
, IMFAsyncCallback
*callback
,
239 struct stream_sink
*stream_sink
= impl_from_IMFStreamSink(iface
);
241 TRACE("iface %p, callback %p, state %p.\n", iface
, callback
, state
);
243 return IMFMediaEventQueue_BeginGetEvent(stream_sink
->event_queue
, callback
, state
);
246 static HRESULT WINAPI
stream_sink_EndGetEvent(IMFStreamSink
*iface
, IMFAsyncResult
*result
,
247 IMFMediaEvent
**event
)
249 struct stream_sink
*stream_sink
= impl_from_IMFStreamSink(iface
);
251 TRACE("iface %p, result %p, event %p.\n", iface
, result
, event
);
253 return IMFMediaEventQueue_EndGetEvent(stream_sink
->event_queue
, result
, event
);
256 static HRESULT WINAPI
stream_sink_QueueEvent(IMFStreamSink
*iface
, MediaEventType event_type
,
257 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
259 struct stream_sink
*stream_sink
= impl_from_IMFStreamSink(iface
);
261 TRACE("iface %p, event_type %lu, ext_type %s, hr %#lx, value %p.\n",
262 iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
264 return IMFMediaEventQueue_QueueEventParamVar(stream_sink
->event_queue
, event_type
, ext_type
, hr
, value
);
267 static HRESULT WINAPI
stream_sink_GetMediaSink(IMFStreamSink
*iface
, IMFMediaSink
**ret
)
269 struct stream_sink
*stream_sink
= impl_from_IMFStreamSink(iface
);
271 TRACE("iface %p, ret %p.\n", iface
, ret
);
273 IMFMediaSink_AddRef((*ret
= (IMFMediaSink
*)stream_sink
->media_sink
));
278 static HRESULT WINAPI
stream_sink_GetIdentifier(IMFStreamSink
*iface
, DWORD
*identifier
)
280 struct stream_sink
*stream_sink
= impl_from_IMFStreamSink(iface
);
282 TRACE("iface %p, identifier %p.\n", iface
, identifier
);
284 *identifier
= stream_sink
->id
;
289 static HRESULT WINAPI
stream_sink_GetMediaTypeHandler(IMFStreamSink
*iface
, IMFMediaTypeHandler
**handler
)
291 struct stream_sink
*stream_sink
= impl_from_IMFStreamSink(iface
);
293 TRACE("iface %p, handler %p.\n", iface
, handler
);
295 IMFMediaTypeHandler_AddRef((*handler
= &stream_sink
->IMFMediaTypeHandler_iface
));
300 static HRESULT WINAPI
stream_sink_ProcessSample(IMFStreamSink
*iface
, IMFSample
*sample
)
302 FIXME("iface %p, sample %p stub!\n", iface
, sample
);
307 static HRESULT WINAPI
stream_sink_PlaceMarker(IMFStreamSink
*iface
, MFSTREAMSINK_MARKER_TYPE marker_type
,
308 const PROPVARIANT
*marker_value
, const PROPVARIANT
*context_value
)
310 FIXME("iface %p, marker_type %d, marker_value %p, context_value %p stub!\n",
311 iface
, marker_type
, marker_value
, context_value
);
316 static HRESULT WINAPI
stream_sink_Flush(IMFStreamSink
*iface
)
318 FIXME("iface %p stub!\n", iface
);
323 static const IMFStreamSinkVtbl stream_sink_vtbl
=
325 stream_sink_QueryInterface
,
328 stream_sink_GetEvent
,
329 stream_sink_BeginGetEvent
,
330 stream_sink_EndGetEvent
,
331 stream_sink_QueueEvent
,
332 stream_sink_GetMediaSink
,
333 stream_sink_GetIdentifier
,
334 stream_sink_GetMediaTypeHandler
,
335 stream_sink_ProcessSample
,
336 stream_sink_PlaceMarker
,
340 static HRESULT WINAPI
stream_sink_type_handler_QueryInterface(IMFMediaTypeHandler
*iface
, REFIID riid
, void **obj
)
342 struct stream_sink
*stream_sink
= impl_from_IMFMediaTypeHandler(iface
);
343 return IMFStreamSink_QueryInterface(&stream_sink
->IMFStreamSink_iface
, riid
, obj
);
346 static ULONG WINAPI
stream_sink_type_handler_AddRef(IMFMediaTypeHandler
*iface
)
348 struct stream_sink
*stream_sink
= impl_from_IMFMediaTypeHandler(iface
);
349 return IMFStreamSink_AddRef(&stream_sink
->IMFStreamSink_iface
);
352 static ULONG WINAPI
stream_sink_type_handler_Release(IMFMediaTypeHandler
*iface
)
354 struct stream_sink
*stream_sink
= impl_from_IMFMediaTypeHandler(iface
);
355 return IMFStreamSink_Release(&stream_sink
->IMFStreamSink_iface
);
358 static HRESULT WINAPI
stream_sink_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler
*iface
,
359 IMFMediaType
*in_type
, IMFMediaType
**out_type
)
361 FIXME("iface %p, in_type %p, out_type %p.\n", iface
, in_type
, out_type
);
366 static HRESULT WINAPI
stream_sink_type_handler_GetMediaTypeCount(IMFMediaTypeHandler
*iface
, DWORD
*count
)
368 FIXME("iface %p, count %p.\n", iface
, count
);
373 static HRESULT WINAPI
stream_sink_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
*iface
, DWORD index
,
376 FIXME("iface %p, index %lu, type %p.\n", iface
, index
, type
);
381 static HRESULT WINAPI
stream_sink_type_handler_SetCurrentMediaType(IMFMediaTypeHandler
*iface
, IMFMediaType
*type
)
383 FIXME("iface %p, type %p.\n", iface
, type
);
388 static HRESULT WINAPI
stream_sink_type_handler_GetCurrentMediaType(IMFMediaTypeHandler
*iface
, IMFMediaType
**type
)
390 struct stream_sink
*stream_sink
= impl_from_IMFMediaTypeHandler(iface
);
392 TRACE("iface %p, type %p.\n", iface
, type
);
396 if (!stream_sink
->type
)
397 return MF_E_NOT_INITIALIZED
;
399 IMFMediaType_AddRef((*type
= stream_sink
->type
));
404 static HRESULT WINAPI
stream_sink_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
406 FIXME("iface %p, type %p.\n", iface
, type
);
411 static const IMFMediaTypeHandlerVtbl stream_sink_type_handler_vtbl
=
413 stream_sink_type_handler_QueryInterface
,
414 stream_sink_type_handler_AddRef
,
415 stream_sink_type_handler_Release
,
416 stream_sink_type_handler_IsMediaTypeSupported
,
417 stream_sink_type_handler_GetMediaTypeCount
,
418 stream_sink_type_handler_GetMediaTypeByIndex
,
419 stream_sink_type_handler_SetCurrentMediaType
,
420 stream_sink_type_handler_GetCurrentMediaType
,
421 stream_sink_type_handler_GetMajorType
,
424 static HRESULT
stream_sink_create(DWORD stream_sink_id
, IMFMediaType
*media_type
, struct media_sink
*media_sink
,
425 struct stream_sink
**out
)
427 struct stream_sink
*stream_sink
;
430 TRACE("stream_sink_id %#lx, media_type %p, media_sink %p, out %p.\n",
431 stream_sink_id
, media_type
, media_sink
, out
);
433 if (!(stream_sink
= calloc(1, sizeof(*stream_sink
))))
434 return E_OUTOFMEMORY
;
436 if (FAILED(hr
= MFCreateEventQueue(&stream_sink
->event_queue
)))
442 stream_sink
->IMFStreamSink_iface
.lpVtbl
= &stream_sink_vtbl
;
443 stream_sink
->IMFMediaTypeHandler_iface
.lpVtbl
= &stream_sink_type_handler_vtbl
;
444 stream_sink
->refcount
= 1;
445 stream_sink
->id
= stream_sink_id
;
447 IMFMediaType_AddRef((stream_sink
->type
= media_type
));
448 IMFFinalizableMediaSink_AddRef((stream_sink
->media_sink
= &media_sink
->IMFFinalizableMediaSink_iface
));
450 TRACE("Created stream sink %p.\n", stream_sink
);
456 static struct stream_sink
*media_sink_get_stream_sink_by_id(struct media_sink
*media_sink
, DWORD id
)
458 struct stream_sink
*stream_sink
;
460 LIST_FOR_EACH_ENTRY(stream_sink
, &media_sink
->stream_sinks
, struct stream_sink
, entry
)
462 if (stream_sink
->id
== id
)
469 static HRESULT
media_sink_queue_command(struct media_sink
*media_sink
, enum async_op op
)
471 struct async_command
*command
;
474 if (media_sink
->state
== STATE_SHUTDOWN
)
475 return MF_E_SHUTDOWN
;
477 if (FAILED(hr
= async_command_create(op
, &command
)))
480 return MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD
, &media_sink
->async_callback
, &command
->IUnknown_iface
);
483 static HRESULT
media_sink_queue_stream_event(struct media_sink
*media_sink
, MediaEventType type
)
485 struct stream_sink
*stream_sink
;
488 LIST_FOR_EACH_ENTRY(stream_sink
, &media_sink
->stream_sinks
, struct stream_sink
, entry
)
490 if (FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(stream_sink
->event_queue
, type
, &GUID_NULL
, S_OK
, NULL
)))
497 static HRESULT
media_sink_start(struct media_sink
*media_sink
)
499 media_sink
->state
= STATE_STARTED
;
500 return media_sink_queue_stream_event(media_sink
, MEStreamSinkStarted
);
503 static HRESULT
media_sink_stop(struct media_sink
*media_sink
)
505 media_sink
->state
= STATE_STOPPED
;
506 return media_sink_queue_stream_event(media_sink
, MEStreamSinkStopped
);
510 static HRESULT
media_sink_pause(struct media_sink
*media_sink
)
512 media_sink
->state
= STATE_PAUSED
;
513 return media_sink_queue_stream_event(media_sink
, MEStreamSinkPaused
);
516 static HRESULT WINAPI
media_sink_QueryInterface(IMFFinalizableMediaSink
*iface
, REFIID riid
, void **obj
)
518 struct media_sink
*media_sink
= impl_from_IMFFinalizableMediaSink(iface
);
520 TRACE("iface %p, riid %s, obj %p.\n", iface
, debugstr_guid(riid
), obj
);
522 if (IsEqualIID(riid
, &IID_IMFFinalizableMediaSink
) ||
523 IsEqualIID(riid
, &IID_IMFMediaSink
) ||
524 IsEqualIID(riid
, &IID_IUnknown
))
528 else if (IsEqualGUID(riid
, &IID_IMFMediaEventGenerator
))
530 *obj
= &media_sink
->IMFMediaEventGenerator_iface
;
532 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
534 *obj
= &media_sink
->IMFClockStateSink_iface
;
538 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
540 return E_NOINTERFACE
;
543 IUnknown_AddRef((IUnknown
*)*obj
);
548 static ULONG WINAPI
media_sink_AddRef(IMFFinalizableMediaSink
*iface
)
550 struct media_sink
*media_sink
= impl_from_IMFFinalizableMediaSink(iface
);
551 ULONG refcount
= InterlockedIncrement(&media_sink
->refcount
);
552 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
556 static ULONG WINAPI
media_sink_Release(IMFFinalizableMediaSink
*iface
)
558 struct media_sink
*media_sink
= impl_from_IMFFinalizableMediaSink(iface
);
559 ULONG refcount
= InterlockedDecrement(&media_sink
->refcount
);
561 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
565 IMFFinalizableMediaSink_Shutdown(iface
);
566 IMFMediaEventQueue_Release(media_sink
->event_queue
);
567 IMFByteStream_Release(media_sink
->bytestream
);
568 media_sink
->cs
.DebugInfo
->Spare
[0] = 0;
569 DeleteCriticalSection(&media_sink
->cs
);
576 static HRESULT WINAPI
media_sink_GetCharacteristics(IMFFinalizableMediaSink
*iface
, DWORD
*flags
)
578 FIXME("iface %p, flags %p stub!\n", iface
, flags
);
583 static HRESULT WINAPI
media_sink_AddStreamSink(IMFFinalizableMediaSink
*iface
, DWORD stream_sink_id
,
584 IMFMediaType
*media_type
, IMFStreamSink
**stream_sink
)
586 struct media_sink
*media_sink
= impl_from_IMFFinalizableMediaSink(iface
);
587 struct stream_sink
*object
;
590 TRACE("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p.\n",
591 iface
, stream_sink_id
, media_type
, stream_sink
);
593 EnterCriticalSection(&media_sink
->cs
);
595 if (media_sink_get_stream_sink_by_id(media_sink
, stream_sink_id
))
597 LeaveCriticalSection(&media_sink
->cs
);
598 return MF_E_STREAMSINK_EXISTS
;
601 if (FAILED(hr
= stream_sink_create(stream_sink_id
, media_type
, media_sink
, &object
)))
603 WARN("Failed to create stream sink, hr %#lx.\n", hr
);
604 LeaveCriticalSection(&media_sink
->cs
);
608 list_add_tail(&media_sink
->stream_sinks
, &object
->entry
);
610 LeaveCriticalSection(&media_sink
->cs
);
613 IMFStreamSink_AddRef((*stream_sink
= &object
->IMFStreamSink_iface
));
618 static HRESULT WINAPI
media_sink_RemoveStreamSink(IMFFinalizableMediaSink
*iface
, DWORD stream_sink_id
)
620 FIXME("iface %p, stream_sink_id %#lx stub!\n", iface
, stream_sink_id
);
625 static HRESULT WINAPI
media_sink_GetStreamSinkCount(IMFFinalizableMediaSink
*iface
, DWORD
*count
)
627 FIXME("iface %p, count %p stub!\n", iface
, count
);
632 static HRESULT WINAPI
media_sink_GetStreamSinkByIndex(IMFFinalizableMediaSink
*iface
, DWORD index
,
633 IMFStreamSink
**stream
)
635 FIXME("iface %p, index %lu, stream %p stub!\n", iface
, index
, stream
);
640 static HRESULT WINAPI
media_sink_GetStreamSinkById(IMFFinalizableMediaSink
*iface
, DWORD stream_sink_id
,
641 IMFStreamSink
**stream
)
643 FIXME("iface %p, stream_sink_id %#lx, stream %p stub!\n", iface
, stream_sink_id
, stream
);
648 static HRESULT WINAPI
media_sink_SetPresentationClock(IMFFinalizableMediaSink
*iface
, IMFPresentationClock
*clock
)
650 FIXME("iface %p, clock %p stub!\n", iface
, clock
);
655 static HRESULT WINAPI
media_sink_GetPresentationClock(IMFFinalizableMediaSink
*iface
, IMFPresentationClock
**clock
)
657 FIXME("iface %p, clock %p stub!\n", iface
, clock
);
662 static HRESULT WINAPI
media_sink_Shutdown(IMFFinalizableMediaSink
*iface
)
664 struct media_sink
*media_sink
= impl_from_IMFFinalizableMediaSink(iface
);
665 struct stream_sink
*stream_sink
, *next
;
667 TRACE("iface %p.\n", iface
);
669 EnterCriticalSection(&media_sink
->cs
);
671 if (media_sink
->state
== STATE_SHUTDOWN
)
673 LeaveCriticalSection(&media_sink
->cs
);
674 return MF_E_SHUTDOWN
;
677 LIST_FOR_EACH_ENTRY_SAFE(stream_sink
, next
, &media_sink
->stream_sinks
, struct stream_sink
, entry
)
679 list_remove(&stream_sink
->entry
);
680 IMFMediaEventQueue_Shutdown(stream_sink
->event_queue
);
681 IMFStreamSink_Release(&stream_sink
->IMFStreamSink_iface
);
684 IMFMediaEventQueue_Shutdown(media_sink
->event_queue
);
685 IMFByteStream_Close(media_sink
->bytestream
);
687 media_sink
->state
= STATE_SHUTDOWN
;
689 LeaveCriticalSection(&media_sink
->cs
);
694 static HRESULT WINAPI
media_sink_BeginFinalize(IMFFinalizableMediaSink
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
696 FIXME("iface %p, callback %p, state %p stub!\n", iface
, callback
, state
);
701 static HRESULT WINAPI
media_sink_EndFinalize(IMFFinalizableMediaSink
*iface
, IMFAsyncResult
*result
)
703 FIXME("iface %p, result %p stub!\n", iface
, result
);
708 static const IMFFinalizableMediaSinkVtbl media_sink_vtbl
=
710 media_sink_QueryInterface
,
713 media_sink_GetCharacteristics
,
714 media_sink_AddStreamSink
,
715 media_sink_RemoveStreamSink
,
716 media_sink_GetStreamSinkCount
,
717 media_sink_GetStreamSinkByIndex
,
718 media_sink_GetStreamSinkById
,
719 media_sink_SetPresentationClock
,
720 media_sink_GetPresentationClock
,
722 media_sink_BeginFinalize
,
723 media_sink_EndFinalize
,
726 static HRESULT WINAPI
media_sink_event_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
728 struct media_sink
*media_sink
= impl_from_IMFMediaEventGenerator(iface
);
729 return IMFFinalizableMediaSink_QueryInterface(&media_sink
->IMFFinalizableMediaSink_iface
, riid
, obj
);
732 static ULONG WINAPI
media_sink_event_AddRef(IMFMediaEventGenerator
*iface
)
734 struct media_sink
*media_sink
= impl_from_IMFMediaEventGenerator(iface
);
735 return IMFFinalizableMediaSink_AddRef(&media_sink
->IMFFinalizableMediaSink_iface
);
738 static ULONG WINAPI
media_sink_event_Release(IMFMediaEventGenerator
*iface
)
740 struct media_sink
*media_sink
= impl_from_IMFMediaEventGenerator(iface
);
741 return IMFFinalizableMediaSink_Release(&media_sink
->IMFFinalizableMediaSink_iface
);
744 static HRESULT WINAPI
media_sink_event_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
746 struct media_sink
*media_sink
= impl_from_IMFMediaEventGenerator(iface
);
748 TRACE("iface %p, flags %#lx, event %p.\n", iface
, flags
, event
);
750 return IMFMediaEventQueue_GetEvent(media_sink
->event_queue
, flags
, event
);
753 static HRESULT WINAPI
media_sink_event_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
756 struct media_sink
*media_sink
= impl_from_IMFMediaEventGenerator(iface
);
758 TRACE("iface %p, callback %p, state %p.\n", iface
, callback
, state
);
760 return IMFMediaEventQueue_BeginGetEvent(media_sink
->event_queue
, callback
, state
);
763 static HRESULT WINAPI
media_sink_event_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
764 IMFMediaEvent
**event
)
766 struct media_sink
*media_sink
= impl_from_IMFMediaEventGenerator(iface
);
768 TRACE("iface %p, result %p, event %p.\n", iface
, result
, event
);
770 return IMFMediaEventQueue_EndGetEvent(media_sink
->event_queue
, result
, event
);
773 static HRESULT WINAPI
media_sink_event_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
774 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
776 struct media_sink
*media_sink
= impl_from_IMFMediaEventGenerator(iface
);
778 TRACE("iface %p, event_type %lu, ext_type %s, hr %#lx, value %p.\n",
779 iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
781 return IMFMediaEventQueue_QueueEventParamVar(media_sink
->event_queue
, event_type
, ext_type
, hr
, value
);
784 static const IMFMediaEventGeneratorVtbl media_sink_event_vtbl
=
786 media_sink_event_QueryInterface
,
787 media_sink_event_AddRef
,
788 media_sink_event_Release
,
789 media_sink_event_GetEvent
,
790 media_sink_event_BeginGetEvent
,
791 media_sink_event_EndGetEvent
,
792 media_sink_event_QueueEvent
,
795 static HRESULT WINAPI
media_sink_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
797 struct media_sink
*media_sink
= impl_from_IMFClockStateSink(iface
);
798 return IMFFinalizableMediaSink_QueryInterface(&media_sink
->IMFFinalizableMediaSink_iface
, riid
, obj
);
801 static ULONG WINAPI
media_sink_clock_sink_AddRef(IMFClockStateSink
*iface
)
803 struct media_sink
*media_sink
= impl_from_IMFClockStateSink(iface
);
804 return IMFFinalizableMediaSink_AddRef(&media_sink
->IMFFinalizableMediaSink_iface
);
807 static ULONG WINAPI
media_sink_clock_sink_Release(IMFClockStateSink
*iface
)
809 struct media_sink
*media_sink
= impl_from_IMFClockStateSink(iface
);
810 return IMFFinalizableMediaSink_Release(&media_sink
->IMFFinalizableMediaSink_iface
);
813 static HRESULT WINAPI
media_sink_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
815 struct media_sink
*media_sink
= impl_from_IMFClockStateSink(iface
);
818 TRACE("iface %p, systime %s, offset %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
820 EnterCriticalSection(&media_sink
->cs
);
822 hr
= media_sink_queue_command(media_sink
, ASYNC_START
);
824 LeaveCriticalSection(&media_sink
->cs
);
828 static HRESULT WINAPI
media_sink_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
830 struct media_sink
*media_sink
= impl_from_IMFClockStateSink(iface
);
833 TRACE("iface %p, systime %s.\n", iface
, debugstr_time(systime
));
835 EnterCriticalSection(&media_sink
->cs
);
837 hr
= media_sink_queue_command(media_sink
, ASYNC_STOP
);
839 LeaveCriticalSection(&media_sink
->cs
);
843 static HRESULT WINAPI
media_sink_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
845 struct media_sink
*media_sink
= impl_from_IMFClockStateSink(iface
);
848 TRACE("iface %p, systime %s.\n", iface
, debugstr_time(systime
));
850 EnterCriticalSection(&media_sink
->cs
);
852 hr
= media_sink_queue_command(media_sink
, ASYNC_PAUSE
);
854 LeaveCriticalSection(&media_sink
->cs
);
858 static HRESULT WINAPI
media_sink_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
860 struct media_sink
*media_sink
= impl_from_IMFClockStateSink(iface
);
863 TRACE("iface %p, systime %s.\n", iface
, debugstr_time(systime
));
865 EnterCriticalSection(&media_sink
->cs
);
867 hr
= media_sink_queue_command(media_sink
, ASYNC_START
);
869 LeaveCriticalSection(&media_sink
->cs
);
873 static HRESULT WINAPI
media_sink_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
875 FIXME("iface %p, systime %s, rate %f stub!\n", iface
, debugstr_time(systime
), rate
);
880 static const IMFClockStateSinkVtbl media_sink_clock_sink_vtbl
=
882 media_sink_clock_sink_QueryInterface
,
883 media_sink_clock_sink_AddRef
,
884 media_sink_clock_sink_Release
,
885 media_sink_clock_sink_OnClockStart
,
886 media_sink_clock_sink_OnClockStop
,
887 media_sink_clock_sink_OnClockPause
,
888 media_sink_clock_sink_OnClockRestart
,
889 media_sink_clock_sink_OnClockSetRate
,
892 static HRESULT WINAPI
media_sink_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
894 TRACE("iface %p, riid %s, obj %p.\n", iface
, debugstr_guid(riid
), obj
);
896 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
897 IsEqualIID(riid
, &IID_IUnknown
))
900 IMFAsyncCallback_AddRef(iface
);
904 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
906 return E_NOINTERFACE
;
909 static ULONG WINAPI
media_sink_callback_AddRef(IMFAsyncCallback
*iface
)
911 struct media_sink
*sink
= impl_from_async_callback(iface
);
912 return IMFFinalizableMediaSink_AddRef(&sink
->IMFFinalizableMediaSink_iface
);
915 static ULONG WINAPI
media_sink_callback_Release(IMFAsyncCallback
*iface
)
917 struct media_sink
*sink
= impl_from_async_callback(iface
);
918 return IMFFinalizableMediaSink_Release(&sink
->IMFFinalizableMediaSink_iface
);
921 static HRESULT WINAPI
media_sink_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
923 TRACE("iface %p, flags %p, queue %p.\n", iface
, flags
, queue
);
928 static HRESULT WINAPI
media_sink_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*async_result
)
930 struct media_sink
*media_sink
= impl_from_async_callback(iface
);
931 struct async_command
*command
;
935 TRACE("iface %p, async_result %p.\n", iface
, async_result
);
937 EnterCriticalSection(&media_sink
->cs
);
939 if (!(state
= IMFAsyncResult_GetStateNoAddRef(async_result
)))
941 LeaveCriticalSection(&media_sink
->cs
);
945 command
= impl_from_async_command_IUnknown(state
);
949 hr
= media_sink_start(media_sink
);
952 hr
= media_sink_stop(media_sink
);
955 hr
= media_sink_pause(media_sink
);
958 WARN("Unsupported op %u.\n", command
->op
);
962 LeaveCriticalSection(&media_sink
->cs
);
967 static const IMFAsyncCallbackVtbl media_sink_callback_vtbl
=
969 media_sink_callback_QueryInterface
,
970 media_sink_callback_AddRef
,
971 media_sink_callback_Release
,
972 media_sink_callback_GetParameters
,
973 media_sink_callback_Invoke
,
976 static HRESULT
media_sink_create(IMFByteStream
*bytestream
, struct media_sink
**out
)
978 struct media_sink
*media_sink
;
981 TRACE("bytestream %p, out %p.\n", bytestream
, out
);
986 if (!(media_sink
= calloc(1, sizeof(*media_sink
))))
987 return E_OUTOFMEMORY
;
989 if (FAILED(hr
= MFCreateEventQueue(&media_sink
->event_queue
)))
995 media_sink
->IMFFinalizableMediaSink_iface
.lpVtbl
= &media_sink_vtbl
;
996 media_sink
->IMFMediaEventGenerator_iface
.lpVtbl
= &media_sink_event_vtbl
;
997 media_sink
->IMFClockStateSink_iface
.lpVtbl
= &media_sink_clock_sink_vtbl
;
998 media_sink
->async_callback
.lpVtbl
= &media_sink_callback_vtbl
;
999 media_sink
->refcount
= 1;
1000 media_sink
->state
= STATE_OPENED
;
1001 InitializeCriticalSection(&media_sink
->cs
);
1002 media_sink
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": cs");
1003 IMFByteStream_AddRef((media_sink
->bytestream
= bytestream
));
1004 list_init(&media_sink
->stream_sinks
);
1007 TRACE("Created media sink %p.\n", media_sink
);
1012 static HRESULT WINAPI
sink_class_factory_QueryInterface(IMFSinkClassFactory
*iface
, REFIID riid
, void **out
)
1014 if (IsEqualIID(riid
, &IID_IMFSinkClassFactory
)
1015 || IsEqualIID(riid
, &IID_IUnknown
))
1018 IMFSinkClassFactory_AddRef(iface
);
1023 return E_NOINTERFACE
;
1026 static ULONG WINAPI
sink_class_factory_AddRef(IMFSinkClassFactory
*iface
)
1031 static ULONG WINAPI
sink_class_factory_Release(IMFSinkClassFactory
*iface
)
1036 static HRESULT WINAPI
sink_class_factory_CreateMediaSink(IMFSinkClassFactory
*iface
, IMFByteStream
*bytestream
,
1037 IMFMediaType
*video_type
, IMFMediaType
*audio_type
, IMFMediaSink
**out
)
1039 IMFFinalizableMediaSink
*media_sink_iface
;
1040 struct media_sink
*media_sink
;
1043 TRACE("iface %p, bytestream %p, video_type %p, audio_type %p, out %p.\n",
1044 iface
, bytestream
, video_type
, audio_type
, out
);
1046 if (FAILED(hr
= media_sink_create(bytestream
, &media_sink
)))
1048 media_sink_iface
= &media_sink
->IMFFinalizableMediaSink_iface
;
1052 if (FAILED(hr
= IMFFinalizableMediaSink_AddStreamSink(media_sink_iface
, 1, video_type
, NULL
)))
1054 IMFFinalizableMediaSink_Shutdown(media_sink_iface
);
1055 IMFFinalizableMediaSink_Release(media_sink_iface
);
1061 if (FAILED(hr
= IMFFinalizableMediaSink_AddStreamSink(media_sink_iface
, 2, audio_type
, NULL
)))
1063 IMFFinalizableMediaSink_Shutdown(media_sink_iface
);
1064 IMFFinalizableMediaSink_Release(media_sink_iface
);
1069 *out
= (IMFMediaSink
*)media_sink_iface
;
1073 static const IMFSinkClassFactoryVtbl sink_class_factory_vtbl
=
1075 sink_class_factory_QueryInterface
,
1076 sink_class_factory_AddRef
,
1077 sink_class_factory_Release
,
1078 sink_class_factory_CreateMediaSink
,
1081 static IMFSinkClassFactory sink_class_factory
= { &sink_class_factory_vtbl
};
1083 HRESULT
sink_class_factory_create(IUnknown
*outer
, IUnknown
**out
)
1085 *out
= (IUnknown
*)&sink_class_factory
;