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

Zebediah Figura zfigura at codeweavers.com
Tue Mar 24 16:10:15 CDT 2020


On 3/24/20 3:45 PM, Derek Lesho wrote:
> 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.

If the optimization wouldn't work, then why mention it?

(Even better, you could mention why it wouldn't work, so that nobody is
tempted to try it.)

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