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 wg_transform_t 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 /* Call of Duty: Black Ops 3 doesn't care about the ProcessInput/ProcessOutput
80 * return values, it calls them in a specific order and expects the decoder
81 * transform to be able to queue its input buffers. We need to use a buffer list
82 * to match its expectations.
84 struct wg_transform_attrs attrs
=
86 .output_plane_align
= 15,
87 .input_queue_length
= 15,
89 struct wg_format input_format
;
90 struct wg_format output_format
;
93 if (decoder
->wg_transform
)
94 wg_transform_destroy(decoder
->wg_transform
);
95 decoder
->wg_transform
= 0;
97 mf_media_type_to_wg_format(decoder
->input_type
, &input_format
);
98 if (input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
99 return MF_E_INVALIDMEDIATYPE
;
101 mf_media_type_to_wg_format(decoder
->output_type
, &output_format
);
102 if (output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
103 return MF_E_INVALIDMEDIATYPE
;
105 /* Don't force any specific size, H264 streams already have the metadata for it
106 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
108 output_format
.u
.video
.width
= 0;
109 output_format
.u
.video
.height
= 0;
110 output_format
.u
.video
.fps_d
= 0;
111 output_format
.u
.video
.fps_n
= 0;
113 if (SUCCEEDED(IMFAttributes_GetUINT32(decoder
->attributes
, &MF_LOW_LATENCY
, &low_latency
)))
114 attrs
.low_latency
= !!low_latency
;
116 if (!(decoder
->wg_transform
= wg_transform_create(&input_format
, &output_format
, &attrs
)))
122 static HRESULT
fill_output_media_type(struct h264_decoder
*decoder
, IMFMediaType
*media_type
)
124 IMFMediaType
*default_type
= decoder
->output_type
;
125 UINT32 value
, width
, height
;
126 MFVideoArea aperture
;
131 if (FAILED(hr
= IMFMediaType_GetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
)))
134 if (FAILED(hr
= IMFMediaType_GetUINT64(media_type
, &MF_MT_FRAME_SIZE
, &ratio
)))
136 if (FAILED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, &ratio
)))
137 ratio
= (UINT64
)1920 << 32 | 1080;
138 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_FRAME_SIZE
, ratio
)))
144 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_FRAME_RATE
, NULL
)))
146 if (FAILED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_RATE
, &ratio
)))
147 ratio
= (UINT64
)30000 << 32 | 1001;
148 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_FRAME_RATE
, ratio
)))
152 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_PIXEL_ASPECT_RATIO
, NULL
)))
154 if (FAILED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_PIXEL_ASPECT_RATIO
, &ratio
)))
155 ratio
= (UINT64
)1 << 32 | 1;
156 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_PIXEL_ASPECT_RATIO
, ratio
)))
160 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_SAMPLE_SIZE
, NULL
)))
162 if (FAILED(hr
= MFCalculateImageSize(&subtype
, width
, height
, &value
)))
164 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_SAMPLE_SIZE
, value
)))
168 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_DEFAULT_STRIDE
, NULL
)))
170 if (FAILED(hr
= MFGetStrideForBitmapInfoHeader(subtype
.Data1
, width
, (LONG
*)&value
)))
172 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_DEFAULT_STRIDE
, value
)))
176 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_INTERLACE_MODE
, NULL
)))
178 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_INTERLACE_MODE
, &value
)))
179 value
= MFVideoInterlace_MixedInterlaceOrProgressive
;
180 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_INTERLACE_MODE
, value
)))
184 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, NULL
)))
186 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, &value
)))
188 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_ALL_SAMPLES_INDEPENDENT
, value
)))
192 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_VIDEO_ROTATION
, NULL
)))
194 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_VIDEO_ROTATION
, &value
)))
196 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_VIDEO_ROTATION
, value
)))
200 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_FIXED_SIZE_SAMPLES
, NULL
)))
202 if (!default_type
|| FAILED(hr
= IMFMediaType_GetUINT32(default_type
, &MF_MT_FIXED_SIZE_SAMPLES
, &value
)))
204 if (FAILED(hr
= IMFMediaType_SetUINT32(media_type
, &MF_MT_FIXED_SIZE_SAMPLES
, value
)))
208 if (FAILED(hr
= IMFMediaType_GetItem(media_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
, NULL
))
209 && SUCCEEDED(hr
= IMFMediaType_GetBlob(decoder
->stream_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
,
210 (BYTE
*)&aperture
, sizeof(aperture
), &value
)))
212 if (FAILED(hr
= IMFMediaType_SetBlob(media_type
, &MF_MT_MINIMUM_DISPLAY_APERTURE
,
213 (BYTE
*)&aperture
, sizeof(aperture
))))
220 static HRESULT
init_allocator(struct h264_decoder
*decoder
)
224 if (decoder
->allocator_initialized
)
227 if (FAILED(hr
= IMFTransform_SetInputType(decoder
->copier
, 0, decoder
->output_type
, 0)))
229 if (FAILED(hr
= IMFTransform_SetOutputType(decoder
->copier
, 0, decoder
->output_type
, 0)))
232 if (FAILED(hr
= IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(decoder
->allocator
, 10, 10,
233 decoder
->attributes
, decoder
->output_type
)))
235 decoder
->allocator_initialized
= TRUE
;
239 static void uninit_allocator(struct h264_decoder
*decoder
)
241 IMFVideoSampleAllocatorEx_UninitializeSampleAllocator(decoder
->allocator
);
242 decoder
->allocator_initialized
= FALSE
;
245 static HRESULT WINAPI
transform_QueryInterface(IMFTransform
*iface
, REFIID iid
, void **out
)
247 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
249 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
251 if (IsEqualGUID(iid
, &IID_IUnknown
) ||
252 IsEqualGUID(iid
, &IID_IMFTransform
))
253 *out
= &decoder
->IMFTransform_iface
;
257 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
258 return E_NOINTERFACE
;
261 IUnknown_AddRef((IUnknown
*)*out
);
265 static ULONG WINAPI
transform_AddRef(IMFTransform
*iface
)
267 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
268 ULONG refcount
= InterlockedIncrement(&decoder
->refcount
);
270 TRACE("iface %p increasing refcount to %lu.\n", decoder
, refcount
);
275 static ULONG WINAPI
transform_Release(IMFTransform
*iface
)
277 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
278 ULONG refcount
= InterlockedDecrement(&decoder
->refcount
);
280 TRACE("iface %p decreasing refcount to %lu.\n", decoder
, refcount
);
284 IMFTransform_Release(decoder
->copier
);
285 IMFVideoSampleAllocatorEx_Release(decoder
->allocator
);
286 if (decoder
->temp_buffer
)
287 IMFMediaBuffer_Release(decoder
->temp_buffer
);
288 if (decoder
->wg_transform
)
289 wg_transform_destroy(decoder
->wg_transform
);
290 if (decoder
->input_type
)
291 IMFMediaType_Release(decoder
->input_type
);
292 if (decoder
->output_type
)
293 IMFMediaType_Release(decoder
->output_type
);
294 if (decoder
->output_attributes
)
295 IMFAttributes_Release(decoder
->output_attributes
);
296 if (decoder
->attributes
)
297 IMFAttributes_Release(decoder
->attributes
);
298 wg_sample_queue_destroy(decoder
->wg_sample_queue
);
305 static HRESULT WINAPI
transform_GetStreamLimits(IMFTransform
*iface
, DWORD
*input_minimum
,
306 DWORD
*input_maximum
, DWORD
*output_minimum
, DWORD
*output_maximum
)
308 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
309 iface
, input_minimum
, input_maximum
, output_minimum
, output_maximum
);
310 *input_minimum
= *input_maximum
= *output_minimum
= *output_maximum
= 1;
314 static HRESULT WINAPI
transform_GetStreamCount(IMFTransform
*iface
, DWORD
*inputs
, DWORD
*outputs
)
316 TRACE("iface %p, inputs %p, outputs %p.\n", iface
, inputs
, outputs
);
317 *inputs
= *outputs
= 1;
321 static HRESULT WINAPI
transform_GetStreamIDs(IMFTransform
*iface
, DWORD input_size
, DWORD
*inputs
,
322 DWORD output_size
, DWORD
*outputs
)
324 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface
,
325 input_size
, inputs
, output_size
, outputs
);
329 static HRESULT WINAPI
transform_GetInputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_INPUT_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
->input_info
;
339 static HRESULT WINAPI
transform_GetOutputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_OUTPUT_STREAM_INFO
*info
)
341 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
343 TRACE("iface %p, id %#lx, info %p.\n", iface
, id
, info
);
345 *info
= decoder
->output_info
;
349 static HRESULT WINAPI
transform_GetAttributes(IMFTransform
*iface
, IMFAttributes
**attributes
)
351 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
353 FIXME("iface %p, attributes %p semi-stub!\n", iface
, attributes
);
358 IMFAttributes_AddRef((*attributes
= decoder
->attributes
));
362 static HRESULT WINAPI
transform_GetInputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
364 TRACE("iface %p, id %#lx, attributes %p.\n", iface
, id
, attributes
);
368 static HRESULT WINAPI
transform_GetOutputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
370 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
372 FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface
, id
, attributes
);
377 return MF_E_INVALIDSTREAMNUMBER
;
379 IMFAttributes_AddRef((*attributes
= decoder
->output_attributes
));
383 static HRESULT WINAPI
transform_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
385 TRACE("iface %p, id %#lx.\n", iface
, id
);
389 static HRESULT WINAPI
transform_AddInputStreams(IMFTransform
*iface
, DWORD streams
, DWORD
*ids
)
391 TRACE("iface %p, streams %lu, ids %p.\n", iface
, streams
, ids
);
395 static HRESULT WINAPI
transform_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
398 IMFMediaType
*media_type
;
402 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
406 if (index
>= ARRAY_SIZE(h264_decoder_input_types
))
407 return MF_E_NO_MORE_TYPES
;
408 subtype
= h264_decoder_input_types
[index
];
410 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
413 if (SUCCEEDED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)) &&
414 SUCCEEDED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, subtype
)))
415 IMFMediaType_AddRef((*type
= media_type
));
417 IMFMediaType_Release(media_type
);
421 static HRESULT WINAPI
transform_GetOutputAvailableType(IMFTransform
*iface
, DWORD id
,
422 DWORD index
, IMFMediaType
**type
)
424 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
425 IMFMediaType
*media_type
;
426 const GUID
*output_type
;
429 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
431 if (!decoder
->input_type
)
432 return MF_E_TRANSFORM_TYPE_NOT_SET
;
436 if (index
>= ARRAY_SIZE(h264_decoder_output_types
))
437 return MF_E_NO_MORE_TYPES
;
438 output_type
= h264_decoder_output_types
[index
];
440 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
443 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)))
445 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, output_type
)))
448 hr
= fill_output_media_type(decoder
, media_type
);
452 IMFMediaType_AddRef((*type
= media_type
));
454 IMFMediaType_Release(media_type
);
458 static HRESULT WINAPI
transform_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
460 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
466 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
468 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)) ||
469 FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
472 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
473 return MF_E_INVALIDMEDIATYPE
;
475 for (i
= 0; i
< ARRAY_SIZE(h264_decoder_input_types
); ++i
)
476 if (IsEqualGUID(&subtype
, h264_decoder_input_types
[i
]))
478 if (i
== ARRAY_SIZE(h264_decoder_input_types
))
479 return MF_E_INVALIDMEDIATYPE
;
480 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
483 if (decoder
->output_type
)
485 IMFMediaType_Release(decoder
->output_type
);
486 decoder
->output_type
= NULL
;
489 if (decoder
->input_type
)
490 IMFMediaType_Release(decoder
->input_type
);
491 IMFMediaType_AddRef((decoder
->input_type
= type
));
493 if (SUCCEEDED(IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
495 if (FAILED(hr
= IMFMediaType_SetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, frame_size
)))
496 WARN("Failed to update stream type frame size, hr %#lx\n", hr
);
497 decoder
->output_info
.cbSize
= (frame_size
>> 32) * (UINT32
)frame_size
* 2;
503 static HRESULT WINAPI
transform_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
505 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
506 UINT64 frame_size
, stream_frame_size
;
511 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
513 if (!decoder
->input_type
)
514 return MF_E_TRANSFORM_TYPE_NOT_SET
;
516 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)) ||
517 FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
520 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
521 return MF_E_INVALIDMEDIATYPE
;
523 for (i
= 0; i
< ARRAY_SIZE(h264_decoder_output_types
); ++i
)
524 if (IsEqualGUID(&subtype
, h264_decoder_output_types
[i
]))
526 if (i
== ARRAY_SIZE(h264_decoder_output_types
))
527 return MF_E_INVALIDMEDIATYPE
;
529 if (FAILED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
530 return MF_E_INVALIDMEDIATYPE
;
531 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, &stream_frame_size
))
532 && frame_size
!= stream_frame_size
)
533 return MF_E_INVALIDMEDIATYPE
;
534 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
537 if (decoder
->output_type
)
538 IMFMediaType_Release(decoder
->output_type
);
539 IMFMediaType_AddRef((decoder
->output_type
= type
));
541 if (decoder
->wg_transform
)
543 struct wg_format output_format
;
544 mf_media_type_to_wg_format(decoder
->output_type
, &output_format
);
546 /* Don't force any specific size, H264 streams already have the metadata for it
547 * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
549 output_format
.u
.video
.width
= 0;
550 output_format
.u
.video
.height
= 0;
551 output_format
.u
.video
.fps_d
= 0;
552 output_format
.u
.video
.fps_n
= 0;
554 if (output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
555 || !wg_transform_set_output_format(decoder
->wg_transform
, &output_format
))
557 IMFMediaType_Release(decoder
->output_type
);
558 decoder
->output_type
= NULL
;
559 return MF_E_INVALIDMEDIATYPE
;
562 else if (FAILED(hr
= try_create_wg_transform(decoder
)))
564 IMFMediaType_Release(decoder
->output_type
);
565 decoder
->output_type
= NULL
;
571 static HRESULT WINAPI
transform_GetInputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
573 FIXME("iface %p, id %#lx, type %p stub!\n", iface
, id
, type
);
577 static HRESULT WINAPI
transform_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
579 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
582 FIXME("iface %p, id %#lx, type %p stub!\n", iface
, id
, type
);
584 if (!decoder
->output_type
)
585 return MF_E_TRANSFORM_TYPE_NOT_SET
;
587 if (FAILED(hr
= MFCreateMediaType(type
)))
590 return IMFMediaType_CopyAllItems(decoder
->output_type
, (IMFAttributes
*)*type
);
593 static HRESULT WINAPI
transform_GetInputStatus(IMFTransform
*iface
, DWORD id
, DWORD
*flags
)
595 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
597 TRACE("iface %p, id %#lx, flags %p.\n", iface
, id
, flags
);
599 if (!decoder
->wg_transform
)
600 return MF_E_TRANSFORM_TYPE_NOT_SET
;
602 *flags
= MFT_INPUT_STATUS_ACCEPT_DATA
;
606 static HRESULT WINAPI
transform_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
608 FIXME("iface %p, flags %p stub!\n", iface
, flags
);
612 static HRESULT WINAPI
transform_SetOutputBounds(IMFTransform
*iface
, LONGLONG lower
, LONGLONG upper
)
614 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface
, lower
, upper
);
618 static HRESULT WINAPI
transform_ProcessEvent(IMFTransform
*iface
, DWORD id
, IMFMediaEvent
*event
)
620 FIXME("iface %p, id %#lx, event %p stub!\n", iface
, id
, event
);
624 static HRESULT WINAPI
transform_ProcessMessage(IMFTransform
*iface
, MFT_MESSAGE_TYPE message
, ULONG_PTR param
)
626 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
629 TRACE("iface %p, message %#x, param %Ix.\n", iface
, message
, param
);
633 case MFT_MESSAGE_SET_D3D_MANAGER
:
634 if (FAILED(hr
= IMFVideoSampleAllocatorEx_SetDirectXManager(decoder
->allocator
, (IUnknown
*)param
)))
637 uninit_allocator(decoder
);
639 decoder
->output_info
.dwFlags
|= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
;
641 decoder
->output_info
.dwFlags
&= ~MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
;
644 case MFT_MESSAGE_COMMAND_DRAIN
:
645 return wg_transform_drain(decoder
->wg_transform
);
647 case MFT_MESSAGE_COMMAND_FLUSH
:
648 return wg_transform_flush(decoder
->wg_transform
);
651 FIXME("Ignoring message %#x.\n", message
);
656 static HRESULT WINAPI
transform_ProcessInput(IMFTransform
*iface
, DWORD id
, IMFSample
*sample
, DWORD flags
)
658 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
660 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface
, id
, sample
, flags
);
662 if (!decoder
->wg_transform
)
663 return MF_E_TRANSFORM_TYPE_NOT_SET
;
665 return wg_transform_push_mf(decoder
->wg_transform
, sample
, decoder
->wg_sample_queue
);
668 static HRESULT
output_sample(struct h264_decoder
*decoder
, IMFSample
**out
, IMFSample
*src_sample
)
670 MFT_OUTPUT_DATA_BUFFER output
[1];
675 if (FAILED(hr
= init_allocator(decoder
)))
677 ERR("Failed to initialize allocator, hr %#lx.\n", hr
);
680 if (FAILED(hr
= IMFVideoSampleAllocatorEx_AllocateSample(decoder
->allocator
, &sample
)))
683 if (FAILED(hr
= IMFTransform_ProcessInput(decoder
->copier
, 0, src_sample
, 0)))
685 IMFSample_Release(sample
);
688 output
[0].pSample
= sample
;
689 if (FAILED(hr
= IMFTransform_ProcessOutput(decoder
->copier
, 0, 1, output
, &status
)))
691 IMFSample_Release(sample
);
698 static HRESULT
handle_stream_type_change(struct h264_decoder
*decoder
, const struct wg_format
*format
)
700 UINT64 frame_size
, frame_rate
;
703 if (decoder
->stream_type
)
704 IMFMediaType_Release(decoder
->stream_type
);
705 if (!(decoder
->stream_type
= mf_media_type_from_wg_format(format
)))
706 return E_OUTOFMEMORY
;
708 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder
->output_type
, &MF_MT_FRAME_RATE
, &frame_rate
))
709 && FAILED(hr
= IMFMediaType_SetUINT64(decoder
->stream_type
, &MF_MT_FRAME_RATE
, frame_rate
)))
710 WARN("Failed to update stream type frame size, hr %#lx\n", hr
);
712 if (FAILED(hr
= IMFMediaType_GetUINT64(decoder
->stream_type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
714 decoder
->output_info
.cbSize
= (frame_size
>> 32) * (UINT32
)frame_size
* 2;
715 uninit_allocator(decoder
);
717 return MF_E_TRANSFORM_STREAM_CHANGE
;
720 static HRESULT WINAPI
transform_ProcessOutput(IMFTransform
*iface
, DWORD flags
, DWORD count
,
721 MFT_OUTPUT_DATA_BUFFER
*samples
, DWORD
*status
)
723 struct h264_decoder
*decoder
= impl_from_IMFTransform(iface
);
724 struct wg_format wg_format
;
728 UINT64 frame_size
, frame_rate
;
733 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface
, flags
, count
, samples
, status
);
738 if (!decoder
->wg_transform
)
739 return MF_E_TRANSFORM_TYPE_NOT_SET
;
741 *status
= samples
->dwStatus
= 0;
742 if (!(sample
= samples
->pSample
) && !(decoder
->output_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
))
745 if (FAILED(hr
= IMFMediaType_GetGUID(decoder
->output_type
, &MF_MT_SUBTYPE
, &subtype
)))
747 if (FAILED(hr
= IMFMediaType_GetUINT64(decoder
->output_type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
749 if (FAILED(hr
= MFCalculateImageSize(&subtype
, frame_size
>> 32, (UINT32
)frame_size
, &sample_size
)))
752 if (decoder
->output_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
)
754 if (decoder
->temp_buffer
)
756 if (FAILED(IMFMediaBuffer_GetMaxLength(decoder
->temp_buffer
, &size
)) || size
< sample_size
)
758 IMFMediaBuffer_Release(decoder
->temp_buffer
);
759 decoder
->temp_buffer
= NULL
;
762 if (!decoder
->temp_buffer
&& FAILED(hr
= MFCreateMemoryBuffer(sample_size
, &decoder
->temp_buffer
)))
764 if (FAILED(hr
= MFCreateSample(&sample
)))
766 if (FAILED(hr
= IMFSample_AddBuffer(sample
, decoder
->temp_buffer
)))
768 IMFSample_Release(sample
);
773 if (SUCCEEDED(hr
= wg_transform_read_mf(decoder
->wg_transform
, sample
,
774 sample_size
, &wg_format
, &samples
->dwStatus
)))
776 wg_sample_queue_flush(decoder
->wg_sample_queue
, false);
778 if (FAILED(IMFMediaType_GetUINT64(decoder
->input_type
, &MF_MT_FRAME_RATE
, &frame_rate
)))
779 frame_rate
= (UINT64
)30000 << 32 | 1001;
781 duration
= (UINT64
)10000000 * (UINT32
)frame_rate
/ (frame_rate
>> 32);
782 if (FAILED(IMFSample_SetSampleTime(sample
, decoder
->sample_time
)))
783 WARN("Failed to set sample time\n");
784 if (FAILED(IMFSample_SetSampleDuration(sample
, duration
)))
785 WARN("Failed to set sample duration\n");
786 decoder
->sample_time
+= duration
;
789 if (hr
== MF_E_TRANSFORM_STREAM_CHANGE
)
791 samples
[0].dwStatus
|= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE
;
792 *status
|= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE
;
793 hr
= handle_stream_type_change(decoder
, &wg_format
);
796 if (decoder
->output_info
.dwFlags
& MFT_OUTPUT_STREAM_PROVIDES_SAMPLES
)
798 if (hr
== S_OK
&& FAILED(hr
= output_sample(decoder
, &samples
->pSample
, sample
)))
799 ERR("Failed to output sample, hr %#lx.\n", hr
);
800 IMFSample_Release(sample
);
806 static const IMFTransformVtbl transform_vtbl
=
808 transform_QueryInterface
,
811 transform_GetStreamLimits
,
812 transform_GetStreamCount
,
813 transform_GetStreamIDs
,
814 transform_GetInputStreamInfo
,
815 transform_GetOutputStreamInfo
,
816 transform_GetAttributes
,
817 transform_GetInputStreamAttributes
,
818 transform_GetOutputStreamAttributes
,
819 transform_DeleteInputStream
,
820 transform_AddInputStreams
,
821 transform_GetInputAvailableType
,
822 transform_GetOutputAvailableType
,
823 transform_SetInputType
,
824 transform_SetOutputType
,
825 transform_GetInputCurrentType
,
826 transform_GetOutputCurrentType
,
827 transform_GetInputStatus
,
828 transform_GetOutputStatus
,
829 transform_SetOutputBounds
,
830 transform_ProcessEvent
,
831 transform_ProcessMessage
,
832 transform_ProcessInput
,
833 transform_ProcessOutput
,
836 HRESULT
h264_decoder_create(REFIID riid
, void **ret
)
838 static const struct wg_format output_format
=
840 .major_type
= WG_MAJOR_TYPE_VIDEO
,
843 .format
= WG_VIDEO_FORMAT_I420
,
848 static const struct wg_format input_format
= {.major_type
= WG_MAJOR_TYPE_VIDEO_H264
};
849 struct wg_transform_attrs attrs
= {0};
850 wg_transform_t transform
;
851 struct h264_decoder
*decoder
;
854 TRACE("riid %s, ret %p.\n", debugstr_guid(riid
), ret
);
856 if (!(transform
= wg_transform_create(&input_format
, &output_format
, &attrs
)))
858 ERR_(winediag
)("GStreamer doesn't support H.264 decoding, please install appropriate plugins\n");
861 wg_transform_destroy(transform
);
863 if (!(decoder
= calloc(1, sizeof(*decoder
))))
864 return E_OUTOFMEMORY
;
866 decoder
->IMFTransform_iface
.lpVtbl
= &transform_vtbl
;
867 decoder
->refcount
= 1;
869 decoder
->input_info
.dwFlags
= MFT_INPUT_STREAM_WHOLE_SAMPLES
| MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
870 | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE
;
871 decoder
->input_info
.cbSize
= 0x1000;
872 decoder
->output_info
.dwFlags
= MFT_OUTPUT_STREAM_WHOLE_SAMPLES
| MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER
873 | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE
;
874 decoder
->output_info
.cbSize
= 1920 * 1088 * 2;
876 if (FAILED(hr
= MFCreateMediaType(&decoder
->stream_type
)))
878 if (FAILED(hr
= MFCreateAttributes(&decoder
->attributes
, 16)))
880 if (FAILED(hr
= IMFAttributes_SetUINT32(decoder
->attributes
, &MF_LOW_LATENCY
, 0)))
882 if (FAILED(hr
= IMFAttributes_SetUINT32(decoder
->attributes
, &MF_SA_D3D11_AWARE
, TRUE
)))
884 if (FAILED(hr
= MFCreateAttributes(&decoder
->output_attributes
, 0)))
886 if (FAILED(hr
= wg_sample_queue_create(&decoder
->wg_sample_queue
)))
888 if (FAILED(hr
= MFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx
, (void **)&decoder
->allocator
)))
890 if (FAILED(hr
= MFCreateSampleCopierMFT(&decoder
->copier
)))
893 *ret
= &decoder
->IMFTransform_iface
;
894 TRACE("Created decoder %p\n", *ret
);
898 if (decoder
->allocator
)
899 IMFVideoSampleAllocatorEx_Release(decoder
->allocator
);
900 if (decoder
->wg_sample_queue
)
901 wg_sample_queue_destroy(decoder
->wg_sample_queue
);
902 if (decoder
->output_attributes
)
903 IMFAttributes_Release(decoder
->output_attributes
);
904 if (decoder
->attributes
)
905 IMFAttributes_Release(decoder
->attributes
);
906 if (decoder
->stream_type
)
907 IMFMediaType_Release(decoder
->stream_type
);