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 IMFMediaType
*input_type
;
77 IMFMediaType
*output_type
;
78 IMFAttributes
*attributes
;
79 IMFAttributes
*output_attributes
;
81 struct wg_transform
*wg_transform
;
82 struct wg_sample_queue
*wg_sample_queue
;
85 static HRESULT
try_create_wg_transform(struct video_processor
*impl
)
87 struct wg_format input_format
, output_format
;
89 if (impl
->wg_transform
)
90 wg_transform_destroy(impl
->wg_transform
);
91 impl
->wg_transform
= NULL
;
93 mf_media_type_to_wg_format(impl
->input_type
, &input_format
);
94 if (input_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
95 return MF_E_INVALIDMEDIATYPE
;
97 mf_media_type_to_wg_format(impl
->output_type
, &output_format
);
98 if (output_format
.major_type
== WG_MAJOR_TYPE_UNKNOWN
)
99 return MF_E_INVALIDMEDIATYPE
;
101 if (!(impl
->wg_transform
= wg_transform_create(&input_format
, &output_format
)))
107 static struct video_processor
*impl_from_IMFTransform(IMFTransform
*iface
)
109 return CONTAINING_RECORD(iface
, struct video_processor
, IMFTransform_iface
);
112 static HRESULT WINAPI
video_processor_QueryInterface(IMFTransform
*iface
, REFIID iid
, void **out
)
114 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
116 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
118 if (IsEqualGUID(iid
, &IID_IMFTransform
))
119 *out
= &impl
->IMFTransform_iface
;
123 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
124 return E_NOINTERFACE
;
127 IUnknown_AddRef((IUnknown
*)*out
);
131 static ULONG WINAPI
video_processor_AddRef(IMFTransform
*iface
)
133 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
134 ULONG refcount
= InterlockedIncrement(&impl
->refcount
);
136 TRACE("iface %p increasing refcount to %lu.\n", iface
, refcount
);
141 static ULONG WINAPI
video_processor_Release(IMFTransform
*iface
)
143 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
144 ULONG refcount
= InterlockedDecrement(&impl
->refcount
);
146 TRACE("iface %p decreasing refcount to %lu.\n", iface
, refcount
);
150 if (impl
->wg_transform
)
151 wg_transform_destroy(impl
->wg_transform
);
152 if (impl
->input_type
)
153 IMFMediaType_Release(impl
->input_type
);
154 if (impl
->output_type
)
155 IMFMediaType_Release(impl
->output_type
);
156 if (impl
->attributes
)
157 IMFAttributes_Release(impl
->attributes
);
158 if (impl
->output_attributes
)
159 IMFAttributes_Release(impl
->output_attributes
);
161 wg_sample_queue_destroy(impl
->wg_sample_queue
);
168 static HRESULT WINAPI
video_processor_GetStreamLimits(IMFTransform
*iface
, DWORD
*input_minimum
,
169 DWORD
*input_maximum
, DWORD
*output_minimum
, DWORD
*output_maximum
)
171 TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
172 iface
, input_minimum
, input_maximum
, output_minimum
, output_maximum
);
173 *input_minimum
= *input_maximum
= *output_minimum
= *output_maximum
= 1;
177 static HRESULT WINAPI
video_processor_GetStreamCount(IMFTransform
*iface
, DWORD
*inputs
, DWORD
*outputs
)
179 TRACE("iface %p, inputs %p, outputs %p.\n", iface
, inputs
, outputs
);
180 *inputs
= *outputs
= 1;
184 static HRESULT WINAPI
video_processor_GetStreamIDs(IMFTransform
*iface
, DWORD input_size
, DWORD
*inputs
,
185 DWORD output_size
, DWORD
*outputs
)
187 FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p stub!\n", iface
,
188 input_size
, inputs
, output_size
, outputs
);
192 static HRESULT WINAPI
video_processor_GetInputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_INPUT_STREAM_INFO
*info
)
194 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 if (impl
->input_type
&& SUCCEEDED(hr
= IMFMediaType_GetGUID(impl
->input_type
, &MF_MT_SUBTYPE
, &subtype
))
206 && SUCCEEDED(hr
= IMFMediaType_GetUINT64(impl
->input_type
, &MF_MT_FRAME_SIZE
, &framesize
)))
207 MFCalculateImageSize(&subtype
, framesize
>> 32, (UINT32
)framesize
, &sample_size
);
212 info
->cbSize
= sample_size
;
213 info
->cbAlignment
= 0;
214 info
->hnsMaxLatency
= 0;
215 info
->cbMaxLookahead
= 0;
220 static HRESULT WINAPI
video_processor_GetOutputStreamInfo(IMFTransform
*iface
, DWORD id
, MFT_OUTPUT_STREAM_INFO
*info
)
222 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
228 TRACE("iface %p, id %#lx, info %p.\n", iface
, id
, info
);
231 return MF_E_INVALIDSTREAMNUMBER
;
233 if (impl
->output_type
&& SUCCEEDED(hr
= IMFMediaType_GetGUID(impl
->output_type
, &MF_MT_SUBTYPE
, &subtype
))
234 && SUCCEEDED(hr
= IMFMediaType_GetUINT64(impl
->output_type
, &MF_MT_FRAME_SIZE
, &framesize
)))
235 MFCalculateImageSize(&subtype
, framesize
>> 32, (UINT32
)framesize
, &sample_size
);
240 info
->cbSize
= sample_size
;
241 info
->cbAlignment
= 0;
246 static HRESULT WINAPI
video_processor_GetAttributes(IMFTransform
*iface
, IMFAttributes
**attributes
)
248 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
250 FIXME("iface %p, attributes %p stub!\n", iface
, attributes
);
252 IMFAttributes_AddRef((*attributes
= impl
->attributes
));
256 static HRESULT WINAPI
video_processor_GetInputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
258 FIXME("iface %p, id %#lx, attributes %p stub!\n", iface
, id
, attributes
);
262 static HRESULT WINAPI
video_processor_GetOutputStreamAttributes(IMFTransform
*iface
, DWORD id
, IMFAttributes
**attributes
)
264 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
266 FIXME("iface %p, id %#lx, attributes %p stub!\n", iface
, id
, attributes
);
268 IMFAttributes_AddRef((*attributes
= impl
->output_attributes
));
272 static HRESULT WINAPI
video_processor_DeleteInputStream(IMFTransform
*iface
, DWORD id
)
274 FIXME("iface %p, id %#lx stub!\n", iface
, id
);
278 static HRESULT WINAPI
video_processor_AddInputStreams(IMFTransform
*iface
, DWORD streams
, DWORD
*ids
)
280 FIXME("iface %p, streams %lu, ids %p stub!\n", iface
, streams
, ids
);
284 static HRESULT WINAPI
video_processor_GetInputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
287 IMFMediaType
*media_type
;
291 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
295 if (index
>= ARRAY_SIZE(input_types
))
296 return MF_E_NO_MORE_TYPES
;
297 subtype
= input_types
[index
];
299 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
302 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)))
304 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, subtype
)))
307 IMFMediaType_AddRef((*type
= media_type
));
310 IMFMediaType_Release(media_type
);
314 static HRESULT WINAPI
video_processor_GetOutputAvailableType(IMFTransform
*iface
, DWORD id
, DWORD index
,
317 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
318 IMFMediaType
*media_type
;
323 TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface
, id
, index
, type
);
327 if (!impl
->input_type
)
328 return MF_E_NO_MORE_TYPES
;
330 if (FAILED(hr
= IMFMediaType_GetGUID(impl
->input_type
, &MF_MT_SUBTYPE
, &subtype
))
331 || FAILED(hr
= IMFMediaType_GetUINT64(impl
->input_type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
334 if (index
> ARRAY_SIZE(output_types
))
335 return MF_E_NO_MORE_TYPES
;
337 subtype
= *output_types
[index
- 1];
339 if (FAILED(hr
= MFCreateMediaType(&media_type
)))
342 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_MAJOR_TYPE
, &MFMediaType_Video
)))
344 if (FAILED(hr
= IMFMediaType_SetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
)))
346 if (FAILED(hr
= IMFMediaType_SetUINT64(media_type
, &MF_MT_FRAME_SIZE
, frame_size
)))
349 IMFMediaType_AddRef((*type
= media_type
));
352 IMFMediaType_Release(media_type
);
356 static HRESULT WINAPI
video_processor_SetInputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
358 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
364 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
366 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
))
367 || !IsEqualGUID(&major
, &MFMediaType_Video
))
369 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
370 return MF_E_INVALIDMEDIATYPE
;
371 if (FAILED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
374 for (i
= 0; i
< ARRAY_SIZE(input_types
); ++i
)
375 if (IsEqualGUID(&subtype
, input_types
[i
]))
377 if (i
== ARRAY_SIZE(input_types
))
378 return MF_E_INVALIDMEDIATYPE
;
379 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
382 if (impl
->input_type
)
383 IMFMediaType_Release(impl
->input_type
);
384 IMFMediaType_AddRef((impl
->input_type
= type
));
386 if (impl
->output_type
&& FAILED(hr
= try_create_wg_transform(impl
)))
388 IMFMediaType_Release(impl
->input_type
);
389 impl
->input_type
= NULL
;
395 static HRESULT WINAPI
video_processor_SetOutputType(IMFTransform
*iface
, DWORD id
, IMFMediaType
*type
, DWORD flags
)
397 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
403 TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface
, id
, type
, flags
);
405 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_MAJOR_TYPE
, &major
))
406 || !IsEqualGUID(&major
, &MFMediaType_Video
))
408 if (FAILED(IMFMediaType_GetGUID(type
, &MF_MT_SUBTYPE
, &subtype
)))
409 return MF_E_INVALIDMEDIATYPE
;
410 if (FAILED(hr
= IMFMediaType_GetUINT64(type
, &MF_MT_FRAME_SIZE
, &frame_size
)))
413 for (i
= 0; i
< ARRAY_SIZE(output_types
); ++i
)
414 if (IsEqualGUID(&subtype
, output_types
[i
]))
416 if (i
== ARRAY_SIZE(output_types
))
417 return MF_E_INVALIDMEDIATYPE
;
418 if (flags
& MFT_SET_TYPE_TEST_ONLY
)
421 if (impl
->output_type
)
422 IMFMediaType_Release(impl
->output_type
);
423 IMFMediaType_AddRef((impl
->output_type
= type
));
425 if (impl
->input_type
&& FAILED(hr
= try_create_wg_transform(impl
)))
427 IMFMediaType_Release(impl
->output_type
);
428 impl
->output_type
= NULL
;
434 static HRESULT WINAPI
video_processor_GetInputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
436 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
439 TRACE("iface %p, id %#lx, type %p.\n", iface
, id
, type
);
442 return MF_E_INVALIDSTREAMNUMBER
;
444 if (!impl
->input_type
)
445 return MF_E_TRANSFORM_TYPE_NOT_SET
;
447 if (FAILED(hr
= MFCreateMediaType(type
)))
450 if (FAILED(hr
= IMFMediaType_CopyAllItems(impl
->input_type
, (IMFAttributes
*)*type
)))
451 IMFMediaType_Release(*type
);
456 static HRESULT WINAPI
video_processor_GetOutputCurrentType(IMFTransform
*iface
, DWORD id
, IMFMediaType
**type
)
458 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
461 TRACE("iface %p, id %#lx, type %p.\n", iface
, id
, type
);
464 return MF_E_INVALIDSTREAMNUMBER
;
466 if (!impl
->output_type
)
467 return MF_E_TRANSFORM_TYPE_NOT_SET
;
469 if (FAILED(hr
= MFCreateMediaType(type
)))
472 if (FAILED(hr
= IMFMediaType_CopyAllItems(impl
->output_type
, (IMFAttributes
*)*type
)))
473 IMFMediaType_Release(*type
);
478 static HRESULT WINAPI
video_processor_GetInputStatus(IMFTransform
*iface
, DWORD id
, DWORD
*flags
)
480 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
482 FIXME("iface %p, id %#lx, flags %p stub!\n", iface
, id
, flags
);
484 if (!impl
->input_type
)
485 return MF_E_TRANSFORM_TYPE_NOT_SET
;
487 *flags
= MFT_INPUT_STATUS_ACCEPT_DATA
;
491 static HRESULT WINAPI
video_processor_GetOutputStatus(IMFTransform
*iface
, DWORD
*flags
)
493 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
495 FIXME("iface %p, flags %p stub!\n", iface
, flags
);
497 if (!impl
->output_type
)
498 return MF_E_TRANSFORM_TYPE_NOT_SET
;
503 static HRESULT WINAPI
video_processor_SetOutputBounds(IMFTransform
*iface
, LONGLONG lower
, LONGLONG upper
)
505 FIXME("iface %p, lower %I64d, upper %I64d stub!\n", iface
, lower
, upper
);
509 static HRESULT WINAPI
video_processor_ProcessEvent(IMFTransform
*iface
, DWORD id
, IMFMediaEvent
*event
)
511 FIXME("iface %p, id %#lx, event %p stub!\n", iface
, id
, event
);
515 static HRESULT WINAPI
video_processor_ProcessMessage(IMFTransform
*iface
, MFT_MESSAGE_TYPE message
, ULONG_PTR param
)
517 FIXME("iface %p, message %#x, param %#Ix stub!\n", iface
, message
, param
);
521 static HRESULT WINAPI
video_processor_ProcessInput(IMFTransform
*iface
, DWORD id
, IMFSample
*sample
, DWORD flags
)
523 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
525 TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface
, id
, sample
, flags
);
527 if (!impl
->wg_transform
)
528 return MF_E_TRANSFORM_TYPE_NOT_SET
;
530 return wg_transform_push_mf(impl
->wg_transform
, sample
, impl
->wg_sample_queue
);
533 static HRESULT WINAPI
video_processor_ProcessOutput(IMFTransform
*iface
, DWORD flags
, DWORD count
,
534 MFT_OUTPUT_DATA_BUFFER
*samples
, DWORD
*status
)
536 struct video_processor
*impl
= impl_from_IMFTransform(iface
);
537 MFT_OUTPUT_STREAM_INFO info
;
538 struct wg_sample
*wg_sample
;
541 TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface
, flags
, count
, samples
, status
);
546 if (FAILED(hr
= IMFTransform_GetOutputStreamInfo(iface
, 0, &info
)))
549 if (!impl
->wg_transform
)
550 return MF_E_TRANSFORM_TYPE_NOT_SET
;
552 samples
[0].dwStatus
= 0;
553 if (!samples
[0].pSample
) return E_INVALIDARG
;
555 if (FAILED(hr
= wg_sample_create_mf(samples
[0].pSample
, &wg_sample
)))
558 if (wg_sample
->max_size
< info
.cbSize
)
560 wg_sample_release(wg_sample
);
561 return MF_E_BUFFERTOOSMALL
;
564 if (SUCCEEDED(hr
= wg_transform_read_mf(impl
->wg_transform
, wg_sample
, NULL
,
565 &samples
[0].dwStatus
)))
566 wg_sample_queue_flush(impl
->wg_sample_queue
, false);
568 wg_sample_release(wg_sample
);
573 static const IMFTransformVtbl video_processor_vtbl
=
575 video_processor_QueryInterface
,
576 video_processor_AddRef
,
577 video_processor_Release
,
578 video_processor_GetStreamLimits
,
579 video_processor_GetStreamCount
,
580 video_processor_GetStreamIDs
,
581 video_processor_GetInputStreamInfo
,
582 video_processor_GetOutputStreamInfo
,
583 video_processor_GetAttributes
,
584 video_processor_GetInputStreamAttributes
,
585 video_processor_GetOutputStreamAttributes
,
586 video_processor_DeleteInputStream
,
587 video_processor_AddInputStreams
,
588 video_processor_GetInputAvailableType
,
589 video_processor_GetOutputAvailableType
,
590 video_processor_SetInputType
,
591 video_processor_SetOutputType
,
592 video_processor_GetInputCurrentType
,
593 video_processor_GetOutputCurrentType
,
594 video_processor_GetInputStatus
,
595 video_processor_GetOutputStatus
,
596 video_processor_SetOutputBounds
,
597 video_processor_ProcessEvent
,
598 video_processor_ProcessMessage
,
599 video_processor_ProcessInput
,
600 video_processor_ProcessOutput
,
603 HRESULT
video_processor_create(REFIID riid
, void **ret
)
605 static const struct wg_format input_format
=
607 .major_type
= WG_MAJOR_TYPE_VIDEO
,
610 .format
= WG_VIDEO_FORMAT_I420
,
615 static const struct wg_format output_format
=
617 .major_type
= WG_MAJOR_TYPE_VIDEO
,
620 .format
= WG_VIDEO_FORMAT_NV12
,
625 struct wg_transform
*transform
;
626 struct video_processor
*impl
;
629 TRACE("riid %s, ret %p.\n", debugstr_guid(riid
), ret
);
631 if (!(transform
= wg_transform_create(&input_format
, &output_format
)))
633 ERR_(winediag
)("GStreamer doesn't support video conversion, please install appropriate plugins.\n");
636 wg_transform_destroy(transform
);
638 if (!(impl
= calloc(1, sizeof(*impl
))))
639 return E_OUTOFMEMORY
;
641 if (FAILED(hr
= MFCreateAttributes(&impl
->attributes
, 0)))
643 if (FAILED(hr
= MFCreateAttributes(&impl
->output_attributes
, 0)))
645 if (FAILED(hr
= wg_sample_queue_create(&impl
->wg_sample_queue
)))
648 impl
->IMFTransform_iface
.lpVtbl
= &video_processor_vtbl
;
651 *ret
= &impl
->IMFTransform_iface
;
652 TRACE("Created %p\n", *ret
);
656 if (impl
->output_attributes
)
657 IMFAttributes_Release(impl
->output_attributes
);
658 if (impl
->attributes
)
659 IMFAttributes_Release(impl
->attributes
);