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 #define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment)))
34 static const GUID
*const h264_decoder_input_types
[] =
37 &MFVideoFormat_H264_ES
,
39 static const GUID
*const h264_decoder_output_types
[] =
50 IMFTransform IMFTransform_iface
;
53 IMFAttributes
*attributes
;
54 IMFAttributes
*output_attributes
;
57 IMFMediaType
*input_type
;
58 MFT_INPUT_STREAM_INFO input_info
;
59 IMFMediaType
*output_type
;
60 MFT_OUTPUT_STREAM_INFO output_info
;
61 IMFMediaType
*stream_type
;
63 struct wg_transform
*wg_transform
;
64 struct wg_sample_queue
*wg_sample_queue
;
66 IMFVideoSampleAllocatorEx
*allocator
;
67 BOOL allocator_initialized
;
69 IMFMediaBuffer
*temp_buffer
;
72 static struct h264_decoder
*impl_from_IMFTransform(IMFTransform
*iface
)
74 return CONTAINING_RECORD(iface
, struct h264_decoder
, IMFTransform_iface
);
77 static HRESULT
try_create_wg_transform(struct h264_decoder
*decoder
)
79 struct wg_transform_attrs attrs
=
81 .output_plane_align
= 15,
83 struct wg_format input_format
;
84 struct wg_format output_format
;
86 if (decoder
->wg_transform
)
87 wg_transform_destroy(decoder
->wg_transform
);
88 decoder
->wg_transform
= NULL
;
90 mf_media_type_to_wg_format(decoder
->input_type
, &input_format
);
91 if (input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
92 return MF_E_INVALIDMEDIATYPE
;
94 mf_media_type_to_wg_format(decoder
->output_type
, &output_format
);
95 if (output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
96 return MF_E_INVALIDMEDIATYPE
;
98 /* Don't force any specific size, H264 streams already have the metadata for it
99 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
101 output_format
.u
.video
.width
= 0;
102 output_format
.u
.video
.height
= 0;
103 output_format
.u
.video
.fps_d
= 0;
104 output_format
.u
.video
.fps_n
= 0;
106 if (!(decoder
->wg_transform
= wg_transform_create(&input_format
, &output_format
, &attrs
)))
112 static HRESULT
fill_output_media_type(struct h264_decoder
*decoder
, IMFMediaType
*media_type
)
114 IMFMediaType
*default_type
= decoder
->output_type
;
115 UINT32 value
, width
, height
;
116 MFVideoArea aperture
;
121 if (FAILED(hr
= IMFMediaType_GetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
)))
124 if (FAILED(hr
= IMFMediaType_GetUINT64(media_type
, &MF_MT_FRAME_SIZE
, &ratio
)))
126 if (FAILED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, &ratio
)))
127 ratio
= (UINT64
)1920 << 32 | 1080;
128 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_FRAME_SIZE
, ratio
)))
134 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_FRAME_RATE
, NULL
)))
136 if (FAILED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_RATE
, &ratio
)))
137 ratio
= (UINT64
)30000 << 32 | 1001;
138 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_FRAME_RATE
, ratio
)))
142 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_PIXEL_ASPECT_RATIO
, NULL
)))
144 if (FAILED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_PIXEL_ASPECT_RATIO
, &ratio
)))
145 ratio
= (UINT64
)1 << 32 | 1;
146 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_PIXEL_ASPECT_RATIO
, ratio
)))
150 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_SAMPLE_SIZE
, NULL
)))
152 if (FAILED(hr
= MFCalculateImageSize(&subtype
, width
, height
, &value
)))
154 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_SAMPLE_SIZE
, value
)))
158 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_DEFAULT_STRIDE
, NULL
)))
160 if (FAILED(hr
= MFGetStrideForBitmapInfoHeader(subtype
.Data1
, width
, (LONG
*)&value
)))
162 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_DEFAULT_STRIDE
, value
)))
166 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_INTERLACE_MODE
, NULL
)))
168 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_INTERLACE_MODE
, &value
)))
169 value
= MFVideoInterlace_MixedInterlaceOrProgressive
;
170 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_INTERLACE_MODE
, value
)))
174 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, NULL
)))
176 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, &value
)))
178 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, value
)))
182 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_VIDEO_ROTATION
, NULL
)))
184 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_VIDEO_ROTATION
, &value
)))
186 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_VIDEO_ROTATION
, value
)))
190 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_FIXED_SIZE_SAMPLES
, NULL
)))
192 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_FIXED_SIZE_SAMPLES
, &value
)))
194 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_FIXED_SIZE_SAMPLES
, value
)))
198 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
, NULL
))
199 && SUCCEEDED(hr
= IMFMediaType_GetBlob(decoder
->stream_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
,
200 (BYTE
*)&aperture
, sizeof(aperture
), &value
)))
202 if (FAILED(hr
= IMFMediaType_SetBlob(media_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
,
203 (BYTE
*)&aperture
, sizeof(aperture
))))
210 static HRESULT
init_allocator(struct h264_decoder
*decoder
)
214 if (decoder
->allocator_initialized
)
217 if (FAILED(hr
= IMFTransform_SetInputType(decoder
->copier
, 0, decoder
->output_type
, 0)))
219 if (FAILED(hr
= IMFTransform_SetOutputType(decoder
->copier
, 0, decoder
->output_type
, 0)))
222 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder
->allocator
, 10, 10,
223 decoder
->attributes
, decoder
->output_type
)))
225 decoder
->allocator_initialized
= TRUE
;
229 static void uninit_allocator(struct h264_decoder
*decoder
)
231 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(decoder
->allocator
);
232 decoder
->allocator_initialized
= FALSE
;
235 static HRESULT WINAPI
transform_QueryInterface(IMFTransform
*iface
, REFIID iid
, void **out
)
237 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
239 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
241 if (IsEqualGUID(iid
, &IID_IUnknown
) ||
242 IsEqualGUID(iid
, &IID_IMFTransform
))
243 *out
= &decoder
->IMFTransform_iface
;
247 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
248 return E_NOINTERFACE
;
251 IUnknown_AddRef((IUnknown
*)*out
);
255 static ULONG WINAPI
transform_AddRef(IMFTransform
*iface
)
257 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
258 ULONG refcount
= InterlockedIncrement(&decoder
->refcount
);
260 TRACE("iface %p increasing refcount to %lu.\n", decoder
, refcount
);
265 static ULONG WINAPI
transform_Release(IMFTransform
*iface
)
267 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
268 ULONG refcount
= InterlockedDecrement(&decoder
->refcount
);
270 TRACE("iface %p decreasing refcount to %lu.\n", decoder
, refcount
);
274 IMFTransform_Release(decoder
->copier
);
275 IMFVideoSampleAllocatorEx_Release(decoder
->allocator
);
276 if (decoder
->temp_buffer
)
277 IMFMediaBuffer_Release(decoder
->temp_buffer
);
278 if (decoder
->wg_transform
)
279 wg_transform_destroy(decoder
->wg_transform
);
280 if (decoder
->input_type
)
281 IMFMediaType_Release(decoder
->input_type
);
282 if (decoder
->output_type
)
283 IMFMediaType_Release(decoder
->output_type
);
284 if (decoder
->output_attributes
)
285 IMFAttributes_Release(decoder
->output_attributes
);
286 if (decoder
->attributes
)
287 IMFAttributes_Release(decoder
->attributes
);
288 wg_sample_queue_destroy(decoder
->wg_sample_queue
);
295 static HRESULT WINAPI
transform_GetStreamLimits(IMFTransform
*iface
, DWORD
*input_minimum
,
296 DWORD
*input_maximum
, DWORD
*output_minimum
, DWORD
*output_maximum
)
298 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
299 iface
, input_minimum
, input_maximum
, output_minimum
, output_maximum
);
300 *input_minimum
= *input_maximum
= *output_minimum
= *output_maximum
= 1;
304 static HRESULT WINAPI
transform_GetStreamCount(IMFTransform
*iface
, DWORD
*inputs
, DWORD
*outputs
)
306 TRACE("iface %p, inputs %p, outputs %p.\n", iface
, inputs
, outputs
);
307 *inputs
= *outputs
= 1;
311 static HRESULT WINAPI
transform_GetStreamIDs(IMFTransform
*iface
, DWORD input_size
, DWORD
*inputs
,
312 DWORD output_size
, DWORD
*outputs
)
314 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface
,
315 input_size
, inputs
, output_size
, outputs
);
319 static HRESULT WINAPI
transform_GetInputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_INPUT_STREAM_INFO
*info
)
321 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
323 TRACE("iface %p, id %#lx, info %p.\n", iface
, id
, info
);
325 *info
= decoder
->input_info
;
329 static HRESULT WINAPI
transform_GetOutputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_OUTPUT_STREAM_INFO
*info
)
331 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
333 TRACE("iface %p, id %#lx, info %p.\n", iface
, id
, info
);
335 *info
= decoder
->output_info
;
339 static HRESULT WINAPI
transform_GetAttributes(IMFTransform
*iface
, IMFAttributes
**attributes
)
341 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
343 FIXME("iface %p, attributes %p semi-stub!\n", iface
, attributes
);
348 IMFAttributes_AddRef((*attributes
= decoder
->attributes
));
352 static HRESULT WINAPI
transform_GetInputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
354 TRACE("iface %p, id %#lx, attributes %p.\n", iface
, id
, attributes
);
358 static HRESULT WINAPI
transform_GetOutputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
360 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
362 FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface
, id
, attributes
);
367 return MF_E_INVALIDSTREAMNUMBER
;
369 IMFAttributes_AddRef((*attributes
= decoder
->output_attributes
));
373 static HRESULT WINAPI
transform_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
375 TRACE("iface %p, id %#lx.\n", iface
, id
);
379 static HRESULT WINAPI
transform_AddInputStreams(IMFTransform
*iface
, DWORD streams
, DWORD
*ids
)
381 TRACE("iface %p, streams %lu, ids %p.\n", iface
, streams
, ids
);
385 static HRESULT WINAPI
transform_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
388 IMFMediaType
*media_type
;
392 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
396 if (index
>= ARRAY_SIZE(h264_decoder_input_types
))
397 return MF_E_NO_MORE_TYPES
;
398 subtype
= h264_decoder_input_types
[index
];
400 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
403 if (SUCCEEDED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)) &&
404 SUCCEEDED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, subtype
)))
405 IMFMediaType_AddRef((*type
= media_type
));
407 IMFMediaType_Release(media_type
);
411 static HRESULT WINAPI
transform_GetOutputAvailableType(IMFTransform
*iface
, DWORD id
,
412 DWORD index
, IMFMediaType
**type
)
414 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
415 IMFMediaType
*media_type
;
416 const GUID
*output_type
;
419 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
421 if (!decoder
->input_type
)
422 return MF_E_TRANSFORM_TYPE_NOT_SET
;
426 if (index
>= ARRAY_SIZE(h264_decoder_output_types
))
427 return MF_E_NO_MORE_TYPES
;
428 output_type
= h264_decoder_output_types
[index
];
430 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
433 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)))
435 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, output_type
)))
438 hr
= fill_output_media_type(decoder
, media_type
);
442 IMFMediaType_AddRef((*type
= media_type
));
444 IMFMediaType_Release(media_type
);
448 static HRESULT WINAPI
transform_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
450 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
456 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
458 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)) ||
459 FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
462 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
463 return MF_E_INVALIDMEDIATYPE
;
465 for (i
= 0; i
< ARRAY_SIZE(h264_decoder_input_types
); ++i
)
466 if (IsEqualGUID(&subtype
, h264_decoder_input_types
[i
]))
468 if (i
== ARRAY_SIZE(h264_decoder_input_types
))
469 return MF_E_INVALIDMEDIATYPE
;
470 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
473 if (decoder
->output_type
)
475 IMFMediaType_Release(decoder
->output_type
);
476 decoder
->output_type
= NULL
;
479 if (decoder
->input_type
)
480 IMFMediaType_Release(decoder
->input_type
);
481 IMFMediaType_AddRef((decoder
->input_type
= type
));
483 if (SUCCEEDED(IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
485 if (FAILED(hr
= IMFMediaType_SetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, frame_size
)))
486 WARN("Failed to update stream type frame size, hr %#lx\n", hr
);
487 decoder
->output_info
.cbSize
= (frame_size
>> 32) * (UINT32
)frame_size
* 2;
493 static HRESULT WINAPI
transform_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
495 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
496 UINT64 frame_size
, stream_frame_size
;
501 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
503 if (!decoder
->input_type
)
504 return MF_E_TRANSFORM_TYPE_NOT_SET
;
506 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)) ||
507 FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
510 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
511 return MF_E_INVALIDMEDIATYPE
;
513 for (i
= 0; i
< ARRAY_SIZE(h264_decoder_output_types
); ++i
)
514 if (IsEqualGUID(&subtype
, h264_decoder_output_types
[i
]))
516 if (i
== ARRAY_SIZE(h264_decoder_output_types
))
517 return MF_E_INVALIDMEDIATYPE
;
519 if (FAILED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
520 return MF_E_INVALIDMEDIATYPE
;
521 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, &stream_frame_size
))
522 && frame_size
!= stream_frame_size
)
523 return MF_E_INVALIDMEDIATYPE
;
524 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
527 if (decoder
->output_type
)
528 IMFMediaType_Release(decoder
->output_type
);
529 IMFMediaType_AddRef((decoder
->output_type
= type
));
531 if (decoder
->wg_transform
)
533 struct wg_format output_format
;
534 mf_media_type_to_wg_format(decoder
->output_type
, &output_format
);
536 /* Don't force any specific size, H264 streams already have the metadata for it
537 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
539 output_format
.u
.video
.width
= 0;
540 output_format
.u
.video
.height
= 0;
541 output_format
.u
.video
.fps_d
= 0;
542 output_format
.u
.video
.fps_n
= 0;
544 if (output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
545 || !wg_transform_set_output_format(decoder
->wg_transform
, &output_format
))
547 IMFMediaType_Release(decoder
->output_type
);
548 decoder
->output_type
= NULL
;
549 return MF_E_INVALIDMEDIATYPE
;
552 else if (FAILED(hr
= try_create_wg_transform(decoder
)))
554 IMFMediaType_Release(decoder
->output_type
);
555 decoder
->output_type
= NULL
;
561 static HRESULT WINAPI
transform_GetInputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
563 FIXME("iface %p, id %#lx, type %p stub!\n", iface
, id
, type
);
567 static HRESULT WINAPI
transform_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
569 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
572 FIXME("iface %p, id %#lx, type %p stub!\n", iface
, id
, type
);
574 if (!decoder
->output_type
)
575 return MF_E_TRANSFORM_TYPE_NOT_SET
;
577 if (FAILED(hr
= MFCreateMediaType(type
)))
580 return IMFMediaType_CopyAllItems(decoder
->output_type
, (IMFAttributes
*)*type
);
583 static HRESULT WINAPI
transform_GetInputStatus(IMFTransform
*iface
, DWORD id
, DWORD
*flags
)
585 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
587 TRACE("iface %p, id %#lx, flags %p.\n", iface
, id
, flags
);
589 if (!decoder
->wg_transform
)
590 return MF_E_TRANSFORM_TYPE_NOT_SET
;
592 *flags
= MFT_INPUT_STATUS_ACCEPT_DATA
;
596 static HRESULT WINAPI
transform_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
598 FIXME("iface %p, flags %p stub!\n", iface
, flags
);
602 static HRESULT WINAPI
transform_SetOutputBounds(IMFTransform
*iface
, LONGLONG lower
, LONGLONG upper
)
604 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface
, lower
, upper
);
608 static HRESULT WINAPI
transform_ProcessEvent(IMFTransform
*iface
, DWORD id
, IMFMediaEvent
*event
)
610 FIXME("iface %p, id %#lx, event %p stub!\n", iface
, id
, event
);
614 static HRESULT WINAPI
transform_ProcessMessage(IMFTransform
*iface
, MFT_MESSAGE_TYPE message
, ULONG_PTR param
)
616 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
619 TRACE("iface %p, message %#x, param %Ix.\n", iface
, message
, param
);
623 case MFT_MESSAGE_SET_D3D_MANAGER
:
624 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(decoder
->allocator
, (IUnknown
*)param
)))
627 uninit_allocator(decoder
);
629 decoder
->output_info
.dwFlags
|= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
;
631 decoder
->output_info
.dwFlags
&= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
;
634 case MFT_MESSAGE_COMMAND_DRAIN
:
635 return wg_transform_drain(decoder
->wg_transform
);
637 case MFT_MESSAGE_COMMAND_FLUSH
:
638 return wg_transform_flush(decoder
->wg_transform
);
641 FIXME("Ignoring message %#x.\n", message
);
646 static HRESULT WINAPI
transform_ProcessInput(IMFTransform
*iface
, DWORD id
, IMFSample
*sample
, DWORD flags
)
648 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
650 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface
, id
, sample
, flags
);
652 if (!decoder
->wg_transform
)
653 return MF_E_TRANSFORM_TYPE_NOT_SET
;
655 return wg_transform_push_mf(decoder
->wg_transform
, sample
, decoder
->wg_sample_queue
);
658 static HRESULT
output_sample(struct h264_decoder
*decoder
, IMFSample
**out
, IMFSample
*src_sample
)
660 MFT_OUTPUT_DATA_BUFFER output
[1];
665 if (FAILED(hr
= init_allocator(decoder
)))
667 ERR("Failed to initialize allocator, hr %#lx.\n", hr
);
670 if (FAILED(hr
= IMFVideoSampleAllocatorEx_AllocateSample(decoder
->allocator
, &sample
)))
673 if (FAILED(hr
= IMFTransform_ProcessInput(decoder
->copier
, 0, src_sample
, 0)))
675 IMFSample_Release(sample
);
678 output
[0].pSample
= sample
;
679 if (FAILED(hr
= IMFTransform_ProcessOutput(decoder
->copier
, 0, 1, output
, &status
)))
681 IMFSample_Release(sample
);
688 static HRESULT
handle_stream_type_change(struct h264_decoder
*decoder
, const struct wg_format
*format
)
690 UINT64 frame_size
, frame_rate
;
693 if (decoder
->stream_type
)
694 IMFMediaType_Release(decoder
->stream_type
);
695 if (!(decoder
->stream_type
= mf_media_type_from_wg_format(format
)))
696 return E_OUTOFMEMORY
;
698 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder
->output_type
, &MF_MT_FRAME_RATE
, &frame_rate
))
699 && FAILED(hr
= IMFMediaType_SetUINT64(decoder
->stream_type
, &MF_MT_FRAME_RATE
, frame_rate
)))
700 WARN("Failed to update stream type frame size, hr %#lx\n", hr
);
702 if (FAILED(hr
= IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
704 decoder
->output_info
.cbSize
= (frame_size
>> 32) * (UINT32
)frame_size
* 2;
705 uninit_allocator(decoder
);
707 return MF_E_TRANSFORM_STREAM_CHANGE
;
710 static HRESULT WINAPI
transform_ProcessOutput(IMFTransform
*iface
, DWORD flags
, DWORD count
,
711 MFT_OUTPUT_DATA_BUFFER
*samples
, DWORD
*status
)
713 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
714 struct wg_format wg_format
;
718 UINT64 frame_size
, frame_rate
;
723 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface
, flags
, count
, samples
, status
);
728 if (!decoder
->wg_transform
)
729 return MF_E_TRANSFORM_TYPE_NOT_SET
;
731 *status
= samples
->dwStatus
= 0;
732 if (!(sample
= samples
->pSample
) && !(decoder
->output_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
))
735 if (FAILED(hr
= IMFMediaType_GetGUID(decoder
->output_type
, &MF_MT_SUBTYPE
, &subtype
)))
737 if (FAILED(hr
= IMFMediaType_GetUINT64(decoder
->output_type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
739 if (FAILED(hr
= MFCalculateImageSize(&subtype
, frame_size
>> 32, (UINT32
)frame_size
, &sample_size
)))
742 if (decoder
->output_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
)
744 if (decoder
->temp_buffer
)
746 if (FAILED(IMFMediaBuffer_GetMaxLength(decoder
->temp_buffer
, &size
)) || size
< sample_size
)
748 IMFMediaBuffer_Release(decoder
->temp_buffer
);
749 decoder
->temp_buffer
= NULL
;
752 if (!decoder
->temp_buffer
&& FAILED(hr
= MFCreateMemoryBuffer(sample_size
, &decoder
->temp_buffer
)))
754 if (FAILED(hr
= MFCreateSample(&sample
)))
756 if (FAILED(hr
= IMFSample_AddBuffer(sample
, decoder
->temp_buffer
)))
758 IMFSample_Release(sample
);
763 if (SUCCEEDED(hr
= wg_transform_read_mf(decoder
->wg_transform
, sample
,
764 sample_size
, &wg_format
, &samples
->dwStatus
)))
766 wg_sample_queue_flush(decoder
->wg_sample_queue
, false);
768 if (FAILED(IMFMediaType_GetUINT64(decoder
->input_type
, &MF_MT_FRAME_RATE
, &frame_rate
)))
769 frame_rate
= (UINT64
)30000 << 32 | 1001;
771 duration
= (UINT64
)10000000 * (UINT32
)frame_rate
/ (frame_rate
>> 32);
772 if (FAILED(IMFSample_SetSampleTime(sample
, decoder
->sample_time
)))
773 WARN("Failed to set sample time\n");
774 if (FAILED(IMFSample_SetSampleDuration(sample
, duration
)))
775 WARN("Failed to set sample duration\n");
776 decoder
->sample_time
+= duration
;
779 if (hr
== MF_E_TRANSFORM_STREAM_CHANGE
)
781 samples
[0].dwStatus
|= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE
;
782 *status
|= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE
;
783 hr
= handle_stream_type_change(decoder
, &wg_format
);
786 if (decoder
->output_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
)
788 if (hr
== S_OK
&& FAILED(hr
= output_sample(decoder
, &samples
->pSample
, sample
)))
789 ERR("Failed to output sample, hr %#lx.\n", hr
);
790 IMFSample_Release(sample
);
796 static const IMFTransformVtbl transform_vtbl
=
798 transform_QueryInterface
,
801 transform_GetStreamLimits
,
802 transform_GetStreamCount
,
803 transform_GetStreamIDs
,
804 transform_GetInputStreamInfo
,
805 transform_GetOutputStreamInfo
,
806 transform_GetAttributes
,
807 transform_GetInputStreamAttributes
,
808 transform_GetOutputStreamAttributes
,
809 transform_DeleteInputStream
,
810 transform_AddInputStreams
,
811 transform_GetInputAvailableType
,
812 transform_GetOutputAvailableType
,
813 transform_SetInputType
,
814 transform_SetOutputType
,
815 transform_GetInputCurrentType
,
816 transform_GetOutputCurrentType
,
817 transform_GetInputStatus
,
818 transform_GetOutputStatus
,
819 transform_SetOutputBounds
,
820 transform_ProcessEvent
,
821 transform_ProcessMessage
,
822 transform_ProcessInput
,
823 transform_ProcessOutput
,
826 HRESULT
h264_decoder_create(REFIID riid
, void **ret
)
828 static const struct wg_format output_format
=
830 .major_type
= WG_MAJOR_TYPE_VIDEO
,
833 .format
= WG_VIDEO_FORMAT_I420
,
838 static const struct wg_format input_format
= {.major_type
= WG_MAJOR_TYPE_VIDEO_H264
};
839 struct wg_transform_attrs attrs
= {0};
840 struct wg_transform
*transform
;
841 struct h264_decoder
*decoder
;
844 TRACE("riid %s, ret %p.\n", debugstr_guid(riid
), ret
);
846 if (!(transform
= wg_transform_create(&input_format
, &output_format
, &attrs
)))
848 ERR_(winediag
)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n");
851 wg_transform_destroy(transform
);
853 if (!(decoder
= calloc(1, sizeof(*decoder
))))
854 return E_OUTOFMEMORY
;
856 decoder
->IMFTransform_iface
.lpVtbl
= &transform_vtbl
;
857 decoder
->refcount
= 1;
859 decoder
->input_info
.dwFlags
= MFT_INPUT_STREAM_WHOLE_SAMPLES
| MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
860 | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE
;
861 decoder
->input_info
.cbSize
= 0x1000;
862 decoder
->output_info
.dwFlags
= MFT_OUTPUT_STREAM_WHOLE_SAMPLES
| MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
863 | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE
;
864 decoder
->output_info
.cbSize
= 1920 * 1088 * 2;
866 if (FAILED(hr
= MFCreateMediaType(&decoder
->stream_type
)))
868 if (FAILED(hr
= MFCreateAttributes(&decoder
->attributes
, 16)))
870 if (FAILED(hr
= IMFAttributes_SetUINT32(decoder
->attributes
, &MF_LOW_LATENCY
, 0)))
872 if (FAILED(hr
= IMFAttributes_SetUINT32(decoder
->attributes
, &MF_SA_D3D11_AWARE
, TRUE
)))
874 if (FAILED(hr
= MFCreateAttributes(&decoder
->output_attributes
, 0)))
876 if (FAILED(hr
= wg_sample_queue_create(&decoder
->wg_sample_queue
)))
878 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&decoder
->allocator
)))
880 if (FAILED(hr
= MFCreateSampleCopierMFT(&decoder
->copier
)))
883 *ret
= &decoder
->IMFTransform_iface
;
884 TRACE("Created decoder %p\n", *ret
);
888 if (decoder
->allocator
)
889 IMFVideoSampleAllocatorEx_Release(decoder
->allocator
);
890 if (decoder
->wg_sample_queue
)
891 wg_sample_queue_destroy(decoder
->wg_sample_queue
);
892 if (decoder
->output_attributes
)
893 IMFAttributes_Release(decoder
->output_attributes
);
894 if (decoder
->attributes
)
895 IMFAttributes_Release(decoder
->attributes
);
896 if (decoder
->stream_type
)
897 IMFMediaType_Release(decoder
->stream_type
);