aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjmarusic@webrtc.org <jmarusic@webrtc.org>2015-03-10 15:41:26 +0000
committerjmarusic@webrtc.org <jmarusic@webrtc.org>2015-03-10 15:42:21 +0000
commit51ccf376387266225cd8c78e63238b725860f0af (patch)
tree685f8abc2ec4711bd60021944abd5fa9f31a2431
parentd7452a016812ab1de69c3d7a53caca5b06c64990 (diff)
downloadwebrtc-51ccf376387266225cd8c78e63238b725860f0af.tar.gz
AudioEncoder: add method MaxEncodedBytes
Added method AudioEncoder::MaxEncodedBytes() and provided implementations in derived encoders. This method returns the number of bytes that can be produced by the encoder at each Encode() call. Unit tests were updated to use the new method. Buffer allocation was not changed in AudioCodingModuleImpl::Encode(). It will be done after additional investigation. Other refactoring work that was done, that may not be obvious why: 1. Moved some code into AudioEncoderCng::EncodePassive() to make it more consistent with EncodeActive(). 2. Changed the order of NumChannels() and RtpTimestampRateHz() declarations in AudioEncoderG722 and AudioEncoderCopyRed classes. It just bothered me that the order was not the same as in AudioEncoder class and its other derived classes. R=kwiberg@webrtc.org Review URL: https://webrtc-codereview.appspot.com/40259005 Cr-Commit-Position: refs/heads/master@{#8671} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8671 4adac7df-926f-26a2-2b94-8c16560cd09d
-rw-r--r--webrtc/modules/audio_coding/codecs/audio_encoder.h8
-rw-r--r--webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc44
-rw-r--r--webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc12
-rw-r--r--webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h7
-rw-r--r--webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc11
-rw-r--r--webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h3
-rw-r--r--webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc18
-rw-r--r--webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h5
-rw-r--r--webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc38
-rw-r--r--webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h3
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h1
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h5
-rw-r--r--webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_red_unittest.cc16
-rw-r--r--webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h1
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc17
-rw-r--r--webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h3
-rw-r--r--webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc4
-rw-r--r--webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h3
-rw-r--r--webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc12
19 files changed, 151 insertions, 60 deletions
diff --git a/webrtc/modules/audio_coding/codecs/audio_encoder.h b/webrtc/modules/audio_coding/codecs/audio_encoder.h
index c0ec2109c3..20ac8b922b 100644
--- a/webrtc/modules/audio_coding/codecs/audio_encoder.h
+++ b/webrtc/modules/audio_coding/codecs/audio_encoder.h
@@ -74,6 +74,14 @@ class AudioEncoder {
virtual int SampleRateHz() const = 0;
virtual int NumChannels() const = 0;
+ // Return the maximum number of bytes that can be produced by the encoder
+ // at each Encode() call. The caller can use the return value to determine
+ // the size of the buffer that needs to be allocated. This value is allowed
+ // to depend on encoder parameters like bitrate, frame size etc., so if
+ // any of these change, the caller of Encode() is responsible for checking
+ // that the buffer is large enough by calling MaxEncodedBytes() again.
+ virtual size_t MaxEncodedBytes() const = 0;
+
// Returns the rate with which the RTP timestamps are updated. By default,
// this is the same as sample_rate_hz().
virtual int RtpTimestampRateHz() const;
diff --git a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc
index 14b210c3ec..d7c1ea013a 100644
--- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc
+++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng.cc
@@ -10,10 +10,17 @@
#include "webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h"
+#include <algorithm>
#include <limits>
namespace webrtc {
+namespace {
+
+const int kMaxFrameSizeMs = 60;
+
+} // namespace
+
AudioEncoderCng::Config::Config()
: num_channels(1),
payload_type(13),
@@ -77,6 +84,13 @@ int AudioEncoderCng::NumChannels() const {
return 1;
}
+size_t AudioEncoderCng::MaxEncodedBytes() const {
+ const size_t max_encoded_bytes_active = speech_encoder_->MaxEncodedBytes();
+ const size_t max_encoded_bytes_passive =
+ rtc::CheckedDivExact(kMaxFrameSizeMs, 10) * SamplesPer10msFrame();
+ return std::max(max_encoded_bytes_active, max_encoded_bytes_passive);
+}
+
int AudioEncoderCng::Num10MsFramesInNextPacket() const {
return speech_encoder_->Num10MsFramesInNextPacket();
}
@@ -114,8 +128,9 @@ void AudioEncoderCng::EncodeInternal(uint32_t rtp_timestamp,
if (frames_in_buffer_ < speech_encoder_->Num10MsFramesInNextPacket()) {
return;
}
- CHECK_LE(frames_in_buffer_, 6)
- << "Frame size cannot be larger than 60 ms when using VAD/CNG.";
+ CHECK_LE(frames_in_buffer_ * 10, kMaxFrameSizeMs)
+ << "Frame size cannot be larger than " << kMaxFrameSizeMs
+ << " ms when using VAD/CNG.";
const size_t samples_per_10ms_frame = 10 * SampleRateHz() / 1000;
CHECK_EQ(speech_buffer_.size(),
static_cast<size_t>(frames_in_buffer_) * samples_per_10ms_frame);
@@ -146,11 +161,7 @@ void AudioEncoderCng::EncodeInternal(uint32_t rtp_timestamp,
switch (activity) {
case Vad::kPassive: {
- EncodePassive(encoded, &info->encoded_bytes);
- info->encoded_timestamp = first_timestamp_in_buffer_;
- info->payload_type = cng_payload_type_;
- info->send_even_if_empty = true;
- info->speech = false;
+ EncodePassive(max_encoded_bytes, encoded, info);
last_frame_active_ = false;
break;
}
@@ -169,10 +180,13 @@ void AudioEncoderCng::EncodeInternal(uint32_t rtp_timestamp,
frames_in_buffer_ = 0;
}
-void AudioEncoderCng::EncodePassive(uint8_t* encoded, size_t* encoded_bytes) {
+void AudioEncoderCng::EncodePassive(size_t max_encoded_bytes,
+ uint8_t* encoded,
+ EncodedInfo* info) {
bool force_sid = last_frame_active_;
bool output_produced = false;
- const size_t samples_per_10ms_frame = 10 * SampleRateHz() / 1000;
+ const size_t samples_per_10ms_frame = SamplesPer10msFrame();
+ CHECK_GE(max_encoded_bytes, frames_in_buffer_ * samples_per_10ms_frame);
for (int i = 0; i < frames_in_buffer_; ++i) {
int16_t encoded_bytes_tmp = 0;
CHECK_GE(WebRtcCng_Encode(cng_inst_.get(),
@@ -181,17 +195,21 @@ void AudioEncoderCng::EncodePassive(uint8_t* encoded, size_t* encoded_bytes) {
encoded, &encoded_bytes_tmp, force_sid), 0);
if (encoded_bytes_tmp > 0) {
CHECK(!output_produced);
- *encoded_bytes = static_cast<size_t>(encoded_bytes_tmp);
+ info->encoded_bytes = static_cast<size_t>(encoded_bytes_tmp);
output_produced = true;
force_sid = false;
}
}
+ info->encoded_timestamp = first_timestamp_in_buffer_;
+ info->payload_type = cng_payload_type_;
+ info->send_even_if_empty = true;
+ info->speech = false;
}
void AudioEncoderCng::EncodeActive(size_t max_encoded_bytes,
uint8_t* encoded,
EncodedInfo* info) {
- const size_t samples_per_10ms_frame = 10 * SampleRateHz() / 1000;
+ const size_t samples_per_10ms_frame = SamplesPer10msFrame();
for (int i = 0; i < frames_in_buffer_; ++i) {
speech_encoder_->Encode(first_timestamp_in_buffer_,
&speech_buffer_[i * samples_per_10ms_frame],
@@ -203,4 +221,8 @@ void AudioEncoderCng::EncodeActive(size_t max_encoded_bytes,
}
}
+size_t AudioEncoderCng::SamplesPer10msFrame() const {
+ return rtc::CheckedDivExact(10 * SampleRateHz(), 1000);
+}
+
} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
index c5d436eb8f..5dfa4d545e 100644
--- a/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/cng/audio_encoder_cng_unittest.cc
@@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <vector>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/common_audio/vad/mock/mock_vad.h"
@@ -23,7 +25,7 @@ using ::testing::Invoke;
namespace webrtc {
namespace {
-static const size_t kMaxEncodedBytes = 1000;
+static const size_t kMockMaxEncodedBytes = 1000;
static const size_t kMaxNumSamples = 48 * 10 * 2; // 10 ms @ 48 kHz stereo.
static const size_t kMockReturnEncodedBytes = 17;
static const int kCngPayloadType = 18;
@@ -36,7 +38,6 @@ class AudioEncoderCngTest : public ::testing::Test {
timestamp_(4711),
num_audio_samples_10ms_(0),
sample_rate_hz_(8000) {
- memset(encoded_, 0, kMaxEncodedBytes);
memset(audio_, 0, kMaxNumSamples * 2);
config_.speech_encoder = &mock_encoder_;
EXPECT_CALL(mock_encoder_, NumChannels()).WillRepeatedly(Return(1));
@@ -66,14 +67,17 @@ class AudioEncoderCngTest : public ::testing::Test {
// is not too small. The return value does not matter that much, as long as
// it is smaller than 10.
EXPECT_CALL(mock_encoder_, Max10MsFramesInAPacket()).WillOnce(Return(1));
+ EXPECT_CALL(mock_encoder_, MaxEncodedBytes())
+ .WillRepeatedly(Return(kMockMaxEncodedBytes));
cng_.reset(new AudioEncoderCng(config_));
+ encoded_.resize(cng_->MaxEncodedBytes(), 0);
}
void Encode() {
ASSERT_TRUE(cng_) << "Must call CreateCng() first.";
encoded_info_ = AudioEncoder::EncodedInfo();
cng_->Encode(timestamp_, audio_, num_audio_samples_10ms_,
- kMaxEncodedBytes, encoded_, &encoded_info_);
+ encoded_.size(), &encoded_[0], &encoded_info_);
timestamp_ += num_audio_samples_10ms_;
}
@@ -182,7 +186,7 @@ class AudioEncoderCngTest : public ::testing::Test {
uint32_t timestamp_;
int16_t audio_[kMaxNumSamples];
size_t num_audio_samples_10ms_;
- uint8_t encoded_[kMaxEncodedBytes];
+ std::vector<uint8_t> encoded_;
AudioEncoder::EncodedInfo encoded_info_;
int sample_rate_hz_;
};
diff --git a/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h b/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h
index 1d3c2f3faa..cc0165054b 100644
--- a/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h
+++ b/webrtc/modules/audio_coding/codecs/cng/include/audio_encoder_cng.h
@@ -48,6 +48,7 @@ class AudioEncoderCng final : public AudioEncoder {
int SampleRateHz() const override;
int NumChannels() const override;
+ size_t MaxEncodedBytes() const override;
int RtpTimestampRateHz() const override;
int Num10MsFramesInNextPacket() const override;
int Max10MsFramesInAPacket() const override;
@@ -68,11 +69,13 @@ class AudioEncoderCng final : public AudioEncoder {
inline void operator()(CNG_enc_inst* ptr) const { WebRtcCng_FreeEnc(ptr); }
};
- void EncodePassive(uint8_t* encoded, size_t* encoded_bytes);
-
+ void EncodePassive(size_t max_encoded_bytes,
+ uint8_t* encoded,
+ EncodedInfo* info);
void EncodeActive(size_t max_encoded_bytes,
uint8_t* encoded,
EncodedInfo* info);
+ size_t SamplesPer10msFrame() const;
AudioEncoder* speech_encoder_;
const int cng_payload_type_;
diff --git a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
index 284a086db4..5c43a85cb5 100644
--- a/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
+++ b/webrtc/modules/audio_coding/codecs/g711/audio_encoder_pcm.cc
@@ -49,9 +49,15 @@ AudioEncoderPcm::~AudioEncoderPcm() {
int AudioEncoderPcm::SampleRateHz() const {
return sample_rate_hz_;
}
+
int AudioEncoderPcm::NumChannels() const {
return num_channels_;
}
+
+size_t AudioEncoderPcm::MaxEncodedBytes() const {
+ return full_frame_samples_;
+}
+
int AudioEncoderPcm::Num10MsFramesInNextPacket() const {
return num_10ms_frames_per_packet_;
}
@@ -72,11 +78,12 @@ void AudioEncoderPcm::EncodeInternal(uint32_t rtp_timestamp,
for (int i = 0; i < num_samples; ++i) {
speech_buffer_.push_back(audio[i]);
}
- if (speech_buffer_.size() < static_cast<size_t>(full_frame_samples_)) {
+ if (speech_buffer_.size() < full_frame_samples_) {
info->encoded_bytes = 0;
return;
}
- CHECK_EQ(speech_buffer_.size(), static_cast<size_t>(full_frame_samples_));
+ CHECK_EQ(speech_buffer_.size(), full_frame_samples_);
+ CHECK_GE(max_encoded_bytes, full_frame_samples_);
int16_t ret = EncodeCall(&speech_buffer_[0], full_frame_samples_, encoded);
CHECK_GE(ret, 0);
speech_buffer_.clear();
diff --git a/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h b/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h
index 3967c5e00d..e64bcea27e 100644
--- a/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h
+++ b/webrtc/modules/audio_coding/codecs/g711/include/audio_encoder_pcm.h
@@ -34,6 +34,7 @@ class AudioEncoderPcm : public AudioEncoder {
int SampleRateHz() const override;
int NumChannels() const override;
+ size_t MaxEncodedBytes() const override;
int Num10MsFramesInNextPacket() const override;
int Max10MsFramesInAPacket() const override;
@@ -55,7 +56,7 @@ class AudioEncoderPcm : public AudioEncoder {
const int num_channels_;
const int payload_type_;
const int num_10ms_frames_per_packet_;
- const int16_t full_frame_samples_;
+ const size_t full_frame_samples_;
std::vector<int16_t> speech_buffer_;
uint32_t first_timestamp_in_buffer_;
};
diff --git a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
index f02bda03a7..bbdcb1da74 100644
--- a/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
+++ b/webrtc/modules/audio_coding/codecs/g722/audio_encoder_g722.cc
@@ -54,17 +54,25 @@ AudioEncoderG722::~AudioEncoderG722() {}
int AudioEncoderG722::SampleRateHz() const {
return kSampleRateHz;
}
+
int AudioEncoderG722::RtpTimestampRateHz() const {
// The RTP timestamp rate for G.722 is 8000 Hz, even though it is a 16 kHz
// codec.
return kSampleRateHz / 2;
}
+
int AudioEncoderG722::NumChannels() const {
return num_channels_;
}
+
+size_t AudioEncoderG722::MaxEncodedBytes() const {
+ return static_cast<size_t>(SamplesPerChannel() / 2 * num_channels_);
+}
+
int AudioEncoderG722::Num10MsFramesInNextPacket() const {
return num_10ms_frames_per_packet_;
}
+
int AudioEncoderG722::Max10MsFramesInAPacket() const {
return num_10ms_frames_per_packet_;
}
@@ -74,10 +82,7 @@ void AudioEncoderG722::EncodeInternal(uint32_t rtp_timestamp,
size_t max_encoded_bytes,
uint8_t* encoded,
EncodedInfo* info) {
- const int samples_per_channel =
- kSampleRateHz / 100 * num_10ms_frames_per_packet_;
- CHECK_GE(max_encoded_bytes,
- static_cast<size_t>(samples_per_channel) / 2 * num_channels_);
+ CHECK_GE(max_encoded_bytes, MaxEncodedBytes());
if (num_10ms_frames_buffered_ == 0)
first_timestamp_in_buffer_ = rtp_timestamp;
@@ -97,6 +102,7 @@ void AudioEncoderG722::EncodeInternal(uint32_t rtp_timestamp,
// Encode each channel separately.
CHECK_EQ(num_10ms_frames_buffered_, num_10ms_frames_per_packet_);
num_10ms_frames_buffered_ = 0;
+ const int samples_per_channel = SamplesPerChannel();
for (int i = 0; i < num_channels_; ++i) {
const int encoded = WebRtcG722_Encode(
encoders_[i].encoder, encoders_[i].speech_buffer.get(),
@@ -123,4 +129,8 @@ void AudioEncoderG722::EncodeInternal(uint32_t rtp_timestamp,
info->payload_type = payload_type_;
}
+int AudioEncoderG722::SamplesPerChannel() const {
+ return kSampleRateHz / 100 * num_10ms_frames_per_packet_;
+}
+
} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h b/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h
index 229c06e463..81b44d6256 100644
--- a/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h
+++ b/webrtc/modules/audio_coding/codecs/g722/include/audio_encoder_g722.h
@@ -31,8 +31,9 @@ class AudioEncoderG722 : public AudioEncoder {
~AudioEncoderG722() override;
int SampleRateHz() const override;
- int RtpTimestampRateHz() const override;
int NumChannels() const override;
+ size_t MaxEncodedBytes() const override;
+ int RtpTimestampRateHz() const override;
int Num10MsFramesInNextPacket() const override;
int Max10MsFramesInAPacket() const override;
@@ -53,6 +54,8 @@ class AudioEncoderG722 : public AudioEncoder {
~EncoderState();
};
+ int SamplesPerChannel() const;
+
const int num_channels_;
const int payload_type_;
const int num_10ms_frames_per_packet_;
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
index b939341212..1e85a077ff 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
+++ b/webrtc/modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.cc
@@ -46,12 +46,19 @@ AudioEncoderIlbc::~AudioEncoderIlbc() {
int AudioEncoderIlbc::SampleRateHz() const {
return kSampleRateHz;
}
+
int AudioEncoderIlbc::NumChannels() const {
return 1;
}
+
+size_t AudioEncoderIlbc::MaxEncodedBytes() const {
+ return RequiredOutputSizeBytes();
+}
+
int AudioEncoderIlbc::Num10MsFramesInNextPacket() const {
return num_10ms_frames_per_packet_;
}
+
int AudioEncoderIlbc::Max10MsFramesInAPacket() const {
return num_10ms_frames_per_packet_;
}
@@ -61,24 +68,7 @@ void AudioEncoderIlbc::EncodeInternal(uint32_t rtp_timestamp,
size_t max_encoded_bytes,
uint8_t* encoded,
EncodedInfo* info) {
- size_t expected_output_len;
- switch (num_10ms_frames_per_packet_) {
- case 2:
- expected_output_len = 38;
- break;
- case 3:
- expected_output_len = 50;
- break;
- case 4:
- expected_output_len = 2 * 38;
- break;
- case 6:
- expected_output_len = 2 * 50;
- break;
- default:
- FATAL();
- }
- DCHECK_GE(max_encoded_bytes, expected_output_len);
+ DCHECK_GE(max_encoded_bytes, RequiredOutputSizeBytes());
// Save timestamp if starting a new packet.
if (num_10ms_frames_buffered_ == 0)
@@ -105,10 +95,20 @@ void AudioEncoderIlbc::EncodeInternal(uint32_t rtp_timestamp,
kSampleRateHz / 100 * num_10ms_frames_per_packet_,
encoded);
CHECK_GE(output_len, 0);
- DCHECK_EQ(output_len, static_cast<int>(expected_output_len));
info->encoded_bytes = output_len;
+ DCHECK_EQ(info->encoded_bytes, RequiredOutputSizeBytes());
info->encoded_timestamp = first_timestamp_in_buffer_;
info->payload_type = payload_type_;
}
+size_t AudioEncoderIlbc::RequiredOutputSizeBytes() const {
+ switch (num_10ms_frames_per_packet_) {
+ case 2: return 38;
+ case 3: return 50;
+ case 4: return 2 * 38;
+ case 6: return 2 * 50;
+ default: FATAL();
+ }
+}
+
} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h b/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h
index fc3aa0d4ba..a5378d1ed1 100644
--- a/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h
+++ b/webrtc/modules/audio_coding/codecs/ilbc/interface/audio_encoder_ilbc.h
@@ -33,6 +33,7 @@ class AudioEncoderIlbc : public AudioEncoder {
int SampleRateHz() const override;
int NumChannels() const override;
+ size_t MaxEncodedBytes() const override;
int Num10MsFramesInNextPacket() const override;
int Max10MsFramesInAPacket() const override;
@@ -44,6 +45,8 @@ class AudioEncoderIlbc : public AudioEncoder {
EncodedInfo* info) override;
private:
+ size_t RequiredOutputSizeBytes() const;
+
static const int kMaxSamplesPerPacket = 480;
const int payload_type_;
const int num_10ms_frames_per_packet_;
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
index c918eafc41..88ead93402 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h
@@ -71,6 +71,7 @@ class AudioEncoderDecoderIsacT : public AudioEncoder, public AudioDecoder {
// AudioEncoder public methods.
int SampleRateHz() const override;
int NumChannels() const override;
+ size_t MaxEncodedBytes() const override;
int Num10MsFramesInNextPacket() const override;
int Max10MsFramesInAPacket() const override;
diff --git a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
index 024efa1413..b9c3e98e8e 100644
--- a/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
+++ b/webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h
@@ -185,6 +185,11 @@ int AudioEncoderDecoderIsacT<T>::NumChannels() const {
}
template <typename T>
+size_t AudioEncoderDecoderIsacT<T>::MaxEncodedBytes() const {
+ return kSufficientEncodeBufferSizeBytes;
+}
+
+template <typename T>
int AudioEncoderDecoderIsacT<T>::Num10MsFramesInNextPacket() const {
CriticalSectionScoped cs(state_lock_.get());
const int samples_in_next_packet = T::GetNewFrameLen(isac_state_);
diff --git a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_red_unittest.cc b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_red_unittest.cc
index 4bc616605e..22949a9275 100644
--- a/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_red_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/isac/main/source/audio_encoder_isac_red_unittest.cc
@@ -30,12 +30,11 @@ TEST(AudioEncoderIsacRedTest, CompareRedAndNoRed) {
double r = rand(); // NOLINT(runtime/threadsafe_fn)
input[i] = (r / RAND_MAX) * 2000 - 1000;
}
- static const size_t kMaxEncodedSizeBytes = 1000;
- uint8_t encoded[kMaxEncodedSizeBytes];
- uint8_t red_encoded[kMaxEncodedSizeBytes];
AudioEncoderDecoderIsac::Config config;
config.sample_rate_hz = kSampleRateHz;
AudioEncoderDecoderIsac isac_encoder(config);
+ size_t max_encoded_bytes = isac_encoder.MaxEncodedBytes();
+ rtc::scoped_ptr<uint8_t[]> encoded(new uint8_t[max_encoded_bytes]);
AudioEncoderDecoderIsac::Config red_config;
red_config.sample_rate_hz = kSampleRateHz;
red_config.red_payload_type = kRedPayloadType;
@@ -43,6 +42,8 @@ TEST(AudioEncoderIsacRedTest, CompareRedAndNoRed) {
ASSERT_NE(red_config.red_payload_type, red_config.payload_type)
<< "iSAC and RED payload types must be different.";
AudioEncoderDecoderIsac isac_red_encoder(red_config);
+ size_t max_red_encoded_bytes = isac_red_encoder.MaxEncodedBytes();
+ rtc::scoped_ptr<uint8_t[]> red_encoded(new uint8_t[max_red_encoded_bytes]);
AudioEncoder::EncodedInfo info, red_info;
// Note that we are not expecting any output from the redundant encoder until
@@ -52,10 +53,11 @@ TEST(AudioEncoderIsacRedTest, CompareRedAndNoRed) {
EXPECT_EQ(0u, red_info.encoded_bytes);
EXPECT_EQ(0u, red_info.redundant.size());
const uint32_t timestamp = static_cast<uint32_t>(i);
- isac_encoder.Encode(timestamp, input, k10MsSamples, kMaxEncodedSizeBytes,
- encoded, &info);
+ isac_encoder.Encode(timestamp, input, k10MsSamples, max_encoded_bytes,
+ encoded.get(), &info);
isac_red_encoder.Encode(timestamp, input, k10MsSamples,
- kMaxEncodedSizeBytes, red_encoded, &red_info);
+ max_red_encoded_bytes, red_encoded.get(),
+ &red_info);
}
EXPECT_GT(info.encoded_bytes, 0u)
<< "Regular codec did not produce any output";
@@ -65,7 +67,7 @@ TEST(AudioEncoderIsacRedTest, CompareRedAndNoRed) {
ASSERT_EQ(info.encoded_bytes, red_info.redundant[0].encoded_bytes)
<< "Primary payload should be same length as non-redundant payload";
// Check that |encoded| and the primary part of |red_encoded| are identical.
- EXPECT_EQ(0, memcmp(encoded, red_encoded, info.encoded_bytes));
+ EXPECT_EQ(0, memcmp(encoded.get(), red_encoded.get(), info.encoded_bytes));
EXPECT_GT(red_info.redundant[0].encoded_bytes,
red_info.redundant[1].encoded_bytes)
<< "Redundant payload should be smaller than primary";
diff --git a/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h b/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h
index 70ee497453..7425e9a188 100644
--- a/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h
+++ b/webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h
@@ -23,6 +23,7 @@ class MockAudioEncoder : public AudioEncoder {
MOCK_METHOD0(Die, void());
MOCK_CONST_METHOD0(SampleRateHz, int());
MOCK_CONST_METHOD0(NumChannels, int());
+ MOCK_CONST_METHOD0(MaxEncodedBytes, size_t());
MOCK_CONST_METHOD0(Num10MsFramesInNextPacket, int());
MOCK_CONST_METHOD0(Max10MsFramesInAPacket, int());
MOCK_METHOD1(SetTargetBitrate, void(int));
diff --git a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
index e4779aa0b8..b98033e06d 100644
--- a/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
+++ b/webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.cc
@@ -111,6 +111,16 @@ int AudioEncoderOpus::NumChannels() const {
return num_channels_;
}
+size_t AudioEncoderOpus::MaxEncodedBytes() const {
+ // Calculate the number of bytes we expect the encoder to produce,
+ // then multiply by two to give a wide margin for error.
+ int frame_size_ms = num_10ms_frames_per_packet_ * 10;
+ int bytes_per_millisecond = bitrate_bps_ / (1000 * 8) + 1;
+ size_t approx_encoded_bytes =
+ static_cast<size_t>(frame_size_ms * bytes_per_millisecond);
+ return 2 * approx_encoded_bytes;
+}
+
int AudioEncoderOpus::Num10MsFramesInNextPacket() const {
return num_10ms_frames_per_packet_;
}
@@ -120,10 +130,9 @@ int AudioEncoderOpus::Max10MsFramesInAPacket() const {
}
void AudioEncoderOpus::SetTargetBitrate(int bits_per_second) {
- CHECK_EQ(WebRtcOpus_SetBitRate(
- inst_, std::max(std::min(bits_per_second, kMaxBitrateBps),
- kMinBitrateBps)),
- 0);
+ bitrate_bps_ = std::max(std::min(bits_per_second, kMaxBitrateBps),
+ kMinBitrateBps);
+ CHECK_EQ(WebRtcOpus_SetBitRate(inst_, bitrate_bps_), 0);
}
void AudioEncoderOpus::SetProjectedPacketLossRate(double fraction) {
diff --git a/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h b/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h
index 417faf806e..bfd4ba86a8 100644
--- a/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h
+++ b/webrtc/modules/audio_coding/codecs/opus/interface/audio_encoder_opus.h
@@ -47,10 +47,12 @@ class AudioEncoderOpus final : public AudioEncoder {
int SampleRateHz() const override;
int NumChannels() const override;
+ size_t MaxEncodedBytes() const override;
int Num10MsFramesInNextPacket() const override;
int Max10MsFramesInAPacket() const override;
void SetTargetBitrate(int bits_per_second) override;
void SetProjectedPacketLossRate(double fraction) override;
+
double packet_loss_rate() const { return packet_loss_rate_; }
ApplicationMode application() const { return application_; }
@@ -66,6 +68,7 @@ class AudioEncoderOpus final : public AudioEncoder {
const int num_channels_;
const int payload_type_;
const ApplicationMode application_;
+ int bitrate_bps_;
const int samples_per_10ms_frame_;
std::vector<int16_t> input_buffer_;
OpusEncInst* inst_;
diff --git a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
index 92e1c0b371..28c72fb3bb 100644
--- a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
+++ b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.cc
@@ -38,6 +38,10 @@ int AudioEncoderCopyRed::NumChannels() const {
return speech_encoder_->NumChannels();
}
+size_t AudioEncoderCopyRed::MaxEncodedBytes() const {
+ return 2 * speech_encoder_->MaxEncodedBytes();
+}
+
int AudioEncoderCopyRed::Num10MsFramesInNextPacket() const {
return speech_encoder_->Num10MsFramesInNextPacket();
}
diff --git a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
index 39f1615d8d..7ce9ca0f01 100644
--- a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
+++ b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h
@@ -36,8 +36,9 @@ class AudioEncoderCopyRed : public AudioEncoder {
~AudioEncoderCopyRed() override;
int SampleRateHz() const override;
- int RtpTimestampRateHz() const override;
int NumChannels() const override;
+ size_t MaxEncodedBytes() const override;
+ int RtpTimestampRateHz() const override;
int Num10MsFramesInNextPacket() const override;
int Max10MsFramesInAPacket() const override;
void SetTargetBitrate(int bits_per_second) override;
diff --git a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc
index ea3ad436a8..2ae2fa21b0 100644
--- a/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc
+++ b/webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red_unittest.cc
@@ -8,6 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
+#include <vector>
+
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/scoped_ptr.h"
@@ -24,7 +26,7 @@ using ::testing::MockFunction;
namespace webrtc {
namespace {
-static const size_t kMaxEncodedBytes = 1000;
+static const size_t kMockMaxEncodedBytes = 1000;
static const size_t kMaxNumSamples = 48 * 10 * 2; // 10 ms @ 48 kHz stereo.
}
@@ -39,11 +41,13 @@ class AudioEncoderCopyRedTest : public ::testing::Test {
config.payload_type = red_payload_type_;
config.speech_encoder = &mock_encoder_;
red_.reset(new AudioEncoderCopyRed(config));
- memset(encoded_, 0, sizeof(encoded_));
memset(audio_, 0, sizeof(audio_));
EXPECT_CALL(mock_encoder_, NumChannels()).WillRepeatedly(Return(1));
EXPECT_CALL(mock_encoder_, SampleRateHz())
.WillRepeatedly(Return(sample_rate_hz_));
+ EXPECT_CALL(mock_encoder_, MaxEncodedBytes())
+ .WillRepeatedly(Return(kMockMaxEncodedBytes));
+ encoded_.resize(red_->MaxEncodedBytes(), 0);
}
void TearDown() override {
@@ -58,7 +62,7 @@ class AudioEncoderCopyRedTest : public ::testing::Test {
ASSERT_TRUE(red_.get() != NULL);
encoded_info_ = AudioEncoder::EncodedInfo();
red_->Encode(timestamp_, audio_, num_audio_samples_10ms,
- kMaxEncodedBytes, encoded_, &encoded_info_);
+ encoded_.size(), &encoded_[0], &encoded_info_);
timestamp_ += num_audio_samples_10ms;
}
@@ -68,7 +72,7 @@ class AudioEncoderCopyRedTest : public ::testing::Test {
int16_t audio_[kMaxNumSamples];
const int sample_rate_hz_;
size_t num_audio_samples_10ms;
- uint8_t encoded_[kMaxEncodedBytes];
+ std::vector<uint8_t> encoded_;
AudioEncoder::EncodedInfo encoded_info_;
const int red_payload_type_;
};