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

Derek Lesho dlesho at codeweavers.com
Tue Mar 24 14:39:53 CDT 2020


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 */
+
+/* TODO: Future optimization could be to create a custom
+   IMFMediaBuffer wrapper around GstMemory, and to utilize
+   gst_memory_new_wrapped on IMFMediaBuffer data */
+
+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;
+            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);
+
+        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;
+}
-- 
2.25.1




More information about the wine-devel mailing list