acm_remixing.cc (4294B)
1 /* 2 * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "modules/audio_coding/acm2/acm_remixing.h" 12 13 #include <algorithm> 14 #include <cstddef> 15 #include <cstdint> 16 #include <vector> 17 18 #include "api/array_view.h" 19 #include "api/audio/audio_frame.h" 20 #include "rtc_base/checks.h" 21 #include "rtc_base/numerics/safe_conversions.h" 22 23 namespace webrtc { 24 25 void DownMixFrame(const AudioFrame& input, ArrayView<int16_t> output) { 26 RTC_DCHECK_EQ(input.num_channels_, 2); 27 RTC_DCHECK_EQ(output.size(), input.samples_per_channel_); 28 29 if (input.muted()) { 30 std::fill(output.begin(), output.begin() + input.samples_per_channel_, 0); 31 } else { 32 const int16_t* const input_data = input.data(); 33 for (size_t n = 0; n < input.samples_per_channel_; ++n) { 34 output[n] = dchecked_cast<int16_t>( 35 (int32_t{input_data[2 * n]} + int32_t{input_data[2 * n + 1]}) >> 1); 36 } 37 } 38 } 39 40 void ReMixFrame(const AudioFrame& input, 41 size_t num_output_channels, 42 std::vector<int16_t>* output) { 43 const size_t output_size = num_output_channels * input.samples_per_channel_; 44 RTC_DCHECK(!(input.num_channels_ == 0 && num_output_channels > 0 && 45 input.samples_per_channel_ > 0)); 46 47 if (output->size() != output_size) { 48 output->resize(output_size); 49 } 50 51 // For muted frames, fill the frame with zeros. 52 if (input.muted()) { 53 std::fill(output->begin(), output->end(), 0); 54 return; 55 } 56 57 // Ensure that the special case of zero input channels is handled correctly 58 // (zero samples per channel is already handled correctly in the code below). 59 if (input.num_channels_ == 0) { 60 return; 61 } 62 63 const int16_t* const input_data = input.data(); 64 size_t out_index = 0; 65 66 // When upmixing is needed and the input is mono copy the left channel 67 // into the left and right channels, and set any remaining channels to zero. 68 if (input.num_channels_ == 1 && input.num_channels_ < num_output_channels) { 69 for (size_t k = 0; k < input.samples_per_channel_; ++k) { 70 (*output)[out_index++] = input_data[k]; 71 (*output)[out_index++] = input_data[k]; 72 for (size_t j = 2; j < num_output_channels; ++j) { 73 (*output)[out_index++] = 0; 74 } 75 RTC_DCHECK_EQ(out_index, (k + 1) * num_output_channels); 76 } 77 RTC_DCHECK_EQ(out_index, input.samples_per_channel_ * num_output_channels); 78 return; 79 } 80 81 size_t in_index = 0; 82 83 // When upmixing is needed and the output is surround, copy the available 84 // channels directly, and set the remaining channels to zero. 85 if (input.num_channels_ < num_output_channels) { 86 for (size_t k = 0; k < input.samples_per_channel_; ++k) { 87 for (size_t j = 0; j < input.num_channels_; ++j) { 88 (*output)[out_index++] = input_data[in_index++]; 89 } 90 for (size_t j = input.num_channels_; j < num_output_channels; ++j) { 91 (*output)[out_index++] = 0; 92 } 93 RTC_DCHECK_EQ(in_index, (k + 1) * input.num_channels_); 94 RTC_DCHECK_EQ(out_index, (k + 1) * num_output_channels); 95 } 96 RTC_DCHECK_EQ(in_index, input.samples_per_channel_ * input.num_channels_); 97 RTC_DCHECK_EQ(out_index, input.samples_per_channel_ * num_output_channels); 98 99 return; 100 } 101 102 // When downmixing is needed, and the input is stereo, average the channels. 103 if (input.num_channels_ == 2) { 104 for (size_t n = 0; n < input.samples_per_channel_; ++n) { 105 (*output)[n] = dchecked_cast<int16_t>( 106 (int32_t{input_data[2 * n]} + int32_t{input_data[2 * n + 1]}) >> 1); 107 } 108 return; 109 } 110 111 // When downmixing is needed, and the input is multichannel, drop the surplus 112 // channels. 113 const size_t num_channels_to_drop = input.num_channels_ - num_output_channels; 114 for (size_t k = 0; k < input.samples_per_channel_; ++k) { 115 for (size_t j = 0; j < num_output_channels; ++j) { 116 (*output)[out_index++] = input_data[in_index++]; 117 } 118 in_index += num_channels_to_drop; 119 } 120 } 121 122 } // namespace webrtc