| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromecast/media/audio/interleaved_channel_mixer.h" |
| |
| #include "base/check_op.h" |
| #include "media/base/channel_mixing_matrix.h" |
| |
| namespace chromecast { |
| namespace media { |
| |
| InterleavedChannelMixer::InterleavedChannelMixer( |
| ::media::ChannelLayout input_layout, |
| int input_channel_count, |
| ::media::ChannelLayout output_layout, |
| int output_channel_count, |
| int max_frames) |
| : input_layout_(input_layout), |
| input_channel_count_(input_channel_count), |
| output_layout_(output_layout), |
| output_channel_count_(output_channel_count), |
| max_frames_(max_frames) { |
| if (input_layout_ == output_layout_) { |
| return; |
| } |
| |
| buffer_.resize(max_frames * output_channel_count_); |
| |
| std::vector<std::vector<float>> matrix; |
| ::media::ChannelMixingMatrix matrix_builder( |
| input_layout_, input_channel_count_, output_layout_, |
| output_channel_count_); |
| matrix_builder.CreateTransformationMatrix(&matrix); |
| |
| transform_.reserve(input_channel_count_ * output_channel_count_); |
| for (const std::vector<float>& output_channel : matrix) { |
| transform_.insert(transform_.end(), output_channel.begin(), |
| output_channel.end()); |
| } |
| } |
| |
| InterleavedChannelMixer::~InterleavedChannelMixer() = default; |
| |
| float* InterleavedChannelMixer::Transform(const float* input, int num_frames) { |
| if (input_layout_ == output_layout_) { |
| return const_cast<float*>(input); |
| } |
| |
| DCHECK_LE(num_frames, max_frames_); |
| // TODO(kmackay) Could use Eigen, but it's not available in public Chromium. |
| float* output = buffer_.data(); |
| for (int f = 0; f < num_frames; ++f) { |
| // For each frame, multiply the row-major transform matrix by the column- |
| // major interleaved input. |
| float* t = transform_.data(); |
| for (int out_c = 0; out_c < output_channel_count_; ++out_c) { |
| // Each channel of the output frame is the current transform row times |
| // the input frame. |
| float result = 0; |
| for (int in_c = 0; in_c < input_channel_count_; ++in_c) { |
| result += *t * input[in_c]; |
| ++t; |
| } |
| *output = result; |
| ++output; |
| } |
| // Move to next input frame. |
| input += input_channel_count_; |
| } |
| |
| return buffer_.data(); |
| } |
| |
| } // namespace media |
| } // namespace chromecast |