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"
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
[] =
35 &MFVideoFormat_H264_ES
,
37 static const GUID
*const h264_decoder_output_types
[] =
48 IMFTransform IMFTransform_iface
;
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
)))
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
;
106 if (FAILED(hr
= IMFMediaType_GetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
)))
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
)))
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
)))
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
)))
132 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_SAMPLE_SIZE
, NULL
)))
134 if (FAILED(hr
= MFCalculateImageSize(&subtype
, width
, height
, &value
)))
136 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_SAMPLE_SIZE
, value
)))
140 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_DEFAULT_STRIDE
, NULL
)))
142 if (FAILED(hr
= MFGetStrideForBitmapInfoHeader(subtype
.Data1
, width
, (LONG
*)&value
)))
144 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_DEFAULT_STRIDE
, value
)))
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
)))
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
)))
160 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, value
)))
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
)))
168 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_VIDEO_ROTATION
, value
)))
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
)))
176 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_FIXED_SIZE_SAMPLES
, value
)))
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
))))
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
;
211 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
212 return E_NOINTERFACE
;
215 IUnknown_AddRef((IUnknown
*)*out
);
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
);
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
);
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
);
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
);
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
);
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
);
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;
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;
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
);
322 IMFAttributes_AddRef((*attributes
= decoder
->attributes
));
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
);
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
);
341 return MF_E_INVALIDSTREAMNUMBER
;
343 IMFAttributes_AddRef((*attributes
= decoder
->output_attributes
));
347 static HRESULT WINAPI
transform_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
349 FIXME("iface %p, id %#lx stub!\n", iface
, id
);
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
);
359 static HRESULT WINAPI
transform_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
362 IMFMediaType
*media_type
;
366 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
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
)))
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
);
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
;
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
;
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
)))
407 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)))
409 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, output_type
)))
412 hr
= fill_output_media_type(decoder
, media_type
);
416 IMFMediaType_AddRef((*type
= media_type
));
418 IMFMediaType_Release(media_type
);
422 static HRESULT WINAPI
transform_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
424 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
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
)))
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
]))
442 if (i
== ARRAY_SIZE(h264_decoder_input_types
))
443 return MF_E_INVALIDMEDIATYPE
;
444 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
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
;
466 static HRESULT WINAPI
transform_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
468 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
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
)))
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
]))
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
)
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
;
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
);
539 static HRESULT WINAPI
transform_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
541 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
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
)))
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
);
561 static HRESULT WINAPI
transform_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
563 FIXME("iface %p, flags %p stub!\n", iface
, flags
);
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
);
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
);
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
);
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
;
608 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface
, flags
, count
, samples
, status
);
613 if (!decoder
->wg_transform
)
614 return MF_E_TRANSFORM_TYPE_NOT_SET
;
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
)))
622 if (FAILED(hr
= MFCalculateImageSize(&subtype
, decoder
->wg_format
.u
.video
.width
,
623 decoder
->wg_format
.u
.video
.height
, &sample_size
)))
626 if (FAILED(hr
= wg_sample_create_mf(samples
[0].pSample
, &wg_sample
)))
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
;
659 static const IMFTransformVtbl transform_vtbl
=
661 transform_QueryInterface
,
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
,
696 .format
= WG_VIDEO_FORMAT_I420
,
701 static const struct wg_format input_format
= {.major_type
= WG_MAJOR_TYPE_H264
};
702 struct wg_transform
*transform
;
703 struct h264_decoder
*decoder
;
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");
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)))
728 if (FAILED(hr
= IMFAttributes_SetUINT32(decoder
->attributes
, &MF_LOW_LATENCY
, 0)))
730 if (FAILED(hr
= MFCreateAttributes(&decoder
->output_attributes
, 0)))
732 if (FAILED(hr
= wg_sample_queue_create(&decoder
->wg_sample_queue
)))
735 *ret
= &decoder
->IMFTransform_iface
;
736 TRACE("Created decoder %p\n", *ret
);
740 if (decoder
->output_attributes
)
741 IMFAttributes_Release(decoder
->output_attributes
);
742 if (decoder
->attributes
)
743 IMFAttributes_Release(decoder
->attributes
);