Index: media/formats/mpeg/mpeg1_audio_stream_parser.cc |
diff --git a/media/formats/mpeg/mp3_stream_parser.cc b/media/formats/mpeg/mpeg1_audio_stream_parser.cc |
similarity index 66% |
rename from media/formats/mpeg/mp3_stream_parser.cc |
rename to media/formats/mpeg/mpeg1_audio_stream_parser.cc |
index f5b743824233afc8dc080209cb90c290075ae114..92bd4ce104e0afcd057b2b34bb7583db47c22ff7 100644 |
--- a/media/formats/mpeg/mp3_stream_parser.cc |
+++ b/media/formats/mpeg/mpeg1_audio_stream_parser.cc |
@@ -2,11 +2,11 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "media/formats/mpeg/mp3_stream_parser.h" |
+#include "media/formats/mpeg/mpeg1_audio_stream_parser.h" |
namespace media { |
-static const uint32 kMP3StartCodeMask = 0xffe00000; |
+static const uint32 kMPEG1StartCodeMask = 0xffe00000; |
// Map that determines which bitrate_index & channel_mode combinations |
// are allowed. |
@@ -80,38 +80,17 @@ static const int kSampleRateMap[4][4] = { |
static const int kXingHeaderMap[2][2] = {{32, 17}, {17, 9}}; |
// Frame header field constants. |
-static const int kVersion2 = 2; |
-static const int kVersionReserved = 1; |
-static const int kVersion2_5 = 0; |
-static const int kLayerReserved = 0; |
-static const int kLayer1 = 3; |
-static const int kLayer2 = 2; |
-static const int kLayer3 = 1; |
static const int kBitrateFree = 0; |
static const int kBitrateBad = 0xf; |
static const int kSampleRateReserved = 3; |
static const int kCodecDelay = 529; |
-MP3StreamParser::MP3StreamParser() |
- : MPEGAudioStreamParserBase(kMP3StartCodeMask, kCodecMP3, kCodecDelay) {} |
- |
-MP3StreamParser::~MP3StreamParser() {} |
- |
-int MP3StreamParser::ParseFrameHeader(const uint8* data, |
- int size, |
- int* frame_size, |
- int* sample_rate, |
- ChannelLayout* channel_layout, |
- int* sample_count, |
- bool* metadata_frame) const { |
- DCHECK(data); |
- DCHECK_GE(size, 0); |
- DCHECK(frame_size); |
- |
- if (size < 4) |
- return 0; |
- |
- BitReader reader(data, size); |
+// static |
+bool MPEG1AudioStreamParser::ParseHeader( |
+ const LogCB& log_cb, |
+ const uint8* data, |
+ Header* header) { |
+ BitReader reader(data, kHeaderSize); |
int sync; |
int version; |
int layer; |
@@ -133,7 +112,7 @@ int MP3StreamParser::ParseFrameHeader(const uint8* data, |
!reader.ReadBits(1, &is_private) || |
!reader.ReadBits(2, &channel_mode) || |
!reader.ReadBits(6, &other_flags)) { |
- return -1; |
+ return false; |
} |
DVLOG(2) << "Header data :" << std::hex |
@@ -149,46 +128,44 @@ int MP3StreamParser::ParseFrameHeader(const uint8* data, |
layer == kLayerReserved || |
bitrate_index == kBitrateFree || bitrate_index == kBitrateBad || |
sample_rate_index == kSampleRateReserved) { |
- MEDIA_LOG(log_cb()) << "Invalid header data :" << std::hex |
- << " sync 0x" << sync |
- << " version 0x" << version |
- << " layer 0x" << layer |
- << " bitrate_index 0x" << bitrate_index |
- << " sample_rate_index 0x" << sample_rate_index |
- << " channel_mode 0x" << channel_mode; |
- return -1; |
+ MEDIA_LOG(log_cb) << "Invalid header data :" << std::hex |
+ << " sync 0x" << sync |
+ << " version 0x" << version |
+ << " layer 0x" << layer |
+ << " bitrate_index 0x" << bitrate_index |
+ << " sample_rate_index 0x" << sample_rate_index |
+ << " channel_mode 0x" << channel_mode; |
+ return false; |
} |
if (layer == kLayer2 && kIsAllowed[bitrate_index][channel_mode]) { |
- MEDIA_LOG(log_cb()) << "Invalid (bitrate_index, channel_mode) combination :" |
- << std::hex |
- << " bitrate_index " << bitrate_index |
- << " channel_mode " << channel_mode; |
- return -1; |
+ MEDIA_LOG(log_cb) << "Invalid (bitrate_index, channel_mode) combination :" |
+ << std::hex |
+ << " bitrate_index " << bitrate_index |
+ << " channel_mode " << channel_mode; |
+ return false; |
} |
int bitrate = kBitrateMap[bitrate_index][kVersionLayerMap[version][layer]]; |
if (bitrate == 0) { |
- MEDIA_LOG(log_cb()) << "Invalid bitrate :" << std::hex |
- << " version " << version |
- << " layer " << layer |
- << " bitrate_index " << bitrate_index; |
- return -1; |
+ MEDIA_LOG(log_cb) << "Invalid bitrate :" << std::hex |
+ << " version " << version |
+ << " layer " << layer |
+ << " bitrate_index " << bitrate_index; |
+ return false; |
} |
DVLOG(2) << " bitrate " << bitrate; |
int frame_sample_rate = kSampleRateMap[sample_rate_index][version]; |
if (frame_sample_rate == 0) { |
- MEDIA_LOG(log_cb()) << "Invalid sample rate :" << std::hex |
- << " version " << version |
- << " sample_rate_index " << sample_rate_index; |
- return -1; |
+ MEDIA_LOG(log_cb) << "Invalid sample rate :" << std::hex |
+ << " version " << version |
+ << " sample_rate_index " << sample_rate_index; |
+ return false; |
} |
- |
- if (sample_rate) |
- *sample_rate = frame_sample_rate; |
+ header->sample_rate = frame_sample_rate; |
// http://teslabs.com/openplayer/docs/docs/specs/mp3_structure2.pdf |
// Table 2.1.5 |
@@ -210,11 +187,9 @@ int MP3StreamParser::ParseFrameHeader(const uint8* data, |
break; |
default: |
- return -1; |
+ return false; |
} |
- |
- if (sample_count) |
- *sample_count = samples_per_frame; |
+ header->sample_count = samples_per_frame; |
// http://teslabs.com/openplayer/docs/docs/specs/mp3_structure2.pdf |
// Text just below Table 2.1.5. |
@@ -223,33 +198,68 @@ int MP3StreamParser::ParseFrameHeader(const uint8* data, |
// but has slightly different truncation characteristics to deal |
// with the fact that Layer 1 has 4 byte "slots" instead of single |
// byte ones. |
- *frame_size = 4 * (12 * bitrate * 1000 / frame_sample_rate); |
+ header->frame_size = 4 * (12 * bitrate * 1000 / frame_sample_rate); |
} else { |
- *frame_size = |
+ header->frame_size = |
((samples_per_frame / 8) * bitrate * 1000) / frame_sample_rate; |
} |
if (has_padding) |
- *frame_size += (layer == kLayer1) ? 4 : 1; |
+ header->frame_size += (layer == kLayer1) ? 4 : 1; |
- if (channel_layout) { |
- // Map Stereo(0), Joint Stereo(1), and Dual Channel (2) to |
- // CHANNEL_LAYOUT_STEREO and Single Channel (3) to CHANNEL_LAYOUT_MONO. |
- *channel_layout = |
- (channel_mode == 3) ? CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO; |
- } |
+ // Map Stereo(0), Joint Stereo(1), and Dual Channel (2) to |
+ // CHANNEL_LAYOUT_STEREO and Single Channel (3) to CHANNEL_LAYOUT_MONO. |
+ header->channel_layout = |
+ (channel_mode == 3) ? CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO; |
+ |
+ header->version = static_cast<Version>(version); |
+ header->layer = static_cast<Layer>(layer); |
+ header->channel_mode = channel_mode; |
+ return true; |
+} |
+ |
+ |
+MPEG1AudioStreamParser::MPEG1AudioStreamParser() |
+ : MPEGAudioStreamParserBase(kMPEG1StartCodeMask, kCodecMP3, kCodecDelay) {} |
+ |
+MPEG1AudioStreamParser::~MPEG1AudioStreamParser() {} |
+ |
+int MPEG1AudioStreamParser::ParseFrameHeader(const uint8* data, |
+ int size, |
+ int* frame_size, |
+ int* sample_rate, |
+ ChannelLayout* channel_layout, |
+ int* sample_count, |
+ bool* metadata_frame) const { |
+ DCHECK(data); |
+ DCHECK_GE(size, 0); |
+ DCHECK(frame_size); |
+ |
+ if (size < kHeaderSize) |
+ return 0; |
+ Header header; |
+ if (!ParseHeader(log_cb(), data, &header)) |
+ return -1; |
+ |
+ *frame_size = header.frame_size; |
+ if (sample_rate) |
+ *sample_rate = header.sample_rate; |
+ if (sample_count) |
+ *sample_count = header.sample_count; |
+ if (channel_layout) |
+ *channel_layout = header.channel_layout; |
if (metadata_frame) |
*metadata_frame = false; |
- const int header_bytes_read = reader.bits_read() / 8; |
- if (layer != kLayer3) |
+ const int header_bytes_read = kHeaderSize; |
+ if (header.layer != kLayer3) |
return header_bytes_read; |
// Check if this is a XING frame and tell the base parser to skip it if so. |
const int xing_header_index = |
- kXingHeaderMap[version == kVersion2 || |
- version == kVersion2_5][channel_mode == 3]; |
+ kXingHeaderMap[header.version == kVersion2 || |
+ header.version == kVersion2_5][header.channel_mode == 3]; |
uint32_t tag = 0; |
// It's not a XING frame if the frame isn't big enough to be one. |
@@ -260,6 +270,7 @@ int MP3StreamParser::ParseFrameHeader(const uint8* data, |
// If we don't have enough data available to check, return 0 so frame parsing |
// will be retried once more data is available. |
+ BitReader reader(data + header_bytes_read, size - header_bytes_read); |
if (!reader.SkipBits(xing_header_index * 8) || |
!reader.ReadBits(sizeof(tag) * 8, &tag)) { |
return 0; |
@@ -270,7 +281,7 @@ int MP3StreamParser::ParseFrameHeader(const uint8* data, |
MEDIA_LOG(log_cb()) << "Skipping XING header."; |
if (metadata_frame) |
*metadata_frame = true; |
- return reader.bits_read() / 8; |
+ return header_bytes_read + reader.bits_read() / 8; |
} |
// If it wasn't a XING frame, just return the number consumed bytes. |