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

View File

@ -11,62 +11,41 @@
#include <vector> #include <vector>
#include "packager/base/macros.h" #include "packager/media/formats/mp2t/audio_header.h"
namespace shaka { namespace shaka {
namespace media { namespace media {
namespace mp2t { namespace mp2t {
/// Class which parses ADTS headers and synthesizes AudioSpecificConfig /// Class which parses ADTS frame (header / metadata) and synthesizes
/// and audio mime type from ADTS header contents. /// AudioSpecificConfig from audio frame content.
class AdtsHeader { class AdtsHeader : public AudioHeader {
public: public:
AdtsHeader(); AdtsHeader() = default;
~AdtsHeader() {} ~AdtsHeader() override = default;
/// Get the size of the ADTS frame from a partial or complete frame. /// @name AudioHeader implementation overrides.
/// @param data is a pointer to the beginning of the ADTS frame. /// @{
/// @param num_bytes is the number of data bytes at @a data. bool IsSyncWord(const uint8_t* buf) const override;
/// @return Size of the ADTS frame (header + payload) if successful, or size_t GetMinFrameSize() const override;
/// zero otherwise. bool Parse(const uint8_t* adts_frame, size_t adts_frame_size) override;
static size_t GetAdtsFrameSize(const uint8_t* data, size_t num_bytes); size_t GetHeaderSize() const override;
size_t GetFrameSize() const override;
/// Get the size of the ADTS header from a partial or complete frame. void GetAudioSpecificConfig(std::vector<uint8_t>* buffer) const override;
/// @param data is a pointer to the beginning of the ADTS frame. uint8_t GetObjectType() const override;
/// @param num_bytes is the number of data bytes at @a data. uint32_t GetSamplingFrequency() const override;
/// @return Size of the ADTS header if successful, or zero otherwise. uint8_t GetNumChannels() const override;
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;
private: private:
bool valid_config_; AdtsHeader(const AdtsHeader&) = delete;
uint8_t profile_; AdtsHeader& operator=(const AdtsHeader&) = delete;
uint8_t sampling_frequency_index_;
uint8_t channel_configuration_;
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 } // namespace mp2t

View File

@ -4,7 +4,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "packager/base/compiler_specific.h"
#include "packager/base/logging.h" #include "packager/base/logging.h"
#include "packager/base/strings/string_number_conversions.h" #include "packager/base/strings/string_number_conversions.h"
#include "packager/media/formats/mp2t/adts_header.h" #include "packager/media/formats/mp2t/adts_header.h"
@ -50,16 +49,19 @@ class AdtsHeaderTest : public testing::Test {
}; };
TEST_F(AdtsHeaderTest, ParseSuccess) { TEST_F(AdtsHeaderTest, ParseSuccess) {
const size_t kExpectedHeaderSize(7);
const uint8_t kExpectedObjectType(2); const uint8_t kExpectedObjectType(2);
const uint32_t kExpectedSamplingFrequency(44100); const uint32_t kExpectedSamplingFrequency(44100);
const uint8_t kExpectedNumChannels(2); const uint8_t kExpectedNumChannels(2);
AdtsHeader adts_header; 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(kExpectedObjectType, adts_header.GetObjectType());
EXPECT_EQ(kExpectedSamplingFrequency, adts_header.GetSamplingFrequency()); EXPECT_EQ(kExpectedSamplingFrequency, adts_header.GetSamplingFrequency());
EXPECT_EQ(kExpectedNumChannels, adts_header.GetNumChannels()); EXPECT_EQ(kExpectedNumChannels, adts_header.GetNumChannels());
std::vector<uint8_t> audio_specific_config; 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), EXPECT_EQ(arraysize(kExpectedAudioSpecificConfig),
audio_specific_config.size()); audio_specific_config.size());
EXPECT_EQ(std::vector<uint8_t>(kExpectedAudioSpecificConfig, EXPECT_EQ(std::vector<uint8_t>(kExpectedAudioSpecificConfig,
@ -68,25 +70,21 @@ TEST_F(AdtsHeaderTest, ParseSuccess) {
audio_specific_config); audio_specific_config);
} }
TEST_F(AdtsHeaderTest, ParseFailFrameSize) { TEST_F(AdtsHeaderTest, ParseVariousDataSize) {
AdtsHeader adts_header; 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)); EXPECT_FALSE(adts_header.Parse(adts_frame_.data(), 1));
} EXPECT_FALSE(adts_header.Parse(adts_frame_.data(), header_size - 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()));
} }
} // Namespace mp2t } // 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 shaka {
namespace media { namespace media {
namespace mp2t {
// Return true if buf corresponds to an ADTS syncword. // Look for a 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.
// |new_pos| returns // |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). // - 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 // 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. // Return whether a syncword was found.
static bool LookForSyncWord(const uint8_t* raw_es, static bool LookForSyncWord(const uint8_t* raw_es,
int raw_es_size, int raw_es_size,
int pos, int pos,
int* new_pos, int* new_pos,
int* frame_sz) { AudioHeader* audio_header) {
DCHECK_GE(pos, 0); DCHECK_GE(pos, 0);
DCHECK_LE(pos, raw_es_size); 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) { if (pos >= max_offset) {
// Do not change the position if: // Do not change the position if:
// - max_offset < 0: not enough bytes to get a full header // - 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++) { for (int offset = pos; offset < max_offset; offset++) {
const uint8_t* cur_buf = &raw_es[offset]; const uint8_t* cur_buf = &raw_es[offset];
if (!isAdtsSyncWord(cur_buf)) if (!audio_header->IsSyncWord(cur_buf))
// The first 12 bits must be 1.
// The layer field (2 bits) must be set to 0.
continue; continue;
int frame_size = static_cast<int>( if (!audio_header->Parse(cur_buf, raw_es_size - offset))
mp2t::AdtsHeader::GetAdtsFrameSize(cur_buf, kAdtsHeaderMinSize));
if (frame_size < kAdtsHeaderMinSize) {
// Too short to be an ADTS frame.
continue; continue;
}
// Check whether there is another frame // Check whether there is another frame |size| apart from the current one.
// |size| apart from the current one. const size_t remaining_size = static_cast<size_t>(raw_es_size - offset);
int remaining_size = raw_es_size - offset; const int kSyncWordSize = 2;
if (remaining_size >= frame_size + 2 && if (remaining_size >= audio_header->GetFrameSize() + kSyncWordSize &&
!isAdtsSyncWord(&cur_buf[frame_size])) { !audio_header->IsSyncWord(&cur_buf[audio_header->GetFrameSize()])) {
continue; continue;
} }
*new_pos = offset; *new_pos = offset;
*frame_sz = frame_size;
return true; return true;
} }
@ -87,17 +77,15 @@ static bool LookForSyncWord(const uint8_t* raw_es,
return false; return false;
} }
namespace mp2t {
EsParserAdts::EsParserAdts(uint32_t pid, EsParserAdts::EsParserAdts(uint32_t pid,
const NewStreamInfoCB& new_stream_info_cb, const NewStreamInfoCB& new_stream_info_cb,
const EmitSampleCB& emit_sample_cb, const EmitSampleCB& emit_sample_cb,
bool sbr_in_mimetype) bool sbr_in_mimetype)
: EsParser(pid), : EsParser(pid),
audio_header_(new AdtsHeader),
new_stream_info_cb_(new_stream_info_cb), new_stream_info_cb_(new_stream_info_cb),
emit_sample_cb_(emit_sample_cb), emit_sample_cb_(emit_sample_cb),
sbr_in_mimetype_(sbr_in_mimetype) { sbr_in_mimetype_(sbr_in_mimetype) {}
}
EsParserAdts::~EsParserAdts() { 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_.Push(buf, static_cast<int>(size));
es_byte_queue_.Peek(&raw_es, &raw_es_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 es_position = 0;
int frame_size; while (LookForSyncWord(raw_es, raw_es_size, es_position, &es_position,
while (LookForSyncWord(raw_es, raw_es_size, es_position, audio_header_.get())) {
&es_position, &frame_size)) {
const uint8_t* frame_ptr = raw_es + es_position; const uint8_t* frame_ptr = raw_es + es_position;
DVLOG(LOG_LEVEL_ES) DVLOG(LOG_LEVEL_ES) << "syncword @ pos=" << es_position
<< "ADTS syncword @ pos=" << es_position << " frame_size=" << audio_header_->GetFrameSize();
<< " frame_size=" << frame_size; DVLOG(LOG_LEVEL_ES) << "header: "
DVLOG(LOG_LEVEL_ES) << base::HexEncode(frame_ptr,
<< "ADTS header: " audio_header_->GetHeaderSize());
<< base::HexEncode(frame_ptr, kAdtsHeaderMinSize);
// Do not process the frame if this one is a partial frame. // Do not process the frame if this one is a partial frame.
int remaining_size = raw_es_size - es_position; int remaining_size = raw_es_size - es_position;
if (frame_size > remaining_size) if (static_cast<int>(audio_header_->GetFrameSize()) > remaining_size)
break; break;
size_t header_size = AdtsHeader::GetAdtsHeaderSize(frame_ptr, frame_size);
// Update the audio configuration if needed. // Update the audio configuration if needed.
DCHECK_GE(frame_size, kAdtsHeaderMinSize); if (!UpdateAudioConfiguration(*audio_header_))
if (!UpdateAudioConfiguration(frame_ptr, frame_size))
return false; return false;
// Get the PTS & the duration of this access unit. // 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; bool is_key_frame = true;
std::shared_ptr<MediaSample> sample = MediaSample::CopyFrom( 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_pts(current_pts);
sample->set_dts(current_pts); sample->set_dts(current_pts);
sample->set_duration(frame_duration); sample->set_duration(frame_duration);
@ -170,7 +155,7 @@ bool EsParserAdts::Parse(const uint8_t* buf,
audio_timestamp_helper_->AddFrames(kSamplesPerAACFrame); audio_timestamp_helper_->AddFrames(kSamplesPerAACFrame);
// Skip the current frame. // Skip the current frame.
es_position += frame_size; es_position += static_cast<int>(audio_header_->GetFrameSize());
} }
// Discard all the bytes that have been processed. // Discard all the bytes that have been processed.
@ -188,18 +173,11 @@ void EsParserAdts::Reset() {
last_audio_decoder_config_ = std::shared_ptr<AudioStreamInfo>(); last_audio_decoder_config_ = std::shared_ptr<AudioStreamInfo>();
} }
bool EsParserAdts::UpdateAudioConfiguration(const uint8_t* adts_frame, bool EsParserAdts::UpdateAudioConfiguration(const AudioHeader& audio_header) {
size_t adts_frame_size) {
const uint8_t kAacSampleSizeBits(16); 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; std::vector<uint8_t> audio_specific_config;
if (!adts_header.GetAudioSpecificConfig(&audio_specific_config)) audio_header.GetAudioSpecificConfig(&audio_specific_config);
return false;
if (last_audio_decoder_config_) { if (last_audio_decoder_config_) {
// Verify that the audio decoder config has not changed. // 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 // 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 // Table 1.22. (Table 1.11 refers to the capping to 48000, Table 1.22 refers
// to SBR doubling the AAC sample rate.) // 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_ int extended_samples_per_second = sbr_in_mimetype_
? std::min(2 * samples_per_second, 48000) ? std::min(2 * samples_per_second, 48000)
: samples_per_second; : samples_per_second;
const Codec codec = kCodecAAC;
last_audio_decoder_config_ = std::make_shared<AudioStreamInfo>( last_audio_decoder_config_ = std::make_shared<AudioStreamInfo>(
pid(), kMpeg2Timescale, kInfiniteDuration, kCodecAAC, pid(), kMpeg2Timescale, kInfiniteDuration, codec,
AudioStreamInfo::GetCodecString(kCodecAAC, adts_header.GetObjectType()), AudioStreamInfo::GetCodecString(codec, audio_header.GetObjectType()),
audio_specific_config.data(), audio_specific_config.size(), 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 */, extended_samples_per_second, 0 /* seek preroll */, 0 /* codec delay */,
0 /* max bitrate */, 0 /* avg bitrate */, std::string(), false); 0 /* max bitrate */, 0 /* avg bitrate */, std::string(), false);
DVLOG(1) << "Sampling frequency: " << samples_per_second; DVLOG(1) << "Sampling frequency: " << samples_per_second;
DVLOG(1) << "Extended sampling frequency: " << extended_samples_per_second; DVLOG(1) << "Extended sampling frequency: " << extended_samples_per_second;
DVLOG(1) << "Channel config: " << adts_header.GetNumChannels(); DVLOG(1) << "Channel config: "
DVLOG(1) << "Object type: " << adts_header.GetObjectType(); << 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. // Reset the timestamp helper to use a new sampling frequency.
if (audio_timestamp_helper_) { if (audio_timestamp_helper_) {
int64_t base_timestamp = audio_timestamp_helper_->GetTimestamp(); int64_t base_timestamp = audio_timestamp_helper_->GetTimestamp();

View File

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

View File

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

View File

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