From 417b4cb45331b11cb1d7dee8c4398ea36ea1c906 Mon Sep 17 00:00:00 2001 From: Ziqing Hui Date: Tue, 18 Jun 2024 11:46:27 +0800 Subject: [PATCH] winegstreamer: Implement stubs for h264 encoder. --- dlls/mf/tests/transform.c | 3 + dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/gst_private.h | 2 + dlls/winegstreamer/mfplat.c | 23 ++ dlls/winegstreamer/video_encoder.c | 338 +++++++++++++++++++ dlls/winegstreamer/winegstreamer_classes.idl | 6 + include/wmcodecdsp.idl | 6 + 7 files changed, 379 insertions(+) create mode 100644 dlls/winegstreamer/video_encoder.c diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index f982f9071a8..262e3bc4726 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -3903,7 +3903,10 @@ static void test_h264_encoder(void) check_mft_get_info(class_id, &expect_mft_info); hr = CoCreateInstance(class_id, NULL, CLSCTX_INPROC_SERVER, &IID_IMFTransform, (void **)&transform); + todo_wine ok(hr == S_OK, "CoCreateInstance returned %#lx.\n", hr); + if (hr != S_OK) + goto failed; check_interface(transform, &IID_IMFTransform, TRUE); check_interface(transform, &IID_IMediaObject, FALSE); diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index e33aa6c4d18..83093620af4 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -19,6 +19,7 @@ SOURCES = \ rsrc.rc \ unixlib.c \ video_decoder.c \ + video_encoder.c \ video_processor.c \ wg_allocator.c \ wg_format.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index ba9064bc467..bc798db5980 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -167,6 +167,8 @@ HRESULT aac_decoder_create(REFIID riid, void **ret); HRESULT h264_decoder_create(REFIID riid, void **ret); HRESULT video_processor_create(REFIID riid, void **ret); +HRESULT h264_encoder_create(REFIID riid, void **ret); + extern const GUID MFAudioFormat_RAW_AAC; #endif /* __GST_PRIVATE_INCLUDED__ */ diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 5775e8552db..dd326232b55 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -133,6 +133,7 @@ class_objects[] = { &CLSID_GStreamerByteStreamHandler, &gstreamer_byte_stream_handler_create }, { &CLSID_MSAACDecMFT, &aac_decoder_create }, { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, + { &CLSID_MSH264EncoderMFT, &h264_encoder_create }, }; HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) @@ -208,6 +209,18 @@ HRESULT mfplat_DllRegisterServer(void) {MFMediaType_Video, MFVideoFormat_YUY2}, }; + MFT_REGISTER_TYPE_INFO h264_encoder_input_types[] = + { + {MFMediaType_Video, MFVideoFormat_IYUV}, + {MFMediaType_Video, MFVideoFormat_YV12}, + {MFMediaType_Video, MFVideoFormat_NV12}, + {MFMediaType_Video, MFVideoFormat_YUY2}, + }; + MFT_REGISTER_TYPE_INFO h264_encoder_output_types[] = + { + {MFMediaType_Video, MFVideoFormat_H264}, + }; + MFT_REGISTER_TYPE_INFO video_processor_input_types[] = { {MFMediaType_Video, MFVideoFormat_IYUV}, @@ -371,6 +384,16 @@ HRESULT mfplat_DllRegisterServer(void) ARRAY_SIZE(h264_decoder_output_types), h264_decoder_output_types, }, + { + CLSID_MSH264EncoderMFT, + MFT_CATEGORY_VIDEO_ENCODER, + L"H264 Encoder MFT", + MFT_ENUM_FLAG_SYNCMFT, + ARRAY_SIZE(h264_encoder_input_types), + h264_encoder_input_types, + ARRAY_SIZE(h264_encoder_output_types), + h264_encoder_output_types, + }, { CLSID_WMVDecoderMFT, MFT_CATEGORY_VIDEO_DECODER, diff --git a/dlls/winegstreamer/video_encoder.c b/dlls/winegstreamer/video_encoder.c new file mode 100644 index 00000000000..beb74003d64 --- /dev/null +++ b/dlls/winegstreamer/video_encoder.c @@ -0,0 +1,338 @@ +/* Generic Video Encoder Transform + * + * Copyright 2024 Ziqing Hui for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "gst_private.h" + +#include "mfapi.h" +#include "mferror.h" +#include "mfobjects.h" +#include "mftransform.h" +#include "mediaerr.h" +#include "wmcodecdsp.h" + +#include "wine/debug.h" + +#include "initguid.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +WINE_DECLARE_DEBUG_CHANNEL(winediag); + +struct video_encoder +{ + IMFTransform IMFTransform_iface; + LONG refcount; + + IMFAttributes *attributes; +}; + +static inline struct video_encoder *impl_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct video_encoder, IMFTransform_iface); +} + +static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) +{ + struct video_encoder *encoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IMFTransform) || IsEqualGUID(iid, &IID_IUnknown)) + *out = &encoder->IMFTransform_iface; + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI transform_AddRef(IMFTransform *iface) +{ + struct video_encoder *encoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&encoder->refcount); + + TRACE("iface %p increasing refcount to %lu.\n", encoder, refcount); + + return refcount; +} + +static ULONG WINAPI transform_Release(IMFTransform *iface) +{ + struct video_encoder *encoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&encoder->refcount); + + TRACE("iface %p decreasing refcount to %lu.\n", encoder, refcount); + + if (!refcount) + { + IMFAttributes_Release(encoder->attributes); + free(encoder); + } + + return refcount; +} + +static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", + iface, input_minimum, input_maximum, output_minimum, output_maximum); + *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1; + return S_OK; +} + +static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); + *inputs = *outputs = 1; + return S_OK; +} + +static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, + DWORD output_size, DWORD *outputs) +{ + FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface, + input_size, inputs, output_size, outputs); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p.\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p.\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + struct video_encoder *encoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, attributes %p.\n", iface, attributes); + + if (!attributes) + return E_POINTER; + + IMFAttributes_AddRef((*attributes = encoder->attributes)); + return S_OK; +} + +static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + FIXME("iface %p, id %#lx.\n", iface, id); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + FIXME("iface %p, streams %lu, ids %p.\n", iface, streams, ids); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, + DWORD index, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + FIXME("iface %p, id %#lx, flags %p.\n", iface, id, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + FIXME("iface %p, flags %p stub!\n", iface, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + FIXME("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + FIXME("iface %p, message %#x, param %Ix.\n", iface, message, param); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + FIXME("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) +{ + FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + return E_NOTIMPL; +} + +static const IMFTransformVtbl transform_vtbl = +{ + transform_QueryInterface, + transform_AddRef, + transform_Release, + transform_GetStreamLimits, + transform_GetStreamCount, + transform_GetStreamIDs, + transform_GetInputStreamInfo, + transform_GetOutputStreamInfo, + transform_GetAttributes, + transform_GetInputStreamAttributes, + transform_GetOutputStreamAttributes, + transform_DeleteInputStream, + transform_AddInputStreams, + transform_GetInputAvailableType, + transform_GetOutputAvailableType, + transform_SetInputType, + transform_SetOutputType, + transform_GetInputCurrentType, + transform_GetOutputCurrentType, + transform_GetInputStatus, + transform_GetOutputStatus, + transform_SetOutputBounds, + transform_ProcessEvent, + transform_ProcessMessage, + transform_ProcessInput, + transform_ProcessOutput, +}; + +static HRESULT video_encoder_create(struct video_encoder **out) +{ + struct video_encoder *encoder; + HRESULT hr; + + if (!(encoder = calloc(1, sizeof(*encoder)))) + return E_OUTOFMEMORY; + + encoder->IMFTransform_iface.lpVtbl = &transform_vtbl; + encoder->refcount = 1; + + if (FAILED(hr = MFCreateAttributes(&encoder->attributes, 16))) + goto failed; + if (FAILED(hr = IMFAttributes_SetUINT32(encoder->attributes, &MFT_ENCODER_SUPPORTS_CONFIG_EVENT, TRUE))) + goto failed; + + *out = encoder; + TRACE("Created video encoder %p\n", encoder); + return S_OK; + +failed: + if (encoder->attributes) + IMFAttributes_Release(encoder->attributes); + free(encoder); + return hr; +} + +HRESULT h264_encoder_create(REFIID riid, void **out) +{ + const MFVIDEOFORMAT input_format = + { + .dwSize = sizeof(MFVIDEOFORMAT), + .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, + .guidFormat = MFVideoFormat_NV12, + }; + const MFVIDEOFORMAT output_format = + { + .dwSize = sizeof(MFVIDEOFORMAT), + .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, + .guidFormat = MFVideoFormat_H264, + }; + struct video_encoder *encoder; + HRESULT hr; + + TRACE("riid %s, out %p.\n", debugstr_guid(riid), out); + + if (FAILED(hr = check_video_transform_support(&input_format, &output_format))) + { + ERR_(winediag)("GStreamer doesn't support H.264 encoding, please install appropriate plugins\n"); + return hr; + } + + if (FAILED(hr = video_encoder_create(&encoder))) + return hr; + + TRACE("Created h264 encoder transform %p.\n", &encoder->IMFTransform_iface); + + hr = IMFTransform_QueryInterface(&encoder->IMFTransform_iface, riid, out); + IMFTransform_Release(&encoder->IMFTransform_iface); + return hr; +} diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index bb727ca8645..41ec2d26123 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -107,6 +107,12 @@ coclass CWMVDecMediaObject {} ] coclass CMSH264DecoderMFT {} +[ + threading(both), + uuid(6ca50344-051a-4ded-9779-a43305165e35) +] +coclass CMSH264EncoderMFT {} + [ threading(both), uuid(f447b69e-1884-4a7e-8055-346f74d6edb3) diff --git a/include/wmcodecdsp.idl b/include/wmcodecdsp.idl index a6f350ea2fc..9982b6e6b8a 100644 --- a/include/wmcodecdsp.idl +++ b/include/wmcodecdsp.idl @@ -52,6 +52,12 @@ coclass CResamplerMediaObject {} ] coclass CMSH264DecoderMFT {} +[ + threading(both), + uuid(6ca50344-051a-4ded-9779-a43305165e35) +] +coclass CMSH264EncoderMFT {} + [ uuid(2d709e52-123f-49b5-9cbc-9af5cde28fb9) ]