From: Paul Gofman pgofman@codeweavers.com
--- dlls/winegstreamer/h264_decoder.c | 96 ++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 9 deletions(-)
diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c index c32e715d749..d7029cd42cb 100644 --- a/dlls/winegstreamer/h264_decoder.c +++ b/dlls/winegstreamer/h264_decoder.c @@ -64,6 +64,7 @@ struct h264_decoder
IMFDXGIDeviceManager *dxgi_manager; IMFVideoSampleAllocatorEx *allocator; + IMFMediaBuffer *temp_buffer; };
static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) @@ -242,6 +243,11 @@ static void free_allocator(struct h264_decoder *decoder) IMFVideoSampleAllocatorEx_Release(decoder->allocator); decoder->allocator = NULL; } + if (decoder->temp_buffer) + { + IMFMediaBuffer_Release(decoder->temp_buffer); + decoder->temp_buffer = NULL; + } }
static ULONG WINAPI transform_Release(IMFTransform *iface) @@ -640,6 +646,8 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS static HRESULT initialize_allocator(struct h264_decoder *decoder) { IMFAttributes *attributes = NULL; + UINT32 sample_size; + GUID subtype; HRESULT hr;
if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&decoder->allocator))) @@ -648,7 +656,16 @@ static HRESULT initialize_allocator(struct h264_decoder *decoder) goto done; if (FAILED(hr = MFCreateAttributes(&attributes, 0))) goto done; - hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder->allocator, 10, 10, attributes, decoder->output_type); + if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder->allocator, 10, 10, attributes, + decoder->output_type))) + goto done; + if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) + goto done; + if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, + decoder->wg_format.u.video.height, &sample_size))) + goto done; + + hr = MFCreateMemoryBuffer(sample_size, &decoder->temp_buffer); done: if (attributes) IMFAttributes_Release(attributes); @@ -657,6 +674,69 @@ done: return hr; }
+static HRESULT output_dxgi_sample(struct h264_decoder *decoder, IMFSample **out, IMFSample *src_sample) +{ + DWORD max_length, current_length, dst_length; + BYTE *dst_data, *buffer_start, *src_data; + IMF2DBuffer2 *dst_buffer = NULL; + IMFMediaBuffer *buffer = NULL; + LONG dst_pitch, row_count; + LONGLONG time; + HRESULT hr; + + if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(decoder->allocator, out))) + return hr; + if (FAILED(hr = IMFSample_DeleteAllItems(*out))) + goto done; + if (FAILED(hr = IMFSample_CopyAllItems(src_sample, (IMFAttributes *)*out))) + goto done; + if (SUCCEEDED(IMFSample_GetSampleTime(src_sample, &time))) + IMFSample_SetSampleTime(*out, time); + if (SUCCEEDED(IMFSample_GetSampleDuration(src_sample, &time))) + IMFSample_SetSampleDuration(*out, time); + if (FAILED(hr = IMFSample_GetBufferByIndex(*out, 0, &buffer))) + goto done; + if (FAILED(hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer2, (void **)&dst_buffer))) + goto done; + + if (FAILED(hr = IMFMediaBuffer_Lock(decoder->temp_buffer, &src_data, &max_length, ¤t_length))) + goto done; + + if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, current_length))) + { + IMFMediaBuffer_Unlock(decoder->temp_buffer); + goto done; + } + + if (FAILED(hr = IMF2DBuffer2_Lock2DSize(dst_buffer, MF2DBuffer_LockFlags_Write, &dst_data, + &dst_pitch, &buffer_start, &dst_length))) + { + IMFMediaBuffer_Unlock(decoder->temp_buffer); + goto done; + } + row_count = current_length / decoder->wg_format.u.video.width; + if (dst_length / dst_pitch != row_count) + { + ERR("Row count mismatch %ld vs %ld.\n", row_count, dst_length / dst_pitch); + IMFMediaBuffer_Unlock(decoder->temp_buffer); + IMF2DBuffer2_Unlock2D(dst_buffer); + goto done; + } + hr = MFCopyImage(dst_data, dst_pitch, src_data, decoder->wg_format.u.video.width, + decoder->wg_format.u.video.width, row_count); + + IMFMediaBuffer_Unlock(decoder->temp_buffer); + IMF2DBuffer2_Unlock2D(dst_buffer); +done: + if (dst_buffer) + IMF2DBuffer2_Release(dst_buffer); + if (buffer) + IMFMediaBuffer_Release(buffer); + if (FAILED(hr)) + IMFSample_Release(*out); + return hr; +} + static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { @@ -684,11 +764,10 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, ERR("Failed to initialize allocator, hr %#lx.\n", hr); return hr; } - if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(decoder->allocator, &sample))) - { - ERR("Failed to allocate sample, hr %#lx.\n", hr); + if (FAILED(hr = MFCreateSample(&sample))) + return hr; + if (FAILED(hr = IMFSample_AddBuffer(sample, decoder->temp_buffer))) return hr; - } } else { @@ -726,10 +805,9 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, done: if (decoder->dxgi_manager) { - if (hr == S_OK) - samples->pSample = sample; - else - IMFSample_Release(sample); + if (hr == S_OK && FAILED(hr = output_dxgi_sample(decoder, &samples->pSample, sample))) + ERR("Failed to output sample, hr %#lx.\n", hr); + IMFSample_Release(sample); }
return hr;