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"
33 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
34 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
36 #define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment)))
38 static const GUID
*const h264_decoder_input_types
[] =
41 &MFVideoFormat_H264_ES
,
43 static const GUID
*const h264_decoder_output_types
[] =
54 IMFTransform IMFTransform_iface
;
57 IMFAttributes
*attributes
;
58 IMFAttributes
*output_attributes
;
61 IMFMediaType
*input_type
;
62 MFT_INPUT_STREAM_INFO input_info
;
63 IMFMediaType
*output_type
;
64 MFT_OUTPUT_STREAM_INFO output_info
;
65 IMFMediaType
*stream_type
;
67 wg_transform_t wg_transform
;
68 struct wg_sample_queue
*wg_sample_queue
;
70 IMFVideoSampleAllocatorEx
*allocator
;
71 BOOL allocator_initialized
;
73 IMFMediaBuffer
*temp_buffer
;
76 static struct h264_decoder
*impl_from_IMFTransform(IMFTransform
*iface
)
78 return CONTAINING_RECORD(iface
, struct h264_decoder
, IMFTransform_iface
);
81 static HRESULT
try_create_wg_transform(struct h264_decoder
*decoder
)
83 /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput
84 * return values, it calls them in a specific order and expects the decoder
85 * transform to be able to queue its input buffers. We need to use a buffer list
86 * to match its expectations.
88 struct wg_transform_attrs attrs
=
90 .output_plane_align
= 15,
91 .input_queue_length
= 15,
93 struct wg_format input_format
;
94 struct wg_format output_format
;
97 if (decoder
->wg_transform
)
98 wg_transform_destroy(decoder
->wg_transform
);
99 decoder
->wg_transform
= 0;
101 mf_media_type_to_wg_format(decoder
->input_type
, &input_format
);
102 if (input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
103 return MF_E_INVALIDMEDIATYPE
;
105 mf_media_type_to_wg_format(decoder
->output_type
, &output_format
);
106 if (output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
107 return MF_E_INVALIDMEDIATYPE
;
109 /* Don't force any specific size, H264 streams already have the metadata for it
110 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
112 output_format
.u
.video
.width
= 0;
113 output_format
.u
.video
.height
= 0;
114 output_format
.u
.video
.fps_d
= 0;
115 output_format
.u
.video
.fps_n
= 0;
117 if (SUCCEEDED(IMFAttributes_GetUINT32(decoder
->attributes
, &MF_LOW_LATENCY
, &low_latency
)))
118 attrs
.low_latency
= !!low_latency
;
120 if (!(decoder
->wg_transform
= wg_transform_create(&input_format
, &output_format
, &attrs
)))
126 static HRESULT
fill_output_media_type(struct h264_decoder
*decoder
, IMFMediaType
*media_type
)
128 IMFMediaType
*default_type
= decoder
->output_type
;
129 UINT32 value
, width
, height
;
130 MFVideoArea aperture
;
135 if (FAILED(hr
= IMFMediaType_GetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
)))
138 if (FAILED(hr
= IMFMediaType_GetUINT64(media_type
, &MF_MT_FRAME_SIZE
, &ratio
)))
140 if (FAILED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, &ratio
)))
141 ratio
= (UINT64
)1920 << 32 | 1080;
142 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_FRAME_SIZE
, ratio
)))
148 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_FRAME_RATE
, NULL
)))
150 if (FAILED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_RATE
, &ratio
)))
151 ratio
= (UINT64
)30000 << 32 | 1001;
152 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_FRAME_RATE
, ratio
)))
156 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_PIXEL_ASPECT_RATIO
, NULL
)))
158 if (FAILED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_PIXEL_ASPECT_RATIO
, &ratio
)))
159 ratio
= (UINT64
)1 << 32 | 1;
160 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_PIXEL_ASPECT_RATIO
, ratio
)))
164 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_SAMPLE_SIZE
, NULL
)))
166 if (FAILED(hr
= MFCalculateImageSize(&subtype
, width
, height
, &value
)))
168 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_SAMPLE_SIZE
, value
)))
172 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_DEFAULT_STRIDE
, NULL
)))
174 if (FAILED(hr
= MFGetStrideForBitmapInfoHeader(subtype
.Data1
, width
, (LONG
*)&value
)))
176 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_DEFAULT_STRIDE
, value
)))
180 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_INTERLACE_MODE
, NULL
)))
182 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_INTERLACE_MODE
, &value
)))
183 value
= MFVideoInterlace_MixedInterlaceOrProgressive
;
184 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_INTERLACE_MODE
, value
)))
188 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, NULL
)))
190 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, &value
)))
192 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, value
)))
196 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_VIDEO_ROTATION
, NULL
)))
198 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_VIDEO_ROTATION
, &value
)))
200 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_VIDEO_ROTATION
, value
)))
204 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_FIXED_SIZE_SAMPLES
, NULL
)))
206 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_FIXED_SIZE_SAMPLES
, &value
)))
208 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_FIXED_SIZE_SAMPLES
, value
)))
212 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
, NULL
))
213 && SUCCEEDED(hr
= IMFMediaType_GetBlob(decoder
->stream_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
,
214 (BYTE
*)&aperture
, sizeof(aperture
), &value
)))
216 if (FAILED(hr
= IMFMediaType_SetBlob(media_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
,
217 (BYTE
*)&aperture
, sizeof(aperture
))))
224 static HRESULT
init_allocator(struct h264_decoder
*decoder
)
228 if (decoder
->allocator_initialized
)
231 if (FAILED(hr
= IMFTransform_SetInputType(decoder
->copier
, 0, decoder
->output_type
, 0)))
233 if (FAILED(hr
= IMFTransform_SetOutputType(decoder
->copier
, 0, decoder
->output_type
, 0)))
236 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder
->allocator
, 10, 10,
237 decoder
->attributes
, decoder
->output_type
)))
239 decoder
->allocator_initialized
= TRUE
;
243 static void uninit_allocator(struct h264_decoder
*decoder
)
245 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(decoder
->allocator
);
246 decoder
->allocator_initialized
= FALSE
;
249 static HRESULT WINAPI
transform_QueryInterface(IMFTransform
*iface
, REFIID iid
, void **out
)
251 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
253 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
255 if (IsEqualGUID(iid
, &IID_IUnknown
) ||
256 IsEqualGUID(iid
, &IID_IMFTransform
))
257 *out
= &decoder
->IMFTransform_iface
;
261 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
262 return E_NOINTERFACE
;
265 IUnknown_AddRef((IUnknown
*)*out
);
269 static ULONG WINAPI
transform_AddRef(IMFTransform
*iface
)
271 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
272 ULONG refcount
= InterlockedIncrement(&decoder
->refcount
);
274 TRACE("iface %p increasing refcount to %lu.\n", decoder
, refcount
);
279 static ULONG WINAPI
transform_Release(IMFTransform
*iface
)
281 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
282 ULONG refcount
= InterlockedDecrement(&decoder
->refcount
);
284 TRACE("iface %p decreasing refcount to %lu.\n", decoder
, refcount
);
288 IMFTransform_Release(decoder
->copier
);
289 IMFVideoSampleAllocatorEx_Release(decoder
->allocator
);
290 if (decoder
->temp_buffer
)
291 IMFMediaBuffer_Release(decoder
->temp_buffer
);
292 if (decoder
->wg_transform
)
293 wg_transform_destroy(decoder
->wg_transform
);
294 if (decoder
->input_type
)
295 IMFMediaType_Release(decoder
->input_type
);
296 if (decoder
->output_type
)
297 IMFMediaType_Release(decoder
->output_type
);
298 if (decoder
->output_attributes
)
299 IMFAttributes_Release(decoder
->output_attributes
);
300 if (decoder
->attributes
)
301 IMFAttributes_Release(decoder
->attributes
);
302 wg_sample_queue_destroy(decoder
->wg_sample_queue
);
309 static HRESULT WINAPI
transform_GetStreamLimits(IMFTransform
*iface
, DWORD
*input_minimum
,
310 DWORD
*input_maximum
, DWORD
*output_minimum
, DWORD
*output_maximum
)
312 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
313 iface
, input_minimum
, input_maximum
, output_minimum
, output_maximum
);
314 *input_minimum
= *input_maximum
= *output_minimum
= *output_maximum
= 1;
318 static HRESULT WINAPI
transform_GetStreamCount(IMFTransform
*iface
, DWORD
*inputs
, DWORD
*outputs
)
320 TRACE("iface %p, inputs %p, outputs %p.\n", iface
, inputs
, outputs
);
321 *inputs
= *outputs
= 1;
325 static HRESULT WINAPI
transform_GetStreamIDs(IMFTransform
*iface
, DWORD input_size
, DWORD
*inputs
,
326 DWORD output_size
, DWORD
*outputs
)
328 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface
,
329 input_size
, inputs
, output_size
, outputs
);
333 static HRESULT WINAPI
transform_GetInputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_INPUT_STREAM_INFO
*info
)
335 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
337 TRACE("iface %p, id %#lx, info %p.\n", iface
, id
, info
);
339 *info
= decoder
->input_info
;
343 static HRESULT WINAPI
transform_GetOutputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_OUTPUT_STREAM_INFO
*info
)
345 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
347 TRACE("iface %p, id %#lx, info %p.\n", iface
, id
, info
);
349 *info
= decoder
->output_info
;
353 static HRESULT WINAPI
transform_GetAttributes(IMFTransform
*iface
, IMFAttributes
**attributes
)
355 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
357 FIXME("iface %p, attributes %p semi-stub!\n", iface
, attributes
);
362 IMFAttributes_AddRef((*attributes
= decoder
->attributes
));
366 static HRESULT WINAPI
transform_GetInputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
368 TRACE("iface %p, id %#lx, attributes %p.\n", iface
, id
, attributes
);
372 static HRESULT WINAPI
transform_GetOutputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
374 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
376 FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface
, id
, attributes
);
381 return MF_E_INVALIDSTREAMNUMBER
;
383 IMFAttributes_AddRef((*attributes
= decoder
->output_attributes
));
387 static HRESULT WINAPI
transform_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
389 TRACE("iface %p, id %#lx.\n", iface
, id
);
393 static HRESULT WINAPI
transform_AddInputStreams(IMFTransform
*iface
, DWORD streams
, DWORD
*ids
)
395 TRACE("iface %p, streams %lu, ids %p.\n", iface
, streams
, ids
);
399 static HRESULT WINAPI
transform_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
402 IMFMediaType
*media_type
;
406 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
410 if (index
>= ARRAY_SIZE(h264_decoder_input_types
))
411 return MF_E_NO_MORE_TYPES
;
412 subtype
= h264_decoder_input_types
[index
];
414 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
417 if (SUCCEEDED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)) &&
418 SUCCEEDED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, subtype
)))
419 IMFMediaType_AddRef((*type
= media_type
));
421 IMFMediaType_Release(media_type
);
425 static HRESULT WINAPI
transform_GetOutputAvailableType(IMFTransform
*iface
, DWORD id
,
426 DWORD index
, IMFMediaType
**type
)
428 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
429 IMFMediaType
*media_type
;
430 const GUID
*output_type
;
433 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
435 if (!decoder
->input_type
)
436 return MF_E_TRANSFORM_TYPE_NOT_SET
;
440 if (index
>= ARRAY_SIZE(h264_decoder_output_types
))
441 return MF_E_NO_MORE_TYPES
;
442 output_type
= h264_decoder_output_types
[index
];
444 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
447 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)))
449 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, output_type
)))
452 hr
= fill_output_media_type(decoder
, media_type
);
456 IMFMediaType_AddRef((*type
= media_type
));
458 IMFMediaType_Release(media_type
);
462 static HRESULT WINAPI
transform_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
464 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
470 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
472 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)) ||
473 FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
476 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
477 return MF_E_INVALIDMEDIATYPE
;
479 for (i
= 0; i
< ARRAY_SIZE(h264_decoder_input_types
); ++i
)
480 if (IsEqualGUID(&subtype
, h264_decoder_input_types
[i
]))
482 if (i
== ARRAY_SIZE(h264_decoder_input_types
))
483 return MF_E_INVALIDMEDIATYPE
;
484 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
487 if (decoder
->output_type
)
489 IMFMediaType_Release(decoder
->output_type
);
490 decoder
->output_type
= NULL
;
493 if (decoder
->input_type
)
494 IMFMediaType_Release(decoder
->input_type
);
495 IMFMediaType_AddRef((decoder
->input_type
= type
));
497 if (SUCCEEDED(IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
499 if (FAILED(hr
= IMFMediaType_SetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, frame_size
)))
500 WARN("Failed to update stream type frame size, hr %#lx\n", hr
);
501 decoder
->output_info
.cbSize
= (frame_size
>> 32) * (UINT32
)frame_size
* 2;
507 static HRESULT WINAPI
transform_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
509 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
510 UINT64 frame_size
, stream_frame_size
;
515 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
517 if (!decoder
->input_type
)
518 return MF_E_TRANSFORM_TYPE_NOT_SET
;
520 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)) ||
521 FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
524 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
525 return MF_E_INVALIDMEDIATYPE
;
527 for (i
= 0; i
< ARRAY_SIZE(h264_decoder_output_types
); ++i
)
528 if (IsEqualGUID(&subtype
, h264_decoder_output_types
[i
]))
530 if (i
== ARRAY_SIZE(h264_decoder_output_types
))
531 return MF_E_INVALIDMEDIATYPE
;
533 if (FAILED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
534 return MF_E_INVALIDMEDIATYPE
;
535 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, &stream_frame_size
))
536 && frame_size
!= stream_frame_size
)
537 return MF_E_INVALIDMEDIATYPE
;
538 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
541 if (decoder
->output_type
)
542 IMFMediaType_Release(decoder
->output_type
);
543 IMFMediaType_AddRef((decoder
->output_type
= type
));
545 if (decoder
->wg_transform
)
547 struct wg_format output_format
;
548 mf_media_type_to_wg_format(decoder
->output_type
, &output_format
);
550 /* Don't force any specific size, H264 streams already have the metadata for it
551 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
553 output_format
.u
.video
.width
= 0;
554 output_format
.u
.video
.height
= 0;
555 output_format
.u
.video
.fps_d
= 0;
556 output_format
.u
.video
.fps_n
= 0;
558 if (output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
559 || !wg_transform_set_output_format(decoder
->wg_transform
, &output_format
))
561 IMFMediaType_Release(decoder
->output_type
);
562 decoder
->output_type
= NULL
;
563 return MF_E_INVALIDMEDIATYPE
;
566 else if (FAILED(hr
= try_create_wg_transform(decoder
)))
568 IMFMediaType_Release(decoder
->output_type
);
569 decoder
->output_type
= NULL
;
575 static HRESULT WINAPI
transform_GetInputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
577 FIXME("iface %p, id %#lx, type %p stub!\n", iface
, id
, type
);
581 static HRESULT WINAPI
transform_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
583 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
586 FIXME("iface %p, id %#lx, type %p stub!\n", iface
, id
, type
);
588 if (!decoder
->output_type
)
589 return MF_E_TRANSFORM_TYPE_NOT_SET
;
591 if (FAILED(hr
= MFCreateMediaType(type
)))
594 return IMFMediaType_CopyAllItems(decoder
->output_type
, (IMFAttributes
*)*type
);
597 static HRESULT WINAPI
transform_GetInputStatus(IMFTransform
*iface
, DWORD id
, DWORD
*flags
)
599 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
601 TRACE("iface %p, id %#lx, flags %p.\n", iface
, id
, flags
);
603 if (!decoder
->wg_transform
)
604 return MF_E_TRANSFORM_TYPE_NOT_SET
;
606 *flags
= MFT_INPUT_STATUS_ACCEPT_DATA
;
610 static HRESULT WINAPI
transform_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
612 FIXME("iface %p, flags %p stub!\n", iface
, flags
);
616 static HRESULT WINAPI
transform_SetOutputBounds(IMFTransform
*iface
, LONGLONG lower
, LONGLONG upper
)
618 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface
, lower
, upper
);
622 static HRESULT WINAPI
transform_ProcessEvent(IMFTransform
*iface
, DWORD id
, IMFMediaEvent
*event
)
624 FIXME("iface %p, id %#lx, event %p stub!\n", iface
, id
, event
);
628 static HRESULT WINAPI
transform_ProcessMessage(IMFTransform
*iface
, MFT_MESSAGE_TYPE message
, ULONG_PTR param
)
630 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
633 TRACE("iface %p, message %#x, param %Ix.\n", iface
, message
, param
);
637 case MFT_MESSAGE_SET_D3D_MANAGER
:
638 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(decoder
->allocator
, (IUnknown
*)param
)))
641 uninit_allocator(decoder
);
643 decoder
->output_info
.dwFlags
|= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
;
645 decoder
->output_info
.dwFlags
&= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
;
648 case MFT_MESSAGE_COMMAND_DRAIN
:
649 return wg_transform_drain(decoder
->wg_transform
);
651 case MFT_MESSAGE_COMMAND_FLUSH
:
652 return wg_transform_flush(decoder
->wg_transform
);
655 FIXME("Ignoring message %#x.\n", message
);
660 static HRESULT WINAPI
transform_ProcessInput(IMFTransform
*iface
, DWORD id
, IMFSample
*sample
, DWORD flags
)
662 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
664 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface
, id
, sample
, flags
);
666 if (!decoder
->wg_transform
)
667 return MF_E_TRANSFORM_TYPE_NOT_SET
;
669 return wg_transform_push_mf(decoder
->wg_transform
, sample
, decoder
->wg_sample_queue
);
672 static HRESULT
output_sample(struct h264_decoder
*decoder
, IMFSample
**out
, IMFSample
*src_sample
)
674 MFT_OUTPUT_DATA_BUFFER output
[1];
679 if (FAILED(hr
= init_allocator(decoder
)))
681 ERR("Failed to initialize allocator, hr %#lx.\n", hr
);
684 if (FAILED(hr
= IMFVideoSampleAllocatorEx_AllocateSample(decoder
->allocator
, &sample
)))
687 if (FAILED(hr
= IMFTransform_ProcessInput(decoder
->copier
, 0, src_sample
, 0)))
689 IMFSample_Release(sample
);
692 output
[0].pSample
= sample
;
693 if (FAILED(hr
= IMFTransform_ProcessOutput(decoder
->copier
, 0, 1, output
, &status
)))
695 IMFSample_Release(sample
);
702 static HRESULT
handle_stream_type_change(struct h264_decoder
*decoder
, const struct wg_format
*format
)
704 UINT64 frame_size
, frame_rate
;
707 if (decoder
->stream_type
)
708 IMFMediaType_Release(decoder
->stream_type
);
709 if (!(decoder
->stream_type
= mf_media_type_from_wg_format(format
)))
710 return E_OUTOFMEMORY
;
712 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder
->output_type
, &MF_MT_FRAME_RATE
, &frame_rate
))
713 && FAILED(hr
= IMFMediaType_SetUINT64(decoder
->stream_type
, &MF_MT_FRAME_RATE
, frame_rate
)))
714 WARN("Failed to update stream type frame size, hr %#lx\n", hr
);
716 if (FAILED(hr
= IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
718 decoder
->output_info
.cbSize
= (frame_size
>> 32) * (UINT32
)frame_size
* 2;
719 uninit_allocator(decoder
);
721 return MF_E_TRANSFORM_STREAM_CHANGE
;
724 static HRESULT WINAPI
transform_ProcessOutput(IMFTransform
*iface
, DWORD flags
, DWORD count
,
725 MFT_OUTPUT_DATA_BUFFER
*samples
, DWORD
*status
)
727 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
728 struct wg_format wg_format
;
732 UINT64 frame_size
, frame_rate
;
737 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface
, flags
, count
, samples
, status
);
742 if (!decoder
->wg_transform
)
743 return MF_E_TRANSFORM_TYPE_NOT_SET
;
745 *status
= samples
->dwStatus
= 0;
746 if (!(sample
= samples
->pSample
) && !(decoder
->output_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
))
749 if (FAILED(hr
= IMFMediaType_GetGUID(decoder
->output_type
, &MF_MT_SUBTYPE
, &subtype
)))
751 if (FAILED(hr
= IMFMediaType_GetUINT64(decoder
->output_type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
753 if (FAILED(hr
= MFCalculateImageSize(&subtype
, frame_size
>> 32, (UINT32
)frame_size
, &sample_size
)))
756 if (decoder
->output_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
)
758 if (decoder
->temp_buffer
)
760 if (FAILED(IMFMediaBuffer_GetMaxLength(decoder
->temp_buffer
, &size
)) || size
< sample_size
)
762 IMFMediaBuffer_Release(decoder
->temp_buffer
);
763 decoder
->temp_buffer
= NULL
;
766 if (!decoder
->temp_buffer
&& FAILED(hr
= MFCreateMemoryBuffer(sample_size
, &decoder
->temp_buffer
)))
768 if (FAILED(hr
= MFCreateSample(&sample
)))
770 if (FAILED(hr
= IMFSample_AddBuffer(sample
, decoder
->temp_buffer
)))
772 IMFSample_Release(sample
);
777 if (SUCCEEDED(hr
= wg_transform_read_mf(decoder
->wg_transform
, sample
,
778 sample_size
, &wg_format
, &samples
->dwStatus
)))
780 wg_sample_queue_flush(decoder
->wg_sample_queue
, false);
782 if (FAILED(IMFMediaType_GetUINT64(decoder
->input_type
, &MF_MT_FRAME_RATE
, &frame_rate
)))
783 frame_rate
= (UINT64
)30000 << 32 | 1001;
785 duration
= (UINT64
)10000000 * (UINT32
)frame_rate
/ (frame_rate
>> 32);
786 if (FAILED(IMFSample_SetSampleTime(sample
, decoder
->sample_time
)))
787 WARN("Failed to set sample time\n");
788 if (FAILED(IMFSample_SetSampleDuration(sample
, duration
)))
789 WARN("Failed to set sample duration\n");
790 decoder
->sample_time
+= duration
;
793 if (hr
== MF_E_TRANSFORM_STREAM_CHANGE
)
795 samples
[0].dwStatus
|= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE
;
796 *status
|= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE
;
797 hr
= handle_stream_type_change(decoder
, &wg_format
);
800 if (decoder
->output_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
)
802 if (hr
== S_OK
&& FAILED(hr
= output_sample(decoder
, &samples
->pSample
, sample
)))
803 ERR("Failed to output sample, hr %#lx.\n", hr
);
804 IMFSample_Release(sample
);
810 static const IMFTransformVtbl transform_vtbl
=
812 transform_QueryInterface
,
815 transform_GetStreamLimits
,
816 transform_GetStreamCount
,
817 transform_GetStreamIDs
,
818 transform_GetInputStreamInfo
,
819 transform_GetOutputStreamInfo
,
820 transform_GetAttributes
,
821 transform_GetInputStreamAttributes
,
822 transform_GetOutputStreamAttributes
,
823 transform_DeleteInputStream
,
824 transform_AddInputStreams
,
825 transform_GetInputAvailableType
,
826 transform_GetOutputAvailableType
,
827 transform_SetInputType
,
828 transform_SetOutputType
,
829 transform_GetInputCurrentType
,
830 transform_GetOutputCurrentType
,
831 transform_GetInputStatus
,
832 transform_GetOutputStatus
,
833 transform_SetOutputBounds
,
834 transform_ProcessEvent
,
835 transform_ProcessMessage
,
836 transform_ProcessInput
,
837 transform_ProcessOutput
,
840 HRESULT
h264_decoder_create(REFIID riid
, void **ret
)
842 static const struct wg_format output_format
=
844 .major_type
= WG_MAJOR_TYPE_VIDEO
,
847 .format
= WG_VIDEO_FORMAT_I420
,
852 static const struct wg_format input_format
= {.major_type
= WG_MAJOR_TYPE_VIDEO_H264
};
853 struct wg_transform_attrs attrs
= {0};
854 wg_transform_t transform
;
855 struct h264_decoder
*decoder
;
858 TRACE("riid %s, ret %p.\n", debugstr_guid(riid
), ret
);
860 if (!(transform
= wg_transform_create(&input_format
, &output_format
, &attrs
)))
862 ERR_(winediag
)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n");
865 wg_transform_destroy(transform
);
867 if (!(decoder
= calloc(1, sizeof(*decoder
))))
868 return E_OUTOFMEMORY
;
870 decoder
->IMFTransform_iface
.lpVtbl
= &transform_vtbl
;
871 decoder
->refcount
= 1;
873 decoder
->input_info
.dwFlags
= MFT_INPUT_STREAM_WHOLE_SAMPLES
| MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
874 | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE
;
875 decoder
->input_info
.cbSize
= 0x1000;
876 decoder
->output_info
.dwFlags
= MFT_OUTPUT_STREAM_WHOLE_SAMPLES
| MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
877 | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE
;
878 decoder
->output_info
.cbSize
= 1920 * 1088 * 2;
880 if (FAILED(hr
= MFCreateMediaType(&decoder
->stream_type
)))
882 if (FAILED(hr
= MFCreateAttributes(&decoder
->attributes
, 16)))
884 if (FAILED(hr
= IMFAttributes_SetUINT32(decoder
->attributes
, &MF_LOW_LATENCY
, 0)))
886 if (FAILED(hr
= IMFAttributes_SetUINT32(decoder
->attributes
, &MF_SA_D3D11_AWARE
, TRUE
)))
888 if (FAILED(hr
= IMFAttributes_SetUINT32(decoder
->attributes
, &AVDecVideoAcceleration_H264
, TRUE
)))
891 if (FAILED(hr
= MFCreateAttributes(&decoder
->output_attributes
, 0)))
893 if (FAILED(hr
= wg_sample_queue_create(&decoder
->wg_sample_queue
)))
895 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&decoder
->allocator
)))
897 if (FAILED(hr
= MFCreateSampleCopierMFT(&decoder
->copier
)))
900 *ret
= &decoder
->IMFTransform_iface
;
901 TRACE("Created decoder %p\n", *ret
);
905 if (decoder
->allocator
)
906 IMFVideoSampleAllocatorEx_Release(decoder
->allocator
);
907 if (decoder
->wg_sample_queue
)
908 wg_sample_queue_destroy(decoder
->wg_sample_queue
);
909 if (decoder
->output_attributes
)
910 IMFAttributes_Release(decoder
->output_attributes
);
911 if (decoder
->attributes
)
912 IMFAttributes_Release(decoder
->attributes
);
913 if (decoder
->stream_type
)
914 IMFMediaType_Release(decoder
->stream_type
);