cmd: DIR command outputs free space for the path.
[wine.git] / dlls / winegstreamer / media_sink.c
blobfcea67eb8f19963cf9a5f5512e3527dd646de4bf
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"
21 #include "mferror.h"
22 #include "mfapi.h"
24 #include "wine/debug.h"
25 #include "wine/list.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
29 enum async_op
31 ASYNC_START,
32 ASYNC_STOP,
33 ASYNC_PAUSE,
36 struct async_command
38 IUnknown IUnknown_iface;
39 LONG refcount;
41 enum async_op op;
44 struct stream_sink
46 IMFStreamSink IMFStreamSink_iface;
47 IMFMediaTypeHandler IMFMediaTypeHandler_iface;
48 LONG refcount;
49 DWORD id;
51 IMFMediaType *type;
52 IMFFinalizableMediaSink *media_sink;
53 IMFMediaEventQueue *event_queue;
55 struct list entry;
58 struct media_sink
60 IMFFinalizableMediaSink IMFFinalizableMediaSink_iface;
61 IMFMediaEventGenerator IMFMediaEventGenerator_iface;
62 IMFClockStateSink IMFClockStateSink_iface;
63 IMFAsyncCallback async_callback;
64 LONG refcount;
65 CRITICAL_SECTION cs;
67 enum
69 STATE_OPENED,
70 STATE_STARTED,
71 STATE_STOPPED,
72 STATE_PAUSED,
73 STATE_SHUTDOWN,
74 } state;
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))
121 *obj = iface;
122 IUnknown_AddRef(iface);
123 return S_OK;
126 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
127 *obj = NULL;
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);
142 if (!refcount)
143 free(command);
145 return 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;
164 command->op = op;
166 TRACE("Created async command %p.\n", command);
167 *out = command;
169 return S_OK;
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;
188 else
190 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
191 *obj = NULL;
192 return E_NOINTERFACE;
195 IUnknown_AddRef((IUnknown *)*obj);
197 return S_OK;
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);
205 return 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);
215 if (!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);
221 free(stream_sink);
224 return refcount;
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,
237 IUnknown *state)
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));
275 return S_OK;
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;
286 return S_OK;
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));
297 return S_OK;
300 static HRESULT WINAPI stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
302 FIXME("iface %p, sample %p stub!\n", iface, sample);
304 return E_NOTIMPL;
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);
313 return E_NOTIMPL;
316 static HRESULT WINAPI stream_sink_Flush(IMFStreamSink *iface)
318 FIXME("iface %p stub!\n", iface);
320 return E_NOTIMPL;
323 static const IMFStreamSinkVtbl stream_sink_vtbl =
325 stream_sink_QueryInterface,
326 stream_sink_AddRef,
327 stream_sink_Release,
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,
337 stream_sink_Flush,
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);
363 return E_NOTIMPL;
366 static HRESULT WINAPI stream_sink_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count)
368 FIXME("iface %p, count %p.\n", iface, count);
370 return E_NOTIMPL;
373 static HRESULT WINAPI stream_sink_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index,
374 IMFMediaType **type)
376 FIXME("iface %p, index %lu, type %p.\n", iface, index, type);
378 return E_NOTIMPL;
381 static HRESULT WINAPI stream_sink_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType *type)
383 FIXME("iface %p, type %p.\n", iface, type);
385 return E_NOTIMPL;
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);
394 if (!type)
395 return E_POINTER;
396 if (!stream_sink->type)
397 return MF_E_NOT_INITIALIZED;
399 IMFMediaType_AddRef((*type = stream_sink->type));
401 return S_OK;
404 static HRESULT WINAPI stream_sink_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type)
406 FIXME("iface %p, type %p.\n", iface, type);
408 return E_NOTIMPL;
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;
428 HRESULT hr;
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)))
438 free(stream_sink);
439 return hr;
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;
446 if (media_type)
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);
451 *out = stream_sink;
453 return S_OK;
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)
463 return stream_sink;
466 return NULL;
469 static HRESULT media_sink_queue_command(struct media_sink *media_sink, enum async_op op)
471 struct async_command *command;
472 HRESULT hr;
474 if (media_sink->state == STATE_SHUTDOWN)
475 return MF_E_SHUTDOWN;
477 if (FAILED(hr = async_command_create(op, &command)))
478 return hr;
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;
486 HRESULT hr;
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)))
491 return hr;
494 return S_OK;
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))
526 *obj = iface;
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;
536 else
538 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
539 *obj = NULL;
540 return E_NOINTERFACE;
543 IUnknown_AddRef((IUnknown *)*obj);
545 return S_OK;
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);
553 return 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);
563 if (!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);
570 free(media_sink);
573 return refcount;
576 static HRESULT WINAPI media_sink_GetCharacteristics(IMFFinalizableMediaSink *iface, DWORD *flags)
578 FIXME("iface %p, flags %p stub!\n", iface, flags);
580 return E_NOTIMPL;
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;
588 HRESULT hr;
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);
605 return hr;
608 list_add_tail(&media_sink->stream_sinks, &object->entry);
610 LeaveCriticalSection(&media_sink->cs);
612 if (stream_sink)
613 IMFStreamSink_AddRef((*stream_sink = &object->IMFStreamSink_iface));
615 return S_OK;
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);
622 return E_NOTIMPL;
625 static HRESULT WINAPI media_sink_GetStreamSinkCount(IMFFinalizableMediaSink *iface, DWORD *count)
627 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
629 TRACE("iface %p, count %p.\n", iface, count);
631 if (!count)
632 return E_POINTER;
634 EnterCriticalSection(&media_sink->cs);
635 *count = list_count(&media_sink->stream_sinks);
636 LeaveCriticalSection(&media_sink->cs);
638 return S_OK;
641 static HRESULT WINAPI media_sink_GetStreamSinkByIndex(IMFFinalizableMediaSink *iface, DWORD index,
642 IMFStreamSink **stream)
644 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
645 struct stream_sink *stream_sink;
646 HRESULT hr = MF_E_INVALIDINDEX;
647 DWORD entry_index = 0;
649 TRACE("iface %p, index %lu, stream %p stub!\n", iface, index, stream);
651 if (!stream)
652 return E_POINTER;
654 EnterCriticalSection(&media_sink->cs);
656 LIST_FOR_EACH_ENTRY(stream_sink, &media_sink->stream_sinks, struct stream_sink, entry)
658 if (entry_index++ == index)
660 IMFStreamSink_AddRef((*stream = &stream_sink->IMFStreamSink_iface));
661 hr = S_OK;
662 break;
666 LeaveCriticalSection(&media_sink->cs);
668 return hr;
671 static HRESULT WINAPI media_sink_GetStreamSinkById(IMFFinalizableMediaSink *iface, DWORD stream_sink_id,
672 IMFStreamSink **stream)
674 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
675 struct stream_sink *stream_sink;
676 HRESULT hr;
678 TRACE("iface %p, stream_sink_id %#lx, stream %p.\n", iface, stream_sink_id, stream);
680 if (!stream)
681 return E_POINTER;
683 EnterCriticalSection(&media_sink->cs);
685 hr = MF_E_INVALIDSTREAMNUMBER;
686 if ((stream_sink = media_sink_get_stream_sink_by_id(media_sink, stream_sink_id)))
688 IMFStreamSink_AddRef((*stream = &stream_sink->IMFStreamSink_iface));
689 hr = S_OK;
692 LeaveCriticalSection(&media_sink->cs);
694 return hr;
697 static HRESULT WINAPI media_sink_SetPresentationClock(IMFFinalizableMediaSink *iface, IMFPresentationClock *clock)
699 FIXME("iface %p, clock %p stub!\n", iface, clock);
701 return E_NOTIMPL;
704 static HRESULT WINAPI media_sink_GetPresentationClock(IMFFinalizableMediaSink *iface, IMFPresentationClock **clock)
706 FIXME("iface %p, clock %p stub!\n", iface, clock);
708 return E_NOTIMPL;
711 static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface)
713 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
714 struct stream_sink *stream_sink, *next;
716 TRACE("iface %p.\n", iface);
718 EnterCriticalSection(&media_sink->cs);
720 if (media_sink->state == STATE_SHUTDOWN)
722 LeaveCriticalSection(&media_sink->cs);
723 return MF_E_SHUTDOWN;
726 LIST_FOR_EACH_ENTRY_SAFE(stream_sink, next, &media_sink->stream_sinks, struct stream_sink, entry)
728 list_remove(&stream_sink->entry);
729 IMFMediaEventQueue_Shutdown(stream_sink->event_queue);
730 IMFStreamSink_Release(&stream_sink->IMFStreamSink_iface);
733 IMFMediaEventQueue_Shutdown(media_sink->event_queue);
734 IMFByteStream_Close(media_sink->bytestream);
736 media_sink->state = STATE_SHUTDOWN;
738 LeaveCriticalSection(&media_sink->cs);
740 return S_OK;
743 static HRESULT WINAPI media_sink_BeginFinalize(IMFFinalizableMediaSink *iface, IMFAsyncCallback *callback, IUnknown *state)
745 FIXME("iface %p, callback %p, state %p stub!\n", iface, callback, state);
747 return E_NOTIMPL;
750 static HRESULT WINAPI media_sink_EndFinalize(IMFFinalizableMediaSink *iface, IMFAsyncResult *result)
752 FIXME("iface %p, result %p stub!\n", iface, result);
754 return E_NOTIMPL;
757 static const IMFFinalizableMediaSinkVtbl media_sink_vtbl =
759 media_sink_QueryInterface,
760 media_sink_AddRef,
761 media_sink_Release,
762 media_sink_GetCharacteristics,
763 media_sink_AddStreamSink,
764 media_sink_RemoveStreamSink,
765 media_sink_GetStreamSinkCount,
766 media_sink_GetStreamSinkByIndex,
767 media_sink_GetStreamSinkById,
768 media_sink_SetPresentationClock,
769 media_sink_GetPresentationClock,
770 media_sink_Shutdown,
771 media_sink_BeginFinalize,
772 media_sink_EndFinalize,
775 static HRESULT WINAPI media_sink_event_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj)
777 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
778 return IMFFinalizableMediaSink_QueryInterface(&media_sink->IMFFinalizableMediaSink_iface, riid, obj);
781 static ULONG WINAPI media_sink_event_AddRef(IMFMediaEventGenerator *iface)
783 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
784 return IMFFinalizableMediaSink_AddRef(&media_sink->IMFFinalizableMediaSink_iface);
787 static ULONG WINAPI media_sink_event_Release(IMFMediaEventGenerator *iface)
789 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
790 return IMFFinalizableMediaSink_Release(&media_sink->IMFFinalizableMediaSink_iface);
793 static HRESULT WINAPI media_sink_event_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event)
795 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
797 TRACE("iface %p, flags %#lx, event %p.\n", iface, flags, event);
799 return IMFMediaEventQueue_GetEvent(media_sink->event_queue, flags, event);
802 static HRESULT WINAPI media_sink_event_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback,
803 IUnknown *state)
805 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
807 TRACE("iface %p, callback %p, state %p.\n", iface, callback, state);
809 return IMFMediaEventQueue_BeginGetEvent(media_sink->event_queue, callback, state);
812 static HRESULT WINAPI media_sink_event_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result,
813 IMFMediaEvent **event)
815 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
817 TRACE("iface %p, result %p, event %p.\n", iface, result, event);
819 return IMFMediaEventQueue_EndGetEvent(media_sink->event_queue, result, event);
822 static HRESULT WINAPI media_sink_event_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type,
823 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
825 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
827 TRACE("iface %p, event_type %lu, ext_type %s, hr %#lx, value %p.\n",
828 iface, event_type, debugstr_guid(ext_type), hr, value);
830 return IMFMediaEventQueue_QueueEventParamVar(media_sink->event_queue, event_type, ext_type, hr, value);
833 static const IMFMediaEventGeneratorVtbl media_sink_event_vtbl =
835 media_sink_event_QueryInterface,
836 media_sink_event_AddRef,
837 media_sink_event_Release,
838 media_sink_event_GetEvent,
839 media_sink_event_BeginGetEvent,
840 media_sink_event_EndGetEvent,
841 media_sink_event_QueueEvent,
844 static HRESULT WINAPI media_sink_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
846 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
847 return IMFFinalizableMediaSink_QueryInterface(&media_sink->IMFFinalizableMediaSink_iface, riid, obj);
850 static ULONG WINAPI media_sink_clock_sink_AddRef(IMFClockStateSink *iface)
852 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
853 return IMFFinalizableMediaSink_AddRef(&media_sink->IMFFinalizableMediaSink_iface);
856 static ULONG WINAPI media_sink_clock_sink_Release(IMFClockStateSink *iface)
858 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
859 return IMFFinalizableMediaSink_Release(&media_sink->IMFFinalizableMediaSink_iface);
862 static HRESULT WINAPI media_sink_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
864 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
865 HRESULT hr;
867 TRACE("iface %p, systime %s, offset %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
869 EnterCriticalSection(&media_sink->cs);
871 hr = media_sink_queue_command(media_sink, ASYNC_START);
873 LeaveCriticalSection(&media_sink->cs);
874 return hr;
877 static HRESULT WINAPI media_sink_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
879 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
880 HRESULT hr;
882 TRACE("iface %p, systime %s.\n", iface, debugstr_time(systime));
884 EnterCriticalSection(&media_sink->cs);
886 hr = media_sink_queue_command(media_sink, ASYNC_STOP);
888 LeaveCriticalSection(&media_sink->cs);
889 return hr;
892 static HRESULT WINAPI media_sink_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
894 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
895 HRESULT hr;
897 TRACE("iface %p, systime %s.\n", iface, debugstr_time(systime));
899 EnterCriticalSection(&media_sink->cs);
901 hr = media_sink_queue_command(media_sink, ASYNC_PAUSE);
903 LeaveCriticalSection(&media_sink->cs);
904 return hr;
907 static HRESULT WINAPI media_sink_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
909 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
910 HRESULT hr;
912 TRACE("iface %p, systime %s.\n", iface, debugstr_time(systime));
914 EnterCriticalSection(&media_sink->cs);
916 hr = media_sink_queue_command(media_sink, ASYNC_START);
918 LeaveCriticalSection(&media_sink->cs);
919 return hr;
922 static HRESULT WINAPI media_sink_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
924 FIXME("iface %p, systime %s, rate %f stub!\n", iface, debugstr_time(systime), rate);
926 return E_NOTIMPL;
929 static const IMFClockStateSinkVtbl media_sink_clock_sink_vtbl =
931 media_sink_clock_sink_QueryInterface,
932 media_sink_clock_sink_AddRef,
933 media_sink_clock_sink_Release,
934 media_sink_clock_sink_OnClockStart,
935 media_sink_clock_sink_OnClockStop,
936 media_sink_clock_sink_OnClockPause,
937 media_sink_clock_sink_OnClockRestart,
938 media_sink_clock_sink_OnClockSetRate,
941 static HRESULT WINAPI media_sink_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
943 TRACE("iface %p, riid %s, obj %p.\n", iface, debugstr_guid(riid), obj);
945 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
946 IsEqualIID(riid, &IID_IUnknown))
948 *obj = iface;
949 IMFAsyncCallback_AddRef(iface);
950 return S_OK;
953 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
954 *obj = NULL;
955 return E_NOINTERFACE;
958 static ULONG WINAPI media_sink_callback_AddRef(IMFAsyncCallback *iface)
960 struct media_sink *sink = impl_from_async_callback(iface);
961 return IMFFinalizableMediaSink_AddRef(&sink->IMFFinalizableMediaSink_iface);
964 static ULONG WINAPI media_sink_callback_Release(IMFAsyncCallback *iface)
966 struct media_sink *sink = impl_from_async_callback(iface);
967 return IMFFinalizableMediaSink_Release(&sink->IMFFinalizableMediaSink_iface);
970 static HRESULT WINAPI media_sink_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
972 TRACE("iface %p, flags %p, queue %p.\n", iface, flags, queue);
974 return E_NOTIMPL;
977 static HRESULT WINAPI media_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *async_result)
979 struct media_sink *media_sink = impl_from_async_callback(iface);
980 struct async_command *command;
981 HRESULT hr = E_FAIL;
982 IUnknown *state;
984 TRACE("iface %p, async_result %p.\n", iface, async_result);
986 EnterCriticalSection(&media_sink->cs);
988 if (!(state = IMFAsyncResult_GetStateNoAddRef(async_result)))
990 LeaveCriticalSection(&media_sink->cs);
991 return hr;
994 command = impl_from_async_command_IUnknown(state);
995 switch (command->op)
997 case ASYNC_START:
998 hr = media_sink_start(media_sink);
999 break;
1000 case ASYNC_STOP:
1001 hr = media_sink_stop(media_sink);
1002 break;
1003 case ASYNC_PAUSE:
1004 hr = media_sink_pause(media_sink);
1005 break;
1006 default:
1007 WARN("Unsupported op %u.\n", command->op);
1008 break;
1011 LeaveCriticalSection(&media_sink->cs);
1013 return hr;
1016 static const IMFAsyncCallbackVtbl media_sink_callback_vtbl =
1018 media_sink_callback_QueryInterface,
1019 media_sink_callback_AddRef,
1020 media_sink_callback_Release,
1021 media_sink_callback_GetParameters,
1022 media_sink_callback_Invoke,
1025 static HRESULT media_sink_create(IMFByteStream *bytestream, struct media_sink **out)
1027 struct media_sink *media_sink;
1028 HRESULT hr;
1030 TRACE("bytestream %p, out %p.\n", bytestream, out);
1032 if (!bytestream)
1033 return E_POINTER;
1035 if (!(media_sink = calloc(1, sizeof(*media_sink))))
1036 return E_OUTOFMEMORY;
1038 if (FAILED(hr = MFCreateEventQueue(&media_sink->event_queue)))
1040 free(media_sink);
1041 return hr;
1044 media_sink->IMFFinalizableMediaSink_iface.lpVtbl = &media_sink_vtbl;
1045 media_sink->IMFMediaEventGenerator_iface.lpVtbl = &media_sink_event_vtbl;
1046 media_sink->IMFClockStateSink_iface.lpVtbl = &media_sink_clock_sink_vtbl;
1047 media_sink->async_callback.lpVtbl = &media_sink_callback_vtbl;
1048 media_sink->refcount = 1;
1049 media_sink->state = STATE_OPENED;
1050 InitializeCriticalSection(&media_sink->cs);
1051 media_sink->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
1052 IMFByteStream_AddRef((media_sink->bytestream = bytestream));
1053 list_init(&media_sink->stream_sinks);
1055 *out = media_sink;
1056 TRACE("Created media sink %p.\n", media_sink);
1058 return S_OK;
1061 static HRESULT WINAPI sink_class_factory_QueryInterface(IMFSinkClassFactory *iface, REFIID riid, void **out)
1063 if (IsEqualIID(riid, &IID_IMFSinkClassFactory)
1064 || IsEqualIID(riid, &IID_IUnknown))
1066 *out = iface;
1067 IMFSinkClassFactory_AddRef(iface);
1068 return S_OK;
1071 *out = NULL;
1072 return E_NOINTERFACE;
1075 static ULONG WINAPI sink_class_factory_AddRef(IMFSinkClassFactory *iface)
1077 return 2;
1080 static ULONG WINAPI sink_class_factory_Release(IMFSinkClassFactory *iface)
1082 return 1;
1085 static HRESULT WINAPI sink_class_factory_CreateMediaSink(IMFSinkClassFactory *iface, IMFByteStream *bytestream,
1086 IMFMediaType *video_type, IMFMediaType *audio_type, IMFMediaSink **out)
1088 IMFFinalizableMediaSink *media_sink_iface;
1089 struct media_sink *media_sink;
1090 HRESULT hr;
1092 TRACE("iface %p, bytestream %p, video_type %p, audio_type %p, out %p.\n",
1093 iface, bytestream, video_type, audio_type, out);
1095 if (FAILED(hr = media_sink_create(bytestream, &media_sink)))
1096 return hr;
1097 media_sink_iface = &media_sink->IMFFinalizableMediaSink_iface;
1099 if (video_type)
1101 if (FAILED(hr = IMFFinalizableMediaSink_AddStreamSink(media_sink_iface, 1, video_type, NULL)))
1103 IMFFinalizableMediaSink_Shutdown(media_sink_iface);
1104 IMFFinalizableMediaSink_Release(media_sink_iface);
1105 return hr;
1108 if (audio_type)
1110 if (FAILED(hr = IMFFinalizableMediaSink_AddStreamSink(media_sink_iface, 2, audio_type, NULL)))
1112 IMFFinalizableMediaSink_Shutdown(media_sink_iface);
1113 IMFFinalizableMediaSink_Release(media_sink_iface);
1114 return hr;
1118 *out = (IMFMediaSink *)media_sink_iface;
1119 return S_OK;
1122 static const IMFSinkClassFactoryVtbl sink_class_factory_vtbl =
1124 sink_class_factory_QueryInterface,
1125 sink_class_factory_AddRef,
1126 sink_class_factory_Release,
1127 sink_class_factory_CreateMediaSink,
1130 static IMFSinkClassFactory sink_class_factory = { &sink_class_factory_vtbl };
1132 HRESULT sink_class_factory_create(IUnknown *outer, IUnknown **out)
1134 *out = (IUnknown *)&sink_class_factory;
1135 return S_OK;