2 * Copyright 2022 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "mfsrcsnk_private.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
31 static inline const char *debugstr_time(LONGLONG time
)
33 ULONGLONG abstime
= time
>= 0 ? time
: -time
;
34 unsigned int i
= 0, j
= 0;
35 char buffer
[23], rev
[23];
37 while (abstime
|| i
<= 8)
39 buffer
[i
++] = '0' + (abstime
% 10);
41 if (i
== 7) buffer
[i
++] = '.';
43 if (time
< 0) buffer
[i
++] = '-';
45 while (i
--) rev
[j
++] = buffer
[i
];
46 while (rev
[j
-1] == '0' && rev
[j
-2] != '.') --j
;
49 return wine_dbg_sprintf("%s", rev
);
55 SINK_HEADER_WRITTEN
= 0x2,
56 SINK_DATA_CHUNK_STARTED
= 0x4,
57 SINK_DATA_FINALIZED
= 0x8,
62 IMFFinalizableMediaSink IMFFinalizableMediaSink_iface
;
63 IMFMediaEventGenerator IMFMediaEventGenerator_iface
;
64 IMFClockStateSink IMFClockStateSink_iface
;
65 IMFMediaTypeHandler IMFMediaTypeHandler_iface
;
66 IMFStreamSink IMFStreamSink_iface
;
69 IMFMediaEventQueue
*event_queue
;
70 IMFMediaEventQueue
*stream_event_queue
;
71 IMFPresentationClock
*clock
;
74 IMFByteStream
*bytestream
;
75 QWORD data_size_offset
;
76 QWORD riff_size_offset
;
84 static struct wave_sink
*impl_from_IMFFinalizableMediaSink(IMFFinalizableMediaSink
*iface
)
86 return CONTAINING_RECORD(iface
, struct wave_sink
, IMFFinalizableMediaSink_iface
);
89 static struct wave_sink
*impl_from_IMFMediaEventGenerator(IMFMediaEventGenerator
*iface
)
91 return CONTAINING_RECORD(iface
, struct wave_sink
, IMFMediaEventGenerator_iface
);
94 static struct wave_sink
*impl_from_IMFStreamSink(IMFStreamSink
*iface
)
96 return CONTAINING_RECORD(iface
, struct wave_sink
, IMFStreamSink_iface
);
99 static struct wave_sink
*impl_from_IMFClockStateSink(IMFClockStateSink
*iface
)
101 return CONTAINING_RECORD(iface
, struct wave_sink
, IMFClockStateSink_iface
);
104 static struct wave_sink
*impl_from_IMFMediaTypeHandler(IMFMediaTypeHandler
*iface
)
106 return CONTAINING_RECORD(iface
, struct wave_sink
, IMFMediaTypeHandler_iface
);
109 static HRESULT WINAPI
wave_sink_QueryInterface(IMFFinalizableMediaSink
*iface
, REFIID riid
, void **obj
)
111 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
113 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
115 if (IsEqualIID(riid
, &IID_IMFFinalizableMediaSink
) ||
116 IsEqualIID(riid
, &IID_IMFMediaSink
) ||
117 IsEqualIID(riid
, &IID_IUnknown
))
121 else if (IsEqualIID(riid
, &IID_IMFMediaEventGenerator
))
123 *obj
= &sink
->IMFMediaEventGenerator_iface
;
125 else if (IsEqualIID(riid
, &IID_IMFClockStateSink
))
127 *obj
= &sink
->IMFClockStateSink_iface
;
131 WARN("Unsupported %s.\n", debugstr_guid(riid
));
133 return E_NOINTERFACE
;
136 IUnknown_AddRef((IUnknown
*)*obj
);
141 static ULONG WINAPI
wave_sink_AddRef(IMFFinalizableMediaSink
*iface
)
143 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
144 ULONG refcount
= InterlockedIncrement(&sink
->refcount
);
145 TRACE("%p, refcount %lu.\n", iface
, refcount
);
149 static ULONG WINAPI
wave_sink_Release(IMFFinalizableMediaSink
*iface
)
151 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
152 ULONG refcount
= InterlockedDecrement(&sink
->refcount
);
154 TRACE("%p, refcount %lu.\n", iface
, refcount
);
158 if (sink
->event_queue
)
159 IMFMediaEventQueue_Release(sink
->event_queue
);
160 if (sink
->stream_event_queue
)
161 IMFMediaEventQueue_Release(sink
->stream_event_queue
);
162 IMFByteStream_Release(sink
->bytestream
);
163 CoTaskMemFree(sink
->fmt
);
164 DeleteCriticalSection(&sink
->cs
);
171 static HRESULT WINAPI
wave_sink_GetCharacteristics(IMFFinalizableMediaSink
*iface
, DWORD
*flags
)
173 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
175 TRACE("%p, %p.\n", iface
, flags
);
177 if (sink
->flags
& SINK_SHUT_DOWN
)
178 return MF_E_SHUTDOWN
;
180 *flags
= MEDIASINK_FIXED_STREAMS
| MEDIASINK_RATELESS
;
185 static HRESULT WINAPI
wave_sink_AddStreamSink(IMFFinalizableMediaSink
*iface
, DWORD stream_sink_id
,
186 IMFMediaType
*media_type
, IMFStreamSink
**stream_sink
)
188 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
190 TRACE("%p, %#lx, %p, %p.\n", iface
, stream_sink_id
, media_type
, stream_sink
);
192 return sink
->flags
& SINK_SHUT_DOWN
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
195 static HRESULT WINAPI
wave_sink_RemoveStreamSink(IMFFinalizableMediaSink
*iface
, DWORD stream_sink_id
)
197 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
199 TRACE("%p, %#lx.\n", iface
, stream_sink_id
);
201 return sink
->flags
& SINK_SHUT_DOWN
? MF_E_SHUTDOWN
: MF_E_STREAMSINKS_FIXED
;
204 static HRESULT WINAPI
wave_sink_GetStreamSinkCount(IMFFinalizableMediaSink
*iface
, DWORD
*count
)
206 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
208 TRACE("%p, %p.\n", iface
, count
);
213 if (sink
->flags
& SINK_SHUT_DOWN
)
214 return MF_E_SHUTDOWN
;
221 static HRESULT WINAPI
wave_sink_GetStreamSinkByIndex(IMFFinalizableMediaSink
*iface
, DWORD index
,
222 IMFStreamSink
**stream
)
224 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
227 TRACE("%p, %lu, %p.\n", iface
, index
, stream
);
229 EnterCriticalSection(&sink
->cs
);
231 if (sink
->flags
& SINK_SHUT_DOWN
)
234 hr
= MF_E_INVALIDINDEX
;
237 *stream
= &sink
->IMFStreamSink_iface
;
238 IMFStreamSink_AddRef(*stream
);
241 LeaveCriticalSection(&sink
->cs
);
246 static HRESULT WINAPI
wave_sink_GetStreamSinkById(IMFFinalizableMediaSink
*iface
, DWORD stream_sink_id
,
247 IMFStreamSink
**stream
)
249 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
252 TRACE("%p, %#lx, %p.\n", iface
, stream_sink_id
, stream
);
254 EnterCriticalSection(&sink
->cs
);
256 if (sink
->flags
& SINK_SHUT_DOWN
)
258 else if (stream_sink_id
!= 1)
259 hr
= MF_E_INVALIDSTREAMNUMBER
;
262 *stream
= &sink
->IMFStreamSink_iface
;
263 IMFStreamSink_AddRef(*stream
);
266 LeaveCriticalSection(&sink
->cs
);
271 static void wave_sink_set_presentation_clock(struct wave_sink
*sink
, IMFPresentationClock
*clock
)
275 IMFPresentationClock_RemoveClockStateSink(sink
->clock
, &sink
->IMFClockStateSink_iface
);
276 IMFPresentationClock_Release(sink
->clock
);
281 IMFPresentationClock_AddRef(sink
->clock
);
282 IMFPresentationClock_AddClockStateSink(sink
->clock
, &sink
->IMFClockStateSink_iface
);
286 static HRESULT WINAPI
wave_sink_SetPresentationClock(IMFFinalizableMediaSink
*iface
, IMFPresentationClock
*clock
)
288 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
291 TRACE("%p, %p.\n", iface
, clock
);
293 EnterCriticalSection(&sink
->cs
);
295 if (sink
->flags
& SINK_SHUT_DOWN
)
298 wave_sink_set_presentation_clock(sink
, clock
);
300 LeaveCriticalSection(&sink
->cs
);
305 static HRESULT WINAPI
wave_sink_GetPresentationClock(IMFFinalizableMediaSink
*iface
, IMFPresentationClock
**clock
)
307 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
310 TRACE("%p, %p.\n", iface
, clock
);
315 EnterCriticalSection(&sink
->cs
);
317 if (sink
->flags
& SINK_SHUT_DOWN
)
319 else if (sink
->clock
)
321 *clock
= sink
->clock
;
322 IMFPresentationClock_AddRef(*clock
);
327 LeaveCriticalSection(&sink
->cs
);
332 static HRESULT WINAPI
wave_sink_Shutdown(IMFFinalizableMediaSink
*iface
)
334 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
337 TRACE("%p.\n", iface
);
339 EnterCriticalSection(&sink
->cs
);
341 if (sink
->flags
& SINK_SHUT_DOWN
)
345 sink
->flags
|= SINK_SHUT_DOWN
;
346 IMFMediaEventQueue_Shutdown(sink
->event_queue
);
347 IMFMediaEventQueue_Shutdown(sink
->stream_event_queue
);
348 wave_sink_set_presentation_clock(sink
, NULL
);
351 LeaveCriticalSection(&sink
->cs
);
356 static void wave_sink_write_raw(struct wave_sink
*sink
, const void *data
, DWORD length
, HRESULT
*hr
)
358 DWORD written_length
;
360 if (FAILED(*hr
)) return;
361 if (SUCCEEDED(*hr
= IMFByteStream_Write(sink
->bytestream
, data
, length
, &written_length
)))
362 sink
->full_length
+= length
;
365 static void wave_sink_write_pad(struct wave_sink
*sink
, DWORD size
, HRESULT
*hr
)
367 DWORD i
, len
= size
/ 4, zero
= 0;
369 for (i
= 0; i
< len
; ++i
)
370 wave_sink_write_raw(sink
, &zero
, 4, hr
);
371 if ((len
= size
% 4))
372 wave_sink_write_raw(sink
, &zero
, len
, hr
);
375 static void wave_sink_write_junk(struct wave_sink
*sink
, DWORD size
, HRESULT
*hr
)
377 wave_sink_write_raw(sink
, "JUNK", 4, hr
);
378 wave_sink_write_raw(sink
, &size
, 4, hr
);
379 wave_sink_write_pad(sink
, size
, hr
);
382 static HRESULT
wave_sink_write_header(struct wave_sink
*sink
)
387 wave_sink_write_raw(sink
, "RIFF", 4, &hr
);
389 hr
= IMFByteStream_GetCurrentPosition(sink
->bytestream
, &sink
->riff_size_offset
);
390 wave_sink_write_raw(sink
, &size
, sizeof(size
), &hr
);
391 wave_sink_write_raw(sink
, "WAVE", 4, &hr
);
392 wave_sink_write_junk(sink
, 28, &hr
);
395 wave_sink_write_raw(sink
, "fmt ", 4, &hr
);
396 size
= sizeof(*sink
->fmt
);
397 wave_sink_write_raw(sink
, &size
, sizeof(size
), &hr
);
398 wave_sink_write_raw(sink
, sink
->fmt
, size
, &hr
);
400 sink
->flags
|= SINK_HEADER_WRITTEN
;
405 static HRESULT
wave_sink_start_data_chunk(struct wave_sink
*sink
)
409 wave_sink_write_raw(sink
, "data", 4, &hr
);
411 hr
= IMFByteStream_GetCurrentPosition(sink
->bytestream
, &sink
->data_size_offset
);
412 wave_sink_write_pad(sink
, 4, &hr
);
413 sink
->flags
|= SINK_DATA_CHUNK_STARTED
;
418 static HRESULT
wave_sink_write_data(struct wave_sink
*sink
, const BYTE
*data
, DWORD length
)
422 wave_sink_write_raw(sink
, data
, length
, &hr
);
424 sink
->data_length
+= length
;
429 static void wave_sink_write_at(struct wave_sink
*sink
, const void *data
, DWORD length
, QWORD offset
, HRESULT
*hr
)
433 if (FAILED(*hr
)) return;
435 if (FAILED(*hr
= IMFByteStream_GetCurrentPosition(sink
->bytestream
, &position
))) return;
436 if (FAILED(*hr
= IMFByteStream_SetCurrentPosition(sink
->bytestream
, offset
))) return;
437 wave_sink_write_raw(sink
, data
, length
, hr
);
438 IMFByteStream_SetCurrentPosition(sink
->bytestream
, position
);
441 static HRESULT WINAPI
wave_sink_BeginFinalize(IMFFinalizableMediaSink
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
443 struct wave_sink
*sink
= impl_from_IMFFinalizableMediaSink(iface
);
444 HRESULT hr
= S_OK
, status
;
445 IMFAsyncResult
*result
;
448 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
450 EnterCriticalSection(&sink
->cs
);
452 if (!(sink
->flags
& SINK_DATA_FINALIZED
))
454 size
= sink
->full_length
- 8 /* RIFF chunk header size */;
455 wave_sink_write_at(sink
, &size
, 4, sink
->riff_size_offset
, &hr
);
456 wave_sink_write_at(sink
, &sink
->data_length
, 4, sink
->data_size_offset
, &hr
);
457 sink
->flags
|= SINK_DATA_FINALIZED
;
461 status
= E_INVALIDARG
;
465 if (SUCCEEDED(hr
= MFCreateAsyncResult(NULL
, callback
, state
, &result
)))
467 IMFAsyncResult_SetStatus(result
, status
);
468 hr
= MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD
, result
);
469 IMFAsyncResult_Release(result
);
473 LeaveCriticalSection(&sink
->cs
);
478 static HRESULT WINAPI
wave_sink_EndFinalize(IMFFinalizableMediaSink
*iface
, IMFAsyncResult
*result
)
480 TRACE("%p, %p.\n", iface
, result
);
482 return result
? IMFAsyncResult_GetStatus(result
) : E_INVALIDARG
;
485 static const IMFFinalizableMediaSinkVtbl wave_sink_vtbl
=
487 wave_sink_QueryInterface
,
490 wave_sink_GetCharacteristics
,
491 wave_sink_AddStreamSink
,
492 wave_sink_RemoveStreamSink
,
493 wave_sink_GetStreamSinkCount
,
494 wave_sink_GetStreamSinkByIndex
,
495 wave_sink_GetStreamSinkById
,
496 wave_sink_SetPresentationClock
,
497 wave_sink_GetPresentationClock
,
499 wave_sink_BeginFinalize
,
500 wave_sink_EndFinalize
,
503 static HRESULT WINAPI
wave_sink_events_QueryInterface(IMFMediaEventGenerator
*iface
, REFIID riid
, void **obj
)
505 struct wave_sink
*sink
= impl_from_IMFMediaEventGenerator(iface
);
506 return IMFFinalizableMediaSink_QueryInterface(&sink
->IMFFinalizableMediaSink_iface
, riid
, obj
);
509 static ULONG WINAPI
wave_sink_events_AddRef(IMFMediaEventGenerator
*iface
)
511 struct wave_sink
*sink
= impl_from_IMFMediaEventGenerator(iface
);
512 return IMFFinalizableMediaSink_AddRef(&sink
->IMFFinalizableMediaSink_iface
);
515 static ULONG WINAPI
wave_sink_events_Release(IMFMediaEventGenerator
*iface
)
517 struct wave_sink
*sink
= impl_from_IMFMediaEventGenerator(iface
);
518 return IMFFinalizableMediaSink_Release(&sink
->IMFFinalizableMediaSink_iface
);
521 static HRESULT WINAPI
wave_sink_events_GetEvent(IMFMediaEventGenerator
*iface
, DWORD flags
, IMFMediaEvent
**event
)
523 struct wave_sink
*sink
= impl_from_IMFMediaEventGenerator(iface
);
525 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
527 return IMFMediaEventQueue_GetEvent(sink
->event_queue
, flags
, event
);
530 static HRESULT WINAPI
wave_sink_events_BeginGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncCallback
*callback
,
533 struct wave_sink
*sink
= impl_from_IMFMediaEventGenerator(iface
);
535 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
537 return IMFMediaEventQueue_BeginGetEvent(sink
->event_queue
, callback
, state
);
540 static HRESULT WINAPI
wave_sink_events_EndGetEvent(IMFMediaEventGenerator
*iface
, IMFAsyncResult
*result
,
541 IMFMediaEvent
**event
)
543 struct wave_sink
*sink
= impl_from_IMFMediaEventGenerator(iface
);
545 TRACE("%p, %p, %p.\n", iface
, result
, event
);
547 return IMFMediaEventQueue_EndGetEvent(sink
->event_queue
, result
, event
);
550 static HRESULT WINAPI
wave_sink_events_QueueEvent(IMFMediaEventGenerator
*iface
, MediaEventType event_type
,
551 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
553 struct wave_sink
*sink
= impl_from_IMFMediaEventGenerator(iface
);
555 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
557 return IMFMediaEventQueue_QueueEventParamVar(sink
->event_queue
, event_type
, ext_type
, hr
, value
);
560 static const IMFMediaEventGeneratorVtbl wave_sink_events_vtbl
=
562 wave_sink_events_QueryInterface
,
563 wave_sink_events_AddRef
,
564 wave_sink_events_Release
,
565 wave_sink_events_GetEvent
,
566 wave_sink_events_BeginGetEvent
,
567 wave_sink_events_EndGetEvent
,
568 wave_sink_events_QueueEvent
,
571 static HRESULT WINAPI
wave_stream_sink_QueryInterface(IMFStreamSink
*iface
, REFIID riid
, void **obj
)
573 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
575 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
577 if (IsEqualIID(riid
, &IID_IMFStreamSink
) ||
578 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
579 IsEqualIID(riid
, &IID_IUnknown
))
581 *obj
= &sink
->IMFStreamSink_iface
;
583 else if (IsEqualIID(riid
, &IID_IMFMediaTypeHandler
))
585 *obj
= &sink
->IMFMediaTypeHandler_iface
;
589 WARN("Unsupported %s.\n", debugstr_guid(riid
));
591 return E_NOINTERFACE
;
594 IUnknown_AddRef((IUnknown
*)*obj
);
599 static ULONG WINAPI
wave_stream_sink_AddRef(IMFStreamSink
*iface
)
601 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
602 return IMFFinalizableMediaSink_AddRef(&sink
->IMFFinalizableMediaSink_iface
);
605 static ULONG WINAPI
wave_stream_sink_Release(IMFStreamSink
*iface
)
607 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
608 return IMFFinalizableMediaSink_Release(&sink
->IMFFinalizableMediaSink_iface
);
611 static HRESULT WINAPI
wave_stream_sink_GetEvent(IMFStreamSink
*iface
, DWORD flags
, IMFMediaEvent
**event
)
613 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
615 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
617 if (sink
->flags
& SINK_SHUT_DOWN
)
618 return MF_E_STREAMSINK_REMOVED
;
620 return IMFMediaEventQueue_GetEvent(sink
->stream_event_queue
, flags
, event
);
623 static HRESULT WINAPI
wave_stream_sink_BeginGetEvent(IMFStreamSink
*iface
, IMFAsyncCallback
*callback
,
626 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
628 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
630 if (sink
->flags
& SINK_SHUT_DOWN
)
631 return MF_E_STREAMSINK_REMOVED
;
633 return IMFMediaEventQueue_BeginGetEvent(sink
->stream_event_queue
, callback
, state
);
636 static HRESULT WINAPI
wave_stream_sink_EndGetEvent(IMFStreamSink
*iface
, IMFAsyncResult
*result
,
637 IMFMediaEvent
**event
)
639 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
641 TRACE("%p, %p, %p.\n", iface
, result
, event
);
643 if (sink
->flags
& SINK_SHUT_DOWN
)
644 return MF_E_STREAMSINK_REMOVED
;
646 return IMFMediaEventQueue_EndGetEvent(sink
->stream_event_queue
, result
, event
);
649 static HRESULT WINAPI
wave_stream_sink_QueueEvent(IMFStreamSink
*iface
, MediaEventType event_type
,
650 REFGUID ext_type
, HRESULT hr
, const PROPVARIANT
*value
)
652 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
654 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
656 if (sink
->flags
& SINK_SHUT_DOWN
)
657 return MF_E_STREAMSINK_REMOVED
;
659 return IMFMediaEventQueue_QueueEventParamVar(sink
->stream_event_queue
, event_type
, ext_type
, hr
, value
);
662 static HRESULT WINAPI
wave_stream_sink_GetMediaSink(IMFStreamSink
*iface
, IMFMediaSink
**ret
)
664 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
666 TRACE("%p, %p.\n", iface
, ret
);
668 if (sink
->flags
& SINK_SHUT_DOWN
)
669 return MF_E_STREAMSINK_REMOVED
;
671 *ret
= (IMFMediaSink
*)&sink
->IMFFinalizableMediaSink_iface
;
672 IMFMediaSink_AddRef(*ret
);
677 static HRESULT WINAPI
wave_stream_sink_GetIdentifier(IMFStreamSink
*iface
, DWORD
*identifier
)
679 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
681 TRACE("%p, %p.\n", iface
, identifier
);
683 if (sink
->flags
& SINK_SHUT_DOWN
)
684 return MF_E_STREAMSINK_REMOVED
;
691 static HRESULT WINAPI
wave_stream_sink_GetMediaTypeHandler(IMFStreamSink
*iface
, IMFMediaTypeHandler
**handler
)
693 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
695 TRACE("%p, %p.\n", iface
, handler
);
697 if (sink
->flags
& SINK_SHUT_DOWN
)
698 return MF_E_STREAMSINK_REMOVED
;
700 *handler
= &sink
->IMFMediaTypeHandler_iface
;
701 IMFMediaTypeHandler_AddRef(*handler
);
706 static HRESULT WINAPI
wave_stream_sink_ProcessSample(IMFStreamSink
*iface
, IMFSample
*sample
)
708 struct wave_sink
*sink
= impl_from_IMFStreamSink(iface
);
709 IMFMediaBuffer
*buffer
= NULL
;
710 DWORD max_length
, length
;
714 TRACE("%p, %p.\n", iface
, sample
);
716 EnterCriticalSection(&sink
->cs
);
718 if (sink
->flags
& SINK_SHUT_DOWN
)
719 hr
= MF_E_STREAMSINK_REMOVED
;
722 if (!(sink
->flags
& SINK_HEADER_WRITTEN
))
723 hr
= wave_sink_write_header(sink
);
725 if (SUCCEEDED(hr
) && !(sink
->flags
& SINK_DATA_CHUNK_STARTED
))
726 hr
= wave_sink_start_data_chunk(sink
);
729 hr
= IMFSample_ConvertToContiguousBuffer(sample
, &buffer
);
733 if (SUCCEEDED(hr
= IMFMediaBuffer_Lock(buffer
, &data
, &max_length
, &length
)))
735 hr
= wave_sink_write_data(sink
, data
, length
);
736 IMFMediaBuffer_Unlock(buffer
);
741 IMFMediaBuffer_Release(buffer
);
744 LeaveCriticalSection(&sink
->cs
);
749 static HRESULT WINAPI
wave_stream_sink_PlaceMarker(IMFStreamSink
*iface
, MFSTREAMSINK_MARKER_TYPE marker_type
,
750 const PROPVARIANT
*marker_value
, const PROPVARIANT
*context_value
)
752 FIXME("%p, %d, %p, %p.\n", iface
, marker_type
, marker_value
, context_value
);
757 static HRESULT WINAPI
wave_stream_sink_Flush(IMFStreamSink
*iface
)
759 FIXME("%p.\n", iface
);
764 static const IMFStreamSinkVtbl wave_stream_sink_vtbl
=
766 wave_stream_sink_QueryInterface
,
767 wave_stream_sink_AddRef
,
768 wave_stream_sink_Release
,
769 wave_stream_sink_GetEvent
,
770 wave_stream_sink_BeginGetEvent
,
771 wave_stream_sink_EndGetEvent
,
772 wave_stream_sink_QueueEvent
,
773 wave_stream_sink_GetMediaSink
,
774 wave_stream_sink_GetIdentifier
,
775 wave_stream_sink_GetMediaTypeHandler
,
776 wave_stream_sink_ProcessSample
,
777 wave_stream_sink_PlaceMarker
,
778 wave_stream_sink_Flush
,
781 static HRESULT WINAPI
wave_sink_clock_sink_QueryInterface(IMFClockStateSink
*iface
, REFIID riid
, void **obj
)
783 struct wave_sink
*sink
= impl_from_IMFClockStateSink(iface
);
784 return IMFFinalizableMediaSink_QueryInterface(&sink
->IMFFinalizableMediaSink_iface
, riid
, obj
);
787 static ULONG WINAPI
wave_sink_clock_sink_AddRef(IMFClockStateSink
*iface
)
789 struct wave_sink
*sink
= impl_from_IMFClockStateSink(iface
);
790 return IMFFinalizableMediaSink_AddRef(&sink
->IMFFinalizableMediaSink_iface
);
793 static ULONG WINAPI
wave_sink_clock_sink_Release(IMFClockStateSink
*iface
)
795 struct wave_sink
*sink
= impl_from_IMFClockStateSink(iface
);
796 return IMFFinalizableMediaSink_Release(&sink
->IMFFinalizableMediaSink_iface
);
799 static HRESULT WINAPI
wave_sink_clock_sink_OnClockStart(IMFClockStateSink
*iface
, MFTIME systime
, LONGLONG offset
)
801 struct wave_sink
*sink
= impl_from_IMFClockStateSink(iface
);
803 TRACE("%p, %s, %s.\n", iface
, debugstr_time(systime
), debugstr_time(offset
));
805 return IMFMediaEventQueue_QueueEventParamVar(sink
->stream_event_queue
, MEStreamSinkStarted
, &GUID_NULL
, S_OK
, NULL
);
808 static HRESULT WINAPI
wave_sink_clock_sink_OnClockStop(IMFClockStateSink
*iface
, MFTIME systime
)
810 struct wave_sink
*sink
= impl_from_IMFClockStateSink(iface
);
812 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
814 return IMFMediaEventQueue_QueueEventParamVar(sink
->stream_event_queue
, MEStreamSinkStopped
, &GUID_NULL
, S_OK
, NULL
);
817 static HRESULT WINAPI
wave_sink_clock_sink_OnClockPause(IMFClockStateSink
*iface
, MFTIME systime
)
819 struct wave_sink
*sink
= impl_from_IMFClockStateSink(iface
);
821 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
823 return IMFMediaEventQueue_QueueEventParamVar(sink
->stream_event_queue
, MEStreamSinkPaused
, &GUID_NULL
, S_OK
, NULL
);
826 static HRESULT WINAPI
wave_sink_clock_sink_OnClockRestart(IMFClockStateSink
*iface
, MFTIME systime
)
828 struct wave_sink
*sink
= impl_from_IMFClockStateSink(iface
);
830 TRACE("%p, %s.\n", iface
, debugstr_time(systime
));
832 return IMFMediaEventQueue_QueueEventParamVar(sink
->stream_event_queue
, MEStreamSinkStarted
, &GUID_NULL
, S_OK
, NULL
);
835 static HRESULT WINAPI
wave_sink_clock_sink_OnClockSetRate(IMFClockStateSink
*iface
, MFTIME systime
, float rate
)
837 FIXME("%p, %s, %f.\n", iface
, debugstr_time(systime
), rate
);
842 static const IMFClockStateSinkVtbl wave_sink_clock_sink_vtbl
=
844 wave_sink_clock_sink_QueryInterface
,
845 wave_sink_clock_sink_AddRef
,
846 wave_sink_clock_sink_Release
,
847 wave_sink_clock_sink_OnClockStart
,
848 wave_sink_clock_sink_OnClockStop
,
849 wave_sink_clock_sink_OnClockPause
,
850 wave_sink_clock_sink_OnClockRestart
,
851 wave_sink_clock_sink_OnClockSetRate
,
854 static HRESULT WINAPI
wave_sink_type_handler_QueryInterface(IMFMediaTypeHandler
*iface
, REFIID riid
,
857 struct wave_sink
*sink
= impl_from_IMFMediaTypeHandler(iface
);
858 return IMFStreamSink_QueryInterface(&sink
->IMFStreamSink_iface
, riid
, obj
);
861 static ULONG WINAPI
wave_sink_type_handler_AddRef(IMFMediaTypeHandler
*iface
)
863 struct wave_sink
*sink
= impl_from_IMFMediaTypeHandler(iface
);
864 return IMFStreamSink_AddRef(&sink
->IMFStreamSink_iface
);
867 static ULONG WINAPI
wave_sink_type_handler_Release(IMFMediaTypeHandler
*iface
)
869 struct wave_sink
*sink
= impl_from_IMFMediaTypeHandler(iface
);
870 return IMFStreamSink_Release(&sink
->IMFStreamSink_iface
);
873 static HRESULT WINAPI
wave_sink_type_handler_IsMediaTypeSupported(IMFMediaTypeHandler
*iface
,
874 IMFMediaType
*in_type
, IMFMediaType
**out_type
)
876 FIXME("%p, %p, %p.\n", iface
, in_type
, out_type
);
881 static HRESULT WINAPI
wave_sink_type_handler_GetMediaTypeCount(IMFMediaTypeHandler
*iface
, DWORD
*count
)
883 TRACE("%p, %p.\n", iface
, count
);
890 static HRESULT WINAPI
wave_sink_type_handler_GetMediaTypeByIndex(IMFMediaTypeHandler
*iface
, DWORD index
,
891 IMFMediaType
**media_type
)
893 FIXME("%p, %lu, %p.\n", iface
, index
, media_type
);
898 static HRESULT WINAPI
wave_sink_type_handler_SetCurrentMediaType(IMFMediaTypeHandler
*iface
,
899 IMFMediaType
*media_type
)
901 FIXME("%p, %p.\n", iface
, media_type
);
906 static HRESULT WINAPI
wave_sink_type_handler_GetCurrentMediaType(IMFMediaTypeHandler
*iface
,
907 IMFMediaType
**media_type
)
909 FIXME("%p, %p.\n", iface
, media_type
);
914 static HRESULT WINAPI
wave_sink_type_handler_GetMajorType(IMFMediaTypeHandler
*iface
, GUID
*type
)
916 struct wave_sink
*sink
= impl_from_IMFMediaTypeHandler(iface
);
918 TRACE("%p, %p.\n", iface
, type
);
923 if (sink
->flags
& SINK_SHUT_DOWN
)
924 return MF_E_STREAMSINK_REMOVED
;
926 memcpy(type
, &MFMediaType_Audio
, sizeof(*type
));
930 static const IMFMediaTypeHandlerVtbl wave_sink_type_handler_vtbl
=
932 wave_sink_type_handler_QueryInterface
,
933 wave_sink_type_handler_AddRef
,
934 wave_sink_type_handler_Release
,
935 wave_sink_type_handler_IsMediaTypeSupported
,
936 wave_sink_type_handler_GetMediaTypeCount
,
937 wave_sink_type_handler_GetMediaTypeByIndex
,
938 wave_sink_type_handler_SetCurrentMediaType
,
939 wave_sink_type_handler_GetCurrentMediaType
,
940 wave_sink_type_handler_GetMajorType
,
943 /***********************************************************************
944 * MFCreateWAVEMediaSink (mfsrcsnk.@)
946 HRESULT WINAPI
MFCreateWAVEMediaSink(IMFByteStream
*bytestream
, IMFMediaType
*media_type
,
949 struct wave_sink
*object
;
954 TRACE("%p, %p, %p.\n", bytestream
, media_type
, sink
);
956 if (!bytestream
|| !media_type
|| !sink
)
959 if (FAILED(hr
= IMFByteStream_GetCapabilities(bytestream
, &flags
))) return hr
;
960 if (!(flags
& MFBYTESTREAM_IS_WRITABLE
)) return E_INVALIDARG
;
962 if (!(object
= calloc(1, sizeof(*object
))))
963 return E_OUTOFMEMORY
;
965 /* FIXME: do basic media type validation */
967 if (FAILED(hr
= MFCreateWaveFormatExFromMFMediaType(media_type
, &object
->fmt
, &size
, 0)))
969 WARN("Failed to produce WAVEFORMATEX representation, hr %#lx.\n", hr
);
973 /* Update derived fields. */
974 object
->fmt
->nAvgBytesPerSec
= object
->fmt
->nSamplesPerSec
* object
->fmt
->nChannels
* object
->fmt
->wBitsPerSample
/ 8;
975 object
->fmt
->nBlockAlign
= object
->fmt
->nChannels
* object
->fmt
->wBitsPerSample
/ 8;
977 object
->IMFFinalizableMediaSink_iface
.lpVtbl
= &wave_sink_vtbl
;
978 object
->IMFMediaEventGenerator_iface
.lpVtbl
= &wave_sink_events_vtbl
;
979 object
->IMFStreamSink_iface
.lpVtbl
= &wave_stream_sink_vtbl
;
980 object
->IMFClockStateSink_iface
.lpVtbl
= &wave_sink_clock_sink_vtbl
;
981 object
->IMFMediaTypeHandler_iface
.lpVtbl
= &wave_sink_type_handler_vtbl
;
982 object
->refcount
= 1;
983 IMFByteStream_AddRef((object
->bytestream
= bytestream
));
984 InitializeCriticalSection(&object
->cs
);
986 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
989 if (FAILED(hr
= MFCreateEventQueue(&object
->stream_event_queue
)))
992 *sink
= (IMFMediaSink
*)&object
->IMFFinalizableMediaSink_iface
;
998 IMFFinalizableMediaSink_Release(&object
->IMFFinalizableMediaSink_iface
);
1003 static HRESULT WINAPI
sink_class_factory_QueryInterface(IMFSinkClassFactory
*iface
, REFIID riid
, void **out
)
1005 if (IsEqualIID(riid
, &IID_IMFSinkClassFactory
)
1006 || IsEqualIID(riid
, &IID_IUnknown
))
1009 IMFSinkClassFactory_AddRef(iface
);
1014 return E_NOINTERFACE
;
1017 static ULONG WINAPI
sink_class_factory_AddRef(IMFSinkClassFactory
*iface
)
1022 static ULONG WINAPI
sink_class_factory_Release(IMFSinkClassFactory
*iface
)
1027 static HRESULT WINAPI
sink_class_factory_CreateMediaSink(IMFSinkClassFactory
*iface
, IMFByteStream
*stream
,
1028 IMFMediaType
*video_type
, IMFMediaType
*audio_type
, IMFMediaSink
**sink
)
1030 TRACE("%p, %p, %p, %p.\n", stream
, video_type
, audio_type
, sink
);
1032 return MFCreateWAVEMediaSink(stream
, audio_type
, sink
);
1035 static const IMFSinkClassFactoryVtbl wave_sink_factory_vtbl
=
1037 sink_class_factory_QueryInterface
,
1038 sink_class_factory_AddRef
,
1039 sink_class_factory_Release
,
1040 sink_class_factory_CreateMediaSink
,
1043 static IMFSinkClassFactory wave_sink_factory
= { &wave_sink_factory_vtbl
};
1045 HRESULT
wave_sink_factory_create(REFIID riid
, void **out
)
1047 return IMFSinkClassFactory_QueryInterface(&wave_sink_factory
, riid
, out
);