winegstreamer: Pass desired output plane alignment to wg_transform_create.
[wine.git] / dlls / winegstreamer / h264_decoder.c
blob81b06445df99294a34f8063964a652044cc7baa4
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 struct wg_transform *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 struct wg_transform_attrs attrs =
81 .output_plane_align = 15,
83 struct wg_format input_format;
84 struct wg_format output_format;
86 if (decoder->wg_transform)
87 wg_transform_destroy(decoder->wg_transform);
88 decoder->wg_transform = NULL;
90 mf_media_type_to_wg_format(decoder->input_type, &input_format);
91 if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
92 return MF_E_INVALIDMEDIATYPE;
94 mf_media_type_to_wg_format(decoder->output_type, &output_format);
95 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
96 return MF_E_INVALIDMEDIATYPE;
98 /* Don't force any specific size, H264 streams already have the metadata for it
99 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
101 output_format.u.video.width = 0;
102 output_format.u.video.height = 0;
103 output_format.u.video.fps_d = 0;
104 output_format.u.video.fps_n = 0;
106 if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format, &attrs)))
107 return E_FAIL;
109 return S_OK;
112 static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType *media_type)
114 IMFMediaType *default_type = decoder->output_type;
115 UINT32 value, width, height;
116 MFVideoArea aperture;
117 UINT64 ratio;
118 GUID subtype;
119 HRESULT hr;
121 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
122 return hr;
124 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio)))
126 if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &ratio)))
127 ratio = (UINT64)1920 << 32 | 1080;
128 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio)))
129 return hr;
131 width = ratio >> 32;
132 height = ratio;
134 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL)))
136 if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, &ratio)))
137 ratio = (UINT64)30000 << 32 | 1001;
138 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio)))
139 return hr;
142 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL)))
144 if (FAILED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_PIXEL_ASPECT_RATIO, &ratio)))
145 ratio = (UINT64)1 << 32 | 1;
146 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio)))
147 return hr;
150 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL)))
152 if (FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value)))
153 return hr;
154 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value)))
155 return hr;
158 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL)))
160 if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG *)&value)))
161 return hr;
162 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value)))
163 return hr;
166 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL)))
168 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value)))
169 value = MFVideoInterlace_MixedInterlaceOrProgressive;
170 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value)))
171 return hr;
174 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL)))
176 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value)))
177 value = 1;
178 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value)))
179 return hr;
182 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL)))
184 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value)))
185 value = 0;
186 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value)))
187 return hr;
190 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL)))
192 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value)))
193 value = 1;
194 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value)))
195 return hr;
198 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL))
199 && SUCCEEDED(hr = IMFMediaType_GetBlob(decoder->stream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
200 (BYTE *)&aperture, sizeof(aperture), &value)))
202 if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
203 (BYTE *)&aperture, sizeof(aperture))))
204 return hr;
207 return S_OK;
210 static HRESULT init_allocator(struct h264_decoder *decoder)
212 HRESULT hr;
214 if (decoder->allocator_initialized)
215 return S_OK;
217 if (FAILED(hr = IMFTransform_SetInputType(decoder->copier, 0, decoder->output_type, 0)))
218 return hr;
219 if (FAILED(hr = IMFTransform_SetOutputType(decoder->copier, 0, decoder->output_type, 0)))
220 return hr;
222 if (FAILED(hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder->allocator, 10, 10,
223 decoder->attributes, decoder->output_type)))
224 return hr;
225 decoder->allocator_initialized = TRUE;
226 return S_OK;
229 static void uninit_allocator(struct h264_decoder *decoder)
231 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(decoder->allocator);
232 decoder->allocator_initialized = FALSE;
235 static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
237 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
239 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
241 if (IsEqualGUID(iid, &IID_IUnknown) ||
242 IsEqualGUID(iid, &IID_IMFTransform))
243 *out = &decoder->IMFTransform_iface;
244 else
246 *out = NULL;
247 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
248 return E_NOINTERFACE;
251 IUnknown_AddRef((IUnknown *)*out);
252 return S_OK;
255 static ULONG WINAPI transform_AddRef(IMFTransform *iface)
257 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
258 ULONG refcount = InterlockedIncrement(&decoder->refcount);
260 TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount);
262 return refcount;
265 static ULONG WINAPI transform_Release(IMFTransform *iface)
267 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
268 ULONG refcount = InterlockedDecrement(&decoder->refcount);
270 TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount);
272 if (!refcount)
274 IMFTransform_Release(decoder->copier);
275 IMFVideoSampleAllocatorEx_Release(decoder->allocator);
276 if (decoder->temp_buffer)
277 IMFMediaBuffer_Release(decoder->temp_buffer);
278 if (decoder->wg_transform)
279 wg_transform_destroy(decoder->wg_transform);
280 if (decoder->input_type)
281 IMFMediaType_Release(decoder->input_type);
282 if (decoder->output_type)
283 IMFMediaType_Release(decoder->output_type);
284 if (decoder->output_attributes)
285 IMFAttributes_Release(decoder->output_attributes);
286 if (decoder->attributes)
287 IMFAttributes_Release(decoder->attributes);
288 wg_sample_queue_destroy(decoder->wg_sample_queue);
289 free(decoder);
292 return refcount;
295 static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
296 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
298 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
299 iface, input_minimum, input_maximum, output_minimum, output_maximum);
300 *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
301 return S_OK;
304 static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
306 TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
307 *inputs = *outputs = 1;
308 return S_OK;
311 static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
312 DWORD output_size, DWORD *outputs)
314 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
315 input_size, inputs, output_size, outputs);
316 return E_NOTIMPL;
319 static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
321 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
323 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
325 *info = decoder->input_info;
326 return S_OK;
329 static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_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->output_info;
336 return S_OK;
339 static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
341 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
343 FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes);
345 if (!attributes)
346 return E_POINTER;
348 IMFAttributes_AddRef((*attributes = decoder->attributes));
349 return S_OK;
352 static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
354 TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
355 return E_NOTIMPL;
358 static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
360 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
362 FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes);
364 if (!attributes)
365 return E_POINTER;
366 if (id)
367 return MF_E_INVALIDSTREAMNUMBER;
369 IMFAttributes_AddRef((*attributes = decoder->output_attributes));
370 return S_OK;
373 static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
375 TRACE("iface %p, id %#lx.\n", iface, id);
376 return E_NOTIMPL;
379 static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
381 TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
382 return E_NOTIMPL;
385 static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
386 IMFMediaType **type)
388 IMFMediaType *media_type;
389 const GUID *subtype;
390 HRESULT hr;
392 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
394 *type = NULL;
396 if (index >= ARRAY_SIZE(h264_decoder_input_types))
397 return MF_E_NO_MORE_TYPES;
398 subtype = h264_decoder_input_types[index];
400 if (FAILED(hr = MFCreateMediaType(&media_type)))
401 return hr;
403 if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) &&
404 SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
405 IMFMediaType_AddRef((*type = media_type));
407 IMFMediaType_Release(media_type);
408 return hr;
411 static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id,
412 DWORD index, IMFMediaType **type)
414 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
415 IMFMediaType *media_type;
416 const GUID *output_type;
417 HRESULT hr;
419 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
421 if (!decoder->input_type)
422 return MF_E_TRANSFORM_TYPE_NOT_SET;
424 *type = NULL;
426 if (index >= ARRAY_SIZE(h264_decoder_output_types))
427 return MF_E_NO_MORE_TYPES;
428 output_type = h264_decoder_output_types[index];
430 if (FAILED(hr = MFCreateMediaType(&media_type)))
431 return hr;
433 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
434 goto done;
435 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type)))
436 goto done;
438 hr = fill_output_media_type(decoder, media_type);
440 done:
441 if (SUCCEEDED(hr))
442 IMFMediaType_AddRef((*type = media_type));
444 IMFMediaType_Release(media_type);
445 return hr;
448 static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
450 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
451 GUID major, subtype;
452 UINT64 frame_size;
453 HRESULT hr;
454 ULONG i;
456 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
458 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
459 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
460 return E_INVALIDARG;
462 if (!IsEqualGUID(&major, &MFMediaType_Video))
463 return MF_E_INVALIDMEDIATYPE;
465 for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i)
466 if (IsEqualGUID(&subtype, h264_decoder_input_types[i]))
467 break;
468 if (i == ARRAY_SIZE(h264_decoder_input_types))
469 return MF_E_INVALIDMEDIATYPE;
470 if (flags & MFT_SET_TYPE_TEST_ONLY)
471 return S_OK;
473 if (decoder->output_type)
475 IMFMediaType_Release(decoder->output_type);
476 decoder->output_type = NULL;
479 if (decoder->input_type)
480 IMFMediaType_Release(decoder->input_type);
481 IMFMediaType_AddRef((decoder->input_type = type));
483 if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
485 if (FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, frame_size)))
486 WARN("Failed to update stream type frame size, hr %#lx\n", hr);
487 decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2;
490 return S_OK;
493 static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
495 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
496 UINT64 frame_size, stream_frame_size;
497 GUID major, subtype;
498 HRESULT hr;
499 ULONG i;
501 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
503 if (!decoder->input_type)
504 return MF_E_TRANSFORM_TYPE_NOT_SET;
506 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
507 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
508 return hr;
510 if (!IsEqualGUID(&major, &MFMediaType_Video))
511 return MF_E_INVALIDMEDIATYPE;
513 for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i)
514 if (IsEqualGUID(&subtype, h264_decoder_output_types[i]))
515 break;
516 if (i == ARRAY_SIZE(h264_decoder_output_types))
517 return MF_E_INVALIDMEDIATYPE;
519 if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
520 return MF_E_INVALIDMEDIATYPE;
521 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &stream_frame_size))
522 && frame_size != stream_frame_size)
523 return MF_E_INVALIDMEDIATYPE;
524 if (flags & MFT_SET_TYPE_TEST_ONLY)
525 return S_OK;
527 if (decoder->output_type)
528 IMFMediaType_Release(decoder->output_type);
529 IMFMediaType_AddRef((decoder->output_type = type));
531 if (decoder->wg_transform)
533 struct wg_format output_format;
534 mf_media_type_to_wg_format(decoder->output_type, &output_format);
536 /* Don't force any specific size, H264 streams already have the metadata for it
537 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
539 output_format.u.video.width = 0;
540 output_format.u.video.height = 0;
541 output_format.u.video.fps_d = 0;
542 output_format.u.video.fps_n = 0;
544 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN
545 || !wg_transform_set_output_format(decoder->wg_transform, &output_format))
547 IMFMediaType_Release(decoder->output_type);
548 decoder->output_type = NULL;
549 return MF_E_INVALIDMEDIATYPE;
552 else if (FAILED(hr = try_create_wg_transform(decoder)))
554 IMFMediaType_Release(decoder->output_type);
555 decoder->output_type = NULL;
558 return hr;
561 static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
563 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
564 return E_NOTIMPL;
567 static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
569 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
570 HRESULT hr;
572 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
574 if (!decoder->output_type)
575 return MF_E_TRANSFORM_TYPE_NOT_SET;
577 if (FAILED(hr = MFCreateMediaType(type)))
578 return hr;
580 return IMFMediaType_CopyAllItems(decoder->output_type, (IMFAttributes *)*type);
583 static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
585 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
587 TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags);
589 if (!decoder->wg_transform)
590 return MF_E_TRANSFORM_TYPE_NOT_SET;
592 *flags = MFT_INPUT_STATUS_ACCEPT_DATA;
593 return S_OK;
596 static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
598 FIXME("iface %p, flags %p stub!\n", iface, flags);
599 return E_NOTIMPL;
602 static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
604 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
605 return E_NOTIMPL;
608 static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
610 FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
611 return E_NOTIMPL;
614 static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
616 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
617 HRESULT hr;
619 TRACE("iface %p, message %#x, param %Ix.\n", iface, message, param);
621 switch (message)
623 case MFT_MESSAGE_SET_D3D_MANAGER:
624 if (FAILED(hr = IMFVideoSampleAllocatorEx_SetDirectXManager(decoder->allocator, (IUnknown *)param)))
625 return hr;
627 uninit_allocator(decoder);
628 if (param)
629 decoder->output_info.dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
630 else
631 decoder->output_info.dwFlags &= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
632 return S_OK;
634 case MFT_MESSAGE_COMMAND_DRAIN:
635 return wg_transform_drain(decoder->wg_transform);
637 case MFT_MESSAGE_COMMAND_FLUSH:
638 return wg_transform_flush(decoder->wg_transform);
640 default:
641 FIXME("Ignoring message %#x.\n", message);
642 return S_OK;
646 static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
648 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
650 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
652 if (!decoder->wg_transform)
653 return MF_E_TRANSFORM_TYPE_NOT_SET;
655 return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue);
658 static HRESULT output_sample(struct h264_decoder *decoder, IMFSample **out, IMFSample *src_sample)
660 MFT_OUTPUT_DATA_BUFFER output[1];
661 IMFSample *sample;
662 DWORD status;
663 HRESULT hr;
665 if (FAILED(hr = init_allocator(decoder)))
667 ERR("Failed to initialize allocator, hr %#lx.\n", hr);
668 return hr;
670 if (FAILED(hr = IMFVideoSampleAllocatorEx_AllocateSample(decoder->allocator, &sample)))
671 return hr;
673 if (FAILED(hr = IMFTransform_ProcessInput(decoder->copier, 0, src_sample, 0)))
675 IMFSample_Release(sample);
676 return hr;
678 output[0].pSample = sample;
679 if (FAILED(hr = IMFTransform_ProcessOutput(decoder->copier, 0, 1, output, &status)))
681 IMFSample_Release(sample);
682 return hr;
684 *out = sample;
685 return S_OK;
688 static HRESULT handle_stream_type_change(struct h264_decoder *decoder, const struct wg_format *format)
690 UINT64 frame_size, frame_rate;
691 HRESULT hr;
693 if (decoder->stream_type)
694 IMFMediaType_Release(decoder->stream_type);
695 if (!(decoder->stream_type = mf_media_type_from_wg_format(format)))
696 return E_OUTOFMEMORY;
698 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))
699 && FAILED(hr = IMFMediaType_SetUINT64(decoder->stream_type, &MF_MT_FRAME_RATE, frame_rate)))
700 WARN("Failed to update stream type frame size, hr %#lx\n", hr);
702 if (FAILED(hr = IMFMediaType_GetUINT64(decoder->stream_type, &MF_MT_FRAME_SIZE, &frame_size)))
703 return hr;
704 decoder->output_info.cbSize = (frame_size >> 32) * (UINT32)frame_size * 2;
705 uninit_allocator(decoder);
707 return MF_E_TRANSFORM_STREAM_CHANGE;
710 static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
711 MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
713 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
714 struct wg_format wg_format;
715 UINT32 sample_size;
716 LONGLONG duration;
717 IMFSample *sample;
718 UINT64 frame_size, frame_rate;
719 GUID subtype;
720 DWORD size;
721 HRESULT hr;
723 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
725 if (count != 1)
726 return E_INVALIDARG;
728 if (!decoder->wg_transform)
729 return MF_E_TRANSFORM_TYPE_NOT_SET;
731 *status = samples->dwStatus = 0;
732 if (!(sample = samples->pSample) && !(decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES))
733 return E_INVALIDARG;
735 if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype)))
736 return hr;
737 if (FAILED(hr = IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &frame_size)))
738 return hr;
739 if (FAILED(hr = MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size, &sample_size)))
740 return hr;
742 if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)
744 if (decoder->temp_buffer)
746 if (FAILED(IMFMediaBuffer_GetMaxLength(decoder->temp_buffer, &size)) || size < sample_size)
748 IMFMediaBuffer_Release(decoder->temp_buffer);
749 decoder->temp_buffer = NULL;
752 if (!decoder->temp_buffer && FAILED(hr = MFCreateMemoryBuffer(sample_size, &decoder->temp_buffer)))
753 return hr;
754 if (FAILED(hr = MFCreateSample(&sample)))
755 return hr;
756 if (FAILED(hr = IMFSample_AddBuffer(sample, decoder->temp_buffer)))
758 IMFSample_Release(sample);
759 return hr;
763 if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, sample,
764 sample_size, &wg_format, &samples->dwStatus)))
766 wg_sample_queue_flush(decoder->wg_sample_queue, false);
768 if (FAILED(IMFMediaType_GetUINT64(decoder->input_type, &MF_MT_FRAME_RATE, &frame_rate)))
769 frame_rate = (UINT64)30000 << 32 | 1001;
771 duration = (UINT64)10000000 * (UINT32)frame_rate / (frame_rate >> 32);
772 if (FAILED(IMFSample_SetSampleTime(sample, decoder->sample_time)))
773 WARN("Failed to set sample time\n");
774 if (FAILED(IMFSample_SetSampleDuration(sample, duration)))
775 WARN("Failed to set sample duration\n");
776 decoder->sample_time += duration;
779 if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
781 samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
782 *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
783 hr = handle_stream_type_change(decoder, &wg_format);
786 if (decoder->output_info.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES)
788 if (hr == S_OK && FAILED(hr = output_sample(decoder, &samples->pSample, sample)))
789 ERR("Failed to output sample, hr %#lx.\n", hr);
790 IMFSample_Release(sample);
793 return hr;
796 static const IMFTransformVtbl transform_vtbl =
798 transform_QueryInterface,
799 transform_AddRef,
800 transform_Release,
801 transform_GetStreamLimits,
802 transform_GetStreamCount,
803 transform_GetStreamIDs,
804 transform_GetInputStreamInfo,
805 transform_GetOutputStreamInfo,
806 transform_GetAttributes,
807 transform_GetInputStreamAttributes,
808 transform_GetOutputStreamAttributes,
809 transform_DeleteInputStream,
810 transform_AddInputStreams,
811 transform_GetInputAvailableType,
812 transform_GetOutputAvailableType,
813 transform_SetInputType,
814 transform_SetOutputType,
815 transform_GetInputCurrentType,
816 transform_GetOutputCurrentType,
817 transform_GetInputStatus,
818 transform_GetOutputStatus,
819 transform_SetOutputBounds,
820 transform_ProcessEvent,
821 transform_ProcessMessage,
822 transform_ProcessInput,
823 transform_ProcessOutput,
826 HRESULT h264_decoder_create(REFIID riid, void **ret)
828 static const struct wg_format output_format =
830 .major_type = WG_MAJOR_TYPE_VIDEO,
831 .u.video =
833 .format = WG_VIDEO_FORMAT_I420,
834 .width = 1920,
835 .height = 1080,
838 static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264};
839 struct wg_transform_attrs attrs = {0};
840 struct wg_transform *transform;
841 struct h264_decoder *decoder;
842 HRESULT hr;
844 TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
846 if (!(transform = wg_transform_create(&input_format, &output_format, &attrs)))
848 ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n");
849 return E_FAIL;
851 wg_transform_destroy(transform);
853 if (!(decoder = calloc(1, sizeof(*decoder))))
854 return E_OUTOFMEMORY;
856 decoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
857 decoder->refcount = 1;
859 decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
860 | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE;
861 decoder->input_info.cbSize = 0x1000;
862 decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
863 | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
864 decoder->output_info.cbSize = 1920 * 1088 * 2;
866 if (FAILED(hr = MFCreateMediaType(&decoder->stream_type)))
867 goto failed;
868 if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16)))
869 goto failed;
870 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0)))
871 goto failed;
872 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE)))
873 goto failed;
874 if (FAILED(hr = MFCreateAttributes(&decoder->output_attributes, 0)))
875 goto failed;
876 if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue)))
877 goto failed;
878 if (FAILED(hr = MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&decoder->allocator)))
879 goto failed;
880 if (FAILED(hr = MFCreateSampleCopierMFT(&decoder->copier)))
881 goto failed;
883 *ret = &decoder->IMFTransform_iface;
884 TRACE("Created decoder %p\n", *ret);
885 return S_OK;
887 failed:
888 if (decoder->allocator)
889 IMFVideoSampleAllocatorEx_Release(decoder->allocator);
890 if (decoder->wg_sample_queue)
891 wg_sample_queue_destroy(decoder->wg_sample_queue);
892 if (decoder->output_attributes)
893 IMFAttributes_Release(decoder->output_attributes);
894 if (decoder->attributes)
895 IMFAttributes_Release(decoder->attributes);
896 if (decoder->stream_type)
897 IMFMediaType_Release(decoder->stream_type);
898 free(decoder);
899 return hr;