diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 69633134f5c..1727ff1e90c 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -1136,9 +1136,78 @@ static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMF return hr; } +static unsigned int sample_get_total_length(struct sample *sample) +{ + DWORD total_length = 0, length; + size_t i; + + for (i = 0; i < sample->buffer_count; ++i) + { + length = 0; + if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length))) + total_length += length; + } + + return total_length; +} + +static HRESULT sample_copy_to_buffer(struct sample *sample, IMFMediaBuffer *buffer) +{ + DWORD total_length, dst_length, dst_current_length, src_max_length, current_length; + BYTE *src_ptr, *dst_ptr; + BOOL locked; + HRESULT hr; + size_t i; + + total_length = sample_get_total_length(sample); + dst_current_length = 0; + + dst_ptr = NULL; + dst_length = current_length = 0; + locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length)); + if (locked) + { + if (dst_length < total_length) + hr = MF_E_BUFFERTOOSMALL; + else if (dst_ptr) + { + for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i) + { + src_ptr = NULL; + src_max_length = current_length = 0; + if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length))) + { + if (src_ptr) + { + if (current_length > dst_length) + hr = MF_E_BUFFERTOOSMALL; + else if (current_length) + { + memcpy(dst_ptr, src_ptr, current_length); + dst_length -= current_length; + dst_current_length += current_length; + dst_ptr += current_length; + } + } + IMFMediaBuffer_Unlock(sample->buffers[i]); + } + } + } + } + + IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length); + + if (locked) + IMFMediaBuffer_Unlock(buffer); + + return hr; +} + static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer) { struct sample *sample = impl_from_IMFSample(iface); + unsigned int total_length, i; + IMFMediaBuffer *dest_buffer; HRESULT hr = S_OK; TRACE("%p, %p.\n", iface, buffer); @@ -1147,16 +1216,30 @@ static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMedi if (sample->buffer_count == 0) hr = E_UNEXPECTED; - else if (sample->buffer_count == 1) + else if (sample->buffer_count > 1) + { + total_length = sample_get_total_length(sample); + if (SUCCEEDED(hr = MFCreateMemoryBuffer(total_length, &dest_buffer))) + { + if (SUCCEEDED(hr = sample_copy_to_buffer(sample, dest_buffer))) + { + for (i = 0; i < sample->buffer_count; ++i) + IMFMediaBuffer_Release(sample->buffers[i]); + + sample->buffers[0] = dest_buffer; + IMFMediaBuffer_AddRef(sample->buffers[0]); + + sample->buffer_count = 1; + } + IMFMediaBuffer_Release(dest_buffer); + } + } + + if (SUCCEEDED(hr)) { *buffer = sample->buffers[0]; IMFMediaBuffer_AddRef(*buffer); } - else - { - FIXME("Samples with multiple buffers are not supported.\n"); - hr = E_NOTIMPL; - } LeaveCriticalSection(&sample->attributes.cs); @@ -1225,21 +1308,6 @@ static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface) return S_OK; } -static DWORD sample_get_total_length(struct sample *sample) -{ - DWORD total_length = 0, length; - size_t i; - - for (i = 0; i < sample->buffer_count; ++i) - { - length = 0; - if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length))) - total_length += length; - } - - return total_length; -} - static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length) { struct sample *sample = impl_from_IMFSample(iface); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 008aa05c302..21105f5ce52 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -1778,7 +1778,7 @@ static void test_system_memory_buffer(void) static void test_sample(void) { static const DWORD test_pattern = 0x22222222; - IMFMediaBuffer *buffer, *buffer2; + IMFMediaBuffer *buffer, *buffer2, *buffer3; DWORD count, flags, length; IMFAttributes *attributes; IMFSample *sample; @@ -1998,9 +1998,15 @@ static void test_sample(void) ok(buffer2 == buffer, "Unexpected buffer instance.\n"); IMFMediaBuffer_Release(buffer2); + hr = IMFMediaBuffer_SetCurrentLength(buffer, 3); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = MFCreateMemoryBuffer(16, &buffer2); ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr); + hr = IMFMediaBuffer_SetCurrentLength(buffer2, 4); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = IMFSample_AddBuffer(sample, buffer2); ok(hr == S_OK, "Failed to add buffer, hr %#x.\n", hr); IMFMediaBuffer_Release(buffer2); @@ -2009,15 +2015,22 @@ static void test_sample(void) ok(hr == S_OK, "Failed to get buffer count, hr %#x.\n", hr); ok(count == 2, "Unexpected buffer count %u.\n", count); - hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer2); -todo_wine + hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer3); ok(hr == S_OK, "Failed to convert, hr %#x.\n", hr); + + hr = IMFMediaBuffer_GetMaxLength(buffer3, &length); + ok(hr == S_OK, "Failed to get maximum length, hr %#x.\n", hr); + ok(length == 7, "Unexpected length %u.\n", length); + + hr = IMFMediaBuffer_GetCurrentLength(buffer3, &length); + ok(hr == S_OK, "Failed to get maximum length, hr %#x.\n", hr); + ok(length == 7, "Unexpected length %u.\n", length); + if (SUCCEEDED(hr)) - IMFMediaBuffer_Release(buffer2); + IMFMediaBuffer_Release(buffer3); hr = IMFSample_GetBufferCount(sample, &count); ok(hr == S_OK, "Failed to get buffer count, hr %#x.\n", hr); -todo_wine ok(count == 1, "Unexpected buffer count %u.\n", count); IMFMediaBuffer_Release(buffer);