-- v2: winegstreamer: Also return output with 2 channels for multichannel inputs from AAC decoder. winegstreamer: Validate maximum channel count in _SetInputType in AAC decoder. winegstreamer: Correct output available types attrs in AAC decoder for channel count > 2. winegstreamer: Handle missing or zero channel count in _GetOutputAvailableType in AAC decoder. mf/tests: Add tests for AAC decoder with different input number of channels.
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/tests/transform.c | 168 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 87dcf7f0814..e6ccb98e9ed 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -36,6 +36,8 @@ #include "mediaerr.h" #include "amvideo.h" #include "vfw.h" +#include "ks.h" +#include "ksmedia.h"
#include "mf_test.h"
@@ -2487,6 +2489,169 @@ failed: CoUninitialize(); }
+static void test_aac_decoder_channels(const struct attribute_desc *input_type_desc) +{ + static const struct attribute_desc expect_output_attributes[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100), + ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1), + {0}, + }; + static const media_type_desc expect_available_outputs[] = + { + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_Float), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 32), + }, + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio), + ATTR_GUID(MF_MT_SUBTYPE, MFAudioFormat_PCM), + ATTR_UINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16), + }, + }; + static const UINT32 expected_mask[7] = + { + 0, + 0, + 0, + SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_CENTER, + KSAUDIO_SPEAKER_QUAD, + KSAUDIO_SPEAKER_QUAD | SPEAKER_FRONT_CENTER, + KSAUDIO_SPEAKER_5POINT1, + }; + + UINT32 value, num_channels, expected_chans, format_index, sample_size; + unsigned int num_channels_index = ~0u; + struct attribute_desc input_desc[64]; + IMFTransform *transform; + IMFAttributes *attrs; + IMFMediaType *type; + BOOL many_channels; + ULONG i, ret; + HRESULT hr; + + for (i = 0; i < ARRAY_SIZE(input_desc); i++) + { + input_desc[i] = input_type_desc[i]; + if (!input_desc[i].key) + break; + if (IsEqualGUID(input_desc[i].key, &MF_MT_AUDIO_NUM_CHANNELS)) + num_channels_index = i; + } + + ok(num_channels_index != ~0u, "Could not find MF_MT_AUDIO_NUM_CHANNELS.\n"); + ok(i < ARRAY_SIZE(input_desc), "Too many attributes.\n"); + + hr = CoInitialize(NULL); + ok(hr == S_OK, "got %#lx.\n", hr); + winetest_push_context("aacdec channels"); + + if (FAILED(hr = CoCreateInstance(&CLSID_MSAACDecMFT, NULL, CLSCTX_INPROC_SERVER, + &IID_IMFTransform, (void **)&transform))) + { + win_skip("AAC decoder transform is not available.\n"); + goto failed; + } + + for (num_channels = 0; num_channels < 16; ++num_channels) + { + many_channels = num_channels > 2; + winetest_push_context("chans %u", num_channels); + input_desc[num_channels_index].value.ulVal = num_channels; + + hr = MFCreateMediaType(&type); + ok(hr == S_OK, "got %#lx.\n", hr); + init_media_type(type, input_desc, -1); + hr = IMFTransform_SetInputType(transform, 0, type, 0); + IMFMediaType_Release(type); + if (num_channels <= 6) + ok(hr == S_OK, "got %#lx.\n", hr); + else + { + todo_wine ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx.\n", hr); + winetest_pop_context(); + continue; + } + + i = -1; + while (SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, ++i, &type))) + { + winetest_push_context("out %lu", i); + ok(hr == S_OK, "got %#lx.\n", hr); + check_media_type(type, expect_output_attributes, -1); + format_index = i % 2; + sample_size = format_index ? 2 : 4; + check_media_type(type, expect_available_outputs[format_index], -1); + attrs = (IMFAttributes *)type; + + hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_NUM_CHANNELS, &value); + ok(hr == S_OK, "got %#lx.\n", hr); + if (!num_channels || i >= ARRAY_SIZE(expect_available_outputs)) + expected_chans = 2; + else + expected_chans = num_channels; + todo_wine_if(!num_channels) + ok(value == expected_chans, "got %u, expected %u.\n", value, expected_chans); + + hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value); + ok(hr == S_OK, "got %#lx.\n", hr); + todo_wine_if(!num_channels) + ok(value == sample_size * 44100 * expected_chans, "got %u, expected %u.\n", + value, sample_size * 44100 * expected_chans); + + hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value); + ok(hr == S_OK, "got %#lx.\n", hr); + todo_wine_if(!num_channels) + ok(value == sample_size * expected_chans, "got %u, expected %u.\n", value, sample_size * expected_chans); + + hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &value); + if (many_channels && i < ARRAY_SIZE(expect_available_outputs)) + { + todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); + } + else + { + ok(hr == S_OK, "got %#lx.\n", hr); + ok(value == 1, "got %u.\n", value); + } + + value = 0xdeadbeef; + hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, &value); + if (expected_chans <= 2) + { + ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); + } + else + { + todo_wine { + ok(hr == S_OK, "got %#lx.\n", hr); + ok(value == expected_mask[expected_chans], "got %#x, expected %#x.\n", + value, expected_mask[expected_chans]); + } + } + + ret = IMFMediaType_Release(type); + ok(ret <= 1, "got %lu.\n", ret); + winetest_pop_context(); + } + ok(hr == MF_E_NO_MORE_TYPES, "got %#lx.\n", hr); + if (many_channels) + todo_wine ok(i == ARRAY_SIZE(expect_available_outputs) * 2, "got %lu media types.\n", i); + else + ok(i == ARRAY_SIZE(expect_available_outputs), "got %lu media types.\n", i); + winetest_pop_context(); + } + + ret = IMFTransform_Release(transform); + ok(!ret, "got %lu.\n", ret); + +failed: + winetest_pop_context(); + CoUninitialize(); +} + static void test_aac_decoder(void) { static const BYTE aac_raw_codec_data[] = {0x12, 0x08}; @@ -2515,6 +2680,9 @@ static void test_aac_decoder(void)
test_aac_decoder_subtype(aac_input_type_desc); test_aac_decoder_subtype(raw_aac_input_type_desc); + + test_aac_decoder_channels(aac_input_type_desc); + test_aac_decoder_channels(raw_aac_input_type_desc); }
static const BYTE wma_codec_data[10] = {0, 0x44, 0, 0, 0x17, 0, 0, 0, 0, 0};
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/tests/transform.c | 19 ++++++++++++++++--- dlls/winegstreamer/aac_decoder.c | 6 ++++-- 2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index e6ccb98e9ed..02eaab25f14 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2555,6 +2555,22 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de goto failed; }
+ hr = MFCreateMediaType(&type); + ok(hr == S_OK, "got %#lx.\n", hr); + input_desc[num_channels_index].value.vt = VT_UI8; + input_desc[num_channels_index].value.ulVal = 1; + init_media_type(type, input_desc, -1); + hr = IMFTransform_SetInputType(transform, 0, type, 0); + ok(hr == S_OK, "got %#lx.\n", hr); + IMFMediaType_Release(type); + hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &type); + ok(hr == S_OK, "got %#lx.\n", hr); + hr = IMFAttributes_GetUINT32((IMFAttributes *)type, &MF_MT_AUDIO_NUM_CHANNELS, &value); + ok(hr == S_OK, "got %#lx.\n", hr); + ok(value == 2, "got %u.\n", value); + IMFMediaType_Release(type); + input_desc[num_channels_index].value.vt = VT_UI4; + for (num_channels = 0; num_channels < 16; ++num_channels) { many_channels = num_channels > 2; @@ -2592,18 +2608,15 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de expected_chans = 2; else expected_chans = num_channels; - todo_wine_if(!num_channels) ok(value == expected_chans, "got %u, expected %u.\n", value, expected_chans);
hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &value); ok(hr == S_OK, "got %#lx.\n", hr); - todo_wine_if(!num_channels) ok(value == sample_size * 44100 * expected_chans, "got %u, expected %u.\n", value, sample_size * 44100 * expected_chans);
hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &value); ok(hr == S_OK, "got %#lx.\n", hr); - todo_wine_if(!num_channels) ok(value == sample_size * expected_chans, "got %u, expected %u.\n", value, sample_size * expected_chans);
hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &value); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 3588d00a28c..ea03d95305b 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -291,6 +291,10 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR
*type = NULL;
+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count)) + || !channel_count) + channel_count = 2; + if (index >= ARRAY_SIZE(aac_decoder_output_types)) return MF_E_NO_MORE_TYPES; index = ARRAY_SIZE(aac_decoder_output_types) - index - 1; @@ -318,8 +322,6 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size))) goto done;
- if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))) - goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channel_count))) goto done;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/tests/transform.c | 4 +--- dlls/winegstreamer/aac_decoder.c | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 02eaab25f14..eadde5237f0 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2622,7 +2622,7 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de hr = IMFAttributes_GetUINT32(attrs, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &value); if (many_channels && i < ARRAY_SIZE(expect_available_outputs)) { - todo_wine ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); + ok(hr == MF_E_ATTRIBUTENOTFOUND, "got %#lx.\n", hr); } else { @@ -2638,11 +2638,9 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de } else { - todo_wine { ok(hr == S_OK, "got %#lx.\n", hr); ok(value == expected_mask[expected_chans], "got %#x, expected %#x.\n", value, expected_mask[expected_chans]); - } }
ret = IMFMediaType_Release(type); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index ea03d95305b..cdd4cc18477 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -24,6 +24,8 @@ #include "mfobjects.h" #include "mftransform.h" #include "wmcodecdsp.h" +#include "ks.h" +#include "ksmedia.h"
#include "wine/debug.h"
@@ -48,6 +50,17 @@ static const GUID *const aac_decoder_output_types[] = &MFAudioFormat_Float, };
+static const UINT32 default_channel_mask[7] = +{ + 0, + 0, + 0, + SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_CENTER, + KSAUDIO_SPEAKER_QUAD, + KSAUDIO_SPEAKER_QUAD | SPEAKER_FRONT_CENTER, + KSAUDIO_SPEAKER_5POINT1, +}; + struct aac_decoder { IMFTransform IMFTransform_iface; @@ -295,6 +308,9 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR || !channel_count) channel_count = 2;
+ if (channel_count >= ARRAY_SIZE(default_channel_mask)) + return MF_E_INVALIDMEDIATYPE; + if (index >= ARRAY_SIZE(aac_decoder_output_types)) return MF_E_NO_MORE_TYPES; index = ARRAY_SIZE(aac_decoder_output_types) - index - 1; @@ -340,7 +356,10 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR goto done; if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1))) goto done; - if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1))) + if (channel_count < 3 && FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1))) + goto done; + if (channel_count >= 3 && FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_CHANNEL_MASK, + default_channel_mask[channel_count]))) goto done;
done:
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/tests/transform.c | 2 +- dlls/winegstreamer/aac_decoder.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index eadde5237f0..787f7663d84 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2586,7 +2586,7 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de ok(hr == S_OK, "got %#lx.\n", hr); else { - todo_wine ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx.\n", hr); + ok(hr == MF_E_INVALIDMEDIATYPE, "got %#lx.\n", hr); winetest_pop_context(); continue; } diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index cdd4cc18477..35689a49c38 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -374,6 +374,7 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM { struct aac_decoder *decoder = impl_from_IMFTransform(iface); MF_ATTRIBUTE_TYPE item_type; + UINT32 channel_count; GUID major, subtype; HRESULT hr; ULONG i; @@ -396,6 +397,10 @@ static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFM if (i == ARRAY_SIZE(aac_decoder_input_types)) return MF_E_INVALIDMEDIATYPE;
+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count)) + && channel_count >= ARRAY_SIZE(default_channel_mask)) + return MF_E_INVALIDMEDIATYPE; + if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) || item_type != MF_ATTRIBUTE_UINT32) return MF_E_INVALIDMEDIATYPE;
From: Paul Gofman pgofman@codeweavers.com
--- dlls/mf/tests/transform.c | 2 +- dlls/winegstreamer/aac_decoder.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c index 787f7663d84..c5ef1f5960a 100644 --- a/dlls/mf/tests/transform.c +++ b/dlls/mf/tests/transform.c @@ -2649,7 +2649,7 @@ static void test_aac_decoder_channels(const struct attribute_desc *input_type_de } ok(hr == MF_E_NO_MORE_TYPES, "got %#lx.\n", hr); if (many_channels) - todo_wine ok(i == ARRAY_SIZE(expect_available_outputs) * 2, "got %lu media types.\n", i); + ok(i == ARRAY_SIZE(expect_available_outputs) * 2, "got %lu media types.\n", i); else ok(i == ARRAY_SIZE(expect_available_outputs), "got %lu media types.\n", i); winetest_pop_context(); diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c index 35689a49c38..3eb96d0106a 100644 --- a/dlls/winegstreamer/aac_decoder.c +++ b/dlls/winegstreamer/aac_decoder.c @@ -311,6 +311,14 @@ static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWOR if (channel_count >= ARRAY_SIZE(default_channel_mask)) return MF_E_INVALIDMEDIATYPE;
+ if (channel_count > 2 && index >= ARRAY_SIZE(aac_decoder_output_types)) + { + /* If there are more than two channels in the input type GetOutputAvailableType additionally lists + * types with 2 channels. */ + index -= ARRAY_SIZE(aac_decoder_output_types); + channel_count = 2; + } + if (index >= ARRAY_SIZE(aac_decoder_output_types)) return MF_E_NO_MORE_TYPES; index = ARRAY_SIZE(aac_decoder_output_types) - index - 1;
This merge request was approved by Rémi Bernon.
This merge request was approved by Zebediah Figura.