winegstreamer: Fix check for non-zero padding in h264 transform.
[wine.git] / dlls / winegstreamer / h264_decoder.c
blob7d9c38837d3d9abf46b33d8f05d0c121da77cf28
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 IMFMediaType *input_type;
57 MFT_INPUT_STREAM_INFO input_info;
58 IMFMediaType *output_type;
59 MFT_OUTPUT_STREAM_INFO output_info;
61 struct wg_format wg_format;
62 struct wg_transform *wg_transform;
63 struct wg_sample_queue *wg_sample_queue;
66 static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
68 return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface);
71 static HRESULT try_create_wg_transform(struct h264_decoder *decoder)
73 struct wg_format input_format;
74 struct wg_format output_format;
76 if (decoder->wg_transform)
77 wg_transform_destroy(decoder->wg_transform);
78 decoder->wg_transform = NULL;
80 mf_media_type_to_wg_format(decoder->input_type, &input_format);
81 if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
82 return MF_E_INVALIDMEDIATYPE;
84 mf_media_type_to_wg_format(decoder->output_type, &output_format);
85 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
86 return MF_E_INVALIDMEDIATYPE;
88 /* Don't force any specific size, H264 streams already have the metadata for it
89 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
91 output_format.u.video.width = 0;
92 output_format.u.video.height = 0;
93 output_format.u.video.fps_d = 0;
94 output_format.u.video.fps_n = 0;
96 if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format)))
97 return E_FAIL;
99 return S_OK;
102 static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType *media_type)
104 IMFMediaType *default_type = decoder->output_type;
105 struct wg_format *wg_format = &decoder->wg_format;
106 UINT32 value, width, height;
107 UINT64 ratio;
108 GUID subtype;
109 HRESULT hr;
111 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
112 return hr;
114 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio)))
116 ratio = (UINT64)wg_format->u.video.width << 32 | wg_format->u.video.height;
117 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio)))
118 return hr;
120 width = ratio >> 32;
121 height = ratio;
123 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL)))
125 ratio = (UINT64)wg_format->u.video.fps_n << 32 | wg_format->u.video.fps_d;
126 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio)))
127 return hr;
130 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL)))
132 ratio = (UINT64)1 << 32 | 1; /* FIXME: read it from format */
133 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio)))
134 return hr;
137 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL)))
139 if (FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value)))
140 return hr;
141 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value)))
142 return hr;
145 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL)))
147 if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG *)&value)))
148 return hr;
149 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value)))
150 return hr;
153 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL)))
155 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value)))
156 value = MFVideoInterlace_MixedInterlaceOrProgressive;
157 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value)))
158 return hr;
161 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL)))
163 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value)))
164 value = 1;
165 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value)))
166 return hr;
169 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL)))
171 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value)))
172 value = 0;
173 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value)))
174 return hr;
177 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL)))
179 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value)))
180 value = 1;
181 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value)))
182 return hr;
185 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL))
186 && (wg_format->u.video.padding.left || wg_format->u.video.padding.right || wg_format->u.video.padding.top
187 || wg_format->u.video.padding.bottom))
189 MFVideoArea aperture =
191 .OffsetX = {.value = wg_format->u.video.padding.left},
192 .OffsetY = {.value = wg_format->u.video.padding.top},
193 .Area.cx = wg_format->u.video.width - wg_format->u.video.padding.right - wg_format->u.video.padding.left,
194 .Area.cy = wg_format->u.video.height - wg_format->u.video.padding.bottom - wg_format->u.video.padding.top,
197 if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
198 (BYTE *)&aperture, sizeof(aperture))))
199 return hr;
202 return S_OK;
205 static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
207 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
209 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
211 if (IsEqualGUID(iid, &IID_IUnknown) ||
212 IsEqualGUID(iid, &IID_IMFTransform))
213 *out = &decoder->IMFTransform_iface;
214 else
216 *out = NULL;
217 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
218 return E_NOINTERFACE;
221 IUnknown_AddRef((IUnknown *)*out);
222 return S_OK;
225 static ULONG WINAPI transform_AddRef(IMFTransform *iface)
227 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
228 ULONG refcount = InterlockedIncrement(&decoder->refcount);
230 TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount);
232 return refcount;
235 static ULONG WINAPI transform_Release(IMFTransform *iface)
237 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
238 ULONG refcount = InterlockedDecrement(&decoder->refcount);
240 TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount);
242 if (!refcount)
244 if (decoder->wg_transform)
245 wg_transform_destroy(decoder->wg_transform);
246 if (decoder->input_type)
247 IMFMediaType_Release(decoder->input_type);
248 if (decoder->output_type)
249 IMFMediaType_Release(decoder->output_type);
250 if (decoder->output_attributes)
251 IMFAttributes_Release(decoder->output_attributes);
252 if (decoder->attributes)
253 IMFAttributes_Release(decoder->attributes);
255 wg_sample_queue_destroy(decoder->wg_sample_queue);
256 free(decoder);
259 return refcount;
262 static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
263 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
265 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
266 iface, input_minimum, input_maximum, output_minimum, output_maximum);
267 *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
268 return S_OK;
271 static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
273 TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
274 *inputs = *outputs = 1;
275 return S_OK;
278 static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
279 DWORD output_size, DWORD *outputs)
281 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
282 input_size, inputs, output_size, outputs);
283 return E_NOTIMPL;
286 static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
288 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
290 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
292 *info = decoder->input_info;
293 return S_OK;
296 static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
298 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
300 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
302 *info = decoder->output_info;
303 return S_OK;
306 static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
308 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
310 FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes);
312 if (!attributes)
313 return E_POINTER;
315 IMFAttributes_AddRef((*attributes = decoder->attributes));
316 return S_OK;
319 static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
321 TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
322 return E_NOTIMPL;
325 static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
327 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
329 FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes);
331 if (!attributes)
332 return E_POINTER;
333 if (id)
334 return MF_E_INVALIDSTREAMNUMBER;
336 IMFAttributes_AddRef((*attributes = decoder->output_attributes));
337 return S_OK;
340 static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
342 TRACE("iface %p, id %#lx.\n", iface, id);
343 return E_NOTIMPL;
346 static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
348 TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
349 return E_NOTIMPL;
352 static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
353 IMFMediaType **type)
355 IMFMediaType *media_type;
356 const GUID *subtype;
357 HRESULT hr;
359 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
361 *type = NULL;
363 if (index >= ARRAY_SIZE(h264_decoder_input_types))
364 return MF_E_NO_MORE_TYPES;
365 subtype = h264_decoder_input_types[index];
367 if (FAILED(hr = MFCreateMediaType(&media_type)))
368 return hr;
370 if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) &&
371 SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
372 IMFMediaType_AddRef((*type = media_type));
374 IMFMediaType_Release(media_type);
375 return hr;
378 static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id,
379 DWORD index, IMFMediaType **type)
381 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
382 IMFMediaType *media_type;
383 const GUID *output_type;
384 HRESULT hr;
386 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
388 if (!decoder->input_type)
389 return MF_E_TRANSFORM_TYPE_NOT_SET;
391 *type = NULL;
393 if (index >= ARRAY_SIZE(h264_decoder_output_types))
394 return MF_E_NO_MORE_TYPES;
395 output_type = h264_decoder_output_types[index];
397 if (FAILED(hr = MFCreateMediaType(&media_type)))
398 return hr;
400 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
401 goto done;
402 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type)))
403 goto done;
405 hr = fill_output_media_type(decoder, media_type);
407 done:
408 if (SUCCEEDED(hr))
409 IMFMediaType_AddRef((*type = media_type));
411 IMFMediaType_Release(media_type);
412 return hr;
415 static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
417 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
418 GUID major, subtype;
419 UINT64 frame_size;
420 HRESULT hr;
421 ULONG i;
423 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
425 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
426 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
427 return E_INVALIDARG;
429 if (!IsEqualGUID(&major, &MFMediaType_Video))
430 return MF_E_INVALIDMEDIATYPE;
432 for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i)
433 if (IsEqualGUID(&subtype, h264_decoder_input_types[i]))
434 break;
435 if (i == ARRAY_SIZE(h264_decoder_input_types))
436 return MF_E_INVALIDMEDIATYPE;
437 if (flags & MFT_SET_TYPE_TEST_ONLY)
438 return S_OK;
440 if (decoder->output_type)
442 IMFMediaType_Release(decoder->output_type);
443 decoder->output_type = NULL;
446 if (decoder->input_type)
447 IMFMediaType_Release(decoder->input_type);
448 IMFMediaType_AddRef((decoder->input_type = type));
450 if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
452 decoder->wg_format.u.video.width = frame_size >> 32;
453 decoder->wg_format.u.video.height = (UINT32)frame_size;
454 decoder->output_info.cbSize = decoder->wg_format.u.video.width
455 * decoder->wg_format.u.video.height * 2;
458 return S_OK;
461 static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
463 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
464 GUID major, subtype;
465 UINT64 frame_size;
466 HRESULT hr;
467 ULONG i;
469 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
471 if (!decoder->input_type)
472 return MF_E_TRANSFORM_TYPE_NOT_SET;
474 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
475 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
476 return hr;
478 if (!IsEqualGUID(&major, &MFMediaType_Video))
479 return MF_E_INVALIDMEDIATYPE;
481 for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i)
482 if (IsEqualGUID(&subtype, h264_decoder_output_types[i]))
483 break;
484 if (i == ARRAY_SIZE(h264_decoder_output_types))
485 return MF_E_INVALIDMEDIATYPE;
487 if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))
488 || (frame_size >> 32) != decoder->wg_format.u.video.width
489 || (UINT32)frame_size != decoder->wg_format.u.video.height)
490 return MF_E_INVALIDMEDIATYPE;
491 if (flags & MFT_SET_TYPE_TEST_ONLY)
492 return S_OK;
494 if (decoder->output_type)
495 IMFMediaType_Release(decoder->output_type);
496 IMFMediaType_AddRef((decoder->output_type = type));
498 if (decoder->wg_transform)
500 struct wg_format output_format;
501 mf_media_type_to_wg_format(decoder->output_type, &output_format);
503 /* Don't force any specific size, H264 streams already have the metadata for it
504 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
506 output_format.u.video.width = 0;
507 output_format.u.video.height = 0;
508 output_format.u.video.fps_d = 0;
509 output_format.u.video.fps_n = 0;
511 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN
512 || !wg_transform_set_output_format(decoder->wg_transform, &output_format))
514 IMFMediaType_Release(decoder->output_type);
515 decoder->output_type = NULL;
516 return MF_E_INVALIDMEDIATYPE;
519 else if (FAILED(hr = try_create_wg_transform(decoder)))
521 IMFMediaType_Release(decoder->output_type);
522 decoder->output_type = NULL;
525 return hr;
528 static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
530 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
531 return E_NOTIMPL;
534 static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
536 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
537 HRESULT hr;
539 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
541 if (!decoder->output_type)
542 return MF_E_TRANSFORM_TYPE_NOT_SET;
544 if (FAILED(hr = MFCreateMediaType(type)))
545 return hr;
547 return IMFMediaType_CopyAllItems(decoder->output_type, (IMFAttributes *)*type);
550 static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
552 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
554 TRACE("iface %p, id %#lx, flags %p.\n", iface, id, flags);
556 if (!decoder->wg_transform)
557 return MF_E_TRANSFORM_TYPE_NOT_SET;
559 *flags = MFT_INPUT_STATUS_ACCEPT_DATA;
560 return S_OK;
563 static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
565 FIXME("iface %p, flags %p stub!\n", iface, flags);
566 return E_NOTIMPL;
569 static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
571 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
572 return E_NOTIMPL;
575 static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
577 FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
578 return E_NOTIMPL;
581 static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
583 FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param);
584 return S_OK;
587 static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
589 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
591 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
593 if (!decoder->wg_transform)
594 return MF_E_TRANSFORM_TYPE_NOT_SET;
596 return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue);
599 static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
600 MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
602 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
603 struct wg_format wg_format;
604 UINT32 sample_size;
605 UINT64 frame_rate;
606 GUID subtype;
607 HRESULT hr;
609 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
611 if (count != 1)
612 return E_INVALIDARG;
614 if (!decoder->wg_transform)
615 return MF_E_TRANSFORM_TYPE_NOT_SET;
617 *status = samples->dwStatus = 0;
618 if (!samples->pSample)
619 return E_INVALIDARG;
621 if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype)))
622 return hr;
623 if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width,
624 decoder->wg_format.u.video.height, &sample_size)))
625 return hr;
627 if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample,
628 sample_size, &wg_format, &samples->dwStatus)))
629 wg_sample_queue_flush(decoder->wg_sample_queue, false);
631 if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
633 decoder->wg_format = wg_format;
634 decoder->output_info.cbSize = ALIGN_SIZE(decoder->wg_format.u.video.width, 0xf)
635 * ALIGN_SIZE(decoder->wg_format.u.video.height, 0xf) * 2;
637 /* keep the frame rate that was requested, GStreamer doesn't provide any */
638 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate)))
640 decoder->wg_format.u.video.fps_n = frame_rate >> 32;
641 decoder->wg_format.u.video.fps_d = (UINT32)frame_rate;
644 samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
645 *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
648 return hr;
651 static const IMFTransformVtbl transform_vtbl =
653 transform_QueryInterface,
654 transform_AddRef,
655 transform_Release,
656 transform_GetStreamLimits,
657 transform_GetStreamCount,
658 transform_GetStreamIDs,
659 transform_GetInputStreamInfo,
660 transform_GetOutputStreamInfo,
661 transform_GetAttributes,
662 transform_GetInputStreamAttributes,
663 transform_GetOutputStreamAttributes,
664 transform_DeleteInputStream,
665 transform_AddInputStreams,
666 transform_GetInputAvailableType,
667 transform_GetOutputAvailableType,
668 transform_SetInputType,
669 transform_SetOutputType,
670 transform_GetInputCurrentType,
671 transform_GetOutputCurrentType,
672 transform_GetInputStatus,
673 transform_GetOutputStatus,
674 transform_SetOutputBounds,
675 transform_ProcessEvent,
676 transform_ProcessMessage,
677 transform_ProcessInput,
678 transform_ProcessOutput,
681 HRESULT h264_decoder_create(REFIID riid, void **ret)
683 static const struct wg_format output_format =
685 .major_type = WG_MAJOR_TYPE_VIDEO,
686 .u.video =
688 .format = WG_VIDEO_FORMAT_I420,
689 .width = 1920,
690 .height = 1080,
693 static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264};
694 struct wg_transform *transform;
695 struct h264_decoder *decoder;
696 HRESULT hr;
698 TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
700 if (!(transform = wg_transform_create(&input_format, &output_format)))
702 ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n");
703 return E_FAIL;
705 wg_transform_destroy(transform);
707 if (!(decoder = calloc(1, sizeof(*decoder))))
708 return E_OUTOFMEMORY;
710 decoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
711 decoder->refcount = 1;
712 decoder->wg_format.u.video.format = WG_VIDEO_FORMAT_UNKNOWN;
713 decoder->wg_format.u.video.width = 1920;
714 decoder->wg_format.u.video.height = 1080;
715 decoder->wg_format.u.video.fps_n = 30000;
716 decoder->wg_format.u.video.fps_d = 1001;
718 decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
719 | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE;
720 decoder->input_info.cbSize = 0x1000;
721 decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
722 | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
723 decoder->output_info.cbSize = 1920 * 1088 * 2;
725 if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16)))
726 goto failed;
727 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0)))
728 goto failed;
729 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_SA_D3D11_AWARE, TRUE)))
730 goto failed;
731 if (FAILED(hr = MFCreateAttributes(&decoder->output_attributes, 0)))
732 goto failed;
733 if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue)))
734 goto failed;
736 *ret = &decoder->IMFTransform_iface;
737 TRACE("Created decoder %p\n", *ret);
738 return S_OK;
740 failed:
741 if (decoder->output_attributes)
742 IMFAttributes_Release(decoder->output_attributes);
743 if (decoder->attributes)
744 IMFAttributes_Release(decoder->attributes);
745 free(decoder);
746 return hr;