[PATCH v2 0/12] MR11679: quartz: Implement color converter.
This MR implements the DirectShow Color Space Converter filter. -- v2: quartz: Implement the ReceiveCanBlock function. quartz: Handle dynamic format change. quartz: Implement the Receive function. quartz: Create and configure the DMO color converter. quartz: Make sure cbBuffer is large enough to fit image. quartz: Implement QueryAccept for source. quartz: Implement media type enum for source. quartz: Implement QueryAccept on sink. quartz: Add the IMemInputPin sink interface. quartz: Add the IMediaSeeking source interface. quartz: Add the source and sink pins. https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/Makefile.in | 1 + dlls/quartz/colorconv.c | 83 +++++++++++++++++++++++++++++++++++ dlls/quartz/main.c | 44 +++++++++++++++++++ dlls/quartz/quartz_private.h | 1 + dlls/quartz/quartz_strmif.idl | 7 +++ dlls/quartz/tests/colorconv.c | 32 +------------- 6 files changed, 137 insertions(+), 31 deletions(-) create mode 100644 dlls/quartz/colorconv.c diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index a61bbc2b5fa..1e38b24ef73 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -9,6 +9,7 @@ VER_OLESELFREGISTER = 1 SOURCES = \ acmwrapper.c \ avidec.c \ + colorconv.c \ control_tlb.idl \ decoder.c \ dsoundrender.c \ diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c new file mode 100644 index 00000000000..934462a345d --- /dev/null +++ b/dlls/quartz/colorconv.c @@ -0,0 +1,83 @@ +/* + * Color converter + * + * Copyright 2026 Brendan McGrath + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "quartz_private.h" + +#include "vfw.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(quartz); + +struct color_converter +{ + struct strmbase_filter filter; +}; + +static struct color_converter *impl_from_strmbase_filter(struct strmbase_filter *iface) +{ + return CONTAINING_RECORD(iface, struct color_converter, filter); +} + +static struct strmbase_pin *color_get_pin(struct strmbase_filter *iface, unsigned int index) +{ + return NULL; +} + +static void color_destroy(struct strmbase_filter *iface) +{ + struct color_converter *filter = impl_from_strmbase_filter(iface); + + strmbase_filter_cleanup(&filter->filter); + free(filter); +} + +static HRESULT color_init_stream(struct strmbase_filter *iface) +{ + return S_OK; +} + +static HRESULT color_cleanup_stream(struct strmbase_filter *iface) +{ + return S_OK; +} + +static const struct strmbase_filter_ops filter_ops = +{ + .filter_get_pin = color_get_pin, + .filter_destroy = color_destroy, + .filter_init_stream = color_init_stream, + .filter_cleanup_stream = color_cleanup_stream, +}; + +HRESULT color_create(IUnknown *outer, IUnknown **out) +{ + struct color_converter *object; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + strmbase_filter_init(&object->filter, outer, &CLSID_Colour, &filter_ops); + + TRACE("Created Color Converter %p.\n", object); + *out = &object->filter.IUnknown_inner; + + return S_OK; +} diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c index d8da7bde5fa..d38ace1eb20 100644 --- a/dlls/quartz/main.c +++ b/dlls/quartz/main.c @@ -93,6 +93,7 @@ static const struct object_creation_info object_creation[] = { &CLSID_AudioRender, dsound_render_create }, { &CLSID_AVIDec, avi_dec_create }, { &CLSID_AviSplitter, avi_splitter_create }, + { &CLSID_Colour, color_create }, { &CLSID_CMpegAudioCodec, mpeg_audio_codec_create }, { &CLSID_CMpegVideoCodec, mpeg_video_codec_create }, { &CLSID_DSoundRender, dsound_render_create }, @@ -353,6 +354,44 @@ HRESULT WINAPI DllRegisterServer(void) .rgPins2 = acm_wrapper_pins, }; + static const REGPINTYPES color_inputs[] = + { + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB8}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB555}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB565}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB24}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB32}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_ARGB32}, + }; + static const REGPINTYPES color_outputs[] = + { + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB8}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB555}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB565}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB24}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_RGB32}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_ARGB32}, + }; + static const REGFILTERPINS2 color_pins[] = + { + { + .nMediaTypes = ARRAY_SIZE(color_inputs), + .lpMediaType = color_inputs, + }, + { + .nMediaTypes = ARRAY_SIZE(color_outputs), + .lpMediaType = color_outputs, + .dwFlags = REG_PINFLAG_B_OUTPUT, + }, + }; + static const REGFILTER2 color_reg = + { + .dwVersion = 2, + .dwMerit = MERIT_UNLIKELY + 1, + .cPins2 = ARRAY_SIZE(color_pins), + .rgPins2 = color_pins, + }; + static const REGPINTYPES mpeg_splitter_inputs[] = { {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1Audio}, @@ -542,6 +581,9 @@ HRESULT WINAPI DllRegisterServer(void) if (FAILED(hr = IFilterMapper2_RegisterFilter(mapper, &CLSID_ACMWrapper, L"ACM Wrapper", NULL, &CLSID_LegacyAmFilterCategory, NULL, &acm_wrapper_reg))) goto done; + if (FAILED(hr = IFilterMapper2_RegisterFilter(mapper, &CLSID_Colour, L"Color Space Converter", NULL, + &CLSID_LegacyAmFilterCategory, NULL, &color_reg))) + goto done; if (FAILED(hr = IFilterMapper2_RegisterFilter(mapper, &CLSID_AviSplitter, L"AVI Splitter", NULL, NULL, NULL, &avi_splitter_reg))) goto done; @@ -589,6 +631,8 @@ HRESULT WINAPI DllUnregisterServer(void) goto done; if (FAILED(hr = IFilterMapper2_UnregisterFilter(mapper, &CLSID_LegacyAmFilterCategory, NULL, &CLSID_ACMWrapper))) goto done; + if (FAILED(hr = IFilterMapper2_UnregisterFilter(mapper, &CLSID_LegacyAmFilterCategory, NULL, &CLSID_Colour))) + goto done; if (FAILED(hr = IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &CLSID_AviSplitter))) goto done; if (FAILED(hr = IFilterMapper2_UnregisterFilter(mapper, NULL, NULL, &CLSID_MPEG1Splitter))) diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h index e683dc51cdc..7c8e296d43c 100644 --- a/dlls/quartz/quartz_private.h +++ b/dlls/quartz/quartz_private.h @@ -54,6 +54,7 @@ HRESULT acm_wrapper_create(IUnknown *outer, IUnknown **out); HRESULT async_reader_create(IUnknown *outer, IUnknown **out); HRESULT avi_dec_create(IUnknown *outer, IUnknown **out); HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out); +HRESULT color_create(IUnknown *outer, IUnknown **out); HRESULT dsound_render_create(IUnknown *outer, IUnknown **out); HRESULT filter_graph_create(IUnknown *outer, IUnknown **out); HRESULT filter_graph_no_thread_create(IUnknown *outer, IUnknown **out); diff --git a/dlls/quartz/quartz_strmif.idl b/dlls/quartz/quartz_strmif.idl index ad63352ff07..e9469e1be80 100644 --- a/dlls/quartz/quartz_strmif.idl +++ b/dlls/quartz/quartz_strmif.idl @@ -91,6 +91,13 @@ coclass AsyncReader { interface IBaseFilter; } ] coclass AVIDec { interface IBaseFilter; } +[ + helpstring("Color Space Converter"), + threading(both), + uuid(1643e180-90f5-11ce-97d5-00aa0055595a) +] +coclass Colour { interface IBaseFilter; } + [ helpstring("DirectSound Audio Renderer"), threading(both), diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index cb8a2ee4fac..f1ceba3f61c 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -806,12 +806,7 @@ static void test_registration(void) int i, j; hr = create_color_conv_property_bag(&property_bag); - - if (hr != S_OK) - { - skip("Skipping registration tests.\n"); - return; - } + ok(hr == S_OK, "Got hr %#lx.\n", hr); VariantInit(&var); hr = IPropertyBag_Read(property_bag, L"FilterData", &var, NULL); @@ -885,12 +880,8 @@ static void test_interfaces(void) IPin *pin; hr = create_color_conv(&filter); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - return; - check_interface(filter, &IID_IBaseFilter, TRUE); check_interface(filter, &IID_IMediaFilter, TRUE); check_interface(filter, &IID_IPersist, TRUE); @@ -1052,10 +1043,7 @@ static void test_enum_pins(void) HRESULT hr; hr = create_color_conv(&filter); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - return; refcount = get_refcount(filter); ok(refcount == 1, "Got refcount %ld.\n", refcount); @@ -1181,10 +1169,7 @@ static void test_find_pin(void) HRESULT hr; hr = create_color_conv(&filter); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - return; hr = IBaseFilter_EnumPins(filter, &enum_pins); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1227,10 +1212,7 @@ static void test_pin_info(void) IPin *pin; hr = create_color_conv(&filter); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - return; hr = IBaseFilter_FindPin(filter, L"In", &pin); todo_wine @@ -1316,10 +1298,7 @@ static void test_media_types(void) int i; hr = create_color_conv(&filter); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - return; hr = create_filter_graph(&graph); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1486,10 +1465,7 @@ static void test_enum_media_types(void) IPin *pin; hr = create_color_conv(&filter); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - return; hr = IBaseFilter_FindPin(filter, L"In", &pin); todo_wine @@ -1570,10 +1546,7 @@ static void test_unconnected_filter_state(void) ULONG ref; hr = create_color_conv(&filter); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - return; hr = IBaseFilter_GetState(filter, 0, &state); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2311,10 +2284,7 @@ static void test_connect_pin(void) HRESULT hr; hr = create_color_conv(&filter); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - return; hr = create_filter_graph(&graph); ok(hr == S_OK, "Got hr %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/colorconv.c | 83 +++++++++++++++++++++++++++++++++++ dlls/quartz/tests/colorconv.c | 74 ++++++++++--------------------- 2 files changed, 105 insertions(+), 52 deletions(-) diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index 934462a345d..31554e18fd4 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -29,6 +29,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz); struct color_converter { struct strmbase_filter filter; + + struct strmbase_source source; + + struct strmbase_sink sink; }; static struct color_converter *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -36,8 +40,46 @@ static struct color_converter *impl_from_strmbase_filter(struct strmbase_filter return CONTAINING_RECORD(iface, struct color_converter, filter); } +static HRESULT color_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) +{ + FIXME("stub\n"); + return S_FALSE; +} + +static const struct strmbase_sink_ops sink_ops = +{ + .base.pin_query_accept = color_sink_query_accept, +}; + +static HRESULT WINAPI color_source_DecideBufferSize( + struct strmbase_source *iface, IMemAllocator *alloc, ALLOCATOR_PROPERTIES *props) +{ + ALLOCATOR_PROPERTIES actual; + + if (!props->cbAlign) + props->cbAlign = 1; + + if (!props->cBuffers) + props->cBuffers = 1; + + return IMemAllocator_SetProperties(alloc, props, &actual); +} + +static const struct strmbase_source_ops source_ops = +{ + .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, + .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, + .pfnDecideBufferSize = color_source_DecideBufferSize, +}; + static struct strmbase_pin *color_get_pin(struct strmbase_filter *iface, unsigned int index) { + struct color_converter *filter = impl_from_strmbase_filter(iface); + + if (index == 0) + return &filter->sink.pin; + else if (index == 1) + return &filter->source.pin; return NULL; } @@ -45,17 +87,44 @@ static void color_destroy(struct strmbase_filter *iface) { struct color_converter *filter = impl_from_strmbase_filter(iface); + if (filter->sink.pin.peer) + IPin_Disconnect(filter->sink.pin.peer); + IPin_Disconnect(&filter->sink.pin.IPin_iface); + + if (filter->source.pin.peer) + IPin_Disconnect(filter->source.pin.peer); + IPin_Disconnect(&filter->source.pin.IPin_iface); + + strmbase_sink_cleanup(&filter->sink); + strmbase_source_cleanup(&filter->source); strmbase_filter_cleanup(&filter->filter); + free(filter); } static HRESULT color_init_stream(struct strmbase_filter *iface) { + struct color_converter *filter = impl_from_strmbase_filter(iface); + HRESULT hr; + + if (!filter->source.pin.peer) + return S_OK; + + if (FAILED(hr = IMemAllocator_Commit(filter->source.pAllocator))) + ERR("Failed to commit allocator, hr %#lx.\n", hr); + return S_OK; } static HRESULT color_cleanup_stream(struct strmbase_filter *iface) { + struct color_converter *filter = impl_from_strmbase_filter(iface); + + if (!filter->source.pin.peer) + return S_OK; + + IMemAllocator_Decommit(filter->source.pAllocator); + return S_OK; } @@ -70,12 +139,26 @@ static const struct strmbase_filter_ops filter_ops = HRESULT color_create(IUnknown *outer, IUnknown **out) { struct color_converter *object; + IMemAllocator *allocator; + HRESULT hr; + + if (FAILED(hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (void **)&allocator))) + return hr; if (!(object = calloc(1, sizeof(*object)))) + { + IMemAllocator_Release(allocator); return E_OUTOFMEMORY; + } strmbase_filter_init(&object->filter, outer, &CLSID_Colour, &filter_ops); + strmbase_sink_init(&object->sink, &object->filter, L"In", &sink_ops, allocator); + wcscpy(object->sink.pin.name, L"Input"); + + strmbase_source_init(&object->source, &object->filter, L"Out", &source_ops); + wcscpy(object->source.pin.name, L"XForm Out"); + TRACE("Created Color Converter %p.\n", object); *out = &object->filter.IUnknown_inner; diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index f1ceba3f61c..10559eb89ce 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -900,43 +900,35 @@ static void test_interfaces(void) check_interface(filter, &IID_IVideoWindow, FALSE); hr = IBaseFilter_FindPin(filter, L"In", &pin); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr == S_OK) - { - todo_wine - check_interface(pin, &IID_IMemInputPin, TRUE); - check_interface(pin, &IID_IPin, TRUE); - todo_wine - check_interface(pin, &IID_IQualityControl, TRUE); - check_interface(pin, &IID_IUnknown, TRUE); + todo_wine + check_interface(pin, &IID_IMemInputPin, TRUE); + check_interface(pin, &IID_IPin, TRUE); + todo_wine + check_interface(pin, &IID_IQualityControl, TRUE); + check_interface(pin, &IID_IUnknown, TRUE); - check_interface(pin, &IID_IMediaPosition, FALSE); - check_interface(pin, &IID_IMediaSeeking, FALSE); + check_interface(pin, &IID_IMediaPosition, FALSE); + check_interface(pin, &IID_IMediaSeeking, FALSE); - IPin_Release(pin); - } + IPin_Release(pin); hr = IBaseFilter_FindPin(filter, L"Out", &pin); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr == S_OK) - { - check_interface(pin, &IID_IPin, TRUE); - todo_wine - check_interface(pin, &IID_IMediaPosition, TRUE); - todo_wine - check_interface(pin, &IID_IMediaSeeking, TRUE); - todo_wine - check_interface(pin, &IID_IQualityControl, TRUE); - check_interface(pin, &IID_IUnknown, TRUE); + check_interface(pin, &IID_IPin, TRUE); + todo_wine + check_interface(pin, &IID_IMediaPosition, TRUE); + todo_wine + check_interface(pin, &IID_IMediaSeeking, TRUE); + todo_wine + check_interface(pin, &IID_IQualityControl, TRUE); + check_interface(pin, &IID_IUnknown, TRUE); - check_interface(pin, &IID_IAsyncReader, FALSE); + check_interface(pin, &IID_IAsyncReader, FALSE); - IPin_Release(pin); - } + IPin_Release(pin); refcount = IBaseFilter_Release(filter); ok(refcount == 0, "Got refcount %lu.\n", refcount); @@ -1062,10 +1054,7 @@ static void test_enum_pins(void) ok(hr == E_POINTER, "Got hr %#lx.\n", hr); hr = IEnumPins_Next(enum1, 1, pins, NULL); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - goto skip_test; refcount = get_refcount(filter); ok(refcount == 3, "Got refcount %ld.\n", refcount); @@ -1153,8 +1142,6 @@ static void test_enum_pins(void) IPin_Release(pins[0]); IEnumPins_Release(enum2); - -skip_test: IEnumPins_Release(enum1); refcount = IBaseFilter_Release(filter); ok(refcount == 0, "Got refcount %ld.\n", refcount); @@ -1175,10 +1162,7 @@ static void test_find_pin(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IBaseFilter_FindPin(filter, L"In", &pin); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - goto skip_test; hr = IEnumPins_Next(enum_pins, 1, &pin2, NULL); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1194,7 +1178,6 @@ static void test_find_pin(void) IPin_Release(pin2); IPin_Release(pin); -skip_test: IEnumPins_Release(enum_pins); refcount = IBaseFilter_Release(filter); ok(refcount == 0, "Got refcount %ld.\n", refcount); @@ -1215,10 +1198,7 @@ static void test_pin_info(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IBaseFilter_FindPin(filter, L"In", &pin); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - goto skip_test; refcount = get_refcount(filter); ok(refcount == 2, "Got refcount %ld.\n", refcount); @@ -1278,7 +1258,6 @@ static void test_pin_info(void) IPin_Release(pin); -skip_test: refcount = IBaseFilter_Release(filter); ok(refcount == 0, "Got refcount %ld.\n", refcount); } @@ -1307,10 +1286,7 @@ static void test_media_types(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IBaseFilter_FindPin(filter, L"Out", &source); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - goto skip_test; hr = IBaseFilter_FindPin(filter, L"In", &sink); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1333,6 +1309,7 @@ static void test_media_types(void) req_mt.cbFormat = subtypes[i].cbFormat; video_info.bmiHeader.biHeight = 240; hr = IPin_QueryAccept(sink, &req_mt); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_ReceiveConnection(sink, &peer->source.pin.IPin_iface, &req_mt); @@ -1347,6 +1324,7 @@ static void test_media_types(void) video_info.bmiHeader.biHeight = -240; hr = IPin_QueryAccept(sink, &req_mt); + todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_ReceiveConnection(sink, &peer->source.pin.IPin_iface, &req_mt); @@ -1444,7 +1422,6 @@ static void test_media_types(void) refcount = IBaseFilter_Release(&peer->filter.IBaseFilter_iface); ok(refcount == 0, "Got refcount %lu.\n", refcount); -skip_test: hr = IFilterGraph_RemoveFilter(graph, filter); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1468,10 +1445,7 @@ static void test_enum_media_types(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IBaseFilter_FindPin(filter, L"In", &pin); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - goto skip_test; hr = IPin_EnumMediaTypes(pin, &enum1); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -1533,7 +1507,6 @@ static void test_enum_media_types(void) IEnumMediaTypes_Release(enum2); IPin_Release(pin); -skip_test: ref = IBaseFilter_Release(filter); ok(!ref, "Got outstanding refcount %ld.\n", ref); } @@ -2296,10 +2269,7 @@ static void test_connect_pin(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IBaseFilter_FindPin(filter, L"In", &sink); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - goto skip_test; hr = IBaseFilter_FindPin(filter, L"Out", &source); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2450,7 +2420,7 @@ skip_connection_test: refcount = IMemAllocator_Release(&sink_allocator->IMemAllocator_iface); ok(refcount == 0, "Got refcount %lu.\n", refcount); -skip_test: + IMediaControl_Release(control); hr = IFilterGraph_RemoveFilter(graph, filter); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/colorconv.c | 19 +++++++++++++++++++ dlls/quartz/tests/colorconv.c | 1 - 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index 31554e18fd4..9c8c227e160 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -31,6 +31,7 @@ struct color_converter struct strmbase_filter filter; struct strmbase_source source; + struct strmbase_passthrough passthrough; struct strmbase_sink sink; }; @@ -65,8 +66,22 @@ static HRESULT WINAPI color_source_DecideBufferSize( return IMemAllocator_SetProperties(alloc, props, &actual); } +static HRESULT color_source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) +{ + struct color_converter *filter = impl_from_strmbase_filter(iface->filter); + + if (IsEqualGUID(iid, &IID_IMediaSeeking)) + *out = &filter->passthrough.IMediaSeeking_iface; + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + static const struct strmbase_source_ops source_ops = { + .base.pin_query_interface = color_source_query_interface, .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, .pfnDecideBufferSize = color_source_DecideBufferSize, @@ -97,6 +112,7 @@ static void color_destroy(struct strmbase_filter *iface) strmbase_sink_cleanup(&filter->sink); strmbase_source_cleanup(&filter->source); + strmbase_passthrough_cleanup(&filter->passthrough); strmbase_filter_cleanup(&filter->filter); free(filter); @@ -159,6 +175,9 @@ HRESULT color_create(IUnknown *outer, IUnknown **out) strmbase_source_init(&object->source, &object->filter, L"Out", &source_ops); wcscpy(object->source.pin.name, L"XForm Out"); + strmbase_passthrough_init(&object->passthrough, (IUnknown *)&object->source.pin.IPin_iface); + ISeekingPassThru_Init(&object->passthrough.ISeekingPassThru_iface, FALSE, &object->sink.pin.IPin_iface); + TRACE("Created Color Converter %p.\n", object); *out = &object->filter.IUnknown_inner; diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index 10559eb89ce..3c29b85294e 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -920,7 +920,6 @@ static void test_interfaces(void) check_interface(pin, &IID_IPin, TRUE); todo_wine check_interface(pin, &IID_IMediaPosition, TRUE); - todo_wine check_interface(pin, &IID_IMediaSeeking, TRUE); todo_wine check_interface(pin, &IID_IQualityControl, TRUE); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/colorconv.c | 14 ++++++++++++++ dlls/quartz/tests/colorconv.c | 2 -- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index 9c8c227e160..12e10d9731a 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -41,6 +41,19 @@ static struct color_converter *impl_from_strmbase_filter(struct strmbase_filter return CONTAINING_RECORD(iface, struct color_converter, filter); } +static HRESULT color_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) +{ + struct color_converter *filter = impl_from_strmbase_filter(iface->filter); + + if (IsEqualGUID(iid, &IID_IMemInputPin)) + *out = &filter->sink.IMemInputPin_iface; + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + static HRESULT color_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) { FIXME("stub\n"); @@ -49,6 +62,7 @@ static HRESULT color_sink_query_accept(struct strmbase_pin *iface, const AM_MEDI static const struct strmbase_sink_ops sink_ops = { + .base.pin_query_interface = color_sink_query_interface, .base.pin_query_accept = color_sink_query_accept, }; diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index 3c29b85294e..ad69ffd19de 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -902,7 +902,6 @@ static void test_interfaces(void) hr = IBaseFilter_FindPin(filter, L"In", &pin); ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine check_interface(pin, &IID_IMemInputPin, TRUE); check_interface(pin, &IID_IPin, TRUE); todo_wine @@ -2275,7 +2274,6 @@ static void test_connect_pin(void) meminput = NULL; hr = IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&meminput); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); sink_allocator = create_mem_allocator(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/colorconv.c | 49 +++++++++++++++++++++++++++++++++-- dlls/quartz/tests/colorconv.c | 15 +---------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index 12e10d9731a..cca109f2e99 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -36,6 +36,49 @@ struct color_converter struct strmbase_sink sink; }; +struct subtype +{ + const GUID *guid; + DWORD compression; + WORD bitcount; + ULONG cbFormat; +}; + +static const struct subtype subtypes[] = +{ + { &MEDIASUBTYPE_ARGB32, BI_RGB, 32, sizeof(VIDEOINFOHEADER) }, + { &MEDIASUBTYPE_RGB32, BI_RGB, 32, sizeof(VIDEOINFOHEADER) }, + { &MEDIASUBTYPE_RGB24, BI_RGB, 24, sizeof(VIDEOINFOHEADER) }, + { &MEDIASUBTYPE_RGB565, BI_BITFIELDS, 16, sizeof(VIDEOINFOHEADER) + sizeof(DWORD[3]) /* dwBitMasks */ }, + { &MEDIASUBTYPE_RGB555, BI_BITFIELDS, 16, sizeof(VIDEOINFOHEADER) + sizeof(DWORD[3]) /* dwBitMasks */ }, + { &MEDIASUBTYPE_RGB8, BI_RGB, 8, sizeof(VIDEOINFOHEADER) + sizeof(RGBQUAD[256]) /* bmiColors */ }, +}; + +static const struct subtype *get_subtype(const AM_MEDIA_TYPE *mt) +{ + const struct subtype *subtype = NULL; + VIDEOINFOHEADER *video_info; + int i; + + if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Video) || !IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo)) + return NULL; + + for (i = 0; i < ARRAY_SIZE(subtypes); i++) + { + if (IsEqualGUID(&mt->subtype, subtypes[i].guid)) + { + subtype = subtypes + i; + break; + } + } + + if (!subtype || mt->cbFormat < subtype->cbFormat || !(video_info = (VIDEOINFOHEADER *)mt->pbFormat) || + video_info->bmiHeader.biSize != sizeof(video_info->bmiHeader)) + return NULL; + + return subtype; +} + static struct color_converter *impl_from_strmbase_filter(struct strmbase_filter *iface) { return CONTAINING_RECORD(iface, struct color_converter, filter); @@ -56,8 +99,10 @@ static HRESULT color_sink_query_interface(struct strmbase_pin *iface, REFIID iid static HRESULT color_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) { - FIXME("stub\n"); - return S_FALSE; + if (get_subtype(mt)) + return S_OK; + else + return S_FALSE; } static const struct strmbase_sink_ops sink_ops = diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index ad69ffd19de..97ff64713a3 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -1307,30 +1307,24 @@ static void test_media_types(void) req_mt.cbFormat = subtypes[i].cbFormat; video_info.bmiHeader.biHeight = 240; hr = IPin_QueryAccept(sink, &req_mt); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_ReceiveConnection(sink, &peer->source.pin.IPin_iface, &req_mt); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_Disconnect(sink); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); /* Test negative height */ video_info.bmiHeader.biHeight = -240; hr = IPin_QueryAccept(sink, &req_mt); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_ReceiveConnection(sink, &peer->source.pin.IPin_iface, &req_mt); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_Disconnect(sink); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); winetest_pop_context(); @@ -1352,7 +1346,6 @@ static void test_media_types(void) video_info.rcTarget.bottom = 220; hr = IPin_ReceiveConnection(sink, &peer->source.pin.IPin_iface, &req_mt); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_EnumMediaTypes(source, &enum_types); @@ -1405,7 +1398,6 @@ static void test_media_types(void) IEnumMediaTypes_Release(enum_types); hr = IPin_Disconnect(sink); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); /* The previously accepted media type is no longer accepted after disconnect */ @@ -2324,10 +2316,7 @@ static void test_connect_pin(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IFilterGraph_ConnectDirect(graph, &testsource->source.pin.IPin_iface, sink, &req_mt); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - goto skip_connection_test; hr = IPin_ConnectedTo(sink, &peer); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2396,9 +2385,7 @@ static void test_connect_pin(void) hr = IFilterGraph_Disconnect(graph, &testsource->source.pin.IPin_iface); ok(hr == S_OK, "Got hr %#lx.\n", hr); -skip_connection_test: - if (meminput) - IMemInputPin_Release(meminput); + IMemInputPin_Release(meminput); IPin_Release(sink); IPin_Release(source); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/colorconv.c | 52 +++++++++++++++++++++++++++++++++++ dlls/quartz/tests/colorconv.c | 2 -- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index cca109f2e99..4a0506f644c 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -138,9 +138,61 @@ static HRESULT color_source_query_interface(struct strmbase_pin *iface, REFIID i return S_OK; } +static HRESULT color_source_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt) +{ + struct color_converter *filter = impl_from_strmbase_filter(iface->filter); + const VIDEOINFOHEADER *sink_format; + const struct subtype *subtype; + VIDEOINFO *format; + + if (!filter->sink.pin.peer || index >= ARRAY_SIZE(subtypes)) + return VFW_S_NO_MORE_ITEMS; + + subtype = subtypes + index; + sink_format = (VIDEOINFOHEADER *)filter->sink.pin.mt.pbFormat; + + memset(mt, 0, sizeof(AM_MEDIA_TYPE)); + + if (!(format = CoTaskMemAlloc(mt->cbFormat = subtype->cbFormat))) + return E_OUTOFMEMORY; + + memset(format, 0, mt->cbFormat); + + format->rcSource = sink_format->rcSource; + format->rcTarget = sink_format->rcTarget; + format->dwBitRate = sink_format->dwBitRate; + format->dwBitErrorRate = sink_format->dwBitErrorRate; + format->AvgTimePerFrame = sink_format->AvgTimePerFrame; + + format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + format->bmiHeader.biWidth = sink_format->bmiHeader.biWidth; + format->bmiHeader.biHeight = sink_format->bmiHeader.biHeight; + format->bmiHeader.biPlanes = sink_format->bmiHeader.biPlanes; + format->bmiHeader.biBitCount = subtype->bitcount; + format->bmiHeader.biCompression = subtype->compression; + format->bmiHeader.biSizeImage = format->bmiHeader.biHeight * format->bmiHeader.biWidth * (subtype->bitcount / 8); + + if (IsEqualGUID(subtype->guid, &MEDIASUBTYPE_RGB565)) + { + format->dwBitMasks[iRED] = 0xf800; + format->dwBitMasks[iGREEN] = 0x07e0; + format->dwBitMasks[iBLUE] = 0x001f; + } + + mt->majortype = MEDIATYPE_Video; + mt->subtype = *subtype->guid; + mt->bFixedSizeSamples = TRUE; + mt->lSampleSize = format->bmiHeader.biSizeImage; + mt->formattype = FORMAT_VideoInfo; + mt->pbFormat = (BYTE *)format; + + return S_OK; +} + static const struct strmbase_source_ops source_ops = { .base.pin_query_interface = color_source_query_interface, + .base.pin_get_media_type = color_source_get_media_type, .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, .pfnDecideBufferSize = color_source_DecideBufferSize, diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index 97ff64713a3..7dd01b9313f 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -1352,9 +1352,7 @@ static void test_media_types(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IEnumMediaTypes_Next(enum_types, ARRAY_SIZE(subtypes), media_types, &num_types); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(num_types == 6, "Got num_types %lu.\n", num_types); mt = req_mt; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/colorconv.c | 11 +++++++++++ dlls/quartz/tests/colorconv.c | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index 4a0506f644c..abbb1eeb5ed 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -138,6 +138,16 @@ static HRESULT color_source_query_interface(struct strmbase_pin *iface, REFIID i return S_OK; } +static HRESULT color_source_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) +{ + struct color_converter *filter = impl_from_strmbase_filter(iface->filter); + + if (!filter->sink.pin.peer) + return S_FALSE; + + return get_subtype(mt) ? S_OK : S_FALSE; +} + static HRESULT color_source_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt) { struct color_converter *filter = impl_from_strmbase_filter(iface->filter); @@ -192,6 +202,7 @@ static HRESULT color_source_get_media_type(struct strmbase_pin *iface, unsigned static const struct strmbase_source_ops source_ops = { .base.pin_query_interface = color_source_query_interface, + .base.pin_query_accept = color_source_query_accept, .base.pin_get_media_type = color_source_get_media_type, .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index 7dd01b9313f..4b058091a3a 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -1400,7 +1400,6 @@ static void test_media_types(void) /* The previously accepted media type is no longer accepted after disconnect */ hr = IPin_QueryAccept(source, &req_mt); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); FreeMediaType(&req_mt); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/colorconv.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index abbb1eeb5ed..08d9acd2b7d 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -114,7 +114,10 @@ static const struct strmbase_sink_ops sink_ops = static HRESULT WINAPI color_source_DecideBufferSize( struct strmbase_source *iface, IMemAllocator *alloc, ALLOCATOR_PROPERTIES *props) { + const struct subtype *subtype; ALLOCATOR_PROPERTIES actual; + BITMAPINFOHEADER *header; + long min_image_size; if (!props->cbAlign) props->cbAlign = 1; @@ -122,6 +125,14 @@ static HRESULT WINAPI color_source_DecideBufferSize( if (!props->cBuffers) props->cBuffers = 1; + subtype = get_subtype(&iface->pin.mt); + + header = &((VIDEOINFOHEADER *)iface->pin.mt.pbFormat)->bmiHeader; + min_image_size = header->biWidth * header->biHeight * (subtype->bitcount / 8); + + if (props->cbBuffer < min_image_size) + props->cbBuffer = min_image_size; + return IMemAllocator_SetProperties(alloc, props, &actual); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/Makefile.in | 2 +- dlls/quartz/colorconv.c | 68 +++++++++++++++++++++++++++++++++-- dlls/quartz/tests/colorconv.c | 6 ++++ 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index 1e38b24ef73..98aac7c5553 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -1,6 +1,6 @@ MODULE = quartz.dll IMPORTLIB = quartz -IMPORTS = strmiids dxguid strmbase uuid dsound msacm32 msvfw32 ole32 oleaut32 rpcrt4 user32 gdi32 advapi32 winmm msvcrt +IMPORTS = strmiids dxguid strmbase uuid dsound msacm32 msvfw32 ole32 oleaut32 rpcrt4 user32 gdi32 advapi32 winmm msvcrt dmoguids wmcodecdspuuid DELAYIMPORTS = ddraw VER_PRODUCTVERSION = 6,5,1,902 diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index 08d9acd2b7d..c918417e7b1 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -20,7 +20,9 @@ #include "quartz_private.h" +#include "mediaobj.h" #include "vfw.h" +#include "wmcodecdsp.h" #include "wine/debug.h" @@ -34,6 +36,8 @@ struct color_converter struct strmbase_passthrough passthrough; struct strmbase_sink sink; + + IMediaObject *dmo; }; struct subtype @@ -79,6 +83,34 @@ static const struct subtype *get_subtype(const AM_MEDIA_TYPE *mt) return subtype; } +static LONG calculate_stride(const BITMAPINFOHEADER *bmi_header) +{ + LONG stride = (bmi_header->biWidth * (bmi_header->biBitCount / 8) + 3) & ~3; + if (bmi_header->biHeight >= 0) + return stride; + else + return -stride; +} + +static void populate_output_dmo_mt( + const AM_MEDIA_TYPE *input_mt, const AM_MEDIA_TYPE *output_mt, DMO_MEDIA_TYPE *dmo_mt) +{ + const VIDEOINFOHEADER *input_video_info; + VIDEOINFOHEADER *video_info; + + input_video_info = (VIDEOINFOHEADER *)input_mt->pbFormat; + + video_info = calloc(1, sizeof(*video_info)); + memcpy(video_info, output_mt->pbFormat, sizeof(*video_info)); + video_info->bmiHeader.biWidth = input_video_info->bmiHeader.biWidth; + video_info->bmiHeader.biHeight = input_video_info->bmiHeader.biHeight; + video_info->bmiHeader.biSizeImage = calculate_stride(&video_info->bmiHeader) * video_info->bmiHeader.biHeight; + + memcpy(dmo_mt, output_mt, sizeof(*dmo_mt)); + dmo_mt->pbFormat = (BYTE *)video_info; + dmo_mt->lSampleSize = video_info->bmiHeader.biSizeImage; +} + static struct color_converter *impl_from_strmbase_filter(struct strmbase_filter *iface) { return CONTAINING_RECORD(iface, struct color_converter, filter); @@ -105,19 +137,39 @@ static HRESULT color_sink_query_accept(struct strmbase_pin *iface, const AM_MEDI return S_FALSE; } +static HRESULT color_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *mt) +{ + struct color_converter *filter = impl_from_strmbase_filter(iface->pin.filter); + HRESULT hr; + + hr = IMediaObject_SetInputType(filter->dmo, 0, mt, 0); + + TRACE("Returning %#lx.\n", hr); + + return hr; +} + static const struct strmbase_sink_ops sink_ops = { .base.pin_query_interface = color_sink_query_interface, .base.pin_query_accept = color_sink_query_accept, + .sink_connect = color_sink_connect, }; static HRESULT WINAPI color_source_DecideBufferSize( struct strmbase_source *iface, IMemAllocator *alloc, ALLOCATOR_PROPERTIES *props) { + struct color_converter *filter = impl_from_strmbase_filter(iface->pin.filter); const struct subtype *subtype; ALLOCATOR_PROPERTIES actual; BITMAPINFOHEADER *header; + DMO_MEDIA_TYPE dmo_mt; long min_image_size; + HRESULT hr; + + populate_output_dmo_mt(&filter->sink.pin.mt, &iface->pin.mt, &dmo_mt); + if (FAILED(hr = IMediaObject_SetOutputType(filter->dmo, 0, &dmo_mt, 0))) + return hr; if (!props->cbAlign) props->cbAlign = 1; @@ -248,6 +300,8 @@ static void color_destroy(struct strmbase_filter *iface) strmbase_passthrough_cleanup(&filter->passthrough); strmbase_filter_cleanup(&filter->filter); + IMediaObject_Release(filter->dmo); + free(filter); } @@ -311,8 +365,16 @@ HRESULT color_create(IUnknown *outer, IUnknown **out) strmbase_passthrough_init(&object->passthrough, (IUnknown *)&object->source.pin.IPin_iface); ISeekingPassThru_Init(&object->passthrough.ISeekingPassThru_iface, FALSE, &object->sink.pin.IPin_iface); - TRACE("Created Color Converter %p.\n", object); - *out = &object->filter.IUnknown_inner; + if (SUCCEEDED(hr = CoCreateInstance(&CLSID_CColorConvertDMO, NULL, CLSCTX_INPROC_SERVER, &IID_IMediaObject, + (void **)&object->dmo))) + { + TRACE("Created Color Converter %p.\n", object); + *out = &object->filter.IUnknown_inner; + } + else + { + ERR("Failed to create color conversion transform %#lx.\n", hr); + } - return S_OK; + return hr; } diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index 4b058091a3a..4807c7601f8 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -1310,9 +1310,12 @@ static void test_media_types(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_ReceiveConnection(sink, &peer->source.pin.IPin_iface, &req_mt); + /* DMO color converter does not support ARGB32 */ + todo_wine_if(i == 0) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_Disconnect(sink); + todo_wine_if(i == 0) ok(hr == S_OK, "Got hr %#lx.\n", hr); /* Test negative height */ @@ -1322,9 +1325,12 @@ static void test_media_types(void) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_ReceiveConnection(sink, &peer->source.pin.IPin_iface, &req_mt); + /* DMO color converter does not support ARGB32 */ + todo_wine_if(i == 0) ok(hr == S_OK, "Got hr %#lx.\n", hr); hr = IPin_Disconnect(sink); + todo_wine_if(i == 0) ok(hr == S_OK, "Got hr %#lx.\n", hr); winetest_pop_context(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/Makefile.in | 2 +- dlls/quartz/colorconv.c | 361 +++++++++++++++++++++++++++++++++- dlls/quartz/tests/colorconv.c | 23 +-- 3 files changed, 359 insertions(+), 27 deletions(-) diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index 98aac7c5553..54d559a12d8 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -1,6 +1,6 @@ MODULE = quartz.dll IMPORTLIB = quartz -IMPORTS = strmiids dxguid strmbase uuid dsound msacm32 msvfw32 ole32 oleaut32 rpcrt4 user32 gdi32 advapi32 winmm msvcrt dmoguids wmcodecdspuuid +IMPORTS = mfplat strmiids dxguid strmbase uuid dsound msacm32 msvfw32 ole32 oleaut32 rpcrt4 user32 gdi32 advapi32 winmm msvcrt dmoguids wmcodecdspuuid DELAYIMPORTS = ddraw VER_PRODUCTVERSION = 6,5,1,902 diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index c918417e7b1..252bca50acc 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -21,6 +21,7 @@ #include "quartz_private.h" #include "mediaobj.h" +#include "mfapi.h" #include "vfw.h" #include "wmcodecdsp.h" @@ -38,8 +39,129 @@ struct color_converter struct strmbase_sink sink; IMediaObject *dmo; + LONG sample_output_stride; + LONG dmo_output_stride; + ULONG dmo_output_sample_size; }; +struct buffer_for_sample +{ + IMediaBuffer IMediaBuffer_iface; + LONG refcount; + + IMediaSample *sample; +}; + +struct buffer +{ + IMediaBuffer IMediaBuffer_iface; + LONG refcount; + + BYTE *data; + DWORD length; + DWORD max_length; +}; + +static struct buffer *buffer_from_IMediaBuffer(IMediaBuffer *iface) +{ + return CONTAINING_RECORD(iface, struct buffer, IMediaBuffer_iface); +} + +static HRESULT WINAPI buffer_QueryInterface(IMediaBuffer *iface, REFIID iid, void **out) +{ + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMediaBuffer)) + { + *out = iface; + } + else + { + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)(*out)); + return S_OK; +} + +static ULONG WINAPI buffer_AddRef(IMediaBuffer *iface) +{ + struct buffer *buffer = buffer_from_IMediaBuffer(iface); + ULONG refcount; + + refcount = InterlockedIncrement(&buffer->refcount); + + return refcount; +} + +static ULONG WINAPI buffer_Release(IMediaBuffer *iface) +{ + struct buffer *buffer = buffer_from_IMediaBuffer(iface); + ULONG refcount; + + refcount = InterlockedDecrement(&buffer->refcount); + + if (!refcount) + { + free(buffer->data); + free(buffer); + } + + return refcount; +} + +static HRESULT WINAPI buffer_SetLength(IMediaBuffer *iface, DWORD length) +{ + struct buffer *buffer = buffer_from_IMediaBuffer(iface); + + buffer->length = length; + + return S_OK; +} + +static HRESULT WINAPI buffer_GetMaxLength(IMediaBuffer *iface, DWORD *max_length) +{ + struct buffer *buffer = buffer_from_IMediaBuffer(iface); + + *max_length = buffer->max_length; + + return S_OK; +} + +static HRESULT WINAPI buffer_GetBufferAndLength(IMediaBuffer *iface, BYTE **data, DWORD *length) +{ + struct buffer *buffer = buffer_from_IMediaBuffer(iface); + + *length = buffer->length; + if (data) + *data = buffer->data; + + return S_OK; +} + +static IMediaBufferVtbl buffer_vtbl = +{ + buffer_QueryInterface, + buffer_AddRef, + buffer_Release, + buffer_SetLength, + buffer_GetMaxLength, + buffer_GetBufferAndLength, +}; + +static struct buffer *create_buffer(DWORD max_length) +{ + struct buffer *buffer; + + buffer = calloc(1, sizeof(*buffer)); + buffer->IMediaBuffer_iface.lpVtbl = &buffer_vtbl; + buffer->refcount = 1; + + buffer->data = malloc(max_length); + buffer->max_length = max_length; + + return buffer; +} + struct subtype { const GUID *guid; @@ -111,6 +233,110 @@ static void populate_output_dmo_mt( dmo_mt->lSampleSize = video_info->bmiHeader.biSizeImage; } +static struct buffer_for_sample *buffer_for_sample_from_IMediaBuffer(IMediaBuffer *iface) +{ + return CONTAINING_RECORD(iface, struct buffer_for_sample, IMediaBuffer_iface); +} + +static HRESULT WINAPI buffer_for_sample_QueryInterface(IMediaBuffer *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMediaBuffer)) + { + *out = iface; + } + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)(*out)); + return S_OK; +} + +static ULONG WINAPI buffer_for_sample_AddRef(IMediaBuffer *iface) +{ + struct buffer_for_sample *buffer = buffer_for_sample_from_IMediaBuffer(iface); + ULONG refcount; + + refcount = InterlockedIncrement(&buffer->refcount); + + return refcount; +} + +static ULONG WINAPI buffer_for_sample_Release(IMediaBuffer *iface) +{ + struct buffer_for_sample *buffer = buffer_for_sample_from_IMediaBuffer(iface); + ULONG refcount; + + refcount = InterlockedDecrement(&buffer->refcount); + + if (!refcount) + { + IMediaSample_Release(buffer->sample); + free(buffer); + } + + return refcount; +} + +static HRESULT WINAPI buffer_for_sample_SetLength(IMediaBuffer *iface, DWORD len) +{ + struct buffer_for_sample *buffer = buffer_for_sample_from_IMediaBuffer(iface); + + TRACE("iface %p, len %lu.\n", iface, len); + + return IMediaSample_SetActualDataLength(buffer->sample, len); +} + +static HRESULT WINAPI buffer_for_sample_GetMaxLength(IMediaBuffer *iface, DWORD *len) +{ + struct buffer_for_sample *buffer = buffer_for_sample_from_IMediaBuffer(iface); + + TRACE("iface %p, len %p.\n", iface, len); + + *len = IMediaSample_GetSize(buffer->sample); + return S_OK; +} + +static HRESULT WINAPI buffer_for_sample_GetBufferAndLength(IMediaBuffer *iface, BYTE **data, DWORD *len) +{ + struct buffer_for_sample *buffer = buffer_for_sample_from_IMediaBuffer(iface); + + TRACE("iface %p, data %p, len %p.\n", iface, data, len); + + *len = IMediaSample_GetActualDataLength(buffer->sample); + if (data) + return IMediaSample_GetPointer(buffer->sample, data); + return S_OK; +} + +static const IMediaBufferVtbl buffer_for_sample_vtbl = +{ + buffer_for_sample_QueryInterface, + buffer_for_sample_AddRef, + buffer_for_sample_Release, + buffer_for_sample_SetLength, + buffer_for_sample_GetMaxLength, + buffer_for_sample_GetBufferAndLength, +}; + +static struct buffer_for_sample *create_buffer_for_sample(IMediaSample *sample) +{ + struct buffer_for_sample *buffer; + + buffer = calloc(1, sizeof(*buffer)); + buffer->IMediaBuffer_iface.lpVtbl = &buffer_for_sample_vtbl; + buffer->refcount = 1; + + IMediaSample_AddRef(buffer->sample = sample); + + return buffer; +} + static struct color_converter *impl_from_strmbase_filter(struct strmbase_filter *iface) { return CONTAINING_RECORD(iface, struct color_converter, filter); @@ -149,13 +375,6 @@ static HRESULT color_sink_connect(struct strmbase_sink *iface, IPin *peer, const return hr; } -static const struct strmbase_sink_ops sink_ops = -{ - .base.pin_query_interface = color_sink_query_interface, - .base.pin_query_accept = color_sink_query_accept, - .sink_connect = color_sink_connect, -}; - static HRESULT WINAPI color_source_DecideBufferSize( struct strmbase_source *iface, IMemAllocator *alloc, ALLOCATOR_PROPERTIES *props) { @@ -171,6 +390,10 @@ static HRESULT WINAPI color_source_DecideBufferSize( if (FAILED(hr = IMediaObject_SetOutputType(filter->dmo, 0, &dmo_mt, 0))) return hr; + filter->sample_output_stride = calculate_stride(&((VIDEOINFOHEADER *)iface->pin.mt.pbFormat)->bmiHeader); + filter->dmo_output_stride = calculate_stride(&((VIDEOINFOHEADER *)dmo_mt.pbFormat)->bmiHeader); + filter->dmo_output_sample_size = dmo_mt.lSampleSize; + if (!props->cbAlign) props->cbAlign = 1; @@ -188,6 +411,130 @@ static HRESULT WINAPI color_source_DecideBufferSize( return IMemAllocator_SetProperties(alloc, props, &actual); } +static HRESULT WINAPI color_sink_Receive(struct strmbase_sink *iface, IMediaSample *src_sample) +{ + struct color_converter *filter = impl_from_strmbase_filter(iface->pin.filter); + BITMAPINFOHEADER *input_bmi_header, *output_bmi_header; + struct buffer_for_sample *src_buffer; + DMO_OUTPUT_DATA_BUFFER output; + struct buffer *dst_buffer; + BITMAPINFOHEADER *header; + IMediaSample *dst_sample; + long output_image_size; + BYTE *src_buff, *dest; + LONGLONG start, stop; + DWORD flags, status; + LONG dst_size; + UINT32 *data; + HRESULT hr; + int i; + + /* We do not expect pin connection state to change while the filter is + * running. This guarantee is necessary, since otherwise we would have to + * take the filter lock, and we can't take the filter lock from a streaming + * thread. */ + if (!filter->source.pMemInputPin) + { + WARN("Source is not connected, returning VFW_E_NOT_CONNECTED.\n"); + return VFW_E_NOT_CONNECTED; + } + + if (filter->filter.state == State_Stopped) + return VFW_E_WRONG_STATE; + + if (filter->sink.flushing) + return S_FALSE; + + hr = IMediaSample_GetPointer(src_sample, &src_buff); + if (FAILED(hr)) + { + ERR("Failed to get input buffer pointer, hr %#lx.\n", hr); + return hr; + } + + if (FAILED(hr = IMemAllocator_GetBuffer(filter->source.pAllocator, &dst_sample, NULL, NULL, 0))) + { + ERR("Failed to get sample, hr %#lx.\n", hr); + return hr; + } + + header = &((VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat)->bmiHeader; + output_image_size = calculate_stride(header) * header->biHeight; + dst_size = IMediaSample_GetSize(dst_sample); + if (dst_size < output_image_size) + { + ERR("Sample size is too small (%ld < %lu).\n", dst_size, output_image_size); + IMediaSample_Release(dst_sample); + return E_FAIL; + } + + hr = IMediaSample_GetTime(src_sample, &start, &stop); + + if (hr == S_OK) + { + IMediaSample_SetTime(dst_sample, &start, &stop); + flags = DMO_INPUT_DATA_BUFFERF_TIME | DMO_INPUT_DATA_BUFFERF_TIMELENGTH; + } + else if (hr == VFW_S_NO_STOP_TIME) + { + IMediaSample_SetTime(dst_sample, &start, NULL); + flags = DMO_INPUT_DATA_BUFFERF_TIME; + } + else + { + IMediaSample_SetTime(dst_sample, NULL, NULL); + flags = 0; + } + + /* perform color conversion */ + src_buffer = create_buffer_for_sample(src_sample); + hr = IMediaObject_ProcessInput(filter->dmo, 0, &src_buffer->IMediaBuffer_iface, flags, start, stop - start); + IMediaBuffer_Release(&src_buffer->IMediaBuffer_iface); + + input_bmi_header = &((VIDEOINFOHEADER *)filter->sink.pin.mt.pbFormat)->bmiHeader; + output_bmi_header = &((VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat)->bmiHeader; + dst_buffer = create_buffer(filter->dmo_output_sample_size); + memset(&output, 0, sizeof(output)); + output.pBuffer = &dst_buffer->IMediaBuffer_iface; + hr = IMediaObject_ProcessOutput(filter->dmo, 0, 1, &output, &status); + if (input_bmi_header->biBitCount < output_bmi_header->biBitCount && output_bmi_header->biBitCount == 32) + { + /* Fix the value of the alpha channel. DMO uses 0xff, whilst quartz uses 0x00. */ + data = (UINT32 *)dst_buffer->data; + + for (i = 0; i < input_bmi_header->biHeight * input_bmi_header->biWidth; i++) + *data++ &= 0xffffff; + } + IMediaSample_GetPointer(dst_sample, &dest); + if (filter->sample_output_stride < 0) + dest += -filter->sample_output_stride * (input_bmi_header->biHeight - 1); + + MFCopyImage(dest, filter->sample_output_stride, dst_buffer->data, filter->dmo_output_stride, + input_bmi_header->biWidth * (output_bmi_header->biBitCount / 8), input_bmi_header->biHeight); + IMediaBuffer_Release(output.pBuffer); + + IMediaSample_SetActualDataLength(dst_sample, output_image_size); + + IMediaSample_SetPreroll(dst_sample, (IMediaSample_IsPreroll(src_sample) == S_OK)); + IMediaSample_SetDiscontinuity(dst_sample, (IMediaSample_IsDiscontinuity(src_sample) == S_OK)); + IMediaSample_SetSyncPoint(dst_sample, TRUE); + + hr = IMemInputPin_Receive(filter->source.pMemInputPin, dst_sample); + if (hr != S_OK && hr != VFW_E_NOT_CONNECTED) + ERR("Failed to send sample, hr %#lx.\n", hr); + + IMediaSample_Release(dst_sample); + return hr; +} + +static const struct strmbase_sink_ops sink_ops = +{ + .base.pin_query_interface = color_sink_query_interface, + .base.pin_query_accept = color_sink_query_accept, + .pfnReceive = color_sink_Receive, + .sink_connect = color_sink_connect, +}; + static HRESULT color_source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) { struct color_converter *filter = impl_from_strmbase_filter(iface->filter); diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index 4807c7601f8..c63fafb5422 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -1721,7 +1721,7 @@ static void test_filter_state(IMediaControl *control, IBaseFilter *filter) #define EXP_DISCONTINUITY (1 << 4) #define EXP_UNDEFINED_TIME_END (1 << 5) -#define TODO_TIME (1 << 0) +#define TODO_TIME_END (1 << 0) #define TODO_MEDIA_TIME (1 << 1) #define TODO_SYNC_POINT (1 << 2) #define TODO_PREROLL (1 << 3) @@ -1740,7 +1740,7 @@ static void test_sample_processing( tests[] = { { - .todo_flags = TODO_SYNC_POINT | TODO_TIME + .todo_flags = TODO_SYNC_POINT }, { .flags = SET_TIME_START | SET_MEDIA_TIME | SET_SYNC_POINT, @@ -1749,7 +1749,7 @@ static void test_sample_processing( .media_time_end = 20000, .sync_point = TRUE, .expected_flags = EXP_TIME | EXP_UNDEFINED_TIME_END | EXP_MEDIA_TIME | EXP_SYNC_POINT, - .todo_flags = TODO_MEDIA_TIME + .todo_flags = TODO_MEDIA_TIME | TODO_TIME_END }, { .flags = SET_TIME, @@ -1915,13 +1915,7 @@ static void test_sample_processing( sink_allocator->expect_get_media_type = TRUE; sink_allocator->media_type_checked = FALSE; hr = IMemInputPin_Receive(input, sample); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - if (hr != S_OK) - { - winetest_pop_context(); - continue; - } ok(sink_allocator->sample_refcount == 1, "Got sample refcount %ld.\n", sink_allocator->sample_refcount); todo_wine @@ -1931,10 +1925,10 @@ static void test_sample_processing( sink_allocator->expect_set_time = FALSE; sink_allocator->expect_get_media_type = FALSE; - todo_wine_if(tests[i].todo_flags & TODO_TIME) if (tests[i].expected_flags & EXP_TIME) { ok(sink_allocator->ts_set, "Time start should be set.\n"); + todo_wine_if(tests[i].todo_flags & TODO_TIME_END) ok(sink_allocator->te_set, "Time end should be set.\n"); ok(sink_allocator->time_start == tests[i].time_start, "Got start time %I64d.\n", sink_allocator->time_start); @@ -2020,7 +2014,6 @@ static void test_sample_processing( sink_allocator->expect_get_media_type = TRUE; sink_allocator->media_type_checked = FALSE; hr = IMemInputPin_Receive(input, sample); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); todo_wine ok(sink_allocator->media_type_checked, "Expected media type to have been checked.\n"); @@ -2032,10 +2025,7 @@ static void test_sample_processing( sample = testsink->sample; testsink->sample = NULL; - todo_wine ok(sample != NULL, "Expected out peer sample.\n"); - if (sample == NULL) - goto skip_test; hr = IMediaSample_GetPointer(sample, &buff); ok(hr == S_OK, "Get hr %#lx.\n", hr); @@ -2126,7 +2116,6 @@ static void test_sample_processing( IMediaSample_Release(sample); ok(sink_allocator->sample_refcount == 0, "Got sample refcount %ld.\n", sink_allocator->sample_refcount); -skip_test: hr = IMemAllocator_Decommit(allocator); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2185,9 +2174,7 @@ static void test_streaming_events(IMediaControl *control, IPin *sink, IMemInputP sink_allocator->media_type_checked = FALSE; sink_allocator->expect_get_media_type = TRUE; hr = IMemInputPin_Receive(input, sample); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(testsink->sample != NULL, "Expected to receive sample.\n"); todo_wine ok(sink_allocator->media_type_checked, "Expected media type to have been checked.\n"); @@ -2216,9 +2203,7 @@ static void test_streaming_events(IMediaControl *control, IPin *sink, IMemInputP sink_allocator->expect_get_media_type = TRUE; sink_allocator->expect_get_buffer = TRUE; hr = IMemInputPin_Receive(input, sample); - todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(testsink->sample != NULL, "Expected to receive sample.\n"); todo_wine ok(sink_allocator->media_type_checked, "Expected media type to have been checked.\n"); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/colorconv.c | 27 +++++++++++++++++++++++++++ dlls/quartz/tests/colorconv.c | 7 ------- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index 252bca50acc..ca22f6bdb24 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -424,6 +424,7 @@ static HRESULT WINAPI color_sink_Receive(struct strmbase_sink *iface, IMediaSamp BYTE *src_buff, *dest; LONGLONG start, stop; DWORD flags, status; + AM_MEDIA_TYPE *mt; LONG dst_size; UINT32 *data; HRESULT hr; @@ -458,6 +459,32 @@ static HRESULT WINAPI color_sink_Receive(struct strmbase_sink *iface, IMediaSamp return hr; } + /* Handle dynamic format change. */ + if ((hr = IMediaSample_GetMediaType(dst_sample, &mt)) == S_OK) + { + if (memcmp(mt, &filter->source.pin.mt, offsetof(AM_MEDIA_TYPE, pbFormat)) + || memcmp(mt->pbFormat, filter->source.pin.mt.pbFormat, mt->cbFormat)) + { + DMO_MEDIA_TYPE dmo_mt; + + populate_output_dmo_mt(&filter->sink.pin.mt, mt, &dmo_mt); + if (FAILED(hr = IMediaObject_SetOutputType(filter->dmo, 0, &dmo_mt, 0))) + WARN("Failed to update media type, hr %#lx.\n", hr); + + filter->sample_output_stride = calculate_stride(&((VIDEOINFOHEADER *)mt->pbFormat)->bmiHeader); + filter->dmo_output_stride = calculate_stride(&((VIDEOINFOHEADER *)dmo_mt.pbFormat)->bmiHeader); + filter->dmo_output_sample_size = dmo_mt.lSampleSize; + + FreeMediaType(&filter->source.pin.mt); + filter->source.pin.mt = *mt; + CoTaskMemFree(mt); + } + } + else if (hr != S_FALSE) + { + ERR("Failed to get media type, hr %#lx.\n", hr); + } + header = &((VIDEOINFOHEADER *)filter->source.pin.mt.pbFormat)->bmiHeader; output_image_size = calculate_stride(header) * header->biHeight; dst_size = IMediaSample_GetSize(dst_sample); diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index c63fafb5422..6a10391a54b 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -1918,7 +1918,6 @@ static void test_sample_processing( ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(sink_allocator->sample_refcount == 1, "Got sample refcount %ld.\n", sink_allocator->sample_refcount); - todo_wine ok(sink_allocator->media_type_checked, "Expected media type to have been checked.\n"); ok(testsink->sample != NULL, "Expected out peer sample.\n"); sink_allocator->expect_get_buffer = FALSE; @@ -2015,7 +2014,6 @@ static void test_sample_processing( sink_allocator->media_type_checked = FALSE; hr = IMemInputPin_Receive(input, sample); ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(sink_allocator->media_type_checked, "Expected media type to have been checked.\n"); sink_allocator->expect_get_buffer = FALSE; sink_allocator->expect_get_media_type = FALSE; @@ -2084,7 +2082,6 @@ static void test_sample_processing( sink_allocator->media_type_checked = FALSE; hr = IMemInputPin_Receive(input, sample); ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(sink_allocator->media_type_checked, "Expected media type to have been checked.\n"); sink_allocator->expect_get_buffer = FALSE; sink_allocator->expect_get_media_type = FALSE; @@ -2109,7 +2106,6 @@ static void test_sample_processing( for (unsigned int i = 0; i < image_size; ++i) diff += abs((int)buff[i] - (int)rgb32_image->data[i]); diff = diff * 100 / 256 / image_size; - todo_wine ok(diff == 0, "Got %I64u%% difference.\n", diff); free(rgb32_image); @@ -2146,7 +2142,6 @@ static void test_streaming_events(IMediaControl *control, IPin *sink, IMemInputP ok(hr == S_OK, "Got hr %#lx.\n", hr); sink_allocator->expect_get_buffer = FALSE; sink_allocator->expect_get_media_type = FALSE; - todo_wine ok(sink_allocator->media_type_checked, "Expected media type to have been checked.\n"); hr = IMediaSample_GetPointer(sample, &data); ok(hr == S_OK, "Got hr %#lx.\n", hr); @@ -2176,7 +2171,6 @@ static void test_streaming_events(IMediaControl *control, IPin *sink, IMemInputP hr = IMemInputPin_Receive(input, sample); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(testsink->sample != NULL, "Expected to receive sample.\n"); - todo_wine ok(sink_allocator->media_type_checked, "Expected media type to have been checked.\n"); sink_allocator->expect_get_media_type = FALSE; if (testsink->sample) @@ -2205,7 +2199,6 @@ static void test_streaming_events(IMediaControl *control, IPin *sink, IMemInputP hr = IMemInputPin_Receive(input, sample); ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(testsink->sample != NULL, "Expected to receive sample.\n"); - todo_wine ok(sink_allocator->media_type_checked, "Expected media type to have been checked.\n"); sink_allocator->expect_get_buffer = FALSE; sink_allocator->expect_get_media_type = FALSE; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/quartz/colorconv.c | 11 +++++++++++ dlls/quartz/tests/colorconv.c | 1 - 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/dlls/quartz/colorconv.c b/dlls/quartz/colorconv.c index ca22f6bdb24..47b9fae6d9b 100644 --- a/dlls/quartz/colorconv.c +++ b/dlls/quartz/colorconv.c @@ -554,12 +554,23 @@ static HRESULT WINAPI color_sink_Receive(struct strmbase_sink *iface, IMediaSamp return hr; } +static HRESULT color_sink_receive_can_block(struct strmbase_sink *iface) +{ + struct color_converter *filter = impl_from_strmbase_filter(iface->pin.filter); + + if (!filter->source.pMemInputPin) + return VFW_E_NOT_CONNECTED; + + return IMemInputPin_ReceiveCanBlock(filter->source.pMemInputPin); +} + static const struct strmbase_sink_ops sink_ops = { .base.pin_query_interface = color_sink_query_interface, .base.pin_query_accept = color_sink_query_accept, .pfnReceive = color_sink_Receive, .sink_connect = color_sink_connect, + .sink_receive_can_block = color_sink_receive_can_block, }; static HRESULT color_source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) diff --git a/dlls/quartz/tests/colorconv.c b/dlls/quartz/tests/colorconv.c index 6a10391a54b..3dd4c912cc8 100644 --- a/dlls/quartz/tests/colorconv.c +++ b/dlls/quartz/tests/colorconv.c @@ -1831,7 +1831,6 @@ static void test_sample_processing( testsink->can_block = S_FALSE; hr = IMemInputPin_ReceiveCanBlock(input); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); sink_allocator = mem_allocator_from_IMemAllocator(testsink->sink.pAllocator); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11679
v2: - Fix formatting of `CoCreateInstance` of `CLSID_MemoryAllocator` by making it one line - Use `color_sink_query_accept` instead of `color_sink_connect` for stubbed pins - Remove `abs` when calculating image size (as height will be negative if stride is negative) - Remove left over VFW flag code - Fix calls to `IMediaSample::SetTime` - Fix and simplify the flag logic in `IMediaObject::ProcessInput` - Fix formatting by putting `||` at the beginning of the line - Removed commit that added `color_sink_end_flush` - Add static declaration and rename `color_sink_can_block` to `color_sink_receive_can_block` For `6/14`, I figured out the reason the tests weren't passing was because I was returning `VFW_E_TYPE_NOT_ACCEPTED` in my stubbed `color_sink_connect`. So I replaced the stubbed `color_sink_connect` with a stubbed `color_sink_query_accept` which returns `S_FALSE` instead. For `10/14`, I realised this line: ``` video_info->bmiHeader.biSizeImage = abs(calculate_stride(&video_info->bmiHeader)) * video_info->bmiHeader.biHeight; ``` was actually incorrect. stride is only negative when height is negative; so this would have caused a negative value for image size. I removed the `abs` (so two negatives will make a positive). I will address the rest of the comments with the change to use FFmpeg directly. Although it hardcodes the alpha channel to 255 when converting from RGB24 to RGB32 (see [here](https://gitlab.winehq.org/wine/wine/-/blob/master/libs/ffmpeg/libswscale/rgb...)), so that inefficient loop in `11/14` will need to remain. Although, now that that source is in our tree, I guess we have the option to change it. Let me know. Thanks! -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11679#note_149801
participants (2)
-
Brendan McGrath -
Brendan McGrath (@redmcg)