Refactor EsParserAdts to handle other audio

Rename will happen in next CL

Change-Id: I28df29bb264eea7a6225b0a4a2eb38de7968f9d6
This commit is contained in:
KongQun Yang 2017-10-22 22:27:27 -07:00
parent 867244645a
commit 2a2493ec2e
8 changed files with 202 additions and 181 deletions

View File

@ -7,6 +7,7 @@
#include "packager/media/formats/mp2t/adts_header.h"
#include "packager/media/base/bit_reader.h"
#include "packager/media/base/bit_writer.h"
#include "packager/media/formats/mp2t/mp2t_common.h"
#include "packager/media/formats/mpeg/adts_constants.h"
@ -14,32 +15,19 @@ namespace shaka {
namespace media {
namespace mp2t {
AdtsHeader::AdtsHeader()
: valid_config_(false),
profile_(0),
sampling_frequency_index_(0),
channel_configuration_(0) {}
size_t AdtsHeader::GetAdtsFrameSize(const uint8_t* data, size_t num_bytes) {
if (num_bytes < 6)
return 0;
return ((static_cast<int>(data[5]) >> 5) |
(static_cast<int>(data[4]) << 3) |
((static_cast<int>(data[3]) & 0x3) << 11));
bool AdtsHeader::IsSyncWord(const uint8_t* buf) const {
return (buf[0] == 0xff) && ((buf[1] & 0xf6) == 0xf0);
}
size_t AdtsHeader::GetAdtsHeaderSize(const uint8_t* data, size_t num_bytes) {
if (num_bytes < 2)
return 0;
if (data[1] & 0x01)
return kAdtsHeaderMinSize;
return kAdtsHeaderMinSize + sizeof(uint16_t); // Header + CRC.
size_t AdtsHeader::GetMinFrameSize() const {
return kAdtsHeaderMinSize + 1;
}
bool AdtsHeader::Parse(const uint8_t* adts_frame, size_t adts_frame_size) {
CHECK(adts_frame);
valid_config_ = false;
if (adts_frame_size < kAdtsHeaderMinSize)
return false;
BitReader frame(adts_frame, adts_frame_size);
// Verify frame starts with sync bits (0xfff).
@ -48,26 +36,18 @@ bool AdtsHeader::Parse(const uint8_t* adts_frame, size_t adts_frame_size) {
RCHECK(sync == 0xfff);
// Skip MPEG version and layer.
RCHECK(frame.SkipBits(3));
// Get "protection absent" flag.
uint8_t protection_absent;
RCHECK(frame.ReadBits(1, &protection_absent));
// Get profile.
RCHECK(frame.ReadBits(1, &protection_absent_));
RCHECK(frame.ReadBits(2, &profile_));
// Get sampling frequency.
RCHECK(frame.ReadBits(4, &sampling_frequency_index_));
RCHECK(sampling_frequency_index_ < kAdtsFrequencyTableSize);
// Skip private stream bit.
RCHECK(frame.SkipBits(1));
// Get number of audio channels.
RCHECK(frame.ReadBits(3, &channel_configuration_));
RCHECK((channel_configuration_ > 0) &&
(channel_configuration_ < kAdtsNumChannelsTableSize));
// Skip originality, home and copyright info.
RCHECK(frame.SkipBits(4));
// Verify that the frame size matches input parameters.
uint16_t frame_size;
RCHECK(frame.ReadBits(13, &frame_size));
RCHECK(frame_size == adts_frame_size);
RCHECK(frame.ReadBits(13, &frame_size_));
// Skip buffer fullness indicator.
RCHECK(frame.SkipBits(11));
uint8_t num_blocks_minus_1;
@ -77,21 +57,26 @@ bool AdtsHeader::Parse(const uint8_t* adts_frame, size_t adts_frame_size) {
"not supported.";
return false;
}
valid_config_ = true;
return true;
}
bool AdtsHeader::GetAudioSpecificConfig(std::vector<uint8_t>* buffer) const {
DCHECK(buffer);
if (!valid_config_)
return false;
size_t AdtsHeader::GetHeaderSize() const {
const size_t kCrcSize = sizeof(uint16_t);
return kAdtsHeaderMinSize + (protection_absent_ ? 0 : kCrcSize);
}
buffer->resize(2);
(*buffer)[0] = ((profile_ + 1) << 3) | (sampling_frequency_index_ >> 1);
(*buffer)[1] = ((sampling_frequency_index_ & 1) << 7) |
(channel_configuration_ << 3);
return true;
size_t AdtsHeader::GetFrameSize() const {
return frame_size_;
}
void AdtsHeader::GetAudioSpecificConfig(std::vector<uint8_t>* buffer) const {
DCHECK(buffer);
buffer->clear();
BitWriter config(buffer);
config.WriteBits(GetObjectType(), 5);
config.WriteBits(sampling_frequency_index_, 4);
config.WriteBits(channel_configuration_, 4);
config.Flush();
}
uint8_t AdtsHeader::GetObjectType() const {

View File

@ -11,62 +11,41 @@
#include <vector>
#include "packager/base/macros.h"
#include "packager/media/formats/mp2t/audio_header.h"
namespace shaka {
namespace media {
namespace mp2t {
/// Class which parses ADTS headers and synthesizes AudioSpecificConfig
/// and audio mime type from ADTS header contents.
class AdtsHeader {
/// Class which parses ADTS frame (header / metadata) and synthesizes
/// AudioSpecificConfig from audio frame content.
class AdtsHeader : public AudioHeader {
public:
AdtsHeader();
~AdtsHeader() {}
AdtsHeader() = default;
~AdtsHeader() override = default;
/// Get the size of the ADTS frame from a partial or complete frame.
/// @param data is a pointer to the beginning of the ADTS frame.
/// @param num_bytes is the number of data bytes at @a data.
/// @return Size of the ADTS frame (header + payload) if successful, or
/// zero otherwise.
static size_t GetAdtsFrameSize(const uint8_t* data, size_t num_bytes);
/// Get the size of the ADTS header from a partial or complete frame.
/// @param data is a pointer to the beginning of the ADTS frame.
/// @param num_bytes is the number of data bytes at @a data.
/// @return Size of the ADTS header if successful, or zero otherwise.
static size_t GetAdtsHeaderSize(const uint8_t* data, size_t num_bytes);
/// Parse an ADTS header, extracting the fields within.
/// @param adts_frame is an input parameter pointing to the ADTS header
/// of an ADTS-framed audio sample.
/// @param adts_frame_size is the size, in bytes of the input ADTS frame.
/// @return true if successful, false otherwise.
bool Parse(const uint8_t* adts_frame, size_t adts_frame_size);
/// Synthesize an AudioSpecificConfig record from the fields within the ADTS
/// header.
/// @param [out] buffer is a pointer to a vector to contain the
/// AudioSpecificConfig.
/// @return true if successful, false otherwise.
bool GetAudioSpecificConfig(std::vector<uint8_t>* buffer) const;
/// @return The audio profile for this ADTS frame.
uint8_t GetObjectType() const;
/// @return The sampling frequency for this ADTS frame.
uint32_t GetSamplingFrequency() const;
/// @return Number of channels for this AAC config.
uint8_t GetNumChannels() const;
/// @name AudioHeader implementation overrides.
/// @{
bool IsSyncWord(const uint8_t* buf) const override;
size_t GetMinFrameSize() const override;
bool Parse(const uint8_t* adts_frame, size_t adts_frame_size) override;
size_t GetHeaderSize() const override;
size_t GetFrameSize() const override;
void GetAudioSpecificConfig(std::vector<uint8_t>* buffer) const override;
uint8_t GetObjectType() const override;
uint32_t GetSamplingFrequency() const override;
uint8_t GetNumChannels() const override;
/// @}
private:
bool valid_config_;
uint8_t profile_;
uint8_t sampling_frequency_index_;
uint8_t channel_configuration_;
AdtsHeader(const AdtsHeader&) = delete;
AdtsHeader& operator=(const AdtsHeader&) = delete;
DISALLOW_COPY_AND_ASSIGN(AdtsHeader);
uint8_t protection_absent_ = 0;
uint16_t frame_size_ = 0;
uint8_t profile_ = 0;
uint8_t sampling_frequency_index_ = 0;
uint8_t channel_configuration_ = 0;
};
} // namespace mp2t

View File

@ -4,7 +4,6 @@
#include <gtest/gtest.h>
#include "packager/base/compiler_specific.h"
#include "packager/base/logging.h"
#include "packager/base/strings/string_number_conversions.h"
#include "packager/media/formats/mp2t/adts_header.h"
@ -50,16 +49,19 @@ class AdtsHeaderTest : public testing::Test {
};
TEST_F(AdtsHeaderTest, ParseSuccess) {
const size_t kExpectedHeaderSize(7);
const uint8_t kExpectedObjectType(2);
const uint32_t kExpectedSamplingFrequency(44100);
const uint8_t kExpectedNumChannels(2);
AdtsHeader adts_header;
EXPECT_TRUE(adts_header.Parse(adts_frame_.data(), adts_frame_.size()));
ASSERT_TRUE(adts_header.Parse(adts_frame_.data(), adts_frame_.size()));
EXPECT_EQ(adts_frame_.size(), adts_header.GetFrameSize());
EXPECT_EQ(kExpectedHeaderSize, adts_header.GetHeaderSize());
EXPECT_EQ(kExpectedObjectType, adts_header.GetObjectType());
EXPECT_EQ(kExpectedSamplingFrequency, adts_header.GetSamplingFrequency());
EXPECT_EQ(kExpectedNumChannels, adts_header.GetNumChannels());
std::vector<uint8_t> audio_specific_config;
ASSERT_TRUE(adts_header.GetAudioSpecificConfig(&audio_specific_config));
adts_header.GetAudioSpecificConfig(&audio_specific_config);
EXPECT_EQ(arraysize(kExpectedAudioSpecificConfig),
audio_specific_config.size());
EXPECT_EQ(std::vector<uint8_t>(kExpectedAudioSpecificConfig,
@ -68,25 +70,21 @@ TEST_F(AdtsHeaderTest, ParseSuccess) {
audio_specific_config);
}
TEST_F(AdtsHeaderTest, ParseFailFrameSize) {
TEST_F(AdtsHeaderTest, ParseVariousDataSize) {
AdtsHeader adts_header;
EXPECT_FALSE(adts_header.Parse(adts_frame_.data(), adts_frame_.size() - 1));
EXPECT_FALSE(adts_header.Parse(adts_frame_.data(), adts_frame_.size() + 1));
// Parse succeeds as long as the full header is provided.
EXPECT_TRUE(adts_header.Parse(adts_frame_.data(), adts_frame_.size() - 1));
const size_t header_size = adts_header.GetHeaderSize();
EXPECT_EQ(adts_frame_.size(), adts_header.GetFrameSize());
EXPECT_TRUE(adts_header.Parse(adts_frame_.data(), header_size));
EXPECT_EQ(adts_frame_.size(), adts_header.GetFrameSize());
EXPECT_EQ(header_size, adts_header.GetHeaderSize());
// Parse fails if there is not enough data (no full header).
EXPECT_FALSE(adts_header.Parse(adts_frame_.data(), 1));
}
TEST_F(AdtsHeaderTest, GetFrameSizeSuccess) {
EXPECT_EQ(adts_frame_.size(),
AdtsHeader::GetAdtsFrameSize(adts_frame_.data(),
adts_frame_.size()));
}
TEST_F(AdtsHeaderTest, GetHeaderSizeSuccess) {
const size_t kExpectedHeaderSize(7);
EXPECT_EQ(kExpectedHeaderSize,
AdtsHeader::GetAdtsHeaderSize(adts_frame_.data(),
adts_frame_.size()));
EXPECT_FALSE(adts_header.Parse(adts_frame_.data(), header_size - 1));
}
} // Namespace mp2t

View File

@ -0,0 +1,79 @@
// Copyright 2017 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#ifndef PACKAGER_MEDIA_FORMATS_MP2T_AUDIO_HEADER_H_
#define PACKAGER_MEDIA_FORMATS_MP2T_AUDIO_HEADER_H_
#include <stddef.h>
#include <stdint.h>
#include <vector>
namespace shaka {
namespace media {
namespace mp2t {
class AudioHeader {
public:
AudioHeader() = default;
virtual ~AudioHeader() = default;
/// Check if the leading word (2 bytes) is sync signal.
/// @param buf points to the buffer to be checked. Must be at least 2 bytes.
/// @return true if corresponds to a syncword.
virtual bool IsSyncWord(const uint8_t* buf) const = 0;
/// @return The minium frame size.
virtual size_t GetMinFrameSize() const = 0;
/// Parse a partial audio frame, extracting the fields within. Only audio
/// frame header / metadata is parsed. The audio_frame_size must contain the
/// full header / metadata.
/// @param audio_frame is an input parameter pointing to an audio frame.
/// @param audio_frame_size is the size, in bytes of the input data. It can be
/// smaller than the actual frame size, but it should not be smaller
/// than the header size.
/// @return true if successful, false otherwise.
virtual bool Parse(const uint8_t* audio_frame, size_t audio_frame_size) = 0;
/// Should only be called after a successful Parse.
/// @return The size of audio header.
virtual size_t GetHeaderSize() const = 0;
/// Should only be called after a successful Parse.
/// @return the size of frame (header + payload).
virtual size_t GetFrameSize() const = 0;
/// Synthesize an AudioSpecificConfig record from the fields within the audio
/// header.
/// Should only be called after a successful Parse.
/// @param [out] buffer is a pointer to a vector to contain the
/// AudioSpecificConfig.
/// @return true if successful, false otherwise.
virtual void GetAudioSpecificConfig(std::vector<uint8_t>* buffer) const = 0;
/// Should only be called after a successful Parse.
/// @return The audio profile for this frame. Only meaningful for AAC.
virtual uint8_t GetObjectType() const = 0;
/// Should only be called after a successful Parse.
/// @return The sampling frequency for this frame.
virtual uint32_t GetSamplingFrequency() const = 0;
/// Should only be called after a successful Parse.
/// @return Number of channels for this frame.
virtual uint8_t GetNumChannels() const = 0;
private:
AudioHeader(const AudioHeader&) = delete;
AudioHeader& operator=(const AudioHeader&) = delete;
};
} // namespace mp2t
} // namespace media
} // namespace shaka
#endif // PACKAGER_MEDIA_FORMATS_MP2T_AUDIO_HEADER_H_

View File

@ -21,29 +21,26 @@
namespace shaka {
namespace media {
namespace mp2t {
// Return true if buf corresponds to an ADTS syncword.
// |buf| size must be at least 2.
static bool isAdtsSyncWord(const uint8_t* buf) {
return (buf[0] == 0xff) && ((buf[1] & 0xf6) == 0xf0);
}
// Look for an ADTS syncword.
// Look for a syncword.
// |new_pos| returns
// - either the byte position of the ADTS frame (if found)
// - either the byte position of the frame (if found)
// - or the byte position of 1st byte that was not processed (if not found).
// In every case, the returned value in |new_pos| is such that new_pos >= pos
// |frame_sz| returns the size of the ADTS frame (if found).
// |audio_header| is updated with the new audio frame info if a syncword is
// found.
// Return whether a syncword was found.
static bool LookForSyncWord(const uint8_t* raw_es,
int raw_es_size,
int pos,
int* new_pos,
int* frame_sz) {
AudioHeader* audio_header) {
DCHECK_GE(pos, 0);
DCHECK_LE(pos, raw_es_size);
int max_offset = raw_es_size - kAdtsHeaderMinSize;
const int max_offset =
raw_es_size - static_cast<int>(audio_header->GetMinFrameSize());
if (pos >= max_offset) {
// Do not change the position if:
// - max_offset < 0: not enough bytes to get a full header
@ -58,28 +55,21 @@ static bool LookForSyncWord(const uint8_t* raw_es,
for (int offset = pos; offset < max_offset; offset++) {
const uint8_t* cur_buf = &raw_es[offset];
if (!isAdtsSyncWord(cur_buf))
// The first 12 bits must be 1.
// The layer field (2 bits) must be set to 0.
if (!audio_header->IsSyncWord(cur_buf))
continue;
int frame_size = static_cast<int>(
mp2t::AdtsHeader::GetAdtsFrameSize(cur_buf, kAdtsHeaderMinSize));
if (frame_size < kAdtsHeaderMinSize) {
// Too short to be an ADTS frame.
if (!audio_header->Parse(cur_buf, raw_es_size - offset))
continue;
}
// Check whether there is another frame
// |size| apart from the current one.
int remaining_size = raw_es_size - offset;
if (remaining_size >= frame_size + 2 &&
!isAdtsSyncWord(&cur_buf[frame_size])) {
// Check whether there is another frame |size| apart from the current one.
const size_t remaining_size = static_cast<size_t>(raw_es_size - offset);
const int kSyncWordSize = 2;
if (remaining_size >= audio_header->GetFrameSize() + kSyncWordSize &&
!audio_header->IsSyncWord(&cur_buf[audio_header->GetFrameSize()])) {
continue;
}
*new_pos = offset;
*frame_sz = frame_size;
return true;
}
@ -87,17 +77,15 @@ static bool LookForSyncWord(const uint8_t* raw_es,
return false;
}
namespace mp2t {
EsParserAdts::EsParserAdts(uint32_t pid,
const NewStreamInfoCB& new_stream_info_cb,
const EmitSampleCB& emit_sample_cb,
bool sbr_in_mimetype)
: EsParser(pid),
audio_header_(new AdtsHeader),
new_stream_info_cb_(new_stream_info_cb),
emit_sample_cb_(emit_sample_cb),
sbr_in_mimetype_(sbr_in_mimetype) {
}
sbr_in_mimetype_(sbr_in_mimetype) {}
EsParserAdts::~EsParserAdts() {
}
@ -120,29 +108,24 @@ bool EsParserAdts::Parse(const uint8_t* buf,
es_byte_queue_.Push(buf, static_cast<int>(size));
es_byte_queue_.Peek(&raw_es, &raw_es_size);
// Look for every ADTS frame in the ES buffer starting at offset = 0
// Look for every frame in the ES buffer starting at offset = 0
int es_position = 0;
int frame_size;
while (LookForSyncWord(raw_es, raw_es_size, es_position,
&es_position, &frame_size)) {
while (LookForSyncWord(raw_es, raw_es_size, es_position, &es_position,
audio_header_.get())) {
const uint8_t* frame_ptr = raw_es + es_position;
DVLOG(LOG_LEVEL_ES)
<< "ADTS syncword @ pos=" << es_position
<< " frame_size=" << frame_size;
DVLOG(LOG_LEVEL_ES)
<< "ADTS header: "
<< base::HexEncode(frame_ptr, kAdtsHeaderMinSize);
DVLOG(LOG_LEVEL_ES) << "syncword @ pos=" << es_position
<< " frame_size=" << audio_header_->GetFrameSize();
DVLOG(LOG_LEVEL_ES) << "header: "
<< base::HexEncode(frame_ptr,
audio_header_->GetHeaderSize());
// Do not process the frame if this one is a partial frame.
int remaining_size = raw_es_size - es_position;
if (frame_size > remaining_size)
if (static_cast<int>(audio_header_->GetFrameSize()) > remaining_size)
break;
size_t header_size = AdtsHeader::GetAdtsHeaderSize(frame_ptr, frame_size);
// Update the audio configuration if needed.
DCHECK_GE(frame_size, kAdtsHeaderMinSize);
if (!UpdateAudioConfiguration(frame_ptr, frame_size))
if (!UpdateAudioConfiguration(*audio_header_))
return false;
// Get the PTS & the duration of this access unit.
@ -160,7 +143,9 @@ bool EsParserAdts::Parse(const uint8_t* buf,
bool is_key_frame = true;
std::shared_ptr<MediaSample> sample = MediaSample::CopyFrom(
frame_ptr + header_size, frame_size - header_size, is_key_frame);
frame_ptr + audio_header_->GetHeaderSize(),
audio_header_->GetFrameSize() - audio_header_->GetHeaderSize(),
is_key_frame);
sample->set_pts(current_pts);
sample->set_dts(current_pts);
sample->set_duration(frame_duration);
@ -170,7 +155,7 @@ bool EsParserAdts::Parse(const uint8_t* buf,
audio_timestamp_helper_->AddFrames(kSamplesPerAACFrame);
// Skip the current frame.
es_position += frame_size;
es_position += static_cast<int>(audio_header_->GetFrameSize());
}
// Discard all the bytes that have been processed.
@ -188,18 +173,11 @@ void EsParserAdts::Reset() {
last_audio_decoder_config_ = std::shared_ptr<AudioStreamInfo>();
}
bool EsParserAdts::UpdateAudioConfiguration(const uint8_t* adts_frame,
size_t adts_frame_size) {
bool EsParserAdts::UpdateAudioConfiguration(const AudioHeader& audio_header) {
const uint8_t kAacSampleSizeBits(16);
AdtsHeader adts_header;
if (!adts_header.Parse(adts_frame, adts_frame_size)) {
LOG(ERROR) << "Error parsing ADTS frame header.";
return false;
}
std::vector<uint8_t> audio_specific_config;
if (!adts_header.GetAudioSpecificConfig(&audio_specific_config))
return false;
audio_header.GetAudioSpecificConfig(&audio_specific_config);
if (last_audio_decoder_config_) {
// Verify that the audio decoder config has not changed.
@ -214,23 +192,27 @@ bool EsParserAdts::UpdateAudioConfiguration(const uint8_t* adts_frame,
// The following code is written according to ISO 14496 Part 3 Table 1.11 and
// Table 1.22. (Table 1.11 refers to the capping to 48000, Table 1.22 refers
// to SBR doubling the AAC sample rate.)
int samples_per_second = adts_header.GetSamplingFrequency();
int samples_per_second = audio_header.GetSamplingFrequency();
// TODO(kqyang): Review if it makes sense to have |sbr_in_mimetype_| in
// es_parser.
int extended_samples_per_second = sbr_in_mimetype_
? std::min(2 * samples_per_second, 48000)
: samples_per_second;
const Codec codec = kCodecAAC;
last_audio_decoder_config_ = std::make_shared<AudioStreamInfo>(
pid(), kMpeg2Timescale, kInfiniteDuration, kCodecAAC,
AudioStreamInfo::GetCodecString(kCodecAAC, adts_header.GetObjectType()),
pid(), kMpeg2Timescale, kInfiniteDuration, codec,
AudioStreamInfo::GetCodecString(codec, audio_header.GetObjectType()),
audio_specific_config.data(), audio_specific_config.size(),
kAacSampleSizeBits, adts_header.GetNumChannels(),
kAacSampleSizeBits, audio_header.GetNumChannels(),
extended_samples_per_second, 0 /* seek preroll */, 0 /* codec delay */,
0 /* max bitrate */, 0 /* avg bitrate */, std::string(), false);
DVLOG(1) << "Sampling frequency: " << samples_per_second;
DVLOG(1) << "Extended sampling frequency: " << extended_samples_per_second;
DVLOG(1) << "Channel config: " << adts_header.GetNumChannels();
DVLOG(1) << "Object type: " << adts_header.GetObjectType();
DVLOG(1) << "Channel config: "
<< static_cast<int>(audio_header.GetNumChannels());
DVLOG(1) << "Object type: " << static_cast<int>(audio_header.GetObjectType());
// Reset the timestamp helper to use a new sampling frequency.
if (audio_timestamp_helper_) {
int64_t base_timestamp = audio_timestamp_helper_->GetTimestamp();

View File

@ -22,6 +22,8 @@ class BitReader;
namespace mp2t {
class AudioHeader;
class EsParserAdts : public EsParser {
public:
EsParserAdts(uint32_t pid,
@ -41,13 +43,14 @@ class EsParserAdts : public EsParser {
typedef std::list<EsPts> EsPtsList;
// Signal any audio configuration change (if any).
// Return false if the current audio config is not
// a supported ADTS audio config.
bool UpdateAudioConfiguration(const uint8_t* adts_frame, size_t frame_size);
// Return false if the current audio config is not a supported audio config.
bool UpdateAudioConfiguration(const AudioHeader& audio_header);
// Discard some bytes from the ES stream.
void DiscardEs(int nbytes);
std::unique_ptr<AudioHeader> audio_header_;
// Callbacks:
// - to signal a new audio configuration,
// - to send ES buffers.

View File

@ -15,6 +15,7 @@
'sources': [
'adts_header.cc',
'adts_header.h',
'audio_header.h',
'continuity_counter.cc',
'continuity_counter.h',
'es_parser_adts.cc',

View File

@ -48,7 +48,6 @@ const uint32_t kPesStreamIdVideo = 0xE0;
const uint32_t kPesStreamIdAudioMask = 0xE0;
const uint32_t kPesStreamIdAudio = 0xC0;
const uint32_t kVersion4 = 4;
const size_t kAdtsHeaderMinSize = 7;
const uint8_t kAacSampleSizeBits = 16;
// Applies to all video streams.
const uint8_t kNaluLengthSize = 4; // unit is bytes.
@ -904,17 +903,15 @@ bool WvmMediaParser::Output(bool output_encrypted_sample) {
} else if ((prev_pes_stream_id_ & kPesStreamIdAudioMask) ==
kPesStreamIdAudio) {
// Set data on the audio stream.
int frame_size = static_cast<int>(mp2t::AdtsHeader::GetAdtsFrameSize(
sample_data_.data(), kAdtsHeaderMinSize));
mp2t::AdtsHeader adts_header;
const uint8_t* frame_ptr = sample_data_.data();
if (!adts_header.Parse(frame_ptr, frame_size)) {
if (!adts_header.Parse(frame_ptr, sample_data_.size())) {
LOG(ERROR) << "Could not parse ADTS header";
return false;
}
size_t header_size = adts_header.GetAdtsHeaderSize(frame_ptr,
frame_size);
media_sample_->SetData(frame_ptr + header_size, frame_size - header_size);
media_sample_->SetData(
frame_ptr + adts_header.GetHeaderSize(),
adts_header.GetFrameSize() - adts_header.GetHeaderSize());
if (!is_initialized_) {
for (uint32_t i = 0; i < stream_infos_.size(); i++) {
if (stream_infos_[i]->stream_type() == kStreamAudio &&
@ -927,10 +924,7 @@ bool WvmMediaParser::Output(bool output_encrypted_sample) {
audio_stream_info->set_sampling_frequency(
adts_header.GetSamplingFrequency());
std::vector<uint8_t> audio_specific_config;
if (!adts_header.GetAudioSpecificConfig(&audio_specific_config)) {
LOG(ERROR) << "Could not compute AACAudiospecificconfig";
return false;
}
adts_header.GetAudioSpecificConfig(&audio_specific_config);
audio_stream_info->set_codec_config(audio_specific_config);
audio_stream_info->set_codec_string(
AudioStreamInfo::GetCodecString(