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

Nikolay Sivov nsivov at codeweavers.com
Mon Mar 23 10:31:10 CDT 2020



On 3/23/20 6:28 PM, Derek Lesho wrote:
> 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

Right.

>> +
>> +        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.

Order doesn't matter, because both segments are protected with same section.

>> +
>> +                    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