winegstreamer: Create wg_sample from IMFSample within of wg_transform_read_mf.
[wine.git] / dlls / winegstreamer / h264_decoder.c
blobead00e20840eb4df41ae7546c9e5942c15f87657
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 && !IsRectEmpty(&wg_format->u.video.padding))
188 MFVideoArea aperture =
190 .OffsetX = {.value = wg_format->u.video.padding.left},
191 .OffsetY = {.value = wg_format->u.video.padding.top},
192 .Area.cx = wg_format->u.video.width - wg_format->u.video.padding.right - wg_format->u.video.padding.left,
193 .Area.cy = wg_format->u.video.height - wg_format->u.video.padding.bottom - wg_format->u.video.padding.top,
196 if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE,
197 (BYTE *)&aperture, sizeof(aperture))))
198 return hr;
201 return S_OK;
204 static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
206 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
208 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
210 if (IsEqualGUID(iid, &IID_IUnknown) ||
211 IsEqualGUID(iid, &IID_IMFTransform))
212 *out = &decoder->IMFTransform_iface;
213 else
215 *out = NULL;
216 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
217 return E_NOINTERFACE;
220 IUnknown_AddRef((IUnknown *)*out);
221 return S_OK;
224 static ULONG WINAPI transform_AddRef(IMFTransform *iface)
226 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
227 ULONG refcount = InterlockedIncrement(&decoder->refcount);
229 TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount);
231 return refcount;
234 static ULONG WINAPI transform_Release(IMFTransform *iface)
236 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
237 ULONG refcount = InterlockedDecrement(&decoder->refcount);
239 TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount);
241 if (!refcount)
243 if (decoder->wg_transform)
244 wg_transform_destroy(decoder->wg_transform);
245 if (decoder->input_type)
246 IMFMediaType_Release(decoder->input_type);
247 if (decoder->output_type)
248 IMFMediaType_Release(decoder->output_type);
249 if (decoder->output_attributes)
250 IMFAttributes_Release(decoder->output_attributes);
251 if (decoder->attributes)
252 IMFAttributes_Release(decoder->attributes);
254 wg_sample_queue_destroy(decoder->wg_sample_queue);
255 free(decoder);
258 return refcount;
261 static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
262 DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
264 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
265 iface, input_minimum, input_maximum, output_minimum, output_maximum);
266 *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
267 return S_OK;
270 static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
272 TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
273 *inputs = *outputs = 1;
274 return S_OK;
277 static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
278 DWORD output_size, DWORD *outputs)
280 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
281 input_size, inputs, output_size, outputs);
282 return E_NOTIMPL;
285 static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
287 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
289 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
291 *info = decoder->input_info;
292 return S_OK;
295 static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
297 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
299 TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
301 *info = decoder->output_info;
302 return S_OK;
305 static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
307 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
309 FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes);
311 if (!attributes)
312 return E_POINTER;
314 IMFAttributes_AddRef((*attributes = decoder->attributes));
315 return S_OK;
318 static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
320 TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
321 return E_NOTIMPL;
324 static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
326 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
328 FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface, id, attributes);
330 if (!attributes)
331 return E_POINTER;
332 if (id)
333 return MF_E_INVALIDSTREAMNUMBER;
335 IMFAttributes_AddRef((*attributes = decoder->output_attributes));
336 return S_OK;
339 static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
341 TRACE("iface %p, id %#lx.\n", iface, id);
342 return E_NOTIMPL;
345 static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
347 TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
348 return E_NOTIMPL;
351 static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
352 IMFMediaType **type)
354 IMFMediaType *media_type;
355 const GUID *subtype;
356 HRESULT hr;
358 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
360 *type = NULL;
362 if (index >= ARRAY_SIZE(h264_decoder_input_types))
363 return MF_E_NO_MORE_TYPES;
364 subtype = h264_decoder_input_types[index];
366 if (FAILED(hr = MFCreateMediaType(&media_type)))
367 return hr;
369 if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) &&
370 SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
371 IMFMediaType_AddRef((*type = media_type));
373 IMFMediaType_Release(media_type);
374 return hr;
377 static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id,
378 DWORD index, IMFMediaType **type)
380 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
381 IMFMediaType *media_type;
382 const GUID *output_type;
383 HRESULT hr;
385 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
387 if (!decoder->input_type)
388 return MF_E_TRANSFORM_TYPE_NOT_SET;
390 *type = NULL;
392 if (index >= ARRAY_SIZE(h264_decoder_output_types))
393 return MF_E_NO_MORE_TYPES;
394 output_type = h264_decoder_output_types[index];
396 if (FAILED(hr = MFCreateMediaType(&media_type)))
397 return hr;
399 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
400 goto done;
401 if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type)))
402 goto done;
404 hr = fill_output_media_type(decoder, media_type);
406 done:
407 if (SUCCEEDED(hr))
408 IMFMediaType_AddRef((*type = media_type));
410 IMFMediaType_Release(media_type);
411 return hr;
414 static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
416 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
417 GUID major, subtype;
418 UINT64 frame_size;
419 HRESULT hr;
420 ULONG i;
422 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
424 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
425 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
426 return E_INVALIDARG;
428 if (!IsEqualGUID(&major, &MFMediaType_Video))
429 return MF_E_INVALIDMEDIATYPE;
431 for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i)
432 if (IsEqualGUID(&subtype, h264_decoder_input_types[i]))
433 break;
434 if (i == ARRAY_SIZE(h264_decoder_input_types))
435 return MF_E_INVALIDMEDIATYPE;
436 if (flags & MFT_SET_TYPE_TEST_ONLY)
437 return S_OK;
439 if (decoder->output_type)
441 IMFMediaType_Release(decoder->output_type);
442 decoder->output_type = NULL;
445 if (decoder->input_type)
446 IMFMediaType_Release(decoder->input_type);
447 IMFMediaType_AddRef((decoder->input_type = type));
449 if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
451 decoder->wg_format.u.video.width = frame_size >> 32;
452 decoder->wg_format.u.video.height = (UINT32)frame_size;
453 decoder->output_info.cbSize = decoder->wg_format.u.video.width
454 * decoder->wg_format.u.video.height * 2;
457 return S_OK;
460 static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
462 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
463 GUID major, subtype;
464 UINT64 frame_size;
465 HRESULT hr;
466 ULONG i;
468 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
470 if (!decoder->input_type)
471 return MF_E_TRANSFORM_TYPE_NOT_SET;
473 if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
474 FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
475 return hr;
477 if (!IsEqualGUID(&major, &MFMediaType_Video))
478 return MF_E_INVALIDMEDIATYPE;
480 for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i)
481 if (IsEqualGUID(&subtype, h264_decoder_output_types[i]))
482 break;
483 if (i == ARRAY_SIZE(h264_decoder_output_types))
484 return MF_E_INVALIDMEDIATYPE;
486 if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))
487 || (frame_size >> 32) != decoder->wg_format.u.video.width
488 || (UINT32)frame_size != decoder->wg_format.u.video.height)
489 return MF_E_INVALIDMEDIATYPE;
490 if (flags & MFT_SET_TYPE_TEST_ONLY)
491 return S_OK;
493 if (decoder->output_type)
494 IMFMediaType_Release(decoder->output_type);
495 IMFMediaType_AddRef((decoder->output_type = type));
497 if (decoder->wg_transform)
499 struct wg_format output_format;
500 mf_media_type_to_wg_format(decoder->output_type, &output_format);
502 /* Don't force any specific size, H264 streams already have the metadata for it
503 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
505 output_format.u.video.width = 0;
506 output_format.u.video.height = 0;
507 output_format.u.video.fps_d = 0;
508 output_format.u.video.fps_n = 0;
510 if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN
511 || !wg_transform_set_output_format(decoder->wg_transform, &output_format))
513 IMFMediaType_Release(decoder->output_type);
514 decoder->output_type = NULL;
515 return MF_E_INVALIDMEDIATYPE;
518 else if (FAILED(hr = try_create_wg_transform(decoder)))
520 IMFMediaType_Release(decoder->output_type);
521 decoder->output_type = NULL;
524 return hr;
527 static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
529 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
530 return E_NOTIMPL;
533 static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
535 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
536 HRESULT hr;
538 FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type);
540 if (!decoder->output_type)
541 return MF_E_TRANSFORM_TYPE_NOT_SET;
543 if (FAILED(hr = MFCreateMediaType(type)))
544 return hr;
546 return IMFMediaType_CopyAllItems(decoder->output_type, (IMFAttributes *)*type);
549 static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
551 FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags);
552 return E_NOTIMPL;
555 static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
557 FIXME("iface %p, flags %p stub!\n", iface, flags);
558 return E_NOTIMPL;
561 static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
563 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
564 return E_NOTIMPL;
567 static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
569 FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
570 return E_NOTIMPL;
573 static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
575 FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param);
576 return S_OK;
579 static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
581 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
583 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
585 if (!decoder->wg_transform)
586 return MF_E_TRANSFORM_TYPE_NOT_SET;
588 return wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue);
591 static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
592 MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
594 struct h264_decoder *decoder = impl_from_IMFTransform(iface);
595 struct wg_format wg_format;
596 UINT32 sample_size;
597 UINT64 frame_rate;
598 GUID subtype;
599 HRESULT hr;
601 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
603 if (count != 1)
604 return E_INVALIDARG;
606 if (!decoder->wg_transform)
607 return MF_E_TRANSFORM_TYPE_NOT_SET;
609 *status = samples->dwStatus = 0;
610 if (!samples->pSample)
611 return E_INVALIDARG;
613 if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype)))
614 return hr;
615 if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width,
616 decoder->wg_format.u.video.height, &sample_size)))
617 return hr;
619 if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample,
620 sample_size, &wg_format, &samples->dwStatus)))
621 wg_sample_queue_flush(decoder->wg_sample_queue, false);
623 if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
625 decoder->wg_format = wg_format;
626 decoder->output_info.cbSize = ALIGN_SIZE(decoder->wg_format.u.video.width, 0xf)
627 * ALIGN_SIZE(decoder->wg_format.u.video.height, 0xf) * 2;
629 /* keep the frame rate that was requested, GStreamer doesn't provide any */
630 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate)))
632 decoder->wg_format.u.video.fps_n = frame_rate >> 32;
633 decoder->wg_format.u.video.fps_d = (UINT32)frame_rate;
636 samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
637 *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
640 return hr;
643 static const IMFTransformVtbl transform_vtbl =
645 transform_QueryInterface,
646 transform_AddRef,
647 transform_Release,
648 transform_GetStreamLimits,
649 transform_GetStreamCount,
650 transform_GetStreamIDs,
651 transform_GetInputStreamInfo,
652 transform_GetOutputStreamInfo,
653 transform_GetAttributes,
654 transform_GetInputStreamAttributes,
655 transform_GetOutputStreamAttributes,
656 transform_DeleteInputStream,
657 transform_AddInputStreams,
658 transform_GetInputAvailableType,
659 transform_GetOutputAvailableType,
660 transform_SetInputType,
661 transform_SetOutputType,
662 transform_GetInputCurrentType,
663 transform_GetOutputCurrentType,
664 transform_GetInputStatus,
665 transform_GetOutputStatus,
666 transform_SetOutputBounds,
667 transform_ProcessEvent,
668 transform_ProcessMessage,
669 transform_ProcessInput,
670 transform_ProcessOutput,
673 HRESULT h264_decoder_create(REFIID riid, void **ret)
675 static const struct wg_format output_format =
677 .major_type = WG_MAJOR_TYPE_VIDEO,
678 .u.video =
680 .format = WG_VIDEO_FORMAT_I420,
681 .width = 1920,
682 .height = 1080,
685 static const struct wg_format input_format = {.major_type = WG_MAJOR_TYPE_VIDEO_H264};
686 struct wg_transform *transform;
687 struct h264_decoder *decoder;
688 HRESULT hr;
690 TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
692 if (!(transform = wg_transform_create(&input_format, &output_format)))
694 ERR_(winediag)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n");
695 return E_FAIL;
697 wg_transform_destroy(transform);
699 if (!(decoder = calloc(1, sizeof(*decoder))))
700 return E_OUTOFMEMORY;
702 decoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
703 decoder->refcount = 1;
704 decoder->wg_format.u.video.format = WG_VIDEO_FORMAT_UNKNOWN;
705 decoder->wg_format.u.video.width = 1920;
706 decoder->wg_format.u.video.height = 1080;
707 decoder->wg_format.u.video.fps_n = 30000;
708 decoder->wg_format.u.video.fps_d = 1001;
710 decoder->input_info.dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
711 | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE;
712 decoder->input_info.cbSize = 0x1000;
713 decoder->output_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
714 | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
715 decoder->output_info.cbSize = 1920 * 1088 * 2;
717 if (FAILED(hr = MFCreateAttributes(&decoder->attributes, 16)))
718 goto failed;
719 if (FAILED(hr = IMFAttributes_SetUINT32(decoder->attributes, &MF_LOW_LATENCY, 0)))
720 goto failed;
721 if (FAILED(hr = MFCreateAttributes(&decoder->output_attributes, 0)))
722 goto failed;
723 if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue)))
724 goto failed;
726 *ret = &decoder->IMFTransform_iface;
727 TRACE("Created decoder %p\n", *ret);
728 return S_OK;
730 failed:
731 if (decoder->output_attributes)
732 IMFAttributes_Release(decoder->output_attributes);
733 if (decoder->attributes)
734 IMFAttributes_Release(decoder->attributes);
735 free(decoder);
736 return hr;