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
);
39 IUnknown IUnknown_iface
;
56 IMFStreamSink IMFStreamSink_iface
;
57 IMFMediaTypeHandler IMFMediaTypeHandler_iface
;
62 IMFFinalizableMediaSink
*media_sink
;
63 IMFMediaEventQueue
*event_queue
;
70 IMFFinalizableMediaSink IMFFinalizableMediaSink_iface
;
71 IMFMediaEventGenerator IMFMediaEventGenerator_iface
;
72 IMFClockStateSink IMFClockStateSink_iface
;
73 IMFAsyncCallback async_callback
;
86 IMFByteStream
*bytestream
;
87 IMFMediaEventQueue
*event_queue
;
89 struct list stream_sinks
;
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
))
134 IUnknown_AddRef(iface
);
138 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
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
);
156 if (command
->op
== ASYNC_PROCESS
&& command
->u
.process
.sample
)
157 IMFSample_Release(command
->u
.process
.sample
);
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;
182 TRACE("Created async command %p.\n", command
);
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
;
206 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
208 return E_NOINTERFACE
;
211 IUnknown_AddRef((IUnknown
*)*obj
);
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
);
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
);
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
);
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
,
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
));
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
;
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
));
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
;
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
);
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
);
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
);
364 static HRESULT WINAPI
stream_sink_Flush(IMFStreamSink
*iface
)
366 FIXME("iface %p stub!\n", iface
);
371 static const IMFStreamSinkVtbl stream_sink_vtbl
=
373 stream_sink_QueryInterface
,
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
,
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
);
414 static HRESULT WINAPI
stream_sink_type_handler_GetMediaTypeCount(IMFMediaTypeHandler
*iface
, DWORD
*count
)
416 FIXME("iface %p, count %p.\n", iface
, count
);
421 static HRESULT WINAPI
stream_sink_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
*iface
, DWORD index
,
424 FIXME("iface %p, index %lu, type %p.\n", iface
, index
, type
);
429 static HRESULT WINAPI
stream_sink_type_handler_SetCurrentMediaType(IMFMediaTypeHandler
*iface
, IMFMediaType
*type
)
431 FIXME("iface %p, type %p.\n", iface
, type
);
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
);
444 if (!stream_sink
->type
)
445 return MF_E_NOT_INITIALIZED
;
447 IMFMediaType_AddRef((*type
= stream_sink
->type
));
452 static HRESULT WINAPI
stream_sink_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
454 FIXME("iface %p, type %p.\n", iface
, type
);
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
;
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
)))
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
;
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
);
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
)
517 static HRESULT
media_sink_queue_command(struct media_sink
*media_sink
, enum async_op op
)
519 struct async_command
*command
;
522 if (media_sink
->state
== STATE_SHUTDOWN
)
523 return MF_E_SHUTDOWN
;
525 if (FAILED(hr
= async_command_create(op
, &command
)))
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
;
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
)))
545 static HRESULT
media_sink_write_stream(struct media_sink
*media_sink
)
548 UINT32 size
= sizeof(buffer
);
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
)))
558 if (FAILED(hr
= IMFByteStream_Write(media_sink
->bytestream
, buffer
, size
, &written
)))
561 size
= sizeof(buffer
);
567 static HRESULT
media_sink_start(struct media_sink
*media_sink
)
571 if (FAILED(hr
= wg_muxer_start(media_sink
->muxer
)))
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
;
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
)))
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
);
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
))
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
;
651 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
653 return E_NOINTERFACE
;
656 IUnknown_AddRef((IUnknown
*)*obj
);
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
);
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
);
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
);
690 static HRESULT WINAPI
media_sink_GetCharacteristics(IMFFinalizableMediaSink
*iface
, DWORD
*flags
)
692 FIXME("iface %p, flags %p stub!\n", iface
, flags
);
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
;
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
);
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
);
731 list_add_tail(&media_sink
->stream_sinks
, &object
->entry
);
733 LeaveCriticalSection(&media_sink
->cs
);
736 IMFStreamSink_AddRef((*stream_sink
= &object
->IMFStreamSink_iface
));
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
);
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
);
757 EnterCriticalSection(&media_sink
->cs
);
758 *count
= list_count(&media_sink
->stream_sinks
);
759 LeaveCriticalSection(&media_sink
->cs
);
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
);
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
));
789 LeaveCriticalSection(&media_sink
->cs
);
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
;
801 TRACE("iface %p, stream_sink_id %#lx, stream %p.\n", iface
, stream_sink_id
, stream
);
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
));
815 LeaveCriticalSection(&media_sink
->cs
);
820 static HRESULT WINAPI
media_sink_SetPresentationClock(IMFFinalizableMediaSink
*iface
, IMFPresentationClock
*clock
)
822 FIXME("iface %p, clock %p stub!\n", iface
, clock
);
827 static HRESULT WINAPI
media_sink_GetPresentationClock(IMFFinalizableMediaSink
*iface
, IMFPresentationClock
**clock
)
829 FIXME("iface %p, clock %p stub!\n", iface
, clock
);
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
);
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
);
873 static HRESULT WINAPI
media_sink_EndFinalize(IMFFinalizableMediaSink
*iface
, IMFAsyncResult
*result
)
875 FIXME("iface %p, result %p stub!\n", iface
, result
);
880 static const IMFFinalizableMediaSinkVtbl media_sink_vtbl
=
882 media_sink_QueryInterface
,
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
,
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
,
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
);
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
);
1000 static HRESULT WINAPI
media_sink_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
1002 struct media_sink
*media_sink
= impl_from_IMFClockStateSink(iface
);
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
);
1015 static HRESULT WINAPI
media_sink_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
1017 struct media_sink
*media_sink
= impl_from_IMFClockStateSink(iface
);
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
);
1030 static HRESULT WINAPI
media_sink_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
1032 struct media_sink
*media_sink
= impl_from_IMFClockStateSink(iface
);
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
);
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
);
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
))
1072 IMFAsyncCallback_AddRef(iface
);
1076 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
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
);
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
;
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
);
1117 command
= impl_from_async_command_IUnknown(state
);
1118 switch (command
->op
)
1121 if (FAILED(hr
= media_sink_start(media_sink
)))
1122 WARN("Failed to start media sink.\n");
1125 hr
= media_sink_stop(media_sink
);
1128 hr
= media_sink_pause(media_sink
);
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
);
1135 WARN("Unsupported op %u.\n", command
->op
);
1139 LeaveCriticalSection(&media_sink
->cs
);
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
;
1158 TRACE("bytestream %p, out %p.\n", bytestream
, out
);
1163 if (!(media_sink
= calloc(1, sizeof(*media_sink
))))
1164 return E_OUTOFMEMORY
;
1166 if (FAILED(hr
= wg_muxer_create(format
, &media_sink
->muxer
)))
1168 if (FAILED(hr
= MFCreateEventQueue(&media_sink
->event_queue
)))
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
);
1183 TRACE("Created media sink %p.\n", media_sink
);
1188 if (media_sink
->muxer
)
1189 wg_muxer_destroy(media_sink
->muxer
);
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
))
1200 IMFSinkClassFactory_AddRef(iface
);
1205 return E_NOINTERFACE
;
1208 static ULONG WINAPI
sink_class_factory_AddRef(IMFSinkClassFactory
*iface
)
1213 static ULONG WINAPI
sink_class_factory_Release(IMFSinkClassFactory
*iface
)
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
;
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
)))
1230 media_sink_iface
= &media_sink
->IMFFinalizableMediaSink_iface
;
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
);
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
);
1251 *out
= (IMFMediaSink
*)media_sink_iface
;
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
;
1296 HRESULT
mpeg4_sink_class_factory_create(IUnknown
*outer
, IUnknown
**out
)
1298 *out
= (IUnknown
*)&mpeg4_sink_class_factory
;