1 /* Generic Video Decoder Transform
3 * Copyright 2022 RĂ©mi Bernon for CodeWeavers
4 * Copyright 2023 Shaun Ren for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "gst_private.h"
25 #include "mfobjects.h"
26 #include "mftransform.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
32 DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50
, MAKEFOURCC('I','V','5','0'));
34 static const GUID
*const input_types
[] =
38 static const GUID
*const output_types
[] =
46 &MFVideoFormat_RGB565
,
47 &MFVideoFormat_RGB555
,
53 IMFTransform IMFTransform_iface
;
56 IMFMediaType
*input_type
;
57 IMFMediaType
*output_type
;
59 struct wg_format wg_format
;
60 struct wg_transform
*wg_transform
;
61 struct wg_sample_queue
*wg_sample_queue
;
64 static struct video_decoder
*impl_from_IMFTransform(IMFTransform
*iface
)
66 return CONTAINING_RECORD(iface
, struct video_decoder
, IMFTransform_iface
);
69 static HRESULT
try_create_wg_transform(struct video_decoder
*decoder
)
71 struct wg_transform_attrs attrs
= {0};
72 struct wg_format input_format
;
73 struct wg_format output_format
;
75 if (decoder
->wg_transform
)
76 wg_transform_destroy(decoder
->wg_transform
);
77 decoder
->wg_transform
= NULL
;
79 mf_media_type_to_wg_format(decoder
->input_type
, &input_format
);
80 if (input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
81 return MF_E_INVALIDMEDIATYPE
;
83 mf_media_type_to_wg_format(decoder
->output_type
, &output_format
);
84 if (output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
85 return MF_E_INVALIDMEDIATYPE
;
87 output_format
.u
.video
.fps_d
= 0;
88 output_format
.u
.video
.fps_n
= 0;
90 if (!(decoder
->wg_transform
= wg_transform_create(&input_format
, &output_format
, &attrs
)))
92 ERR("Failed to create transform with input major_type %u.\n", input_format
.major_type
);
99 static HRESULT WINAPI
transform_QueryInterface(IMFTransform
*iface
, REFIID iid
, void **out
)
101 struct video_decoder
*decoder
= impl_from_IMFTransform(iface
);
103 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
105 if (IsEqualGUID(iid
, &IID_IUnknown
) ||
106 IsEqualGUID(iid
, &IID_IMFTransform
))
107 *out
= &decoder
->IMFTransform_iface
;
111 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
112 return E_NOINTERFACE
;
115 IUnknown_AddRef((IUnknown
*)*out
);
119 static ULONG WINAPI
transform_AddRef(IMFTransform
*iface
)
121 struct video_decoder
*decoder
= impl_from_IMFTransform(iface
);
122 ULONG refcount
= InterlockedIncrement(&decoder
->refcount
);
124 TRACE("iface %p increasing refcount to %lu.\n", decoder
, refcount
);
129 static ULONG WINAPI
transform_Release(IMFTransform
*iface
)
131 struct video_decoder
*decoder
= impl_from_IMFTransform(iface
);
132 ULONG refcount
= InterlockedDecrement(&decoder
->refcount
);
134 TRACE("iface %p decreasing refcount to %lu.\n", decoder
, refcount
);
138 if (decoder
->wg_transform
)
139 wg_transform_destroy(decoder
->wg_transform
);
140 if (decoder
->input_type
)
141 IMFMediaType_Release(decoder
->input_type
);
142 if (decoder
->output_type
)
143 IMFMediaType_Release(decoder
->output_type
);
145 wg_sample_queue_destroy(decoder
->wg_sample_queue
);
152 static HRESULT WINAPI
transform_GetStreamLimits(IMFTransform
*iface
, DWORD
*input_minimum
,
153 DWORD
*input_maximum
, DWORD
*output_minimum
, DWORD
*output_maximum
)
155 FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
156 iface
, input_minimum
, input_maximum
, output_minimum
, output_maximum
);
160 static HRESULT WINAPI
transform_GetStreamCount(IMFTransform
*iface
, DWORD
*inputs
, DWORD
*outputs
)
162 FIXME("iface %p, inputs %p, outputs %p.\n", iface
, inputs
, outputs
);
166 static HRESULT WINAPI
transform_GetStreamIDs(IMFTransform
*iface
, DWORD input_size
, DWORD
*inputs
,
167 DWORD output_size
, DWORD
*outputs
)
169 FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n",
170 iface
, input_size
, inputs
, output_size
, outputs
);
174 static HRESULT WINAPI
transform_GetInputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_INPUT_STREAM_INFO
*info
)
176 FIXME("iface %p, id %#lx, info %p.\n", iface
, id
, info
);
180 static HRESULT WINAPI
transform_GetOutputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_OUTPUT_STREAM_INFO
*info
)
182 FIXME("iface %p, id %#lx, info %p.\n", iface
, id
, info
);
186 static HRESULT WINAPI
transform_GetAttributes(IMFTransform
*iface
, IMFAttributes
**attributes
)
188 FIXME("iface %p, attributes %p semi-stub!\n", iface
, attributes
);
192 static HRESULT WINAPI
transform_GetInputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
194 FIXME("iface %p, id %#lx, attributes %p.\n", iface
, id
, attributes
);
198 static HRESULT WINAPI
transform_GetOutputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
200 FIXME("iface %p, id %#lx, attributes %p stub!\n", iface
, id
, attributes
);
204 static HRESULT WINAPI
transform_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
206 FIXME("iface %p, id %#lx.\n", iface
, id
);
210 static HRESULT WINAPI
transform_AddInputStreams(IMFTransform
*iface
, DWORD streams
, DWORD
*ids
)
212 FIXME("iface %p, streams %lu, ids %p.\n", iface
, streams
, ids
);
216 static HRESULT WINAPI
transform_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
219 FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
223 static HRESULT WINAPI
transform_GetOutputAvailableType(IMFTransform
*iface
, DWORD id
,
224 DWORD index
, IMFMediaType
**type
)
226 FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
230 static HRESULT WINAPI
transform_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
232 struct video_decoder
*decoder
= impl_from_IMFTransform(iface
);
238 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
240 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)) ||
241 FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
244 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
245 return MF_E_INVALIDMEDIATYPE
;
247 for (i
= 0; i
< ARRAY_SIZE(input_types
); ++i
)
248 if (IsEqualGUID(&subtype
, input_types
[i
]))
250 if (i
== ARRAY_SIZE(input_types
))
251 return MF_E_INVALIDMEDIATYPE
;
253 if (FAILED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)) ||
254 (frame_size
>> 32) == 0 || (UINT32
)frame_size
== 0)
255 return MF_E_INVALIDMEDIATYPE
;
257 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
260 if (decoder
->output_type
)
262 IMFMediaType_Release(decoder
->output_type
);
263 decoder
->output_type
= NULL
;
266 if (decoder
->input_type
)
267 IMFMediaType_Release(decoder
->input_type
);
268 IMFMediaType_AddRef((decoder
->input_type
= type
));
273 static HRESULT WINAPI
transform_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
275 struct video_decoder
*decoder
= impl_from_IMFTransform(iface
);
278 struct wg_format output_format
;
282 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
284 if (!decoder
->input_type
)
285 return MF_E_TRANSFORM_TYPE_NOT_SET
;
287 if (FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
)) ||
288 FAILED(hr
= IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
291 if (!IsEqualGUID(&major
, &MFMediaType_Video
))
292 return MF_E_INVALIDMEDIATYPE
;
294 for (i
= 0; i
< ARRAY_SIZE(output_types
); ++i
)
295 if (IsEqualGUID(&subtype
, output_types
[i
]))
297 if (i
== ARRAY_SIZE(output_types
))
298 return MF_E_INVALIDMEDIATYPE
;
300 if (FAILED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
303 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
306 if (decoder
->output_type
)
307 IMFMediaType_Release(decoder
->output_type
);
308 IMFMediaType_AddRef((decoder
->output_type
= type
));
310 if (decoder
->wg_transform
)
312 mf_media_type_to_wg_format(decoder
->output_type
, &output_format
);
314 output_format
.u
.video
.fps_d
= 0;
315 output_format
.u
.video
.fps_n
= 0;
317 if (output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
318 || !wg_transform_set_output_format(decoder
->wg_transform
, &output_format
))
320 IMFMediaType_Release(decoder
->output_type
);
321 decoder
->output_type
= NULL
;
322 return MF_E_INVALIDMEDIATYPE
;
325 else if (FAILED(hr
= try_create_wg_transform(decoder
)))
327 IMFMediaType_Release(decoder
->output_type
);
328 decoder
->output_type
= NULL
;
332 decoder
->wg_format
.u
.video
.width
= frame_size
>> 32;
333 decoder
->wg_format
.u
.video
.height
= (UINT32
)frame_size
;
338 static HRESULT WINAPI
transform_GetInputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
340 FIXME("iface %p, id %#lx, type %p stub!\n", iface
, id
, type
);
344 static HRESULT WINAPI
transform_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
346 FIXME("iface %p, id %#lx, type %p stub!\n", iface
, id
, type
);
350 static HRESULT WINAPI
transform_GetInputStatus(IMFTransform
*iface
, DWORD id
, DWORD
*flags
)
352 FIXME("iface %p, id %#lx, flags %p stub!\n", iface
, id
, flags
);
356 static HRESULT WINAPI
transform_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
358 FIXME("iface %p, flags %p stub!\n", iface
, flags
);
362 static HRESULT WINAPI
transform_SetOutputBounds(IMFTransform
*iface
, LONGLONG lower
, LONGLONG upper
)
364 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface
, lower
, upper
);
368 static HRESULT WINAPI
transform_ProcessEvent(IMFTransform
*iface
, DWORD id
, IMFMediaEvent
*event
)
370 FIXME("iface %p, id %#lx, event %p stub!\n", iface
, id
, event
);
374 static HRESULT WINAPI
transform_ProcessMessage(IMFTransform
*iface
, MFT_MESSAGE_TYPE message
, ULONG_PTR param
)
376 FIXME("iface %p, message %#x, param %Ix stub!\n", iface
, message
, param
);
380 static HRESULT WINAPI
transform_ProcessInput(IMFTransform
*iface
, DWORD id
, IMFSample
*sample
, DWORD flags
)
382 struct video_decoder
*decoder
= impl_from_IMFTransform(iface
);
385 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface
, id
, sample
, flags
);
387 if (!decoder
->wg_transform
)
388 return MF_E_TRANSFORM_TYPE_NOT_SET
;
390 hr
= wg_transform_push_mf(decoder
->wg_transform
, sample
, decoder
->wg_sample_queue
);
395 static HRESULT WINAPI
transform_ProcessOutput(IMFTransform
*iface
, DWORD flags
, DWORD count
,
396 MFT_OUTPUT_DATA_BUFFER
*samples
, DWORD
*status
)
398 struct video_decoder
*decoder
= impl_from_IMFTransform(iface
);
399 struct wg_format wg_format
;
405 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface
, flags
, count
, samples
, status
);
410 if (!decoder
->wg_transform
)
411 return MF_E_TRANSFORM_TYPE_NOT_SET
;
413 *status
= samples
->dwStatus
= 0;
414 if (!samples
->pSample
)
417 if (FAILED(hr
= IMFMediaType_GetGUID(decoder
->output_type
, &MF_MT_SUBTYPE
, &subtype
)))
419 if (FAILED(hr
= MFCalculateImageSize(&subtype
, decoder
->wg_format
.u
.video
.width
,
420 decoder
->wg_format
.u
.video
.height
, &sample_size
)))
423 if (SUCCEEDED(hr
= wg_transform_read_mf(decoder
->wg_transform
, samples
->pSample
,
424 sample_size
, &wg_format
, &samples
->dwStatus
)))
425 wg_sample_queue_flush(decoder
->wg_sample_queue
, false);
427 if (hr
== MF_E_TRANSFORM_STREAM_CHANGE
)
429 decoder
->wg_format
= wg_format
;
431 if (FAILED(hr
= MFCalculateImageSize(&subtype
, decoder
->wg_format
.u
.video
.width
,
432 decoder
->wg_format
.u
.video
.height
, &sample_size
)))
435 /* keep the frame rate that was requested, GStreamer doesn't provide any */
436 if (SUCCEEDED(IMFMediaType_GetUINT64(decoder
->output_type
, &MF_MT_FRAME_RATE
, &frame_rate
)))
438 decoder
->wg_format
.u
.video
.fps_n
= frame_rate
>> 32;
439 decoder
->wg_format
.u
.video
.fps_d
= (UINT32
)frame_rate
;
442 samples
[0].dwStatus
|= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE
;
443 *status
|= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE
;
449 static const IMFTransformVtbl transform_vtbl
=
451 transform_QueryInterface
,
454 transform_GetStreamLimits
,
455 transform_GetStreamCount
,
456 transform_GetStreamIDs
,
457 transform_GetInputStreamInfo
,
458 transform_GetOutputStreamInfo
,
459 transform_GetAttributes
,
460 transform_GetInputStreamAttributes
,
461 transform_GetOutputStreamAttributes
,
462 transform_DeleteInputStream
,
463 transform_AddInputStreams
,
464 transform_GetInputAvailableType
,
465 transform_GetOutputAvailableType
,
466 transform_SetInputType
,
467 transform_SetOutputType
,
468 transform_GetInputCurrentType
,
469 transform_GetOutputCurrentType
,
470 transform_GetInputStatus
,
471 transform_GetOutputStatus
,
472 transform_SetOutputBounds
,
473 transform_ProcessEvent
,
474 transform_ProcessMessage
,
475 transform_ProcessInput
,
476 transform_ProcessOutput
,
479 HRESULT WINAPI
winegstreamer_create_video_decoder(IMFTransform
**out
)
481 struct video_decoder
*decoder
;
484 TRACE("out %p.\n", out
);
486 if (!init_gstreamer())
489 if (!(decoder
= calloc(1, sizeof(*decoder
))))
490 return E_OUTOFMEMORY
;
492 decoder
->IMFTransform_iface
.lpVtbl
= &transform_vtbl
;
493 decoder
->refcount
= 1;
495 decoder
->wg_format
.u
.video
.fps_d
= 1;
496 decoder
->wg_format
.u
.video
.fps_n
= 1;
498 if (FAILED(hr
= wg_sample_queue_create(&decoder
->wg_sample_queue
)))
501 *out
= &decoder
->IMFTransform_iface
;
502 TRACE("created decoder %p.\n", *out
);