Nikolay Sivov : mfsrcsnk/wave: Implement sample processing.

Alexandre Julliard julliard at winehq.org
Mon Aug 15 15:22:31 CDT 2022


Module: wine
Branch: master
Commit: cf9b383032ad7c477726ca559e21c2c85edfa30b
URL:    https://gitlab.winehq.org/wine/wine/-/commit/cf9b383032ad7c477726ca559e21c2c85edfa30b

Author: Nikolay Sivov <nsivov at codeweavers.com>
Date:   Sun Aug 14 10:11:17 2022 +0300

mfsrcsnk/wave: Implement sample processing.

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>

---

 dlls/mfsrcsnk/wave.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 168 insertions(+), 6 deletions(-)

diff --git a/dlls/mfsrcsnk/wave.c b/dlls/mfsrcsnk/wave.c
index 583eefb98b0..ce57865d093 100644
--- a/dlls/mfsrcsnk/wave.c
+++ b/dlls/mfsrcsnk/wave.c
@@ -50,6 +50,9 @@ static inline const char *debugstr_time(LONGLONG time)
 enum wave_sink_flags
 {
     SINK_SHUT_DOWN = 0x1,
+    SINK_HEADER_WRITTEN = 0x2,
+    SINK_DATA_CHUNK_STARTED = 0x4,
+    SINK_DATA_FINALIZED = 0x8,
 };
 
 struct wave_sink
@@ -66,6 +69,10 @@ struct wave_sink
 
     WAVEFORMATEX *fmt;
     IMFByteStream *bytestream;
+    QWORD data_size_offset;
+    QWORD riff_size_offset;
+    DWORD data_length;
+    DWORD full_length;
 
     unsigned int flags;
     CRITICAL_SECTION cs;
@@ -338,18 +345,133 @@ static HRESULT WINAPI wave_sink_Shutdown(IMFFinalizableMediaSink *iface)
     return hr;
 }
 
