diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index 8e54a538f64..07c2517788c 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -771,22 +771,29 @@ 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); - DWORD length; - size_t i; TRACE("%p, %p.\n", iface, total_length); - *total_length = 0; - EnterCriticalSection(&sample->attributes.cs); - for (i = 0; i < sample->buffer_count; ++i) - { - if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length))) - *total_length += length; - } + *total_length = sample_get_total_length(sample); LeaveCriticalSection(&sample->attributes.cs); return S_OK; @@ -794,9 +801,61 @@ static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_lengt static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer) { - FIXME("%p, %p.\n", iface, buffer); + struct sample *sample = impl_from_IMFSample(iface); + 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; - return E_NOTIMPL; + TRACE("%p, %p.\n", iface, buffer); + + EnterCriticalSection(&sample->attributes.cs); + + 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); + + LeaveCriticalSection(&sample->attributes.cs); + + return hr; } static const IMFSampleVtbl samplevtbl = diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 36fe9dc8319..38713a4f445 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -1760,12 +1760,14 @@ static void test_system_memory_buffer(void) static void test_sample(void) { + static const DWORD test_pattern = 0x22222222; IMFMediaBuffer *buffer, *buffer2; DWORD count, flags, length; IMFAttributes *attributes; IMFSample *sample; LONGLONG time; HRESULT hr; + BYTE *data; hr = MFCreateSample( &sample ); ok(hr == S_OK, "got 0x%08x\n", hr); @@ -1868,6 +1870,94 @@ static void test_sample(void) IMFAttributes_Release(attributes); IMFSample_Release(sample); + /* CopyToBuffer() */ + hr = MFCreateSample(&sample); + ok(hr == S_OK, "Failed to create a sample, hr %#x.\n", hr); + + hr = MFCreateMemoryBuffer(16, &buffer2); + ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr); + + /* Sample with no buffers. */ + hr = IMFMediaBuffer_SetCurrentLength(buffer2, 1); + ok(hr == S_OK, "Failed to set current length, hr %#x.\n", hr); + hr = IMFSample_CopyToBuffer(sample, buffer2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = IMFMediaBuffer_GetCurrentLength(buffer2, &length); + ok(hr == S_OK, "Failed to get current length, hr %#x.\n", hr); + ok(!length, "Unexpected length %u.\n", length); + + /* Single buffer, larger destination. */ + hr = MFCreateMemoryBuffer(8, &buffer); + ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr); + + hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); + ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr); + *(DWORD *)data = 0x11111111; + hr = IMFMediaBuffer_Unlock(buffer); + ok(hr == S_OK, "Failed to unlock, hr %#x.\n", hr); + hr = IMFMediaBuffer_SetCurrentLength(buffer, 4); + ok(hr == S_OK, "Failed to set current length, hr %#x.\n", hr); + + hr = IMFSample_AddBuffer(sample, buffer); + ok(hr == S_OK, "Failed to add buffer, hr %#x.\n", hr); + + /* Existing content is overwritten. */ + hr = IMFMediaBuffer_SetCurrentLength(buffer2, 8); + ok(hr == S_OK, "Failed to set length, hr %#x.\n", hr); + + hr = IMFSample_CopyToBuffer(sample, buffer2); + ok(hr == S_OK, "Failed to copy to buffer, hr %#x.\n", hr); + + hr = IMFMediaBuffer_GetCurrentLength(buffer2, &length); + ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr); + ok(length == 4, "Unexpected buffer length %u.\n", length); + + /* Multiple buffers, matching total size. */ + hr = IMFSample_AddBuffer(sample, buffer); + ok(hr == S_OK, "Failed to add buffer, hr %#x.\n", hr); + + hr = IMFSample_GetBufferCount(sample, &count); + ok(hr == S_OK, "Failed to get buffer count, hr %#x.\n", hr); + ok(count == 2, "Unexpected buffer count %u.\n", count); + + hr = IMFMediaBuffer_SetCurrentLength(buffer, 8); + ok(hr == S_OK, "Failed to set current length, hr %#x.\n", hr); + + hr = IMFSample_CopyToBuffer(sample, buffer2); + ok(hr == S_OK, "Failed to copy to buffer, hr %#x.\n", hr); + + hr = IMFMediaBuffer_GetCurrentLength(buffer2, &length); + ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr); + ok(length == 16, "Unexpected buffer length %u.\n", length); + + hr = IMFSample_AddBuffer(sample, buffer); + ok(hr == S_OK, "Failed to add buffer, hr %#x.\n", hr); + + hr = IMFMediaBuffer_SetCurrentLength(buffer2, 1); + ok(hr == S_OK, "Failed to set buffer length, hr %#x.\n", hr); + + hr = IMFMediaBuffer_Lock(buffer2, &data, NULL, NULL); + ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr); + *(DWORD *)data = test_pattern; + hr = IMFMediaBuffer_Unlock(buffer2); + ok(hr == S_OK, "Failed to unlock buffer, hr %#x.\n", hr); + + hr = IMFSample_CopyToBuffer(sample, buffer2); + ok(hr == MF_E_BUFFERTOOSMALL, "Unexpected hr %#x.\n", hr); + + hr = IMFMediaBuffer_Lock(buffer2, &data, NULL, NULL); + ok(hr == S_OK, "Failed to lock buffer, hr %#x.\n", hr); + ok(!memcmp(data, &test_pattern, sizeof(test_pattern)), "Unexpected contents, %#x\n", *(DWORD *)data); + hr = IMFMediaBuffer_Unlock(buffer2); + ok(hr == S_OK, "Failed to unlock buffer, hr %#x.\n", hr); + + hr = IMFMediaBuffer_GetCurrentLength(buffer2, &length); + ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr); + ok(!length, "Unexpected buffer length %u.\n", length); + + IMFMediaBuffer_Release(buffer2); + IMFSample_Release(sample); + /* ConvertToContiguousBuffer() */ hr = MFCreateSample(&sample); ok(hr == S_OK, "Failed to create a sample, hr %#x.\n", hr);