[v5 PATCH 1/6] mfreadwrite: Pass source samples through decoder as they arrive.
Nikolay Sivov
nsivov at codeweavers.com
Mon Mar 23 10:48:18 CDT 2020
From: Derek Lesho <dlesho at codeweavers.com>
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
v5:
- fixed a leak introduced in v4
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 | 132 ++++++++++++++++++++++++++++++++++------
1 file changed, 114 insertions(+), 18 deletions(-)
diff --git a/dlls/mfreadwrite/main.c b/dlls/mfreadwrite/main.c
index d3c10a4d11..f1519d17a7 100644
--- a/dlls/mfreadwrite/main.c
+++ b/dlls/mfreadwrite/main.c
@@ -366,6 +366,100 @@ 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)))
+ {
+ if (out_buffer.pSample)
+ IMFSample_Release(out_buffer.pSample);
+ 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 +487,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 +504,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 +524,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