+static void wave_sink_write_raw(struct wave_sink *sink, const void *data, DWORD length, HRESULT *hr)
+{
+    DWORD written_length;
+
+    if (FAILED(*hr)) return;
+    if (SUCCEEDED(*hr = IMFByteStream_Write(sink->bytestream, data, length, &written_length)))
+        sink->full_length += length;
+}
+
+static void wave_sink_write_pad(struct wave_sink *sink, DWORD size, HRESULT *hr)
+{
+    DWORD i, len = size / 4, zero = 0;
+
+    for (i = 0; i < len; ++i)
+        wave_sink_write_raw(sink, &zero, 4, hr);
+    if ((len = size % 4))
+        wave_sink_write_raw(sink, &zero, len, hr);
+}
+
+static void wave_sink_write_junk(struct wave_sink *sink, DWORD size, HRESULT *hr)
+{
+    wave_sink_write_raw(sink, "JUNK", 4, hr);
+    wave_sink_write_raw(sink, &size, 4, hr);
+    wave_sink_write_pad(sink, size, hr);
+}
+
+static HRESULT wave_sink_write_header(struct wave_sink *sink)
+{
+    HRESULT hr = S_OK;
+    DWORD size = 0;
+
+    wave_sink_write_raw(sink, "RIFF", 4, &hr);
+    if (SUCCEEDED(hr))
+        hr = IMFByteStream_GetCurrentPosition(sink->bytestream, &sink->riff_size_offset);
+    wave_sink_write_raw(sink, &size, sizeof(size), &hr);
+    wave_sink_write_raw(sink, "WAVE", 4, &hr);
+    wave_sink_write_junk(sink, 28, &hr);
+
+    /* Format chunk */
+    wave_sink_write_raw(sink, "fmt ", 4, &hr);
+    size = sizeof(*sink->fmt);
+    wave_sink_write_raw(sink, &size, sizeof(size), &hr);
+    wave_sink_write_raw(sink, sink->fmt, size, &hr);
+
+    sink->flags |= SINK_HEADER_WRITTEN;
+
+    return hr;
+}
+
+static HRESULT wave_sink_start_data_chunk(struct wave_sink *sink)
+{
+    HRESULT hr = S_OK;
+
+    wave_sink_write_raw(sink, "data", 4, &hr);
+    if (SUCCEEDED(hr))
+        hr = IMFByteStream_GetCurrentPosition(sink->bytestream, &sink->data_size_offset);
+    wave_sink_write_pad(sink, 4, &hr);
+    sink->flags |= SINK_DATA_CHUNK_STARTED;
+
+    return hr;
+}
+
+static HRESULT wave_sink_write_data(struct wave_sink *sink, const BYTE *data, DWORD length)
+{
+    HRESULT hr = S_OK;
+
+    wave_sink_write_raw(sink, data, length, &hr);
+    if (SUCCEEDED(hr))
+        sink->data_length += length;
+
+    return hr;
+}
+
+static void wave_sink_write_at(struct wave_sink *sink, const void *data, DWORD length, QWORD offset, HRESULT *hr)
+{
+    QWORD position;
+
+    if (FAILED(*hr)) return;
+
+    if (FAILED(*hr = IMFByteStream_GetCurrentPosition(sink->bytestream, &position))) return;
+    if (FAILED(*hr = IMFByteStream_SetCurrentPosition(sink->bytestream, offset))) return;
+    wave_sink_write_raw(sink, data, length, hr);
+    IMFByteStream_SetCurrentPosition(sink->bytestream, position);
+}
+
 static HRESULT WINAPI wave_sink_BeginFinalize(IMFFinalizableMediaSink *iface, IMFAsyncCallback *callback, IUnknown *state)
 {
-    FIXME("%p, %p, %p.\n", iface, callback, state);
+    struct wave_sink *sink = impl_from_IMFFinalizableMediaSink(iface);
+    HRESULT hr = S_OK, status;
+    IMFAsyncResult *result;
+    DWORD size;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p, %p.\n", iface, callback, state);
+
+    EnterCriticalSection(&sink->cs);
+
+    if (!(sink->flags & SINK_DATA_FINALIZED))
+    {
+        size = sink->full_length - 8 /* RIFF chunk header size */;
+        wave_sink_write_at(sink, &size, 4, sink->riff_size_offset, &hr);
+        wave_sink_write_at(sink, &sink->data_length, 4, sink->data_size_offset, &hr);
+        sink->flags |= SINK_DATA_FINALIZED;
+        status = hr;
+    }
+    else
+        status = E_INVALIDARG;
+
+    if (callback)
+    {
+        if (SUCCEEDED(hr = MFCreateAsyncResult(NULL, callback, state, &result)))
+        {
+            IMFAsyncResult_SetStatus(result, status);
+            hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_STANDARD, result);
+            IMFAsyncResult_Release(result);
+        }
+    }
+
+    LeaveCriticalSection(&sink->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI wave_sink_EndFinalize(IMFFinalizableMediaSink *iface, IMFAsyncResult *result)
 {
-    FIXME("%p, %p.\n", iface, result);
+    TRACE("%p, %p.\n", iface, result);
 
-    return E_NOTIMPL;
+    return result ? IMFAsyncResult_GetStatus(result) : E_INVALIDARG;
 }
 
 static const IMFFinalizableMediaSinkVtbl wave_sink_vtbl =
@@ -563,9 +685,45 @@ static HRESULT WINAPI wave_stream_sink_GetMediaTypeHandler(IMFStreamSink *iface,
 
 static HRESULT WINAPI wave_stream_sink_ProcessSample(IMFStreamSink *iface, IMFSample *sample)
 {
-    FIXME("%p, %p.\n", iface, sample);
+    struct wave_sink *sink = impl_from_IMFStreamSink(iface);
+    DWORD max_length, length;
+    IMFMediaBuffer *buffer;
+    HRESULT hr = S_OK;
+    BYTE *data;
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, sample);
+
+    EnterCriticalSection(&sink->cs);
+
+    if (sink->flags & SINK_SHUT_DOWN)
+        hr = MF_E_STREAMSINK_REMOVED;
+    else
+    {
+        if (!(sink->flags & SINK_HEADER_WRITTEN))
+            hr = wave_sink_write_header(sink);
+
+        if (SUCCEEDED(hr) && !(sink->flags & SINK_DATA_CHUNK_STARTED))
+            hr = wave_sink_start_data_chunk(sink);
+
+        if (SUCCEEDED(hr))
+            hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer);
+
+        if (SUCCEEDED(hr))
+        {
+            if (SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &data, &max_length, &length)))
+            {
+                hr = wave_sink_write_data(sink, data, length);
+                IMFMediaBuffer_Unlock(buffer);
+            }
+        }
+
+        if (buffer)
+            IMFMediaBuffer_Release(buffer);
+    }
+
+    LeaveCriticalSection(&sink->cs);
+
+    return hr;
 }
 
 static HRESULT WINAPI wave_stream_sink_PlaceMarker(IMFStreamSink *iface, MFSTREAMSINK_MARKER_TYPE marker_type,
@@ -703,6 +861,10 @@ HRESULT WINAPI MFCreateWAVEMediaSink(IMFByteStream *bytestream, IMFMediaType *me
         goto failed;
     }
 
+    /* Update derived fields. */
+    object->fmt->nAvgBytesPerSec = object->fmt->nSamplesPerSec * object->fmt->nChannels * object->fmt->wBitsPerSample / 8;
+    object->fmt->nBlockAlign = object->fmt->nChannels * object->fmt->wBitsPerSample / 8;
+
     object->IMFFinalizableMediaSink_iface.lpVtbl = &wave_sink_vtbl;
     object->IMFMediaEventGenerator_iface.lpVtbl = &wave_sink_events_vtbl;
     object->IMFStreamSink_iface.lpVtbl = &wave_stream_sink_vtbl;




More information about the wine-cvs mailing list