On 2020-03-23 08:22, Nikolay Sivov wrote:
From: Derek Lesho dlesho@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@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;
It's probably important to free the sample we provide after ProcessOutput returns MF_E_TRANSFORM_NEEDS_MORE_INPUT
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;
ReadSample uses this state to set MF_SOURCE_READERF_ENDOFSTREAM. We don't want this flag to be set until the drain is complete.
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; }