Chromium Code Reviews| Index: media/formats/mpeg/mp3_stream_parser.cc |
| diff --git a/media/formats/mpeg/mp3_stream_parser.cc b/media/formats/mpeg/mp3_stream_parser.cc |
| index f5b743824233afc8dc080209cb90c290075ae114..3ad081bf25e1ebd8640b2c84f51644ea0aca549a 100644 |
| --- a/media/formats/mpeg/mp3_stream_parser.cc |
| +++ b/media/formats/mpeg/mp3_stream_parser.cc |
| @@ -6,6 +6,9 @@ |
| namespace media { |
| +// static |
| +const int MP3StreamParser::kMpeg1AudioHeaderSize = 4u; |
|
damienv1
2014/09/03 17:43:43
Should be 4 (not 4u)
|
| + |
| static const uint32 kMP3StartCodeMask = 0xffe00000; |
| // Map that determines which bitrate_index & channel_mode combinations |
| @@ -92,26 +95,12 @@ 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 MP3StreamParser::ParserMpeg1AudioFrameHeader( |
| + const LogCB& log_cb, |
| + const uint8* data, |
| + Mpeg1AudioHeader* header) { |
| + BitReader reader(data, kMpeg1AudioHeaderSize); |
| int sync; |
| int version; |
| int layer; |
| @@ -133,7 +122,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 +138,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 +197,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 +208,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 = version; |
| + header->layer = layer; |
| + header->channel_mode = channel_mode; |
| + return true; |
| +} |
| + |
| + |
| +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 < static_cast<int>(kMpeg1AudioHeaderSize)) |
| + return 0; |
| + |
| + Mpeg1AudioHeader header; |
| + if (!ParserMpeg1AudioFrameHeader(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 = kMpeg1AudioHeaderSize; |
| + 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 +280,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 +291,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. |