Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(126)

Side by Side Diff: media/base/channel_mixing_matrix.cc

Issue 672793002: Expose the internal MatrixBuilder class as ChannelMixingMatrix. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: List expected_value first in ASSERT_FLOAT_EQ Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/base/channel_mixing_matrix.h ('k') | media/base/channel_mixing_matrix_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // MSVC++ requires this to be set before any other includes to get M_SQRT1_2. 5 // MSVC++ requires this to be set before any other includes to get M_SQRT1_2.
6 #define _USE_MATH_DEFINES 6 #define _USE_MATH_DEFINES
7 7
8 #include "media/base/channel_mixer.h" 8 #include "media/base/channel_mixing_matrix.h"
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <cmath> 11 #include <cmath>
12 12
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "media/audio/audio_parameters.h"
15 #include "media/base/audio_bus.h"
16 #include "media/base/vector_math.h"
17 14
18 namespace media { 15 namespace media {
19 16
20 // Default scale factor for mixing two channels together. We use a different 17 // Default scale factor for mixing two channels together. We use a different
21 // value for stereo -> mono and mono -> stereo mixes. 18 // value for stereo -> mono and mono -> stereo mixes.
22 static const float kEqualPowerScale = static_cast<float>(M_SQRT1_2); 19 static const float kEqualPowerScale = static_cast<float>(M_SQRT1_2);
23 20
24 static void ValidateLayout(ChannelLayout layout) { 21 static void ValidateLayout(ChannelLayout layout) {
25 CHECK_NE(layout, CHANNEL_LAYOUT_NONE); 22 CHECK_NE(layout, CHANNEL_LAYOUT_NONE);
26 CHECK_LE(layout, CHANNEL_LAYOUT_MAX); 23 CHECK_LE(layout, CHANNEL_LAYOUT_MAX);
(...skipping 18 matching lines...) Expand all
45 ChannelOrder(layout, SIDE_RIGHT) >= 0); 42 ChannelOrder(layout, SIDE_RIGHT) >= 0);
46 DCHECK_EQ(ChannelOrder(layout, BACK_LEFT) >= 0, 43 DCHECK_EQ(ChannelOrder(layout, BACK_LEFT) >= 0,
47 ChannelOrder(layout, BACK_RIGHT) >= 0); 44 ChannelOrder(layout, BACK_RIGHT) >= 0);
48 DCHECK_EQ(ChannelOrder(layout, LEFT_OF_CENTER) >= 0, 45 DCHECK_EQ(ChannelOrder(layout, LEFT_OF_CENTER) >= 0,
49 ChannelOrder(layout, RIGHT_OF_CENTER) >= 0); 46 ChannelOrder(layout, RIGHT_OF_CENTER) >= 0);
50 } else { 47 } else {
51 DCHECK_EQ(layout, CHANNEL_LAYOUT_MONO); 48 DCHECK_EQ(layout, CHANNEL_LAYOUT_MONO);
52 } 49 }
53 } 50 }
54 51
55 class MatrixBuilder { 52 ChannelMixingMatrix::ChannelMixingMatrix(ChannelLayout input_layout,
56 public: 53 int input_channels,
57 MatrixBuilder(ChannelLayout input_layout, int input_channels, 54 ChannelLayout output_layout,
58 ChannelLayout output_layout, int output_channels) 55 int output_channels)
59 : input_layout_(input_layout), 56 : input_layout_(input_layout),
60 input_channels_(input_channels), 57 input_channels_(input_channels),
61 output_layout_(output_layout), 58 output_layout_(output_layout),
62 output_channels_(output_channels) { 59 output_channels_(output_channels) {
63 // Special case for 5.0, 5.1 with back channels when upmixed to 7.0, 7.1,
64 // which should map the back LR to side LR.
65 if (input_layout_ == CHANNEL_LAYOUT_5_0_BACK &&
66 output_layout_ == CHANNEL_LAYOUT_7_0) {
67 input_layout_ = CHANNEL_LAYOUT_5_0;
68 } else if (input_layout_ == CHANNEL_LAYOUT_5_1_BACK &&
69 output_layout_ == CHANNEL_LAYOUT_7_1) {
70 input_layout_ = CHANNEL_LAYOUT_5_1;
71 }
72 }
73
74 ~MatrixBuilder() { }
75
76 // Create the transformation matrix of input channels to output channels.
77 // Updates the empty matrix with the transformation, and returns true
78 // if the transformation is just a remapping of channels (no mixing).
79 bool CreateTransformationMatrix(std::vector< std::vector<float> >* matrix);
80
81 private:
82 // Result transformation of input channels to output channels
83 std::vector< std::vector<float> >* matrix_;
84
85 // Input and output channel layout provided during construction.
86 ChannelLayout input_layout_;
87 int input_channels_;
88 ChannelLayout output_layout_;
89 int output_channels_;
90
91 // Helper variable for tracking which inputs are currently unaccounted,
92 // should be empty after construction completes.
93 std::vector<Channels> unaccounted_inputs_;
94
95 // Helper methods for managing unaccounted input channels.
96 void AccountFor(Channels ch);
97 bool IsUnaccounted(Channels ch) const;
98
99 // Helper methods for checking if |ch| exists in either |input_layout_| or
100 // |output_layout_| respectively.
101 bool HasInputChannel(Channels ch) const;
102 bool HasOutputChannel(Channels ch) const;
103
104 // Helper methods for updating |matrix_| with the proper value for
105 // mixing |input_ch| into |output_ch|. MixWithoutAccounting() does not
106 // remove the channel from |unaccounted_inputs_|.
107 void Mix(Channels input_ch, Channels output_ch, float scale);
108 void MixWithoutAccounting(Channels input_ch, Channels output_ch, float scale);
109
110 DISALLOW_COPY_AND_ASSIGN(MatrixBuilder);
111 };
112
113 ChannelMixer::ChannelMixer(ChannelLayout input_layout,
114 ChannelLayout output_layout) {
115 Initialize(input_layout,
116 ChannelLayoutToChannelCount(input_layout),
117 output_layout,
118 ChannelLayoutToChannelCount(output_layout));
119 }
120
121 ChannelMixer::ChannelMixer(
122 const AudioParameters& input, const AudioParameters& output) {
123 Initialize(input.channel_layout(),
124 input.channels(),
125 output.channel_layout(),
126 output.channels());
127 }
128
129 void ChannelMixer::Initialize(
130 ChannelLayout input_layout, int input_channels,
131 ChannelLayout output_layout, int output_channels) {
132 // Stereo down mix should never be the output layout. 60 // Stereo down mix should never be the output layout.
133 CHECK_NE(output_layout, CHANNEL_LAYOUT_STEREO_DOWNMIX); 61 CHECK_NE(output_layout, CHANNEL_LAYOUT_STEREO_DOWNMIX);
134 62
135 // Verify that the layouts are supported 63 // Verify that the layouts are supported
136 if (input_layout != CHANNEL_LAYOUT_DISCRETE) 64 if (input_layout != CHANNEL_LAYOUT_DISCRETE)
137 ValidateLayout(input_layout); 65 ValidateLayout(input_layout);
138 if (output_layout != CHANNEL_LAYOUT_DISCRETE) 66 if (output_layout != CHANNEL_LAYOUT_DISCRETE)
139 ValidateLayout(output_layout); 67 ValidateLayout(output_layout);
140 68
141 // Create the transformation matrix 69 // Special case for 5.0, 5.1 with back channels when upmixed to 7.0, 7.1,
142 MatrixBuilder matrix_builder(input_layout, input_channels, 70 // which should map the back LR to side LR.
143 output_layout, output_channels); 71 if (input_layout_ == CHANNEL_LAYOUT_5_0_BACK &&
144 remapping_ = matrix_builder.CreateTransformationMatrix(&matrix_); 72 output_layout_ == CHANNEL_LAYOUT_7_0) {
73 input_layout_ = CHANNEL_LAYOUT_5_0;
74 } else if (input_layout_ == CHANNEL_LAYOUT_5_1_BACK &&
75 output_layout_ == CHANNEL_LAYOUT_7_1) {
76 input_layout_ = CHANNEL_LAYOUT_5_1;
77 }
145 } 78 }
146 79
147 bool MatrixBuilder::CreateTransformationMatrix( 80 ChannelMixingMatrix::~ChannelMixingMatrix() {
148 std::vector< std::vector<float> >* matrix) { 81 }
82
83 bool ChannelMixingMatrix::CreateTransformationMatrix(
84 std::vector<std::vector<float>>* matrix) {
149 matrix_ = matrix; 85 matrix_ = matrix;
150 86
151 // Size out the initial matrix. 87 // Size out the initial matrix.
152 matrix_->reserve(output_channels_); 88 matrix_->reserve(output_channels_);
153 for (int output_ch = 0; output_ch < output_channels_; ++output_ch) 89 for (int output_ch = 0; output_ch < output_channels_; ++output_ch)
154 matrix_->push_back(std::vector<float>(input_channels_, 0)); 90 matrix_->push_back(std::vector<float>(input_channels_, 0));
155 91
156 // First check for discrete case. 92 // First check for discrete case.
157 if (input_layout_ == CHANNEL_LAYOUT_DISCRETE || 93 if (input_layout_ == CHANNEL_LAYOUT_DISCRETE ||
158 output_layout_ == CHANNEL_LAYOUT_DISCRETE) { 94 output_layout_ == CHANNEL_LAYOUT_DISCRETE) {
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 // output channel is mapped from a single unscaled input channel. 255 // output channel is mapped from a single unscaled input channel.
320 if ((*matrix_)[output_ch][input_ch] != 1 || ++input_mappings > 1) 256 if ((*matrix_)[output_ch][input_ch] != 1 || ++input_mappings > 1)
321 return false; 257 return false;
322 } 258 }
323 } 259 }
324 260
325 // If we've gotten here, |matrix_| is simply a remapping. 261 // If we've gotten here, |matrix_| is simply a remapping.
326 return true; 262 return true;
327 } 263 }
328 264
329 ChannelMixer::~ChannelMixer() {} 265 void ChannelMixingMatrix::AccountFor(Channels ch) {
330
331 void ChannelMixer::Transform(const AudioBus* input, AudioBus* output) {
332 CHECK_EQ(matrix_.size(), static_cast<size_t>(output->channels()));
333 CHECK_EQ(matrix_[0].size(), static_cast<size_t>(input->channels()));
334 CHECK_EQ(input->frames(), output->frames());
335
336 // Zero initialize |output| so we're accumulating from zero.
337 output->Zero();
338
339 // If we're just remapping we can simply copy the correct input to output.
340 if (remapping_) {
341 for (int output_ch = 0; output_ch < output->channels(); ++output_ch) {
342 for (int input_ch = 0; input_ch < input->channels(); ++input_ch) {
343 float scale = matrix_[output_ch][input_ch];
344 if (scale > 0) {
345 DCHECK_EQ(scale, 1.0f);
346 memcpy(output->channel(output_ch), input->channel(input_ch),
347 sizeof(*output->channel(output_ch)) * output->frames());
348 break;
349 }
350 }
351 }
352 return;
353 }
354
355 for (int output_ch = 0; output_ch < output->channels(); ++output_ch) {
356 for (int input_ch = 0; input_ch < input->channels(); ++input_ch) {
357 float scale = matrix_[output_ch][input_ch];
358 // Scale should always be positive. Don't bother scaling by zero.
359 DCHECK_GE(scale, 0);
360 if (scale > 0) {
361 vector_math::FMAC(input->channel(input_ch), scale, output->frames(),
362 output->channel(output_ch));
363 }
364 }
365 }
366 }
367
368 void MatrixBuilder::AccountFor(Channels ch) {
369 unaccounted_inputs_.erase(std::find( 266 unaccounted_inputs_.erase(std::find(
370 unaccounted_inputs_.begin(), unaccounted_inputs_.end(), ch)); 267 unaccounted_inputs_.begin(), unaccounted_inputs_.end(), ch));
371 } 268 }
372 269
373 bool MatrixBuilder::IsUnaccounted(Channels ch) const { 270 bool ChannelMixingMatrix::IsUnaccounted(Channels ch) const {
374 return std::find(unaccounted_inputs_.begin(), unaccounted_inputs_.end(), 271 return std::find(unaccounted_inputs_.begin(), unaccounted_inputs_.end(),
375 ch) != unaccounted_inputs_.end(); 272 ch) != unaccounted_inputs_.end();
376 } 273 }
377 274
378 bool MatrixBuilder::HasInputChannel(Channels ch) const { 275 bool ChannelMixingMatrix::HasInputChannel(Channels ch) const {
379 return ChannelOrder(input_layout_, ch) >= 0; 276 return ChannelOrder(input_layout_, ch) >= 0;
380 } 277 }
381 278
382 bool MatrixBuilder::HasOutputChannel(Channels ch) const { 279 bool ChannelMixingMatrix::HasOutputChannel(Channels ch) const {
383 return ChannelOrder(output_layout_, ch) >= 0; 280 return ChannelOrder(output_layout_, ch) >= 0;
384 } 281 }
385 282
386 void MatrixBuilder::Mix(Channels input_ch, Channels output_ch, float scale) { 283 void ChannelMixingMatrix::Mix(Channels input_ch,
284 Channels output_ch,
285 float scale) {
387 MixWithoutAccounting(input_ch, output_ch, scale); 286 MixWithoutAccounting(input_ch, output_ch, scale);
388 AccountFor(input_ch); 287 AccountFor(input_ch);
389 } 288 }
390 289
391 void MatrixBuilder::MixWithoutAccounting(Channels input_ch, Channels output_ch, 290 void ChannelMixingMatrix::MixWithoutAccounting(Channels input_ch,
392 float scale) { 291 Channels output_ch,
292 float scale) {
393 int input_ch_index = ChannelOrder(input_layout_, input_ch); 293 int input_ch_index = ChannelOrder(input_layout_, input_ch);
394 int output_ch_index = ChannelOrder(output_layout_, output_ch); 294 int output_ch_index = ChannelOrder(output_layout_, output_ch);
395 295
396 DCHECK(IsUnaccounted(input_ch)); 296 DCHECK(IsUnaccounted(input_ch));
397 DCHECK_GE(input_ch_index, 0); 297 DCHECK_GE(input_ch_index, 0);
398 DCHECK_GE(output_ch_index, 0); 298 DCHECK_GE(output_ch_index, 0);
399 299
400 DCHECK_EQ((*matrix_)[output_ch_index][input_ch_index], 0); 300 DCHECK_EQ((*matrix_)[output_ch_index][input_ch_index], 0);
401 (*matrix_)[output_ch_index][input_ch_index] = scale; 301 (*matrix_)[output_ch_index][input_ch_index] = scale;
402 } 302 }
403 303
404 } // namespace media 304 } // namespace media
OLDNEW
« no previous file with comments | « media/base/channel_mixing_matrix.h ('k') | media/base/channel_mixing_matrix_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698