Reland 8749: AudioEncoder: return EncodedInfo from Encode() and EncodeInternal()
Old review at: https://webrtc-codereview.appspot.com/43839004/ R=kwiberg@webrtc.org Review URL: https://webrtc-codereview.appspot.com/45769004 Cr-Commit-Position: refs/heads/master@{#8788} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8788 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@ -60,48 +60,48 @@ void AudioEncoderCopyRed::SetProjectedPacketLossRate(double fraction) {
|
||||
speech_encoder_->SetProjectedPacketLossRate(fraction);
|
||||
}
|
||||
|
||||
void AudioEncoderCopyRed::EncodeInternal(uint32_t rtp_timestamp,
|
||||
const int16_t* audio,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded,
|
||||
EncodedInfo* info) {
|
||||
speech_encoder_->Encode(rtp_timestamp, audio,
|
||||
static_cast<size_t>(SampleRateHz() / 100),
|
||||
max_encoded_bytes, encoded, info);
|
||||
AudioEncoder::EncodedInfo AudioEncoderCopyRed::EncodeInternal(
|
||||
uint32_t rtp_timestamp,
|
||||
const int16_t* audio,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded) {
|
||||
EncodedInfo info = speech_encoder_->Encode(
|
||||
rtp_timestamp, audio, static_cast<size_t>(SampleRateHz() / 100),
|
||||
max_encoded_bytes, encoded);
|
||||
CHECK_GE(max_encoded_bytes,
|
||||
info->encoded_bytes + secondary_info_.encoded_bytes);
|
||||
CHECK(info->redundant.empty()) << "Cannot use nested redundant encoders.";
|
||||
info.encoded_bytes + secondary_info_.encoded_bytes);
|
||||
CHECK(info.redundant.empty()) << "Cannot use nested redundant encoders.";
|
||||
|
||||
if (info->encoded_bytes > 0) {
|
||||
if (info.encoded_bytes > 0) {
|
||||
// |info| will be implicitly cast to an EncodedInfoLeaf struct, effectively
|
||||
// discarding the (empty) vector of redundant information. This is
|
||||
// intentional.
|
||||
info->redundant.push_back(*info);
|
||||
DCHECK_EQ(info->redundant.size(), 1u);
|
||||
info.redundant.push_back(info);
|
||||
DCHECK_EQ(info.redundant.size(), 1u);
|
||||
if (secondary_info_.encoded_bytes > 0) {
|
||||
memcpy(&encoded[info->encoded_bytes], secondary_encoded_.get(),
|
||||
memcpy(&encoded[info.encoded_bytes], secondary_encoded_.get(),
|
||||
secondary_info_.encoded_bytes);
|
||||
info->redundant.push_back(secondary_info_);
|
||||
DCHECK_EQ(info->redundant.size(), 2u);
|
||||
info.redundant.push_back(secondary_info_);
|
||||
DCHECK_EQ(info.redundant.size(), 2u);
|
||||
}
|
||||
// Save primary to secondary.
|
||||
if (secondary_allocated_ < info->encoded_bytes) {
|
||||
secondary_encoded_.reset(new uint8_t[info->encoded_bytes]);
|
||||
secondary_allocated_ = info->encoded_bytes;
|
||||
if (secondary_allocated_ < info.encoded_bytes) {
|
||||
secondary_encoded_.reset(new uint8_t[info.encoded_bytes]);
|
||||
secondary_allocated_ = info.encoded_bytes;
|
||||
}
|
||||
CHECK(secondary_encoded_);
|
||||
memcpy(secondary_encoded_.get(), encoded, info->encoded_bytes);
|
||||
secondary_info_ = *info;
|
||||
DCHECK_EQ(info->speech, info->redundant[0].speech);
|
||||
memcpy(secondary_encoded_.get(), encoded, info.encoded_bytes);
|
||||
secondary_info_ = info;
|
||||
DCHECK_EQ(info.speech, info.redundant[0].speech);
|
||||
}
|
||||
// Update main EncodedInfo.
|
||||
info->payload_type = red_payload_type_;
|
||||
info->encoded_bytes = 0;
|
||||
for (std::vector<EncodedInfoLeaf>::const_iterator it =
|
||||
info->redundant.begin();
|
||||
it != info->redundant.end(); ++it) {
|
||||
info->encoded_bytes += it->encoded_bytes;
|
||||
info.payload_type = red_payload_type_;
|
||||
info.encoded_bytes = 0;
|
||||
for (std::vector<EncodedInfoLeaf>::const_iterator it = info.redundant.begin();
|
||||
it != info.redundant.end(); ++it) {
|
||||
info.encoded_bytes += it->encoded_bytes;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -45,11 +45,10 @@ class AudioEncoderCopyRed : public AudioEncoder {
|
||||
void SetProjectedPacketLossRate(double fraction) override;
|
||||
|
||||
protected:
|
||||
void EncodeInternal(uint32_t rtp_timestamp,
|
||||
const int16_t* audio,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded,
|
||||
EncodedInfo* info) override;
|
||||
EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
|
||||
const int16_t* audio,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded) override;
|
||||
|
||||
private:
|
||||
AudioEncoder* speech_encoder_;
|
||||
|
||||
@ -60,9 +60,8 @@ class AudioEncoderCopyRedTest : public ::testing::Test {
|
||||
|
||||
void Encode() {
|
||||
ASSERT_TRUE(red_.get() != NULL);
|
||||
encoded_info_ = AudioEncoder::EncodedInfo();
|
||||
red_->Encode(timestamp_, audio_, num_audio_samples_10ms,
|
||||
encoded_.size(), &encoded_[0], &encoded_info_);
|
||||
encoded_info_ = red_->Encode(timestamp_, audio_, num_audio_samples_10ms,
|
||||
encoded_.size(), &encoded_[0]);
|
||||
timestamp_ += num_audio_samples_10ms;
|
||||
}
|
||||
|
||||
@ -83,18 +82,16 @@ class MockEncodeHelper {
|
||||
memset(&info_, 0, sizeof(info_));
|
||||
}
|
||||
|
||||
void Encode(uint32_t timestamp,
|
||||
const int16_t* audio,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded,
|
||||
AudioEncoder::EncodedInfo* info) {
|
||||
AudioEncoder::EncodedInfo Encode(uint32_t timestamp,
|
||||
const int16_t* audio,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded) {
|
||||
if (write_payload_) {
|
||||
CHECK(encoded);
|
||||
CHECK_LE(info_.encoded_bytes, max_encoded_bytes);
|
||||
memcpy(encoded, payload_, info_.encoded_bytes);
|
||||
}
|
||||
CHECK(info);
|
||||
*info = info_;
|
||||
return info_;
|
||||
}
|
||||
|
||||
AudioEncoder::EncodedInfo info_;
|
||||
@ -144,7 +141,8 @@ TEST_F(AudioEncoderCopyRedTest, CheckImmediateEncode) {
|
||||
InSequence s;
|
||||
MockFunction<void(int check_point_id)> check;
|
||||
for (int i = 1; i <= 6; ++i) {
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _));
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _))
|
||||
.WillRepeatedly(Return(AudioEncoder::EncodedInfo()));
|
||||
EXPECT_CALL(check, Call(i));
|
||||
Encode();
|
||||
check.Call(i);
|
||||
@ -153,13 +151,13 @@ TEST_F(AudioEncoderCopyRedTest, CheckImmediateEncode) {
|
||||
|
||||
// Checks that no output is produced if the underlying codec doesn't emit any
|
||||
// new data, even if the RED codec is loaded with a secondary encoding.
|
||||
TEST_F(AudioEncoderCopyRedTest, CheckNoOuput) {
|
||||
TEST_F(AudioEncoderCopyRedTest, CheckNoOutput) {
|
||||
// Start with one Encode() call that will produce output.
|
||||
static const size_t kEncodedSize = 17;
|
||||
AudioEncoder::EncodedInfo info;
|
||||
info.encoded_bytes = kEncodedSize;
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
|
||||
.WillOnce(SetArgPointee<4>(info));
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _))
|
||||
.WillOnce(Return(info));
|
||||
Encode();
|
||||
// First call is a special case, since it does not include a secondary
|
||||
// payload.
|
||||
@ -168,15 +166,15 @@ TEST_F(AudioEncoderCopyRedTest, CheckNoOuput) {
|
||||
|
||||
// Next call to the speech encoder will not produce any output.
|
||||
info.encoded_bytes = 0;
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
|
||||
.WillOnce(SetArgPointee<4>(info));
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _))
|
||||
.WillOnce(Return(info));
|
||||
Encode();
|
||||
EXPECT_EQ(0u, encoded_info_.encoded_bytes);
|
||||
|
||||
// Final call to the speech encoder will produce output.
|
||||
info.encoded_bytes = kEncodedSize;
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
|
||||
.WillOnce(SetArgPointee<4>(info));
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _))
|
||||
.WillOnce(Return(info));
|
||||
Encode();
|
||||
EXPECT_EQ(2 * kEncodedSize, encoded_info_.encoded_bytes);
|
||||
ASSERT_EQ(2u, encoded_info_.redundant.size());
|
||||
@ -192,8 +190,8 @@ TEST_F(AudioEncoderCopyRedTest, CheckPayloadSizes) {
|
||||
for (int encode_size = 1; encode_size <= kNumPackets; ++encode_size) {
|
||||
AudioEncoder::EncodedInfo info;
|
||||
info.encoded_bytes = encode_size;
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
|
||||
.WillOnce(SetArgPointee<4>(info));
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _))
|
||||
.WillOnce(Return(info));
|
||||
}
|
||||
|
||||
// First call is a special case, since it does not include a secondary
|
||||
@ -218,7 +216,7 @@ TEST_F(AudioEncoderCopyRedTest, CheckTimestamps) {
|
||||
helper.info_.encoded_bytes = 17;
|
||||
helper.info_.encoded_timestamp = timestamp_;
|
||||
uint32_t primary_timestamp = timestamp_;
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _))
|
||||
.WillRepeatedly(Invoke(&helper, &MockEncodeHelper::Encode));
|
||||
|
||||
// First call is a special case, since it does not include a secondary
|
||||
@ -249,7 +247,7 @@ TEST_F(AudioEncoderCopyRedTest, CheckPayloads) {
|
||||
payload[i] = i;
|
||||
}
|
||||
helper.payload_ = payload;
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _))
|
||||
.WillRepeatedly(Invoke(&helper, &MockEncodeHelper::Encode));
|
||||
|
||||
// First call is a special case, since it does not include a secondary
|
||||
@ -286,7 +284,7 @@ TEST_F(AudioEncoderCopyRedTest, CheckPayloadType) {
|
||||
helper.info_.encoded_bytes = 17;
|
||||
const int primary_payload_type = red_payload_type_ + 1;
|
||||
helper.info_.payload_type = primary_payload_type;
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
|
||||
EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _))
|
||||
.WillRepeatedly(Invoke(&helper, &MockEncodeHelper::Encode));
|
||||
|
||||
// First call is a special case, since it does not include a secondary
|
||||
|
||||
Reference in New Issue
Block a user