d3dx9: Unify calling parse_mesh helper functions.
[wine.git] / dlls / mfsrcsnk / wave.c
blob736bbb5aa3cb6f14cad736a99ef5040b52a3c20b
1 /*
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
19 #define COBJMACROS
21 #include "mfapi.h"
22 #include "mfidl.h"
23 #include "mferror.h"
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);
40 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;
47 rev[j] = 0;
49 return wine_dbg_sprintf("%s", rev);
52 enum wave_sink_flags
54 SINK_SHUT_DOWN = 0x1,
55 SINK_HEADER_WRITTEN = 0x2,
56 SINK_DATA_CHUNK_STARTED = 0x4,
57 SINK_DATA_FINALIZED = 0x8,
60 struct wave_sink
62 IMFFinalizableMediaSink IMFFinalizableMediaSink_iface;
63 IMFMediaEventGenerator IMFMediaEventGenerator_iface;
64 IMFClockStateSink IMFClockStateSink_iface;
65 IMFMediaTypeHandler IMFMediaTypeHandler_iface;
66 IMFStreamSink IMFStreamSink_iface;
67 LONG refcount;
69 IMFMediaEventQueue *event_queue;
70 IMFMediaEventQueue *stream_event_queue;
71 IMFPresentationClock *clock;
73 WAVEFORMATEX *fmt;
74 IMFByteStream *bytestream;
75 QWORD data_size_offset;
76 QWORD riff_size_offset;
77 DWORD data_length;
78 DWORD full_length;
80 unsigned int flags;
81 CRITICAL_SECTION cs;
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))
119 *obj = iface;
121 else if (IsEqualIID(riid, &IID_IMFMediaEventGenerator))
123 *obj = &sink->IMFMediaEventGenerator_iface;
125 else if (IsEqualIID(riid, &IID_IMFClockStateSink))
127 *obj = &sink->IMFClockStateSink_iface;
129 else
131 WARN("Unsupported %s.\n", debugstr_guid(riid));
132 *obj = NULL;
133 return E_NOINTERFACE;
136 IUnknown_AddRef((IUnknown *)*obj);
138 return S_OK;
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);
146 return 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);
156 if (!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);
165 free(sink);
168 return refcount;
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;
182 return S_OK;
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);
210 if (!count)
211 return E_POINTER;
213 if (sink->flags & SINK_SHUT_DOWN)
214 return MF_E_SHUTDOWN;
216 *count = 1;
218 return S_OK;
221 static HRESULT WINAPI wave_sink_GetStreamSinkByIndex(IMFFinalizableMediaSink *iface, DWORD index,
222 IMFStreamSink **stream)
224 struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface);
225 HRESULT hr = S_OK;
227 TRACE("%p, %lu, %p.\n", iface, index, stream);
229 EnterCriticalSection(&sink->cs);
231 if (sink->flags & SINK_SHUT_DOWN)
232 hr = MF_E_SHUTDOWN;
233 else if (index)
234 hr = MF_E_INVALIDINDEX;
235 else
237 *stream = &sink->IMFStreamSink_iface;
238 IMFStreamSink_AddRef(*stream);
241 LeaveCriticalSection(&sink->cs);
243 return hr;
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);
250 HRESULT hr = S_OK;
252 TRACE("%p, %#lx, %p.\n", iface, stream_sink_id, stream);
254 EnterCriticalSection(&sink->cs);
256 if (sink->flags & SINK_SHUT_DOWN)
257 hr = MF_E_SHUTDOWN;
258 else if (stream_sink_id != 1)
259 hr = MF_E_INVALIDSTREAMNUMBER;
260 else
262 *stream = &sink->IMFStreamSink_iface;
263 IMFStreamSink_AddRef(*stream);
266 LeaveCriticalSection(&sink->cs);
268 return hr;
271 static void wave_sink_set_presentation_clock(struct wave_sink *sink, IMFPresentationClock *clock)
273 if (sink->clock)
275 IMFPresentationClock_RemoveClockStateSink(sink->clock, &sink->IMFClockStateSink_iface);
276 IMFPresentationClock_Release(sink->clock);
278 sink->clock = clock;
279 if (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);
289 HRESULT hr = S_OK;
291 TRACE("%p, %p.\n", iface, clock);
293 EnterCriticalSection(&sink->cs);
295 if (sink->flags & SINK_SHUT_DOWN)
296 hr = MF_E_SHUTDOWN;
297 else
298 wave_sink_set_presentation_clock(sink, clock);
300 LeaveCriticalSection(&sink->cs);
302 return hr;
305 static HRESULT WINAPI wave_sink_GetPresentationClock(IMFFinalizableMediaSink *iface, IMFPresentationClock **clock)
307 struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface);
308 HRESULT hr = S_OK;
310 TRACE("%p, %p.\n", iface, clock);
312 if (!clock)
313 return E_POINTER;
315 EnterCriticalSection(&sink->cs);
317 if (sink->flags & SINK_SHUT_DOWN)
318 hr = MF_E_SHUTDOWN;
319 else if (sink->clock)
321 *clock = sink->clock;
322 IMFPresentationClock_AddRef(*clock);
324 else
325 hr = MF_E_NO_CLOCK;
327 LeaveCriticalSection(&sink->cs);
329 return hr;
332 static HRESULT WINAPI wave_sink_Shutdown(IMFFinalizableMediaSink *iface)
334 struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface);
335 HRESULT hr = S_OK;
337 TRACE("%p.\n", iface);
339 EnterCriticalSection(&sink->cs);
341 if (sink->flags & SINK_SHUT_DOWN)
342 hr = MF_E_SHUTDOWN;
343 else
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);
353 return hr;
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)
384 HRESULT hr = S_OK;
385 DWORD size = 0;
387 wave_sink_write_raw(sink, "RIFF", 4, &hr);
388 if (SUCCEEDED(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);
394 /* Format chunk */
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;
402 return hr;
405 static HRESULT wave_sink_start_data_chunk(struct wave_sink *sink)
407 HRESULT hr = S_OK;
409 wave_sink_write_raw(sink, "data", 4, &hr);
410 if (SUCCEEDED(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;
415 return hr;
418 static HRESULT wave_sink_write_data(struct wave_sink *sink, const BYTE *data, DWORD length)
420 HRESULT hr = S_OK;
422 wave_sink_write_raw(sink, data, length, &hr);
423 if (SUCCEEDED(hr))
424 sink->data_length += length;
426 return hr;
429 static void wave_sink_write_at(struct wave_sink *sink, const void *data, DWORD length, QWORD offset, HRESULT *hr)
431 QWORD position;
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;
446 DWORD size;
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;
458 status = hr;
460 else
461 status = E_INVALIDARG;
463 if (callback)
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);
475 return hr;
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,
488 wave_sink_AddRef,
489 wave_sink_Release,
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,
498 wave_sink_Shutdown,
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,
531 IUnknown *state)
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;
587 else
589 WARN("Unsupported %s.\n", debugstr_guid(riid));
590 *obj = NULL;
591 return E_NOINTERFACE;
594 IUnknown_AddRef((IUnknown *)*obj);
596 return S_OK;
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,
624 IUnknown *state)
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);
674 return S_OK;
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;
686 *identifier = 1;
688 return S_OK;
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);
703 return S_OK;
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;
711 HRESULT hr = S_OK;
712 BYTE *data;
714 TRACE("%p, %p.\n", iface, sample);
716 EnterCriticalSection(&sink->cs);
718 if (sink->flags & SINK_SHUT_DOWN)
719 hr = MF_E_STREAMSINK_REMOVED;
720 else
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);
728 if (SUCCEEDED(hr))
729 hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer);
731 if (SUCCEEDED(hr))
733 if (SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &data, &max_length, &length)))
735 hr = wave_sink_write_data(sink, data, length);
736 IMFMediaBuffer_Unlock(buffer);
740 if (buffer)
741 IMFMediaBuffer_Release(buffer);
744 LeaveCriticalSection(&sink->cs);
746 return hr;
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);
754 return E_NOTIMPL;
757 static HRESULT WINAPI wave_stream_sink_Flush(IMFStreamSink *iface)
759 FIXME("%p.\n", iface);
761 return E_NOTIMPL;
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);
839 return E_NOTIMPL;
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,
855 void **obj)
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);
878 return E_NOTIMPL;
881 static HRESULT WINAPI wave_sink_type_handler_GetMediaTypeCount(IMFMediaTypeHandler *iface, DWORD *count)
883 TRACE("%p, %p.\n", iface, count);
885 *count = 1;
887 return S_OK;
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);
895 return E_NOTIMPL;
898 static HRESULT WINAPI wave_sink_type_handler_SetCurrentMediaType(IMFMediaTypeHandler *iface,
899 IMFMediaType *media_type)
901 FIXME("%p, %p.\n", iface, media_type);
903 return E_NOTIMPL;
906 static HRESULT WINAPI wave_sink_type_handler_GetCurrentMediaType(IMFMediaTypeHandler *iface,
907 IMFMediaType **media_type)
909 FIXME("%p, %p.\n", iface, media_type);
911 return E_NOTIMPL;
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);
920 if (!type)
921 return E_POINTER;
923 if (sink->flags & SINK_SHUT_DOWN)
924 return MF_E_STREAMSINK_REMOVED;
926 memcpy(type, &MFMediaType_Audio, sizeof(*type));
927 return S_OK;
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,
947 IMFMediaSink **sink)
949 struct wave_sink *object;
950 DWORD flags = 0;
951 UINT32 size;
952 HRESULT hr;
954 TRACE("%p, %p, %p.\n", bytestream, media_type, sink);
956 if (!bytestream || !media_type || !sink)
957 return E_POINTER;
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);
970 goto failed;
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)))
987 goto failed;
989 if (FAILED(hr = MFCreateEventQueue(&object->stream_event_queue)))
990 goto failed;
992 *sink = (IMFMediaSink *)&object->IMFFinalizableMediaSink_iface;
994 return S_OK;
996 failed:
998 IMFFinalizableMediaSink_Release(&object->IMFFinalizableMediaSink_iface);
1000 return hr;
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))
1008 *out = iface;
1009 IMFSinkClassFactory_AddRef(iface);
1010 return S_OK;
1013 *out = NULL;
1014 return E_NOINTERFACE;
1017 static ULONG WINAPI sink_class_factory_AddRef(IMFSinkClassFactory *iface)
1019 return 2;
1022 static ULONG WINAPI sink_class_factory_Release(IMFSinkClassFactory *iface)
1024 return 1;
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);