Development branch: https://gitlab.winehq.org/baskanov/wine/-/commits/l3codecx/
From: Anton Baskanov baskanov@gmail.com
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/quartz/tests/mpeglayer3.c | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+)
diff --git a/dlls/quartz/tests/mpeglayer3.c b/dlls/quartz/tests/mpeglayer3.c index 66ef86e2b90..66feb35b577 100644 --- a/dlls/quartz/tests/mpeglayer3.c +++ b/dlls/quartz/tests/mpeglayer3.c @@ -488,6 +488,81 @@ static void test_pin_info(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+static void test_enum_media_types(void) +{ + IBaseFilter *filter = create_mpeg_layer3_decoder(); + IEnumMediaTypes *enum1, *enum2; + AM_MEDIA_TYPE *mts[1]; + ULONG ref, count; + HRESULT hr; + IPin *pin; + + IBaseFilter_FindPin(filter, L"In", &pin); + + hr = IPin_EnumMediaTypes(pin, &enum1); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Next(enum1, 1, mts, &count); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(!count, "Got count %lu.\n", count); + + hr = IEnumMediaTypes_Reset(enum1); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Clone(enum1, &enum2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Skip(enum1, 1); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Next(enum2, 1, mts, NULL); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + IEnumMediaTypes_Release(enum1); + IEnumMediaTypes_Release(enum2); + IPin_Release(pin); + + IBaseFilter_FindPin(filter, L"Out", &pin); + + hr = IPin_EnumMediaTypes(pin, &enum1); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Next(enum1, 1, mts, &count); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(!count, "Got count %lu.\n", count); + + hr = IEnumMediaTypes_Reset(enum1); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Next(enum1, 1, mts, NULL); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Clone(enum1, &enum2); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Skip(enum1, 1); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + hr = IEnumMediaTypes_Next(enum2, 1, mts, NULL); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + IEnumMediaTypes_Release(enum1); + IEnumMediaTypes_Release(enum2); + IPin_Release(pin); + + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +} + START_TEST(mpeglayer3) { IBaseFilter *filter; @@ -508,6 +583,7 @@ START_TEST(mpeglayer3) test_enum_pins(); test_find_pin(); test_pin_info(); + test_enum_media_types();
CoUninitialize(); }
From: Anton Baskanov baskanov@gmail.com
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=18773 Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/winegstreamer/gst_guids.h | 1 + dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 3 ++ dlls/winegstreamer/quartz_transform.c | 46 ++++++++++++++++++++ dlls/winegstreamer/winegstreamer_classes.idl | 7 +++ 5 files changed, 58 insertions(+)
diff --git a/dlls/winegstreamer/gst_guids.h b/dlls/winegstreamer/gst_guids.h index ea859586d7f..313066fa4d8 100644 --- a/dlls/winegstreamer/gst_guids.h +++ b/dlls/winegstreamer/gst_guids.h @@ -20,4 +20,5 @@ */
DEFINE_GUID(CLSID_decodebin_parser, 0xf9d8d64e, 0xa144, 0x47dc, 0x8e, 0xe0, 0xf5, 0x34, 0x98, 0x37, 0x2c, 0x29); +DEFINE_GUID(CLSID_mpeg_layer3_decoder, 0x38be3000, 0xdbf4, 0x11d0, 0x86, 0x0e, 0x00, 0xa0, 0x24, 0xcf, 0xef, 0x6d); DEFINE_GUID(WINESUBTYPE_Gstreamer, 0xffffffff, 0x128f, 0x4dd1, 0xad, 0x22, 0xbe, 0xcf, 0xa6, 0x6c, 0xe7, 0xaa); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index c33a89afd5b..5707ef423fc 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -109,6 +109,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format); HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out); HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out); HRESULT mpeg_audio_codec_create(IUnknown *outer, IUnknown **out); +HRESULT mpeg_layer3_decoder_create(IUnknown *outer, IUnknown **out); HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out); HRESULT wave_parser_create(IUnknown *outer, IUnknown **out); HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out); diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 2efa3bd26ac..32964c0effc 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -450,6 +450,7 @@ static const IClassFactoryVtbl class_factory_vtbl = static struct class_factory avi_splitter_cf = {{&class_factory_vtbl}, avi_splitter_create}; static struct class_factory decodebin_parser_cf = {{&class_factory_vtbl}, decodebin_parser_create}; static struct class_factory mpeg_audio_codec_cf = {{&class_factory_vtbl}, mpeg_audio_codec_create}; +static struct class_factory mpeg_layer3_decoder_cf = {{&class_factory_vtbl}, mpeg_layer3_decoder_create}; static struct class_factory mpeg_splitter_cf = {{&class_factory_vtbl}, mpeg_splitter_create}; 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}; @@ -476,6 +477,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) factory = &decodebin_parser_cf; else if (IsEqualGUID(clsid, &CLSID_CMpegAudioCodec)) factory = &mpeg_audio_codec_cf; + else if (IsEqualGUID(clsid, &CLSID_mpeg_layer3_decoder)) + factory = &mpeg_layer3_decoder_cf; else if (IsEqualGUID(clsid, &CLSID_MPEG1Splitter)) factory = &mpeg_splitter_cf; else if (IsEqualGUID(clsid, &CLSID_WAVEParser)) diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 9a713b120d2..79b3a8af89b 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -19,6 +19,7 @@ */
#include "gst_private.h" +#include "gst_guids.h"
#include "mferror.h" #include "mpegtype.h" @@ -733,3 +734,48 @@ HRESULT mpeg_audio_codec_create(IUnknown *outer, IUnknown **out) *out = &object->filter.IUnknown_inner; return hr; } + +static HRESULT mpeg_layer3_decoder_sink_query_accept(struct transform *filter, const AM_MEDIA_TYPE *mt) +{ + return S_OK; +} + +static HRESULT mpeg_layer3_decoder_source_query_accept(struct transform *filter, const AM_MEDIA_TYPE *mt) +{ + return S_OK; +} + +static HRESULT mpeg_layer3_decoder_source_get_media_type(struct transform *filter, unsigned int index, AM_MEDIA_TYPE *mt) +{ + return VFW_S_NO_MORE_ITEMS; +} + +static HRESULT mpeg_layer3_decoder_source_decide_buffer_size(struct transform *filter, IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props) +{ + return S_OK; +} + +static const struct transform_ops mpeg_layer3_decoder_transform_ops = +{ + mpeg_layer3_decoder_sink_query_accept, + mpeg_layer3_decoder_source_query_accept, + mpeg_layer3_decoder_source_get_media_type, + mpeg_layer3_decoder_source_decide_buffer_size, +}; + +HRESULT mpeg_layer3_decoder_create(IUnknown *outer, IUnknown **out) +{ + struct transform *object; + HRESULT hr; + + hr = transform_create(outer, &CLSID_mpeg_layer3_decoder, &mpeg_layer3_decoder_transform_ops, &object); + if (FAILED(hr)) + return hr; + + wcscpy(object->sink.pin.name, L"XForm In"); + wcscpy(object->source.pin.name, L"XForm Out"); + + TRACE("Created MPEG layer-3 decoder %p.\n", object); + *out = &object->filter.IUnknown_inner; + return hr; +} diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl index ae258f1c2ec..30a99c9acfb 100644 --- a/dlls/winegstreamer/winegstreamer_classes.idl +++ b/dlls/winegstreamer/winegstreamer_classes.idl @@ -35,6 +35,13 @@ coclass AviSplitter {} ] coclass CMpegAudioCodec {}
+[ + helpstring("MPEG Layer-3 Decoder"), + threading(both), + uuid(38be3000-dbf4-11d0-860e-00a024cfef6d) +] +coclass mpeg_layer3_decoder {} + [ helpstring("MPEG-I Stream Splitter"), threading(both),
From: Anton Baskanov baskanov@gmail.com
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/quartz/tests/mpeglayer3.c | 177 +++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+)
diff --git a/dlls/quartz/tests/mpeglayer3.c b/dlls/quartz/tests/mpeglayer3.c index 66feb35b577..8777232ccc9 100644 --- a/dlls/quartz/tests/mpeglayer3.c +++ b/dlls/quartz/tests/mpeglayer3.c @@ -19,11 +19,115 @@
#define COBJMACROS #include "dshow.h" +#include "mmreg.h" #include "wine/test.h"
#include "initguid.h" DEFINE_GUID(CLSID_mpeg_layer3_decoder, 0x38be3000, 0xdbf4, 0x11d0, 0x86, 0x0e, 0x00, 0xa0, 0x24, 0xcf, 0xef, 0x6d);
+static const MPEG1WAVEFORMAT mp1_format = +{ + .wfx.wFormatTag = WAVE_FORMAT_MPEG, + .wfx.nChannels = 1, + .wfx.nSamplesPerSec = 32000, + .wfx.nBlockAlign = 48, + .wfx.nAvgBytesPerSec = 4000, + .wfx.cbSize = sizeof(MPEG1WAVEFORMAT) - sizeof(WAVEFORMATEX), + .fwHeadLayer = ACM_MPEG_LAYER1, + .dwHeadBitrate = 32000, + .fwHeadMode = ACM_MPEG_SINGLECHANNEL, + .fwHeadFlags = ACM_MPEG_ID_MPEG1, +}; + +static const AM_MEDIA_TYPE mp1_mt = +{ + /* MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1AudioPayload, FORMAT_WaveFormatEx */ + .majortype = {0x73647561, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .subtype = {0x00000050, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .bFixedSizeSamples = TRUE, + .lSampleSize = 1, + .formattype = {0x05589f81, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}}, + .cbFormat = sizeof(MPEG1WAVEFORMAT), + .pbFormat = (BYTE *)&mp1_format, +}; + +static const MPEG1WAVEFORMAT mp2_format = +{ + .wfx.wFormatTag = WAVE_FORMAT_MPEG, + .wfx.nChannels = 1, + .wfx.nSamplesPerSec = 32000, + .wfx.nBlockAlign = 144, + .wfx.nAvgBytesPerSec = 4000, + .wfx.cbSize = sizeof(MPEG1WAVEFORMAT) - sizeof(WAVEFORMATEX), + .fwHeadLayer = ACM_MPEG_LAYER2, + .dwHeadBitrate = 32000, + .fwHeadMode = ACM_MPEG_SINGLECHANNEL, + .fwHeadFlags = ACM_MPEG_ID_MPEG1, +}; + +static const AM_MEDIA_TYPE mp2_mt = +{ + /* MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1AudioPayload, FORMAT_WaveFormatEx */ + .majortype = {0x73647561, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .subtype = {0x00000050, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .bFixedSizeSamples = TRUE, + .lSampleSize = 1, + .formattype = {0x05589f81, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}}, + .cbFormat = sizeof(MPEG1WAVEFORMAT), + .pbFormat = (BYTE *)&mp2_format, +}; + +static const MPEG1WAVEFORMAT mp3_format0 = +{ + .wfx.wFormatTag = WAVE_FORMAT_MPEG, + .wfx.nChannels = 1, + .wfx.nSamplesPerSec = 32000, + .wfx.nBlockAlign = 144, + .wfx.nAvgBytesPerSec = 4000, + .wfx.cbSize = sizeof(MPEG1WAVEFORMAT) - sizeof(WAVEFORMATEX), + .fwHeadLayer = ACM_MPEG_LAYER3, + .dwHeadBitrate = 32000, + .fwHeadMode = ACM_MPEG_SINGLECHANNEL, + .fwHeadFlags = ACM_MPEG_ID_MPEG1, +}; + +static const AM_MEDIA_TYPE mp3_mt0 = +{ + /* MEDIATYPE_Audio, MEDIASUBTYPE_MPEG1AudioPayload, FORMAT_WaveFormatEx */ + .majortype = {0x73647561, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .subtype = {0x00000050, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .bFixedSizeSamples = TRUE, + .lSampleSize = 1, + .formattype = {0x05589f81, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}}, + .cbFormat = sizeof(MPEG1WAVEFORMAT), + .pbFormat = (BYTE *)&mp3_format0, +}; + +static const MPEGLAYER3WAVEFORMAT mp3_format1 = +{ + .wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3, + .wfx.nChannels = 1, + .wfx.nSamplesPerSec = 32000, + .wfx.nBlockAlign = 144, + .wfx.nAvgBytesPerSec = 4000, + .wfx.cbSize = sizeof(MPEGLAYER3WAVEFORMAT) - sizeof(WAVEFORMATEX), + .wID = MPEGLAYER3_ID_MPEG, + .nBlockSize = 144, + .nFramesPerBlock = 1, +}; + +static const AM_MEDIA_TYPE mp3_mt1 = +{ + /* MEDIATYPE_Audio, MEDIASUBTYPE_MP3, FORMAT_WaveFormatEx */ + .majortype = {0x73647561, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .subtype = {WAVE_FORMAT_MPEGLAYER3, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .bFixedSizeSamples = TRUE, + .lSampleSize = 1, + .formattype = {0x05589f81, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}}, + .cbFormat = sizeof(MPEGLAYER3WAVEFORMAT), + .pbFormat = (BYTE *)&mp3_format1, +}; + static IBaseFilter *create_mpeg_layer3_decoder(void) { IBaseFilter *filter = NULL; @@ -33,6 +137,26 @@ static IBaseFilter *create_mpeg_layer3_decoder(void) return filter; }
+static void init_pcm_mt(AM_MEDIA_TYPE *mt, WAVEFORMATEX *format, + WORD channels, DWORD sample_rate, WORD depth) +{ + memset(format, 0, sizeof(WAVEFORMATEX)); + format->wFormatTag = WAVE_FORMAT_PCM; + format->nChannels = channels; + format->nSamplesPerSec = sample_rate; + format->wBitsPerSample = depth; + format->nBlockAlign = channels * depth / 8; + format->nAvgBytesPerSec = format->nBlockAlign * format->nSamplesPerSec; + memset(mt, 0, sizeof(AM_MEDIA_TYPE)); + mt->majortype = MEDIATYPE_Audio; + mt->subtype = MEDIASUBTYPE_PCM; + mt->bFixedSizeSamples = TRUE; + mt->lSampleSize = format->nBlockAlign; + mt->formattype = FORMAT_WaveFormatEx; + mt->cbFormat = sizeof(WAVEFORMATEX); + mt->pbFormat = (BYTE *)format; +} + static ULONG get_refcount(void *iface) { IUnknown *unknown = iface; @@ -563,6 +687,58 @@ static void test_enum_media_types(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+static void test_media_types(void) +{ + IBaseFilter *filter = create_mpeg_layer3_decoder(); + WAVEFORMATEX format; + AM_MEDIA_TYPE mt; + HRESULT hr; + ULONG ref; + IPin *pin; + + IBaseFilter_FindPin(filter, L"In", &pin); + + hr = IPin_QueryAccept(pin, &mp3_mt1); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + mt = mp3_mt1; + mt.subtype = MEDIASUBTYPE_PCM; + hr = IPin_QueryAccept(pin, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IPin_QueryAccept(pin, &mp1_mt); + todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + hr = IPin_QueryAccept(pin, &mp2_mt); + todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + hr = IPin_QueryAccept(pin, &mp3_mt0); + todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + mt = mp3_mt1; + mt.majortype = GUID_NULL; + hr = IPin_QueryAccept(pin, &mt); + todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + mt = mp3_mt1; + mt.formattype = GUID_NULL; + hr = IPin_QueryAccept(pin, &mt); + todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + IPin_Release(pin); + + IBaseFilter_FindPin(filter, L"Out", &pin); + + init_pcm_mt(&mt, &format, 1, 32000, 16); + hr = IPin_QueryAccept(pin, &mt); + todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + IPin_Release(pin); + + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +} + START_TEST(mpeglayer3) { IBaseFilter *filter; @@ -584,6 +760,7 @@ START_TEST(mpeglayer3) test_find_pin(); test_pin_info(); test_enum_media_types(); + test_media_types();
CoUninitialize(); }
From: Anton Baskanov baskanov@gmail.com
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/quartz/tests/mpeglayer3.c | 10 +++++----- dlls/winegstreamer/quartz_transform.c | 12 ++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/dlls/quartz/tests/mpeglayer3.c b/dlls/quartz/tests/mpeglayer3.c index 8777232ccc9..17c4f74597f 100644 --- a/dlls/quartz/tests/mpeglayer3.c +++ b/dlls/quartz/tests/mpeglayer3.c @@ -707,23 +707,23 @@ static void test_media_types(void) ok(hr == S_OK, "Got hr %#lx.\n", hr);
hr = IPin_QueryAccept(pin, &mp1_mt); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
hr = IPin_QueryAccept(pin, &mp2_mt); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
hr = IPin_QueryAccept(pin, &mp3_mt0); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
mt = mp3_mt1; mt.majortype = GUID_NULL; hr = IPin_QueryAccept(pin, &mt); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
mt = mp3_mt1; mt.formattype = GUID_NULL; hr = IPin_QueryAccept(pin, &mt); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
IPin_Release(pin);
diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 79b3a8af89b..0956f844bd7 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -737,6 +737,18 @@ HRESULT mpeg_audio_codec_create(IUnknown *outer, IUnknown **out)
static HRESULT mpeg_layer3_decoder_sink_query_accept(struct transform *filter, const AM_MEDIA_TYPE *mt) { + const MPEGLAYER3WAVEFORMAT *format; + + if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio) + || !IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx) + || mt->cbFormat < sizeof(MPEGLAYER3WAVEFORMAT)) + return S_FALSE; + + format = (const MPEGLAYER3WAVEFORMAT *)mt->pbFormat; + + if (format->wfx.wFormatTag != WAVE_FORMAT_MPEGLAYER3) + return S_FALSE; + return S_OK; }
From: Anton Baskanov baskanov@gmail.com
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/quartz/tests/mpeglayer3.c | 216 +++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+)
diff --git a/dlls/quartz/tests/mpeglayer3.c b/dlls/quartz/tests/mpeglayer3.c index 17c4f74597f..4f06c3ec58e 100644 --- a/dlls/quartz/tests/mpeglayer3.c +++ b/dlls/quartz/tests/mpeglayer3.c @@ -20,6 +20,9 @@ #define COBJMACROS #include "dshow.h" #include "mmreg.h" +#include "ks.h" +#include "ksmedia.h" +#include "wine/strmbase.h" #include "wine/test.h"
#include "initguid.h" @@ -128,6 +131,33 @@ static const AM_MEDIA_TYPE mp3_mt1 = .pbFormat = (BYTE *)&mp3_format1, };
+static const WAVEFORMATEXTENSIBLE pcm16ex_format = +{ + .Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE, + .Format.nChannels = 1, + .Format.nSamplesPerSec = 32000, + .Format.wBitsPerSample = 16, + .Format.nBlockAlign = 2, + .Format.nAvgBytesPerSec = 64000, + .Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX), + .Samples.wValidBitsPerSample = 16, + .dwChannelMask = KSAUDIO_SPEAKER_STEREO, + /* KSDATAFORMAT_SUBTYPE_PCM */ + .SubFormat = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, +}; + +static const AM_MEDIA_TYPE pcm16ex_mt = +{ + /* MEDIATYPE_Audio, MEDIASUBTYPE_PCM, FORMAT_WaveFormatEx */ + .majortype = {0x73647561, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .subtype = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}, + .bFixedSizeSamples = TRUE, + .lSampleSize = 2, + .formattype = {0x05589f81, 0xc356, 0x11ce, {0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}}, + .cbFormat = sizeof(WAVEFORMATEXTENSIBLE), + .pbFormat = (BYTE *)&pcm16ex_format, +}; + static IBaseFilter *create_mpeg_layer3_decoder(void) { IBaseFilter *filter = NULL; @@ -137,6 +167,12 @@ static IBaseFilter *create_mpeg_layer3_decoder(void) return filter; }
+static inline BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TYPE *b) +{ + return !memcmp(a, b, offsetof(AM_MEDIA_TYPE, pbFormat)) + && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat); +} + static void init_pcm_mt(AM_MEDIA_TYPE *mt, WAVEFORMATEX *format, WORD channels, DWORD sample_rate, WORD depth) { @@ -739,6 +775,185 @@ static void test_media_types(void) ok(!ref, "Got outstanding refcount %ld.\n", ref); }
+struct testfilter +{ + struct strmbase_filter filter; + struct strmbase_source source; +}; + +static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface) +{ + return CONTAINING_RECORD(iface, struct testfilter, filter); +} + +static struct strmbase_pin *testfilter_get_pin(struct strmbase_filter *iface, unsigned int index) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface); + if (!index) + return &filter->source.pin; + return NULL; +} + +static void testfilter_destroy(struct strmbase_filter *iface) +{ + struct testfilter *filter = impl_from_strmbase_filter(iface); + strmbase_source_cleanup(&filter->source); + strmbase_filter_cleanup(&filter->filter); +} + +static const struct strmbase_filter_ops testfilter_ops = +{ + .filter_get_pin = testfilter_get_pin, + .filter_destroy = testfilter_destroy, +}; + +static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface, + IMemInputPin *peer, IMemAllocator **allocator) +{ + return S_OK; +} + +static const struct strmbase_source_ops testsource_ops = +{ + .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, + .pfnDecideAllocator = testsource_DecideAllocator, +}; + +static void testfilter_init(struct testfilter *filter) +{ + static const GUID clsid = {0xabacab}; + memset(filter, 0, sizeof(*filter)); + strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops); + strmbase_source_init(&filter->source, &filter->filter, L"source", &testsource_ops); +} + +static void test_connect_pin(void) +{ + IBaseFilter *filter = create_mpeg_layer3_decoder(); + struct testfilter testsource; + IPin *sink, *source, *peer; + WAVEFORMATEX req_format; + IMediaControl *control; + IMemInputPin *meminput; + AM_MEDIA_TYPE req_mt; + IFilterGraph2 *graph; + AM_MEDIA_TYPE mt; + HRESULT hr; + ULONG ref; + + CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, + &IID_IFilterGraph2, (void **)&graph); + testfilter_init(&testsource); + IFilterGraph2_AddFilter(graph, &testsource.filter.IBaseFilter_iface, L"source"); + IFilterGraph2_AddFilter(graph, filter, L"MPEG layer-3 decoder"); + IBaseFilter_FindPin(filter, L"In", &sink); + IBaseFilter_FindPin(filter, L"Out", &source); + IPin_QueryInterface(sink, &IID_IMemInputPin, (void **)&meminput); + IFilterGraph2_QueryInterface(graph, &IID_IMediaControl, (void **)&control); + + /* Test sink connection. */ + + peer = (IPin *)0xdeadbeef; + hr = IPin_ConnectedTo(sink, &peer); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr); + ok(!peer, "Got peer %p.\n", peer); + + hr = IPin_ConnectionMediaType(sink, &mt); + ok(hr == VFW_E_NOT_CONNECTED, "Got hr %#lx.\n", hr); + + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &mp3_mt1); + ok(hr == VFW_E_NOT_STOPPED, "Got hr %#lx.\n", hr); + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + req_mt = mp1_mt; + req_mt.subtype = MEDIASUBTYPE_PCM; + hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &req_mt); + ok(hr == VFW_E_TYPE_NOT_ACCEPTED, "Got hr %#lx.\n", hr); + + hr = IFilterGraph2_ConnectDirect(graph, &testsource.source.pin.IPin_iface, sink, &mp3_mt1); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IPin_ConnectedTo(sink, &peer); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(peer == &testsource.source.pin.IPin_iface, "Got peer %p.\n", peer); + IPin_Release(peer); + + hr = IPin_ConnectionMediaType(sink, &mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + ok(compare_media_types(&mt, &mp3_mt1), "Media types didn't match.\n"); + ok(compare_media_types(&testsource.source.pin.mt, &mp3_mt1), "Media types didn't match.\n"); + FreeMediaType(&mt); + + init_pcm_mt(&req_mt, &req_format, 1, 32000, 16); + hr = IPin_QueryAccept(source, &req_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + init_pcm_mt(&req_mt, &req_format, 1, 32000, 8); + hr = IPin_QueryAccept(source, &req_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + init_pcm_mt(&req_mt, &req_format, 1, 32000, 16); + req_mt.formattype = GUID_NULL; + hr = IPin_QueryAccept(source, &req_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + init_pcm_mt(&req_mt, &req_format, 2, 32000, 16); + hr = IPin_QueryAccept(source, &req_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + init_pcm_mt(&req_mt, &req_format, 1, 16000, 16); + hr = IPin_QueryAccept(source, &req_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + init_pcm_mt(&req_mt, &req_format, 1, 32000, 24); + hr = IPin_QueryAccept(source, &req_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + hr = IPin_QueryAccept(source, &pcm16ex_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + init_pcm_mt(&req_mt, &req_format, 1, 32000, 16); + req_format.nAvgBytesPerSec = 333; + hr = IPin_QueryAccept(source, &req_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + init_pcm_mt(&req_mt, &req_format, 1, 32000, 16); + req_format.nBlockAlign = 333; + hr = IPin_QueryAccept(source, &req_mt); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + init_pcm_mt(&req_mt, &req_format, 1, 32000, 16); + req_mt.majortype = GUID_NULL; + hr = IPin_QueryAccept(source, &req_mt); + todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + init_pcm_mt(&req_mt, &req_format, 1, 32000, 16); + req_mt.subtype = GUID_NULL; + hr = IPin_QueryAccept(source, &req_mt); + todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + + hr = IMediaControl_Pause(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + hr = IFilterGraph2_Disconnect(graph, sink); + ok(hr == VFW_E_NOT_STOPPED, "Got hr %#lx.\n", hr); + hr = IMediaControl_Stop(control); + ok(hr == S_OK, "Got hr %#lx.\n", hr); + + IMemInputPin_Release(meminput); + IPin_Release(sink); + IPin_Release(source); + IMediaControl_Release(control); + ref = IFilterGraph2_Release(graph); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ref = IBaseFilter_Release(filter); + ok(!ref, "Got outstanding refcount %ld.\n", ref); + ref = IBaseFilter_Release(&testsource.filter.IBaseFilter_iface); + ok(!ref, "Got outstanding refcount %ld.\n", ref); +} + START_TEST(mpeglayer3) { IBaseFilter *filter; @@ -761,6 +976,7 @@ START_TEST(mpeglayer3) test_pin_info(); test_enum_media_types(); test_media_types(); + test_connect_pin();
CoUninitialize(); }
From: Anton Baskanov baskanov@gmail.com
Signed-off-by: Anton Baskanov baskanov@gmail.com --- dlls/quartz/tests/mpeglayer3.c | 6 +++--- dlls/winegstreamer/quartz_transform.c | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/dlls/quartz/tests/mpeglayer3.c b/dlls/quartz/tests/mpeglayer3.c index 4f06c3ec58e..be4a1dfa97f 100644 --- a/dlls/quartz/tests/mpeglayer3.c +++ b/dlls/quartz/tests/mpeglayer3.c @@ -767,7 +767,7 @@ static void test_media_types(void)
init_pcm_mt(&mt, &format, 1, 32000, 16); hr = IPin_QueryAccept(pin, &mt); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
IPin_Release(pin);
@@ -928,12 +928,12 @@ static void test_connect_pin(void) init_pcm_mt(&req_mt, &req_format, 1, 32000, 16); req_mt.majortype = GUID_NULL; hr = IPin_QueryAccept(source, &req_mt); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
init_pcm_mt(&req_mt, &req_format, 1, 32000, 16); req_mt.subtype = GUID_NULL; hr = IPin_QueryAccept(source, &req_mt); - todo_wine ok(hr == S_FALSE, "Got hr %#lx.\n", hr); + ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
hr = IMediaControl_Pause(control); ok(hr == S_OK, "Got hr %#lx.\n", hr); diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c index 0956f844bd7..db2c5f69a5b 100644 --- a/dlls/winegstreamer/quartz_transform.c +++ b/dlls/winegstreamer/quartz_transform.c @@ -754,6 +754,13 @@ static HRESULT mpeg_layer3_decoder_sink_query_accept(struct transform *filter, c
static HRESULT mpeg_layer3_decoder_source_query_accept(struct transform *filter, const AM_MEDIA_TYPE *mt) { + if (!filter->sink.pin.peer) + return S_FALSE; + + if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio) + || !IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_PCM)) + return S_FALSE; + return S_OK; }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=125383
Your paranoid android.
=== debian11 (32 bit report) ===
dxva2: dxva2: Timeout
evr: evr: Timeout
explorerframe: nstc: Timeout taskbarlist: Timeout
gameux: gameexplorer: Timeout gamestatistics: Timeout
gdi32: bitmap: Timeout brush: Timeout clipping: Timeout dc: Timeout dib: Timeout driver: Timeout font: Timeout gdiobj: Timeout icm: Timeout mapping: Timeout metafile: Timeout palette: Timeout path: Timeout pen: Timeout
gdiplus: brush: Timeout font: Timeout graphics: Timeout
Report validation errors: graphicspath: Timeout
=== debian11 (build log) ===
WineRunWineTest.pl:error: The task timed out
This merge request was approved by Zebediah Figura.