winegstreamer: Replace pointers with handles in PE->Unix transition.
[wine.git] / dlls / winegstreamer / h264_decoder.c
blob6d8f2a146dad9b8900c1aac088c31d139721ad74
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 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
30 WINE_DECLARE_DEBUG_CHANNEL(winediag);
32 #define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment)))
34 static const GUID *const h264_decoder_input_types[] =
36 &MFVideoFormat_H264,
37 &MFVideoFormat_H264_ES,
39 static const GUID *const h264_decoder_output_types[] =
41 &MFVideoFormat_NV12,
42 &MFVideoFormat_YV12,
43 &MFVideoFormat_IYUV,
44 &MFVideoFormat_I420,
45 &MFVideoFormat_YUY2,
48 struct h264_decoder
50 IMFTransform IMFTransform_iface;
51 LONG refcount;
53 IMFAttributes *attributes;
54 IMFAttributes *output_attributes;
56 UINT64 sample_time;
57 IMFMediaType *input_type;
58 MFT_INPUT_STREAM_INFO input_info;
59 IMFMediaType *output_type;
60 MFT_OUTPUT_STREAM_INFO output_info;
61 IMFMediaType *stream_type;
63 wg_transform_t wg_transform;
64 struct wg_sample_queue *wg_sample_queue;
66 IMFVideoSampleAllocatorEx *allocator;
67 BOOL allocator_initialized;
68 IMFTransform *copier;
69 IMFMediaBuffer *temp_buffer;
72 static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
74 return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface);
77 static HRESULT try_create_wg_transform(struct h264_decoder *decoder)
79 /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput
80 * return values, it calls them in a specific order and expects the decoder
81 * transform to be able to queue its input buffers. We need to use a buffer list
82 * to match its expectations.
84 struct wg_transform_attrs attrs =
86 .output_plane_align = 15,
87 .input_queue_length = 15,
89 struct wg_format input_format;
90 struct wg_format output_format;
91 UINT32 low_latency;
93 if (decoder->wg_transform)
94 wg_transform_destroy(decoder->wg_transform);
95 decoder->wg_transform = 0;
97 mf_media_type_to_wg_format(decoder->input_type, &input_format);
98 if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
99 return MF_E_INVALIDMEDIATYPE;
101 mf_media_type_to_wg_format(decoder->output_type, &output_format);
102 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
103 return MF_E_INVALIDMEDIATYPE;
105 /* Don't force any specific size, H264 streams already have the metadata for it
106 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
108 output_format.u.video.width = 0;
109 output_format.u.video.height = 0;
110 output_format.u.video.fps_d = 0;
111 output_format.u.video.fps_n = 0;
113 if (SUCCEEDED(IMFAttributes_GetUINT32(decoder->attributes, &MF_LOW_LATENCY, &low_latency)))
114 attrs.low_latency = !!low_latency;
116 if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs)))
117 return E_FAIL;
119 return S_OK;
122 static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType *media_type)
124 IMFMediaType *default_type = decoder->output_type;
125 UINT32 value, width, height;
126 MFVideoArea aperture;
127 UINT64 ratio;
128 GUID subtype;
129 HRESULT hr;
131 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
132 return hr;
134 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio)))
136 if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio)))
137 ratio = (UINT64)1920 << 32 | 1080;
138 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio)))
139 return hr;
141 width = ratio >> 32;
142 height = ratio;
144 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL)))
146 if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio)))
147 ratio = (UINT64)30000 << 32 | 1001;
148 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio)))
149 return hr;
152 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL)))
154 if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio)))
155 ratio = (UINT64)1 << 32 | 1;
156 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio)))
157 return hr;
160 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL)))
162 if (FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value)))
163 return hr;
164 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value)))
165 return hr;
168 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL)))
170 if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG *)&value)))
171 return hr;
172 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value)))
173 return hr;
176 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL)))
178 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value)))
179 value = MFVideoInterlace_MixedInterlaceOrProgressive;
180 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value)))
181 return hr;
184 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL)))
186 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value)))
187 value = 1;
188 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value)))
189 return hr;
192 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL)))
194 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value)))
195 value = 0;
196 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value)))
197 return hr;
200 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL)))
202 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value)))
203 value = 1;
204 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value)))
205 return hr;
208 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL))
209 && SUCCEEDED(hr = IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
210 (BYTE *)&aperture, sizeof(aperture), &value)))
212 if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
213 (BYTE *)&aperture, sizeof(aperture))))
214 return hr;
217 return S_OK;
220 static HRESULT init_allocator(struct h264_decoder *decoder)
222 HRESULT hr;
224 if (decoder->allocator_initialized)
225 return S_OK;
227 if (FAILED(hr = IMFTransform_SetInputType(decoder->copier, 0, decoder->output_type, 0)))
228 return hr;
229 if (FAILED(hr = IMFTransform_SetOutputType(decoder->copier, 0, decoder->output_type, 0)))
230 return hr;
232 if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder->allocator, 10, 10,
233 decoder->attributes, decoder->output_type)))
234 return hr;
235 decoder->allocator_initialized = TRUE;
236 return S_OK;
239 static void uninit_allocator(struct h264_decoder *decoder)
241 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(decoder->allocator);
242 decoder->allocator_initialized = FALSE;
245 static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
247 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
249 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
251 if (IsEqualGUID(iid, &IID_IUnknown) ||
252 IsEqualGUID(iid, &IID_IMFTransform))
253 *out = &decoder->IMFTransform_iface;
254 else
256 *out = NULL;
257 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
258 return E_NOINTERFACE;
261 IUnknown_AddRef((IUnknown *)*out);
262 return S_OK;
265 static ULONG WINAPI transform_AddRef(IMFTransform *iface)
267 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
268 ULONG refcount = InterlockedIncrement(&decoder->refcount);
270 TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount);
272 return refcount;
275 static ULONG WINAPI transform_Release(IMFTransform *iface)
277 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
278 ULONG refcount = InterlockedDecrement(&decoder->refcount);
280 TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount);
282 if (!refcount)
284 IMFTransform_Release(decoder->copier);
285 IMFVideoSampleAllocatorEx_Release(decoder->allocator);
286 if (decoder->temp_buffer)
287 IMFMediaBuffer_Release(decoder->temp_buffer);
288 if (decoder->wg_transform)
289 wg_transform_destroy(decoder->wg_transform);
290 if (decoder->input_type)
291 IMFMediaType_Release(decoder->input_type);
292 if (decoder->output_type)
293 IMFMediaType_Release(decoder->output_type);
294 if (decoder->output_attributes)
295 IMFAttributes_Release(decoder->output_attributes);
296 if (decoder->attributes)
297 IMFAttributes_Release(decoder->attributes);
298 wg_sample_queue_destroy(decoder->wg_sample_queue);
299 free(decoder);
302 return refcount;
305 static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
306 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
308 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
309 iface, input_minimum, input_maximum, output_minimum, output_maximum);
310 *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
311 return S_OK;
314 static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
316 TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
317 *inputs = *outputs = 1;
318 return S_OK;
321 static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
322 DWORD output_size, DWORD *outputs)
324 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
325 input_size, inputs, output_size, outputs);
326 return E_NOTIMPL;
329 static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
331 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
333 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
335 *info = decoder->input_info;
336 return S_OK;
339 static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
341 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
343 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
345 *info = decoder->output_info;
346 return S_OK;
349 static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
351 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
353 FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes);
355 if (!attributes)
356 return E_POINTER;
358 IMFAttributes_AddRef((*attributes = decoder->attributes));
359 return S_OK;
362 static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
364 TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
365 return E_NOTIMPL;
368 static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
370 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
372 FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes);
374 if (!attributes)
375 return E_POINTER;
376 if (id)
377 return MF_E_INVALIDSTREAMNUMBER;
379 IMFAttributes_AddRef((*attributes = decoder->output_attributes));
380 return S_OK;
383 static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
385 TRACE("iface %p, id %#lx.\n", iface, id);
386 return E_NOTIMPL;
389 static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
391 TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
392 return E_NOTIMPL;
395 static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
396 IMFMediaType **type)
398 IMFMediaType *media_type;
399 const GUID *subtype;
400 HRESULT hr;
402 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
404 *type = NULL;
406 if (index >= ARRAY_SIZE(h264_decoder_input_types))
407 return MF_E_NO_MORE_TYPES;
408 subtype = h264_decoder_input_types[index];
410 if (FAILED(hr = MFCreateMediaType(&media_type)))
411 return hr;
413 if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) &&
414 SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
415 IMFMediaType_AddRef((*type = media_type));
417 IMFMediaType_Release(media_type);
418 return hr;
421 static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id,
422 DWORD index, IMFMediaType **type)
424 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
425 IMFMediaType *media_type;
426 const GUID *output_type;
427 HRESULT hr;
429 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
431 if (!decoder->input_type)
432 return MF_E_TRANSFORM_TYPE_NOT_SET;
434 *type = NULL;
436 if (index >= ARRAY_SIZE(h264_decoder_output_types))
437 return MF_E_NO_MORE_TYPES;
438 output_type = h264_decoder_output_types[index];
440 if (FAILED(hr = MFCreateMediaType(&media_type)))
441 return hr;
443 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
444 goto done;
445 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type)))
446 goto done;
448 hr = fill_output_media_type(decoder, media_type);
450 done:
451 if (SUCCEEDED(hr))
452 IMFMediaType_AddRef((*type = media_type));
454 IMFMediaType_Release(media_type);
455 return hr;
458 static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
460 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
461 GUID major, subtype;
462 UINT64 frame_size;
463 HRESULT hr;
464 ULONG i;
466 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
468 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
469 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
470 return E_INVALIDARG;
472 if (!IsEqualGUID(&major, &MFMediaType_Video))
473 return MF_E_INVALIDMEDIATYPE;
475 for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i)
476 if (IsEqualGUID(&subtype, h264_decoder_input_types[i]))
477 break;
478 if (i == ARRAY_SIZE(h264_decoder_input_types))
479 return MF_E_INVALIDMEDIATYPE;
480 if (flags & MFT_SET_TYPE_TEST_ONLY)
481 return S_OK;
483 if (decoder->output_type)
485 IMFMediaType_Release(decoder->output_type);
486 decoder->output_type = NULL;
489 if (decoder->input_type)
490 IMFMediaType_Release(decoder->input_type);
491 IMFMediaType_AddRef((decoder->input_type = type));
493 if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
495 if (FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, frame_size)))
496 WARN("Failed to update stream type frame size, hr %#lx\n", hr);
497 decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2;
500 return S_OK;
503 static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
505 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
506 UINT64 frame_size, stream_frame_size;
507 GUID major, subtype;
508 HRESULT hr;
509 ULONG i;
511 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
513 if (!decoder->input_type)
514 return MF_E_TRANSFORM_TYPE_NOT_SET;
516 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
517 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
518 return hr;
520 if (!IsEqualGUID(&major, &MFMediaType_Video))
521 return MF_E_INVALIDMEDIATYPE;
523 for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i)
524 if (IsEqualGUID(&subtype, h264_decoder_output_types[i]))
525 break;
526 if (i == ARRAY_SIZE(h264_decoder_output_types))
527 return MF_E_INVALIDMEDIATYPE;
529 if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
530 return MF_E_INVALIDMEDIATYPE;
531 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &stream_frame_size))
532 && frame_size != stream_frame_size)
533 return MF_E_INVALIDMEDIATYPE;
534 if (flags & MFT_SET_TYPE_TEST_ONLY)
535 return S_OK;
537 if (decoder->output_type)
538 IMFMediaType_Release(decoder->output_type);
539 IMFMediaType_AddRef((decoder->output_type = type));
541 if (decoder->wg_transform)
543 struct wg_format output_format;
544 mf_media_type_to_wg_format(decoder->output_type, &output_format);
546 /* Don't force any specific size, H264 streams already have the metadata for it
547 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
549 output_format.u.video.width = 0;
550 output_format.u.video.height = 0;
551 output_format.u.video.fps_d = 0;
552 output_format.u.video.fps_n = 0;
554 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN
555 || !wg_transform_set_output_format(decoder->wg_transform, &output_format))
557 IMFMediaType_Release(decoder->output_type);
558 decoder->output_type = NULL;
559 return MF_E_INVALIDMEDIATYPE;
562 else if (FAILED(hr = try_create_wg_transform(decoder)))
564 IMFMediaType_Release(decoder->output_type);
565 decoder->output_type = NULL;
568 return hr;
571 static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
573 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
574 return E_NOTIMPL;
577 static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
579 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
580 HRESULT hr;
582 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
584 if (!decoder->output_type)
585 return MF_E_TRANSFORM_TYPE_NOT_SET;
587 if (FAILED(hr = MFCreateMediaType(type)))
588 return hr;
590 return IMFMediaType_CopyAllItems(decoder->output_type, (IMFAttributes *)*type);
593 static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
595 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
597 TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags);
599 if (!decoder->wg_transform)
600 return MF_E_TRANSFORM_TYPE_NOT_SET;
602 *flags = MFT_INPUT_STATUS_ACCEPT_DATA;
603 return S_OK;
606 static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
608 FIXME("iface %p, flags %p stub!\n", iface, flags);
609 return E_NOTIMPL;
612 static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
614 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
615 return E_NOTIMPL;
618 static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
620 FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
621 return E_NOTIMPL;
624 static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
626 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
627 HRESULT hr;
629 TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param);
631 switch (message)
633 case MFT_MESSAGE_SET_D3D_MANAGER:
634 if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(decoder->allocator, (IUnknown *)param)))
635 return hr;
637 uninit_allocator(decoder);
638 if (param)
639 decoder->output_info.dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
640 else
641 decoder->output_info.dwFlags &= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
642 return S_OK;
644 case MFT_MESSAGE_COMMAND_DRAIN:
645 return wg_transform_drain(decoder->wg_transform);
647 case MFT_MESSAGE_COMMAND_FLUSH:
648 return wg_transform_flush(decoder->wg_transform);
650 default:
651 FIXME("Ignoring message %#x.\n", message);
652 return S_OK;
656 static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
658 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
660 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
662 if (!decoder->wg_transform)
663 return MF_E_TRANSFORM_TYPE_NOT_SET;
665 return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue);
668 static HRESULT output_sample(struct h264_decoder *decoder, IMFSample **out, IMFSample *src_sample)
670 MFT_OUTPUT_DATA_BUFFER output[1];
671 IMFSample *sample;
672 DWORD status;
673 HRESULT hr;
675 if (FAILED(hr = init_allocator(decoder)))
677 ERR("Failed to initialize allocator, hr %#lx.\n", hr);
678 return hr;
680 if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(decoder->allocator, &sample)))
681 return hr;
683 if (FAILED(hr = IMFTransform_ProcessInput(decoder->copier, 0, src_sample, 0)))
685 IMFSample_Release(sample);
686 return hr;
688 output[0].pSample = sample;
689 if (FAILED(hr = IMFTransform_ProcessOutput(decoder->copier, 0, 1, output, &status)))
691 IMFSample_Release(sample);
692 return hr;
694 *out = sample;
695 return S_OK;
698 static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const struct wg_format *format)
700 UINT64 frame_size, frame_rate;
701 HRESULT hr;
703 if (decoder->stream_type)
704 IMFMediaType_Release(decoder->stream_type);
705 if (!(decoder->stream_type = mf_media_type_from_wg_format(format)))
706 return E_OUTOFMEMORY;
708 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))
709 && FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, frame_rate)))
710 WARN("Failed to update stream type frame size, hr %#lx\n", hr);
712 if (FAILED(hr = IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &frame_size)))
713 return hr;
714 decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2;
715 uninit_allocator(decoder);
717 return MF_E_TRANSFORM_STREAM_CHANGE;
720 static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
721 MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
723 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
724 struct wg_format wg_format;
725 UINT32 sample_size;
726 LONGLONG duration;
727 IMFSample *sample;
728 UINT64 frame_size, frame_rate;
729 GUID subtype;
730 DWORD size;
731 HRESULT hr;
733 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
735 if (count != 1)
736 return E_INVALIDARG;
738 if (!decoder->wg_transform)
739 return MF_E_TRANSFORM_TYPE_NOT_SET;
741 *status = samples->dwStatus = 0;
742 if (!(sample = samples->pSample) && !(decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
743 return E_INVALIDARG;
745 if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype)))
746 return hr;
747 if (FAILED(hr = IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &frame_size)))
748 return hr;
749 if (FAILED(hr = MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size, &sample_size)))
750 return hr;
752 if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)
754 if (decoder->temp_buffer)
756 if (FAILED(IMFMediaBuffer_GetMaxLength(decoder->temp_buffer, &size)) || size < sample_size)
758 IMFMediaBuffer_Release(decoder->temp_buffer);
759 decoder->temp_buffer = NULL;
762 if (!decoder->temp_buffer && FAILED(hr = MFCreateMemoryBuffer(sample_size, &decoder->temp_buffer)))
763 return hr;
764 if (FAILED(hr = MFCreateSample(&sample)))
765 return hr;
766 if (FAILED(hr = IMFSample_AddBuffer(sample, decoder->temp_buffer)))
768 IMFSample_Release(sample);
769 return hr;
773 if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, sample,
774 sample_size, &wg_format, &samples->dwStatus)))
776 wg_sample_queue_flush(decoder->wg_sample_queue, false);
778 if (FAILED(IMFMediaType_GetUINT64(decoder->input_type, &MF_MT_FRAME_RATE, &frame_rate)))
779 frame_rate = (UINT64)30000 << 32 | 1001;
781 duration = (UINT64)10000000 * (UINT32)frame_rate / (frame_rate >> 32);
782 if (FAILED(IMFSample_SetSampleTime(sample, decoder->sample_time)))
783 WARN("Failed to set sample time\n");
784 if (FAILED(IMFSample_SetSampleDuration(sample, duration)))
785 WARN("Failed to set sample duration\n");
786 decoder->sample_time += duration;
789 if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
791 samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
792 *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
793 hr = handle_stream_type_change(decoder, &wg_format);
796 if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)
798 if (hr == S_OK && FAILED(hr = output_sample(decoder, &samples->pSample, sample)))
799 ERR("Failed to output sample, hr %#lx.\n", hr);
800 IMFSample_Release(sample);
803 return hr;
806 static const IMFTransformVtbl transform_vtbl =
808 transform_QueryInterface,
809 transform_AddRef,
810 transform_Release,
811 transform_GetStreamLimits,
812 transform_GetStreamCount,
813 transform_GetStreamIDs,
814 transform_GetInputStreamInfo,
815 transform_GetOutputStreamInfo,
816 transform_GetAttributes,
817 transform_GetInputStreamAttributes,
818 transform_GetOutputStreamAttributes,
819 transform_DeleteInputStream,
820 transform_AddInputStreams,
821 transform_GetInputAvailableType,
822 transform_GetOutputAvailableType,
823 transform_SetInputType,
824 transform_SetOutputType,
825 transform_GetInputCurrentType,
826 transform_GetOutputCurrentType,
827 transform_GetInputStatus,
828 transform_GetOutputStatus,
829 transform_SetOutputBounds,
830 transform_ProcessEvent,
831 transform_ProcessMessage,
832 transform_ProcessInput,
833 transform_ProcessOutput,
836 HRESULT h264_decoder_create(REFIID riid, void **ret)
838 static const struct wg_format output_format =
840 .major_type = WG_MAJOR_TYPE_VIDEO,
841 .u.video =
843 .format = WG_VIDEO_FORMAT_I420,
844 .width = 1920,
845 .height = 1080,
848 static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264};
849 struct wg_transform_attrs attrs = {0};
850 wg_transform_t transform;
851 struct h264_decoder *decoder;
852 HRESULT hr;
854 TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
856 if (!(transform = wg_transform_create(&input_format, &output_format, &attrs)))
858 ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n");
859 return E_FAIL;
861 wg_transform_destroy(transform);
863 if (!(decoder = calloc(1, sizeof(*decoder))))
864 return E_OUTOFMEMORY;
866 decoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
867 decoder->refcount = 1;
869 decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
870 | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE;
871 decoder->input_info.cbSize = 0x1000;
872 decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
873 | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
874 decoder->output_info.cbSize = 1920 * 1088 * 2;
876 if (FAILED(hr = MFCreateMediaType(&decoder->stream_type)))
877 goto failed;
878 if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16)))
879 goto failed;
880 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0)))
881 goto failed;
882 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE)))
883 goto failed;
884 if (FAILED(hr = MFCreateAttributes(&decoder->output_attributes, 0)))
885 goto failed;
886 if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue)))
887 goto failed;
888 if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&decoder->allocator)))
889 goto failed;
890 if (FAILED(hr = MFCreateSampleCopierMFT(&decoder->copier)))
891 goto failed;
893 *ret = &decoder->IMFTransform_iface;
894 TRACE("Created decoder %p\n", *ret);
895 return S_OK;
897 failed:
898 if (decoder->allocator)
899 IMFVideoSampleAllocatorEx_Release(decoder->allocator);
900 if (decoder->wg_sample_queue)
901 wg_sample_queue_destroy(decoder->wg_sample_queue);
902 if (decoder->output_attributes)
903 IMFAttributes_Release(decoder->output_attributes);
904 if (decoder->attributes)
905 IMFAttributes_Release(decoder->attributes);
906 if (decoder->stream_type)
907 IMFMediaType_Release(decoder->stream_type);
908 free(decoder);
909 return hr;