1 /* Copyright 2022 RĂ©mi Bernon for CodeWeavers
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 #include "gst_private.h"
22 #include "mfobjects.h"
23 #include "mftransform.h"
24 #include "wmcodecdsp.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
29 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
31 static const GUID
*const input_types
[] =
42 &MFVideoFormat_ARGB32
,
47 &MFVideoFormat_RGB555
,
48 &MFVideoFormat_RGB565
,
56 static const GUID
*const output_types
[] =
63 &MFVideoFormat_ARGB32
,
67 &MFVideoFormat_RGB555
,
68 &MFVideoFormat_RGB565
,
71 struct video_processor
73 IMFTransform IMFTransform_iface
;
76 IMFAttributes
*attributes
;
77 IMFAttributes
*output_attributes
;
79 IMFMediaType
*input_type
;
80 MFT_INPUT_STREAM_INFO input_info
;
81 IMFMediaType
*output_type
;
82 MFT_OUTPUT_STREAM_INFO output_info
;
84 wg_transform_t wg_transform
;
85 struct wg_sample_queue
*wg_sample_queue
;
88 static HRESULT
try_create_wg_transform(struct video_processor
*impl
)
90 struct wg_format input_format
, output_format
;
91 struct wg_transform_attrs attrs
= {0};
93 if (impl
->wg_transform
)
94 wg_transform_destroy(impl
->wg_transform
);
95 impl
->wg_transform
= 0;
97 mf_media_type_to_wg_format(impl
->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(impl
->output_type
, &output_format
);
102 if (output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
103 return MF_E_INVALIDMEDIATYPE
;
105 if (!(impl
->wg_transform
= wg_transform_create(&input_format
, &output_format
, &attrs
)))
111 static struct video_processor
*impl_from_IMFTransform(IMFTransform
*iface
)
113 return CONTAINING_RECORD(iface
, struct video_processor
, IMFTransform_iface
);
116 static HRESULT WINAPI
video_processor_QueryInterface(IMFTransform
*iface
, REFIID iid
, void **out
)
118 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
120 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
122 if (IsEqualGUID(iid
, &IID_IMFTransform
))
123 *out
= &impl
->IMFTransform_iface
;
127 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
128 return E_NOINTERFACE
;
131 IUnknown_AddRef((IUnknown
*)*out
);
135 static ULONG WINAPI
video_processor_AddRef(IMFTransform
*iface
)
137 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
138 ULONG refcount
= InterlockedIncrement(&impl
->refcount
);
140 TRACE("iface %p increasing refcount to %lu.\n", iface
, refcount
);
145 static ULONG WINAPI
video_processor_Release(IMFTransform
*iface
)
147 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
148 ULONG refcount
= InterlockedDecrement(&impl
->refcount
);
150 TRACE("iface %p decreasing refcount to %lu.\n", iface
, refcount
);
154 if (impl
->wg_transform
)
155 wg_transform_destroy(impl
->wg_transform
);
156 if (impl
->input_type
)
157 IMFMediaType_Release(impl
->input_type
);
158 if (impl
->output_type
)
159 IMFMediaType_Release(impl
->output_type
);
160 if (impl
->attributes
)
161 IMFAttributes_Release(impl
->attributes
);
162 if (impl
->output_attributes
)
163 IMFAttributes_Release(impl
->output_attributes
);
165 wg_sample_queue_destroy(impl
->wg_sample_queue
);
172 static HRESULT WINAPI
video_processor_GetStreamLimits(IMFTransform
*iface
, DWORD
*input_minimum
,
173 DWORD
*input_maximum
, DWORD
*output_minimum
, DWORD
*output_maximum
)
175 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
176 iface
, input_minimum
, input_maximum
, output_minimum
, output_maximum
);
177 *input_minimum
= *input_maximum
= *output_minimum
= *output_maximum
= 1;
181 static HRESULT WINAPI
video_processor_GetStreamCount(IMFTransform
*iface
, DWORD
*inputs
, DWORD
*outputs
)
183 TRACE("iface %p, inputs %p, outputs %p.\n", iface
, inputs
, outputs
);
184 *inputs
= *outputs
= 1;
188 static HRESULT WINAPI
video_processor_GetStreamIDs(IMFTransform
*iface
, DWORD input_size
, DWORD
*inputs
,
189 DWORD output_size
, DWORD
*outputs
)
191 TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface
,
192 input_size
, inputs
, output_size
, outputs
);
196 static HRESULT WINAPI
video_processor_GetInputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_INPUT_STREAM_INFO
*info
)
198 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
200 TRACE("iface %p, id %#lx, info %p.\n", iface
, id
, info
);
203 return MF_E_INVALIDSTREAMNUMBER
;
205 *info
= impl
->input_info
;
209 static HRESULT WINAPI
video_processor_GetOutputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_OUTPUT_STREAM_INFO
*info
)
211 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
213 TRACE("iface %p, id %#lx, info %p.\n", iface
, id
, info
);
216 return MF_E_INVALIDSTREAMNUMBER
;
218 *info
= impl
->output_info
;
222 static HRESULT WINAPI
video_processor_GetAttributes(IMFTransform
*iface
, IMFAttributes
**attributes
)
224 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
226 FIXME("iface %p, attributes %p semi-stub!\n", iface
, attributes
);
231 IMFAttributes_AddRef((*attributes
= impl
->attributes
));
235 static HRESULT WINAPI
video_processor_GetInputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
237 TRACE("iface %p, id %#lx, attributes %p.\n", iface
, id
, attributes
);
241 static HRESULT WINAPI
video_processor_GetOutputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
243 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
245 FIXME("iface %p, id %#lx, attributes %p semi-stub!\n", iface
, id
, attributes
);
250 return MF_E_INVALIDSTREAMNUMBER
;
252 IMFAttributes_AddRef((*attributes
= impl
->output_attributes
));
256 static HRESULT WINAPI
video_processor_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
258 TRACE("iface %p, id %#lx.\n", iface
, id
);
262 static HRESULT WINAPI
video_processor_AddInputStreams(IMFTransform
*iface
, DWORD streams
, DWORD
*ids
)
264 TRACE("iface %p, streams %lu, ids %p.\n", iface
, streams
, ids
);
268 static HRESULT WINAPI
video_processor_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
271 IMFMediaType
*media_type
;
275 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
279 if (index
>= ARRAY_SIZE(input_types
))
280 return MF_E_NO_MORE_TYPES
;
281 subtype
= input_types
[index
];
283 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
286 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)))
288 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, subtype
)))
291 IMFMediaType_AddRef((*type
= media_type
));
294 IMFMediaType_Release(media_type
);
298 static HRESULT WINAPI
video_processor_GetOutputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
301 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
302 IMFMediaType
*media_type
;
307 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
311 if (!impl
->input_type
)
312 return MF_E_NO_MORE_TYPES
;
314 if (FAILED(hr
= IMFMediaType_GetGUID(impl
->input_type
, &MF_MT_SUBTYPE
, &subtype
))
315 || FAILED(hr
= IMFMediaType_GetUINT64(impl
->input_type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
318 if (index
> ARRAY_SIZE(output_types
))
319 return MF_E_NO_MORE_TYPES
;
321 subtype
= *output_types
[index
- 1];
323 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
326 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)))
328 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
)))
330 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_FRAME_SIZE
, frame_size
)))
333 IMFMediaType_AddRef((*type
= media_type
));
336 IMFMediaType_Release(media_type
);
340 static HRESULT WINAPI
video_processor_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
342 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
348 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
350 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
))
351 || !IsEqualGUID(&major
, &MFMediaType_Video
))
353 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
354 return MF_E_INVALIDMEDIATYPE
;
355 if (FAILED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
358 for (i
= 0; i
< ARRAY_SIZE(input_types
); ++i
)
359 if (IsEqualGUID(&subtype
, input_types
[i
]))
361 if (i
== ARRAY_SIZE(input_types
))
362 return MF_E_INVALIDMEDIATYPE
;
363 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
366 if (impl
->input_type
)
367 IMFMediaType_Release(impl
->input_type
);
368 IMFMediaType_AddRef((impl
->input_type
= type
));
370 if (impl
->output_type
&& FAILED(hr
= try_create_wg_transform(impl
)))
372 IMFMediaType_Release(impl
->input_type
);
373 impl
->input_type
= NULL
;
376 if (FAILED(hr
) || FAILED(MFCalculateImageSize(&subtype
, frame_size
>> 32, (UINT32
)frame_size
,
377 (UINT32
*)&impl
->input_info
.cbSize
)))
378 impl
->input_info
.cbSize
= 0;
383 static HRESULT WINAPI
video_processor_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
385 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
391 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
393 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
))
394 || !IsEqualGUID(&major
, &MFMediaType_Video
))
396 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
397 return MF_E_INVALIDMEDIATYPE
;
398 if (FAILED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
401 for (i
= 0; i
< ARRAY_SIZE(output_types
); ++i
)
402 if (IsEqualGUID(&subtype
, output_types
[i
]))
404 if (i
== ARRAY_SIZE(output_types
))
405 return MF_E_INVALIDMEDIATYPE
;
406 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
409 if (impl
->output_type
)
410 IMFMediaType_Release(impl
->output_type
);
411 IMFMediaType_AddRef((impl
->output_type
= type
));
413 if (impl
->input_type
&& FAILED(hr
= try_create_wg_transform(impl
)))
415 IMFMediaType_Release(impl
->output_type
);
416 impl
->output_type
= NULL
;
419 if (FAILED(hr
) || FAILED(MFCalculateImageSize(&subtype
, frame_size
>> 32, (UINT32
)frame_size
,
420 (UINT32
*)&impl
->output_info
.cbSize
)))
421 impl
->output_info
.cbSize
= 0;
426 static HRESULT WINAPI
video_processor_GetInputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
428 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
431 TRACE("iface %p, id %#lx, type %p.\n", iface
, id
, type
);
434 return MF_E_INVALIDSTREAMNUMBER
;
436 if (!impl
->input_type
)
437 return MF_E_TRANSFORM_TYPE_NOT_SET
;
439 if (FAILED(hr
= MFCreateMediaType(type
)))
442 if (FAILED(hr
= IMFMediaType_CopyAllItems(impl
->input_type
, (IMFAttributes
*)*type
)))
443 IMFMediaType_Release(*type
);
448 static HRESULT WINAPI
video_processor_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
450 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
453 TRACE("iface %p, id %#lx, type %p.\n", iface
, id
, type
);
456 return MF_E_INVALIDSTREAMNUMBER
;
458 if (!impl
->output_type
)
459 return MF_E_TRANSFORM_TYPE_NOT_SET
;
461 if (FAILED(hr
= MFCreateMediaType(type
)))
464 if (FAILED(hr
= IMFMediaType_CopyAllItems(impl
->output_type
, (IMFAttributes
*)*type
)))
465 IMFMediaType_Release(*type
);
470 static HRESULT WINAPI
video_processor_GetInputStatus(IMFTransform
*iface
, DWORD id
, DWORD
*flags
)
472 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
474 FIXME("iface %p, id %#lx, flags %p stub!\n", iface
, id
, flags
);
476 if (!impl
->input_type
)
477 return MF_E_TRANSFORM_TYPE_NOT_SET
;
479 *flags
= MFT_INPUT_STATUS_ACCEPT_DATA
;
483 static HRESULT WINAPI
video_processor_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
485 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
487 FIXME("iface %p, flags %p stub!\n", iface
, flags
);
489 if (!impl
->output_type
)
490 return MF_E_TRANSFORM_TYPE_NOT_SET
;
495 static HRESULT WINAPI
video_processor_SetOutputBounds(IMFTransform
*iface
, LONGLONG lower
, LONGLONG upper
)
497 TRACE("iface %p, lower %I64d, upper %I64d.\n", iface
, lower
, upper
);
501 static HRESULT WINAPI
video_processor_ProcessEvent(IMFTransform
*iface
, DWORD id
, IMFMediaEvent
*event
)
503 FIXME("iface %p, id %#lx, event %p stub!\n", iface
, id
, event
);
507 static HRESULT WINAPI
video_processor_ProcessMessage(IMFTransform
*iface
, MFT_MESSAGE_TYPE message
, ULONG_PTR param
)
509 FIXME("iface %p, message %#x, param %#Ix stub!\n", iface
, message
, param
);
513 static HRESULT WINAPI
video_processor_ProcessInput(IMFTransform
*iface
, DWORD id
, IMFSample
*sample
, DWORD flags
)
515 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
517 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface
, id
, sample
, flags
);
519 if (!impl
->wg_transform
)
520 return MF_E_TRANSFORM_TYPE_NOT_SET
;
522 return wg_transform_push_mf(impl
->wg_transform
, sample
, impl
->wg_sample_queue
);
525 static HRESULT WINAPI
video_processor_ProcessOutput(IMFTransform
*iface
, DWORD flags
, DWORD count
,
526 MFT_OUTPUT_DATA_BUFFER
*samples
, DWORD
*status
)
528 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
529 MFT_OUTPUT_STREAM_INFO info
;
532 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface
, flags
, count
, samples
, status
);
537 if (!impl
->wg_transform
)
538 return MF_E_TRANSFORM_TYPE_NOT_SET
;
540 samples
->dwStatus
= 0;
541 if (!samples
->pSample
)
544 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(iface
, 0, &info
)))
547 if (SUCCEEDED(hr
= wg_transform_read_mf(impl
->wg_transform
, samples
->pSample
,
548 info
.cbSize
, NULL
, &samples
->dwStatus
)))
549 wg_sample_queue_flush(impl
->wg_sample_queue
, false);
554 static const IMFTransformVtbl video_processor_vtbl
=
556 video_processor_QueryInterface
,
557 video_processor_AddRef
,
558 video_processor_Release
,
559 video_processor_GetStreamLimits
,
560 video_processor_GetStreamCount
,
561 video_processor_GetStreamIDs
,
562 video_processor_GetInputStreamInfo
,
563 video_processor_GetOutputStreamInfo
,
564 video_processor_GetAttributes
,
565 video_processor_GetInputStreamAttributes
,
566 video_processor_GetOutputStreamAttributes
,
567 video_processor_DeleteInputStream
,
568 video_processor_AddInputStreams
,
569 video_processor_GetInputAvailableType
,
570 video_processor_GetOutputAvailableType
,
571 video_processor_SetInputType
,
572 video_processor_SetOutputType
,
573 video_processor_GetInputCurrentType
,
574 video_processor_GetOutputCurrentType
,
575 video_processor_GetInputStatus
,
576 video_processor_GetOutputStatus
,
577 video_processor_SetOutputBounds
,
578 video_processor_ProcessEvent
,
579 video_processor_ProcessMessage
,
580 video_processor_ProcessInput
,
581 video_processor_ProcessOutput
,
584 HRESULT
video_processor_create(REFIID riid
, void **ret
)
586 static const struct wg_format input_format
=
588 .major_type
= WG_MAJOR_TYPE_VIDEO
,
591 .format
= WG_VIDEO_FORMAT_I420
,
596 static const struct wg_format output_format
=
598 .major_type
= WG_MAJOR_TYPE_VIDEO
,
601 .format
= WG_VIDEO_FORMAT_NV12
,
606 struct wg_transform_attrs attrs
= {0};
607 wg_transform_t transform
;
608 struct video_processor
*impl
;
611 TRACE("riid %s, ret %p.\n", debugstr_guid(riid
), ret
);
613 if (!(transform
= wg_transform_create(&input_format
, &output_format
, &attrs
)))
615 ERR_(winediag
)("GStreamer doesn't support video conversion, please install appropriate plugins.\n");
618 wg_transform_destroy(transform
);
620 if (!(impl
= calloc(1, sizeof(*impl
))))
621 return E_OUTOFMEMORY
;
623 if (FAILED(hr
= MFCreateAttributes(&impl
->attributes
, 0)))
625 if (FAILED(hr
= MFCreateAttributes(&impl
->output_attributes
, 0)))
627 if (FAILED(hr
= wg_sample_queue_create(&impl
->wg_sample_queue
)))
630 impl
->IMFTransform_iface
.lpVtbl
= &video_processor_vtbl
;
633 *ret
= &impl
->IMFTransform_iface
;
634 TRACE("Created %p\n", *ret
);
638 if (impl
->output_attributes
)
639 IMFAttributes_Release(impl
->output_attributes
);
640 if (impl
->attributes
)
641 IMFAttributes_Release(impl
->attributes
);