Add duration, language, codec data to stream info.

Change-Id: I83d221fd36adb53ccf5629c80b137ba0ec730d55
This commit is contained in:
Kongqun Yang 2013-10-14 13:55:48 -07:00 committed by KongQun Yang
parent e82f0c00c1
commit 3f3d9a6b76
12 changed files with 283 additions and 147 deletions

View File

@ -6,48 +6,68 @@
#include <sstream> #include <sstream>
#include "base/strings/string_number_conversions.h"
#include "media/base/limits.h" #include "media/base/limits.h"
namespace media { namespace media {
AudioStreamInfo::AudioStreamInfo(int track_id, AudioStreamInfo::AudioStreamInfo(int track_id,
int time_scale, uint32 time_scale,
uint64 duration,
AudioCodec codec, AudioCodec codec,
int bytes_per_channel, const std::string& codec_string,
int num_channels, const std::string& language,
int samples_per_second, uint8 sample_bits,
uint8 num_channels,
uint32 sampling_frequency,
const uint8* extra_data, const uint8* extra_data,
size_t extra_data_size, size_t extra_data_size,
bool is_encrypted) bool is_encrypted)
: StreamInfo(kStreamAudio, : StreamInfo(kStreamAudio,
track_id, track_id,
time_scale, time_scale,
duration,
codec_string,
language,
extra_data, extra_data,
extra_data_size, extra_data_size,
is_encrypted), is_encrypted),
codec_(codec), codec_(codec),
bytes_per_channel_(bytes_per_channel), sample_bits_(sample_bits),
num_channels_(num_channels), num_channels_(num_channels),
samples_per_second_(samples_per_second) {} sampling_frequency_(sampling_frequency) {}
AudioStreamInfo::~AudioStreamInfo() {} AudioStreamInfo::~AudioStreamInfo() {}
bool AudioStreamInfo::IsValidConfig() const { bool AudioStreamInfo::IsValidConfig() const {
return codec_ != kUnknownAudioCodec && num_channels_ != 0 && return codec_ != kUnknownAudioCodec && num_channels_ != 0 &&
num_channels_ <= limits::kMaxChannels && bytes_per_channel_ > 0 && num_channels_ <= limits::kMaxChannels && sample_bits_ > 0 &&
bytes_per_channel_ <= limits::kMaxBytesPerSample && sample_bits_ <= limits::kMaxBitsPerSample &&
samples_per_second_ > 0 && sampling_frequency_ > 0 &&
samples_per_second_ <= limits::kMaxSampleRate; sampling_frequency_ <= limits::kMaxSampleRate;
} }
std::string AudioStreamInfo::ToString() { std::string AudioStreamInfo::ToString() const {
std::ostringstream s; std::ostringstream s;
s << "codec: " << codec_ s << "codec: " << codec_
<< " bytes_per_channel: " << bytes_per_channel_ << " sample_bits: " << static_cast<int>(sample_bits_)
<< " num_channels: " << num_channels_ << " num_channels: " << static_cast<int>(num_channels_)
<< " samples_per_second: " << samples_per_second_ << " sampling_frequency: " << sampling_frequency_
<< " " << StreamInfo::ToString(); << " " << StreamInfo::ToString();
return s.str(); return s.str();
} }
std::string AudioStreamInfo::GetCodecString(AudioCodec codec,
uint8 audio_object_type) {
switch (codec) {
case kCodecVorbis:
return "vorbis";
case kCodecOpus:
return "opus";
case kCodecAAC:
return "mp4a.40." + base::UintToString(audio_object_type);
}
return "unknown";
}
} // namespace media } // namespace media

View File

@ -35,11 +35,14 @@ class AudioStreamInfo : public StreamInfo {
// Constructs an initialized object. It is acceptable to pass in NULL for // Constructs an initialized object. It is acceptable to pass in NULL for
// |extra_data|, otherwise the memory is copied. // |extra_data|, otherwise the memory is copied.
AudioStreamInfo(int track_id, AudioStreamInfo(int track_id,
int time_scale, uint32 time_scale,
uint64 duration,
AudioCodec codec, AudioCodec codec,
int bytes_per_channel, const std::string& codec_string,
int num_channels, const std::string& language,
int samples_per_second, uint8 sample_bits,
uint8 num_channels,
uint32 sampling_frequency,
const uint8* extra_data, const uint8* extra_data,
size_t extra_data_size, size_t extra_data_size,
bool is_encrypted); bool is_encrypted);
@ -48,23 +51,28 @@ class AudioStreamInfo : public StreamInfo {
// Returns true if this object has appropriate configuration values, false // Returns true if this object has appropriate configuration values, false
// otherwise. // otherwise.
virtual bool IsValidConfig() const; virtual bool IsValidConfig() const OVERRIDE;
// Returns a human-readable string describing |*this|. // Returns a human-readable string describing |*this|.
virtual std::string ToString(); virtual std::string ToString() const OVERRIDE;
AudioCodec codec() const { return codec_; } AudioCodec codec() const { return codec_; }
int bits_per_channel() const { return bytes_per_channel_ * 8; } uint8 sample_bits() const { return sample_bits_; }
int bytes_per_channel() const { return bytes_per_channel_; } uint8 sample_bytes() const { return sample_bits_ / 8; }
int num_channels() const { return num_channels_; } uint8 num_channels() const { return num_channels_; }
int samples_per_second() const { return samples_per_second_; } uint32 sampling_frequency() const { return sampling_frequency_; }
int bytes_per_frame() const { return num_channels_ * bytes_per_channel_; } uint32 bytes_per_frame() const {
return static_cast<uint32>(num_channels_) * sample_bits_ / 8;
}
// Returns the codec string. The second parameter is only used by AAC Codec.
static std::string GetCodecString(AudioCodec codec, uint8 audio_object_type);
private: private:
AudioCodec codec_; AudioCodec codec_;
int bytes_per_channel_; uint8 sample_bits_;
int num_channels_; uint8 num_channels_;
int samples_per_second_; uint32 sampling_frequency_;
// Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler
// generated copy constructor and assignment operator. Since the extra data is // generated copy constructor and assignment operator. Since the extra data is

View File

@ -10,13 +10,19 @@ namespace media {
StreamInfo::StreamInfo(StreamType stream_type, StreamInfo::StreamInfo(StreamType stream_type,
int track_id, int track_id,
int time_scale, uint32 time_scale,
uint64 duration,
const std::string& codec_string,
const std::string& language,
const uint8* extra_data, const uint8* extra_data,
size_t extra_data_size, size_t extra_data_size,
bool is_encrypted) bool is_encrypted)
: stream_type_(stream_type), : stream_type_(stream_type),
track_id_(track_id), track_id_(track_id),
time_scale_(time_scale), time_scale_(time_scale),
duration_(duration),
codec_string_(codec_string),
language_(language),
is_encrypted_(is_encrypted) { is_encrypted_(is_encrypted) {
CHECK((extra_data_size != 0) == (extra_data != NULL)); CHECK((extra_data_size != 0) == (extra_data != NULL));
@ -25,11 +31,14 @@ StreamInfo::StreamInfo(StreamType stream_type,
StreamInfo::~StreamInfo() {} StreamInfo::~StreamInfo() {}
std::string StreamInfo::ToString() { std::string StreamInfo::ToString() const {
std::ostringstream s; std::ostringstream s;
s << "type: " << (stream_type_ == kStreamAudio ? "Audio" : "Video") s << "type: " << (stream_type_ == kStreamAudio ? "Audio" : "Video")
<< " track_id: " << track_id_ << " track_id: " << track_id_
<< " time_scale: " << time_scale_ << " time_scale: " << time_scale_
<< " duration: " << duration_
<< " codec_string: " << codec_string_
<< " language: " << language_
<< " is_encrypted: " << is_encrypted_; << " is_encrypted: " << is_encrypted_;
return s.str(); return s.str();
} }

View File

@ -21,7 +21,10 @@ class StreamInfo : public base::RefCountedThreadSafe<StreamInfo> {
public: public:
StreamInfo(StreamType stream_type, StreamInfo(StreamType stream_type,
int track_id, int track_id,
int time_scale, uint32 time_scale,
uint64 duration,
const std::string& codec_string,
const std::string& language,
const uint8* extra_data, const uint8* extra_data,
size_t extra_data_size, size_t extra_data_size,
bool is_encrypted); bool is_encrypted);
@ -32,11 +35,14 @@ class StreamInfo : public base::RefCountedThreadSafe<StreamInfo> {
virtual bool IsValidConfig() const = 0; virtual bool IsValidConfig() const = 0;
// Returns a human-readable string describing |*this|. // Returns a human-readable string describing |*this|.
virtual std::string ToString(); virtual std::string ToString() const;
StreamType stream_type() const { return stream_type_; } StreamType stream_type() const { return stream_type_; }
int track_id() const { return track_id_; } int track_id() const { return track_id_; }
int time_scale() const { return time_scale_; } uint32 time_scale() const { return time_scale_; }
uint64 duration() const { return duration_; }
const std::string& codec_string() const { return codec_string_; }
const std::string& language() const { return language_; }
bool is_encrypted() const { return is_encrypted_; } bool is_encrypted() const { return is_encrypted_; }
@ -47,11 +53,18 @@ class StreamInfo : public base::RefCountedThreadSafe<StreamInfo> {
return extra_data_.size(); return extra_data_.size();
} }
void set_duration(int duration) { duration_ = duration; }
private: private:
// Whether the stream is Audio or Video. // Whether the stream is Audio or Video.
StreamType stream_type_; StreamType stream_type_;
int track_id_; int track_id_;
int time_scale_; // The actual time is calculated as time / time_scale_ in seconds.
uint32 time_scale_;
// Duration base on time_scale.
uint64 duration_;
std::string codec_string_;
std::string language_;
// Whether the stream is potentially encrypted. // Whether the stream is potentially encrypted.
// Note that in a potentially encrypted stream, individual buffers // Note that in a potentially encrypted stream, individual buffers
// can be encrypted or not encrypted. // can be encrypted or not encrypted.

View File

@ -6,21 +6,29 @@
#include <sstream> #include <sstream>
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "media/base/limits.h" #include "media/base/limits.h"
namespace media { namespace media {
VideoStreamInfo::VideoStreamInfo(int track_id, VideoStreamInfo::VideoStreamInfo(int track_id,
int time_scale, uint32 time_scale,
uint64 duration,
VideoCodec codec, VideoCodec codec,
int width, const std::string& codec_string,
int height, const std::string& language,
uint16 width,
uint16 height,
const uint8* extra_data, const uint8* extra_data,
size_t extra_data_size, size_t extra_data_size,
bool is_encrypted) bool is_encrypted)
: StreamInfo(kStreamVideo, : StreamInfo(kStreamVideo,
track_id, track_id,
time_scale, time_scale,
duration,
codec_string,
language,
extra_data, extra_data,
extra_data_size, extra_data_size,
is_encrypted), is_encrypted),
@ -36,7 +44,7 @@ bool VideoStreamInfo::IsValidConfig() const {
height_ > 0 && height_ <= limits::kMaxDimension; height_ > 0 && height_ <= limits::kMaxDimension;
} }
std::string VideoStreamInfo::ToString() { std::string VideoStreamInfo::ToString() const {
std::ostringstream s; std::ostringstream s;
s << "codec: " << codec_ s << "codec: " << codec_
<< " width: " << width_ << " width: " << width_
@ -45,4 +53,24 @@ std::string VideoStreamInfo::ToString() {
return s.str(); return s.str();
} }
std::string VideoStreamInfo::GetCodecString(VideoCodec codec,
uint8 profile,
uint8 compatible_profiles,
uint8 level) {
switch (codec) {
case kCodecVP8:
return "vp8";
case kCodecVP9:
return "vp9";
case kCodecH264: {
const uint8 bytes[] = {profile, compatible_profiles, level};
return "avc1."
+ StringToLowerASCII(base::HexEncode(bytes, arraysize(bytes)));
}
default:
NOTIMPLEMENTED() << "Codec: " << codec;
return "unknown";
}
}
} // namespace media } // namespace media

View File

@ -27,10 +27,13 @@ class VideoStreamInfo : public StreamInfo {
// Constructs an initialized object. It is acceptable to pass in NULL for // Constructs an initialized object. It is acceptable to pass in NULL for
// |extra_data|, otherwise the memory is copied. // |extra_data|, otherwise the memory is copied.
VideoStreamInfo(int track_id, VideoStreamInfo(int track_id,
int time_scale, uint32 time_scale,
uint64 duration,
VideoCodec codec, VideoCodec codec,
int width, const std::string& codec_string,
int height, const std::string& language,
uint16 width,
uint16 height,
const uint8* extra_data, const uint8* extra_data,
size_t extra_data_size, size_t extra_data_size,
bool is_encrypted); bool is_encrypted);
@ -39,19 +42,24 @@ class VideoStreamInfo : public StreamInfo {
// Returns true if this object has appropriate configuration values, false // Returns true if this object has appropriate configuration values, false
// otherwise. // otherwise.
virtual bool IsValidConfig() const; virtual bool IsValidConfig() const OVERRIDE;
// Returns a human-readable string describing |*this|. // Returns a human-readable string describing |*this|.
virtual std::string ToString(); virtual std::string ToString() const OVERRIDE;
VideoCodec codec() const { return codec_; } VideoCodec codec() const { return codec_; }
int width() const { return width_; } uint16 width() const { return width_; }
int height() const { return height_; } uint16 height() const { return height_; }
// Returns the codec string. The parameters beyond codec are only used by
// H.264 codec.
static std::string GetCodecString(VideoCodec codec, uint8 profile,
uint8 compatible_profiles, uint8 level);
private: private:
VideoCodec codec_; VideoCodec codec_;
int width_; uint16 width_;
int height_; uint16 height_;
// Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler
// generated copy constructor and assignment operator. Since the extra data is // generated copy constructor and assignment operator. Since the extra data is

View File

@ -13,13 +13,13 @@
namespace { namespace {
// Sampling Frequency Index table, from ISO 14496-3 Table 1.16 // Sampling Frequency Index table, from ISO 14496-3 Table 1.16
static const int kSampleRates[] = { static const uint32 kSampleRates[] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 96000, 88200, 64000, 48000, 44100, 32000, 24000,
22050, 16000, 12000, 11025, 8000, 7350 22050, 16000, 12000, 11025, 8000, 7350
}; };
// Channel Configuration table, from ISO 14496-3 Table 1.17 // Channel Configuration table, from ISO 14496-3 Table 1.17
const uint32 kChannelConfigs[] = {0, 1, 2, 3, 4, 5, 6, 8}; const uint8 kChannelConfigs[] = {0, 1, 2, 3, 4, 5, 6, 8};
} // namespace } // namespace
@ -28,46 +28,51 @@ namespace media {
namespace mp4 { namespace mp4 {
AAC::AAC() AAC::AAC()
: profile_(0), frequency_index_(0), channel_config_(0), frequency_(0), : audio_object_type_(0), frequency_index_(0), channel_config_(0),
extension_frequency_(0), num_channels_(0) { ps_present_(false), frequency_(0), extension_frequency_(0),
num_channels_(0) {
} }
AAC::~AAC() { AAC::~AAC() {
} }
bool AAC::Parse(const std::vector<uint8>& data) { bool AAC::Parse(const std::vector<uint8>& data) {
#if defined(OS_ANDROID)
codec_specific_data_ = data; codec_specific_data_ = data;
#endif
if (data.empty()) if (data.empty())
return false; return false;
BitReader reader(&data[0], data.size()); BitReader reader(&data[0], data.size());
uint8 extension_type = 0; uint8 extension_type = 0;
bool ps_present = false;
uint8 extension_frequency_index = 0xff; uint8 extension_frequency_index = 0xff;
ps_present_ = false;
frequency_ = 0; frequency_ = 0;
extension_frequency_ = 0; extension_frequency_ = 0;
// The following code is written according to ISO 14496 Part 3 Table 1.13 - // The following code is written according to ISO 14496 Part 3 Table 1.13 -
// Syntax of AudioSpecificConfig. // Syntax of AudioSpecificConfig.
// Read base configuration // Read base configuration.
RCHECK(reader.ReadBits(5, &profile_)); // Audio Object Types specified in ISO 14496-3, Table 1.15.
RCHECK(reader.ReadBits(5, &audio_object_type_));
// Audio objects type >=31 is not supported yet.
RCHECK(audio_object_type_ < 31);
RCHECK(reader.ReadBits(4, &frequency_index_)); RCHECK(reader.ReadBits(4, &frequency_index_));
if (frequency_index_ == 0xf) if (frequency_index_ == 0xf)
RCHECK(reader.ReadBits(24, &frequency_)); RCHECK(reader.ReadBits(24, &frequency_));
RCHECK(reader.ReadBits(4, &channel_config_)); RCHECK(reader.ReadBits(4, &channel_config_));
// Read extension configuration. // Read extension configuration.
if (profile_ == 5 || profile_ == 29) { if (audio_object_type_ == 5 || audio_object_type_ == 29) {
ps_present = (profile_ == 29); ps_present_ = (audio_object_type_ == 29);
extension_type = 5; extension_type = 5;
RCHECK(reader.ReadBits(4, &extension_frequency_index)); RCHECK(reader.ReadBits(4, &extension_frequency_index));
if (extension_frequency_index == 0xf) if (extension_frequency_index == 0xf)
RCHECK(reader.ReadBits(24, &extension_frequency_)); RCHECK(reader.ReadBits(24, &extension_frequency_));
RCHECK(reader.ReadBits(5, &profile_)); RCHECK(reader.ReadBits(5, &audio_object_type_));
// Audio objects type >=31 is not supported yet.
RCHECK(audio_object_type_ < 31);
} }
RCHECK(SkipDecoderGASpecificConfig(&reader)); RCHECK(SkipDecoderGASpecificConfig(&reader));
@ -96,7 +101,7 @@ bool AAC::Parse(const std::vector<uint8>& data) {
RCHECK(reader.ReadBits(11, &sync_extension_type)); RCHECK(reader.ReadBits(11, &sync_extension_type));
if (sync_extension_type == 0x548) { if (sync_extension_type == 0x548) {
RCHECK(reader.ReadBits(1, &ps_present_flag)); RCHECK(reader.ReadBits(1, &ps_present_flag));
ps_present = ps_present_flag != 0; ps_present_ = ps_present_flag != 0;
} }
} }
} }
@ -114,20 +119,15 @@ bool AAC::Parse(const std::vector<uint8>& data) {
extension_frequency_ = kSampleRates[extension_frequency_index]; extension_frequency_ = kSampleRates[extension_frequency_index];
} }
// TODO(kqyang): should we care about whether Parametric Stereo is on?
// When Parametric Stereo is on, mono will be played as stereo.
if (ps_present && channel_config_ == 1)
num_channels_ = 2; // CHANNEL_LAYOUT_STEREO
else {
RCHECK(channel_config_ < arraysize(kChannelConfigs)); RCHECK(channel_config_ < arraysize(kChannelConfigs));
num_channels_ = kChannelConfigs[channel_config_]; num_channels_ = kChannelConfigs[channel_config_];
return frequency_ != 0 && num_channels_ != 0 && audio_object_type_ >= 1 &&
audio_object_type_ <= 4 && frequency_index_ != 0xf &&
channel_config_ <= 7;
} }
return frequency_ != 0 && num_channels_ != 0 && profile_ >= 1 && uint32 AAC::GetOutputSamplesPerSecond(bool sbr_in_mimetype) const {
profile_ <= 4 && frequency_index_ != 0xf && channel_config_ <= 7;
}
int AAC::GetOutputSamplesPerSecond(bool sbr_in_mimetype) const {
if (extension_frequency_ > 0) if (extension_frequency_ > 0)
return extension_frequency_; return extension_frequency_;
@ -139,24 +139,28 @@ int AAC::GetOutputSamplesPerSecond(bool sbr_in_mimetype) const {
// to SBR doubling the AAC sample rate.) // to SBR doubling the AAC sample rate.)
// TODO(acolwell) : Extend sample rate cap to 96kHz for Level 5 content. // TODO(acolwell) : Extend sample rate cap to 96kHz for Level 5 content.
DCHECK_GT(frequency_, 0); DCHECK_GT(frequency_, 0);
return std::min(2 * frequency_, 48000); return std::min(2 * frequency_, 48000u);
} }
int AAC::GetNumChannels(bool sbr_in_mimetype) const { uint8 AAC::GetNumChannels(bool sbr_in_mimetype) const {
// Check for implicit signalling of HE-AAC and indicate stereo output // Check for implicit signalling of HE-AAC and indicate stereo output
// if the mono channel configuration is signalled. // if the mono channel configuration is signalled.
// See ISO-14496-3 Section 1.6.6.1.2 for details about this special casing. // See ISO-14496-3 Section 1.6.6.1.2 for details about this special casing.
if (sbr_in_mimetype && channel_config_ == 1) if (sbr_in_mimetype && channel_config_ == 1)
return 2; // CHANNEL_LAYOUT_STEREO return 2; // CHANNEL_LAYOUT_STEREO
// When Parametric Stereo is on, mono will be played as stereo.
if (ps_present_ && channel_config_ == 1)
return 2; // CHANNEL_LAYOUT_STEREO
return num_channels_; return num_channels_;
} }
bool AAC::ConvertToADTS(std::vector<uint8>* buffer) const { bool AAC::ConvertToADTS(std::vector<uint8>* buffer) const {
size_t size = buffer->size() + kADTSHeaderSize; size_t size = buffer->size() + kADTSHeaderSize;
DCHECK(profile_ >= 1 && profile_ <= 4 && frequency_index_ != 0xf && DCHECK(audio_object_type_ >= 1 && audio_object_type_ <= 4 &&
channel_config_ <= 7); frequency_index_ != 0xf && channel_config_ <= 7);
// ADTS header uses 13 bits for packet size. // ADTS header uses 13 bits for packet size.
if (size >= (1 << 13)) if (size >= (1 << 13))
@ -167,7 +171,7 @@ bool AAC::ConvertToADTS(std::vector<uint8>* buffer) const {
adts.insert(buffer->begin(), kADTSHeaderSize, 0); adts.insert(buffer->begin(), kADTSHeaderSize, 0);
adts[0] = 0xff; adts[0] = 0xff;
adts[1] = 0xf1; adts[1] = 0xf1;
adts[2] = ((profile_ - 1) << 6) + (frequency_index_ << 2) + adts[2] = ((audio_object_type_ - 1) << 6) + (frequency_index_ << 2) +
(channel_config_ >> 2); (channel_config_ >> 2);
adts[3] = ((channel_config_ & 0x3) << 6) + (size >> 11); adts[3] = ((channel_config_ & 0x3) << 6) + (size >> 11);
adts[4] = (size & 0x7ff) >> 3; adts[4] = (size & 0x7ff) >> 3;
@ -180,7 +184,7 @@ bool AAC::ConvertToADTS(std::vector<uint8>* buffer) const {
// Currently this function only support GASpecificConfig defined in // Currently this function only support GASpecificConfig defined in
// ISO 14496 Part 3 Table 4.1 - Syntax of GASpecificConfig() // ISO 14496 Part 3 Table 4.1 - Syntax of GASpecificConfig()
bool AAC::SkipDecoderGASpecificConfig(BitReader* bit_reader) const { bool AAC::SkipDecoderGASpecificConfig(BitReader* bit_reader) const {
switch (profile_) { switch (audio_object_type_) {
case 1: case 1:
case 2: case 2:
case 3: case 3:
@ -202,7 +206,7 @@ bool AAC::SkipDecoderGASpecificConfig(BitReader* bit_reader) const {
} }
bool AAC::SkipErrorSpecificConfig() const { bool AAC::SkipErrorSpecificConfig() const {
switch (profile_) { switch (audio_object_type_) {
case 17: case 17:
case 19: case 19:
case 20: case 20:
@ -236,16 +240,17 @@ bool AAC::SkipGASpecificConfig(BitReader* bit_reader) const {
RCHECK(bit_reader->ReadBits(1, &extension_flag)); RCHECK(bit_reader->ReadBits(1, &extension_flag));
RCHECK(channel_config_ != 0); RCHECK(channel_config_ != 0);
if (profile_ == 6 || profile_ == 20) if (audio_object_type_ == 6 || audio_object_type_ == 20)
RCHECK(bit_reader->ReadBits(3, &dummy)); // layerNr RCHECK(bit_reader->ReadBits(3, &dummy)); // layerNr
if (extension_flag) { if (extension_flag) {
if (profile_ == 22) { if (audio_object_type_ == 22) {
RCHECK(bit_reader->ReadBits(5, &dummy)); // numOfSubFrame RCHECK(bit_reader->ReadBits(5, &dummy)); // numOfSubFrame
RCHECK(bit_reader->ReadBits(11, &dummy)); // layer_length RCHECK(bit_reader->ReadBits(11, &dummy)); // layer_length
} }
if (profile_ == 17 || profile_ == 19 || profile_ == 20 || profile_ == 23) { if (audio_object_type_ == 17 || audio_object_type_ == 19 ||
audio_object_type_ == 20 || audio_object_type_ == 23) {
RCHECK(bit_reader->ReadBits(3, &dummy)); // resilience flags RCHECK(bit_reader->ReadBits(3, &dummy)); // resilience flags
} }

View File

@ -30,17 +30,18 @@ class AAC {
// The function will parse the data and get the ElementaryStreamDescriptor, // The function will parse the data and get the ElementaryStreamDescriptor,
// then it will parse the ElementaryStreamDescriptor to get audio stream // then it will parse the ElementaryStreamDescriptor to get audio stream
// configurations. // configurations.
// |data| is always copied to |codec_specific_data_|.
bool Parse(const std::vector<uint8>& data); bool Parse(const std::vector<uint8>& data);
// Gets the output sample rate for the AAC stream. // Gets the output sample rate for the AAC stream.
// |sbr_in_mimetype| should be set to true if the SBR mode is // |sbr_in_mimetype| should be set to true if the SBR mode is
// signalled in the mimetype. (ie mp4a.40.5 in the codecs parameter). // signalled in the mimetype. (ie mp4a.40.5 in the codecs parameter).
int GetOutputSamplesPerSecond(bool sbr_in_mimetype) const; uint32 GetOutputSamplesPerSecond(bool sbr_in_mimetype) const;
// Gets number of channels for the AAC stream. // Gets number of channels for the AAC stream.
// |sbr_in_mimetype| should be set to true if the SBR mode is // |sbr_in_mimetype| should be set to true if the SBR mode is
// signalled in the mimetype. (ie mp4a.40.5 in the codecs parameter). // signalled in the mimetype. (ie mp4a.40.5 in the codecs parameter).
int GetNumChannels(bool sbr_in_mimetype) const; uint8 GetNumChannels(bool sbr_in_mimetype) const;
// This function converts a raw AAC frame into an AAC frame with an ADTS // This function converts a raw AAC frame into an AAC frame with an ADTS
// header. On success, the function returns true and stores the converted data // header. On success, the function returns true and stores the converted data
@ -48,12 +49,22 @@ class AAC {
// unchanged. // unchanged.
bool ConvertToADTS(std::vector<uint8>* buffer) const; bool ConvertToADTS(std::vector<uint8>* buffer) const;
#if defined(OS_ANDROID) uint8 audio_object_type() const {
// Returns the codec specific data needed by android MediaCodec. return audio_object_type_;
}
uint32 frequency() const {
return frequency_;
}
uint8 num_channels() const {
return num_channels_;
}
// Returns the codec specific data.
std::vector<uint8> codec_specific_data() const { std::vector<uint8> codec_specific_data() const {
return codec_specific_data_; return codec_specific_data_;
} }
#endif
// Size in bytes of the ADTS header added by ConvertEsdsToADTS(). // Size in bytes of the ADTS header added by ConvertEsdsToADTS().
static const size_t kADTSHeaderSize = 7; static const size_t kADTSHeaderSize = 7;
@ -65,21 +76,20 @@ class AAC {
// The following variables store the AAC specific configuration information // The following variables store the AAC specific configuration information
// that are used to generate the ADTS header. // that are used to generate the ADTS header.
uint8 profile_; uint8 audio_object_type_;
uint8 frequency_index_; uint8 frequency_index_;
uint8 channel_config_; uint8 channel_config_;
// Is Parametric Stereo on?
bool ps_present_;
#if defined(OS_ANDROID)
// The codec specific data needed by the android MediaCodec.
std::vector<uint8> codec_specific_data_; std::vector<uint8> codec_specific_data_;
#endif
// The following variables store audio configuration information. // The following variables store audio configuration information.
// They are based on the AAC specific configuration but can be overridden // They are based on the AAC specific configuration but can be overridden
// by extensions in elementary stream descriptor. // by extensions in elementary stream descriptor.
int frequency_; uint32 frequency_;
int extension_frequency_; uint32 extension_frequency_;
int num_channels_; uint8 num_channels_;
}; };
} // namespace mp4 } // namespace mp4

View File

@ -5,6 +5,7 @@
#include "media/mp4/box_definitions.h" #include "media/mp4/box_definitions.h"
#include "base/logging.h" #include "base/logging.h"
#include "media/base/bit_reader.h"
#include "media/mp4/es_descriptor.h" #include "media/mp4/es_descriptor.h"
#include "media/mp4/rcheck.h" #include "media/mp4/rcheck.h"
@ -506,6 +507,13 @@ AVCDecoderConfigurationRecord::~AVCDecoderConfigurationRecord() {}
FourCC AVCDecoderConfigurationRecord::BoxType() const { return FOURCC_AVCC; } FourCC AVCDecoderConfigurationRecord::BoxType() const { return FOURCC_AVCC; }
bool AVCDecoderConfigurationRecord::Parse(BoxReader* reader) { bool AVCDecoderConfigurationRecord::Parse(BoxReader* reader) {
RCHECK(reader->ReadVec(&data, reader->size() - 8));
BufferReader buffer_reader(&data[0], data.size());
return ParseData(&buffer_reader);
}
bool AVCDecoderConfigurationRecord::ParseData(BufferReader* reader) {
RCHECK(reader->Read1(&version) && version == 1 && RCHECK(reader->Read1(&version) && version == 1 &&
reader->Read1(&profile_indication) && reader->Read1(&profile_indication) &&
reader->Read1(&profile_compatibility) && reader->Read1(&profile_compatibility) &&
@ -679,8 +687,21 @@ bool MediaHeader::Parse(BoxReader* reader) {
reader->Read4(&timescale) && reader->Read4(&timescale) &&
reader->Read4Into8(&duration)); reader->Read4Into8(&duration));
} }
// Skip language information
return reader->SkipBytes(4); // Read language codes into temp first then use BitReader to read the values.
// ISO-639-2/T language code: unsigned int(5)[3] language (2 bytes).
std::vector<uint8> temp;
RCHECK(reader->ReadVec(&temp, 2));
BitReader bit_reader(&temp[0], 2);
bit_reader.SkipBits(1);
for (int i = 0; i < 3; ++i) {
CHECK(bit_reader.ReadBits(5, &language[i]));
language[i] += 0x60;
}
language[3] = '\0';
return reader->SkipBytes(2);
} }
MediaInformation::MediaInformation() {} MediaInformation::MediaInformation() {}

View File

@ -145,6 +145,13 @@ struct HandlerReference : Box {
struct AVCDecoderConfigurationRecord : Box { struct AVCDecoderConfigurationRecord : Box {
DECLARE_BOX_METHODS(AVCDecoderConfigurationRecord); DECLARE_BOX_METHODS(AVCDecoderConfigurationRecord);
bool ParseData(BufferReader* reader);
// Contains full avc decoder configuration record as defined in iso14496-15
// 5.2.4.1, including possible extension bytes described in paragraph 3.
// Known fields defined in the spec are also parsed and included in this
// structure.
std::vector<uint8> data;
uint8 version; uint8 version;
uint8 profile_indication; uint8 profile_indication;
@ -307,6 +314,8 @@ struct MediaHeader : Box {
uint64 modification_time; uint64 modification_time;
uint32 timescale; uint32 timescale;
uint64 duration; uint64 duration;
// 3-char language code + 1 null terminating char.
char language[4];
}; };
struct MediaInformation : Box { struct MediaInformation : Box {

View File

@ -8,9 +8,7 @@
#include "base/callback_helpers.h" #include "base/callback_helpers.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "media/base/audio_stream_info.h" #include "media/base/audio_stream_info.h"
#include "media/base/buffers.h"
#include "media/base/media_sample.h" #include "media/base/media_sample.h"
#include "media/base/video_stream_info.h" #include "media/base/video_stream_info.h"
#include "media/mp4/box_definitions.h" #include "media/mp4/box_definitions.h"
@ -21,11 +19,8 @@
namespace { namespace {
base::TimeDelta TimeDeltaFromRational(int64 numer, int64 denom) { uint64 Rescale(uint64 time_in_old_scale, uint32 old_scale, uint32 new_scale) {
DCHECK_LT((numer > 0 ? numer : -numer), return (static_cast<double>(time_in_old_scale) / old_scale) * new_scale;
kint64max / base::Time::kMicrosecondsPerSecond);
return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond *
numer / denom);
} }
} // namespace } // namespace
@ -41,8 +36,6 @@ MP4MediaParser::MP4MediaParser()
has_video_(false), has_video_(false),
audio_track_id_(0), audio_track_id_(0),
video_track_id_(0), video_track_id_(0),
// TODO(kqyang): do we need to care about it??
has_sbr_(false),
is_audio_track_encrypted_(false), is_audio_track_encrypted_(false),
is_video_track_encrypted_(false) { is_video_track_encrypted_(false) {
} }
@ -150,6 +143,23 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
for (std::vector<Track>::const_iterator track = moov_->tracks.begin(); for (std::vector<Track>::const_iterator track = moov_->tracks.begin();
track != moov_->tracks.end(); ++track) { track != moov_->tracks.end(); ++track) {
const uint32 timescale = track->media.header.timescale;
// Calculate duration (based on timescale).
uint64 duration = 0;
if (track->media.header.duration > 0) {
duration = track->media.header.duration;
} else if (moov_->extends.header.fragment_duration > 0) {
DCHECK(moov_->header.timescale != 0);
duration = Rescale(moov_->extends.header.fragment_duration,
moov_->header.timescale, timescale);
} else if (moov_->header.duration > 0 &&
moov_->header.duration != kuint64max) {
DCHECK(moov_->header.timescale != 0);
duration = Rescale(moov_->header.duration, moov_->header.timescale,
timescale);
}
// TODO(strobe): Only the first audio and video track present in a file are // TODO(strobe): Only the first audio and video track present in a file are
// used. (Track selection is better accomplished via Source IDs, though, so // used. (Track selection is better accomplished via Source IDs, though, so
// adding support for track selection within a stream is low-priority.) // adding support for track selection within a stream is low-priority.)
@ -209,22 +219,22 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
} }
AudioCodec codec = kUnknownAudioCodec; AudioCodec codec = kUnknownAudioCodec;
int num_channels = 0; uint8 num_channels = 0;
int sample_per_second = 0; uint32 sampling_frequency = 0;
uint8 audio_object_type = 0;
std::vector<uint8> extra_data; std::vector<uint8> extra_data;
// Check if it is MPEG4 AAC defined in ISO 14496 Part 3 or // Check if it is MPEG4 AAC defined in ISO 14496 Part 3 or
// supported MPEG2 AAC varients. // supported MPEG2 AAC variants.
if (ESDescriptor::IsAAC(audio_type)) { if (ESDescriptor::IsAAC(audio_type)) {
codec = kCodecAAC; codec = kCodecAAC;
num_channels = aac.GetNumChannels(has_sbr_); num_channels = aac.num_channels();
sample_per_second = aac.GetOutputSamplesPerSecond(has_sbr_); sampling_frequency = aac.frequency();
#if defined(OS_ANDROID) audio_object_type = aac.audio_object_type();
extra_data = aac.codec_specific_data(); extra_data = aac.codec_specific_data();
#endif
} else if (audio_type == kEAC3) { } else if (audio_type == kEAC3) {
codec = kCodecEAC3; codec = kCodecEAC3;
num_channels = entry.channelcount; num_channels = entry.channelcount;
sample_per_second = entry.samplerate; sampling_frequency = entry.samplerate;
} else { } else {
LOG(ERROR) << "Unsupported audio object type 0x" LOG(ERROR) << "Unsupported audio object type 0x"
<< std::hex << audio_type << " in esds."; << std::hex << audio_type << " in esds.";
@ -234,12 +244,16 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
is_audio_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted; is_audio_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted;
DVLOG(1) << "is_audio_track_encrypted_: " << is_audio_track_encrypted_; DVLOG(1) << "is_audio_track_encrypted_: " << is_audio_track_encrypted_;
streams.push_back( streams.push_back(
new AudioStreamInfo(track->header.track_id, new AudioStreamInfo(
track->media.header.timescale, track->header.track_id,
timescale,
duration,
codec, codec,
entry.samplesize / 8, AudioStreamInfo::GetCodecString(codec, audio_object_type),
track->media.header.language,
entry.samplesize,
num_channels, num_channels,
sample_per_second, sampling_frequency,
extra_data.size() ? &extra_data[0] : NULL, extra_data.size() ? &extra_data[0] : NULL,
extra_data.size(), extra_data.size(),
is_audio_track_encrypted_)); is_audio_track_encrypted_));
@ -265,35 +279,31 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
return false; return false;
} }
const std::string codec_string =
VideoStreamInfo::GetCodecString(
kCodecH264, entry.avcc.profile_indication,
entry.avcc.profile_compatibility, entry.avcc.avc_level);
is_video_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted; is_video_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted;
DVLOG(1) << "is_video_track_encrypted_: " << is_video_track_encrypted_; DVLOG(1) << "is_video_track_encrypted_: " << is_video_track_encrypted_;
streams.push_back( streams.push_back(
new VideoStreamInfo(track->header.track_id, new VideoStreamInfo(
track->media.header.timescale, track->header.track_id,
timescale,
duration,
kCodecH264, kCodecH264,
codec_string,
track->media.header.language,
entry.width, entry.width,
entry.height, entry.height,
// No decoder-specific buffer needed for AVC. &entry.avcc.data[0],
NULL, 0, entry.avcc.data.size(),
is_video_track_encrypted_)); is_video_track_encrypted_));
has_video_ = true; has_video_ = true;
video_track_id_ = track->header.track_id; video_track_id_ = track->header.track_id;
} }
} }
// TODO(kqyang): figure out how to get duration for every tracks/streams.
base::TimeDelta duration;
if (moov_->extends.header.fragment_duration > 0) {
duration = TimeDeltaFromRational(moov_->extends.header.fragment_duration,
moov_->header.timescale);
} else if (moov_->header.duration > 0 &&
moov_->header.duration != kuint64max) {
duration = TimeDeltaFromRational(moov_->header.duration,
moov_->header.timescale);
} else {
duration = kInfiniteDuration();
}
init_cb_.Run(true, streams); init_cb_.Run(true, streams);
EmitNeedKeyIfNecessary(moov_->pssh); EmitNeedKeyIfNecessary(moov_->pssh);

View File

@ -16,13 +16,9 @@
namespace media { namespace media {
class SubsampleEntry;
namespace mp4 { namespace mp4 {
struct Movie; struct Movie;
class AAC;
class AVCDecoderConfigurationRecord;
class BoxReader; class BoxReader;
class ProtectionSystemSpecificHeader; class ProtectionSystemSpecificHeader;
class TrackRunIterator; class TrackRunIterator;
@ -92,7 +88,6 @@ class MP4MediaParser : public MediaParser {
bool has_video_; bool has_video_;
uint32 audio_track_id_; uint32 audio_track_id_;
uint32 video_track_id_; uint32 video_track_id_;
bool has_sbr_;
bool is_audio_track_encrypted_; bool is_audio_track_encrypted_;
bool is_video_track_encrypted_; bool is_video_track_encrypted_;