Improve ConvertToADTS function performance (#639)
Remove the extra data copying.
This commit is contained in:
parent
443519aeb3
commit
b8ee20df1d
|
@ -137,27 +137,33 @@ bool AACAudioSpecificConfig::Parse(const std::vector<uint8_t>& data) {
|
|||
channel_config_ <= 7;
|
||||
}
|
||||
|
||||
bool AACAudioSpecificConfig::ConvertToADTS(std::vector<uint8_t>* buffer) const {
|
||||
size_t size = buffer->size() + kADTSHeaderSize;
|
||||
|
||||
bool AACAudioSpecificConfig::ConvertToADTS(
|
||||
const uint8_t* data,
|
||||
size_t data_size,
|
||||
std::vector<uint8_t>* audio_frame) const {
|
||||
DCHECK(audio_object_type_ >= 1 && audio_object_type_ <= 4 &&
|
||||
frequency_index_ != 0xf && channel_config_ <= 7);
|
||||
|
||||
size_t size = kADTSHeaderSize + data_size;
|
||||
|
||||
// ADTS header uses 13 bits for packet size.
|
||||
if (size >= (1 << 13))
|
||||
return false;
|
||||
|
||||
std::vector<uint8_t>& adts = *buffer;
|
||||
audio_frame->reserve(size);
|
||||
audio_frame->resize(kADTSHeaderSize);
|
||||
|
||||
adts.insert(buffer->begin(), kADTSHeaderSize, 0);
|
||||
adts[0] = 0xff;
|
||||
adts[1] = 0xf1;
|
||||
adts[2] = ((audio_object_type_ - 1) << 6) + (frequency_index_ << 2) +
|
||||
(channel_config_ >> 2);
|
||||
adts[3] = ((channel_config_ & 0x3) << 6) + static_cast<uint8_t>(size >> 11);
|
||||
adts[4] = static_cast<uint8_t>((size & 0x7ff) >> 3);
|
||||
adts[5] = static_cast<uint8_t>(((size & 7) << 5) + 0x1f);
|
||||
adts[6] = 0xfc;
|
||||
audio_frame->at(0) = 0xff;
|
||||
audio_frame->at(1) = 0xf1;
|
||||
audio_frame->at(2) = ((audio_object_type_ - 1) << 6) +
|
||||
(frequency_index_ << 2) + (channel_config_ >> 2);
|
||||
audio_frame->at(3) =
|
||||
((channel_config_ & 0x3) << 6) + static_cast<uint8_t>(size >> 11);
|
||||
audio_frame->at(4) = static_cast<uint8_t>((size & 0x7ff) >> 3);
|
||||
audio_frame->at(5) = static_cast<uint8_t>(((size & 7) << 5) + 0x1f);
|
||||
audio_frame->at(6) = 0xfc;
|
||||
|
||||
audio_frame->insert(audio_frame->end(), data, data + data_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -84,11 +84,14 @@ class AACAudioSpecificConfig {
|
|||
virtual bool Parse(const std::vector<uint8_t>& data);
|
||||
|
||||
/// Convert a raw AAC frame into an AAC frame with an ADTS header.
|
||||
/// @param[in,out] buffer contains the raw AAC frame on input, and the
|
||||
/// converted frame on output if successful; it is untouched
|
||||
/// on failure.
|
||||
/// @param data points to the raw AAC frame to be converted.
|
||||
/// @param data_size the size of a raw AAC frame.
|
||||
/// @param[out] audio_frame contains the converted frame if successful; it is
|
||||
/// untouched on failure.
|
||||
/// @return true on success, false otherwise.
|
||||
virtual bool ConvertToADTS(std::vector<uint8_t>* buffer) const;
|
||||
virtual bool ConvertToADTS(const uint8_t* data,
|
||||
size_t data_size,
|
||||
std::vector<uint8_t>* audio_frame) const;
|
||||
|
||||
/// @return The audio object type for this AAC config, with possible extension
|
||||
/// considered.
|
||||
|
|
|
@ -52,7 +52,8 @@ bool PesPacketGenerator::Initialize(const StreamInfo& stream_info) {
|
|||
converter_.reset(new NalUnitToByteStreamConverter());
|
||||
return converter_->Initialize(video_stream_info.codec_config().data(),
|
||||
video_stream_info.codec_config().size());
|
||||
} else if (stream_type_ == kStreamAudio) {
|
||||
}
|
||||
if (stream_type_ == kStreamAudio) {
|
||||
const AudioStreamInfo& audio_stream_info =
|
||||
static_cast<const AudioStreamInfo&>(stream_info);
|
||||
timescale_scale_ = kTsTimescale / audio_stream_info.time_scale();
|
||||
|
@ -60,7 +61,8 @@ bool PesPacketGenerator::Initialize(const StreamInfo& stream_info) {
|
|||
audio_stream_id_ = kAacAudioStreamId;
|
||||
adts_converter_.reset(new AACAudioSpecificConfig());
|
||||
return adts_converter_->Parse(audio_stream_info.codec_config());
|
||||
} else if (audio_stream_info.codec() == Codec::kCodecAC3 ||
|
||||
}
|
||||
if (audio_stream_info.codec() == Codec::kCodecAC3 ||
|
||||
audio_stream_info.codec() == Codec::kCodecEAC3) {
|
||||
audio_stream_id_ = kAc3AudioStreamId;
|
||||
// No converter needed for AC3 and E-AC3.
|
||||
|
@ -117,17 +119,15 @@ bool PesPacketGenerator::PushSample(const MediaSample& sample) {
|
|||
}
|
||||
DCHECK_EQ(stream_type_, kStreamAudio);
|
||||
|
||||
std::vector<uint8_t> audio_frame(sample.data(),
|
||||
sample.data() + sample.data_size());
|
||||
std::vector<uint8_t> audio_frame;
|
||||
|
||||
// AAC is carried in ADTS.
|
||||
if (adts_converter_) {
|
||||
// TODO(rkuroiwa): ConvertToADTS() makes another copy of audio_frame
|
||||
// internally. Optimize copying in this function, possibly by adding a
|
||||
// method on AACAudioSpecificConfig that takes {pointer, length} pair and
|
||||
// returns a vector that has the ADTS header.
|
||||
if (!adts_converter_->ConvertToADTS(&audio_frame))
|
||||
if (!adts_converter_->ConvertToADTS(sample.data(), sample.data_size(),
|
||||
&audio_frame))
|
||||
return false;
|
||||
} else {
|
||||
audio_frame.assign(sample.data(), sample.data() + sample.data_size());
|
||||
}
|
||||
|
||||
// TODO(rkuriowa): Put multiple samples in the PES packet to reduce # of PES
|
||||
|
|
|
@ -112,7 +112,10 @@ class MockNalUnitToByteStreamConverter : public NalUnitToByteStreamConverter {
|
|||
class MockAACAudioSpecificConfig : public AACAudioSpecificConfig {
|
||||
public:
|
||||
MOCK_METHOD1(Parse, bool(const std::vector<uint8_t>& data));
|
||||
MOCK_CONST_METHOD1(ConvertToADTS, bool(std::vector<uint8_t>* buffer));
|
||||
MOCK_CONST_METHOD3(ConvertToADTS,
|
||||
bool(const uint8_t* data,
|
||||
size_t data_size,
|
||||
std::vector<uint8_t>* audio_frame));
|
||||
};
|
||||
|
||||
std::shared_ptr<VideoStreamInfo> CreateVideoStreamInfo(Codec codec) {
|
||||
|
@ -307,8 +310,8 @@ TEST_F(PesPacketGeneratorTest, AddAudioSample) {
|
|||
|
||||
std::unique_ptr<MockAACAudioSpecificConfig> mock(
|
||||
new MockAACAudioSpecificConfig());
|
||||
EXPECT_CALL(*mock, ConvertToADTS(_))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(expected_data), Return(true)));
|
||||
EXPECT_CALL(*mock, ConvertToADTS(sample->data(), sample->data_size(), _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(expected_data), Return(true)));
|
||||
|
||||
UseMockAACAudioSpecificConfig(std::move(mock));
|
||||
|
||||
|
@ -335,7 +338,7 @@ TEST_F(PesPacketGeneratorTest, AddAudioSampleFailedToConvert) {
|
|||
|
||||
std::unique_ptr<MockAACAudioSpecificConfig> mock(
|
||||
new MockAACAudioSpecificConfig());
|
||||
EXPECT_CALL(*mock, ConvertToADTS(_)).WillOnce(Return(false));
|
||||
EXPECT_CALL(*mock, ConvertToADTS(_, _, _)).WillOnce(Return(false));
|
||||
|
||||
UseMockAACAudioSpecificConfig(std::move(mock));
|
||||
|
||||
|
|
|
@ -67,9 +67,9 @@ Status PackedAudioSegmenter::AddSample(const MediaSample& sample) {
|
|||
}
|
||||
|
||||
if (adts_converter_) {
|
||||
std::vector<uint8_t> audio_frame(sample.data(),
|
||||
sample.data() + sample.data_size());
|
||||
if (!adts_converter_->ConvertToADTS(&audio_frame))
|
||||
std::vector<uint8_t> audio_frame;
|
||||
if (!adts_converter_->ConvertToADTS(sample.data(), sample.data_size(),
|
||||
&audio_frame))
|
||||
return Status(error::MUXER_FAILURE, "Failed to convert to ADTS.");
|
||||
segment_buffer_.AppendArray(audio_frame.data(), audio_frame.size());
|
||||
} else {
|
||||
|
|
|
@ -19,9 +19,7 @@ using ::testing::_;
|
|||
using ::testing::ByMove;
|
||||
using ::testing::DoAll;
|
||||
using ::testing::ElementsAreArray;
|
||||
using ::testing::Eq;
|
||||
using ::testing::Invoke;
|
||||
using ::testing::Pointee;
|
||||
using ::testing::Return;
|
||||
using ::testing::SetArgPointee;
|
||||
using ::testing::Test;
|
||||
|
@ -107,7 +105,10 @@ std::shared_ptr<MediaSample> CreateEncryptedSample(
|
|||
class MockAACAudioSpecificConfig : public AACAudioSpecificConfig {
|
||||
public:
|
||||
MOCK_METHOD1(Parse, bool(const std::vector<uint8_t>& data));
|
||||
MOCK_CONST_METHOD1(ConvertToADTS, bool(std::vector<uint8_t>* buffer));
|
||||
MOCK_CONST_METHOD3(ConvertToADTS,
|
||||
bool(const uint8_t* data,
|
||||
size_t data_size,
|
||||
std::vector<uint8_t>* audio_frame));
|
||||
};
|
||||
|
||||
class MockId3Tag : public Id3Tag {
|
||||
|
@ -170,8 +171,8 @@ TEST_F(PackedAudioSegmenterTest, AacAddSample) {
|
|||
EXPECT_CALL(*mock_adts_converter_, Parse(ElementsAreArray(kCodecConfig)))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*mock_adts_converter_,
|
||||
ConvertToADTS(Pointee(Eq(StringToVector(kSample1Data)))))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(StringToVector(kAdtsSample1Data)),
|
||||
ConvertToADTS(_, sizeof(kSample1Data) - 1, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(StringToVector(kAdtsSample1Data)),
|
||||
Return(true)));
|
||||
|
||||
EXPECT_CALL(segmenter_, CreateAdtsConverter())
|
||||
|
@ -199,8 +200,8 @@ TEST_F(PackedAudioSegmenterTest, TruncateLargeTimestamp) {
|
|||
EXPECT_CALL(*mock_adts_converter_, Parse(ElementsAreArray(kCodecConfig)))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*mock_adts_converter_,
|
||||
ConvertToADTS(Pointee(Eq(StringToVector(kSample1Data)))))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(StringToVector(kAdtsSample1Data)),
|
||||
ConvertToADTS(_, sizeof(kSample1Data) - 1, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(StringToVector(kAdtsSample1Data)),
|
||||
Return(true)));
|
||||
|
||||
EXPECT_CALL(segmenter_, CreateAdtsConverter())
|
||||
|
@ -301,8 +302,8 @@ TEST_F(PackedAudioSegmenterTest, AacAddEncryptedSample) {
|
|||
EXPECT_CALL(*mock_adts_converter_, Parse(ElementsAreArray(kCodecConfig)))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*mock_adts_converter_,
|
||||
ConvertToADTS(Pointee(Eq(StringToVector(kSample1Data)))))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(StringToVector(kAdtsSample1Data)),
|
||||
ConvertToADTS(_, sizeof(kSample1Data) - 1, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(StringToVector(kAdtsSample1Data)),
|
||||
Return(true)));
|
||||
|
||||
EXPECT_CALL(segmenter_, CreateAdtsConverter())
|
||||
|
|
Loading…
Reference in New Issue