// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // MSVC++ requires this to be set before any other includes to get M_SQRT1_2. #define _USE_MATH_DEFINES #include "media/base/channel_mixing_matrix.h" #include #include #include "base/macros.h" #include "base/strings/stringprintf.h" #include "testing/gtest/include/gtest/gtest.h" namespace media { // Test all possible layout conversions can be constructed and mixed. TEST(ChannelMixingMatrixTest, ConstructAllPossibleLayouts) { for (ChannelLayout input_layout = CHANNEL_LAYOUT_MONO; input_layout <= CHANNEL_LAYOUT_MAX; input_layout = static_cast(input_layout + 1)) { for (ChannelLayout output_layout = CHANNEL_LAYOUT_MONO; output_layout <= CHANNEL_LAYOUT_MAX; output_layout = static_cast(output_layout + 1)) { // DISCRETE can't be tested here based on the current approach. // CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC is not mixable. // Stereo down mix should never be the output layout. if (input_layout == CHANNEL_LAYOUT_DISCRETE || input_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC || output_layout == CHANNEL_LAYOUT_DISCRETE || output_layout == CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC || output_layout == CHANNEL_LAYOUT_STEREO_DOWNMIX) { continue; } SCOPED_TRACE(base::StringPrintf( "Input Layout: %d, Output Layout: %d", input_layout, output_layout)); ChannelMixingMatrix matrix_builder( input_layout, ChannelLayoutToChannelCount(input_layout), output_layout, ChannelLayoutToChannelCount(output_layout)); std::vector> matrix; matrix_builder.CreateTransformationMatrix(&matrix); } } } // Verify channels are mixed and scaled correctly. TEST(ChannelMixingMatrixTest, StereoToMono) { ChannelLayout input_layout = CHANNEL_LAYOUT_STEREO; ChannelLayout output_layout = CHANNEL_LAYOUT_MONO; ChannelMixingMatrix matrix_builder( input_layout, ChannelLayoutToChannelCount(input_layout), output_layout, ChannelLayoutToChannelCount(output_layout)); std::vector> matrix; bool remapping = matrix_builder.CreateTransformationMatrix(&matrix); // Input: stereo // LEFT RIGHT // Output: mono CENTER 0.5 0.5 // EXPECT_FALSE(remapping); EXPECT_EQ(1u, matrix.size()); EXPECT_EQ(2u, matrix[0].size()); EXPECT_EQ(0.5f, matrix[0][0]); EXPECT_EQ(0.5f, matrix[0][1]); } TEST(ChannelMixingMatrixTest, MonoToStereo) { ChannelLayout input_layout = CHANNEL_LAYOUT_MONO; ChannelLayout output_layout = CHANNEL_LAYOUT_STEREO; ChannelMixingMatrix matrix_builder( input_layout, ChannelLayoutToChannelCount(input_layout), output_layout, ChannelLayoutToChannelCount(output_layout)); std::vector> matrix; bool remapping = matrix_builder.CreateTransformationMatrix(&matrix); // Input: mono // CENTER // Output: stereo LEFT 1 // RIGHT 1 // EXPECT_TRUE(remapping); EXPECT_EQ(2u, matrix.size()); EXPECT_EQ(1u, matrix[0].size()); EXPECT_EQ(1.0f, matrix[0][0]); EXPECT_EQ(1u, matrix[1].size()); EXPECT_EQ(1.0f, matrix[1][0]); } TEST(ChannelMixingMatrixTest, FiveOneToMono) { ChannelLayout input_layout = CHANNEL_LAYOUT_5_1; ChannelLayout output_layout = CHANNEL_LAYOUT_MONO; ChannelMixingMatrix matrix_builder( input_layout, ChannelLayoutToChannelCount(input_layout), output_layout, ChannelLayoutToChannelCount(output_layout)); std::vector> matrix; bool remapping = matrix_builder.CreateTransformationMatrix(&matrix); // Note: 1/sqrt(2) is shown as 0.707. // // Input: 5.1 // LEFT RIGHT CENTER LFE SIDE_LEFT SIDE_RIGHT // Output: mono CENTER 0.707 0.707 1 0.707 0.707 0.707 // EXPECT_FALSE(remapping); EXPECT_EQ(1u, matrix.size()); EXPECT_EQ(6u, matrix[0].size()); EXPECT_FLOAT_EQ(static_cast(M_SQRT1_2), matrix[0][0]); EXPECT_FLOAT_EQ(static_cast(M_SQRT1_2), matrix[0][1]); // The center channel will be mixed at scale 1. EXPECT_EQ(1.0f, matrix[0][2]); EXPECT_FLOAT_EQ(static_cast(M_SQRT1_2), matrix[0][3]); EXPECT_FLOAT_EQ(static_cast(M_SQRT1_2), matrix[0][4]); EXPECT_FLOAT_EQ(static_cast(M_SQRT1_2), matrix[0][5]); } TEST(ChannelMixingMatrixTest, DiscreteToDiscrete) { const struct { int input_channels; int output_channels; } test_case[] = { {2, 2}, {2, 5}, {5, 2}, }; for (size_t n = 0; n < arraysize(test_case); n++) { int input_channels = test_case[n].input_channels; int output_channels = test_case[n].output_channels; ChannelMixingMatrix matrix_builder(CHANNEL_LAYOUT_DISCRETE, input_channels, CHANNEL_LAYOUT_DISCRETE, output_channels); std::vector> matrix; bool remapping = matrix_builder.CreateTransformationMatrix(&matrix); EXPECT_TRUE(remapping); EXPECT_EQ(static_cast(output_channels), matrix.size()); for (int i = 0; i < output_channels; i++) { EXPECT_EQ(static_cast(input_channels), matrix[i].size()); for (int j = 0; j < input_channels; j++) { if (i == j) { EXPECT_EQ(1.0f, matrix[i][j]); } else { EXPECT_EQ(0.0f, matrix[i][j]); } } } } } } // namespace media