d3dx9: Unify calling parse_mesh helper functions.
[wine.git] / dlls / winegstreamer / h264_decoder.c
blob5c48130eee92d9f1125a1456f00030f93fe0b949
1 /* H264 Decoder Transform
3 * Copyright 2022 RĂ©mi Bernon for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "gst_private.h"
22 #include "mfapi.h"
23 #include "mferror.h"
24 #include "mfobjects.h"
25 #include "mftransform.h"
27 #include "wine/debug.h"
29 #include "initguid.h"
31 #include "codecapi.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
34 WINE_DECLARE_DEBUG_CHANNEL(winediag);
36 #define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment)))
38 static const GUID *const h264_decoder_input_types[] =
40 &MFVideoFormat_H264,
41 &MFVideoFormat_H264_ES,
43 static const GUID *const h264_decoder_output_types[] =
45 &MFVideoFormat_NV12,
46 &MFVideoFormat_YV12,
47 &MFVideoFormat_IYUV,
48 &MFVideoFormat_I420,
49 &MFVideoFormat_YUY2,
52 struct h264_decoder
54 IMFTransform IMFTransform_iface;
55 LONG refcount;
57 IMFAttributes *attributes;
58 IMFAttributes *output_attributes;
60 UINT64 sample_time;
61 IMFMediaType *input_type;
62 MFT_INPUT_STREAM_INFO input_info;
63 IMFMediaType *output_type;
64 MFT_OUTPUT_STREAM_INFO output_info;
65 IMFMediaType *stream_type;
67 wg_transform_t wg_transform;
68 struct wg_sample_queue *wg_sample_queue;
70 IMFVideoSampleAllocatorEx *allocator;
71 BOOL allocator_initialized;
72 IMFTransform *copier;
73 IMFMediaBuffer *temp_buffer;
76 static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
78 return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface);
81 static HRESULT try_create_wg_transform(struct h264_decoder *decoder)
83 /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput
84 * return values, it calls them in a specific order and expects the decoder
85 * transform to be able to queue its input buffers. We need to use a buffer list
86 * to match its expectations.
88 struct wg_transform_attrs attrs =
90 .output_plane_align = 15,
91 .input_queue_length = 15,
93 struct wg_format input_format;
94 struct wg_format output_format;
95 UINT32 low_latency;
97 if (decoder->wg_transform)
98 wg_transform_destroy(decoder->wg_transform);
99 decoder->wg_transform = 0;
101 mf_media_type_to_wg_format(decoder->input_type, &input_format);
102 if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
103 return MF_E_INVALIDMEDIATYPE;
105 mf_media_type_to_wg_format(decoder->output_type, &output_format);
106 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
107 return MF_E_INVALIDMEDIATYPE;
109 /* Don't force any specific size, H264 streams already have the metadata for it
110 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
112 output_format.u.video.width = 0;
113 output_format.u.video.height = 0;
114 output_format.u.video.fps_d = 0;
115 output_format.u.video.fps_n = 0;
117 if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency)))
118 attrs.low_latency = !!low_latency;
120 if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs)))
121 return E_FAIL;
123 return S_OK;
126 static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType *media_type)
128 IMFMediaType *default_type = decoder->output_type;
129 UINT32 value, width, height;
130 MFVideoArea aperture;
131 UINT64 ratio;
132 GUID subtype;
133 HRESULT hr;
135 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
136 return hr;
138 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio)))
140 if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio)))
141 ratio = (UINT64)1920 << 32 | 1080;
142 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio)))
143 return hr;
145 width = ratio >> 32;
146 height = ratio;
148 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL)))
150 if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio)))
151 ratio = (UINT64)30000 << 32 | 1001;
152 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio)))
153 return hr;
156 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL)))
158 if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio)))
159 ratio = (UINT64)1 << 32 | 1;
160 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio)))
161 return hr;
164 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL)))
166 if (FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value)))
167 return hr;
168 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value)))
169 return hr;
172 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL)))
174 if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG *)&value)))
175 return hr;
176 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value)))
177 return hr;
180 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL)))
182 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value)))
183 value = MFVideoInterlace_MixedInterlaceOrProgressive;
184 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value)))
185 return hr;
188 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL)))
190 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value)))
191 value = 1;
192 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value)))
193 return hr;
196 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL)))
198 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value)))
199 value = 0;
200 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value)))
201 return hr;
204 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL)))
206 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value)))
207 value = 1;
208 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value)))
209 return hr;
212 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL))
213 && SUCCEEDED(hr = IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
214 (BYTE *)&aperture, sizeof(aperture), &value)))
216 if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
217 (BYTE *)&aperture, sizeof(aperture))))
218 return hr;
221 return S_OK;
224 static HRESULT init_allocator(struct h264_decoder *decoder)
226 HRESULT hr;
228 if (decoder->allocator_initialized)
229 return S_OK;
231 if (FAILED(hr = IMFTransform_SetInputType(decoder->copier, 0, decoder->output_type, 0)))
232 return hr;
233 if (FAILED(hr = IMFTransform_SetOutputType(decoder->copier, 0, decoder->output_type, 0)))
234 return hr;
236 if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder->allocator, 10, 10,
237 decoder->attributes, decoder->output_type)))
238 return hr;
239 decoder->allocator_initialized = TRUE;
240 return S_OK;
243 static void uninit_allocator(struct h264_decoder *decoder)
245 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(decoder->allocator);
246 decoder->allocator_initialized = FALSE;
249 static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
251 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
253 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
255 if (IsEqualGUID(iid, &IID_IUnknown) ||
256 IsEqualGUID(iid, &IID_IMFTransform))
257 *out = &decoder->IMFTransform_iface;
258 else
260 *out = NULL;
261 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
262 return E_NOINTERFACE;
265 IUnknown_AddRef((IUnknown *)*out);
266 return S_OK;
269 static ULONG WINAPI transform_AddRef(IMFTransform *iface)
271 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
272 ULONG refcount = InterlockedIncrement(&decoder->refcount);
274 TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount);
276 return refcount;
279 static ULONG WINAPI transform_Release(IMFTransform *iface)
281 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
282 ULONG refcount = InterlockedDecrement(&decoder->refcount);
284 TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount);
286 if (!refcount)
288 IMFTransform_Release(decoder->copier);
289 IMFVideoSampleAllocatorEx_Release(decoder->allocator);
290 if (decoder->temp_buffer)
291 IMFMediaBuffer_Release(decoder->temp_buffer);
292 if (decoder->wg_transform)
293 wg_transform_destroy(decoder->wg_transform);
294 if (decoder->input_type)
295 IMFMediaType_Release(decoder->input_type);
296 if (decoder->output_type)
297 IMFMediaType_Release(decoder->output_type);
298 if (decoder->output_attributes)
299 IMFAttributes_Release(decoder->output_attributes);
300 if (decoder->attributes)
301 IMFAttributes_Release(decoder->attributes);
302 wg_sample_queue_destroy(decoder->wg_sample_queue);
303 free(decoder);
306 return refcount;
309 static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
310 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
312 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
313 iface, input_minimum, input_maximum, output_minimum, output_maximum);
314 *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
315 return S_OK;
318 static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
320 TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
321 *inputs = *outputs = 1;
322 return S_OK;
325 static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
326 DWORD output_size, DWORD *outputs)
328 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
329 input_size, inputs, output_size, outputs);
330 return E_NOTIMPL;
333 static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
335 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
337 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
339 *info = decoder->input_info;
340 return S_OK;
343 static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
345 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
347 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
349 *info = decoder->output_info;
350 return S_OK;
353 static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
355 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
357 FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes);
359 if (!attributes)
360 return E_POINTER;
362 IMFAttributes_AddRef((*attributes = decoder->attributes));
363 return S_OK;
366 static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
368 TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
369 return E_NOTIMPL;
372 static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
374 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
376 FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes);
378 if (!attributes)
379 return E_POINTER;
380 if (id)
381 return MF_E_INVALIDSTREAMNUMBER;
383 IMFAttributes_AddRef((*attributes = decoder->output_attributes));
384 return S_OK;
387 static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
389 TRACE("iface %p, id %#lx.\n", iface, id);
390 return E_NOTIMPL;
393 static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
395 TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
396 return E_NOTIMPL;
399 static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
400 IMFMediaType **type)
402 IMFMediaType *media_type;
403 const GUID *subtype;
404 HRESULT hr;
406 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
408 *type = NULL;
410 if (index >= ARRAY_SIZE(h264_decoder_input_types))
411 return MF_E_NO_MORE_TYPES;
412 subtype = h264_decoder_input_types[index];
414 if (FAILED(hr = MFCreateMediaType(&media_type)))
415 return hr;
417 if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) &&
418 SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
419 IMFMediaType_AddRef((*type = media_type));
421 IMFMediaType_Release(media_type);
422 return hr;
425 static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id,
426 DWORD index, IMFMediaType **type)
428 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
429 IMFMediaType *media_type;
430 const GUID *output_type;
431 HRESULT hr;
433 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
435 if (!decoder->input_type)
436 return MF_E_TRANSFORM_TYPE_NOT_SET;
438 *type = NULL;
440 if (index >= ARRAY_SIZE(h264_decoder_output_types))
441 return MF_E_NO_MORE_TYPES;
442 output_type = h264_decoder_output_types[index];
444 if (FAILED(hr = MFCreateMediaType(&media_type)))
445 return hr;
447 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
448 goto done;
449 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type)))
450 goto done;
452 hr = fill_output_media_type(decoder, media_type);
454 done:
455 if (SUCCEEDED(hr))
456 IMFMediaType_AddRef((*type = media_type));
458 IMFMediaType_Release(media_type);
459 return hr;
462 static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
464 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
465 GUID major, subtype;
466 UINT64 frame_size;
467 HRESULT hr;
468 ULONG i;
470 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
472 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
473 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
474 return E_INVALIDARG;
476 if (!IsEqualGUID(&major, &MFMediaType_Video))
477 return MF_E_INVALIDMEDIATYPE;
479 for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i)
480 if (IsEqualGUID(&subtype, h264_decoder_input_types[i]))
481 break;
482 if (i == ARRAY_SIZE(h264_decoder_input_types))
483 return MF_E_INVALIDMEDIATYPE;
484 if (flags & MFT_SET_TYPE_TEST_ONLY)
485 return S_OK;
487 if (decoder->output_type)
489 IMFMediaType_Release(decoder->output_type);
490 decoder->output_type = NULL;
493 if (decoder->input_type)
494 IMFMediaType_Release(decoder->input_type);
495 IMFMediaType_AddRef((decoder->input_type = type));
497 if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
499 if (FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, frame_size)))
500 WARN("Failed to update stream type frame size, hr %#lx\n", hr);
501 decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2;
504 return S_OK;
507 static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
509 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
510 UINT64 frame_size, stream_frame_size;
511 GUID major, subtype;
512 HRESULT hr;
513 ULONG i;
515 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
517 if (!decoder->input_type)
518 return MF_E_TRANSFORM_TYPE_NOT_SET;
520 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
521 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
522 return hr;
524 if (!IsEqualGUID(&major, &MFMediaType_Video))
525 return MF_E_INVALIDMEDIATYPE;
527 for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i)
528 if (IsEqualGUID(&subtype, h264_decoder_output_types[i]))
529 break;
530 if (i == ARRAY_SIZE(h264_decoder_output_types))
531 return MF_E_INVALIDMEDIATYPE;
533 if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
534 return MF_E_INVALIDMEDIATYPE;
535 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &stream_frame_size))
536 && frame_size != stream_frame_size)
537 return MF_E_INVALIDMEDIATYPE;
538 if (flags & MFT_SET_TYPE_TEST_ONLY)
539 return S_OK;
541 if (decoder->output_type)
542 IMFMediaType_Release(decoder->output_type);
543 IMFMediaType_AddRef((decoder->output_type = type));
545 if (decoder->wg_transform)
547 struct wg_format output_format;
548 mf_media_type_to_wg_format(decoder->output_type, &output_format);
550 /* Don't force any specific size, H264 streams already have the metadata for it
551 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
553 output_format.u.video.width = 0;
554 output_format.u.video.height = 0;
555 output_format.u.video.fps_d = 0;
556 output_format.u.video.fps_n = 0;
558 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN
559 || !wg_transform_set_output_format(decoder->wg_transform, &output_format))
561 IMFMediaType_Release(decoder->output_type);
562 decoder->output_type = NULL;
563 return MF_E_INVALIDMEDIATYPE;
566 else if (FAILED(hr = try_create_wg_transform(decoder)))
568 IMFMediaType_Release(decoder->output_type);
569 decoder->output_type = NULL;
572 return hr;
575 static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
577 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
578 return E_NOTIMPL;
581 static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
583 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
584 HRESULT hr;
586 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
588 if (!decoder->output_type)
589 return MF_E_TRANSFORM_TYPE_NOT_SET;
591 if (FAILED(hr = MFCreateMediaType(type)))
592 return hr;
594 return IMFMediaType_CopyAllItems(decoder->output_type, (IMFAttributes *)*type);
597 static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
599 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
601 TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags);
603 if (!decoder->wg_transform)
604 return MF_E_TRANSFORM_TYPE_NOT_SET;
606 *flags = MFT_INPUT_STATUS_ACCEPT_DATA;
607 return S_OK;
610 static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
612 FIXME("iface %p, flags %p stub!\n", iface, flags);
613 return E_NOTIMPL;
616 static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
618 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
619 return E_NOTIMPL;
622 static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
624 FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
625 return E_NOTIMPL;
628 static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
630 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
631 HRESULT hr;
633 TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param);
635 switch (message)
637 case MFT_MESSAGE_SET_D3D_MANAGER:
638 if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(decoder->allocator, (IUnknown *)param)))
639 return hr;
641 uninit_allocator(decoder);
642 if (param)
643 decoder->output_info.dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
644 else
645 decoder->output_info.dwFlags &= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
646 return S_OK;
648 case MFT_MESSAGE_COMMAND_DRAIN:
649 return wg_transform_drain(decoder->wg_transform);
651 case MFT_MESSAGE_COMMAND_FLUSH:
652 return wg_transform_flush(decoder->wg_transform);
654 default:
655 FIXME("Ignoring message %#x.\n", message);
656 return S_OK;
660 static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
662 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
664 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
666 if (!decoder->wg_transform)
667 return MF_E_TRANSFORM_TYPE_NOT_SET;
669 return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue);
672 static HRESULT output_sample(struct h264_decoder *decoder, IMFSample **out, IMFSample *src_sample)
674 MFT_OUTPUT_DATA_BUFFER output[1];
675 IMFSample *sample;
676 DWORD status;
677 HRESULT hr;
679 if (FAILED(hr = init_allocator(decoder)))
681 ERR("Failed to initialize allocator, hr %#lx.\n", hr);
682 return hr;
684 if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(decoder->allocator, &sample)))
685 return hr;
687 if (FAILED(hr = IMFTransform_ProcessInput(decoder->copier, 0, src_sample, 0)))
689 IMFSample_Release(sample);
690 return hr;
692 output[0].pSample = sample;
693 if (FAILED(hr = IMFTransform_ProcessOutput(decoder->copier, 0, 1, output, &status)))
695 IMFSample_Release(sample);
696 return hr;
698 *out = sample;
699 return S_OK;
702 static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const struct wg_format *format)
704 UINT64 frame_size, frame_rate;
705 HRESULT hr;
707 if (decoder->stream_type)
708 IMFMediaType_Release(decoder->stream_type);
709 if (!(decoder->stream_type = mf_media_type_from_wg_format(format)))
710 return E_OUTOFMEMORY;
712 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))
713 && FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, frame_rate)))
714 WARN("Failed to update stream type frame size, hr %#lx\n", hr);
716 if (FAILED(hr = IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &frame_size)))
717 return hr;
718 decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2;
719 uninit_allocator(decoder);
721 return MF_E_TRANSFORM_STREAM_CHANGE;
724 static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
725 MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
727 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
728 struct wg_format wg_format;
729 UINT32 sample_size;
730 LONGLONG duration;
731 IMFSample *sample;
732 UINT64 frame_size, frame_rate;
733 GUID subtype;
734 DWORD size;
735 HRESULT hr;
737 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
739 if (count != 1)
740 return E_INVALIDARG;
742 if (!decoder->wg_transform)
743 return MF_E_TRANSFORM_TYPE_NOT_SET;
745 *status = samples->dwStatus = 0;
746 if (!(sample = samples->pSample) && !(decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
747 return E_INVALIDARG;
749 if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype)))
750 return hr;
751 if (FAILED(hr = IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &frame_size)))
752 return hr;
753 if (FAILED(hr = MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size, &sample_size)))
754 return hr;
756 if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)
758 if (decoder->temp_buffer)
760 if (FAILED(IMFMediaBuffer_GetMaxLength(decoder->temp_buffer, &size)) || size < sample_size)
762 IMFMediaBuffer_Release(decoder->temp_buffer);
763 decoder->temp_buffer = NULL;
766 if (!decoder->temp_buffer && FAILED(hr = MFCreateMemoryBuffer(sample_size, &decoder->temp_buffer)))
767 return hr;
768 if (FAILED(hr = MFCreateSample(&sample)))
769 return hr;
770 if (FAILED(hr = IMFSample_AddBuffer(sample, decoder->temp_buffer)))
772 IMFSample_Release(sample);
773 return hr;
777 if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, sample,
778 sample_size, &wg_format, &samples->dwStatus)))
780 wg_sample_queue_flush(decoder->wg_sample_queue, false);
782 if (FAILED(IMFMediaType_GetUINT64(decoder->input_type, &MF_MT_FRAME_RATE, &frame_rate)))
783 frame_rate = (UINT64)30000 << 32 | 1001;
785 duration = (UINT64)10000000 * (UINT32)frame_rate / (frame_rate >> 32);
786 if (FAILED(IMFSample_SetSampleTime(sample, decoder->sample_time)))
787 WARN("Failed to set sample time\n");
788 if (FAILED(IMFSample_SetSampleDuration(sample, duration)))
789 WARN("Failed to set sample duration\n");
790 decoder->sample_time += duration;
793 if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
795 samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
796 *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
797 hr = handle_stream_type_change(decoder, &wg_format);
800 if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)
802 if (hr == S_OK && FAILED(hr = output_sample(decoder, &samples->pSample, sample)))
803 ERR("Failed to output sample, hr %#lx.\n", hr);
804 IMFSample_Release(sample);
807 return hr;
810 static const IMFTransformVtbl transform_vtbl =
812 transform_QueryInterface,
813 transform_AddRef,
814 transform_Release,
815 transform_GetStreamLimits,
816 transform_GetStreamCount,
817 transform_GetStreamIDs,
818 transform_GetInputStreamInfo,
819 transform_GetOutputStreamInfo,
820 transform_GetAttributes,
821 transform_GetInputStreamAttributes,
822 transform_GetOutputStreamAttributes,
823 transform_DeleteInputStream,
824 transform_AddInputStreams,
825 transform_GetInputAvailableType,
826 transform_GetOutputAvailableType,
827 transform_SetInputType,
828 transform_SetOutputType,
829 transform_GetInputCurrentType,
830 transform_GetOutputCurrentType,
831 transform_GetInputStatus,
832 transform_GetOutputStatus,
833 transform_SetOutputBounds,
834 transform_ProcessEvent,
835 transform_ProcessMessage,
836 transform_ProcessInput,
837 transform_ProcessOutput,
840 HRESULT h264_decoder_create(REFIID riid, void **ret)
842 static const struct wg_format output_format =
844 .major_type = WG_MAJOR_TYPE_VIDEO,
845 .u.video =
847 .format = WG_VIDEO_FORMAT_I420,
848 .width = 1920,
849 .height = 1080,
852 static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264};
853 struct wg_transform_attrs attrs = {0};
854 wg_transform_t transform;
855 struct h264_decoder *decoder;
856 HRESULT hr;
858 TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
860 if (!(transform = wg_transform_create(&input_format, &output_format, &attrs)))
862 ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n");
863 return E_FAIL;
865 wg_transform_destroy(transform);
867 if (!(decoder = calloc(1, sizeof(*decoder))))
868 return E_OUTOFMEMORY;
870 decoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
871 decoder->refcount = 1;
873 decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
874 | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE;
875 decoder->input_info.cbSize = 0x1000;
876 decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
877 | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
878 decoder->output_info.cbSize = 1920 * 1088 * 2;
880 if (FAILED(hr = MFCreateMediaType(&decoder->stream_type)))
881 goto failed;
882 if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16)))
883 goto failed;
884 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0)))
885 goto failed;
886 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE)))
887 goto failed;
888 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &AVDecVideoAcceleration_H264, TRUE)))
889 goto failed;
891 if (FAILED(hr = MFCreateAttributes(&decoder->output_attributes, 0)))
892 goto failed;
893 if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue)))
894 goto failed;
895 if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&decoder->allocator)))
896 goto failed;
897 if (FAILED(hr = MFCreateSampleCopierMFT(&decoder->copier)))
898 goto failed;
900 *ret = &decoder->IMFTransform_iface;
901 TRACE("Created decoder %p\n", *ret);
902 return S_OK;
904 failed:
905 if (decoder->allocator)
906 IMFVideoSampleAllocatorEx_Release(decoder->allocator);
907 if (decoder->wg_sample_queue)
908 wg_sample_queue_destroy(decoder->wg_sample_queue);
909 if (decoder->output_attributes)
910 IMFAttributes_Release(decoder->output_attributes);
911 if (decoder->attributes)
912 IMFAttributes_Release(decoder->attributes);
913 if (decoder->stream_type)
914 IMFMediaType_Release(decoder->stream_type);
915 free(decoder);
916 return hr;