[PATCH 0/6] MR11194: colorcnv, msvproc: Reimplement using libswscale.
The remaining bits of https://gitlab.winehq.org/wine/wine/-/merge_requests/10687, performance seems to be even better. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11194
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/winegstreamer/color_convert.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index 5d9e5f1c0a9..878508d6265 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -90,7 +90,7 @@ struct color_convert struct wg_sample_queue *wg_sample_queue; }; -static inline struct color_convert *impl_from_IUnknown(IUnknown *iface) +static struct color_convert *impl_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, struct color_convert, IUnknown_inner); } @@ -702,7 +702,7 @@ static const IMFTransformVtbl transform_vtbl = transform_ProcessOutput, }; -static inline struct color_convert *impl_from_IMediaObject(IMediaObject *iface) +static struct color_convert *impl_from_IMediaObject(IMediaObject *iface) { return CONTAINING_RECORD(iface, struct color_convert, IMediaObject_iface); } @@ -885,7 +885,7 @@ static const IMediaObjectVtbl media_object_vtbl = media_object_Lock, }; -static inline struct color_convert *impl_from_IPropertyBag(IPropertyBag *iface) +static struct color_convert *impl_from_IPropertyBag(IPropertyBag *iface) { return CONTAINING_RECORD(iface, struct color_convert, IPropertyBag_iface); } @@ -927,7 +927,7 @@ static const IPropertyBagVtbl property_bag_vtbl = property_bag_Write, }; -static inline struct color_convert *impl_from_IPropertyStore(IPropertyStore *iface) +static struct color_convert *impl_from_IPropertyStore(IPropertyStore *iface) { return CONTAINING_RECORD(iface, struct color_convert, IPropertyStore_iface); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11194
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/winegstreamer/Makefile.in | 3 +- dlls/winegstreamer/color_convert.c | 678 ++++++++++++++++++++++++++++- 2 files changed, 663 insertions(+), 18 deletions(-) diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 1cc69e4a443..98c9b16dcce 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -1,7 +1,8 @@ MODULE = winegstreamer.dll UNIXLIB = winegstreamer.so IMPORTLIB = winegstreamer -IMPORTS = strmbase ole32 oleaut32 msdmo user32 +IMPORTS = $(FFMPEG_PE_LIBS) bcrypt strmbase ole32 oleaut32 msdmo user32 +EXTRAINCL = $(FFMPEG_PE_CFLAGS) DELAYIMPORTS = mfplat mf UNIX_CFLAGS = $(GSTREAMER_CFLAGS) UNIX_LIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index 878508d6265..d1c419fa13d 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -15,19 +15,248 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include <stdarg.h> +#include <stddef.h> + +#include "windef.h" +#include "winbase.h" + #include "gst_private.h" +#include "dmort.h" +#include "mediaerr.h" #include "mfapi.h" #include "mferror.h" #include "mfobjects.h" #include "mftransform.h" #include "wmcodecdsp.h" +#include <libavutil/avutil.h> +#include <libavutil/imgutils.h> +#include <libavutil/opt.h> +#include <libswscale/swscale.h> + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(winediag); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8); + +static const AVRational USER_TIME_BASE_Q = {1, 10000000}; + +static const char *debugstr_avtime(INT64 time, AVRational time_base) +{ + time = av_rescale_q_rnd(time, time_base, USER_TIME_BASE_Q, AV_ROUND_PASS_MINMAX); + if (time == AV_NOPTS_VALUE) + return "(none)"; + return wine_dbg_sprintf("%I64d", time); +} + +static const char *debugstr_avframe(AVFrame *frame) +{ + return wine_dbg_sprintf("fmt %s %dx%d stride %d", av_get_pix_fmt_name(frame->format), + frame->width, frame->height, frame->linesize[0]); +} + +static enum AVPixelFormat pixel_format_from_video_subtype(const GUID *subtype) +{ + switch (subtype->Data1) + { + /* MEDIASUBTYPE_AYUV */ case MAKEFOURCC('A','Y','U','V'): return AV_PIX_FMT_AYUV; + /* MEDIASUBTYPE_I420 */ case MAKEFOURCC('I','4','2','0'): return AV_PIX_FMT_YUV420P; + /* MEDIASUBTYPE_IYUV */ case MAKEFOURCC('I','Y','U','V'): return AV_PIX_FMT_YUV420P; + /* MEDIASUBTYPE_NV11 */ case MAKEFOURCC('N','V','1','1'): return AV_PIX_FMT_YUV411P; + /* MEDIASUBTYPE_NV12 */ case MAKEFOURCC('N','V','1','2'): return AV_PIX_FMT_NV12; + /* MEDIASUBTYPE_UYVY */ case MAKEFOURCC('U','Y','V','Y'): return AV_PIX_FMT_UYVY422; + /* MEDIASUBTYPE_V216 */ case MAKEFOURCC('V','2','1','6'): break; + /* MEDIASUBTYPE_V410 */ case MAKEFOURCC('V','4','1','0'): break; + /* MEDIASUBTYPE_Y41P */ case MAKEFOURCC('Y','4','1','P'): break; + /* MEDIASUBTYPE_Y41T */ case MAKEFOURCC('Y','4','1','T'): break; + /* MEDIASUBTYPE_Y42T */ case MAKEFOURCC('Y','4','2','T'): break; + /* MEDIASUBTYPE_YUY2 */ case MAKEFOURCC('Y','U','Y','2'): return AV_PIX_FMT_YUYV422; + /* MEDIASUBTYPE_YV12 */ case MAKEFOURCC('Y','V','1','2'): return AV_PIX_FMT_YUV420P; + /* MEDIASUBTYPE_YVU9 */ case MAKEFOURCC('Y','V','U','9'): break; + /* MEDIASUBTYPE_YVYU */ case MAKEFOURCC('Y','V','Y','U'): return AV_PIX_FMT_YVYU422; + /* MEDIASUBTYPE_RGB24 */ case 0xe436eb7d: return AV_PIX_FMT_BGR24; + /* MEDIASUBTYPE_RGB32 */ case 0xe436eb7e: return AV_PIX_FMT_BGR0; + /* MEDIASUBTYPE_RGB555 */ case 0xe436eb7c: return AV_PIX_FMT_RGB555; + /* MEDIASUBTYPE_RGB565 */ case 0xe436eb7b: return AV_PIX_FMT_RGB565; + /* MEDIASUBTYPE_RGB8 */ case 0xe436eb7a: return AV_PIX_FMT_RGB8; + } + + FIXME("Unsupported subtype %s (%s)\n", debugstr_guid(subtype), debugstr_fourcc(subtype->Data1)); + return AV_PIX_FMT_NONE; +} + +static void video_frame_init_aperture(AVFrame *frame, const MFVIDEOFORMAT *format) +{ + /* unlike the video processor, color converter doesn't really support aperture */ + frame->width = format->videoInfo.dwWidth; + frame->height = format->videoInfo.dwHeight; +} + +static void media_buffer_release(void *opaque, uint8_t *data) +{ + IMediaBuffer *media_buffer = opaque; + IMF2DBuffer2 *buffer2; + + if (SUCCEEDED(IMediaBuffer_QueryInterface(media_buffer, &IID_IMF2DBuffer2, (void **)&buffer2))) + { + IMF2DBuffer2_Unlock2D(buffer2); + IMF2DBuffer2_Release(buffer2); + } + IMediaBuffer_Release(media_buffer); +} + +static AVBufferRef *buffer_from_media_buffer(IMediaBuffer *media_buffer, int flags, LONG *pitch) +{ + BYTE *data, *scanline0; + IMF2DBuffer2 *buffer2; + AVBufferRef *buffer; + HRESULT hr; + DWORD size; + + if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(media_buffer, &IID_IMF2DBuffer2, (void **)&buffer2))) + { + MF2DBuffer_LockFlags lock_flags = (flags & AV_BUFFER_FLAG_READONLY) ? MF2DBuffer_LockFlags_Read + : MF2DBuffer_LockFlags_Write; + hr = IMF2DBuffer2_Lock2DSize(buffer2, lock_flags, &scanline0, pitch, &data, &size); + IMF2DBuffer2_Release(buffer2); + } + if (FAILED(hr)) + { + if (FAILED(hr = IMediaBuffer_GetBufferAndLength(media_buffer, &data, &size))) + return NULL; + if (!flags && FAILED(hr = IMediaBuffer_GetMaxLength(media_buffer, &size))) + return NULL; + *pitch = 0; + } + + if (!(buffer = av_buffer_create(data, size, media_buffer_release, media_buffer, flags))) + return NULL; + IMediaBuffer_AddRef(media_buffer); + return buffer; +} + +static void video_frame_init_from_format(AVFrame *frame, const MFVIDEOFORMAT *format) +{ + frame->format = pixel_format_from_video_subtype(&format->guidFormat); + frame->width = format->videoInfo.dwWidth; + frame->height = format->videoInfo.dwHeight; + frame->color_range = AVCOL_RANGE_UNSPECIFIED; + frame->color_primaries = AVCOL_PRI_UNSPECIFIED; + frame->color_trc = AVCOL_TRC_UNSPECIFIED; + frame->colorspace = AVCOL_SPC_UNSPECIFIED; + frame->chroma_location = AVCHROMA_LOC_UNSPECIFIED; +} + +static int fill_arrays_with_format(uint8_t *planes[4], int strides[4], AVBufferRef *buffer, + const MFVIDEOFORMAT *format, LONG pitch) +{ + enum AVPixelFormat pix_fmt = pixel_format_from_video_subtype(&format->guidFormat); + UINT width = format->videoInfo.dwWidth, height = format->videoInfo.dwHeight; + int size; + + size = av_image_fill_arrays(planes, strides, buffer->data, pix_fmt, width, height, 1); + TRACE("buffer %p / %#Ix size %d pitch %ld, planes %p,%p,%p strides %d,%d,%d\n", buffer->data, buffer->size, + size, pitch, planes[0], planes[1], planes[2], strides[0], strides[1], strides[2]); + if (size > buffer->size) + { + ERR("stride %lu linesize %u,%u,%u,%u size %#x buffer %#Ix\n", pitch, strides[0], strides[1], + strides[2], strides[3], size, buffer->size); + return -1; + } + + if (pitch && abs(pitch) != strides[0]) + { + int new_strides[4] = {0}; + for (int i = 0; i < 4; i++) new_strides[i] = (abs(pitch) * strides[i]) / strides[0]; + for (int i = 1; i < 4 && planes[i]; i++) + { + size_t height = (planes[i] - planes[i - 1]) / strides[i - 1]; + planes[i] = planes[i - 1] + height * new_strides[i - 1]; + } + memcpy(strides, new_strides, sizeof(new_strides)); + } + + /* unlike the video processor, color converter doesn't care about 2D buffer pitch */ + if (format->videoInfo.VideoFlags & MFVideoFlag_BottomUpLinearRep) + { + planes[0] = planes[0] + strides[0] * (height - 1); + strides[0] = -strides[0]; + } + + TRACE("buffer %p / %#Ix size %d stride %ld, planes %p,%p,%p strides %d,%d,%d\n", buffer->data, buffer->size, + size, pitch, planes[0], planes[1], planes[2], strides[0], strides[1], strides[2]); + return size; +} + +static BOOL check_arrays_alignment(uint8_t *planes[4], int strides[4], int size, int align) +{ + if (size % align) + return FALSE; + for (int i = 0; i < 4; i++) + if ((UINT_PTR)planes[i] % align) + return FALSE; + for (int i = 0; i < 4; i++) + if (strides[i] % align) + return FALSE; + return TRUE; +} + +static BOOL video_frame_wrap_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer, LONG pitch) +{ + int size; + + TRACE("frame %p, info %p, buffer %p\n", frame, format, buffer); + + video_frame_init_from_format(frame, format); + video_frame_init_aperture(frame, format); + + if ((size = fill_arrays_with_format(frame->data, frame->linesize, buffer, format, pitch)) < 0) + return size; + /* swscale requires 16byte alignment for data pointers when SSE2 optimizations are used. */ + if (!check_arrays_alignment(frame->data, frame->linesize, size, 16)) + { + ERR("frame %s isn't aligned to 16 bytes\n", debugstr_avframe(frame)); + return -1; + } + + frame->opaque = (void *)-1; + frame->buf[0] = av_buffer_ref(buffer); + frame->extended_data = frame->data; + return size; +} + +static int video_frame_copy_from_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer, + LONG pitch) +{ + int size, input_strides[4]; + UINT8 *input_planes[4]; + + ERR("frame %s, format %p, buffer %p\n", debugstr_avframe(frame), format, buffer); + + size = fill_arrays_with_format(input_planes, input_strides, buffer, format, pitch); + av_image_copy(frame->data, frame->linesize, (const UINT8 **)input_planes, input_strides, + frame->format, format->videoInfo.dwWidth, format->videoInfo.dwHeight); + return size; +} + +static int video_frame_copy_to_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer, + LONG pitch) +{ + int size, output_strides[4]; + UINT8 *output_planes[4]; + + ERR("frame %s, format %p, buffer %p\n", debugstr_avframe(frame), format, buffer); + + size = fill_arrays_with_format(output_planes, output_strides, buffer, format, pitch); + av_image_copy(output_planes, output_strides, (const UINT8 **)frame->data, frame->linesize, + frame->format, format->videoInfo.dwWidth, format->videoInfo.dwHeight); + return size; +} + static const GUID *const input_types[] = { &MFVideoFormat_YV12, @@ -82,14 +311,255 @@ struct color_convert LONG refcount; IMFMediaType *input_type; + DMO_MEDIA_TYPE input_mt; + MFVIDEOFORMAT input_format; MFT_INPUT_STREAM_INFO input_info; IMFMediaType *output_type; + DMO_MEDIA_TYPE output_mt; + MFVIDEOFORMAT output_format; MFT_OUTPUT_STREAM_INFO output_info; wg_transform_t wg_transform; struct wg_sample_queue *wg_sample_queue; + + SwsContext *context; + AVFrame input_frame; + AVFrame output_frame; + AVFrame current_frame; }; +static HRESULT color_convert_process_frame(struct color_convert *impl, AVFrame *input_frame, + DMO_OUTPUT_DATA_BUFFER *output) +{ + AVFrame output_frame = {0}; + AVBufferRef *buffer; + IMFSample *sample; + int size, ret; + HRESULT hr; + LONG pitch; + + if (!(buffer = buffer_from_media_buffer(output->pBuffer, 0, &pitch))) + return E_OUTOFMEMORY; + if ((size = video_frame_wrap_buffer(&output_frame, &impl->output_format, buffer, pitch)) < 0) + av_frame_move_ref(&output_frame, &impl->output_frame); + + TRACE("input %s output %s\n", debugstr_avframe(input_frame), debugstr_avframe(&output_frame)); + + if ((ret = sws_scale_frame(impl->context, &output_frame, input_frame)) < 0) + ERR("error ret %d (%s)\n", -ret, av_err2str(ret)); + else if ((ret = size) < 0) + ret = video_frame_copy_to_buffer(&output_frame, &impl->output_format, buffer, pitch); + + av_buffer_unref(&buffer); + + if (!output_frame.opaque) + av_frame_move_ref(&impl->output_frame, &output_frame); + else + av_frame_unref(&output_frame); + + output->dwStatus = 0; + IMediaBuffer_SetLength(output->pBuffer, ret >= 0 ? ret : 0); + if (ret < 0) + return E_FAIL; + if (!ret) + return S_FALSE; + + if (input_frame->flags & AV_FRAME_FLAG_KEY) + output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT; + output->rtTimestamp = input_frame->pts; + if (output->rtTimestamp != INT64_MIN) + output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIME; + output->rtTimelength = input_frame->duration; + if (output->rtTimelength != INT64_MIN) + output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH; + + if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(output->pBuffer, &IID_IMFSample, (void **)&sample))) + { + if (output->rtTimestamp != INT64_MIN) + IMFSample_SetSampleTime(sample, output->rtTimestamp); + if (output->rtTimelength != INT64_MIN) + IMFSample_SetSampleDuration(sample, output->rtTimelength); + if (output->dwStatus & DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT) + IMFSample_SetUINT32(sample, &MFSampleExtension_CleanPoint, 1); + IMFSample_Release(sample); + } + + TRACE("returning output size %#x, pts %s, duration %s status %#lx\n", ret, + debugstr_avtime(output->rtTimestamp, USER_TIME_BASE_Q), + debugstr_avtime(output->rtTimelength, USER_TIME_BASE_Q), output->dwStatus); + return S_OK; +} + +static HRESULT color_convert_process_input(struct color_convert *impl, const DMO_OUTPUT_DATA_BUFFER *input) +{ + LONGLONG pts = input->rtTimestamp, duration = input->rtTimelength; + AVBufferRef *buffer; + IMFSample *sample; + HRESULT hr; + LONG pitch; + int ret; + + if (!impl->context) + return DMO_E_TYPE_NOT_SET; + if (impl->current_frame.width) + return DMO_E_NOTACCEPTING; + + if (!(buffer = buffer_from_media_buffer(input->pBuffer, AV_BUFFER_FLAG_READONLY, &pitch))) + return E_OUTOFMEMORY; + if ((ret = video_frame_wrap_buffer(&impl->current_frame, &impl->input_format, buffer, pitch)) < 0) + { + ret = video_frame_copy_from_buffer(&impl->input_frame, &impl->input_format, buffer, pitch); + av_frame_move_ref(&impl->current_frame, &impl->input_frame); + } + av_buffer_unref(&buffer); + + if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(input->pBuffer, &IID_IMFSample, (void **)&sample))) + { + if (FAILED(IMFSample_GetSampleTime(sample, &pts))) + pts = INT64_MIN; + if (FAILED(IMFSample_GetSampleDuration(sample, &duration))) + duration = INT64_MIN; + IMFSample_Release(sample); + } + + impl->current_frame.pts = pts; + impl->current_frame.duration = duration; + TRACE("input frame size %ux%u, time %s, duration %s\n", impl->current_frame.width, + impl->current_frame.height, debugstr_avtime(impl->current_frame.pts, USER_TIME_BASE_Q), + debugstr_avtime(impl->current_frame.duration, USER_TIME_BASE_Q)); + return S_OK; +} + +static HRESULT color_convert_process_output(struct color_convert *impl, DMO_OUTPUT_DATA_BUFFER *output) +{ + HRESULT hr; + + if (!impl->context) + return DMO_E_TYPE_NOT_SET; + if (!impl->current_frame.width) + return S_FALSE; + + hr = color_convert_process_frame(impl, &impl->current_frame, output); + if (!impl->current_frame.opaque) + av_frame_move_ref(&impl->input_frame, &impl->current_frame); + else + av_frame_unref(&impl->current_frame); + + return hr; +} + +static void color_convert_cleanup(struct color_convert *impl) +{ + memset(&impl->input_format, 0, sizeof(impl->input_format)); + memset(&impl->output_format, 0, sizeof(impl->output_format)); + av_frame_unref(&impl->current_frame); + av_frame_unref(&impl->output_frame); + av_frame_unref(&impl->input_frame); + sws_free_context(&impl->context); +} + +static BOOL get_default_stride_sign(const BITMAPINFOHEADER *header) +{ + return header->biCompression == BI_RGB || header->biCompression == BI_BITFIELDS ? -1 : 1; +} + +static const GUID *get_dmo_subtype(const GUID *subtype) +{ + if (IsEqualGUID(subtype, &MFVideoFormat_RGB8)) + return &MEDIASUBTYPE_RGB8; + if (IsEqualGUID(subtype, &MFVideoFormat_RGB555)) + return &MEDIASUBTYPE_RGB555; + if (IsEqualGUID(subtype, &MFVideoFormat_RGB565)) + return &MEDIASUBTYPE_RGB565; + if (IsEqualGUID(subtype, &MFVideoFormat_RGB24)) + return &MEDIASUBTYPE_RGB24; + if (IsEqualGUID(subtype, &MFVideoFormat_RGB32)) + return &MEDIASUBTYPE_RGB32; + return subtype; +} + +static HRESULT init_video_format(const DMO_MEDIA_TYPE *type, MFVIDEOFORMAT *format) +{ + if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) + { + const VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)type->pbFormat; + memset(format, 0, sizeof(*format)); + format->videoInfo.dwWidth = vih->bmiHeader.biWidth; + format->videoInfo.dwHeight = abs(vih->bmiHeader.biHeight); + if (get_default_stride_sign(&vih->bmiHeader) < 0 && vih->bmiHeader.biHeight > 0) + format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep; + format->guidFormat = type->subtype; + return S_OK; + } + if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) + { + const VIDEOINFOHEADER2 *vih = (VIDEOINFOHEADER2 *)type->pbFormat; + memset(format, 0, sizeof(*format)); + format->videoInfo.dwWidth = vih->bmiHeader.biWidth; + format->videoInfo.dwHeight = abs(vih->bmiHeader.biHeight); + if (get_default_stride_sign(&vih->bmiHeader) < 0 && vih->bmiHeader.biHeight > 0) + format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep; + format->guidFormat = type->subtype; + return S_OK; + } + if (IsEqualGUID(&type->formattype, &FORMAT_MFVideoFormat)) + { + *format = *(MFVIDEOFORMAT *)type->pbFormat; + format->guidFormat = *get_dmo_subtype(&format->guidFormat); + return S_OK; + } + + FIXME("Format %s not implemented\n", debugstr_guid(&type->formattype)); + return E_NOTIMPL; +} + +static HRESULT color_convert_init(struct color_convert *impl) +{ + HRESULT hr; + int ret; + + color_convert_cleanup(impl); + + if (!(impl->context = sws_alloc_context())) + return E_OUTOFMEMORY; + if (FAILED(hr = init_video_format(&impl->input_mt, &impl->input_format)) + || FAILED(hr = init_video_format(&impl->output_mt, &impl->output_format))) + { + color_convert_cleanup(impl); + return hr; + } + + video_frame_init_from_format(&impl->input_frame, &impl->input_format); + if ((ret = av_frame_get_buffer(&impl->input_frame, 0)) < 0) + goto failed; + video_frame_init_aperture(&impl->input_frame, &impl->input_format); + + video_frame_init_from_format(&impl->output_frame, &impl->output_format); + if ((ret = av_frame_get_buffer(&impl->output_frame, 0)) < 0) + goto failed; + video_frame_init_aperture(&impl->output_frame, &impl->output_format); + + av_opt_set(impl->context, "sws_flags", "neighbor", 0); + av_opt_set_int(impl->context, "threads", 0, 0); + av_opt_set_int(impl->context, "srcw", impl->input_frame.width, 0); + av_opt_set_int(impl->context, "srch", impl->input_frame.height, 0); + av_opt_set_pixel_fmt(impl->context, "src_format", impl->input_frame.format, 0); + av_opt_set_int(impl->context, "dstw", impl->output_frame.width, 0); + av_opt_set_int(impl->context, "dsth", impl->output_frame.height, 0); + av_opt_set_pixel_fmt(impl->context, "dst_format", impl->output_frame.format, 0); + + if ((ret = sws_init_context(impl->context, NULL, NULL)) < 0) + goto failed; + + TRACE("input %s -> output %s\n", debugstr_avframe(&impl->input_frame), debugstr_avframe(&impl->output_frame)); + return S_OK; + +failed: + ERR("ret %d\n", ret); + color_convert_cleanup(impl); + return E_FAIL; +} + static struct color_convert *impl_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, struct color_convert, IUnknown_inner); @@ -210,6 +680,7 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) if (!refcount) { + color_convert_cleanup(impl); if (impl->wg_transform) wg_transform_destroy(impl->wg_transform); if (impl->input_type) @@ -740,44 +1211,195 @@ static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWOR return E_NOTIMPL; } +static HRESULT get_available_dmo_media_type(const GUID *subtype, DMO_MEDIA_TYPE *type, BOOL output) +{ + VIDEOINFOHEADER *vih; + + if (!(vih = CoTaskMemAlloc(sizeof(*vih)))) + return E_OUTOFMEMORY; + memset(vih, 0, sizeof(*vih)); + + memset(type, 0, sizeof(*type)); + type->majortype = MEDIATYPE_Video; + type->formattype = FORMAT_VideoInfo; + type->subtype = *subtype; + type->pbFormat = (BYTE *)vih; + type->cbFormat = sizeof(*vih); + return S_OK; +} + static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) { FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type); - return E_NOTIMPL; + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (type_index >= ARRAY_SIZE(input_types)) + return DMO_E_NO_MORE_ITEMS; + return get_available_dmo_media_type(input_types[type_index], type, FALSE); } static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index, DMO_MEDIA_TYPE *type) { FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type); - return E_NOTIMPL; + + if (index > 0) + return DMO_E_INVALIDSTREAMINDEX; + if (type_index >= ARRAY_SIZE(output_types)) + return DMO_E_NO_MORE_ITEMS; + return get_available_dmo_media_type(output_types[type_index], type, TRUE); +} + +static HRESULT check_dmo_media_type(const DMO_MEDIA_TYPE *type, UINT32 *image_size, + const GUID *const *formats, UINT format_count) +{ + ULONG i; + + if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) + return DMO_E_INVALIDTYPE; + for (i = 0; i < format_count; ++i) + if (IsEqualGUID(get_dmo_subtype(&type->subtype), get_dmo_subtype(formats[i]))) + break; + if (i == format_count) + return DMO_E_INVALIDTYPE; + + if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo) + && type->cbFormat >= sizeof(VIDEOINFOHEADER)) + { + VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)type->pbFormat; + if (!vih->bmiHeader.biWidth || !vih->bmiHeader.biHeight) + return DMO_E_INVALIDTYPE; + *image_size = vih->bmiHeader.biSizeImage; + return S_OK; + } + if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2) + && type->cbFormat >= sizeof(VIDEOINFOHEADER2)) + { + VIDEOINFOHEADER2 *vih = (VIDEOINFOHEADER2 *)type->pbFormat; + if (!vih->bmiHeader.biWidth || !vih->bmiHeader.biHeight) + return DMO_E_INVALIDTYPE; + *image_size = vih->bmiHeader.biSizeImage; + return S_OK; + } + if (IsEqualGUID(&type->formattype, &FORMAT_MFVideoFormat) + && type->cbFormat >= sizeof(MFVIDEOFORMAT)) + { + MFVIDEOFORMAT *fmt = (MFVIDEOFORMAT *)type->pbFormat; + if (!fmt->videoInfo.dwWidth || !fmt->videoInfo.dwHeight) + return DMO_E_INVALIDTYPE; + return MFCalculateImageSize(&type->subtype, fmt->videoInfo.dwWidth, fmt->videoInfo.dwHeight, + (UINT32 *)image_size); + } + + return DMO_E_INVALIDTYPE; +} + +static void clear_dmo_media_type(DMO_MEDIA_TYPE *mt) +{ + MoFreeMediaType(mt); + memset(mt, 0, sizeof(*mt)); } static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) { - FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags); - return E_NOTIMPL; + struct color_convert *impl = impl_from_IMediaObject(iface); + UINT32 image_size; + HRESULT hr; + + TRACE("converter %p, index %#lx, type %p, flags %#lx.\n", impl, index, type, flags); + + if (index != 0) + return DMO_E_INVALIDSTREAMINDEX; + if (!type) + { + clear_dmo_media_type(&impl->input_mt); + color_convert_cleanup(impl); + return S_OK; + } + + if (FAILED(hr = check_dmo_media_type(type, &image_size, input_types, ARRAY_SIZE(input_types)))) + return hr; + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + clear_dmo_media_type(&impl->input_mt); + if (FAILED(hr = MoCopyMediaType(&impl->input_mt, type))) + return hr; + impl->input_info.cbSize = image_size; + + if (!IsEqualGUID(&impl->output_mt.majortype, &GUID_NULL) + && FAILED(hr = color_convert_init(impl))) + { + clear_dmo_media_type(&impl->input_mt); + impl->input_info.cbSize = 0; + } + return hr; } static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index, const DMO_MEDIA_TYPE *type, DWORD flags) { - FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags); - return E_NOTIMPL; + struct color_convert *impl = impl_from_IMediaObject(iface); + UINT32 image_size; + HRESULT hr; + + TRACE("converter %p, index %#lx, type %p, flags %#lx.\n", impl, index, type, flags); + + if (index != 0) + return DMO_E_INVALIDSTREAMINDEX; + if (!type) + { + clear_dmo_media_type(&impl->output_mt); + color_convert_cleanup(impl); + return S_OK; + } + + if (FAILED(hr = check_dmo_media_type(type, &image_size, output_types, ARRAY_SIZE(output_types)))) + return hr; + if (flags & DMO_SET_TYPEF_TEST_ONLY) + return S_OK; + + clear_dmo_media_type(&impl->output_mt); + if (FAILED(hr = MoCopyMediaType(&impl->output_mt, type))) + return hr; + impl->output_info.cbSize = image_size; + + if (!IsEqualGUID(&impl->input_mt.majortype, &GUID_NULL) + && FAILED(hr = color_convert_init(impl))) + { + clear_dmo_media_type(&impl->output_mt); + impl->output_info.cbSize = 0; + } + return hr; } static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) { - FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); - return E_NOTIMPL; + struct color_convert *impl = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %#lx, type %p.\n", iface, index, type); + + if (index != 0) + return DMO_E_INVALIDSTREAMINDEX; + if (IsEqualGUID(&impl->input_mt.majortype, &GUID_NULL)) + return DMO_E_TYPE_NOT_SET; + return MoCopyMediaType(type, &impl->input_mt); } static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) { - FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type); - return E_NOTIMPL; + struct color_convert *impl = impl_from_IMediaObject(iface); + + TRACE("iface %p, index %#lx, type %p.\n", iface, index, type); + + if (index != 0) + return DMO_E_INVALIDSTREAMINDEX; + if (IsEqualGUID(&impl->output_mt.majortype, &GUID_NULL)) + return DMO_E_TYPE_NOT_SET; + return MoCopyMediaType(type, &impl->output_mt); } static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, @@ -839,16 +1461,30 @@ static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD ind static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index, IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength) { - FIXME("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s stub!\n", iface, - index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength)); - return E_NOTIMPL; + DMO_OUTPUT_DATA_BUFFER input = {.pBuffer = buffer, .dwStatus = flags, .rtTimestamp = timestamp, + .rtTimelength = timelength}; + struct color_convert *impl = impl_from_IMediaObject(iface); + + TRACE("converter %p, index %lu, buffer %p, flags %#lx, timestamp %I64d, timelength %I64d\n", + impl, index, buffer, flags, timestamp, timelength); + + return color_convert_process_input(impl, &input); } static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count, - DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status) + DMO_OUTPUT_DATA_BUFFER *output, DWORD *output_status) { - FIXME("iface %p, flags %#lx, count %lu, buffers %p, status %p stub!\n", iface, flags, count, buffers, status); - return E_NOTIMPL; + struct color_convert *impl = impl_from_IMediaObject(iface); + + TRACE("converter %p, flags %#lx, count %lu, output %p, output_status %p\n", impl, flags, count, + output, output_status); + + if (count != 1) + return E_INVALIDARG; + if (flags) + FIXME("Unimplemented flags %#lx\n", flags); + + return color_convert_process_output(impl, output); } static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock) @@ -989,6 +1625,12 @@ static const IPropertyStoreVtbl property_store_vtbl = property_store_Commit, }; +static const char *debugstr_version(UINT version) +{ + return wine_dbg_sprintf("%u.%u.%u", AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version), + AV_VERSION_MICRO(version)); +} + HRESULT color_convert_create(IUnknown *outer, IUnknown **out) { const MFVIDEOFORMAT input_format = @@ -1008,6 +1650,9 @@ HRESULT color_convert_create(IUnknown *outer, IUnknown **out) TRACE("outer %p, out %p.\n", outer, out); + TRACE("avutil version %s\n", debugstr_version(avutil_version())); + TRACE("swscale version %s\n", debugstr_version(swscale_version())); + if (FAILED(hr = check_video_transform_support(&input_format, &output_format))) { ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n"); @@ -1016,7 +1661,6 @@ HRESULT color_convert_create(IUnknown *outer, IUnknown **out) if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY; - if (FAILED(hr = wg_sample_queue_create(&impl->wg_sample_queue))) { free(impl); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11194
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/mf/tests/transform.c | 55 ++-- dlls/winegstreamer/color_convert.c | 511 +++++++++-------------------- 2 files changed, 179 insertions(+), 387 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index a8116d6f13c..2043c2e72fd 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -8959,10 +8959,10 @@ static void test_color_convert(BOOL use_2d_buffer) ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2, .todo = TRUE), - ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), - ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE), - ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), {0}, }; const struct attribute_desc expect_output_type_desc[] = @@ -8971,10 +8971,10 @@ static void test_color_convert(BOOL use_2d_buffer) ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4, .todo = TRUE), - ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), - ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE), - ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), {0}, }; const struct attribute_desc expect_output_type_desc_negative_stride[] = @@ -8983,10 +8983,10 @@ static void test_color_convert(BOOL use_2d_buffer) ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height), ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4), - ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4, .todo = TRUE), - ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE), - ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE), - ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE), + ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1), + ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1), {0}, }; const MFT_OUTPUT_STREAM_INFO output_info = @@ -9153,7 +9153,7 @@ static void test_color_convert(BOOL use_2d_buffer) check_mft_set_input_type_required(transform, input_type_desc); check_mft_set_input_type(transform, input_type_desc, S_OK); - check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, FALSE, TRUE); + check_mft_get_input_current_type(transform, expect_input_type_desc); hr = IMFTransform_QueryInterface(transform, &IID_IMediaObject, (void **)&dmo); @@ -9161,15 +9161,13 @@ static void test_color_convert(BOOL use_2d_buffer) memset(&dmo_mt, 0, sizeof(dmo_mt)); hr = IMediaObject_GetInputCurrentType(dmo, 0, &dmo_mt); - todo_wine ok(hr == S_OK, "GetInputCurrentType returned %#lx\n", hr); - todo_wine ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_MFVideoFormat), "got format %s\n", debugstr_guid(&dmo_mt.formattype)); - todo_wine ok(dmo_mt.cbFormat == sizeof(MFVIDEOFORMAT), "got cbFormat %#lx\n", dmo_mt.cbFormat); + ok(hr == S_OK, "GetInputCurrentType returned %#lx\n", hr); + ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_MFVideoFormat), "got format %s\n", debugstr_guid(&dmo_mt.formattype)); + ok(dmo_mt.cbFormat == sizeof(MFVIDEOFORMAT), "got cbFormat %#lx\n", dmo_mt.cbFormat); ok(is_dmo_subtype(&dmo_mt.subtype), "got subtype %s\n", debugstr_guid(&dmo_mt.subtype)); hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &dmo_mt, &media_type); - todo_wine ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr); /* MFCreateMediaTypeFromRepresentation automatically converts MF to DMO media types */ hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, get_mf_subtype_for_am_subtype(&dmo_mt.subtype)); ok(hr == S_OK, "SetGUID returned %#lx\n", hr); @@ -9178,8 +9176,7 @@ static void test_color_convert(BOOL use_2d_buffer) hr = IMediaObject_SetInputType(dmo, 0, &dmo_mt, 0); ok(hr == S_OK, "SetInputType returned %#lx\n", hr); - check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, FALSE, TRUE); - } + check_mft_get_input_current_type(transform, expect_input_type_desc); MoFreeMediaType(&dmo_mt); IMediaObject_Release(dmo); @@ -9194,7 +9191,7 @@ static void test_color_convert(BOOL use_2d_buffer) winetest_push_context("color conversion #%lu", i); check_mft_set_output_type_required(transform, color_conversion_tests[i].output_type_desc); check_mft_set_output_type(transform, color_conversion_tests[i].output_type_desc, S_OK); - check_mft_get_output_current_type_(__LINE__, transform, color_conversion_tests[i].expect_output_type_desc, FALSE, TRUE); + check_mft_get_output_current_type(transform, color_conversion_tests[i].expect_output_type_desc); hr = IMFTransform_QueryInterface(transform, &IID_IMediaObject, (void **)&dmo); @@ -9202,15 +9199,14 @@ static void test_color_convert(BOOL use_2d_buffer) memset(&dmo_mt, 0, sizeof(dmo_mt)); hr = IMediaObject_GetOutputCurrentType(dmo, 0, &dmo_mt); - todo_wine ok(hr == S_OK, "GetOutputCurrentType returned %#lx\n", hr); - todo_wine ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_MFVideoFormat), "got format %s\n", debugstr_guid(&dmo_mt.formattype)); - todo_wine ok(dmo_mt.cbFormat == sizeof(MFVIDEOFORMAT), "got cbFormat %#lx\n", dmo_mt.cbFormat); + ok(hr == S_OK, "GetOutputCurrentType returned %#lx\n", hr); + ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_MFVideoFormat), "got format %s\n", debugstr_guid(&dmo_mt.formattype)); + ok(dmo_mt.cbFormat == sizeof(MFVIDEOFORMAT), "got cbFormat %#lx\n", dmo_mt.cbFormat); ok(is_dmo_subtype(&dmo_mt.subtype), "got subtype %s\n", debugstr_guid(&dmo_mt.subtype)); hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &dmo_mt, &media_type); - todo_wine ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr); - if (hr == S_OK) - { + ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr); + /* MFCreateMediaTypeFromRepresentation automatically converts MF to DMO media types */ hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, get_mf_subtype_for_am_subtype(&dmo_mt.subtype)); ok(hr == S_OK, "SetGUID returned %#lx\n", hr); @@ -9219,8 +9215,7 @@ static void test_color_convert(BOOL use_2d_buffer) hr = IMediaObject_SetOutputType(dmo, 0, &dmo_mt, 0); ok(hr == S_OK, "SetOutputType returned %#lx\n", hr); - check_mft_get_output_current_type_(__LINE__, transform, color_conversion_tests[i].expect_output_type_desc, FALSE, TRUE); - } + check_mft_get_output_current_type(transform, color_conversion_tests[i].expect_output_type_desc); MoFreeMediaType(&dmo_mt); IMediaObject_Release(dmo); diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c index d1c419fa13d..20f7d15b419 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/winegstreamer/color_convert.c @@ -259,45 +259,45 @@ static int video_frame_copy_to_buffer(AVFrame *frame, const MFVIDEOFORMAT *forma static const GUID *const input_types[] = { - &MFVideoFormat_YV12, - &MFVideoFormat_YUY2, - &MFVideoFormat_UYVY, - &MFVideoFormat_AYUV, - &MFVideoFormat_NV12, - &MFVideoFormat_RGB32, - &MFVideoFormat_RGB565, - &MFVideoFormat_I420, - &MFVideoFormat_IYUV, - &MFVideoFormat_YVYU, - &MFVideoFormat_RGB24, - &MFVideoFormat_RGB555, + &MEDIASUBTYPE_YV12, + &MEDIASUBTYPE_YUY2, + &MEDIASUBTYPE_UYVY, + &MEDIASUBTYPE_AYUV, + &MEDIASUBTYPE_NV12, + &MEDIASUBTYPE_RGB32, + &MEDIASUBTYPE_RGB565, + &MEDIASUBTYPE_I420, + &MEDIASUBTYPE_IYUV, + &MEDIASUBTYPE_YVYU, + &MEDIASUBTYPE_RGB24, + &MEDIASUBTYPE_RGB555, &MEDIASUBTYPE_RGB8, &MEDIASUBTYPE_V216, &MEDIASUBTYPE_V410, - &MFVideoFormat_NV11, - &MFVideoFormat_Y41P, - &MFVideoFormat_Y41T, - &MFVideoFormat_Y42T, - &MFVideoFormat_YVU9, + &MEDIASUBTYPE_NV11, + &MEDIASUBTYPE_Y41P, + &MEDIASUBTYPE_Y41T, + &MEDIASUBTYPE_Y42T, + &MEDIASUBTYPE_YVU9, }; static const GUID *const output_types[] = { - &MFVideoFormat_YV12, - &MFVideoFormat_YUY2, - &MFVideoFormat_UYVY, - &MFVideoFormat_AYUV, - &MFVideoFormat_NV12, - &MFVideoFormat_RGB32, - &MFVideoFormat_RGB565, - &MFVideoFormat_I420, - &MFVideoFormat_IYUV, - &MFVideoFormat_YVYU, - &MFVideoFormat_RGB24, - &MFVideoFormat_RGB555, + &MEDIASUBTYPE_YV12, + &MEDIASUBTYPE_YUY2, + &MEDIASUBTYPE_UYVY, + &MEDIASUBTYPE_AYUV, + &MEDIASUBTYPE_NV12, + &MEDIASUBTYPE_RGB32, + &MEDIASUBTYPE_RGB565, + &MEDIASUBTYPE_I420, + &MEDIASUBTYPE_IYUV, + &MEDIASUBTYPE_YVYU, + &MEDIASUBTYPE_RGB24, + &MEDIASUBTYPE_RGB555, &MEDIASUBTYPE_RGB8, &MEDIASUBTYPE_V216, &MEDIASUBTYPE_V410, - &MFVideoFormat_NV11, + &MEDIASUBTYPE_NV11, }; struct color_convert @@ -310,18 +310,13 @@ struct color_convert IUnknown *outer; LONG refcount; - IMFMediaType *input_type; - DMO_MEDIA_TYPE input_mt; + DMO_MEDIA_TYPE input_type; MFVIDEOFORMAT input_format; MFT_INPUT_STREAM_INFO input_info; - IMFMediaType *output_type; - DMO_MEDIA_TYPE output_mt; + DMO_MEDIA_TYPE output_type; MFVIDEOFORMAT output_format; MFT_OUTPUT_STREAM_INFO output_info; - wg_transform_t wg_transform; - struct wg_sample_queue *wg_sample_queue; - SwsContext *context; AVFrame input_frame; AVFrame output_frame; @@ -505,6 +500,7 @@ static HRESULT init_video_format(const DMO_MEDIA_TYPE *type, MFVIDEOFORMAT *form if (IsEqualGUID(&type->formattype, &FORMAT_MFVideoFormat)) { *format = *(MFVIDEOFORMAT *)type->pbFormat; + /* normalize subtype with other formats for pixel_format_from_video_subtype */ format->guidFormat = *get_dmo_subtype(&format->guidFormat); return S_OK; } @@ -522,8 +518,8 @@ static HRESULT color_convert_init(struct color_convert *impl) if (!(impl->context = sws_alloc_context())) return E_OUTOFMEMORY; - if (FAILED(hr = init_video_format(&impl->input_mt, &impl->input_format)) - || FAILED(hr = init_video_format(&impl->output_mt, &impl->output_format))) + if (FAILED(hr = init_video_format(&impl->input_type, &impl->input_format)) + || FAILED(hr = init_video_format(&impl->output_type, &impl->output_format))) { color_convert_cleanup(impl); return hr; @@ -565,75 +561,6 @@ static struct color_convert *impl_from_IUnknown(IUnknown *iface) return CONTAINING_RECORD(iface, struct color_convert, IUnknown_inner); } -static void update_video_aperture(MFVideoInfo *input_info, MFVideoInfo *output_info) -{ - static const MFVideoArea empty_area = {0}; - - /* Tests show that the color converter ignores aperture entirely, probably a side - * effect of an internal conversion to VIDEOINFOHEADER2, as the component is also - * exposing a IMediaObject interface, and designed for dshow. - */ - - input_info->GeometricAperture = empty_area; - input_info->MinimumDisplayAperture = empty_area; - input_info->PanScanAperture = empty_area; - - output_info->GeometricAperture = empty_area; - output_info->MinimumDisplayAperture = empty_area; - output_info->PanScanAperture = empty_area; -} - -static HRESULT normalize_media_types(IMFMediaType **input_type, IMFMediaType **output_type) -{ - MFVIDEOFORMAT *input_format, *output_format; - UINT32 size; - HRESULT hr; - - if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(*input_type, &input_format, &size))) - return hr; - if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(*output_type, &output_format, &size))) - { - CoTaskMemFree(input_format); - return hr; - } - - update_video_aperture(&input_format->videoInfo, &output_format->videoInfo); - - if (FAILED(hr = MFCreateVideoMediaType(input_format, (IMFVideoMediaType **)input_type))) - goto done; - if (FAILED(hr = MFCreateVideoMediaType(output_format, (IMFVideoMediaType **)output_type))) - { - IMFMediaType_Release(*input_type); - *input_type = NULL; - } - -done: - CoTaskMemFree(input_format); - CoTaskMemFree(output_format); - return hr; -} - -static HRESULT try_create_wg_transform(struct color_convert *impl) -{ - IMFMediaType *input_type = impl->input_type, *output_type = impl->output_type; - struct wg_transform_attrs attrs = {0}; - HRESULT hr; - - if (impl->wg_transform) - { - wg_transform_destroy(impl->wg_transform); - impl->wg_transform = 0; - } - - if (FAILED(hr = normalize_media_types(&input_type, &output_type))) - return hr; - hr = wg_transform_create_mf(input_type, output_type, &attrs, &impl->wg_transform); - IMFMediaType_Release(output_type); - IMFMediaType_Release(input_type); - - return hr; -} - static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) { struct color_convert *impl = impl_from_IUnknown(iface); @@ -681,14 +608,6 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) if (!refcount) { color_convert_cleanup(impl); - if (impl->wg_transform) - wg_transform_destroy(impl->wg_transform); - if (impl->input_type) - IMFMediaType_Release(impl->input_type); - if (impl->output_type) - IMFMediaType_Release(impl->output_type); - - wg_sample_queue_destroy(impl->wg_sample_queue); free(impl); } @@ -702,6 +621,22 @@ static const IUnknownVtbl unknown_vtbl = unknown_Release, }; +static HRESULT MF_RESULT_FROM_DMO(HRESULT hr) +{ + switch (hr) + { + case DMO_E_INVALIDSTREAMINDEX: return MF_E_INVALIDSTREAMNUMBER; + case DMO_E_INVALIDTYPE: return MF_E_INVALIDMEDIATYPE; + case DMO_E_TYPE_NOT_SET: return MF_E_TRANSFORM_TYPE_NOT_SET; + case DMO_E_NOTACCEPTING: return MF_E_NOTACCEPTING; + case DMO_E_TYPE_NOT_ACCEPTED: return MF_E_INVALIDMEDIATYPE; + case DMO_E_NO_MORE_ITEMS: return MF_E_NO_MORE_TYPES; + case S_FALSE: return MF_E_TRANSFORM_NEED_MORE_INPUT; + } + + return hr; +} + static struct color_convert *impl_from_IMFTransform(IMFTransform *iface) { return CONTAINING_RECORD(iface, struct color_convert, IMFTransform_iface); @@ -752,7 +687,7 @@ static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); - if (!impl->input_type || !impl->output_type) + if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL) || IsEqualGUID(&impl->output_type.majortype, &GUID_NULL)) { memset(info, 0, sizeof(*info)); return MF_E_TRANSFORM_TYPE_NOT_SET; @@ -768,7 +703,7 @@ static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD i TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); - if (!impl->input_type || !impl->output_type) + if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL) || IsEqualGUID(&impl->output_type.majortype, &GUID_NULL)) { memset(info, 0, sizeof(*info)); return MF_E_TRANSFORM_TYPE_NOT_SET; @@ -808,272 +743,126 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea return E_NOTIMPL; } +/* some exotic YUV formats aren't supported by MFCreateMediaTypeFromRepresentation, fill missing attributes */ +static HRESULT create_media_type_from_dmo(DMO_MEDIA_TYPE *mt, IMFMediaType **type) +{ + HRESULT hr; + + if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, mt, type))) + return hr; + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8)) + IMFMediaType_SetGUID(*type, &MF_MT_SUBTYPE, &mt->subtype); + IMFMediaType_SetUINT32(*type, &MF_MT_FIXED_SIZE_SAMPLES, 1); + + return hr; +} + static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - IMFMediaType *media_type; - const GUID *subtype; + struct color_convert *impl = impl_from_IMFTransform(iface); + DMO_MEDIA_TYPE mt = {0}; HRESULT hr; TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); - *type = NULL; - - if (index >= ARRAY_SIZE(input_types)) - return MF_E_NO_MORE_TYPES; - subtype = input_types[index]; - - if (FAILED(hr = MFCreateMediaType(&media_type))) + if (FAILED(hr = MF_RESULT_FROM_DMO(IMediaObject_GetInputType(&impl->IMediaObject_iface, id, index, &mt)))) return hr; - - if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) - goto done; - if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype))) - goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1))) - goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) - goto done; - - IMFMediaType_AddRef((*type = media_type)); - -done: - IMFMediaType_Release(media_type); + hr = create_media_type_from_dmo(&mt, type); + MoFreeMediaType(&mt); return hr; } static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - IMFMediaType *media_type; - const GUID *subtype; + struct color_convert *impl = impl_from_IMFTransform(iface); + DMO_MEDIA_TYPE mt = {0}; HRESULT hr; TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); - *type = NULL; + if (FAILED(hr = MF_RESULT_FROM_DMO(IMediaObject_GetOutputType(&impl->IMediaObject_iface, id, index, &mt)))) + return hr; + hr = create_media_type_from_dmo(&mt, type); + MoFreeMediaType(&mt); + return hr; +} - if (index >= ARRAY_SIZE(output_types)) - return MF_E_NO_MORE_TYPES; - subtype = output_types[index]; +static HRESULT init_dmo_media_type(IMFMediaType *type, DMO_MEDIA_TYPE *mt) +{ + MFVIDEOFORMAT *format; + HRESULT hr; - if (FAILED(hr = MFCreateMediaType(&media_type))) + if (FAILED(hr = MFInitAMMediaTypeFromMFMediaType(type, FORMAT_MFVideoFormat, (AM_MEDIA_TYPE *)mt))) return hr; - if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) - goto done; - if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype))) - goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1))) - goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) - goto done; + format = (MFVIDEOFORMAT *)mt->pbFormat; + mt->subtype = *get_dmo_subtype(&format->guidFormat); /* need to use DMO subtypes to be accepted */ + if (!format->videoInfo.PixelAspectRatio.Numerator) + format->videoInfo.PixelAspectRatio.Numerator = 1; + if (!format->videoInfo.PixelAspectRatio.Denominator) + format->videoInfo.PixelAspectRatio.Denominator = 1; - IMFMediaType_AddRef((*type = media_type)); - -done: - IMFMediaType_Release(media_type); return hr; } static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { + DWORD dmo_flags = flags & MFT_SET_TYPE_TEST_ONLY ? DMO_SET_TYPEF_TEST_ONLY : 0; struct color_convert *impl = impl_from_IMFTransform(iface); - GUID major, subtype; - UINT64 frame_size; - UINT32 stride; + DMO_MEDIA_TYPE tmp = {0}, *mt = type ? &tmp : NULL; HRESULT hr; - ULONG i; - - TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - if (!type) - { - if (impl->input_type) - { - IMFMediaType_Release(impl->input_type); - impl->input_type = NULL; - } - if (impl->wg_transform) - { - wg_transform_destroy(impl->wg_transform); - impl->wg_transform = 0; - } + TRACE("converter %p, id %#lx, type %p, flags %#lx.\n", impl, id, type, flags); - return S_OK; - } - - if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || - FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) - return MF_E_ATTRIBUTENOTFOUND; - - if (!IsEqualGUID(&major, &MFMediaType_Video) - || IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)) - return E_INVALIDARG; - - for (i = 0; i < ARRAY_SIZE(input_types); ++i) - if (IsEqualGUID(&subtype, input_types[i])) - break; - if (i == ARRAY_SIZE(input_types)) - return MF_E_INVALIDMEDIATYPE; - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; - - if (!impl->input_type && FAILED(hr = MFCreateMediaType(&impl->input_type))) + if (type && FAILED(hr = init_dmo_media_type(type, &tmp))) return hr; - - if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)impl->input_type))) - { - IMFMediaType_Release(impl->input_type); - impl->input_type = NULL; - } - if (FAILED(IMFMediaType_GetUINT32(impl->input_type, &MF_MT_DEFAULT_STRIDE, &stride))) - { - if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, frame_size >> 32, (LONG *)&stride))) - { - IMFMediaType_Release(impl->input_type); - impl->input_type = NULL; - } - if (FAILED(hr = IMFMediaType_SetUINT32(impl->input_type, &MF_MT_DEFAULT_STRIDE, abs((INT32)stride)))) - { - IMFMediaType_Release(impl->input_type); - impl->input_type = NULL; - } - } - - if (impl->output_type && FAILED(hr = try_create_wg_transform(impl))) - { - IMFMediaType_Release(impl->input_type); - impl->input_type = NULL; - } - - if (FAILED(hr) || FAILED(MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size, - (UINT32 *)&impl->input_info.cbSize))) - impl->input_info.cbSize = 0; - + hr = MF_RESULT_FROM_DMO(IMediaObject_SetInputType(&impl->IMediaObject_iface, id, mt, dmo_flags)); + MoFreeMediaType(&tmp); return hr; } static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { + DWORD dmo_flags = flags & MFT_SET_TYPE_TEST_ONLY ? DMO_SET_TYPEF_TEST_ONLY : 0; struct color_convert *impl = impl_from_IMFTransform(iface); - GUID major, subtype; - UINT64 frame_size; - UINT32 stride; + DMO_MEDIA_TYPE tmp = {0}, *mt = type ? &tmp : NULL; HRESULT hr; - ULONG i; - - TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - - if (!type) - { - if (impl->output_type) - { - IMFMediaType_Release(impl->output_type); - impl->output_type = NULL; - } - if (impl->wg_transform) - { - wg_transform_destroy(impl->wg_transform); - impl->wg_transform = 0; - } - - return S_OK; - } - - if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || - FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) - return MF_E_ATTRIBUTENOTFOUND; - if (!IsEqualGUID(&major, &MFMediaType_Video) - || IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)) - return E_INVALIDARG; - - for (i = 0; i < ARRAY_SIZE(output_types); ++i) - if (IsEqualGUID(&subtype, output_types[i])) - break; - if (i == ARRAY_SIZE(output_types)) - return MF_E_INVALIDMEDIATYPE; - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; + TRACE("converter %p, id %#lx, type %p, flags %#lx.\n", impl, id, type, flags); - if (!impl->output_type && FAILED(hr = MFCreateMediaType(&impl->output_type))) + if (type && FAILED(hr = init_dmo_media_type(type, &tmp))) return hr; - - if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)impl->output_type))) - { - IMFMediaType_Release(impl->output_type); - impl->output_type = NULL; - } - if (FAILED(IMFMediaType_GetUINT32(impl->output_type, &MF_MT_DEFAULT_STRIDE, &stride))) - { - if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, frame_size >> 32, (LONG *)&stride))) - { - IMFMediaType_Release(impl->output_type); - impl->output_type = NULL; - } - if (FAILED(hr = IMFMediaType_SetUINT32(impl->output_type, &MF_MT_DEFAULT_STRIDE, abs((INT32)stride)))) - { - IMFMediaType_Release(impl->output_type); - impl->output_type = NULL; - } - } - - if (impl->input_type && FAILED(hr = try_create_wg_transform(impl))) - { - IMFMediaType_Release(impl->output_type); - impl->output_type = NULL; - } - - if (FAILED(hr) || FAILED(MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size, - (UINT32 *)&impl->output_info.cbSize))) - impl->output_info.cbSize = 0; - + hr = MF_RESULT_FROM_DMO(IMediaObject_SetOutputType(&impl->IMediaObject_iface, id, mt, dmo_flags)); + MoFreeMediaType(&tmp); return hr; } static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) { struct color_convert *impl = impl_from_IMFTransform(iface); - HRESULT hr; - TRACE("iface %p, id %#lx, type %p.\n", iface, id, type); + TRACE("converter %p, id %#lx, type %p.\n", impl, id, type); if (id != 0) return MF_E_INVALIDSTREAMNUMBER; - - if (!impl->input_type) + if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL)) return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaType(type))) - return hr; - - if (FAILED(hr = IMFMediaType_CopyAllItems(impl->input_type, (IMFAttributes *)*type))) - IMFMediaType_Release(*type); - - return hr; + return MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &impl->input_type, type); } static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) { struct color_convert *impl = impl_from_IMFTransform(iface); - HRESULT hr; - TRACE("iface %p, id %#lx, type %p.\n", iface, id, type); + TRACE("converter %p, id %#lx, type %p.\n", impl, id, type); if (id != 0) return MF_E_INVALIDSTREAMNUMBER; - - if (!impl->output_type) + if (IsEqualGUID(&impl->output_type.majortype, &GUID_NULL)) return MF_E_TRANSFORM_TYPE_NOT_SET; - - if (FAILED(hr = MFCreateMediaType(type))) - return hr; - - if (FAILED(hr = IMFMediaType_CopyAllItems(impl->output_type, (IMFAttributes *)*type))) - IMFMediaType_Release(*type); - - return hr; + return MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &impl->output_type, type); } static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) @@ -1109,37 +898,51 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { struct color_convert *impl = impl_from_IMFTransform(iface); + IMediaBuffer *dmo_buffer; + IMFMediaBuffer *buffer; + HRESULT hr; - TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); + TRACE("converter %p, id %#lx, sample %p, flags %#lx.\n", impl, id, sample, flags); - if (!impl->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer))) + return hr; + if (SUCCEEDED(hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(sample, buffer, 0, &dmo_buffer))) + { + hr = MF_RESULT_FROM_DMO(IMediaObject_ProcessInput(&impl->IMediaObject_iface, id, dmo_buffer, 0, 0, 0)); + IMediaBuffer_Release(dmo_buffer); + } + IMFMediaBuffer_Release(buffer); - return wg_transform_push_mf(impl->wg_transform, sample, impl->wg_sample_queue); + return hr; } static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) + MFT_OUTPUT_DATA_BUFFER *output, DWORD *output_status) { struct color_convert *impl = impl_from_IMFTransform(iface); + DMO_OUTPUT_DATA_BUFFER dmo_output = {0}; + IMFMediaBuffer *buffer; + DWORD dmo_status; HRESULT hr; - TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + TRACE("converter %p, flags %#lx, count %lu, output %p, output_status %p.\n", impl, flags, count, + output, output_status); if (count != 1) return E_INVALIDARG; - if (!impl->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; - - *status = samples->dwStatus = 0; - if (!samples->pSample) - return E_INVALIDARG; - - if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample, - impl->output_info.cbSize, &samples->dwStatus, NULL))) - wg_sample_queue_flush(impl->wg_sample_queue, false); + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(output->pSample, &buffer))) + return hr; + if (SUCCEEDED(hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(output->pSample, buffer, 0, + &dmo_output.pBuffer))) + { + hr = MF_RESULT_FROM_DMO(IMediaObject_ProcessOutput(&impl->IMediaObject_iface, flags, 1, + &dmo_output, &dmo_status)); + IMediaBuffer_Release(dmo_output.pBuffer); + } + IMFMediaBuffer_Release(buffer); + output->dwStatus = *output_status = 0; return hr; } @@ -1260,7 +1063,7 @@ static HRESULT check_dmo_media_type(const DMO_MEDIA_TYPE *type, UINT32 *image_si if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) return DMO_E_INVALIDTYPE; for (i = 0; i < format_count; ++i) - if (IsEqualGUID(get_dmo_subtype(&type->subtype), get_dmo_subtype(formats[i]))) + if (IsEqualGUID(&type->subtype, formats[i])) break; if (i == format_count) return DMO_E_INVALIDTYPE; @@ -1315,7 +1118,7 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index return DMO_E_INVALIDSTREAMINDEX; if (!type) { - clear_dmo_media_type(&impl->input_mt); + clear_dmo_media_type(&impl->input_type); color_convert_cleanup(impl); return S_OK; } @@ -1325,15 +1128,15 @@ static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK; - clear_dmo_media_type(&impl->input_mt); - if (FAILED(hr = MoCopyMediaType(&impl->input_mt, type))) + clear_dmo_media_type(&impl->input_type); + if (FAILED(hr = MoCopyMediaType(&impl->input_type, type))) return hr; impl->input_info.cbSize = image_size; - if (!IsEqualGUID(&impl->output_mt.majortype, &GUID_NULL) + if (!IsEqualGUID(&impl->output_type.majortype, &GUID_NULL) && FAILED(hr = color_convert_init(impl))) { - clear_dmo_media_type(&impl->input_mt); + clear_dmo_media_type(&impl->input_type); impl->input_info.cbSize = 0; } return hr; @@ -1352,7 +1155,7 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde return DMO_E_INVALIDSTREAMINDEX; if (!type) { - clear_dmo_media_type(&impl->output_mt); + clear_dmo_media_type(&impl->output_type); color_convert_cleanup(impl); return S_OK; } @@ -1362,15 +1165,15 @@ static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD inde if (flags & DMO_SET_TYPEF_TEST_ONLY) return S_OK; - clear_dmo_media_type(&impl->output_mt); - if (FAILED(hr = MoCopyMediaType(&impl->output_mt, type))) + clear_dmo_media_type(&impl->output_type); + if (FAILED(hr = MoCopyMediaType(&impl->output_type, type))) return hr; impl->output_info.cbSize = image_size; - if (!IsEqualGUID(&impl->input_mt.majortype, &GUID_NULL) + if (!IsEqualGUID(&impl->input_type.majortype, &GUID_NULL) && FAILED(hr = color_convert_init(impl))) { - clear_dmo_media_type(&impl->output_mt); + clear_dmo_media_type(&impl->output_type); impl->output_info.cbSize = 0; } return hr; @@ -1384,9 +1187,9 @@ static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWOR if (index != 0) return DMO_E_INVALIDSTREAMINDEX; - if (IsEqualGUID(&impl->input_mt.majortype, &GUID_NULL)) + if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET; - return MoCopyMediaType(type, &impl->input_mt); + return MoCopyMediaType(type, &impl->input_type); } static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type) @@ -1397,9 +1200,9 @@ static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWO if (index != 0) return DMO_E_INVALIDSTREAMINDEX; - if (IsEqualGUID(&impl->output_mt.majortype, &GUID_NULL)) + if (IsEqualGUID(&impl->output_type.majortype, &GUID_NULL)) return DMO_E_TYPE_NOT_SET; - return MoCopyMediaType(type, &impl->output_mt); + return MoCopyMediaType(type, &impl->output_type); } static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, @@ -1661,12 +1464,6 @@ HRESULT color_convert_create(IUnknown *outer, IUnknown **out) if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY; - if (FAILED(hr = wg_sample_queue_create(&impl->wg_sample_queue))) - { - free(impl); - return hr; - } - impl->IUnknown_inner.lpVtbl = &unknown_vtbl; impl->IMFTransform_iface.lpVtbl = &transform_vtbl; impl->IMediaObject_iface.lpVtbl = &media_object_vtbl; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11194
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/colorcnv/Makefile.in | 4 +- .../color_converter.c} | 86 ++++++++++--------- dlls/colorcnv/colorcnv.c | 47 +++------- dlls/iyuv_32/Makefile.in | 5 +- dlls/iyuv_32/iyuv.c | 8 +- dlls/iyuv_32/iyuv_private.h | 2 - dlls/winegstreamer/Makefile.in | 4 +- dlls/winegstreamer/gst_private.h | 1 - dlls/winegstreamer/main.c | 4 - dlls/winegstreamer/winegstreamer.spec | 1 - dlls/winegstreamer/winegstreamer_classes.idl | 6 -- 11 files changed, 73 insertions(+), 95 deletions(-) rename dlls/{winegstreamer/color_convert.c => colorcnv/color_converter.c} (96%) diff --git a/dlls/colorcnv/Makefile.in b/dlls/colorcnv/Makefile.in index 1798af91c9b..cfff9e88d10 100644 --- a/dlls/colorcnv/Makefile.in +++ b/dlls/colorcnv/Makefile.in @@ -1,6 +1,8 @@ MODULE = colorcnv.dll -IMPORTS = combase mfplat msdmo mfuuid dmoguids strmiids wmcodecdspuuid uuid +IMPORTS = $(FFMPEG_PE_LIBS) bcrypt combase mfplat msdmo mfuuid dmoguids strmiids wmcodecdspuuid uuid +EXTRAINCL = $(FFMPEG_PE_CFLAGS) SOURCES = \ + color_converter.c \ colorcnv.c \ colorcnv.idl diff --git a/dlls/winegstreamer/color_convert.c b/dlls/colorcnv/color_converter.c similarity index 96% rename from dlls/winegstreamer/color_convert.c rename to dlls/colorcnv/color_converter.c index 20f7d15b419..1d5f48e615e 100644 --- a/dlls/winegstreamer/color_convert.c +++ b/dlls/colorcnv/color_converter.c @@ -18,12 +18,15 @@ #include <stdarg.h> #include <stddef.h> +#define COBJMACROS #include "windef.h" #include "winbase.h" -#include "gst_private.h" - +#include "d3d9types.h" +#include "dmoreg.h" #include "dmort.h" +#include "dshow.h" +#include "dvdmedia.h" #include "mediaerr.h" #include "mfapi.h" #include "mferror.h" @@ -38,10 +41,14 @@ #include "wine/debug.h" -WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -WINE_DECLARE_DEBUG_CHANNEL(winediag); +WINE_DEFAULT_DEBUG_CHANNEL(dmo); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8); +DEFINE_GUID(DMOVideoFormat_RGB32,D3DFMT_X8R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(DMOVideoFormat_RGB24,D3DFMT_R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(DMOVideoFormat_RGB565,D3DFMT_R5G6B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); +DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); static const AVRational USER_TIME_BASE_Q = {1, 10000000}; @@ -1434,34 +1441,20 @@ static const char *debugstr_version(UINT version) AV_VERSION_MICRO(version)); } -HRESULT color_convert_create(IUnknown *outer, IUnknown **out) +static HRESULT WINAPI color_converter_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, + REFIID riid, void **out) { - const MFVIDEOFORMAT input_format = - { - .dwSize = sizeof(MFVIDEOFORMAT), - .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, - .guidFormat = MFVideoFormat_I420, - }; - const MFVIDEOFORMAT output_format = - { - .dwSize = sizeof(MFVIDEOFORMAT), - .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, - .guidFormat = MFVideoFormat_NV12, - }; struct color_convert *impl; HRESULT hr; - TRACE("outer %p, out %p.\n", outer, out); + TRACE("outer %p, riid %s, out %p.\n", outer, debugstr_guid(riid), out); + + if (outer && !IsEqualGUID(riid, &IID_IUnknown)) + return E_NOINTERFACE; TRACE("avutil version %s\n", debugstr_version(avutil_version())); TRACE("swscale version %s\n", debugstr_version(swscale_version())); - if (FAILED(hr = check_video_transform_support(&input_format, &output_format))) - { - ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n"); - return hr; - } - if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY; impl->IUnknown_inner.lpVtbl = &unknown_vtbl; @@ -1475,23 +1468,38 @@ HRESULT color_convert_create(IUnknown *outer, IUnknown **out) impl->input_info.cbAlignment = 1; impl->output_info.cbAlignment = 1; - *out = &impl->IUnknown_inner; - TRACE("Created %p\n", *out); - return S_OK; + TRACE("Created converter %p\n", impl); + + hr = IUnknown_QueryInterface(&impl->IUnknown_inner, riid, out); + IUnknown_Release(&impl->IUnknown_inner); + return hr; } -HRESULT WINAPI winegstreamer_create_color_converter(IMFTransform **out) +static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out) { - IUnknown *unknown; - HRESULT hr; - - TRACE("out %p.\n", out); - - if (!init_gstreamer()) - return E_FAIL; + *out = IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown) ? iface : NULL; + return *out ? S_OK : E_NOINTERFACE; +} +static ULONG WINAPI class_factory_AddRef(IClassFactory *iface) +{ + return 2; +} +static ULONG WINAPI class_factory_Release(IClassFactory *iface) +{ + return 1; +} +static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock) +{ + return S_OK; +} - if (FAILED(hr = color_convert_create(NULL, &unknown))) - return hr; +static const IClassFactoryVtbl color_converter_factory_vtbl = +{ + class_factory_QueryInterface, + class_factory_AddRef, + class_factory_Release, + color_converter_factory_CreateInstance, + class_factory_LockServer, +}; - return IUnknown_QueryInterface(unknown, &IID_IMFTransform, (void**)out); -} +IClassFactory color_converter_factory = {&color_converter_factory_vtbl}; diff --git a/dlls/colorcnv/colorcnv.c b/dlls/colorcnv/colorcnv.c index e9bf90932bc..467a0df8c82 100644 --- a/dlls/colorcnv/colorcnv.c +++ b/dlls/colorcnv/colorcnv.c @@ -25,11 +25,22 @@ #include "d3d9.h" #include "dmoreg.h" +#include "dmort.h" #include "dshow.h" +#include "dvdmedia.h" +#include "mediaerr.h" #include "mfapi.h" +#include "mferror.h" +#include "mfobjects.h" +#include "mftransform.h" #include "rpcproxy.h" #include "wmcodecdsp.h" +#include <libavutil/avutil.h> +#include <libavutil/opt.h> +#include <libavutil/imgutils.h> +#include <libswscale/swscale.h> + #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(dmo); @@ -43,41 +54,7 @@ DEFINE_GUID(DMOVideoFormat_RGB565,D3DFMT_R5G6B5,0x524f,0x11ce,0x9f,0x53,0x00,0x2 DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); -static HRESULT WINAPI color_converter_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, - REFIID riid, void **out) -{ - static const GUID CLSID_wg_color_converter = {0xf47e2da5,0xe370,0x47b7,{0x90,0x3a,0x07,0x8d,0xdd,0x45,0xa5,0xcc}}; - return CoCreateInstance(&CLSID_wg_color_converter, outer, CLSCTX_INPROC_SERVER, riid, out); -} - -static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out) -{ - *out = IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown) ? iface : NULL; - return *out ? S_OK : E_NOINTERFACE; -} -static ULONG WINAPI class_factory_AddRef(IClassFactory *iface) -{ - return 2; -} -static ULONG WINAPI class_factory_Release(IClassFactory *iface) -{ - return 1; -} -static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock) -{ - return S_OK; -} - -static const IClassFactoryVtbl color_converter_factory_vtbl = -{ - class_factory_QueryInterface, - class_factory_AddRef, - class_factory_Release, - color_converter_factory_CreateInstance, - class_factory_LockServer, -}; - -static IClassFactory color_converter_factory = {&color_converter_factory_vtbl}; +extern IClassFactory color_converter_factory; /*********************************************************************** * DllGetClassObject (colorcnv.@) diff --git a/dlls/iyuv_32/Makefile.in b/dlls/iyuv_32/Makefile.in index e5a261b973f..7830169ed28 100644 --- a/dlls/iyuv_32/Makefile.in +++ b/dlls/iyuv_32/Makefile.in @@ -1,6 +1,9 @@ MODULE = iyuv_32.dll -IMPORTS = user32 mfplat ole32 winegstreamer +IMPORTS = $(FFMPEG_PE_LIBS) bcrypt user32 combase mfplat msdmo mfuuid dmoguids strmiids wmcodecdspuuid uuid +EXTRAINCL = $(FFMPEG_PE_CFLAGS) +PARENTSRC = ../colorcnv SOURCES = \ + color_converter.c \ iyuv.c \ iyuv_32.rc diff --git a/dlls/iyuv_32/iyuv.c b/dlls/iyuv_32/iyuv.c index f990a5bd6a1..6c9a8b43a51 100644 --- a/dlls/iyuv_32/iyuv.c +++ b/dlls/iyuv_32/iyuv.c @@ -26,9 +26,10 @@ #include "wingdi.h" #include "winuser.h" +#define COBJMACROS #include "commdlg.h" -#include "initguid.h" #include "vfw.h" +#include "unknwn.h" #include "wmcodecdsp.h" #include "iyuv_private.h" @@ -45,6 +46,9 @@ static HINSTANCE IYUV_32_module; #define compare_fourcc(fcc1, fcc2) (((fcc1) ^ (fcc2)) & ~0x20202020) +/* in dlls/colorcnv/color_converter.c */ +extern IClassFactory color_converter_factory; + static inline UINT64 make_uint64(UINT32 high, UINT32 low) { return ((UINT64)high << 32) | low; @@ -59,7 +63,7 @@ static LRESULT IYUV_Open(const ICINFO *icinfo) if (icinfo && compare_fourcc(icinfo->fccType, ICTYPE_VIDEO)) return 0; - if (FAILED(winegstreamer_create_color_converter(&transform))) + if (FAILED(IClassFactory_CreateInstance(&color_converter_factory, NULL, &IID_IMFTransform, (void **)&transform))) transform = NULL; return (LRESULT)transform; diff --git a/dlls/iyuv_32/iyuv_private.h b/dlls/iyuv_32/iyuv_private.h index 694f89799d5..a58482f7a0d 100644 --- a/dlls/iyuv_32/iyuv_private.h +++ b/dlls/iyuv_32/iyuv_private.h @@ -25,8 +25,6 @@ #include "mfapi.h" #include "mftransform.h" -HRESULT WINAPI winegstreamer_create_color_converter(IMFTransform **out); - #define IDS_NAME 100 #define IDS_DESCRIPTION 101 diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 98c9b16dcce..81700f12ea9 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -1,8 +1,7 @@ MODULE = winegstreamer.dll UNIXLIB = winegstreamer.so IMPORTLIB = winegstreamer -IMPORTS = $(FFMPEG_PE_LIBS) bcrypt strmbase ole32 oleaut32 msdmo user32 -EXTRAINCL = $(FFMPEG_PE_CFLAGS) +IMPORTS = strmbase ole32 oleaut32 msdmo user32 DELAYIMPORTS = mfplat mf UNIX_CFLAGS = $(GSTREAMER_CFLAGS) UNIX_LIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) @@ -12,7 +11,6 @@ VER_OLESELFREGISTER = 1 SOURCES = \ aac_decoder.c \ - color_convert.c \ main.c \ media_sink.c \ media_source.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 5770e2a5c8d..0301db6e627 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -138,7 +138,6 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out); HRESULT wave_parser_create(IUnknown *outer, IUnknown **out); HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out); HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out); -HRESULT color_convert_create(IUnknown *outer, IUnknown **out); HRESULT mp3_sink_class_factory_create(IUnknown *outer, IUnknown **out); HRESULT mpeg4_sink_class_factory_create(IUnknown *outer, IUnknown **out); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 0bf35669c98..6a8bd4b6413 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -979,14 +979,12 @@ static struct class_factory mpeg_splitter_cf = {{&class_factory_vtbl}, mpeg_spli static struct class_factory wave_parser_cf = {{&class_factory_vtbl}, wave_parser_create}; static struct class_factory wma_decoder_cf = {{&class_factory_vtbl}, wma_decoder_create}; static struct class_factory wmv_decoder_cf = {{&class_factory_vtbl}, wmv_decoder_create}; -static struct class_factory color_convert_cf = {{&class_factory_vtbl}, color_convert_create}; static struct class_factory mp3_sink_class_factory_cf = {{&class_factory_vtbl}, mp3_sink_class_factory_create}; static struct class_factory mpeg4_sink_class_factory_cf = {{&class_factory_vtbl}, mpeg4_sink_class_factory_create}; HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) { static const GUID CLSID_wg_avi_splitter = {0x272bfbfb,0x50d0,0x4078,{0xb6,0x00,0x1e,0x95,0x9c,0x30,0x13,0x37}}; - static const GUID CLSID_wg_color_converter = {0xf47e2da5,0xe370,0x47b7,{0x90,0x3a,0x07,0x8d,0xdd,0x45,0xa5,0xcc}}; static const GUID CLSID_wg_mp3_sink_factory = {0x1f302877,0xaaab,0x40a3,{0xb9,0xe0,0x9f,0x48,0xda,0xf3,0x5b,0xc8}}; static const GUID CLSID_wg_mpeg4_sink_factory = {0x5d5407d9,0xc6ca,0x4770,{0xa7,0xcc,0x27,0xc0,0xcb,0x8a,0x76,0x27}}; static const GUID CLSID_wg_mpeg_audio_decoder = {0xc9f285f8,0x4380,0x4121,{0x97,0x1f,0x49,0xa9,0x53,0x16,0xc2,0x7b}}; @@ -1025,8 +1023,6 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) factory = &wma_decoder_cf; else if (IsEqualGUID(clsid, &CLSID_wg_wmv_decoder)) factory = &wmv_decoder_cf; - else if (IsEqualGUID(clsid, &CLSID_wg_color_converter)) - factory = &color_convert_cf; else if (IsEqualGUID(clsid, &CLSID_wg_mp3_sink_factory)) factory = &mp3_sink_class_factory_cf; else if (IsEqualGUID(clsid, &CLSID_wg_mpeg4_sink_factory)) diff --git a/dlls/winegstreamer/winegstreamer.spec b/dlls/winegstreamer/winegstreamer.spec index 69eed004b78..095f75a0865 100644 --- a/dlls/winegstreamer/winegstreamer.spec +++ b/dlls/winegstreamer/winegstreamer.spec @@ -4,4 +4,3 @@ @ stdcall -private DllUnregisterServer() @ stdcall winegstreamer_create_wm_sync_reader(ptr ptr) @ stdcall winegstreamer_create_video_decoder(ptr) -@ stdcall winegstreamer_create_color_converter(ptr) diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index 15c0c13260d..8afa08df5f7 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -107,12 +107,6 @@ coclass wg_h264_decoder {} ] coclass wg_h264_encoder {} -[ - threading(both), - uuid(f47e2da5-e370-47b7-903a-078ddd45a5cc) -] -coclass wg_color_converter {} - [ threading(both), uuid(1f302877-aaab-40a3-b9e0-9f48daf35bc8) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11194
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/mf/tests/transform.c | 21 +- dlls/winegstreamer/Makefile.in | 3 +- dlls/winegstreamer/video_processor.c | 550 +++++++++++++++++++++++---- 3 files changed, 474 insertions(+), 100 deletions(-) diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 2043c2e72fd..4dcff7ef8cc 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -9738,7 +9738,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = rgb32_default_stride, .output_bitmap = L"rgb32frame-flip.bmp", .output_buffer_desc = use_2d_buffer ? rgb32_negative_stride : NULL, .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc, - .delta = 2, /* Windows returns 0, Wine needs 2 */ }, { /* Test 1 */ .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame.bmp", @@ -9746,7 +9745,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = rgb32_negative_stride, .output_bitmap = L"rgb32frame-flip.bmp", .output_buffer_desc = use_2d_buffer ? rgb32_negative_stride : NULL, .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc, - .delta = 2, /* Windows returns 0, Wine needs 2 */ }, { /* Test 2 */ .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame.bmp", @@ -9762,7 +9760,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = nv12_default_stride, .output_bitmap = L"nv12frame-flip.bmp", .output_bitmap_2d = L"nv12frame-flip-2d.bmp", .output_buffer_desc = use_2d_buffer ? nv12_default_stride : NULL, .output_sample_desc = &nv12_sample_desc, .output_sample_2d_desc = &nv12_sample_2d_desc, - .delta = 2, /* Windows returns 0, Wine needs 2 */ }, { /* Test 4 */ .input_type_desc = rgb32_negative_stride, .input_bitmap = L"rgb32frame.bmp", @@ -9770,7 +9767,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = nv12_default_stride, .output_bitmap = L"nv12frame-flip.bmp", .output_bitmap_2d = L"nv12frame-flip-2d.bmp", .output_buffer_desc = use_2d_buffer ? nv12_default_stride : NULL, .output_sample_desc = &nv12_sample_desc, .output_sample_2d_desc = &nv12_sample_2d_desc, - .delta = 2, /* Windows returns 0, Wine needs 2 */ }, { /* Test 5 */ .input_type_desc = rgb32_positive_stride, .input_bitmap = L"rgb32frame.bmp", @@ -9817,6 +9813,7 @@ static void test_video_processor(BOOL use_2d_buffer) .output_buffer_desc = use_2d_buffer ? rgb32_with_aperture : NULL, .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc, .broken = TRUE, /* old Windows version incorrectly rescale */ + .delta = 3, /* Windows returns 0, Wine needs 3 */ }, { /* Test 11 */ .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame.bmp", @@ -9824,7 +9821,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = rgb555_default_stride, .output_bitmap = L"rgb555frame.bmp", .output_buffer_desc = use_2d_buffer ? rgb555_negative_stride : NULL, .output_sample_desc = &rgb555_sample_desc, .output_sample_2d_desc = &rgb555_sample_desc, - .delta = 5, /* Windows returns 0, Wine needs 5 */ }, { /* Test 12 */ .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame.bmp", @@ -9832,7 +9828,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = rgb555_negative_stride, .output_bitmap = L"rgb555frame.bmp", .output_buffer_desc = use_2d_buffer ? rgb555_negative_stride : NULL, .output_sample_desc = &rgb555_sample_desc, .output_sample_2d_desc = &rgb555_sample_desc, - .delta = 5, /* Windows returns 0, Wine needs 5 */ }, { /* Test 13 */ .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame.bmp", @@ -9840,7 +9835,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = rgb555_positive_stride, .output_bitmap = L"rgb555frame-flip.bmp", .output_buffer_desc = use_2d_buffer ? rgb555_positive_stride : NULL, .output_sample_desc = &rgb555_sample_desc, .output_sample_2d_desc = &rgb555_sample_desc, - .delta = 3, /* Windows returns 0, Wine needs 3 */ }, { /* Test 14 */ .input_type_desc = rgb555_default_stride, .input_bitmap = L"rgb555frame.bmp", @@ -9848,7 +9842,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = rgb555_positive_stride, .output_bitmap = L"rgb555frame-flip.bmp", .output_buffer_desc = use_2d_buffer ? rgb555_positive_stride : NULL, .output_sample_desc = &rgb555_sample_desc, .output_sample_2d_desc = &rgb555_sample_desc, - .delta = 4, /* Windows returns 0, Wine needs 4 */ }, { /* Test 15 */ .input_type_desc = nv12_with_aperture, .input_bitmap = L"nv12frame.bmp", @@ -9865,7 +9858,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_buffer_desc = use_2d_buffer ? rgb32_with_aperture : NULL, .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc, .broken = TRUE, /* old Windows version incorrectly rescale */ - .todo = use_2d_buffer, }, { /* Test 17 */ .input_type_desc = rgb32_with_aperture, .input_bitmap = L"rgb32frame-flip.bmp", @@ -9890,7 +9882,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_buffer_desc = use_2d_buffer ? rgb32_default_stride : NULL, .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc, .delta = 3, /* Windows returns 3 with 2D buffer */ - .todo = use_2d_buffer, }, { /* Test 20 */ .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame.bmp", @@ -9899,7 +9890,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_buffer_desc = use_2d_buffer ? rgb32_positive_stride : NULL, .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc, .delta = 3, /* Windows returns 3 with 2D buffer */ - .todo = use_2d_buffer, }, { /* Test 21, 2D only */ @@ -9908,7 +9898,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = rgb32_default_stride, .output_bitmap = L"rgb32frame-extra-width.bmp", .output_buffer_desc = rgb32_extra_width, .output_sample_desc = &rgb32_extra_width_sample_desc, .output_sample_2d_desc = &rgb32_extra_width_sample_desc, - .todo = TRUE, }, { /* Test 22, 2D only */ .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame-extra-width.bmp", @@ -9916,7 +9905,7 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = nv12_default_stride, .output_bitmap_1d = L"nv12frame.bmp", .output_bitmap_2d = L"nv12frame-2d.bmp", .output_buffer_desc = nv12_default_stride, .output_sample_desc = &nv12_sample_desc, .output_sample_2d_desc = &nv12_sample_2d_desc, - .delta = 2, /* Windows returns 2 with 1D buffer */ .todo = TRUE, + .delta = 2, /* Windows returns 2 with 1D buffer */ }, { /* Test 23, 2D only */ .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame-extra-width.bmp", @@ -9924,7 +9913,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = nv12_default_stride, .output_bitmap_1d = L"nv12frame-extra-width.bmp", .output_bitmap_2d = L"nv12frame-extra-width-2d.bmp", .output_buffer_desc = nv12_extra_width, .output_sample_desc = &nv12_extra_width_sample_desc, .output_sample_2d_desc = &nv12_extra_width_sample_2d_desc, - .todo = TRUE, }, { /* Test 24, 2D only */ .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame-extra-width.bmp", @@ -9932,7 +9920,6 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = rgb32_default_stride, .output_bitmap_1d = L"rgb32frame.bmp", .output_bitmap_2d = L"rgb32frame.bmp", .output_buffer_desc = rgb32_default_stride, .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc, - .todo = TRUE, }, { /* Test 25 */ .input_type_desc = rgb32_crop, .input_bitmap = L"rgb32frame-crop.bmp", @@ -9940,8 +9927,7 @@ static void test_video_processor(BOOL use_2d_buffer) .output_type_desc = nv12_crop, .output_bitmap = L"nv12frame-crop.bmp", .output_bitmap_1d = L"nv12frame-crop-1d.bmp", .output_bitmap_2d = L"nv12frame-crop-2d.bmp", .output_buffer_desc = use_2d_buffer ? nv12_crop : NULL, .output_sample_desc = &nv12_crop_sample_desc, .output_sample_2d_desc = &nv12_crop_sample_2d_desc, - .delta = 2, /* Windows returns 1, Wine needs 2 */ - .todo = use_2d_buffer, + .delta = 1, /* Windows returns 1, Wine needs 2 */ }, }; @@ -10131,7 +10117,6 @@ static void test_video_processor(BOOL use_2d_buffer) ok(hr == S_OK, "Failed to create a sample, hr %#lx.\n", hr); hr = check_mft_process_output(transform, output_sample, &output_status); - todo_wine ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "Unexpected hr %#lx.\n", hr); hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0); diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 81700f12ea9..1df91596e30 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -1,7 +1,8 @@ MODULE = winegstreamer.dll UNIXLIB = winegstreamer.so IMPORTLIB = winegstreamer -IMPORTS = strmbase ole32 oleaut32 msdmo user32 +IMPORTS = $(FFMPEG_PE_LIBS) bcrypt strmbase ole32 oleaut32 msdmo user32 +EXTRAINCL = $(FFMPEG_PE_CFLAGS) DELAYIMPORTS = mfplat mf UNIX_CFLAGS = $(GSTREAMER_CFLAGS) UNIX_LIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/winegstreamer/video_processor.c index 301a76ca91c..9208106e10e 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/winegstreamer/video_processor.c @@ -17,21 +17,256 @@ #include "gst_private.h" +#include "d3d9types.h" +#include "mediaerr.h" #include "mfapi.h" #include "mferror.h" #include "mfobjects.h" #include "mftransform.h" #include "wmcodecdsp.h" +#include <libavutil/avutil.h> +#include <libavutil/imgutils.h> +#include <libavutil/opt.h> +#include <libswscale/swscale.h> + #include "wine/debug.h" -WINE_DEFAULT_DEBUG_CHANNEL(mfplat); +WINE_DEFAULT_DEBUG_CHANNEL(dmo); WINE_DECLARE_DEBUG_CHANNEL(winediag); extern GUID MFVideoFormat_ABGR32; static const GUID MF_XVP_PLAYBACK_MODE = { 0x3c5d293f, 0xad67, 0x4e29, { 0xaf, 0x12, 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9 } }; +static const AVRational USER_TIME_BASE_Q = {1, 10000000}; + +static const char *debugstr_avtime(INT64 time, AVRational time_base) +{ + time = av_rescale_q_rnd(time, time_base, USER_TIME_BASE_Q, AV_ROUND_PASS_MINMAX); + if (time == AV_NOPTS_VALUE) + return "(none)"; + return wine_dbg_sprintf("%I64d", time); +} + +static const char *debugstr_avframe(AVFrame *frame) +{ + return wine_dbg_sprintf("fmt %s %dx%d stride %d", av_get_pix_fmt_name(frame->format), + frame->width, frame->height, frame->linesize[0]); +} + +static enum AVPixelFormat pixel_format_from_video_subtype(const GUID *subtype) +{ + switch (subtype->Data1) + { + /* MFVideoFormat_420O */ case MAKEFOURCC('4','2','0','O'): break; + /* MFVideoFormat_AYUV */ case MAKEFOURCC('A','Y','U','V'): return AV_PIX_FMT_AYUV; + /* MFVideoFormat_I420 */ case MAKEFOURCC('I','4','2','0'): return AV_PIX_FMT_YUV420P; + /* MFVideoFormat_IYUV */ case MAKEFOURCC('I','Y','U','V'): return AV_PIX_FMT_YUV420P; + /* MFVideoFormat_NV11 */ case MAKEFOURCC('N','V','1','1'): return AV_PIX_FMT_YUV411P; + /* MFVideoFormat_NV12 */ case MAKEFOURCC('N','V','1','2'): return AV_PIX_FMT_NV12; + /* MFVideoFormat_P208 */ case MAKEFOURCC('P','2','0','8'): break; + /* MFVideoFormat_UYVY */ case MAKEFOURCC('U','Y','V','Y'): return AV_PIX_FMT_UYVY422; + /* MFVideoFormat_v410 */ case MAKEFOURCC('v','4','1','0'): break; + /* MFVideoFormat_Y216 */ case MAKEFOURCC('Y','2','1','6'): return AV_PIX_FMT_Y216; + /* MFVideoFormat_Y41P */ case MAKEFOURCC('Y','4','1','P'): break; + /* MFVideoFormat_Y41T */ case MAKEFOURCC('Y','4','1','T'): break; + /* MFVideoFormat_Y42T */ case MAKEFOURCC('Y','4','2','T'): break; + /* MFVideoFormat_YUY2 */ case MAKEFOURCC('Y','U','Y','2'): return AV_PIX_FMT_YUYV422; + /* MFVideoFormat_YV12 */ case MAKEFOURCC('Y','V','1','2'): return AV_PIX_FMT_YUV420P; + /* MFVideoFormat_YVYU */ case MAKEFOURCC('Y','V','Y','U'): return AV_PIX_FMT_YVYU422; + /* MFVideoFormat_ABGR32 */ case D3DFMT_A8B8G8R8: return AV_PIX_FMT_RGBA; + /* MFVideoFormat_ARGB32 */ case D3DFMT_A8R8G8B8: return AV_PIX_FMT_BGRA; + /* MFVideoFormat_RGB24 */ case D3DFMT_R8G8B8: return AV_PIX_FMT_BGR24; + /* MFVideoFormat_RGB32 */ case D3DFMT_X8R8G8B8: return AV_PIX_FMT_BGR0; + /* MFVideoFormat_RGB555 */ case D3DFMT_X1R5G5B5: return AV_PIX_FMT_RGB555; + /* MFVideoFormat_RGB565 */ case D3DFMT_R5G6B5: return AV_PIX_FMT_RGB565; + /* MFVideoFormat_RGB8 */ case D3DFMT_P8: return AV_PIX_FMT_RGB8; + } + + FIXME("Unsupported subtype %s (%s)\n", debugstr_guid(subtype), debugstr_fourcc(subtype->Data1)); + return AV_PIX_FMT_NONE; +} + +static void video_frame_init_aperture(AVFrame *frame, const MFVIDEOFORMAT *format) +{ + if (format->videoInfo.MinimumDisplayAperture.OffsetX.value + || format->videoInfo.MinimumDisplayAperture.OffsetY.value + || format->videoInfo.MinimumDisplayAperture.Area.cx + || format->videoInfo.MinimumDisplayAperture.Area.cy) + { + frame->width = format->videoInfo.MinimumDisplayAperture.OffsetX.value + + format->videoInfo.MinimumDisplayAperture.Area.cx; + frame->height = format->videoInfo.MinimumDisplayAperture.OffsetY.value + + format->videoInfo.MinimumDisplayAperture.Area.cy; + } + else + { + frame->width = format->videoInfo.dwWidth; + frame->height = format->videoInfo.dwHeight; + } +} + +static void media_buffer_release(void *opaque, uint8_t *data) +{ + IMediaBuffer *media_buffer = opaque; + IMF2DBuffer2 *buffer2; + + if (SUCCEEDED(IMediaBuffer_QueryInterface(media_buffer, &IID_IMF2DBuffer2, (void **)&buffer2))) + { + IMF2DBuffer2_Unlock2D(buffer2); + IMF2DBuffer2_Release(buffer2); + } + IMediaBuffer_Release(media_buffer); +} + +static AVBufferRef *buffer_from_media_buffer(IMediaBuffer *media_buffer, int flags, LONG *pitch) +{ + BYTE *data, *scanline0; + IMF2DBuffer2 *buffer2; + AVBufferRef *buffer; + HRESULT hr; + DWORD size; + + if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(media_buffer, &IID_IMF2DBuffer2, (void **)&buffer2))) + { + MF2DBuffer_LockFlags lock_flags = (flags & AV_BUFFER_FLAG_READONLY) ? MF2DBuffer_LockFlags_Read + : MF2DBuffer_LockFlags_Write; + hr = IMF2DBuffer2_Lock2DSize(buffer2, lock_flags, &scanline0, pitch, &data, &size); + IMF2DBuffer2_Release(buffer2); + } + if (FAILED(hr)) + { + if (FAILED(hr = IMediaBuffer_GetBufferAndLength(media_buffer, &data, &size))) + return NULL; + if (!flags && FAILED(hr = IMediaBuffer_GetMaxLength(media_buffer, &size))) + return NULL; + *pitch = 0; + } + + if (!(buffer = av_buffer_create(data, size, media_buffer_release, media_buffer, flags))) + return NULL; + IMediaBuffer_AddRef(media_buffer); + return buffer; +} + +static void video_frame_init_from_format(AVFrame *frame, const MFVIDEOFORMAT *format) +{ + frame->format = pixel_format_from_video_subtype(&format->guidFormat); + frame->width = format->videoInfo.dwWidth; + frame->height = format->videoInfo.dwHeight; + frame->color_range = AVCOL_RANGE_UNSPECIFIED; + frame->color_primaries = AVCOL_PRI_UNSPECIFIED; + frame->color_trc = AVCOL_TRC_UNSPECIFIED; + frame->colorspace = AVCOL_SPC_UNSPECIFIED; + frame->chroma_location = AVCHROMA_LOC_UNSPECIFIED; +} + +static int fill_arrays_with_format(uint8_t *planes[4], int strides[4], AVBufferRef *buffer, + const MFVIDEOFORMAT *format, LONG pitch) +{ + enum AVPixelFormat pix_fmt = pixel_format_from_video_subtype(&format->guidFormat); + UINT width = format->videoInfo.dwWidth, height = format->videoInfo.dwHeight; + int size; + + size = av_image_fill_arrays(planes, strides, buffer->data, pix_fmt, width, height, 1); + TRACE("buffer %p / %#Ix size %d pitch %ld, planes %p,%p,%p strides %d,%d,%d\n", buffer->data, buffer->size, + size, pitch, planes[0], planes[1], planes[2], strides[0], strides[1], strides[2]); + if (size > buffer->size) + { + ERR("stride %ld linesize %u,%u,%u,%u size %#x buffer %#Ix\n", pitch, strides[0], strides[1], + strides[2], strides[3], size, buffer->size); + return -1; + } + + if (pitch && abs(pitch) != strides[0]) + { + int new_strides[4] = {0}; + for (int i = 0; i < 4; i++) new_strides[i] = (abs(pitch) * strides[i]) / strides[0]; + for (int i = 1; i < 4 && planes[i]; i++) + { + size_t height = (planes[i] - planes[i - 1]) / strides[i - 1]; + planes[i] = planes[i - 1] + height * new_strides[i - 1]; + } + memcpy(strides, new_strides, sizeof(new_strides)); + } + + if ((format->videoInfo.VideoFlags & MFVideoFlag_BottomUpLinearRep) && pitch <= 0) + { + planes[0] = planes[0] + strides[0] * (format->videoInfo.dwHeight - 1); + strides[0] = -strides[0]; + } + + TRACE("buffer %p / %#Ix size %d stride %ld, planes %p,%p,%p strides %d,%d,%d\n", buffer->data, buffer->size, + size, pitch, planes[0], planes[1], planes[2], strides[0], strides[1], strides[2]); + return size; +} + +static BOOL check_arrays_alignment(uint8_t *planes[4], int strides[4], int size, int align) +{ + if (size % align) + return FALSE; + for (int i = 0; i < 4; i++) + if ((UINT_PTR)planes[i] % align) + return FALSE; + for (int i = 0; i < 4; i++) + if (strides[i] % align) + return FALSE; + return TRUE; +} + +static BOOL video_frame_wrap_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer, LONG pitch) +{ + int size; + + TRACE("frame %p, info %p, buffer %p\n", frame, format, buffer); + + video_frame_init_from_format(frame, format); + video_frame_init_aperture(frame, format); + + if ((size = fill_arrays_with_format(frame->data, frame->linesize, buffer, format, pitch)) < 0) + return size; + /* swscale requires 16byte alignment for data pointers when SSE2 optimizations are used. */ + if (!check_arrays_alignment(frame->data, frame->linesize, size, 16)) + { + ERR("frame %s isn't aligned to 16 bytes\n", debugstr_avframe(frame)); + return -1; + } + + frame->opaque = (void *)-1; + frame->buf[0] = av_buffer_ref(buffer); + frame->extended_data = frame->data; + return size; +} + +static int video_frame_copy_from_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer, + LONG pitch) +{ + int size, input_strides[4]; + UINT8 *input_planes[4]; + + ERR("frame %s, format %p, buffer %p\n", debugstr_avframe(frame), format, buffer); + + size = fill_arrays_with_format(input_planes, input_strides, buffer, format, pitch); + av_image_copy(frame->data, frame->linesize, (const UINT8 **)input_planes, input_strides, + frame->format, format->videoInfo.dwWidth, format->videoInfo.dwHeight); + return size; +} + +static int video_frame_copy_to_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer, + LONG pitch) +{ + int size, output_strides[4]; + UINT8 *output_planes[4]; + + ERR("frame %s, format %p, buffer %p\n", debugstr_avframe(frame), format, buffer); + + size = fill_arrays_with_format(output_planes, output_strides, buffer, format, pitch); + av_image_copy(output_planes, output_strides, (const UINT8 **)frame->data, frame->linesize, + frame->format, format->videoInfo.dwWidth, format->videoInfo.dwHeight); + return size; +} + static const GUID *const input_types[] = { &MFVideoFormat_IYUV, @@ -82,17 +317,153 @@ struct video_processor IMFAttributes *output_attributes; IMFMediaType *input_type; + MFVIDEOFORMAT *input_format; MFT_INPUT_STREAM_INFO input_info; IMFMediaType *output_type; + MFVIDEOFORMAT *output_format; MFT_OUTPUT_STREAM_INFO output_info; - wg_transform_t wg_transform; - struct wg_sample_queue *wg_sample_queue; + SwsContext *context; + AVFrame input_frame; + AVFrame output_frame; + AVFrame current_frame; IUnknown *device_manager; IMFVideoSampleAllocatorEx *allocator; }; +static HRESULT video_processor_process_frame(struct video_processor *impl, AVFrame *input_frame, + DMO_OUTPUT_DATA_BUFFER *output) +{ + AVFrame output_frame = {0}; + AVBufferRef *buffer; + IMFSample *sample; + int size, ret; + LONG pitch; + HRESULT hr; + + if (!(buffer = buffer_from_media_buffer(output->pBuffer, 0, &pitch))) + return E_OUTOFMEMORY; + if ((size = video_frame_wrap_buffer(&output_frame, impl->output_format, buffer, pitch)) < 0) + av_frame_move_ref(&output_frame, &impl->output_frame); + + TRACE("input %s output %s\n", debugstr_avframe(input_frame), debugstr_avframe(&output_frame)); + + if ((ret = sws_scale_frame(impl->context, &output_frame, input_frame)) < 0) + ERR("error ret %d (%s)\n", -ret, av_err2str(ret)); + else if ((ret = size) < 0) + ret = video_frame_copy_to_buffer(&output_frame, impl->output_format, buffer, pitch); + + av_buffer_unref(&buffer); + + if (!output_frame.opaque) + av_frame_move_ref(&impl->output_frame, &output_frame); + else + av_frame_unref(&output_frame); + + output->dwStatus = 0; + IMediaBuffer_SetLength(output->pBuffer, ret >= 0 ? ret : 0); + if (ret < 0) + return E_FAIL; + if (!ret) + return MF_E_TRANSFORM_NEED_MORE_INPUT; + + if (input_frame->flags & AV_FRAME_FLAG_KEY) + output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT; + output->rtTimestamp = input_frame->pts; + if (output->rtTimestamp != INT64_MIN) + output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIME; + output->rtTimelength = input_frame->duration; + if (output->rtTimelength != INT64_MIN) + output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH; + + if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(output->pBuffer, &IID_IMFSample, (void **)&sample))) + { + if (output->rtTimestamp != INT64_MIN) + IMFSample_SetSampleTime(sample, output->rtTimestamp); + if (output->rtTimelength != INT64_MIN) + IMFSample_SetSampleDuration(sample, output->rtTimelength); + if (output->dwStatus & DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT) + IMFSample_SetUINT32(sample, &MFSampleExtension_CleanPoint, 1); + IMFSample_Release(sample); + } + + TRACE("returning output size %#x, pts %s, duration %s status %#lx\n", ret, + debugstr_avtime(output->rtTimestamp, USER_TIME_BASE_Q), + debugstr_avtime(output->rtTimelength, USER_TIME_BASE_Q), output->dwStatus); + return S_OK; +} + +static HRESULT video_processor_process_input(struct video_processor *impl, const DMO_OUTPUT_DATA_BUFFER *input) +{ + LONGLONG pts = input->rtTimestamp, duration = input->rtTimelength; + AVBufferRef *buffer; + IMFSample *sample; + HRESULT hr; + LONG pitch; + int ret; + + if (!impl->context) + return MF_E_TRANSFORM_TYPE_NOT_SET; + if (impl->current_frame.width) + return MF_E_NOTACCEPTING; + + if (!(buffer = buffer_from_media_buffer(input->pBuffer, AV_BUFFER_FLAG_READONLY, &pitch))) + return E_OUTOFMEMORY; + if ((ret = video_frame_wrap_buffer(&impl->current_frame, impl->input_format, buffer, pitch)) < 0) + { + ret = video_frame_copy_from_buffer(&impl->input_frame, impl->input_format, buffer, pitch); + av_frame_move_ref(&impl->current_frame, &impl->input_frame); + } + av_buffer_unref(&buffer); + + if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(input->pBuffer, &IID_IMFSample, (void **)&sample))) + { + if (FAILED(IMFSample_GetSampleTime(sample, &pts))) + pts = INT64_MIN; + if (FAILED(IMFSample_GetSampleDuration(sample, &duration))) + duration = INT64_MIN; + IMFSample_Release(sample); + } + + impl->current_frame.pts = pts; + impl->current_frame.duration = duration; + TRACE("input frame %s, time %s, duration %s\n", debugstr_avframe(&impl->current_frame), + debugstr_avtime(impl->current_frame.pts, USER_TIME_BASE_Q), + debugstr_avtime(impl->current_frame.duration, USER_TIME_BASE_Q)); + return S_OK; +} + +static HRESULT video_processor_process_output(struct video_processor *impl, DMO_OUTPUT_DATA_BUFFER *output) +{ + HRESULT hr; + + if (!impl->context) + return MF_E_TRANSFORM_TYPE_NOT_SET; + if (!impl->current_frame.width) + return MF_E_TRANSFORM_NEED_MORE_INPUT; + + hr = video_processor_process_frame(impl, &impl->current_frame, output); + if (!impl->current_frame.opaque) + av_frame_move_ref(&impl->input_frame, &impl->current_frame); + else + av_frame_unref(&impl->current_frame); + + return hr; +} + +static void video_processor_cleanup(struct video_processor *impl) +{ + CoTaskMemFree(impl->output_format); + impl->output_format = NULL; + CoTaskMemFree(impl->input_format); + impl->input_format = NULL; + av_frame_unref(&impl->current_frame); + av_frame_unref(&impl->output_frame); + av_frame_unref(&impl->input_frame); + sws_free_context(&impl->context); +} + static void update_video_aperture(MFVideoInfo *input_info, MFVideoInfo *output_info) { RECT input_rect, output_rect; @@ -113,65 +484,68 @@ static void update_video_aperture(MFVideoInfo *input_info, MFVideoInfo *output_i output_info->MinimumDisplayAperture = input_info->MinimumDisplayAperture; } -static HRESULT normalize_media_types(BOOL bottom_up, IMFMediaType **input_type, IMFMediaType **output_type) +static HRESULT create_video_format(BOOL bottom_up, IMFMediaType *media_type, MFVIDEOFORMAT **format) { - MFVIDEOFORMAT *input_format, *output_format; - BOOL normalize_input, normalize_output; + LONG stride; UINT32 size; HRESULT hr; - normalize_input = FAILED(IMFMediaType_GetItem(*input_type, &MF_MT_DEFAULT_STRIDE, NULL)); - normalize_output = FAILED(IMFMediaType_GetItem(*output_type, &MF_MT_DEFAULT_STRIDE, NULL)); - - if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(*input_type, &input_format, &size))) + if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(media_type, format, &size))) return hr; - if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(*output_type, &output_format, &size))) - { - CoTaskMemFree(input_format); - return hr; - } - - if (bottom_up && normalize_input) - input_format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep; - if (bottom_up && normalize_output) - output_format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep; - - update_video_aperture(&input_format->videoInfo, &output_format->videoInfo); - - if (FAILED(hr = MFCreateVideoMediaType(input_format, (IMFVideoMediaType **)input_type))) - goto done; - if (FAILED(hr = MFCreateVideoMediaType(output_format, (IMFVideoMediaType **)output_type))) - { - IMFMediaType_Release(*input_type); - *input_type = NULL; - } - -done: - CoTaskMemFree(input_format); - CoTaskMemFree(output_format); + if (bottom_up && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL)) + && SUCCEEDED(MFGetStrideForBitmapInfoHeader((*format)->guidFormat.Data1, 1, &stride)) && stride < 0) + (*format)->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep; return hr; } -static HRESULT try_create_wg_transform(struct video_processor *impl) +static HRESULT video_processor_init(struct video_processor *impl) { BOOL bottom_up = !impl->device_manager; /* when not D3D-enabled, the transform outputs bottom up RGB buffers */ - IMFMediaType *input_type = impl->input_type, *output_type = impl->output_type; - struct wg_transform_attrs attrs = {0}; HRESULT hr; + int ret; - if (impl->wg_transform) + video_processor_cleanup(impl); + + if (!(impl->context = sws_alloc_context())) + return E_OUTOFMEMORY; + if (FAILED(hr = create_video_format(bottom_up, impl->input_type, &impl->input_format)) + || FAILED(hr = create_video_format(bottom_up, impl->output_type, &impl->output_format))) { - wg_transform_destroy(impl->wg_transform); - impl->wg_transform = 0; + video_processor_cleanup(impl); + return hr; } - if (FAILED(hr = normalize_media_types(bottom_up, &input_type, &output_type))) - return hr; - hr = wg_transform_create_mf(input_type, output_type, &attrs, &impl->wg_transform); - IMFMediaType_Release(output_type); - IMFMediaType_Release(input_type); + update_video_aperture(&impl->input_format->videoInfo, &impl->output_format->videoInfo); - return hr; + video_frame_init_from_format(&impl->input_frame, impl->input_format); + if ((ret = av_frame_get_buffer(&impl->input_frame, 0)) < 0) + goto failed; + video_frame_init_aperture(&impl->input_frame, impl->input_format); + + video_frame_init_from_format(&impl->output_frame, impl->output_format); + if ((ret = av_frame_get_buffer(&impl->output_frame, 0)) < 0) + goto failed; + video_frame_init_aperture(&impl->output_frame, impl->input_format); + + av_opt_set(impl->context, "sws_flags", "neighbor", 0); + av_opt_set_int(impl->context, "threads", 0, 0); + av_opt_set_int(impl->context, "srcw", impl->input_frame.width, 0); + av_opt_set_int(impl->context, "srch", impl->input_frame.height, 0); + av_opt_set_pixel_fmt(impl->context, "src_format", impl->input_frame.format, 0); + av_opt_set_int(impl->context, "dstw", impl->output_frame.width, 0); + av_opt_set_int(impl->context, "dsth", impl->output_frame.height, 0); + av_opt_set_pixel_fmt(impl->context, "dst_format", impl->output_frame.format, 0); + + if ((ret = sws_init_context(impl->context, NULL, NULL)) < 0) + goto failed; + + TRACE("input %s -> output %s\n", debugstr_avframe(&impl->input_frame), debugstr_avframe(&impl->output_frame)); + return S_OK; + +failed: + ERR("ret %d\n", ret); + video_processor_cleanup(impl); + return E_FAIL; } static HRESULT video_processor_init_allocator(struct video_processor *processor) @@ -260,8 +634,6 @@ static ULONG WINAPI video_processor_Release(IMFTransform *iface) video_processor_uninit_allocator(impl); if (impl->device_manager) IUnknown_Release(impl->device_manager); - if (impl->wg_transform) - wg_transform_destroy(impl->wg_transform); if (impl->input_type) IMFMediaType_Release(impl->input_type); if (impl->output_type) @@ -270,8 +642,7 @@ static ULONG WINAPI video_processor_Release(IMFTransform *iface) IMFAttributes_Release(impl->attributes); if (impl->output_attributes) IMFAttributes_Release(impl->output_attributes); - - wg_sample_queue_destroy(impl->wg_sample_queue); + video_processor_cleanup(impl); free(impl); } @@ -461,12 +832,7 @@ static HRESULT WINAPI video_processor_SetInputType(IMFTransform *iface, DWORD id IMFMediaType_Release(impl->input_type); impl->input_type = NULL; } - if (impl->wg_transform) - { - wg_transform_destroy(impl->wg_transform); - impl->wg_transform = 0; - } - + video_processor_cleanup(impl); return S_OK; } @@ -490,7 +856,7 @@ static HRESULT WINAPI video_processor_SetInputType(IMFTransform *iface, DWORD id IMFMediaType_Release(impl->input_type); IMFMediaType_AddRef((impl->input_type = type)); - if (impl->output_type && FAILED(hr = try_create_wg_transform(impl))) + if (impl->output_type && FAILED(hr = video_processor_init(impl))) { IMFMediaType_Release(impl->input_type); impl->input_type = NULL; @@ -499,7 +865,6 @@ static HRESULT WINAPI video_processor_SetInputType(IMFTransform *iface, DWORD id if (FAILED(hr) || FAILED(MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size, (UINT32 *)&impl->input_info.cbSize))) impl->input_info.cbSize = 0; - return hr; } @@ -520,12 +885,7 @@ static HRESULT WINAPI video_processor_SetOutputType(IMFTransform *iface, DWORD i IMFMediaType_Release(impl->output_type); impl->output_type = NULL; } - if (impl->wg_transform) - { - wg_transform_destroy(impl->wg_transform); - impl->wg_transform = 0; - } - + video_processor_cleanup(impl); return S_OK; } @@ -552,7 +912,7 @@ static HRESULT WINAPI video_processor_SetOutputType(IMFTransform *iface, DWORD i IMFMediaType_Release(impl->output_type); IMFMediaType_AddRef((impl->output_type = type)); - if (impl->input_type && FAILED(hr = try_create_wg_transform(impl))) + if (impl->input_type && FAILED(hr = video_processor_init(impl))) { IMFMediaType_Release(impl->output_type); impl->output_type = NULL; @@ -561,7 +921,6 @@ static HRESULT WINAPI video_processor_SetOutputType(IMFTransform *iface, DWORD i if (FAILED(hr) || FAILED(MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size, (UINT32 *)&impl->output_info.cbSize))) impl->output_info.cbSize = 0; - return hr; } @@ -681,32 +1040,45 @@ static HRESULT WINAPI video_processor_ProcessMessage(IMFTransform *iface, MFT_ME static HRESULT WINAPI video_processor_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { struct video_processor *impl = impl_from_IMFTransform(iface); + DMO_OUTPUT_DATA_BUFFER input = {.dwStatus = flags}; + IMFMediaBuffer *buffer; + HRESULT hr; TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); - if (!impl->wg_transform) - return MF_E_TRANSFORM_TYPE_NOT_SET; + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer))) + return hr; + if (SUCCEEDED(hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(sample, buffer, 0, &input.pBuffer))) + { + hr = video_processor_process_input(impl, &input); + IMediaBuffer_Release(input.pBuffer); + } + IMFMediaBuffer_Release(buffer); - return wg_transform_push_mf(impl->wg_transform, sample, impl->wg_sample_queue); + return hr; } static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) + MFT_OUTPUT_DATA_BUFFER *output, DWORD *output_status) { struct video_processor *impl = impl_from_IMFTransform(iface); + DMO_OUTPUT_DATA_BUFFER dmo_output = {0}; + BOOL playback_mode, provide_samples; IMFSample *output_sample; + IMFMediaBuffer *buffer; HRESULT hr; - BOOL playback_mode, provide_samples; - TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + TRACE("iface %p, flags %#lx, count %lu, output %p, output_status %p.\n", iface, flags, count, + output, output_status); if (count != 1) return E_INVALIDARG; - - if (!impl->wg_transform) + if (!impl->input_format || !impl->output_format) return MF_E_TRANSFORM_TYPE_NOT_SET; + if (!impl->current_frame.width) + return MF_E_TRANSFORM_NEED_MORE_INPUT; - samples->dwStatus = 0; + output->dwStatus = 0; if (FAILED(IMFAttributes_GetUINT32(impl->attributes, &MF_XVP_PLAYBACK_MODE, (UINT32 *) &playback_mode))) playback_mode = FALSE; @@ -722,18 +1094,26 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f } else { - if (!(output_sample = samples->pSample)) + if (!(output_sample = output->pSample)) return E_INVALIDARG; IMFSample_AddRef(output_sample); } - if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, impl->output_info.cbSize, &samples->dwStatus, NULL))) + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(output_sample, &buffer))) goto done; - wg_sample_queue_flush(impl->wg_sample_queue, false); + if (SUCCEEDED(hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(output_sample, buffer, 0, + &dmo_output.pBuffer))) + { + hr = video_processor_process_output(impl, &dmo_output); + IMediaBuffer_Release(dmo_output.pBuffer); + } + IMFMediaBuffer_Release(buffer); + + output->dwStatus = *output_status = 0; if (provide_samples) { - samples->pSample = output_sample; + output->pSample = output_sample; IMFSample_AddRef(output_sample); } @@ -772,6 +1152,12 @@ static const IMFTransformVtbl video_processor_vtbl = video_processor_ProcessOutput, }; +static const char *debugstr_version(UINT version) +{ + return wine_dbg_sprintf("%u.%u.%u", AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version), + AV_VERSION_MICRO(version)); +} + HRESULT video_processor_create(REFIID riid, void **ret) { const MFVIDEOFORMAT input_format = @@ -791,6 +1177,9 @@ HRESULT video_processor_create(REFIID riid, void **ret) TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); + TRACE("avutil version %s\n", debugstr_version(avutil_version())); + TRACE("swscale version %s\n", debugstr_version(swscale_version())); + if (FAILED(hr = check_video_transform_support(&input_format, &output_format))) { ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n"); @@ -809,8 +1198,6 @@ HRESULT video_processor_create(REFIID riid, void **ret) goto failed; if (FAILED(hr = MFCreateAttributes(&impl->output_attributes, 0))) goto failed; - if (FAILED(hr = wg_sample_queue_create(&impl->wg_sample_queue))) - goto failed; impl->IMFTransform_iface.lpVtbl = &video_processor_vtbl; impl->refcount = 1; @@ -824,6 +1211,7 @@ failed: IMFAttributes_Release(impl->output_attributes); if (impl->attributes) IMFAttributes_Release(impl->attributes); + sws_free_context(&impl->context); free(impl); return hr; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11194
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/msvproc/Makefile.in | 6 +- dlls/msvproc/msvproc.c | 36 +------ .../video_processor.c | 100 +++++++++++++----- dlls/winegstreamer/Makefile.in | 4 +- dlls/winegstreamer/gst_private.h | 2 - dlls/winegstreamer/mfplat.c | 2 - dlls/winegstreamer/winegstreamer_classes.idl | 6 -- 7 files changed, 79 insertions(+), 77 deletions(-) rename dlls/{winegstreamer => msvproc}/video_processor.c (94%) diff --git a/dlls/msvproc/Makefile.in b/dlls/msvproc/Makefile.in index f98b4d6d44b..cf19d1dfd17 100644 --- a/dlls/msvproc/Makefile.in +++ b/dlls/msvproc/Makefile.in @@ -1,6 +1,8 @@ MODULE = msvproc.dll -IMPORTS = combase mfplat mfuuid dmoguids dxguid strmiids wmcodecdspuuid uuid +IMPORTS = $(FFMPEG_PE_LIBS) bcrypt combase mfplat mfuuid dmoguids dxguid strmiids wmcodecdspuuid uuid +EXTRAINCL = $(FFMPEG_PE_CFLAGS) SOURCES = \ msvproc.c \ - msvproc.idl + msvproc.idl \ + video_processor.c diff --git a/dlls/msvproc/msvproc.c b/dlls/msvproc/msvproc.c index fdf6a1cddb1..17c3b8def93 100644 --- a/dlls/msvproc/msvproc.c +++ b/dlls/msvproc/msvproc.c @@ -37,41 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmo); DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8); DEFINE_MEDIATYPE_GUID(MFVideoFormat_P208,MAKEFOURCC('P','2','0','8')); -static HRESULT WINAPI video_processor_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, - REFIID riid, void **out) -{ - static const GUID CLSID_wg_video_processor = {0xd527607f,0x89cb,0x4e94,{0x95,0x71,0xbc,0xfe,0x62,0x17,0x56,0x13}}; - return CoCreateInstance(&CLSID_wg_video_processor, outer, CLSCTX_INPROC_SERVER, riid, out); -} - -static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out) -{ - *out = IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown) ? iface : NULL; - return *out ? S_OK : E_NOINTERFACE; -} -static ULONG WINAPI class_factory_AddRef(IClassFactory *iface) -{ - return 2; -} -static ULONG WINAPI class_factory_Release(IClassFactory *iface) -{ - return 1; -} -static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock) -{ - return S_OK; -} - -static const IClassFactoryVtbl video_processor_factory_vtbl = -{ - class_factory_QueryInterface, - class_factory_AddRef, - class_factory_Release, - video_processor_factory_CreateInstance, - class_factory_LockServer, -}; - -static IClassFactory video_processor_factory = {&video_processor_factory_vtbl}; +extern IClassFactory video_processor_factory; /*********************************************************************** * DllGetClassObject (msvproc.@) diff --git a/dlls/winegstreamer/video_processor.c b/dlls/msvproc/video_processor.c similarity index 94% rename from dlls/winegstreamer/video_processor.c rename to dlls/msvproc/video_processor.c index 9208106e10e..f2ad3e0fe78 100644 --- a/dlls/winegstreamer/video_processor.c +++ b/dlls/msvproc/video_processor.c @@ -15,15 +15,21 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "gst_private.h" +#include <stddef.h> +#include <stdarg.h> + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" #include "d3d9types.h" -#include "mediaerr.h" +#include "dshow.h" +#include "dvdmedia.h" #include "mfapi.h" +#include "mfidl.h" #include "mferror.h" #include "mfobjects.h" #include "mftransform.h" -#include "wmcodecdsp.h" #include <libavutil/avutil.h> #include <libavutil/imgutils.h> @@ -33,9 +39,9 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(dmo); -WINE_DECLARE_DEBUG_CHANNEL(winediag); -extern GUID MFVideoFormat_ABGR32; +DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_P208,MAKEFOURCC('P','2','0','8')); static const GUID MF_XVP_PLAYBACK_MODE = { 0x3c5d293f, 0xad67, 0x4e29, { 0xaf, 0x12, 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9 } }; @@ -464,6 +470,29 @@ static void video_processor_cleanup(struct video_processor *impl) sws_free_context(&impl->context); } +static BOOL is_mf_video_area_empty(const MFVideoArea *area) +{ + return !area->OffsetX.value && !area->OffsetY.value && !area->Area.cx && !area->Area.cy; +} + +static void get_mf_video_content_rect(const MFVideoInfo *info, RECT *rect) +{ + if (!is_mf_video_area_empty(&info->MinimumDisplayAperture)) + { + rect->left = info->MinimumDisplayAperture.OffsetX.value; + rect->top = info->MinimumDisplayAperture.OffsetY.value; + rect->right = rect->left + info->MinimumDisplayAperture.Area.cx; + rect->bottom = rect->top + info->MinimumDisplayAperture.Area.cy; + } + else + { + rect->left = 0; + rect->top = 0; + rect->right = info->dwWidth; + rect->bottom = info->dwHeight; + } +} + static void update_video_aperture(MFVideoInfo *input_info, MFVideoInfo *output_info) { RECT input_rect, output_rect; @@ -1158,34 +1187,22 @@ static const char *debugstr_version(UINT version) AV_VERSION_MICRO(version)); } -HRESULT video_processor_create(REFIID riid, void **ret) +static HRESULT WINAPI video_processor_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, + REFIID riid, void **out) { - const MFVIDEOFORMAT input_format = - { - .dwSize = sizeof(MFVIDEOFORMAT), - .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, - .guidFormat = MFVideoFormat_I420, - }; - const MFVIDEOFORMAT output_format = - { - .dwSize = sizeof(MFVIDEOFORMAT), - .videoInfo = {.dwWidth = 1920, .dwHeight = 1080}, - .guidFormat = MFVideoFormat_NV12, - }; struct video_processor *impl; HRESULT hr; - TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); + TRACE("outer %p, riid %s, out %p.\n", outer, debugstr_guid(riid), out); + + *out = NULL; + + if (outer) + return CLASS_E_NOAGGREGATION; TRACE("avutil version %s\n", debugstr_version(avutil_version())); TRACE("swscale version %s\n", debugstr_version(swscale_version())); - if (FAILED(hr = check_video_transform_support(&input_format, &output_format))) - { - ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n"); - return hr; - } - if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY; @@ -1201,9 +1218,9 @@ HRESULT video_processor_create(REFIID riid, void **ret) impl->IMFTransform_iface.lpVtbl = &video_processor_vtbl; impl->refcount = 1; + TRACE("Created video processor %p\n", impl); - *ret = &impl->IMFTransform_iface; - TRACE("Created %p\n", *ret); + *out = &impl->IMFTransform_iface; return S_OK; failed: @@ -1215,3 +1232,32 @@ failed: free(impl); return hr; } + +static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out) +{ + *out = IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown) ? iface : NULL; + return *out ? S_OK : E_NOINTERFACE; +} +static ULONG WINAPI class_factory_AddRef(IClassFactory *iface) +{ + return 2; +} +static ULONG WINAPI class_factory_Release(IClassFactory *iface) +{ + return 1; +} +static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock) +{ + return S_OK; +} + +static const IClassFactoryVtbl video_processor_factory_vtbl = +{ + class_factory_QueryInterface, + class_factory_AddRef, + class_factory_Release, + video_processor_factory_CreateInstance, + class_factory_LockServer, +}; + +IClassFactory video_processor_factory = {&video_processor_factory_vtbl}; diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 1df91596e30..12907f90b2f 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -1,8 +1,7 @@ MODULE = winegstreamer.dll UNIXLIB = winegstreamer.so IMPORTLIB = winegstreamer -IMPORTS = $(FFMPEG_PE_LIBS) bcrypt strmbase ole32 oleaut32 msdmo user32 -EXTRAINCL = $(FFMPEG_PE_CFLAGS) +IMPORTS = strmbase ole32 oleaut32 msdmo user32 DELAYIMPORTS = mfplat mf UNIX_CFLAGS = $(GSTREAMER_CFLAGS) UNIX_LIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) @@ -22,7 +21,6 @@ SOURCES = \ unixlib.c \ video_decoder.c \ video_encoder.c \ - video_processor.c \ wg_allocator.c \ wg_format.c \ wg_media_type.c \ diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 0301db6e627..7a5c2f3f4b0 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -181,8 +181,6 @@ bool wg_video_format_is_rgb(enum wg_video_format format); 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; diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index 4088a935625..65a1079155e 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -121,7 +121,6 @@ static const IClassFactoryVtbl class_factory_vtbl = }; static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}}; -static const GUID CLSID_wg_video_processor = {0xd527607f,0x89cb,0x4e94,{0x95,0x71,0xbc,0xfe,0x62,0x17,0x56,0x13}}; static const GUID CLSID_wg_aac_decoder = {0xe7889a8a,0x2083,0x4844,{0x83,0x70,0x5e,0xe3,0x49,0xb1,0x45,0x03}}; static const GUID CLSID_wg_h264_decoder = {0x1f1e273d,0x12c0,0x4b3a,{0x8e,0x9b,0x19,0x33,0xc2,0x49,0x8a,0xea}}; static const GUID CLSID_wg_h264_encoder = {0x6c34de69,0x4670,0x46cd,{0x8c,0xb4,0x1f,0x2f,0xa1,0xdf,0xfb,0x65}}; @@ -133,7 +132,6 @@ static const struct class_object } class_objects[] = { - { &CLSID_wg_video_processor, &video_processor_create }, { &CLSID_GStreamerByteStreamHandler, &gstreamer_byte_stream_handler_create }, { &CLSID_wg_aac_decoder, &aac_decoder_create }, { &CLSID_wg_h264_decoder, &h264_decoder_create }, diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index 8afa08df5f7..fd46ba3e687 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -64,12 +64,6 @@ coclass wg_wave_parser {} ] coclass decodebin_parser {} -[ - threading(both), - uuid(d527607f-89cb-4e94-9571-bcfe62175613) -] -coclass wg_video_processor {} - [ helpstring("Generic Decodebin Byte Stream Handler"), threading(both), -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11194
Are those unrelated test failures? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11194#note_143591
I fails in mf:mf and on Windows, I haven't touched the mf:mf tests so I don't think it's related. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11194#note_143594
On Fri Jun 19 10:17:02 2026 +0000, Rémi Bernon wrote:
It fails in mf:mf and on Windows, I haven't touched the mf:mf tests so I don't think it's related. Ok, I was only tagged because of test, and I'm unfamiliar with functional part of this.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/11194#note_143605
participants (3)
-
Nikolay Sivov (@nsivov) -
Rémi Bernon -
Rémi Bernon (@rbernon)