[PATCH 2/2] winegstreamer: Add helper for GstBuffer <-> IMFSample conversion.

Derek Lesho dlesho at codeweavers.com
Tue Mar 24 15:45:11 CDT 2020


On 3/24/20 3:37 PM, Zebediah Figura wrote:

> On 3/24/20 2:39 PM, Derek Lesho wrote:
>> Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
>> ---
>>   dlls/winegstreamer/gst_private.h |   2 +
>>   dlls/winegstreamer/mfplat.c      | 162 +++++++++++++++++++++++++++++++
>>   2 files changed, 164 insertions(+)
>>
>> diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
>> index a6c3fd3784..13ba467a9e 100644
>> --- a/dlls/winegstreamer/gst_private.h
>> +++ b/dlls/winegstreamer/gst_private.h
>> @@ -57,5 +57,7 @@ extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
>>   
>>   IMFMediaType* media_type_from_caps(GstCaps *caps);
>>   GstCaps *caps_from_media_type(IMFMediaType *type);
>> +IMFSample* mf_sample_from_gst_buffer(GstBuffer *in);
>> +GstBuffer* gst_buffer_from_mf_sample(IMFSample *in);
>>   
>>   #endif /* __GST_PRIVATE_INCLUDED__ */
>> diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
>> index a6f4fbc2ec..e66bc3ffe6 100644
>> --- a/dlls/winegstreamer/mfplat.c
>> +++ b/dlls/winegstreamer/mfplat.c
>> @@ -964,3 +964,165 @@ GstCaps *caps_from_media_type(IMFMediaType *type)
>>       ERR("Unrecognized major type %s\n", debugstr_guid(&major_type));
>>       return NULL;
>>   }
>> +
>> +/* IMFSample = GstBuffer
>> +   IMFBuffer = GstMemory */
> IMFBuffer isn't an interface.
>
> I'm not sure that this comment is especially useful anyway, though.
That is a typo, but in general I think it helps avoid confusion between 
gstreamer buffers and media foundation buffers.
>
>> +
>> +/* TODO: Future optimization could be to create a custom
>> +   IMFMediaBuffer wrapper around GstMemory, and to utilize
>> +   gst_memory_new_wrapped on IMFMediaBuffer data */
> This seems like a better idea than what's done below; any particular
> reason why not?
Mainly because this way is simpler and works fine for now.  Also, 
Microsoft's decoders which I've looked at have the user of the transform 
allocate the output buffers, and this optimization wouldn't work if we 
wanted to match that.
>> +
>> +IMFSample* mf_sample_from_gst_buffer(GstBuffer *gst_buffer)
>> +{
>> +    IMFSample *out = NULL;
>> +    LONGLONG duration, time;
>> +    int buffer_count;
>> +    HRESULT hr;
>> +
>> +    if (FAILED(hr = MFCreateSample(&out)))
>> +        goto fail;
>> +
>> +    duration = GST_BUFFER_DURATION(gst_buffer);
>> +    time = GST_BUFFER_PTS(gst_buffer);
>> +
>> +    if (FAILED(IMFSample_SetSampleDuration(out, duration / 100)))
>> +        goto fail;
>> +
>> +    if (FAILED(IMFSample_SetSampleTime(out, time / 100)))
>> +        goto fail;
>> +
>> +    buffer_count = gst_buffer_n_memory(gst_buffer);
>> +
>> +    for (unsigned int i = 0; i < buffer_count; i++)
>> +    {
>> +        GstMemory *memory = gst_buffer_get_memory(gst_buffer, i);
>> +        IMFMediaBuffer *mf_buffer = NULL;
>> +        GstMapInfo map_info;
>> +        BYTE *buf_data;
>> +
>> +        if (!memory)
>> +        {
>> +            hr = ERROR_INTERNAL_ERROR;
> That's not an HRESULT.
oof, yeah I'll fix that.
>
>> +            goto loop_done;
>> +        }
>> +
>> +        if (!(gst_memory_map(memory, &map_info, GST_MAP_READ)))
>> +        {
>> +            hr = ERROR_INTERNAL_ERROR;
>> +            goto loop_done;
>> +        }
>> +
>> +        if (FAILED(hr = MFCreateMemoryBuffer(map_info.maxsize, &mf_buffer)))
>> +        {
>> +            gst_memory_unmap(memory, &map_info);
>> +            goto loop_done;
>> +        }
>> +
>> +        if (FAILED(hr = IMFMediaBuffer_Lock(mf_buffer, &buf_data, NULL, NULL)))
>> +        {
>> +            gst_memory_unmap(memory, &map_info);
>> +            goto loop_done;
>> +        }
>> +
>> +        memcpy(buf_data, map_info.data, map_info.size);
>> +
>> +        gst_memory_unmap(memory, &map_info);
>> +
>> +        if (FAILED(hr = IMFMediaBuffer_Unlock(mf_buffer)))
>> +            goto loop_done;
>> +
>> +        if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(mf_buffer, map_info.size)))
>> +            goto loop_done;
>> +
>> +        if (FAILED(hr = IMFSample_AddBuffer(out, mf_buffer)))
>> +            goto loop_done;
>> +
>> +        loop_done:
>> +        if (mf_buffer)
>> +            IMFMediaBuffer_Release(mf_buffer);
>> +        if (memory)
>> +            gst_memory_unref(memory);
>> +        if (FAILED(hr))
>> +            goto fail;
>> +    }
>> +
>> +    return out;
>> +    fail:
>> +    ERR("Failed to copy IMFSample to GstBuffer, hr = %#x\n", hr);
>> +    IMFSample_Release(out);
>> +    return NULL;
>> +}
>> +
>> +GstBuffer* gst_buffer_from_mf_sample(IMFSample *mf_sample)
>> +{
>> +    GstBuffer *out = gst_buffer_new();
>> +    IMFMediaBuffer *mf_buffer = NULL;
>> +    LONGLONG duration, time;
>> +    DWORD buffer_count;
>> +    HRESULT hr;
>> +
>> +    if (FAILED(hr = IMFSample_GetSampleDuration(mf_sample, &duration)))
>> +        goto fail;
>> +
>> +    if (FAILED(hr = IMFSample_GetSampleTime(mf_sample, &time)))
>> +        goto fail;
>> +
>> +    GST_BUFFER_DURATION(out) = duration;
>> +    GST_BUFFER_PTS(out) = time * 100;
>> +
>> +    if (FAILED(hr = IMFSample_GetBufferCount(mf_sample, &buffer_count)))
>> +        goto fail;
>> +
>> +    for (unsigned int i = 0; i < buffer_count; i++)
>> +    {
>> +        DWORD buffer_max_size, buffer_size;
>> +        GstMapInfo map_info;
>> +        GstMemory *memory;
>> +        BYTE *buf_data;
>> +
>> +        if (FAILED(hr = IMFSample_GetBufferByIndex(mf_sample, i, &mf_buffer)))
>> +            goto fail;
>> +
>> +        if (FAILED(hr = IMFMediaBuffer_GetMaxLength(mf_buffer, &buffer_max_size)))
>> +            goto fail;
>> +
>> +        if (FAILED(hr = IMFMediaBuffer_GetCurrentLength(mf_buffer, &buffer_size)))
>> +            goto fail;
>> +
>> +        memory = gst_allocator_alloc(NULL, buffer_size, NULL);
>> +        gst_memory_resize(memory, 0, buffer_size);
> Why is this call to gst_memory_resize() here?
I think I planned on using buffer_max_size for the allocation, but yeah 
that shouldn't matter and I'll remove it.
>
>> +
>> +        if (!(gst_memory_map(memory, &map_info, GST_MAP_WRITE)))
>> +        {
>> +            hr = ERROR_INTERNAL_ERROR;
>> +            goto fail;
>> +        }
>> +
>> +        if (FAILED(hr = IMFMediaBuffer_Lock(mf_buffer, &buf_data, NULL, NULL)))
>> +            goto fail;
>> +
>> +        memcpy(map_info.data, buf_data, buffer_size);
>> +
>> +        if (FAILED(hr = IMFMediaBuffer_Unlock(mf_buffer)))
>> +            goto fail;
>> +
>> +        if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(mf_buffer, buffer_size)))
>> +            goto fail;
>> +
>> +        gst_memory_unmap(memory, &map_info);
>> +
>> +        gst_buffer_append_memory(out, memory);
>> +
>> +        IMFMediaBuffer_Release(mf_buffer);
>> +        mf_buffer = NULL;
>> +    }
>> +
>> +    return out;
>> +
>> +    fail:
>> +    ERR("Failed to copy IMFSample to GstBuffer, hr = %#x\n", hr);
>> +    if (mf_buffer)
>> +        IMFMediaBuffer_Release(mf_buffer);
>> +    gst_buffer_unref(out);
>> +    return NULL;
>> +}
>>



More information about the wine-devel mailing list