Signed-off-by: Derek Lesho dlesho@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; +}