winegstreamer: Avoid leaking attributes on video processor creation failure.
[wine.git] / dlls / winegstreamer / h264_decoder.c
blobc6098aee3025833951859f6e7131c1076ca895fa
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 static const GUID *const h264_decoder_input_types[] =
34 &MFVideoFormat_H264,
35 &MFVideoFormat_H264_ES,
37 static const GUID *const h264_decoder_output_types[] =
39 &MFVideoFormat_NV12,
40 &MFVideoFormat_YV12,
41 &MFVideoFormat_IYUV,
42 &MFVideoFormat_I420,
43 &MFVideoFormat_YUY2,
46 struct h264_decoder
48 IMFTransform IMFTransform_iface;
49 LONG refcount;
50 IMFMediaType *input_type;
51 IMFMediaType *output_type;
53 struct wg_format wg_format;
54 struct wg_transform *wg_transform;
55 struct wg_sample_queue *wg_sample_queue;
58 static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
60 return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface);
63 static HRESULT try_create_wg_transform(struct h264_decoder *decoder)
65 struct wg_format input_format;
66 struct wg_format output_format;
68 if (decoder->wg_transform)
69 wg_transform_destroy(decoder->wg_transform);
70 decoder->wg_transform = NULL;
72 mf_media_type_to_wg_format(decoder->input_type, &input_format);
73 if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
74 return MF_E_INVALIDMEDIATYPE;
76 mf_media_type_to_wg_format(decoder->output_type, &output_format);
77 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
78 return MF_E_INVALIDMEDIATYPE;
80 /* Don't force any specific size, H264 streams already have the metadata for it
81 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
83 output_format.u.video.width = 0;
84 output_format.u.video.height = 0;
85 output_format.u.video.fps_d = 0;
86 output_format.u.video.fps_n = 0;
88 if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format)))
89 return E_FAIL;
91 return S_OK;
94 static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType *media_type)
96 IMFMediaType *default_type = decoder->output_type;
97 struct wg_format *wg_format = &decoder->wg_format;
98 UINT32 value, width, height;
99 UINT64 ratio;
100 GUID subtype;
101 HRESULT hr;
103 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
104 return hr;
106 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio)))
108 ratio = (UINT64)wg_format->u.video.width << 32 | wg_format->u.video.height;
109 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio)))
110 return hr;
112 width = ratio >> 32;
113 height = ratio;
115 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL)))
117 ratio = (UINT64)wg_format->u.video.fps_n << 32 | wg_format->u.video.fps_d;
118 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio)))
119 return hr;
122 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL)))
124 ratio = (UINT64)1 << 32 | 1; /* FIXME: read it from format */
125 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio)))
126 return hr;
129 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL)))
131 if (FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value)))
132 return hr;
133 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value)))
134 return hr;
137 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL)))
139 if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG *)&value)))
140 return hr;
141 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value)))
142 return hr;
145 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL)))
147 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value)))
148 value = MFVideoInterlace_MixedInterlaceOrProgressive;
149 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value)))
150 return hr;
153 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL)))
155 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value)))
156 value = 1;
157 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value)))
158 return hr;
161 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL)))
163 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value)))
164 value = 0;
165 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value)))
166 return hr;
169 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL)))
171 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value)))
172 value = 1;
173 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value)))
174 return hr;
177 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL))
178 && !IsRectEmpty(&wg_format->u.video.padding))
180 MFVideoArea aperture =
182 .OffsetX = {.value = wg_format->u.video.padding.left},
183 .OffsetY = {.value = wg_format->u.video.padding.top},
184 .Area.cx = wg_format->u.video.width - wg_format->u.video.padding.right - wg_format->u.video.padding.left,
185 .Area.cy = wg_format->u.video.height - wg_format->u.video.padding.bottom - wg_format->u.video.padding.top,
188 if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
189 (BYTE *)&aperture, sizeof(aperture))))
190 return hr;
193 return S_OK;
196 static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
198 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
200 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
202 if (IsEqualGUID(iid, &IID_IUnknown) ||
203 IsEqualGUID(iid, &IID_IMFTransform))
204 *out = &decoder->IMFTransform_iface;
205 else
207 *out = NULL;
208 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
209 return E_NOINTERFACE;
212 IUnknown_AddRef((IUnknown *)*out);
213 return S_OK;
216 static ULONG WINAPI transform_AddRef(IMFTransform *iface)
218 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
219 ULONG refcount = InterlockedIncrement(&decoder->refcount);
221 TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount);
223 return refcount;
226 static ULONG WINAPI transform_Release(IMFTransform *iface)
228 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
229 ULONG refcount = InterlockedDecrement(&decoder->refcount);
231 TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount);
233 if (!refcount)
235 if (decoder->wg_transform)
236 wg_transform_destroy(decoder->wg_transform);
237 if (decoder->input_type)
238 IMFMediaType_Release(decoder->input_type);
239 if (decoder->output_type)
240 IMFMediaType_Release(decoder->output_type);
242 wg_sample_queue_destroy(decoder->wg_sample_queue);
243 free(decoder);
246 return refcount;
249 static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
250 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
252 FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p stub!\n",
253 iface, input_minimum, input_maximum, output_minimum, output_maximum);
254 return E_NOTIMPL;
257 static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
259 FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs);
260 return E_NOTIMPL;
263 static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size,
264 DWORD *inputs, DWORD output_size, DWORD *outputs)
266 FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p stub!\n", iface,
267 input_size, inputs, output_size, outputs);
268 return E_NOTIMPL;
271 static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
273 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
275 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
277 if (!decoder->input_type)
278 return MF_E_TRANSFORM_TYPE_NOT_SET;
280 info->hnsMaxLatency = 0;
281 info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE;
282 info->cbSize = 0x1000;
283 info->cbMaxLookahead = 0;
284 info->cbAlignment = 0;
286 return S_OK;
289 static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
291 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
292 UINT32 actual_width, actual_height;
294 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
296 actual_width = (decoder->wg_format.u.video.width + 15) & ~15;
297 actual_height = (decoder->wg_format.u.video.height + 15) & ~15;
299 info->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
300 info->cbSize = actual_width * actual_height * 2;
301 info->cbAlignment = 0;
303 return S_OK;
306 static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
308 FIXME("iface %p, attributes %p stub!\n", iface, attributes);
309 return MFCreateAttributes(attributes, 0);
312 static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
314 FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes);
315 return E_NOTIMPL;
318 static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id,
319 IMFAttributes **attributes)
321 FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes);
322 return E_NOTIMPL;
325 static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
327 FIXME("iface %p, id %#lx stub!\n", iface, id);
328 return E_NOTIMPL;
331 static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
333 FIXME("iface %p, streams %lu, ids %p stub!\n", iface, streams, ids);
334 return E_NOTIMPL;
337 static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
338 IMFMediaType **type)
340 IMFMediaType *media_type;
341 const GUID *subtype;
342 HRESULT hr;
344 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
346 *type = NULL;
348 if (index >= ARRAY_SIZE(h264_decoder_input_types))
349 return MF_E_NO_MORE_TYPES;
350 subtype = h264_decoder_input_types[index];
352 if (FAILED(hr = MFCreateMediaType(&media_type)))
353 return hr;
355 if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) &&
356 SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
357 IMFMediaType_AddRef((*type = media_type));
359 IMFMediaType_Release(media_type);
360 return hr;
363 static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id,
364 DWORD index, IMFMediaType **type)
366 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
367 IMFMediaType *media_type;
368 const GUID *output_type;
369 HRESULT hr;
371 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
373 if (!decoder->input_type)
374 return MF_E_TRANSFORM_TYPE_NOT_SET;
376 *type = NULL;
378 if (index >= ARRAY_SIZE(h264_decoder_output_types))
379 return MF_E_NO_MORE_TYPES;
380 output_type = h264_decoder_output_types[index];
382 if (FAILED(hr = MFCreateMediaType(&media_type)))
383 return hr;
385 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
386 goto done;
387 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type)))
388 goto done;
390 hr = fill_output_media_type(decoder, media_type);
392 done:
393 if (SUCCEEDED(hr))
394 IMFMediaType_AddRef((*type = media_type));
396 IMFMediaType_Release(media_type);
397 return hr;
400 static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
402 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
403 GUID major, subtype;
404 UINT64 frame_size;
405 HRESULT hr;
406 ULONG i;
408 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
410 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
411 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
412 return E_INVALIDARG;
414 if (!IsEqualGUID(&major, &MFMediaType_Video))
415 return MF_E_INVALIDMEDIATYPE;
417 for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i)
418 if (IsEqualGUID(&subtype, h264_decoder_input_types[i]))
419 break;
420 if (i == ARRAY_SIZE(h264_decoder_input_types))
421 return MF_E_INVALIDMEDIATYPE;
422 if (flags & MFT_SET_TYPE_TEST_ONLY)
423 return S_OK;
425 if (decoder->output_type)
427 IMFMediaType_Release(decoder->output_type);
428 decoder->output_type = NULL;
431 if (decoder->input_type)
432 IMFMediaType_Release(decoder->input_type);
433 IMFMediaType_AddRef((decoder->input_type = type));
435 if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
437 decoder->wg_format.u.video.width = frame_size >> 32;
438 decoder->wg_format.u.video.height = (UINT32)frame_size;
441 return S_OK;
444 static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
446 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
447 GUID major, subtype;
448 UINT64 frame_size;
449 HRESULT hr;
450 ULONG i;
452 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
454 if (!decoder->input_type)
455 return MF_E_TRANSFORM_TYPE_NOT_SET;
457 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
458 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
459 return hr;
461 if (!IsEqualGUID(&major, &MFMediaType_Video))
462 return MF_E_INVALIDMEDIATYPE;
464 for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i)
465 if (IsEqualGUID(&subtype, h264_decoder_output_types[i]))
466 break;
467 if (i == ARRAY_SIZE(h264_decoder_output_types))
468 return MF_E_INVALIDMEDIATYPE;
470 if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))
471 || (frame_size >> 32) != decoder->wg_format.u.video.width
472 || (UINT32)frame_size != decoder->wg_format.u.video.height)
473 return MF_E_INVALIDMEDIATYPE;
474 if (flags & MFT_SET_TYPE_TEST_ONLY)
475 return S_OK;
477 if (decoder->output_type)
478 IMFMediaType_Release(decoder->output_type);
479 IMFMediaType_AddRef((decoder->output_type = type));
481 if (decoder->wg_transform)
483 struct wg_format output_format;
484 mf_media_type_to_wg_format(decoder->output_type, &output_format);
486 /* Don't force any specific size, H264 streams already have the metadata for it
487 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
489 output_format.u.video.width = 0;
490 output_format.u.video.height = 0;
491 output_format.u.video.fps_d = 0;
492 output_format.u.video.fps_n = 0;
494 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN
495 || !wg_transform_set_output_format(decoder->wg_transform, &output_format))
497 IMFMediaType_Release(decoder->output_type);
498 decoder->output_type = NULL;
499 return MF_E_INVALIDMEDIATYPE;
502 else if (FAILED(hr = try_create_wg_transform(decoder)))
504 IMFMediaType_Release(decoder->output_type);
505 decoder->output_type = NULL;
508 return hr;
511 static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
513 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
514 return E_NOTIMPL;
517 static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
519 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
520 HRESULT hr;
522 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
524 if (!decoder->output_type)
525 return MF_E_TRANSFORM_TYPE_NOT_SET;
527 if (FAILED(hr = MFCreateMediaType(type)))
528 return hr;
530 return IMFMediaType_CopyAllItems(decoder->output_type, (IMFAttributes *)*type);
533 static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
535 FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags);
536 return E_NOTIMPL;
539 static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
541 FIXME("iface %p, flags %p stub!\n", iface, flags);
542 return E_NOTIMPL;
545 static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
547 FIXME("iface %p, lower %I64d, upper %I64d stub!\n", iface, lower, upper);
548 return E_NOTIMPL;
551 static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
553 FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
554 return E_NOTIMPL;
557 static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
559 FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param);
560 return S_OK;
563 static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
565 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
566 struct wg_sample *wg_sample;
567 MFT_INPUT_STREAM_INFO info;
568 HRESULT hr;
570 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
572 if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info)))
573 return hr;
575 if (!decoder->wg_transform)
576 return MF_E_TRANSFORM_TYPE_NOT_SET;
578 if (FAILED(hr = wg_sample_create_mf(sample, &wg_sample)))
579 return hr;
581 return wg_transform_push_mf(decoder->wg_transform, wg_sample, decoder->wg_sample_queue);
584 static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
585 MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
587 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
588 struct wg_sample *wg_sample;
589 struct wg_format wg_format;
590 UINT32 sample_size;
591 UINT64 frame_rate;
592 GUID subtype;
593 HRESULT hr;
595 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
597 if (count != 1)
598 return E_INVALIDARG;
600 if (!decoder->wg_transform)
601 return MF_E_TRANSFORM_TYPE_NOT_SET;
603 *status = 0;
604 samples[0].dwStatus = 0;
605 if (!samples[0].pSample) return E_INVALIDARG;
607 if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype)))
608 return hr;
609 if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width,
610 decoder->wg_format.u.video.height, &sample_size)))
611 return hr;
613 if (FAILED(hr = wg_sample_create_mf(samples[0].pSample, &wg_sample)))
614 return hr;
616 if (wg_sample->max_size < sample_size)
618 wg_sample_release(wg_sample);
619 return MF_E_BUFFERTOOSMALL;
622 if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, wg_sample, &wg_format)))
623 wg_sample_queue_flush(decoder->wg_sample_queue, false);
624 wg_sample_release(wg_sample);
626 if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
628 decoder->wg_format = wg_format;
630 /* keep the frame rate that was requested, GStreamer doesn't provide any */
631 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate)))
633 decoder->wg_format.u.video.fps_n = frame_rate >> 32;
634 decoder->wg_format.u.video.fps_d = (UINT32)frame_rate;
637 samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
638 *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
641 return hr;
644 static const IMFTransformVtbl transform_vtbl =
646 transform_QueryInterface,
647 transform_AddRef,
648 transform_Release,
649 transform_GetStreamLimits,
650 transform_GetStreamCount,
651 transform_GetStreamIDs,
652 transform_GetInputStreamInfo,
653 transform_GetOutputStreamInfo,
654 transform_GetAttributes,
655 transform_GetInputStreamAttributes,
656 transform_GetOutputStreamAttributes,
657 transform_DeleteInputStream,
658 transform_AddInputStreams,
659 transform_GetInputAvailableType,
660 transform_GetOutputAvailableType,
661 transform_SetInputType,
662 transform_SetOutputType,
663 transform_GetInputCurrentType,
664 transform_GetOutputCurrentType,
665 transform_GetInputStatus,
666 transform_GetOutputStatus,
667 transform_SetOutputBounds,
668 transform_ProcessEvent,
669 transform_ProcessMessage,
670 transform_ProcessInput,
671 transform_ProcessOutput,
674 HRESULT h264_decoder_create(REFIID riid, void **ret)
676 static const struct wg_format output_format =
678 .major_type = WG_MAJOR_TYPE_VIDEO,
679 .u.video =
681 .format = WG_VIDEO_FORMAT_I420,
682 .width = 1920,
683 .height = 1080,
686 static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_H264};
687 struct wg_transform *transform;
688 struct h264_decoder *decoder;
689 HRESULT hr;
691 TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
693 if (!(transform = wg_transform_create(&input_format, &output_format)))
695 ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n");
696 return E_FAIL;
698 wg_transform_destroy(transform);
700 if (!(decoder = calloc(1, sizeof(*decoder))))
701 return E_OUTOFMEMORY;
703 decoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
704 decoder->refcount = 1;
705 decoder->wg_format.u.video.format = WG_VIDEO_FORMAT_UNKNOWN;
706 decoder->wg_format.u.video.width = 1920;
707 decoder->wg_format.u.video.height = 1080;
708 decoder->wg_format.u.video.fps_n = 30000;
709 decoder->wg_format.u.video.fps_d = 1001;
711 if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue)))
713 free(decoder);
714 return hr;
717 *ret = &decoder->IMFTransform_iface;
718 TRACE("Created decoder %p\n", *ret);
719 return S_OK;