d3dx9: Unify calling parse_mesh helper functions.
[wine.git] / dlls / winegstreamer / media_sink.c
blob6996d689e83493e688c08e918f59e77ceed3418e
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,
34 ASYNC_PROCESS,
37 struct async_command
39 IUnknown IUnknown_iface;
40 LONG refcount;
42 enum async_op op;
44 union
46 struct
48 IMFSample *sample;
49 UINT32 stream_id;
50 } process;
51 } u;
54 struct stream_sink
56 IMFStreamSink IMFStreamSink_iface;
57 IMFMediaTypeHandler IMFMediaTypeHandler_iface;
58 LONG refcount;
59 DWORD id;
61 IMFMediaType *type;
62 IMFFinalizableMediaSink *media_sink;
63 IMFMediaEventQueue *event_queue;
65 struct list entry;
68 struct media_sink
70 IMFFinalizableMediaSink IMFFinalizableMediaSink_iface;
71 IMFMediaEventGenerator IMFMediaEventGenerator_iface;
72 IMFClockStateSink IMFClockStateSink_iface;
73 IMFAsyncCallback async_callback;
74 LONG refcount;
75 CRITICAL_SECTION cs;
77 enum
79 STATE_OPENED,
80 STATE_STARTED,
81 STATE_STOPPED,
82 STATE_PAUSED,
83 STATE_SHUTDOWN,
84 } state;
86 IMFByteStream *bytestream;
87 IMFMediaEventQueue *event_queue;
89 struct list stream_sinks;
91 wg_muxer_t muxer;
94 static struct stream_sink *impl_from_IMFStreamSink(IMFStreamSink *iface)
96 return CONTAINING_RECORD(iface, struct stream_sink, IMFStreamSink_iface);
99 static struct stream_sink *impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler *iface)
101 return CONTAINING_RECORD(iface, struct stream_sink, IMFMediaTypeHandler_iface);
104 static struct media_sink *impl_from_IMFFinalizableMediaSink(IMFFinalizableMediaSink *iface)
106 return CONTAINING_RECORD(iface, struct media_sink, IMFFinalizableMediaSink_iface);
109 static struct media_sink *impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator *iface)
111 return CONTAINING_RECORD(iface, struct media_sink, IMFMediaEventGenerator_iface);
114 static struct media_sink *impl_from_IMFClockStateSink(IMFClockStateSink *iface)
116 return CONTAINING_RECORD(iface, struct media_sink, IMFClockStateSink_iface);
119 static struct media_sink *impl_from_async_callback(IMFAsyncCallback *iface)
121 return CONTAINING_RECORD(iface, struct media_sink, async_callback);
124 static struct async_command *impl_from_async_command_IUnknown(IUnknown *iface)
126 return CONTAINING_RECORD(iface, struct async_command, IUnknown_iface);
129 static HRESULT WINAPI async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
131 if (IsEqualIID(riid, &IID_IUnknown))
133 *obj = iface;
134 IUnknown_AddRef(iface);
135 return S_OK;
138 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
139 *obj = NULL;
140 return E_NOINTERFACE;
143 static ULONG WINAPI async_command_AddRef(IUnknown *iface)
145 struct async_command *command = impl_from_async_command_IUnknown(iface);
146 return InterlockedIncrement(&command->refcount);
149 static ULONG WINAPI async_command_Release(IUnknown *iface)
151 struct async_command *command = impl_from_async_command_IUnknown(iface);
152 ULONG refcount = InterlockedDecrement(&command->refcount);
154 if (!refcount)
156 if (command->op == ASYNC_PROCESS && command->u.process.sample)
157 IMFSample_Release(command->u.process.sample);
158 free(command);
161 return refcount;
164 static const IUnknownVtbl async_command_vtbl =
166 async_command_QueryInterface,
167 async_command_AddRef,
168 async_command_Release,
171 static HRESULT async_command_create(enum async_op op, struct async_command **out)
173 struct async_command *command;
175 if (!(command = calloc(1, sizeof(*command))))
176 return E_OUTOFMEMORY;
178 command->IUnknown_iface.lpVtbl = &async_command_vtbl;
179 command->refcount = 1;
180 command->op = op;
182 TRACE("Created async command %p.\n", command);
183 *out = command;
185 return S_OK;
188 static HRESULT WINAPI stream_sink_QueryInterface(IMFStreamSink *iface, REFIID riid, void **obj)
190 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
192 TRACE("iface %p, riid %s, obj %p.\n", iface, debugstr_guid(riid), obj);
194 if (IsEqualIID(riid, &IID_IMFStreamSink) ||
195 IsEqualGUID(riid, &IID_IMFMediaEventGenerator) ||
196 IsEqualIID(riid, &IID_IUnknown))
198 *obj = &stream_sink->IMFStreamSink_iface;
200 else if (IsEqualIID(riid, &IID_IMFMediaTypeHandler))
202 *obj = &stream_sink->IMFMediaTypeHandler_iface;
204 else
206 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
207 *obj = NULL;
208 return E_NOINTERFACE;
211 IUnknown_AddRef((IUnknown *)*obj);
213 return S_OK;
216 static ULONG WINAPI stream_sink_AddRef(IMFStreamSink *iface)
218 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
219 ULONG refcount = InterlockedIncrement(&stream_sink->refcount);
220 TRACE("iface %p, refcount %lu.\n", iface, refcount);
221 return refcount;
224 static ULONG WINAPI stream_sink_Release(IMFStreamSink *iface)
226 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
227 ULONG refcount = InterlockedDecrement(&stream_sink->refcount);
229 TRACE("iface %p, refcount %lu.\n", iface, refcount);
231 if (!refcount)
233 IMFMediaEventQueue_Release(stream_sink->event_queue);
234 IMFFinalizableMediaSink_Release(stream_sink->media_sink);
235 if (stream_sink->type)
236 IMFMediaType_Release(stream_sink->type);
237 free(stream_sink);
240 return refcount;
243 static HRESULT WINAPI stream_sink_GetEvent(IMFStreamSink *iface, DWORD flags, IMFMediaEvent **event)
245 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
247 TRACE("iface %p, flags %#lx, event %p.\n", iface, flags, event);
249 return IMFMediaEventQueue_GetEvent(stream_sink->event_queue, flags, event);
252 static HRESULT WINAPI stream_sink_BeginGetEvent(IMFStreamSink *iface, IMFAsyncCallback *callback,
253 IUnknown *state)
255 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
257 TRACE("iface %p, callback %p, state %p.\n", iface, callback, state);
259 return IMFMediaEventQueue_BeginGetEvent(stream_sink->event_queue, callback, state);
262 static HRESULT WINAPI stream_sink_EndGetEvent(IMFStreamSink *iface, IMFAsyncResult *result,
263 IMFMediaEvent **event)
265 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
267 TRACE("iface %p, result %p, event %p.\n", iface, result, event);
269 return IMFMediaEventQueue_EndGetEvent(stream_sink->event_queue, result, event);
272 static HRESULT WINAPI stream_sink_QueueEvent(IMFStreamSink *iface, MediaEventType event_type,
273 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
275 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
277 TRACE("iface %p, event_type %lu, ext_type %s, hr %#lx, value %p.\n",
278 iface, event_type, debugstr_guid(ext_type), hr, value);
280 return IMFMediaEventQueue_QueueEventParamVar(stream_sink->event_queue, event_type, ext_type, hr, value);
283 static HRESULT WINAPI stream_sink_GetMediaSink(IMFStreamSink *iface, IMFMediaSink **ret)
285 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
287 TRACE("iface %p, ret %p.\n", iface, ret);
289 IMFMediaSink_AddRef((*ret = (IMFMediaSink *)stream_sink->media_sink));
291 return S_OK;
294 static HRESULT WINAPI stream_sink_GetIdentifier(IMFStreamSink *iface, DWORD *identifier)
296 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
298 TRACE("iface %p, identifier %p.\n", iface, identifier);
300 *identifier = stream_sink->id;
302 return S_OK;
305 static HRESULT WINAPI stream_sink_GetMediaTypeHandler(IMFStreamSink *iface, IMFMediaTypeHandler **handler)
307 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
309 TRACE("iface %p, handler %p.\n", iface, handler);
311 IMFMediaTypeHandler_AddRef((*handler = &stream_sink->IMFMediaTypeHandler_iface));
313 return S_OK;
316 static HRESULT WINAPI stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
318 struct stream_sink *stream_sink = impl_from_IMFStreamSink(iface);
319 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(stream_sink->media_sink);
320 struct async_command *command;
321 HRESULT hr;
323 TRACE("iface %p, sample %p.\n", iface, sample);
325 EnterCriticalSection(&media_sink->cs);
327 if (media_sink->state == STATE_SHUTDOWN)
329 LeaveCriticalSection(&media_sink->cs);
330 return MF_E_SHUTDOWN;
333 if (media_sink->state != STATE_STARTED && media_sink->state != STATE_PAUSED)
335 LeaveCriticalSection(&media_sink->cs);
336 return MF_E_INVALIDREQUEST;
339 if (FAILED(hr = (async_command_create(ASYNC_PROCESS, &command))))
341 LeaveCriticalSection(&media_sink->cs);
342 return hr;
344 IMFSample_AddRef((command->u.process.sample = sample));
345 command->u.process.stream_id = stream_sink->id;
347 if (FAILED(hr = MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &media_sink->async_callback, &command->IUnknown_iface)))
348 IUnknown_Release(&command->IUnknown_iface);
350 LeaveCriticalSection(&media_sink->cs);
352 return hr;
355 static HRESULT WINAPI stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
356 const PROPVARIANT *marker_value, const PROPVARIANT *context_value)
358 FIXME("iface %p, marker_type %d, marker_value %p, context_value %p stub!\n",
359 iface, marker_type, marker_value, context_value);
361 return E_NOTIMPL;
364 static HRESULT WINAPI stream_sink_Flush(IMFStreamSink *iface)
366 FIXME("iface %p stub!\n", iface);
368 return E_NOTIMPL;
371 static const IMFStreamSinkVtbl stream_sink_vtbl =
373 stream_sink_QueryInterface,
374 stream_sink_AddRef,
375 stream_sink_Release,
376 stream_sink_GetEvent,
377 stream_sink_BeginGetEvent,
378 stream_sink_EndGetEvent,
379 stream_sink_QueueEvent,
380 stream_sink_GetMediaSink,
381 stream_sink_GetIdentifier,
382 stream_sink_GetMediaTypeHandler,
383 stream_sink_ProcessSample,
384 stream_sink_PlaceMarker,
385 stream_sink_Flush,
388 static HRESULT WINAPI stream_sink_type_handler_QueryInterface(IMFMediaTypeHandler *iface, REFIID riid, void **obj)
390 struct stream_sink *stream_sink = impl_from_IMFMediaTypeHandler(iface);
391 return IMFStreamSink_QueryInterface(&stream_sink->IMFStreamSink_iface, riid, obj);
394 static ULONG WINAPI stream_sink_type_handler_AddRef(IMFMediaTypeHandler *iface)
396 struct stream_sink *stream_sink = impl_from_IMFMediaTypeHandler(iface);
397 return IMFStreamSink_AddRef(&stream_sink->IMFStreamSink_iface);
400 static ULONG WINAPI stream_sink_type_handler_Release(IMFMediaTypeHandler *iface)
402 struct stream_sink *stream_sink = impl_from_IMFMediaTypeHandler(iface);
403 return IMFStreamSink_Release(&stream_sink->IMFStreamSink_iface);
406 static HRESULT WINAPI stream_sink_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler *iface,
407 IMFMediaType *in_type, IMFMediaType **out_type)
409 FIXME("iface %p, in_type %p, out_type %p.\n", iface, in_type, out_type);
411 return E_NOTIMPL;
414 static HRESULT WINAPI stream_sink_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count)
416 FIXME("iface %p, count %p.\n", iface, count);
418 return E_NOTIMPL;
421 static HRESULT WINAPI stream_sink_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler *iface, DWORD index,
422 IMFMediaType **type)
424 FIXME("iface %p, index %lu, type %p.\n", iface, index, type);
426 return E_NOTIMPL;
429 static HRESULT WINAPI stream_sink_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType *type)
431 FIXME("iface %p, type %p.\n", iface, type);
433 return E_NOTIMPL;
436 static HRESULT WINAPI stream_sink_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface, IMFMediaType **type)
438 struct stream_sink *stream_sink = impl_from_IMFMediaTypeHandler(iface);
440 TRACE("iface %p, type %p.\n", iface, type);
442 if (!type)
443 return E_POINTER;
444 if (!stream_sink->type)
445 return MF_E_NOT_INITIALIZED;
447 IMFMediaType_AddRef((*type = stream_sink->type));
449 return S_OK;
452 static HRESULT WINAPI stream_sink_type_handler_GetMajorType(IMFMediaTypeHandler *iface, GUID *type)
454 FIXME("iface %p, type %p.\n", iface, type);
456 return E_NOTIMPL;
459 static const IMFMediaTypeHandlerVtbl stream_sink_type_handler_vtbl =
461 stream_sink_type_handler_QueryInterface,
462 stream_sink_type_handler_AddRef,
463 stream_sink_type_handler_Release,
464 stream_sink_type_handler_IsMediaTypeSupported,
465 stream_sink_type_handler_GetMediaTypeCount,
466 stream_sink_type_handler_GetMediaTypeByIndex,
467 stream_sink_type_handler_SetCurrentMediaType,
468 stream_sink_type_handler_GetCurrentMediaType,
469 stream_sink_type_handler_GetMajorType,
472 static HRESULT stream_sink_create(DWORD stream_sink_id, IMFMediaType *media_type, struct media_sink *media_sink,
473 struct stream_sink **out)
475 struct stream_sink *stream_sink;
476 HRESULT hr;
478 TRACE("stream_sink_id %#lx, media_type %p, media_sink %p, out %p.\n",
479 stream_sink_id, media_type, media_sink, out);
481 if (!(stream_sink = calloc(1, sizeof(*stream_sink))))
482 return E_OUTOFMEMORY;
484 if (FAILED(hr = MFCreateEventQueue(&stream_sink->event_queue)))
486 free(stream_sink);
487 return hr;
490 stream_sink->IMFStreamSink_iface.lpVtbl = &stream_sink_vtbl;
491 stream_sink->IMFMediaTypeHandler_iface.lpVtbl = &stream_sink_type_handler_vtbl;
492 stream_sink->refcount = 1;
493 stream_sink->id = stream_sink_id;
494 if (media_type)
495 IMFMediaType_AddRef((stream_sink->type = media_type));
496 IMFFinalizableMediaSink_AddRef((stream_sink->media_sink = &media_sink->IMFFinalizableMediaSink_iface));
498 TRACE("Created stream sink %p.\n", stream_sink);
499 *out = stream_sink;
501 return S_OK;
504 static struct stream_sink *media_sink_get_stream_sink_by_id(struct media_sink *media_sink, DWORD id)
506 struct stream_sink *stream_sink;
508 LIST_FOR_EACH_ENTRY(stream_sink, &media_sink->stream_sinks, struct stream_sink, entry)
510 if (stream_sink->id == id)
511 return stream_sink;
514 return NULL;
517 static HRESULT media_sink_queue_command(struct media_sink *media_sink, enum async_op op)
519 struct async_command *command;
520 HRESULT hr;
522 if (media_sink->state == STATE_SHUTDOWN)
523 return MF_E_SHUTDOWN;
525 if (FAILED(hr = async_command_create(op, &command)))
526 return hr;
528 return MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_STANDARD, &media_sink->async_callback, &command->IUnknown_iface);
531 static HRESULT media_sink_queue_stream_event(struct media_sink *media_sink, MediaEventType type)
533 struct stream_sink *stream_sink;
534 HRESULT hr;
536 LIST_FOR_EACH_ENTRY(stream_sink, &media_sink->stream_sinks, struct stream_sink, entry)
538 if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream_sink->event_queue, type, &GUID_NULL, S_OK, NULL)))
539 return hr;
542 return S_OK;
545 static HRESULT media_sink_write_stream(struct media_sink *media_sink)
547 BYTE buffer[1024];
548 UINT32 size = sizeof(buffer);
549 ULONG written;
550 QWORD offset;
551 HRESULT hr;
553 while (SUCCEEDED(hr = wg_muxer_read_data(media_sink->muxer, buffer, &size, &offset)))
555 if (offset != UINT64_MAX && FAILED(hr = IMFByteStream_SetCurrentPosition(media_sink->bytestream, offset)))
556 return hr;
558 if (FAILED(hr = IMFByteStream_Write(media_sink->bytestream, buffer, size, &written)))
559 return hr;
561 size = sizeof(buffer);
564 return S_OK;
567 static HRESULT media_sink_start(struct media_sink *media_sink)
569 HRESULT hr;
571 if (FAILED(hr = wg_muxer_start(media_sink->muxer)))
572 return hr;
574 media_sink->state = STATE_STARTED;
576 return media_sink_queue_stream_event(media_sink, MEStreamSinkStarted);
579 static HRESULT media_sink_stop(struct media_sink *media_sink)
581 media_sink->state = STATE_STOPPED;
582 return media_sink_queue_stream_event(media_sink, MEStreamSinkStopped);
586 static HRESULT media_sink_pause(struct media_sink *media_sink)
588 media_sink->state = STATE_PAUSED;
589 return media_sink_queue_stream_event(media_sink, MEStreamSinkPaused);
592 static HRESULT media_sink_process(struct media_sink *media_sink, IMFSample *sample, UINT32 stream_id)
594 wg_muxer_t muxer = media_sink->muxer;
595 struct wg_sample *wg_sample;
596 LONGLONG time, duration;
597 UINT32 value;
598 HRESULT hr;
600 TRACE("media_sink %p, sample %p, stream_id %u.\n", media_sink, sample, stream_id);
602 if (FAILED(hr = media_sink_write_stream(media_sink)))
603 WARN("Failed to write output samples to stream, hr %#lx.\n", hr);
605 if (FAILED(hr = wg_sample_create_mf(sample, &wg_sample)))
606 return hr;
608 if (SUCCEEDED(IMFSample_GetSampleTime(sample, &time)))
610 wg_sample->flags |= WG_SAMPLE_FLAG_HAS_PTS;
611 wg_sample->pts = time;
613 if (SUCCEEDED(IMFSample_GetSampleDuration(sample, &duration)))
615 wg_sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION;
616 wg_sample->duration = duration;
618 if (SUCCEEDED(IMFSample_GetUINT32(sample, &MFSampleExtension_CleanPoint, &value)) && value)
619 wg_sample->flags |= WG_SAMPLE_FLAG_SYNC_POINT;
620 if (SUCCEEDED(IMFSample_GetUINT32(sample, &MFSampleExtension_Discontinuity, &value)) && value)
621 wg_sample->flags |= WG_SAMPLE_FLAG_DISCONTINUITY;
623 hr = wg_muxer_push_sample(muxer, wg_sample, stream_id);
624 wg_sample_release(wg_sample);
626 return hr;
629 static HRESULT WINAPI media_sink_QueryInterface(IMFFinalizableMediaSink *iface, REFIID riid, void **obj)
631 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
633 TRACE("iface %p, riid %s, obj %p.\n", iface, debugstr_guid(riid), obj);
635 if (IsEqualIID(riid, &IID_IMFFinalizableMediaSink) ||
636 IsEqualIID(riid, &IID_IMFMediaSink) ||
637 IsEqualIID(riid, &IID_IUnknown))
639 *obj = iface;
641 else if (IsEqualGUID(riid, &IID_IMFMediaEventGenerator))
643 *obj = &media_sink->IMFMediaEventGenerator_iface;
645 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
647 *obj = &media_sink->IMFClockStateSink_iface;
649 else
651 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
652 *obj = NULL;
653 return E_NOINTERFACE;
656 IUnknown_AddRef((IUnknown *)*obj);
658 return S_OK;
661 static ULONG WINAPI media_sink_AddRef(IMFFinalizableMediaSink *iface)
663 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
664 ULONG refcount = InterlockedIncrement(&media_sink->refcount);
665 TRACE("iface %p, refcount %lu.\n", iface, refcount);
666 return refcount;
669 static ULONG WINAPI media_sink_Release(IMFFinalizableMediaSink *iface)
671 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
672 ULONG refcount = InterlockedDecrement(&media_sink->refcount);
674 TRACE("iface %p, refcount %lu.\n", iface, refcount);
676 if (!refcount)
678 IMFFinalizableMediaSink_Shutdown(iface);
679 IMFMediaEventQueue_Release(media_sink->event_queue);
680 IMFByteStream_Release(media_sink->bytestream);
681 media_sink->cs.DebugInfo->Spare[0] = 0;
682 DeleteCriticalSection(&media_sink->cs);
683 wg_muxer_destroy(media_sink->muxer);
684 free(media_sink);
687 return refcount;
690 static HRESULT WINAPI media_sink_GetCharacteristics(IMFFinalizableMediaSink *iface, DWORD *flags)
692 FIXME("iface %p, flags %p stub!\n", iface, flags);
694 return E_NOTIMPL;
697 static HRESULT WINAPI media_sink_AddStreamSink(IMFFinalizableMediaSink *iface, DWORD stream_sink_id,
698 IMFMediaType *media_type, IMFStreamSink **stream_sink)
700 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
701 struct stream_sink *object;
702 struct wg_format format;
703 HRESULT hr;
705 TRACE("iface %p, stream_sink_id %#lx, media_type %p, stream_sink %p.\n",
706 iface, stream_sink_id, media_type, stream_sink);
708 EnterCriticalSection(&media_sink->cs);
710 if (media_sink_get_stream_sink_by_id(media_sink, stream_sink_id))
712 LeaveCriticalSection(&media_sink->cs);
713 return MF_E_STREAMSINK_EXISTS;
716 if (FAILED(hr = stream_sink_create(stream_sink_id, media_type, media_sink, &object)))
718 WARN("Failed to create stream sink, hr %#lx.\n", hr);
719 LeaveCriticalSection(&media_sink->cs);
720 return hr;
723 mf_media_type_to_wg_format(media_type, &format);
724 if (FAILED(hr = wg_muxer_add_stream(media_sink->muxer, stream_sink_id, &format)))
726 LeaveCriticalSection(&media_sink->cs);
727 IMFStreamSink_Release(&object->IMFStreamSink_iface);
728 return hr;
731 list_add_tail(&media_sink->stream_sinks, &object->entry);
733 LeaveCriticalSection(&media_sink->cs);
735 if (stream_sink)
736 IMFStreamSink_AddRef((*stream_sink = &object->IMFStreamSink_iface));
738 return S_OK;
741 static HRESULT WINAPI media_sink_RemoveStreamSink(IMFFinalizableMediaSink *iface, DWORD stream_sink_id)
743 FIXME("iface %p, stream_sink_id %#lx stub!\n", iface, stream_sink_id);
745 return E_NOTIMPL;
748 static HRESULT WINAPI media_sink_GetStreamSinkCount(IMFFinalizableMediaSink *iface, DWORD *count)
750 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
752 TRACE("iface %p, count %p.\n", iface, count);
754 if (!count)
755 return E_POINTER;
757 EnterCriticalSection(&media_sink->cs);
758 *count = list_count(&media_sink->stream_sinks);
759 LeaveCriticalSection(&media_sink->cs);
761 return S_OK;
764 static HRESULT WINAPI media_sink_GetStreamSinkByIndex(IMFFinalizableMediaSink *iface, DWORD index,
765 IMFStreamSink **stream)
767 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
768 struct stream_sink *stream_sink;
769 HRESULT hr = MF_E_INVALIDINDEX;
770 DWORD entry_index = 0;
772 TRACE("iface %p, index %lu, stream %p stub!\n", iface, index, stream);
774 if (!stream)
775 return E_POINTER;
777 EnterCriticalSection(&media_sink->cs);
779 LIST_FOR_EACH_ENTRY(stream_sink, &media_sink->stream_sinks, struct stream_sink, entry)
781 if (entry_index++ == index)
783 IMFStreamSink_AddRef((*stream = &stream_sink->IMFStreamSink_iface));
784 hr = S_OK;
785 break;
789 LeaveCriticalSection(&media_sink->cs);
791 return hr;
794 static HRESULT WINAPI media_sink_GetStreamSinkById(IMFFinalizableMediaSink *iface, DWORD stream_sink_id,
795 IMFStreamSink **stream)
797 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
798 struct stream_sink *stream_sink;
799 HRESULT hr;
801 TRACE("iface %p, stream_sink_id %#lx, stream %p.\n", iface, stream_sink_id, stream);
803 if (!stream)
804 return E_POINTER;
806 EnterCriticalSection(&media_sink->cs);
808 hr = MF_E_INVALIDSTREAMNUMBER;
809 if ((stream_sink = media_sink_get_stream_sink_by_id(media_sink, stream_sink_id)))
811 IMFStreamSink_AddRef((*stream = &stream_sink->IMFStreamSink_iface));
812 hr = S_OK;
815 LeaveCriticalSection(&media_sink->cs);
817 return hr;
820 static HRESULT WINAPI media_sink_SetPresentationClock(IMFFinalizableMediaSink *iface, IMFPresentationClock *clock)
822 FIXME("iface %p, clock %p stub!\n", iface, clock);
824 return E_NOTIMPL;
827 static HRESULT WINAPI media_sink_GetPresentationClock(IMFFinalizableMediaSink *iface, IMFPresentationClock **clock)
829 FIXME("iface %p, clock %p stub!\n", iface, clock);
831 return E_NOTIMPL;
834 static HRESULT WINAPI media_sink_Shutdown(IMFFinalizableMediaSink *iface)
836 struct media_sink *media_sink = impl_from_IMFFinalizableMediaSink(iface);
837 struct stream_sink *stream_sink, *next;
839 TRACE("iface %p.\n", iface);
841 EnterCriticalSection(&media_sink->cs);
843 if (media_sink->state == STATE_SHUTDOWN)
845 LeaveCriticalSection(&media_sink->cs);
846 return MF_E_SHUTDOWN;
849 LIST_FOR_EACH_ENTRY_SAFE(stream_sink, next, &media_sink->stream_sinks, struct stream_sink, entry)
851 list_remove(&stream_sink->entry);
852 IMFMediaEventQueue_Shutdown(stream_sink->event_queue);
853 IMFStreamSink_Release(&stream_sink->IMFStreamSink_iface);
856 IMFMediaEventQueue_Shutdown(media_sink->event_queue);
857 IMFByteStream_Close(media_sink->bytestream);
859 media_sink->state = STATE_SHUTDOWN;
861 LeaveCriticalSection(&media_sink->cs);
863 return S_OK;
866 static HRESULT WINAPI media_sink_BeginFinalize(IMFFinalizableMediaSink *iface, IMFAsyncCallback *callback, IUnknown *state)
868 FIXME("iface %p, callback %p, state %p stub!\n", iface, callback, state);
870 return E_NOTIMPL;
873 static HRESULT WINAPI media_sink_EndFinalize(IMFFinalizableMediaSink *iface, IMFAsyncResult *result)
875 FIXME("iface %p, result %p stub!\n", iface, result);
877 return E_NOTIMPL;
880 static const IMFFinalizableMediaSinkVtbl media_sink_vtbl =
882 media_sink_QueryInterface,
883 media_sink_AddRef,
884 media_sink_Release,
885 media_sink_GetCharacteristics,
886 media_sink_AddStreamSink,
887 media_sink_RemoveStreamSink,
888 media_sink_GetStreamSinkCount,
889 media_sink_GetStreamSinkByIndex,
890 media_sink_GetStreamSinkById,
891 media_sink_SetPresentationClock,
892 media_sink_GetPresentationClock,
893 media_sink_Shutdown,
894 media_sink_BeginFinalize,
895 media_sink_EndFinalize,
898 static HRESULT WINAPI media_sink_event_QueryInterface(IMFMediaEventGenerator *iface, REFIID riid, void **obj)
900 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
901 return IMFFinalizableMediaSink_QueryInterface(&media_sink->IMFFinalizableMediaSink_iface, riid, obj);
904 static ULONG WINAPI media_sink_event_AddRef(IMFMediaEventGenerator *iface)
906 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
907 return IMFFinalizableMediaSink_AddRef(&media_sink->IMFFinalizableMediaSink_iface);
910 static ULONG WINAPI media_sink_event_Release(IMFMediaEventGenerator *iface)
912 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
913 return IMFFinalizableMediaSink_Release(&media_sink->IMFFinalizableMediaSink_iface);
916 static HRESULT WINAPI media_sink_event_GetEvent(IMFMediaEventGenerator *iface, DWORD flags, IMFMediaEvent **event)
918 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
920 TRACE("iface %p, flags %#lx, event %p.\n", iface, flags, event);
922 return IMFMediaEventQueue_GetEvent(media_sink->event_queue, flags, event);
925 static HRESULT WINAPI media_sink_event_BeginGetEvent(IMFMediaEventGenerator *iface, IMFAsyncCallback *callback,
926 IUnknown *state)
928 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
930 TRACE("iface %p, callback %p, state %p.\n", iface, callback, state);
932 return IMFMediaEventQueue_BeginGetEvent(media_sink->event_queue, callback, state);
935 static HRESULT WINAPI media_sink_event_EndGetEvent(IMFMediaEventGenerator *iface, IMFAsyncResult *result,
936 IMFMediaEvent **event)
938 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
940 TRACE("iface %p, result %p, event %p.\n", iface, result, event);
942 return IMFMediaEventQueue_EndGetEvent(media_sink->event_queue, result, event);
945 static HRESULT WINAPI media_sink_event_QueueEvent(IMFMediaEventGenerator *iface, MediaEventType event_type,
946 REFGUID ext_type, HRESULT hr, const PROPVARIANT *value)
948 struct media_sink *media_sink = impl_from_IMFMediaEventGenerator(iface);
950 TRACE("iface %p, event_type %lu, ext_type %s, hr %#lx, value %p.\n",
951 iface, event_type, debugstr_guid(ext_type), hr, value);
953 return IMFMediaEventQueue_QueueEventParamVar(media_sink->event_queue, event_type, ext_type, hr, value);
956 static const IMFMediaEventGeneratorVtbl media_sink_event_vtbl =
958 media_sink_event_QueryInterface,
959 media_sink_event_AddRef,
960 media_sink_event_Release,
961 media_sink_event_GetEvent,
962 media_sink_event_BeginGetEvent,
963 media_sink_event_EndGetEvent,
964 media_sink_event_QueueEvent,
967 static HRESULT WINAPI media_sink_clock_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj)
969 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
970 return IMFFinalizableMediaSink_QueryInterface(&media_sink->IMFFinalizableMediaSink_iface, riid, obj);
973 static ULONG WINAPI media_sink_clock_sink_AddRef(IMFClockStateSink *iface)
975 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
976 return IMFFinalizableMediaSink_AddRef(&media_sink->IMFFinalizableMediaSink_iface);
979 static ULONG WINAPI media_sink_clock_sink_Release(IMFClockStateSink *iface)
981 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
982 return IMFFinalizableMediaSink_Release(&media_sink->IMFFinalizableMediaSink_iface);
985 static HRESULT WINAPI media_sink_clock_sink_OnClockStart(IMFClockStateSink *iface, MFTIME systime, LONGLONG offset)
987 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
988 HRESULT hr;
990 TRACE("iface %p, systime %s, offset %s.\n", iface, debugstr_time(systime), debugstr_time(offset));
992 EnterCriticalSection(&media_sink->cs);
994 hr = media_sink_queue_command(media_sink, ASYNC_START);
996 LeaveCriticalSection(&media_sink->cs);
997 return hr;
1000 static HRESULT WINAPI media_sink_clock_sink_OnClockStop(IMFClockStateSink *iface, MFTIME systime)
1002 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
1003 HRESULT hr;
1005 TRACE("iface %p, systime %s.\n", iface, debugstr_time(systime));
1007 EnterCriticalSection(&media_sink->cs);
1009 hr = media_sink_queue_command(media_sink, ASYNC_STOP);
1011 LeaveCriticalSection(&media_sink->cs);
1012 return hr;
1015 static HRESULT WINAPI media_sink_clock_sink_OnClockPause(IMFClockStateSink *iface, MFTIME systime)
1017 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
1018 HRESULT hr;
1020 TRACE("iface %p, systime %s.\n", iface, debugstr_time(systime));
1022 EnterCriticalSection(&media_sink->cs);
1024 hr = media_sink_queue_command(media_sink, ASYNC_PAUSE);
1026 LeaveCriticalSection(&media_sink->cs);
1027 return hr;
1030 static HRESULT WINAPI media_sink_clock_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME systime)
1032 struct media_sink *media_sink = impl_from_IMFClockStateSink(iface);
1033 HRESULT hr;
1035 TRACE("iface %p, systime %s.\n", iface, debugstr_time(systime));
1037 EnterCriticalSection(&media_sink->cs);
1039 hr = media_sink_queue_command(media_sink, ASYNC_START);
1041 LeaveCriticalSection(&media_sink->cs);
1042 return hr;
1045 static HRESULT WINAPI media_sink_clock_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME systime, float rate)
1047 FIXME("iface %p, systime %s, rate %f stub!\n", iface, debugstr_time(systime), rate);
1049 return E_NOTIMPL;
1052 static const IMFClockStateSinkVtbl media_sink_clock_sink_vtbl =
1054 media_sink_clock_sink_QueryInterface,
1055 media_sink_clock_sink_AddRef,
1056 media_sink_clock_sink_Release,
1057 media_sink_clock_sink_OnClockStart,
1058 media_sink_clock_sink_OnClockStop,
1059 media_sink_clock_sink_OnClockPause,
1060 media_sink_clock_sink_OnClockRestart,
1061 media_sink_clock_sink_OnClockSetRate,
1064 static HRESULT WINAPI media_sink_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
1066 TRACE("iface %p, riid %s, obj %p.\n", iface, debugstr_guid(riid), obj);
1068 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1069 IsEqualIID(riid, &IID_IUnknown))
1071 *obj = iface;
1072 IMFAsyncCallback_AddRef(iface);
1073 return S_OK;
1076 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1077 *obj = NULL;
1078 return E_NOINTERFACE;
1081 static ULONG WINAPI media_sink_callback_AddRef(IMFAsyncCallback *iface)
1083 struct media_sink *sink = impl_from_async_callback(iface);
1084 return IMFFinalizableMediaSink_AddRef(&sink->IMFFinalizableMediaSink_iface);
1087 static ULONG WINAPI media_sink_callback_Release(IMFAsyncCallback *iface)
1089 struct media_sink *sink = impl_from_async_callback(iface);
1090 return IMFFinalizableMediaSink_Release(&sink->IMFFinalizableMediaSink_iface);
1093 static HRESULT WINAPI media_sink_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
1095 TRACE("iface %p, flags %p, queue %p.\n", iface, flags, queue);
1097 return E_NOTIMPL;
1100 static HRESULT WINAPI media_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *async_result)
1102 struct media_sink *media_sink = impl_from_async_callback(iface);
1103 struct async_command *command;
1104 HRESULT hr = E_FAIL;
1105 IUnknown *state;
1107 TRACE("iface %p, async_result %p.\n", iface, async_result);
1109 EnterCriticalSection(&media_sink->cs);
1111 if (!(state = IMFAsyncResult_GetStateNoAddRef(async_result)))
1113 LeaveCriticalSection(&media_sink->cs);
1114 return hr;
1117 command = impl_from_async_command_IUnknown(state);
1118 switch (command->op)
1120 case ASYNC_START:
1121 if (FAILED(hr = media_sink_start(media_sink)))
1122 WARN("Failed to start media sink.\n");
1123 break;
1124 case ASYNC_STOP:
1125 hr = media_sink_stop(media_sink);
1126 break;
1127 case ASYNC_PAUSE:
1128 hr = media_sink_pause(media_sink);
1129 break;
1130 case ASYNC_PROCESS:
1131 if (FAILED(hr = media_sink_process(media_sink, command->u.process.sample, command->u.process.stream_id)))
1132 WARN("Failed to process sample, hr %#lx.\n", hr);
1133 break;
1134 default:
1135 WARN("Unsupported op %u.\n", command->op);
1136 break;
1139 LeaveCriticalSection(&media_sink->cs);
1141 return hr;
1144 static const IMFAsyncCallbackVtbl media_sink_callback_vtbl =
1146 media_sink_callback_QueryInterface,
1147 media_sink_callback_AddRef,
1148 media_sink_callback_Release,
1149 media_sink_callback_GetParameters,
1150 media_sink_callback_Invoke,
1153 static HRESULT media_sink_create(IMFByteStream *bytestream, const char *format, struct media_sink **out)
1155 struct media_sink *media_sink;
1156 HRESULT hr;
1158 TRACE("bytestream %p, out %p.\n", bytestream, out);
1160 if (!bytestream)
1161 return E_POINTER;
1163 if (!(media_sink = calloc(1, sizeof(*media_sink))))
1164 return E_OUTOFMEMORY;
1166 if (FAILED(hr = wg_muxer_create(format, &media_sink->muxer)))
1167 goto fail;
1168 if (FAILED(hr = MFCreateEventQueue(&media_sink->event_queue)))
1169 goto fail;
1171 media_sink->IMFFinalizableMediaSink_iface.lpVtbl = &media_sink_vtbl;
1172 media_sink->IMFMediaEventGenerator_iface.lpVtbl = &media_sink_event_vtbl;
1173 media_sink->IMFClockStateSink_iface.lpVtbl = &media_sink_clock_sink_vtbl;
1174 media_sink->async_callback.lpVtbl = &media_sink_callback_vtbl;
1175 media_sink->refcount = 1;
1176 media_sink->state = STATE_OPENED;
1177 InitializeCriticalSection(&media_sink->cs);
1178 media_sink->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
1179 IMFByteStream_AddRef((media_sink->bytestream = bytestream));
1180 list_init(&media_sink->stream_sinks);
1182 *out = media_sink;
1183 TRACE("Created media sink %p.\n", media_sink);
1185 return S_OK;
1187 fail:
1188 if (media_sink->muxer)
1189 wg_muxer_destroy(media_sink->muxer);
1190 free(media_sink);
1191 return hr;
1194 static HRESULT WINAPI sink_class_factory_QueryInterface(IMFSinkClassFactory *iface, REFIID riid, void **out)
1196 if (IsEqualIID(riid, &IID_IMFSinkClassFactory)
1197 || IsEqualIID(riid, &IID_IUnknown))
1199 *out = iface;
1200 IMFSinkClassFactory_AddRef(iface);
1201 return S_OK;
1204 *out = NULL;
1205 return E_NOINTERFACE;
1208 static ULONG WINAPI sink_class_factory_AddRef(IMFSinkClassFactory *iface)
1210 return 2;
1213 static ULONG WINAPI sink_class_factory_Release(IMFSinkClassFactory *iface)
1215 return 1;
1218 static HRESULT WINAPI sink_class_factory_create_media_sink(IMFSinkClassFactory *iface, IMFByteStream *bytestream,
1219 const char *format, IMFMediaType *video_type, IMFMediaType *audio_type, IMFMediaSink **out)
1221 IMFFinalizableMediaSink *media_sink_iface;
1222 struct media_sink *media_sink;
1223 HRESULT hr;
1225 TRACE("iface %p, bytestream %p, video_type %p, audio_type %p, out %p.\n",
1226 iface, bytestream, video_type, audio_type, out);
1228 if (FAILED(hr = media_sink_create(bytestream, format, &media_sink)))
1229 return hr;
1230 media_sink_iface = &media_sink->IMFFinalizableMediaSink_iface;
1232 if (video_type)
1234 if (FAILED(hr = IMFFinalizableMediaSink_AddStreamSink(media_sink_iface, 1, video_type, NULL)))
1236 IMFFinalizableMediaSink_Shutdown(media_sink_iface);
1237 IMFFinalizableMediaSink_Release(media_sink_iface);
1238 return hr;
1241 if (audio_type)
1243 if (FAILED(hr = IMFFinalizableMediaSink_AddStreamSink(media_sink_iface, 2, audio_type, NULL)))
1245 IMFFinalizableMediaSink_Shutdown(media_sink_iface);
1246 IMFFinalizableMediaSink_Release(media_sink_iface);
1247 return hr;
1251 *out = (IMFMediaSink *)media_sink_iface;
1252 return S_OK;
1255 static HRESULT WINAPI mp3_sink_class_factory_CreateMediaSink(IMFSinkClassFactory *iface, IMFByteStream *bytestream,
1256 IMFMediaType *video_type, IMFMediaType *audio_type, IMFMediaSink **out)
1258 const char *format = "application/x-id3";
1260 return sink_class_factory_create_media_sink(iface, bytestream, format, video_type, audio_type, out);
1263 static HRESULT WINAPI mpeg4_sink_class_factory_CreateMediaSink(IMFSinkClassFactory *iface, IMFByteStream *bytestream,
1264 IMFMediaType *video_type, IMFMediaType *audio_type, IMFMediaSink **out)
1266 const char *format = "video/quicktime, variant=iso";
1268 return sink_class_factory_create_media_sink(iface, bytestream, format, video_type, audio_type, out);
1271 static const IMFSinkClassFactoryVtbl mp3_sink_class_factory_vtbl =
1273 sink_class_factory_QueryInterface,
1274 sink_class_factory_AddRef,
1275 sink_class_factory_Release,
1276 mp3_sink_class_factory_CreateMediaSink,
1279 static const IMFSinkClassFactoryVtbl mpeg4_sink_class_factory_vtbl =
1281 sink_class_factory_QueryInterface,
1282 sink_class_factory_AddRef,
1283 sink_class_factory_Release,
1284 mpeg4_sink_class_factory_CreateMediaSink,
1287 static IMFSinkClassFactory mp3_sink_class_factory = { &mp3_sink_class_factory_vtbl };
1288 static IMFSinkClassFactory mpeg4_sink_class_factory = { &mpeg4_sink_class_factory_vtbl };
1290 HRESULT mp3_sink_class_factory_create(IUnknown *outer, IUnknown **out)
1292 *out = (IUnknown *)&mp3_sink_class_factory;
1293 return S_OK;
1296 HRESULT mpeg4_sink_class_factory_create(IUnknown *outer, IUnknown **out)
1298 *out = (IUnknown *)&mpeg4_sink_class_factory;
1299 return S_OK;