winegstreamer: Create wg_sample from IMFSample within wg_transform_push_mf.
[wine.git] / dlls / winegstreamer / h264_decoder.c
blob44c6d992b551a8a3b3b294d5294f6d58fa38ad20
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;
51 IMFAttributes *attributes;
52 IMFAttributes *output_attributes;
53 IMFMediaType *input_type;
54 IMFMediaType *output_type;
56 struct wg_format wg_format;
57 struct wg_transform *wg_transform;
58 struct wg_sample_queue *wg_sample_queue;
61 static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
63 return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface);
66 static HRESULT try_create_wg_transform(struct h264_decoder *decoder)
68 struct wg_format input_format;
69 struct wg_format output_format;
71 if (decoder->wg_transform)
72 wg_transform_destroy(decoder->wg_transform);
73 decoder->wg_transform = NULL;
75 mf_media_type_to_wg_format(decoder->input_type, &input_format);
76 if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
77 return MF_E_INVALIDMEDIATYPE;
79 mf_media_type_to_wg_format(decoder->output_type, &output_format);
80 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
81 return MF_E_INVALIDMEDIATYPE;
83 /* Don't force any specific size, H264 streams already have the metadata for it
84 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
86 output_format.u.video.width = 0;
87 output_format.u.video.height = 0;
88 output_format.u.video.fps_d = 0;
89 output_format.u.video.fps_n = 0;
91 if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format)))
92 return E_FAIL;
94 return S_OK;
97 static HRESULT fill_output_media_type(struct h264_decoder *decoder, IMFMediaType *media_type)
99 IMFMediaType *default_type = decoder->output_type;
100 struct wg_format *wg_format = &decoder->wg_format;
101 UINT32 value, width, height;
102 UINT64 ratio;
103 GUID subtype;
104 HRESULT hr;
106 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
107 return hr;
109 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio)))
111 ratio = (UINT64)wg_format->u.video.width << 32 | wg_format->u.video.height;
112 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio)))
113 return hr;
115 width = ratio >> 32;
116 height = ratio;
118 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL)))
120 ratio = (UINT64)wg_format->u.video.fps_n << 32 | wg_format->u.video.fps_d;
121 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio)))
122 return hr;
125 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL)))
127 ratio = (UINT64)1 << 32 | 1; /* FIXME: read it from format */
128 if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, ratio)))
129 return hr;
132 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL)))
134 if (FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value)))
135 return hr;
136 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value)))
137 return hr;
140 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL)))
142 if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, (LONG *)&value)))
143 return hr;
144 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value)))
145 return hr;
148 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL)))
150 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value)))
151 value = MFVideoInterlace_MixedInterlaceOrProgressive;
152 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value)))
153 return hr;
156 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL)))
158 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value)))
159 value = 1;
160 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value)))
161 return hr;
164 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL)))
166 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value)))
167 value = 0;
168 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value)))
169 return hr;
172 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL)))
174 if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value)))
175 value = 1;
176 if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value)))
177 return hr;
180 if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL))
181 && !IsRectEmpty(&wg_format->u.video.padding))
183 MFVideoArea aperture =
185 .OffsetX = {.value = wg_format->u.video.padding.left},
186 .OffsetY = {.value = wg_format->u.video.padding.top},
187 .Area.cx = wg_format->u.video.width - wg_format->u.video.padding.right - wg_format->u.video.padding.left,
188 .Area.cy = wg_format->u.video.height - wg_format->u.video.padding.bottom - wg_format->u.video.padding.top,
191 if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
192 (BYTE *)&aperture, sizeof(aperture))))
193 return hr;
196 return S_OK;
199 static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
201 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
203 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
205 if (IsEqualGUID(iid, &IID_IUnknown) ||
206 IsEqualGUID(iid, &IID_IMFTransform))
207 *out = &decoder->IMFTransform_iface;
208 else
210 *out = NULL;
211 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
212 return E_NOINTERFACE;
215 IUnknown_AddRef((IUnknown *)*out);
216 return S_OK;
219 static ULONG WINAPI transform_AddRef(IMFTransform *iface)
221 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
222 ULONG refcount = InterlockedIncrement(&decoder->refcount);
224 TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount);
226 return refcount;
229 static ULONG WINAPI transform_Release(IMFTransform *iface)
231 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
232 ULONG refcount = InterlockedDecrement(&decoder->refcount);
234 TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount);
236 if (!refcount)
238 if (decoder->wg_transform)
239 wg_transform_destroy(decoder->wg_transform);
240 if (decoder->input_type)
241 IMFMediaType_Release(decoder->input_type);
242 if (decoder->output_type)
243 IMFMediaType_Release(decoder->output_type);
244 if (decoder->output_attributes)
245 IMFAttributes_Release(decoder->output_attributes);
246 if (decoder->attributes)
247 IMFAttributes_Release(decoder->attributes);
249 wg_sample_queue_destroy(decoder->wg_sample_queue);
250 free(decoder);
253 return refcount;
256 static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
257 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
259 FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p stub!\n",
260 iface, input_minimum, input_maximum, output_minimum, output_maximum);
261 return E_NOTIMPL;
264 static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
266 FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs);
267 return E_NOTIMPL;
270 static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size,
271 DWORD *inputs, DWORD output_size, DWORD *outputs)
273 FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p stub!\n", iface,
274 input_size, inputs, output_size, outputs);
275 return E_NOTIMPL;
278 static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
280 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
282 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
284 if (!decoder->input_type)
285 return MF_E_TRANSFORM_TYPE_NOT_SET;
287 info->hnsMaxLatency = 0;
288 info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE;
289 info->cbSize = 0x1000;
290 info->cbMaxLookahead = 0;
291 info->cbAlignment = 0;
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);
299 UINT32 actual_width, actual_height;
301 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
303 actual_width = (decoder->wg_format.u.video.width + 15) & ~15;
304 actual_height = (decoder->wg_format.u.video.height + 15) & ~15;
306 info->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
307 info->cbSize = actual_width * actual_height * 2;
308 info->cbAlignment = 0;
310 return S_OK;
313 static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
315 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
317 FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes);
319 if (!attributes)
320 return E_POINTER;
322 IMFAttributes_AddRef((*attributes = decoder->attributes));
323 return S_OK;
326 static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
328 FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes);
329 return E_NOTIMPL;
332 static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
334 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
336 FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes);
338 if (!attributes)
339 return E_POINTER;
340 if (id)
341 return MF_E_INVALIDSTREAMNUMBER;
343 IMFAttributes_AddRef((*attributes = decoder->output_attributes));
344 return S_OK;
347 static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
349 FIXME("iface %p, id %#lx stub!\n", iface, id);
350 return E_NOTIMPL;
353 static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
355 FIXME("iface %p, streams %lu, ids %p stub!\n", iface, streams, ids);
356 return E_NOTIMPL;
359 static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
360 IMFMediaType **type)
362 IMFMediaType *media_type;
363 const GUID *subtype;
364 HRESULT hr;
366 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
368 *type = NULL;
370 if (index >= ARRAY_SIZE(h264_decoder_input_types))
371 return MF_E_NO_MORE_TYPES;
372 subtype = h264_decoder_input_types[index];
374 if (FAILED(hr = MFCreateMediaType(&media_type)))
375 return hr;
377 if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) &&
378 SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
379 IMFMediaType_AddRef((*type = media_type));
381 IMFMediaType_Release(media_type);
382 return hr;
385 static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id,
386 DWORD index, IMFMediaType **type)
388 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
389 IMFMediaType *media_type;
390 const GUID *output_type;
391 HRESULT hr;
393 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
395 if (!decoder->input_type)
396 return MF_E_TRANSFORM_TYPE_NOT_SET;
398 *type = NULL;
400 if (index >= ARRAY_SIZE(h264_decoder_output_types))
401 return MF_E_NO_MORE_TYPES;
402 output_type = h264_decoder_output_types[index];
404 if (FAILED(hr = MFCreateMediaType(&media_type)))
405 return hr;
407 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
408 goto done;
409 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type)))
410 goto done;
412 hr = fill_output_media_type(decoder, media_type);
414 done:
415 if (SUCCEEDED(hr))
416 IMFMediaType_AddRef((*type = media_type));
418 IMFMediaType_Release(media_type);
419 return hr;
422 static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
424 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
425 GUID major, subtype;
426 UINT64 frame_size;
427 HRESULT hr;
428 ULONG i;
430 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
432 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
433 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
434 return E_INVALIDARG;
436 if (!IsEqualGUID(&major, &MFMediaType_Video))
437 return MF_E_INVALIDMEDIATYPE;
439 for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i)
440 if (IsEqualGUID(&subtype, h264_decoder_input_types[i]))
441 break;
442 if (i == ARRAY_SIZE(h264_decoder_input_types))
443 return MF_E_INVALIDMEDIATYPE;
444 if (flags & MFT_SET_TYPE_TEST_ONLY)
445 return S_OK;
447 if (decoder->output_type)
449 IMFMediaType_Release(decoder->output_type);
450 decoder->output_type = NULL;
453 if (decoder->input_type)
454 IMFMediaType_Release(decoder->input_type);
455 IMFMediaType_AddRef((decoder->input_type = type));
457 if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
459 decoder->wg_format.u.video.width = frame_size >> 32;
460 decoder->wg_format.u.video.height = (UINT32)frame_size;
463 return S_OK;
466 static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
468 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
469 GUID major, subtype;
470 UINT64 frame_size;
471 HRESULT hr;
472 ULONG i;
474 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
476 if (!decoder->input_type)
477 return MF_E_TRANSFORM_TYPE_NOT_SET;
479 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
480 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
481 return hr;
483 if (!IsEqualGUID(&major, &MFMediaType_Video))
484 return MF_E_INVALIDMEDIATYPE;
486 for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i)
487 if (IsEqualGUID(&subtype, h264_decoder_output_types[i]))
488 break;
489 if (i == ARRAY_SIZE(h264_decoder_output_types))
490 return MF_E_INVALIDMEDIATYPE;
492 if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))
493 || (frame_size >> 32) != decoder->wg_format.u.video.width
494 || (UINT32)frame_size != decoder->wg_format.u.video.height)
495 return MF_E_INVALIDMEDIATYPE;
496 if (flags & MFT_SET_TYPE_TEST_ONLY)
497 return S_OK;
499 if (decoder->output_type)
500 IMFMediaType_Release(decoder->output_type);
501 IMFMediaType_AddRef((decoder->output_type = type));
503 if (decoder->wg_transform)
505 struct wg_format output_format;
506 mf_media_type_to_wg_format(decoder->output_type, &output_format);
508 /* Don't force any specific size, H264 streams already have the metadata for it
509 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
511 output_format.u.video.width = 0;
512 output_format.u.video.height = 0;
513 output_format.u.video.fps_d = 0;
514 output_format.u.video.fps_n = 0;
516 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN
517 || !wg_transform_set_output_format(decoder->wg_transform, &output_format))
519 IMFMediaType_Release(decoder->output_type);
520 decoder->output_type = NULL;
521 return MF_E_INVALIDMEDIATYPE;
524 else if (FAILED(hr = try_create_wg_transform(decoder)))
526 IMFMediaType_Release(decoder->output_type);
527 decoder->output_type = NULL;
530 return hr;
533 static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
535 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
536 return E_NOTIMPL;
539 static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
541 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
542 HRESULT hr;
544 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
546 if (!decoder->output_type)
547 return MF_E_TRANSFORM_TYPE_NOT_SET;
549 if (FAILED(hr = MFCreateMediaType(type)))
550 return hr;
552 return IMFMediaType_CopyAllItems(decoder->output_type, (IMFAttributes *)*type);
555 static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
557 FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags);
558 return E_NOTIMPL;
561 static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
563 FIXME("iface %p, flags %p stub!\n", iface, flags);
564 return E_NOTIMPL;
567 static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
569 FIXME("iface %p, lower %I64d, upper %I64d stub!\n", iface, lower, upper);
570 return E_NOTIMPL;
573 static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
575 FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
576 return E_NOTIMPL;
579 static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
581 FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param);
582 return S_OK;
585 static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
587 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
589 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
591 if (!decoder->wg_transform)
592 return MF_E_TRANSFORM_TYPE_NOT_SET;
594 return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue);
597 static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
598 MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
600 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
601 struct wg_sample *wg_sample;
602 struct wg_format wg_format;
603 UINT32 sample_size;
604 UINT64 frame_rate;
605 GUID subtype;
606 HRESULT hr;
608 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
610 if (count != 1)
611 return E_INVALIDARG;
613 if (!decoder->wg_transform)
614 return MF_E_TRANSFORM_TYPE_NOT_SET;
616 *status = 0;
617 samples[0].dwStatus = 0;
618 if (!samples[0].pSample) return E_INVALIDARG;
620 if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype)))
621 return hr;
622 if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width,
623 decoder->wg_format.u.video.height, &sample_size)))
624 return hr;
626 if (FAILED(hr = wg_sample_create_mf(samples[0].pSample, &wg_sample)))
627 return hr;
629 if (wg_sample->max_size < sample_size)
631 wg_sample_release(wg_sample);
632 return MF_E_BUFFERTOOSMALL;
635 if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, wg_sample, &wg_format,
636 &samples[0].dwStatus)))
637 wg_sample_queue_flush(decoder->wg_sample_queue, false);
639 wg_sample_release(wg_sample);
641 if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
643 decoder->wg_format = wg_format;
645 /* keep the frame rate that was requested, GStreamer doesn't provide any */
646 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate)))
648 decoder->wg_format.u.video.fps_n = frame_rate >> 32;
649 decoder->wg_format.u.video.fps_d = (UINT32)frame_rate;
652 samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
653 *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
656 return hr;
659 static const IMFTransformVtbl transform_vtbl =
661 transform_QueryInterface,
662 transform_AddRef,
663 transform_Release,
664 transform_GetStreamLimits,
665 transform_GetStreamCount,
666 transform_GetStreamIDs,
667 transform_GetInputStreamInfo,
668 transform_GetOutputStreamInfo,
669 transform_GetAttributes,
670 transform_GetInputStreamAttributes,
671 transform_GetOutputStreamAttributes,
672 transform_DeleteInputStream,
673 transform_AddInputStreams,
674 transform_GetInputAvailableType,
675 transform_GetOutputAvailableType,
676 transform_SetInputType,
677 transform_SetOutputType,
678 transform_GetInputCurrentType,
679 transform_GetOutputCurrentType,
680 transform_GetInputStatus,
681 transform_GetOutputStatus,
682 transform_SetOutputBounds,
683 transform_ProcessEvent,
684 transform_ProcessMessage,
685 transform_ProcessInput,
686 transform_ProcessOutput,
689 HRESULT h264_decoder_create(REFIID riid, void **ret)
691 static const struct wg_format output_format =
693 .major_type = WG_MAJOR_TYPE_VIDEO,
694 .u.video =
696 .format = WG_VIDEO_FORMAT_I420,
697 .width = 1920,
698 .height = 1080,
701 static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_H264};
702 struct wg_transform *transform;
703 struct h264_decoder *decoder;
704 HRESULT hr;
706 TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
708 if (!(transform = wg_transform_create(&input_format, &output_format)))
710 ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n");
711 return E_FAIL;
713 wg_transform_destroy(transform);
715 if (!(decoder = calloc(1, sizeof(*decoder))))
716 return E_OUTOFMEMORY;
718 decoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
719 decoder->refcount = 1;
720 decoder->wg_format.u.video.format = WG_VIDEO_FORMAT_UNKNOWN;
721 decoder->wg_format.u.video.width = 1920;
722 decoder->wg_format.u.video.height = 1080;
723 decoder->wg_format.u.video.fps_n = 30000;
724 decoder->wg_format.u.video.fps_d = 1001;
726 if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16)))
727 goto failed;
728 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0)))
729 goto failed;
730 if (FAILED(hr = MFCreateAttributes(&decoder->output_attributes, 0)))
731 goto failed;
732 if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue)))
733 goto failed;
735 *ret = &decoder->IMFTransform_iface;
736 TRACE("Created decoder %p\n", *ret);
737 return S_OK;
739 failed:
740 if (decoder->output_attributes)
741 IMFAttributes_Release(decoder->output_attributes);
742 if (decoder->attributes)
743 IMFAttributes_Release(decoder->attributes);
744 free(decoder);
745 return hr;