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

Derek Lesho dlesho at codeweavers.com
Mon Mar 23 10:28:07 CDT 2020


On 2020-03-23 08:22, Nikolay Sivov wrote:

> 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;
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;
>           }



More information about the wine-devel mailing list