[v4 PATCH 1/6] mfreadwrite: Pass source samples through decoder as they arrive.

Nikolay Sivov nsivov at codeweavers.com
Mon Mar 23 08:22:11 CDT 2020


From: Derek Lesho <dlesho at codeweavers.com>

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

v4:

- changed decoder calls logic;
- added support for external samples;
- now pulling all samples right on EOS event.

v3:

- moved decoding calls to event handler, queue now always contains processed samples;
- removed draining logic for now, I believe we can do that explicitly on ReadSample() or
  on EndOfStream instead. Same helper could be used for sync/async read and EOS event;
- added a check for output transform flags;

 dlls/mfreadwrite/main.c | 128 ++++++++++++++++++++++++++++++++++------
 1 file changed, 110 insertions(+), 18 deletions(-)

diff --git a/dlls/mfreadwrite/main.c b/dlls/mfreadwrite/main.c
index d3c10a4d11..aa46ac188b 100644
--- a/dlls/mfreadwrite/main.c
+++ b/dlls/mfreadwrite/main.c
@@ -366,6 +366,96 @@ static ULONG WINAPI source_reader_stream_events_callback_Release(IMFAsyncCallbac
     return IMFSourceReader_Release(&reader->IMFSourceReader_iface);
 }
 
+static void source_reader_queue_sample(struct media_stream *stream, IMFSample *sample)
+{
+    struct sample *pending_sample;
+
+    if (!sample)
+        return;
+
+    pending_sample = heap_alloc(sizeof(*pending_sample));
+    pending_sample->sample = sample;
+    IMFSample_AddRef(pending_sample->sample);
+
+    list_add_tail(&stream->samples, &pending_sample->entry);
+}
+
+static HRESULT source_reader_pull_stream_samples(struct media_stream *stream)
+{
+    MFT_OUTPUT_STREAM_INFO stream_info = { 0 };
+    MFT_OUTPUT_DATA_BUFFER out_buffer;
+    IMFMediaBuffer *buffer;
+    DWORD status;
+    HRESULT hr;
+
+    if (FAILED(hr = IMFTransform_GetOutputStreamInfo(stream->decoder, 0, &stream_info)))
+    {
+        WARN("Failed to get output stream info, hr %#x.\n", hr);
+        return hr;
+    }
+
+    for (;;)
+    {
+        memset(&out_buffer, 0, sizeof(out_buffer));
+
+        if (!(stream_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
+        {
+            if (FAILED(hr = MFCreateSample(&out_buffer.pSample)))
+                break;
+
+            if (FAILED(hr = MFCreateAlignedMemoryBuffer(stream_info.cbSize, stream_info.cbAlignment, &buffer)))
+            {
+                IMFSample_Release(out_buffer.pSample);
+                break;
+            }
+
+            IMFSample_AddBuffer(out_buffer.pSample, buffer);
+            IMFMediaBuffer_Release(buffer);
+        }
+
+        if (FAILED(hr = IMFTransform_ProcessOutput(stream->decoder, 0, 1, &out_buffer, &status)))
+            break;
+
+        source_reader_queue_sample(stream, out_buffer.pSample);
+        if (out_buffer.pSample)
+            IMFSample_Release(out_buffer.pSample);
+        if (out_buffer.pEvents)
+            IMFCollection_Release(out_buffer.pEvents);
+    }
+
+    return hr;
+}
+
+static HRESULT source_reader_process_sample(struct media_stream *stream, IMFSample *sample)
+{
+    HRESULT hr;
+
+    if (!stream->decoder)
+    {
+        source_reader_queue_sample(stream, sample);
+        return S_OK;
+    }
+
+    /* It's assumed that decoder has 1 input and 1 output, both id's are 0. */
+
+    hr = source_reader_pull_stream_samples(stream);
+    if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
+    {
+        if (FAILED(hr = IMFTransform_ProcessInput(stream->decoder, 0, sample, 0)))
+        {
+            WARN("Transform failed to process input, hr %#x.\n", hr);
+            return hr;
+        }
+
+        if ((hr = source_reader_pull_stream_samples(stream)) == MF_E_TRANSFORM_NEED_MORE_INPUT)
+            return S_OK;
+    }
+    else
+        WARN("Transform failed to process output, hr %#x.\n", hr);
+
+    return hr;
+}
+
 static HRESULT source_reader_media_sample_handler(struct source_reader *reader, IMFMediaStream *stream,
         IMFMediaEvent *event)
 {
@@ -393,21 +483,14 @@ static HRESULT source_reader_media_sample_handler(struct source_reader *reader,
     {
         if (id == reader->streams[i].id)
         {
-            struct sample *pending_sample;
-
-            if (!(pending_sample = heap_alloc(sizeof(*pending_sample))))
-            {
-                hr = E_OUTOFMEMORY;
-                goto failed;
-            }
+            EnterCriticalSection(&reader->streams[i].cs);
 
-            pending_sample->sample = sample;
-            IMFSample_AddRef(pending_sample->sample);
+            hr = source_reader_process_sample(&reader->streams[i], sample);
 
-            EnterCriticalSection(&reader->streams[i].cs);
-            list_add_tail(&reader->streams[i].samples, &pending_sample->entry);
             LeaveCriticalSection(&reader->streams[i].cs);
 
+            /* FIXME: propagate processing errors? */
+
             WakeAllConditionVariable(&reader->streams[i].sample_event);
 
             break;
@@ -417,7 +500,6 @@ static HRESULT source_reader_media_sample_handler(struct source_reader *reader,
     if (i == reader->stream_count)
         WARN("Stream with id %#x was not present in presentation descriptor.\n", id);
 
-failed:
     IMFSample_Release(sample);
 
     return hr;
@@ -438,26 +520,36 @@ static HRESULT source_reader_media_stream_state_handler(struct source_reader *re
 
     for (i = 0; i < reader->stream_count; ++i)
     {
-        if (id == reader->streams[i].id)
+        struct media_stream *stream = &reader->streams[i];
+
+        if (id == stream->id)
         {
-            EnterCriticalSection(&reader->streams[i].cs);
+            EnterCriticalSection(&stream->cs);
 
             switch (event)
             {
                 case MEEndOfStream:
-                    reader->streams[i].state = STREAM_STATE_EOS;
+                    stream->state = STREAM_STATE_EOS;
+
+                    if (stream->decoder && SUCCEEDED(IMFTransform_ProcessMessage(stream->decoder,
+                            MFT_MESSAGE_COMMAND_DRAIN, 0)))
+                    {
+                        if ((hr = source_reader_pull_stream_samples(stream)) != MF_E_TRANSFORM_NEED_MORE_INPUT)
+                            WARN("Failed to pull pending samples, hr %#x.\n", hr);
+                    }
+
                     break;
                 case MEStreamSeeked:
                 case MEStreamStarted:
-                    reader->streams[i].state = STREAM_STATE_READY;
+                    stream->state = STREAM_STATE_READY;
                     break;
                 default:
                     ;
             }
 
-            LeaveCriticalSection(&reader->streams[i].cs);
+            LeaveCriticalSection(&stream->cs);
 
-            WakeAllConditionVariable(&reader->streams[i].sample_event);
+            WakeAllConditionVariable(&stream->sample_event);
 
             break;
         }
-- 
2.25.1




More information about the wine-devel mailing list