summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstevet@chromium.org <stevet@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-12 17:26:56 +0000
committerstevet@chromium.org <stevet@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-12 17:26:56 +0000
commitb859d81f7e6fdd179fc20f1afc6e0a477fda7b31 (patch)
tree2f9dec6df896983e1d0ea1a5ca49da9c64931e53
parent128daf6bc3b24d366cf8f252ebe20f70818ea1b7 (diff)
downloadchromium_src-b859d81f7e6fdd179fc20f1afc6e0a477fda7b31.zip
chromium_src-b859d81f7e6fdd179fc20f1afc6e0a477fda7b31.tar.gz
chromium_src-b859d81f7e6fdd179fc20f1afc6e0a477fda7b31.tar.bz2
Revert 250730 "Introduce ADTSStreamParser. Factorize MP3StreamPa..."
Causing compile failure on mac: http://build.chromium.org/p/chromium.chrome/builders/Google%20Chrome%20Mac/builds/16420/steps/compile/logs/stdio > Introduce ADTSStreamParser. Factorize MP3StreamParser and tests. > > Factorizes MP3StreamParser into MPEGAudioStreamParserBase for reuse > with a new ADTSStreamParser. In the process, also factorizes the > MP3StreamParserTest into a new test helper StreamParserTest for > reuse with the ADTSStreamParserTest. > > Introduces an adts_constants.{cc,h} to remove duplicate constants > across the AAC and ES ADTS parsers. Fixes a channel layout bug in > the AAC parser. > > sfx.adts test file will be landed manually in a separate change. > > BUG=341648,340426 > TEST=new unittests pass! > > Review URL: https://codereview.chromium.org/120503006 TBR=dalecurtis@chromium.org Review URL: https://codereview.chromium.org/160593002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@250736 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc1
-rw-r--r--media/base/media_switches.cc3
-rw-r--r--media/base/media_switches.h1
-rw-r--r--media/filters/stream_parser_factory.cc24
-rw-r--r--media/formats/common/stream_parser_test_base.cc121
-rw-r--r--media/formats/common/stream_parser_test_base.h66
-rw-r--r--media/formats/mp2t/es_parser_adts.cc68
-rw-r--r--media/formats/mp3/mp3_stream_parser.cc (renamed from media/formats/mpeg/mpeg_audio_stream_parser_base.cc)325
-rw-r--r--media/formats/mp3/mp3_stream_parser.h (renamed from media/formats/mpeg/mpeg_audio_stream_parser_base.h)105
-rw-r--r--media/formats/mp3/mp3_stream_parser_unittest.cc170
-rw-r--r--media/formats/mp4/aac.cc57
-rw-r--r--media/formats/mp4/aac.h3
-rw-r--r--media/formats/mp4/aac_unittest.cc2
-rw-r--r--media/formats/mp4/mp4_stream_parser.cc7
-rw-r--r--media/formats/mpeg/adts_constants.cc27
-rw-r--r--media/formats/mpeg/adts_constants.h28
-rw-r--r--media/formats/mpeg/adts_stream_parser.cc95
-rw-r--r--media/formats/mpeg/adts_stream_parser.h33
-rw-r--r--media/formats/mpeg/adts_stream_parser_unittest.cc59
-rw-r--r--media/formats/mpeg/mp3_stream_parser.cc239
-rw-r--r--media/formats/mpeg/mp3_stream_parser.h33
-rw-r--r--media/formats/mpeg/mp3_stream_parser_unittest.cc61
-rw-r--r--media/media.gyp15
23 files changed, 592 insertions, 951 deletions
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 104dda2..f6b4832 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1014,7 +1014,6 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableAcceleratedOverflowScroll,
switches::kEnableAcceleratedScrollableFrames,
switches::kEnableAccessibilityLogging,
- switches::kEnableADTSStreamParser,
switches::kEnableBeginFrameScheduling,
switches::kEnableBrowserPluginForAllViewTypes,
switches::kEnableCompositedScrollingForFrames,
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 7377fb9..9ea08a1 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -18,9 +18,6 @@ const char kDisableVp8AlphaPlayback[] = "disable-vp8-alpha-playback";
// Set number of threads to use for video decoding.
const char kVideoThreads[] = "video-threads";
-// Enables ADTS stream parser for Media Source Extensions.
-const char kEnableADTSStreamParser[] = "enable-adts-stream-parser";
-
// Enables MP3 stream parser for Media Source Extensions.
const char kEnableMP3StreamParser[] = "enable-mp3-stream-parser";
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index c1f5588..56db618 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -20,7 +20,6 @@ MEDIA_EXPORT extern const char kDisableVp8AlphaPlayback[];
MEDIA_EXPORT extern const char kVideoThreads[];
-MEDIA_EXPORT extern const char kEnableADTSStreamParser[];
MEDIA_EXPORT extern const char kEnableMP3StreamParser[];
#if defined(OS_ANDROID)
diff --git a/media/filters/stream_parser_factory.cc b/media/filters/stream_parser_factory.cc
index 4b7ee5a..6b22f4d 100644
--- a/media/filters/stream_parser_factory.cc
+++ b/media/filters/stream_parser_factory.cc
@@ -10,8 +10,7 @@
#include "base/strings/string_util.h"
#include "media/base/media_log.h"
#include "media/base/media_switches.h"
-#include "media/formats/mpeg/adts_stream_parser.h"
-#include "media/formats/mpeg/mp3_stream_parser.h"
+#include "media/formats/mp3/mp3_stream_parser.h"
#include "media/formats/webm/webm_stream_parser.h"
#if defined(OS_ANDROID)
@@ -194,18 +193,6 @@ static StreamParser* BuildMP3Parser(
return new MP3StreamParser();
}
-static const CodecInfo kADTSCodecInfo = { NULL, CodecInfo::AUDIO, NULL,
- CodecInfo::HISTOGRAM_MPEG4AAC };
-static const CodecInfo* kAudioADTSCodecs[] = {
- &kADTSCodecInfo,
- NULL
-};
-
-static StreamParser* BuildADTSParser(
- const std::vector<std::string>& codecs, const LogCB& log_cb) {
- return new ADTSStreamParser();
-}
-
#if defined(ENABLE_MPEG2TS_STREAM_PARSER)
static const CodecInfo* kVideoMP2TCodecs[] = {
&kH264AVC1CodecInfo,
@@ -236,7 +223,6 @@ static const SupportedTypeInfo kSupportedTypeInfo[] = {
{ "video/webm", &BuildWebMParser, kVideoWebMCodecs },
{ "audio/webm", &BuildWebMParser, kAudioWebMCodecs },
#if defined(USE_PROPRIETARY_CODECS)
- { "audio/aac", &BuildADTSParser, kAudioADTSCodecs },
{ "audio/mpeg", &BuildMP3Parser, kAudioMP3Codecs },
{ "video/mp4", &BuildMP4Parser, kVideoMP4Codecs },
{ "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs },
@@ -322,6 +308,7 @@ static bool CheckTypeAndCodecs(
const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
if (type == type_info.type) {
if (codecs.empty()) {
+
#if defined(USE_PROPRIETARY_CODECS)
if (type_info.codecs == kAudioMP3Codecs &&
!CommandLine::ForCurrentProcess()->HasSwitch(
@@ -329,13 +316,6 @@ static bool CheckTypeAndCodecs(
DVLOG(1) << "MP3StreamParser is not enabled.";
return false;
}
-
- if (type_info.codecs == kAudioADTSCodecs &&
- !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableADTSStreamParser)) {
- DVLOG(1) << "ADTSStreamParser is not enabled.";
- return false;
- }
#endif
const CodecInfo* codec_info = type_info.codecs[0];
diff --git a/media/formats/common/stream_parser_test_base.cc b/media/formats/common/stream_parser_test_base.cc
deleted file mode 100644
index 40d39d6..0000000
--- a/media/formats/common/stream_parser_test_base.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/formats/common/stream_parser_test_base.h"
-
-#include "base/bind.h"
-#include "media/base/test_data_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace media {
-
-static std::string BufferQueueToString(
- const StreamParser::BufferQueue& buffers) {
- std::stringstream ss;
-
- ss << "{";
- for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
- itr != buffers.end();
- ++itr) {
- ss << " " << (*itr)->timestamp().InMilliseconds();
- if ((*itr)->IsKeyframe())
- ss << "K";
- }
- ss << " }";
-
- return ss.str();
-}
-
-StreamParserTestBase::StreamParserTestBase(
- scoped_ptr<StreamParser> stream_parser)
- : parser_(stream_parser.Pass()) {}
-
-StreamParserTestBase::~StreamParserTestBase() {}
-
-std::string StreamParserTestBase::ParseFile(const std::string& filename,
- int append_bytes) {
- results_stream_.clear();
- InitializeParser();
-
- scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename);
- EXPECT_TRUE(
- AppendDataInPieces(buffer->data(), buffer->data_size(), append_bytes));
- return results_stream_.str();
-}
-
-void StreamParserTestBase::InitializeParser() {
- parser_->Init(
- base::Bind(&StreamParserTestBase::OnInitDone, base::Unretained(this)),
- base::Bind(&StreamParserTestBase::OnNewConfig, base::Unretained(this)),
- base::Bind(&StreamParserTestBase::OnNewBuffers, base::Unretained(this)),
- true,
- base::Bind(&StreamParserTestBase::OnKeyNeeded, base::Unretained(this)),
- base::Bind(&StreamParserTestBase::OnNewSegment, base::Unretained(this)),
- base::Bind(&StreamParserTestBase::OnEndOfSegment, base::Unretained(this)),
- LogCB());
-}
-
-bool StreamParserTestBase::AppendDataInPieces(const uint8* data,
- size_t length,
- size_t piece_size) {
- const uint8* start = data;
- const uint8* end = data + length;
- while (start < end) {
- size_t append_size = std::min(piece_size, static_cast<size_t>(end - start));
- if (!parser_->Parse(start, append_size))
- return false;
- start += append_size;
- }
- return true;
-}
-
-void StreamParserTestBase::OnInitDone(bool success, base::TimeDelta duration) {
- DVLOG(1) << __FUNCTION__ << "(" << success << ", "
- << duration.InMilliseconds() << ")";
-}
-
-bool StreamParserTestBase::OnNewConfig(
- const AudioDecoderConfig& audio_config,
- const VideoDecoderConfig& video_config,
- const StreamParser::TextTrackConfigMap& text_config) {
- DVLOG(1) << __FUNCTION__ << "(" << audio_config.IsValidConfig() << ", "
- << video_config.IsValidConfig() << ")";
- EXPECT_TRUE(audio_config.IsValidConfig());
- EXPECT_FALSE(video_config.IsValidConfig());
- return true;
-}
-
-bool StreamParserTestBase::OnNewBuffers(
- const StreamParser::BufferQueue& audio_buffers,
- const StreamParser::BufferQueue& video_buffers,
- const StreamParser::TextBufferQueueMap& text_map) {
- EXPECT_FALSE(audio_buffers.empty());
- EXPECT_TRUE(video_buffers.empty());
-
- // TODO(wolenetz/acolwell): Add text track support to more MSE parsers. See
- // http://crbug.com/336926.
- EXPECT_TRUE(text_map.empty());
-
- const std::string buffers_str = BufferQueueToString(audio_buffers);
- DVLOG(1) << __FUNCTION__ << " : " << buffers_str;
- results_stream_ << buffers_str;
- return true;
-}
-
-void StreamParserTestBase::OnKeyNeeded(const std::string& type,
- const std::vector<uint8>& init_data) {
- DVLOG(1) << __FUNCTION__ << "(" << type << ", " << init_data.size() << ")";
-}
-
-void StreamParserTestBase::OnNewSegment() {
- DVLOG(1) << __FUNCTION__;
- results_stream_ << "NewSegment";
-}
-
-void StreamParserTestBase::OnEndOfSegment() {
- DVLOG(1) << __FUNCTION__;
- results_stream_ << "EndOfSegment";
-}
-
-} // namespace media
diff --git a/media/formats/common/stream_parser_test_base.h b/media/formats/common/stream_parser_test_base.h
deleted file mode 100644
index 4e26274..0000000
--- a/media/formats/common/stream_parser_test_base.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_FORMATS_COMMON_STREAM_PARSER_TEST_BASE_H_
-#define MEDIA_FORMATS_COMMON_STREAM_PARSER_TEST_BASE_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "media/base/audio_decoder_config.h"
-#include "media/base/stream_parser.h"
-#include "media/base/stream_parser_buffer.h"
-#include "media/base/text_track_config.h"
-#include "media/base/video_decoder_config.h"
-
-namespace media {
-
-// Test helper for verifying StreamParser behavior.
-class StreamParserTestBase {
- public:
- explicit StreamParserTestBase(scoped_ptr<StreamParser> stream_parser);
- virtual ~StreamParserTestBase();
-
- protected:
- // Chunks a given parser appropriate file. Appends |append_bytes| at a time
- // until the file is exhausted. Returns a coded string representing the
- // segments and timestamps of the extracted frames.
- //
- // The start of each media segment is designated by "NewSegment", similarly
- // the end of each segment by "EndOfSegment". Segments end when one or more
- // frames are parsed from an append. If the append contains a partial frame
- // the segment will continue into the next append.
- //
- // Parsed frame(s) are represented as "{ xxK yyK zzK }" Where xx, yy, and zz
- // are the timestamps in milliseconds of each parsed frame. For example:
- //
- // "NewSegment{ 0K 23K 46K }EndOfSegment"
- // "NewSegment{ 0K }{ 23K }{ 46K }EndOfSegment"
- // "NewSegment{ 0K }{ 23K }EndOfSegmentNewSegment{ 46K }EndOfSegment"
- //
- std::string ParseFile(const std::string& filename, int append_bytes);
-
- private:
- void InitializeParser();
- bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size);
-
- void OnInitDone(bool success, base::TimeDelta duration);
- bool OnNewConfig(const AudioDecoderConfig& audio_config,
- const VideoDecoderConfig& video_config,
- const StreamParser::TextTrackConfigMap& text_config);
- bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
- const StreamParser::BufferQueue& video_buffers,
- const StreamParser::TextBufferQueueMap& text_map);
- void OnKeyNeeded(const std::string& type,
- const std::vector<uint8>& init_data);
- void OnNewSegment();
- void OnEndOfSegment();
-
- scoped_ptr<StreamParser> parser_;
- std::stringstream results_stream_;
-
- DISALLOW_COPY_AND_ASSIGN(StreamParserTestBase);
-};
-
-} // namespace media
-
-#endif // MEDIA_FORMATS_COMMON_STREAM_PARSER_TEST_BASE_H_ \ No newline at end of file
diff --git a/media/formats/mp2t/es_parser_adts.cc b/media/formats/mp2t/es_parser_adts.cc
index 2154c9e..5a47163 100644
--- a/media/formats/mp2t/es_parser_adts.cc
+++ b/media/formats/mp2t/es_parser_adts.cc
@@ -15,9 +15,43 @@
#include "media/base/channel_layout.h"
#include "media/base/stream_parser_buffer.h"
#include "media/formats/mp2t/mp2t_common.h"
-#include "media/formats/mpeg/adts_constants.h"
-namespace media {
+// Adts header is at least 7 bytes (can be 9 bytes).
+static const int kAdtsHeaderMinSize = 7;
+
+static const int adts_frequency_table[16] = {
+ 96000,
+ 88200,
+ 64000,
+ 48000,
+ 44100,
+ 32000,
+ 24000,
+ 22050,
+ 16000,
+ 12000,
+ 11025,
+ 8000,
+ 7350,
+ 0,
+ 0,
+ 0,
+};
+static const int kMaxSupportedFrequencyIndex = 12;
+
+static media::ChannelLayout adts_channel_layout[8] = {
+ media::CHANNEL_LAYOUT_NONE,
+ media::CHANNEL_LAYOUT_MONO,
+ media::CHANNEL_LAYOUT_STEREO,
+ media::CHANNEL_LAYOUT_SURROUND,
+ media::CHANNEL_LAYOUT_4_0,
+ media::CHANNEL_LAYOUT_5_0_BACK,
+ media::CHANNEL_LAYOUT_5_1_BACK,
+ media::CHANNEL_LAYOUT_7_1,
+};
+
+// Number of samples per frame.
+static const int kNumberSamplesPerAACFrame = 1024;
static int ExtractAdtsFrameSize(const uint8* adts_header) {
return ((static_cast<int>(adts_header[5]) >> 5) |
@@ -25,11 +59,11 @@ static int ExtractAdtsFrameSize(const uint8* adts_header) {
((static_cast<int>(adts_header[3]) & 0x3) << 11));
}
-static size_t ExtractAdtsFrequencyIndex(const uint8* adts_header) {
+static int ExtractAdtsFrequencyIndex(const uint8* adts_header) {
return ((adts_header[2] >> 2) & 0xf);
}
-static size_t ExtractAdtsChannelConfig(const uint8* adts_header) {
+static int ExtractAdtsChannelConfig(const uint8* adts_header) {
return (((adts_header[3] >> 6) & 0x3) |
((adts_header[2] & 0x1) << 2));
}
@@ -53,7 +87,7 @@ static bool LookForSyncWord(const uint8* raw_es, int raw_es_size,
DCHECK_GE(pos, 0);
DCHECK_LE(pos, raw_es_size);
- int max_offset = raw_es_size - kADTSHeaderMinSize;
+ int max_offset = raw_es_size - kAdtsHeaderMinSize;
if (pos >= max_offset) {
// Do not change the position if:
// - max_offset < 0: not enough bytes to get a full header
@@ -74,7 +108,7 @@ static bool LookForSyncWord(const uint8* raw_es, int raw_es_size,
continue;
int frame_size = ExtractAdtsFrameSize(cur_buf);
- if (frame_size < kADTSHeaderMinSize) {
+ if (frame_size < kAdtsHeaderMinSize) {
// Too short to be an ADTS frame.
continue;
}
@@ -96,6 +130,7 @@ static bool LookForSyncWord(const uint8* raw_es, int raw_es_size,
return false;
}
+namespace media {
namespace mp2t {
EsParserAdts::EsParserAdts(
@@ -137,7 +172,7 @@ bool EsParserAdts::Parse(const uint8* buf, int size,
<< " frame_size=" << frame_size;
DVLOG(LOG_LEVEL_ES)
<< "ADTS header: "
- << base::HexEncode(&raw_es[es_position], kADTSHeaderMinSize);
+ << base::HexEncode(&raw_es[es_position], kAdtsHeaderMinSize);
// Do not process the frame if this one is a partial frame.
int remaining_size = raw_es_size - es_position;
@@ -145,7 +180,7 @@ bool EsParserAdts::Parse(const uint8* buf, int size,
break;
// Update the audio configuration if needed.
- DCHECK_GE(frame_size, kADTSHeaderMinSize);
+ DCHECK_GE(frame_size, kAdtsHeaderMinSize);
if (!UpdateAudioConfiguration(&raw_es[es_position]))
return false;
@@ -158,7 +193,7 @@ bool EsParserAdts::Parse(const uint8* buf, int size,
base::TimeDelta current_pts = audio_timestamp_helper_->GetTimestamp();
base::TimeDelta frame_duration =
- audio_timestamp_helper_->GetFrameDuration(kSamplesPerAACFrame);
+ audio_timestamp_helper_->GetFrameDuration(kNumberSamplesPerAACFrame);
// Emit an audio frame.
bool is_key_frame = true;
@@ -177,7 +212,7 @@ bool EsParserAdts::Parse(const uint8* buf, int size,
emit_buffer_cb_.Run(stream_parser_buffer);
// Update the PTS of the next frame.
- audio_timestamp_helper_->AddFrames(kSamplesPerAACFrame);
+ audio_timestamp_helper_->AddFrames(kNumberSamplesPerAACFrame);
// Skip the current frame.
es_position += frame_size;
@@ -199,24 +234,23 @@ void EsParserAdts::Reset() {
}
bool EsParserAdts::UpdateAudioConfiguration(const uint8* adts_header) {
- size_t frequency_index = ExtractAdtsFrequencyIndex(adts_header);
- if (frequency_index >= kADTSFrequencyTableSize) {
+ int frequency_index = ExtractAdtsFrequencyIndex(adts_header);
+ if (frequency_index > kMaxSupportedFrequencyIndex) {
// Frequency index 13 & 14 are reserved
// while 15 means that the frequency is explicitly written
// (not supported).
return false;
}
- size_t channel_configuration = ExtractAdtsChannelConfig(adts_header);
- if (channel_configuration == 0 ||
- channel_configuration >= kADTSChannelLayoutTableSize) {
+ int channel_configuration = ExtractAdtsChannelConfig(adts_header);
+ if (channel_configuration == 0) {
// TODO(damienv): Add support for inband channel configuration.
return false;
}
// TODO(damienv): support HE-AAC frequency doubling (SBR)
// based on the incoming ADTS profile.
- int samples_per_second = kADTSFrequencyTable[frequency_index];
+ int samples_per_second = adts_frequency_table[frequency_index];
int adts_profile = (adts_header[2] >> 6) & 0x3;
// The following code is written according to ISO 14496 Part 3 Table 1.11 and
@@ -230,7 +264,7 @@ bool EsParserAdts::UpdateAudioConfiguration(const uint8* adts_header) {
AudioDecoderConfig audio_decoder_config(
kCodecAAC,
kSampleFormatS16,
- kADTSChannelLayoutTable[channel_configuration],
+ adts_channel_layout[channel_configuration],
extended_samples_per_second,
NULL, 0,
false);
diff --git a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc b/media/formats/mp3/mp3_stream_parser.cc
index ba3cbd9..2127cc4 100644
--- a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
+++ b/media/formats/mp3/mp3_stream_parser.cc
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "media/formats/mpeg/mpeg_audio_stream_parser_base.h"
+#include "media/formats/mp3/mp3_stream_parser.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/message_loop/message_loop.h"
+#include "media/base/bit_reader.h"
#include "media/base/buffers.h"
#include "media/base/stream_parser_buffer.h"
#include "media/base/text_track_config.h"
@@ -14,6 +15,7 @@
namespace media {
+static const uint32 kMP3StartCodeMask = 0xffe00000;
static const uint32 kICYStartCode = 0x49435920; // 'ICY '
// Arbitrary upper bound on the size of an IceCast header before it
@@ -26,40 +28,100 @@ static const int kID3v1Size = 128;
static const int kID3v1ExtendedSize = 227;
static const uint32 kID3v2StartCode = 0x49443300; // 'ID3\0'
-static int LocateEndOfHeaders(const uint8_t* buf, int buf_len, int i) {
- bool was_lf = false;
- char last_c = '\0';
- for (; i < buf_len; ++i) {
- char c = buf[i];
- if (c == '\n') {
- if (was_lf)
- return i + 1;
- was_lf = true;
- } else if (c != '\r' || last_c != '\n') {
- was_lf = false;
- }
- last_c = c;
- }
- return -1;
+// Map that determines which bitrate_index & channel_mode combinations
+// are allowed.
+// Derived from: http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
+static const bool kIsAllowed[17][4] = {
+ { true, true, true, true }, // free
+ { true, false, false, false }, // 32
+ { true, false, false, false }, // 48
+ { true, false, false, false }, // 56
+ { true, true, true, true }, // 64
+ { true, false, false, false }, // 80
+ { true, true, true, true }, // 96
+ { true, true, true, true }, // 112
+ { true, true, true, true }, // 128
+ { true, true, true, true }, // 160
+ { true, true, true, true }, // 192
+ { false, true, true, true }, // 224
+ { false, true, true, true }, // 256
+ { false, true, true, true }, // 320
+ { false, true, true, true }, // 384
+ { false, false, false, false } // bad
+};
+
+// Maps version and layer information in the frame header
+// into an index for the |kBitrateMap|.
+// Derived from: http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
+static const int kVersionLayerMap[4][4] = {
+ // { reserved, L3, L2, L1 }
+ { 5, 4, 4, 3 }, // MPEG 2.5
+ { 5, 5, 5, 5 }, // reserved
+ { 5, 4, 4, 3 }, // MPEG 2
+ { 5, 2, 1, 0 } // MPEG 1
+};
+
+// Maps the bitrate index field in the header and an index
+// from |kVersionLayerMap| to a frame bitrate.
+// Derived from: http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
+static const int kBitrateMap[16][6] = {
+ // { V1L1, V1L2, V1L3, V2L1, V2L2 & V2L3, reserved }
+ { 0, 0, 0, 0, 0, 0 },
+ { 32, 32, 32, 32, 8, 0 },
+ { 64, 48, 40, 48, 16, 0 },
+ { 96, 56, 48, 56, 24, 0 },
+ { 128, 64, 56, 64, 32, 0 },
+ { 160, 80, 64, 80, 40, 0 },
+ { 192, 96, 80, 96, 48, 0 },
+ { 224, 112, 96, 112, 56, 0 },
+ { 256, 128, 112, 128, 64, 0 },
+ { 288, 160, 128, 144, 80, 0 },
+ { 320, 192, 160, 160, 96, 0 },
+ { 352, 224, 192, 176, 112, 0 },
+ { 384, 256, 224, 192, 128, 0 },
+ { 416, 320, 256, 224, 144, 0 },
+ { 448, 384, 320, 256, 160, 0 },
+ { 0, 0, 0, 0, 0}
+};
+
+// Maps the sample rate index and version fields from the frame header
+// to a sample rate.
+// Derived from: http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
+static const int kSampleRateMap[4][4] = {
+ // { V2.5, reserved, V2, V1 }
+ { 11025, 0, 22050, 44100 },
+ { 12000, 0, 24000, 48000 },
+ { 8000, 0, 16000, 32000 },
+ { 0, 0, 0, 0 }
+};
+
+// 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;
+
+MP3StreamParser::MP3StreamParser()
+ : state_(UNINITIALIZED),
+ in_media_segment_(false) {
}
-MPEGAudioStreamParserBase::MPEGAudioStreamParserBase(uint32 start_code_mask,
- AudioCodec audio_codec)
- : state_(UNINITIALIZED),
- in_media_segment_(false),
- start_code_mask_(start_code_mask),
- audio_codec_(audio_codec) {}
-
-MPEGAudioStreamParserBase::~MPEGAudioStreamParserBase() {}
-
-void MPEGAudioStreamParserBase::Init(const InitCB& init_cb,
- const NewConfigCB& config_cb,
- const NewBuffersCB& new_buffers_cb,
- bool ignore_text_tracks,
- const NeedKeyCB& need_key_cb,
- const NewMediaSegmentCB& new_segment_cb,
- const base::Closure& end_of_segment_cb,
- const LogCB& log_cb) {
+MP3StreamParser::~MP3StreamParser() {}
+
+void MP3StreamParser::Init(const InitCB& init_cb,
+ const NewConfigCB& config_cb,
+ const NewBuffersCB& new_buffers_cb,
+ bool ignore_text_tracks,
+ const NeedKeyCB& need_key_cb,
+ const NewMediaSegmentCB& new_segment_cb,
+ const base::Closure& end_of_segment_cb,
+ const LogCB& log_cb) {
DVLOG(1) << __FUNCTION__;
DCHECK_EQ(state_, UNINITIALIZED);
init_cb_ = init_cb;
@@ -72,7 +134,7 @@ void MPEGAudioStreamParserBase::Init(const InitCB& init_cb,
ChangeState(INITIALIZED);
}
-void MPEGAudioStreamParserBase::Flush() {
+void MP3StreamParser::Flush() {
DVLOG(1) << __FUNCTION__;
DCHECK_NE(state_, UNINITIALIZED);
queue_.Reset();
@@ -80,7 +142,7 @@ void MPEGAudioStreamParserBase::Flush() {
in_media_segment_ = false;
}
-bool MPEGAudioStreamParserBase::Parse(const uint8* buf, int size) {
+bool MP3StreamParser::Parse(const uint8* buf, int size) {
DVLOG(1) << __FUNCTION__ << "(" << size << ")";
DCHECK(buf);
DCHECK_GT(size, 0);
@@ -106,8 +168,8 @@ bool MPEGAudioStreamParserBase::Parse(const uint8* buf, int size) {
uint32 start_code = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
int bytes_read = 0;
bool parsed_metadata = true;
- if ((start_code & start_code_mask_) == start_code_mask_) {
- bytes_read = ParseFrame(data, data_size, &buffers);
+ if ((start_code & kMP3StartCodeMask) == kMP3StartCodeMask) {
+ bytes_read = ParseMP3Frame(data, data_size, &buffers);
// Only allow the current segment to end if a full frame has been parsed.
end_of_segment = bytes_read > 0;
@@ -152,14 +214,157 @@ bool MPEGAudioStreamParserBase::Parse(const uint8* buf, int size) {
return SendBuffers(&buffers, end_of_segment);
}
-void MPEGAudioStreamParserBase::ChangeState(State state) {
+void MP3StreamParser::ChangeState(State state) {
DVLOG(1) << __FUNCTION__ << "() : " << state_ << " -> " << state;
state_ = state;
}
-int MPEGAudioStreamParserBase::ParseFrame(const uint8* data,
- int size,
- BufferQueue* buffers) {
+int MP3StreamParser::ParseFrameHeader(const uint8* data, int size,
+ int* frame_size,
+ int* sample_rate,
+ ChannelLayout* channel_layout,
+ int* sample_count) const {
+ DCHECK(data);
+ DCHECK_GE(size, 0);
+ DCHECK(frame_size);
+
+ if (size < 4)
+ return 0;
+
+ BitReader reader(data, size);
+ int sync;
+ int version;
+ int layer;
+ int is_protected;
+ int bitrate_index;
+ int sample_rate_index;
+ int has_padding;
+ int is_private;
+ int channel_mode;
+ int other_flags;
+
+ if (!reader.ReadBits(11, &sync) ||
+ !reader.ReadBits(2, &version) ||
+ !reader.ReadBits(2, &layer) ||
+ !reader.ReadBits(1, &is_protected) ||
+ !reader.ReadBits(4, &bitrate_index) ||
+ !reader.ReadBits(2, &sample_rate_index) ||
+ !reader.ReadBits(1, &has_padding) ||
+ !reader.ReadBits(1, &is_private) ||
+ !reader.ReadBits(2, &channel_mode) ||
+ !reader.ReadBits(6, &other_flags)) {
+ return -1;
+ }
+
+ DVLOG(2) << "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;
+
+ if (sync != 0x7ff ||
+ version == kVersionReserved ||
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ if (sample_rate)
+ *sample_rate = frame_sample_rate;
+
+ // http://teslabs.com/openplayer/docs/docs/specs/mp3_structure2.pdf
+ // Table 2.1.5
+ int samples_per_frame;
+ switch (layer) {
+ case kLayer1:
+ samples_per_frame = 384;
+ break;
+
+ case kLayer2:
+ samples_per_frame = 1152;
+ break;
+
+ case kLayer3:
+ if (version == kVersion2 || version == kVersion2_5)
+ samples_per_frame = 576;
+ else
+ samples_per_frame = 1152;
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (sample_count)
+ *sample_count = samples_per_frame;
+
+ // http://teslabs.com/openplayer/docs/docs/specs/mp3_structure2.pdf
+ // Text just below Table 2.1.5.
+ if (layer == kLayer1) {
+ // This formulation is a slight variation on the equation below,
+ // 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);
+ } else {
+ *frame_size =
+ ((samples_per_frame / 8) * bitrate * 1000) / frame_sample_rate;
+ }
+
+ if (has_padding)
+ *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;
+ }
+
+ return 4;
+}
+
+int MP3StreamParser::ParseMP3Frame(const uint8* data,
+ int size,
+ BufferQueue* buffers) {
DVLOG(2) << __FUNCTION__ << "(" << size << ")";
int sample_rate;
@@ -178,8 +383,7 @@ int MPEGAudioStreamParserBase::ParseFrame(const uint8* data,
DVLOG(2) << " sample_rate " << sample_rate
<< " channel_layout " << channel_layout
- << " frame_size " << frame_size
- << " sample_count " << sample_count;
+ << " frame_size " << frame_size;
if (config_.IsValidConfig() &&
(config_.samples_per_second() != sample_rate ||
@@ -193,7 +397,7 @@ int MPEGAudioStreamParserBase::ParseFrame(const uint8* data,
}
if (!config_.IsValidConfig()) {
- config_.Initialize(audio_codec_, kSampleFormatF32, channel_layout,
+ config_.Initialize(kCodecMP3, kSampleFormatF32, channel_layout,
sample_rate, NULL, 0, false, false,
base::TimeDelta(), base::TimeDelta());
@@ -229,7 +433,25 @@ int MPEGAudioStreamParserBase::ParseFrame(const uint8* data,
return frame_size;
}
-int MPEGAudioStreamParserBase::ParseIcecastHeader(const uint8* data, int size) {
+static int LocateEndOfHeaders(const uint8_t* buf, int buf_len, int i) {
+ bool was_lf = false;
+ char last_c = '\0';
+ for (; i < buf_len; ++i) {
+ char c = buf[i];
+ if (c == '\n') {
+ if (was_lf)
+ return i + 1;
+ was_lf = true;
+ } else if (c != '\r' || last_c != '\n') {
+ was_lf = false;
+ }
+ last_c = c;
+ }
+ return -1;
+}
+
+
+int MP3StreamParser::ParseIcecastHeader(const uint8* data, int size) {
DVLOG(1) << __FUNCTION__ << "(" << size << ")";
if (size < 4)
@@ -252,7 +474,7 @@ int MPEGAudioStreamParserBase::ParseIcecastHeader(const uint8* data, int size) {
return offset;
}
-int MPEGAudioStreamParserBase::ParseID3v1(const uint8* data, int size) {
+int MP3StreamParser::ParseID3v1(const uint8* data, int size) {
DVLOG(1) << __FUNCTION__ << "(" << size << ")";
if (size < kID3v1Size)
@@ -263,7 +485,7 @@ int MPEGAudioStreamParserBase::ParseID3v1(const uint8* data, int size) {
return !memcmp(data, "TAG+", 4) ? kID3v1ExtendedSize : kID3v1Size;
}
-int MPEGAudioStreamParserBase::ParseID3v2(const uint8* data, int size) {
+int MP3StreamParser::ParseID3v2(const uint8* data, int size) {
DVLOG(1) << __FUNCTION__ << "(" << size << ")";
if (size < 10)
@@ -297,8 +519,7 @@ int MPEGAudioStreamParserBase::ParseID3v2(const uint8* data, int size) {
return actual_tag_size;
}
-bool MPEGAudioStreamParserBase::ParseSyncSafeInt(BitReader* reader,
- int32* value) {
+bool MP3StreamParser::ParseSyncSafeInt(BitReader* reader, int32* value) {
*value = 0;
for (int i = 0; i < 4; ++i) {
uint8 tmp;
@@ -317,8 +538,7 @@ bool MPEGAudioStreamParserBase::ParseSyncSafeInt(BitReader* reader,
return true;
}
-int MPEGAudioStreamParserBase::FindNextValidStartCode(const uint8* data,
- int size) const {
+int MP3StreamParser::FindNextValidStartCode(const uint8* data, int size) const {
const uint8* start = data;
const uint8* end = data + size;
@@ -373,8 +593,7 @@ int MPEGAudioStreamParserBase::FindNextValidStartCode(const uint8* data,
return 0;
}
-bool MPEGAudioStreamParserBase::SendBuffers(BufferQueue* buffers,
- bool end_of_segment) {
+bool MP3StreamParser::SendBuffers(BufferQueue* buffers, bool end_of_segment) {
DCHECK(!buffers->empty());
if (!in_media_segment_) {
diff --git a/media/formats/mpeg/mpeg_audio_stream_parser_base.h b/media/formats/mp3/mp3_stream_parser.h
index 5975c1b..6b4b388 100644
--- a/media/formats/mpeg/mpeg_audio_stream_parser_base.h
+++ b/media/formats/mp3/mp3_stream_parser.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef MEDIA_FORMATS_MPEG_MPEG_AUDIO_STREAM_PARSER_BASE_H_
-#define MEDIA_FORMATS_MPEG_MPEG_AUDIO_STREAM_PARSER_BASE_H_
+#ifndef MEDIA_FORMATS_MP3_MP3_STREAM_PARSER_H_
+#define MEDIA_FORMATS_MP3_MP3_STREAM_PARSER_H_
#include <set>
#include <vector>
@@ -12,23 +12,21 @@
#include "base/callback.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/audio_timestamp_helper.h"
-#include "media/base/bit_reader.h"
#include "media/base/byte_queue.h"
#include "media/base/media_export.h"
#include "media/base/stream_parser.h"
namespace media {
-class MEDIA_EXPORT MPEGAudioStreamParserBase : public StreamParser {
+class BitReader;
+
+class MEDIA_EXPORT MP3StreamParser : public StreamParser {
public:
- // |start_code_mask| is used to find the start of each frame header. Also
- // referred to as the sync code in the MP3 and ADTS header specifications.
- MPEGAudioStreamParserBase(uint32 start_code_mask, AudioCodec audio_codec);
- virtual ~MPEGAudioStreamParserBase();
+ MP3StreamParser();
+ virtual ~MP3StreamParser();
// StreamParser implementation.
- virtual void Init(const InitCB& init_cb,
- const NewConfigCB& config_cb,
+ virtual void Init(const InitCB& init_cb, const NewConfigCB& config_cb,
const NewBuffersCB& new_buffers_cb,
bool ignore_text_tracks,
const NeedKeyCB& need_key_cb,
@@ -38,13 +36,35 @@ class MEDIA_EXPORT MPEGAudioStreamParserBase : public StreamParser {
virtual void Flush() OVERRIDE;
virtual bool Parse(const uint8* buf, int size) OVERRIDE;
- protected:
- // Subclasses implement this method to parse format specific frame headers.
+ private:
+ enum State {
+ UNINITIALIZED,
+ INITIALIZED,
+ PARSE_ERROR
+ };
+
+ State state_;
+
+ InitCB init_cb_;
+ NewConfigCB config_cb_;
+ NewBuffersCB new_buffers_cb_;
+ NewMediaSegmentCB new_segment_cb_;
+ base::Closure end_of_segment_cb_;
+ LogCB log_cb_;
+
+ ByteQueue queue_;
+
+ AudioDecoderConfig config_;
+ scoped_ptr<AudioTimestampHelper> timestamp_helper_;
+ bool in_media_segment_;
+
+ void ChangeState(State state);
+
+ // Parsing functions for various byte stream elements.
// |data| & |size| describe the data available for parsing.
- //
- // Implementations are expected to consume an entire frame header. It should
- // only return a value greater than 0 when |data| has enough bytes to
- // successfully parse & consume the entire frame header.
+ // These functions are expected to consume an entire frame/header.
+ // It should only return a value greater than 0 when |data| has
+ // enough bytes to successfully parse & consume the entire element.
//
// |frame_size| - Required parameter that is set to the size of the frame, in
// bytes, including the frame header if the function returns a value > 0.
@@ -60,34 +80,14 @@ class MEDIA_EXPORT MPEGAudioStreamParserBase : public StreamParser {
//
// Returns:
// > 0 : The number of bytes parsed.
- // 0 : If more data is needed to parse the entire frame header.
- // < 0 : An error was encountered during parsing.
- virtual int ParseFrameHeader(const uint8* data,
- int size,
- int* frame_size,
- int* sample_rate,
- ChannelLayout* channel_layout,
- int* sample_count) const = 0;
-
- const LogCB& log_cb() const { return log_cb_; }
-
- private:
- enum State {
- UNINITIALIZED,
- INITIALIZED,
- PARSE_ERROR
- };
-
- void ChangeState(State state);
-
- // Parsing functions for various byte stream elements. |data| & |size|
- // describe the data available for parsing.
- //
- // Returns:
- // > 0 : The number of bytes parsed.
// 0 : If more data is needed to parse the entire element.
// < 0 : An error was encountered during parsing.
- int ParseFrame(const uint8* data, int size, BufferQueue* buffers);
+ int ParseFrameHeader(const uint8* data, int size,
+ int* frame_size,
+ int* sample_rate,
+ ChannelLayout* channel_layout,
+ int* sample_count) const;
+ int ParseMP3Frame(const uint8* data, int size, BufferQueue* buffers);
int ParseIcecastHeader(const uint8* data, int size);
int ParseID3v1(const uint8* data, int size);
int ParseID3v2(const uint8* data, int size);
@@ -118,26 +118,9 @@ class MEDIA_EXPORT MPEGAudioStreamParserBase : public StreamParser {
// Returns true if the buffers are sent successfully.
bool SendBuffers(BufferQueue* buffers, bool end_of_segment);
- State state_;
-
- InitCB init_cb_;
- NewConfigCB config_cb_;
- NewBuffersCB new_buffers_cb_;
- NewMediaSegmentCB new_segment_cb_;
- base::Closure end_of_segment_cb_;
- LogCB log_cb_;
-
- ByteQueue queue_;
-
- AudioDecoderConfig config_;
- scoped_ptr<AudioTimestampHelper> timestamp_helper_;
- bool in_media_segment_;
- const uint32 start_code_mask_;
- const AudioCodec audio_codec_;
-
- DISALLOW_COPY_AND_ASSIGN(MPEGAudioStreamParserBase);
+ DISALLOW_COPY_AND_ASSIGN(MP3StreamParser);
};
} // namespace media
-#endif // MEDIA_FORMATS_MPEG_MPEG_AUDIO_STREAM_PARSER_BASE_H_
+#endif // MEDIA_FORMATS_MP3_MP3_STREAM_PARSER_H_
diff --git a/media/formats/mp3/mp3_stream_parser_unittest.cc b/media/formats/mp3/mp3_stream_parser_unittest.cc
new file mode 100644
index 0000000..4ff7853
--- /dev/null
+++ b/media/formats/mp3/mp3_stream_parser_unittest.cc
@@ -0,0 +1,170 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/decoder_buffer.h"
+#include "media/base/stream_parser_buffer.h"
+#include "media/base/test_data_util.h"
+#include "media/base/text_track_config.h"
+#include "media/base/video_decoder_config.h"
+#include "media/formats/mp3/mp3_stream_parser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+class MP3StreamParserTest : public testing::Test {
+ public:
+ MP3StreamParserTest() {}
+
+ protected:
+ MP3StreamParser parser_;
+ std::stringstream results_stream_;
+
+ bool AppendData(const uint8* data, size_t length) {
+ return parser_.Parse(data, length);
+ }
+
+ bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) {
+ const uint8* start = data;
+ const uint8* end = data + length;
+ while (start < end) {
+ size_t append_size =
+ std::min(piece_size, static_cast<size_t>(end - start));
+ if (!AppendData(start, append_size))
+ return false;
+ start += append_size;
+ }
+ return true;
+ }
+
+ void OnInitDone(bool success, base::TimeDelta duration) {
+ DVLOG(1) << __FUNCTION__ << "(" << success << ", "
+ << duration.InMilliseconds() << ")";
+ }
+
+ bool OnNewConfig(const AudioDecoderConfig& audio_config,
+ const VideoDecoderConfig& video_config,
+ const StreamParser::TextTrackConfigMap& text_config) {
+ DVLOG(1) << __FUNCTION__ << "(" << audio_config.IsValidConfig() << ", "
+ << video_config.IsValidConfig() << ")";
+ EXPECT_TRUE(audio_config.IsValidConfig());
+ EXPECT_FALSE(video_config.IsValidConfig());
+ return true;
+ }
+
+ std::string BufferQueueToString(const StreamParser::BufferQueue& buffers) {
+ std::stringstream ss;
+
+ ss << "{";
+ for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
+ itr != buffers.end();
+ ++itr) {
+ ss << " " << (*itr)->timestamp().InMilliseconds();
+ if ((*itr)->IsKeyframe())
+ ss << "K";
+ }
+ ss << " }";
+
+ return ss.str();
+ }
+
+ bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
+ const StreamParser::BufferQueue& video_buffers,
+ const StreamParser::TextBufferQueueMap& text_map) {
+ EXPECT_FALSE(audio_buffers.empty());
+ EXPECT_TRUE(video_buffers.empty());
+
+ // TODO(wolenetz/acolwell): Add text track support to more MSE parsers. See
+ // http://crbug.com/336926.
+ EXPECT_TRUE(text_map.empty());
+
+ std::string buffers_str = BufferQueueToString(audio_buffers);
+ DVLOG(1) << __FUNCTION__ << " : " << buffers_str;
+ results_stream_ << buffers_str;
+ return true;
+ }
+
+ void OnKeyNeeded(const std::string& type,
+ const std::vector<uint8>& init_data) {
+ DVLOG(1) << __FUNCTION__ << "(" << type << ", " << init_data.size() << ")";
+ }
+
+ void OnNewSegment() {
+ DVLOG(1) << __FUNCTION__;
+ results_stream_ << "NewSegment";
+ }
+
+ void OnEndOfSegment() {
+ DVLOG(1) << __FUNCTION__;
+ results_stream_ << "EndOfSegment";
+ }
+
+ void InitializeParser() {
+ parser_.Init(
+ base::Bind(&MP3StreamParserTest::OnInitDone, base::Unretained(this)),
+ base::Bind(&MP3StreamParserTest::OnNewConfig, base::Unretained(this)),
+ base::Bind(&MP3StreamParserTest::OnNewBuffers, base::Unretained(this)),
+ true,
+ base::Bind(&MP3StreamParserTest::OnKeyNeeded, base::Unretained(this)),
+ base::Bind(&MP3StreamParserTest::OnNewSegment, base::Unretained(this)),
+ base::Bind(&MP3StreamParserTest::OnEndOfSegment,
+ base::Unretained(this)),
+ LogCB());
+ }
+
+ std::string ParseFile(const std::string& filename, int append_bytes) {
+ results_stream_.clear();
+ InitializeParser();
+
+ scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename);
+ EXPECT_TRUE(
+ AppendDataInPieces(buffer->data(), buffer->data_size(), append_bytes));
+ return results_stream_.str();
+ }
+};
+
+// Test parsing with small prime sized chunks to smoke out "power of
+// 2" field size assumptions.
+TEST_F(MP3StreamParserTest, UnalignedAppend) {
+ std::string expected =
+ "NewSegment"
+ "{ 0K }"
+ "{ 26K }"
+ "{ 52K }"
+ "{ 78K }"
+ "{ 104K }"
+ "{ 130K }"
+ "{ 156K }"
+ "{ 182K }"
+ "EndOfSegment"
+ "NewSegment"
+ "{ 208K }"
+ "{ 235K }"
+ "{ 261K }"
+ "EndOfSegment"
+ "NewSegment"
+ "{ 287K }"
+ "{ 313K }"
+ "EndOfSegment";
+ EXPECT_EQ(expected, ParseFile("sfx.mp3", 17));
+}
+
+// Test parsing with a larger piece size to verify that multiple buffers
+// are passed to |new_buffer_cb_|.
+TEST_F(MP3StreamParserTest, UnalignedAppend512) {
+ std::string expected =
+ "NewSegment"
+ "{ 0K }"
+ "{ 26K 52K 78K 104K }"
+ "EndOfSegment"
+ "NewSegment"
+ "{ 130K 156K 182K }"
+ "{ 208K 235K 261K 287K }"
+ "{ 313K }"
+ "EndOfSegment";
+ EXPECT_EQ(expected, ParseFile("sfx.mp3", 512));
+}
+
+} // namespace media
diff --git a/media/formats/mp4/aac.cc b/media/formats/mp4/aac.cc
index c6be6be..fedb33f 100644
--- a/media/formats/mp4/aac.cc
+++ b/media/formats/mp4/aac.cc
@@ -9,9 +9,39 @@
#include "base/logging.h"
#include "media/base/bit_reader.h"
#include "media/formats/mp4/rcheck.h"
-#include "media/formats/mpeg/adts_constants.h"
+
+// The following conversion table is extracted from ISO 14496 Part 3 -
+// Table 1.16 - Sampling Frequency Index.
+static const int kFrequencyMap[] = {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000,
+ 22050, 16000, 12000, 11025, 8000, 7350
+};
namespace media {
+
+static ChannelLayout ConvertChannelConfigToLayout(uint8 channel_config) {
+ switch (channel_config) {
+ case 1:
+ return CHANNEL_LAYOUT_MONO;
+ case 2:
+ return CHANNEL_LAYOUT_STEREO;
+ case 3:
+ return CHANNEL_LAYOUT_SURROUND;
+ case 4:
+ return CHANNEL_LAYOUT_4_0;
+ case 5:
+ return CHANNEL_LAYOUT_5_0;
+ case 6:
+ return CHANNEL_LAYOUT_5_1;
+ case 8:
+ return CHANNEL_LAYOUT_7_1;
+ default:
+ break;
+ }
+
+ return CHANNEL_LAYOUT_UNSUPPORTED;
+}
+
namespace mp4 {
AAC::AAC()
@@ -92,25 +122,24 @@ bool AAC::Parse(const std::vector<uint8>& data) {
}
if (frequency_ == 0) {
- RCHECK(frequency_index_ < kADTSFrequencyTableSize);
- frequency_ = kADTSFrequencyTable[frequency_index_];
+ RCHECK(frequency_index_ < arraysize(kFrequencyMap));
+ frequency_ = kFrequencyMap[frequency_index_];
}
if (extension_frequency_ == 0 && extension_frequency_index != 0xff) {
- RCHECK(extension_frequency_index < kADTSFrequencyTableSize);
- extension_frequency_ = kADTSFrequencyTable[extension_frequency_index];
+ RCHECK(extension_frequency_index < arraysize(kFrequencyMap));
+ extension_frequency_ = kFrequencyMap[extension_frequency_index];
}
// When Parametric Stereo is on, mono will be played as stereo.
- if (ps_present && channel_config_ == 1) {
+ if (ps_present && channel_config_ == 1)
channel_layout_ = CHANNEL_LAYOUT_STEREO;
- } else {
- RCHECK(channel_layout_ < kADTSChannelLayoutTableSize);
- channel_layout_ = kADTSChannelLayoutTable[channel_config_];
- }
+ else
+ channel_layout_ = ConvertChannelConfigToLayout(channel_config_);
- return frequency_ != 0 && channel_layout_ != CHANNEL_LAYOUT_NONE &&
- profile_ >= 1 && profile_ <= 4;
+ return frequency_ != 0 && channel_layout_ != CHANNEL_LAYOUT_UNSUPPORTED &&
+ profile_ >= 1 && profile_ <= 4 && frequency_index_ != 0xf &&
+ channel_config_ <= 7;
}
int AAC::GetOutputSamplesPerSecond(bool sbr_in_mimetype) const {
@@ -139,7 +168,7 @@ ChannelLayout AAC::GetChannelLayout(bool sbr_in_mimetype) const {
}
bool AAC::ConvertEsdsToADTS(std::vector<uint8>* buffer) const {
- size_t size = buffer->size() + kADTSHeaderMinSize;
+ size_t size = buffer->size() + kADTSHeaderSize;
DCHECK(profile_ >= 1 && profile_ <= 4 && frequency_index_ != 0xf &&
channel_config_ <= 7);
@@ -150,7 +179,7 @@ bool AAC::ConvertEsdsToADTS(std::vector<uint8>* buffer) const {
std::vector<uint8>& adts = *buffer;
- adts.insert(buffer->begin(), kADTSHeaderMinSize, 0);
+ adts.insert(buffer->begin(), kADTSHeaderSize, 0);
adts[0] = 0xff;
adts[1] = 0xf1;
adts[2] = ((profile_ - 1) << 6) + (frequency_index_ << 2) +
diff --git a/media/formats/mp4/aac.h b/media/formats/mp4/aac.h
index 0b1d950..333d621 100644
--- a/media/formats/mp4/aac.h
+++ b/media/formats/mp4/aac.h
@@ -59,6 +59,9 @@ class MEDIA_EXPORT AAC {
}
#endif
+ // Size in bytes of the ADTS header added by ConvertEsdsToADTS().
+ static const size_t kADTSHeaderSize = 7;
+
private:
bool SkipDecoderGASpecificConfig(BitReader* bit_reader) const;
bool SkipErrorSpecificConfig() const;
diff --git a/media/formats/mp4/aac_unittest.cc b/media/formats/mp4/aac_unittest.cc
index d3ca839..6c2e797 100644
--- a/media/formats/mp4/aac_unittest.cc
+++ b/media/formats/mp4/aac_unittest.cc
@@ -85,7 +85,7 @@ TEST(AACTest, SixChannelTest) {
EXPECT_TRUE(aac.Parse(data));
EXPECT_EQ(aac.GetOutputSamplesPerSecond(false), 48000);
- EXPECT_EQ(aac.GetChannelLayout(false), CHANNEL_LAYOUT_5_1_BACK);
+ EXPECT_EQ(aac.GetChannelLayout(false), CHANNEL_LAYOUT_5_1);
}
TEST(AACTest, DataTooShortTest) {
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index 809bd82..e6de37e 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -17,7 +17,6 @@
#include "media/formats/mp4/box_reader.h"
#include "media/formats/mp4/es_descriptor.h"
#include "media/formats/mp4/rcheck.h"
-#include "media/formats/mpeg/adts_constants.h"
namespace media {
namespace mp4 {
@@ -385,11 +384,11 @@ bool MP4StreamParser::PrepareAACBuffer(
// not required to use subsample encryption, so we may need to add an entry.
if (subsamples->empty()) {
SubsampleEntry entry;
- entry.clear_bytes = kADTSHeaderMinSize;
- entry.cypher_bytes = frame_buf->size() - kADTSHeaderMinSize;
+ entry.clear_bytes = AAC::kADTSHeaderSize;
+ entry.cypher_bytes = frame_buf->size() - AAC::kADTSHeaderSize;
subsamples->push_back(entry);
} else {
- (*subsamples)[0].clear_bytes += kADTSHeaderMinSize;
+ (*subsamples)[0].clear_bytes += AAC::kADTSHeaderSize;
}
return true;
}
diff --git a/media/formats/mpeg/adts_constants.cc b/media/formats/mpeg/adts_constants.cc
deleted file mode 100644
index bc89890..0000000
--- a/media/formats/mpeg/adts_constants.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/formats/mpeg/adts_constants.h"
-
-#include "base/macros.h"
-
-namespace media {
-
-// The following conversion table is extracted from ISO 14496 Part 3 -
-// Table 1.16 - Sampling Frequency Index.
-const int kADTSFrequencyTable[] = {96000, 88200, 64000, 48000, 44100,
- 32000, 24000, 22050, 16000, 12000,
- 11025, 8000, 7350};
-const size_t kADTSFrequencyTableSize = arraysize(kADTSFrequencyTable);
-
-// The following conversion table is extracted from ISO 14496 Part 3 -
-// Table 1.17 - Channel Configuration.
-const media::ChannelLayout kADTSChannelLayoutTable[] = {
- media::CHANNEL_LAYOUT_NONE, media::CHANNEL_LAYOUT_MONO,
- media::CHANNEL_LAYOUT_STEREO, media::CHANNEL_LAYOUT_SURROUND,
- media::CHANNEL_LAYOUT_4_0, media::CHANNEL_LAYOUT_5_0_BACK,
- media::CHANNEL_LAYOUT_5_1_BACK, media::CHANNEL_LAYOUT_7_1};
-const size_t kADTSChannelLayoutTableSize = arraysize(kADTSChannelLayoutTable);
-
-} // namespace media
diff --git a/media/formats/mpeg/adts_constants.h b/media/formats/mpeg/adts_constants.h
deleted file mode 100644
index e080766..0000000
--- a/media/formats/mpeg/adts_constants.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_FORMATS_MPEG_ADTS_CONSTANTS_H_
-#define MEDIA_FORMATS_MPEG_ADTS_CONSTANTS_H_
-
-#include <stddef.h>
-
-#include "media/base/channel_layout.h"
-#include "media/base/media_export.h"
-
-namespace media {
-
-enum {
- kADTSHeaderMinSize = 7,
- kSamplesPerAACFrame = 1024,
-};
-
-MEDIA_EXPORT extern const int kADTSFrequencyTable[];
-MEDIA_EXPORT extern const size_t kADTSFrequencyTableSize;
-
-MEDIA_EXPORT extern const media::ChannelLayout kADTSChannelLayoutTable[];
-MEDIA_EXPORT extern const size_t kADTSChannelLayoutTableSize;
-
-} // namespace media
-
-#endif // MEDIA_FORMATS_MPEG_ADTS_CONSTANTS_H_ \ No newline at end of file
diff --git a/media/formats/mpeg/adts_stream_parser.cc b/media/formats/mpeg/adts_stream_parser.cc
deleted file mode 100644
index 0f5e280..0000000
--- a/media/formats/mpeg/adts_stream_parser.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/formats/mpeg/adts_stream_parser.h"
-
-#include "media/formats/mpeg/adts_constants.h"
-
-namespace media {
-
-static const uint32 kADTSStartCodeMask = 0xfff00000;
-
-ADTSStreamParser::ADTSStreamParser()
- : MPEGAudioStreamParserBase(kADTSStartCodeMask, kCodecAAC) {}
-
-ADTSStreamParser::~ADTSStreamParser() {}
-
-int ADTSStreamParser::ParseFrameHeader(const uint8* data,
- int size,
- int* frame_size,
- int* sample_rate,
- ChannelLayout* channel_layout,
- int* sample_count) const {
- DCHECK(data);
- DCHECK_GE(size, 0);
- DCHECK(frame_size);
-
- if (size < 8)
- return 0;
-
- BitReader reader(data, size);
- int sync;
- int version;
- int layer;
- int protection_absent;
- int profile;
- size_t sample_rate_index;
- size_t channel_layout_index;
- int frame_length;
- size_t num_data_blocks;
- int unused;
-
- if (!reader.ReadBits(12, &sync) ||
- !reader.ReadBits(1, &version) ||
- !reader.ReadBits(2, &layer) ||
- !reader.ReadBits(1, &protection_absent) ||
- !reader.ReadBits(2, &profile) ||
- !reader.ReadBits(4, &sample_rate_index) ||
- !reader.ReadBits(1, &unused) ||
- !reader.ReadBits(3, &channel_layout_index) ||
- !reader.ReadBits(4, &unused) ||
- !reader.ReadBits(13, &frame_length) ||
- !reader.ReadBits(11, &unused) ||
- !reader.ReadBits(2, &num_data_blocks) ||
- (!protection_absent && !reader.ReadBits(16, &unused))) {
- return -1;
- }
-
- DVLOG(2) << "Header data :" << std::hex
- << " sync 0x" << sync
- << " version 0x" << version
- << " layer 0x" << layer
- << " profile 0x" << profile
- << " sample_rate_index 0x" << sample_rate_index
- << " channel_layout_index 0x" << channel_layout_index;
-
- const int bytes_read = reader.bits_read() / 8;
- if (sync != 0xfff || layer != 0 || frame_length < bytes_read ||
- sample_rate_index >= kADTSFrequencyTableSize ||
- channel_layout_index >= kADTSChannelLayoutTableSize) {
- MEDIA_LOG(log_cb()) << "Invalid header data :" << std::hex
- << " sync 0x" << sync
- << " version 0x" << version
- << " layer 0x" << layer
- << " sample_rate_index 0x" << sample_rate_index
- << " channel_layout_index 0x" << channel_layout_index;
- return -1;
- }
-
- if (sample_rate)
- *sample_rate = kADTSFrequencyTable[sample_rate_index];
-
- if (frame_size)
- *frame_size = frame_length;
-
- if (sample_count)
- *sample_count = (num_data_blocks + 1) * kSamplesPerAACFrame;
-
- if (channel_layout)
- *channel_layout = kADTSChannelLayoutTable[channel_layout_index];
-
- return bytes_read;
-}
-
-} // namespace media
diff --git a/media/formats/mpeg/adts_stream_parser.h b/media/formats/mpeg/adts_stream_parser.h
deleted file mode 100644
index 26ebcc9..0000000
--- a/media/formats/mpeg/adts_stream_parser.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_FORMATS_MPEG_ADTS_STREAM_PARSER_H_
-#define MEDIA_FORMATS_MPEG_ADTS_STREAM_PARSER_H_
-
-#include "base/basictypes.h"
-#include "media/base/media_export.h"
-#include "media/formats/mpeg/mpeg_audio_stream_parser_base.h"
-
-namespace media {
-
-class MEDIA_EXPORT ADTSStreamParser : public MPEGAudioStreamParserBase {
- public:
- ADTSStreamParser();
- virtual ~ADTSStreamParser();
-
- private:
- // MPEGAudioStreamParserBase overrides.
- virtual int ParseFrameHeader(const uint8* data,
- int size,
- int* frame_size,
- int* sample_rate,
- ChannelLayout* channel_layout,
- int* sample_count) const OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(ADTSStreamParser);
-};
-
-} // namespace media
-
-#endif // MEDIA_FORMATS_MPEG_ADTS_STREAM_PARSER_H_
diff --git a/media/formats/mpeg/adts_stream_parser_unittest.cc b/media/formats/mpeg/adts_stream_parser_unittest.cc
deleted file mode 100644
index d0bedbe..0000000
--- a/media/formats/mpeg/adts_stream_parser_unittest.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/formats/common/stream_parser_test_base.h"
-#include "media/formats/mpeg/adts_stream_parser.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace media {
-
-class ADTSStreamParserTest : public StreamParserTestBase, public testing::Test {
- public:
- ADTSStreamParserTest()
- : StreamParserTestBase(
- scoped_ptr<StreamParser>(new ADTSStreamParser()).Pass()) {}
- virtual ~ADTSStreamParserTest() {}
-};
-
-// Test parsing with small prime sized chunks to smoke out "power of
-// 2" field size assumptions.
-TEST_F(ADTSStreamParserTest, UnalignedAppend) {
- const std::string expected =
- "NewSegment"
- "{ 0K }"
- "{ 23K }"
- "{ 46K }"
- "{ 69K }"
- "{ 92K }"
- "{ 116K }"
- "{ 139K }"
- "{ 162K }"
- "{ 185K }"
- "EndOfSegment"
- "NewSegment"
- "{ 208K }"
- "{ 232K }"
- "{ 255K }"
- "{ 278K }"
- "{ 301K }"
- "EndOfSegment";
- EXPECT_EQ(expected, ParseFile("sfx.adts", 17));
-}
-
-// Test parsing with a larger piece size to verify that multiple buffers
-// are passed to |new_buffer_cb_|.
-TEST_F(ADTSStreamParserTest, UnalignedAppend512) {
- const std::string expected =
- "NewSegment"
- "{ 0K 23K 46K }"
- "{ 69K 92K 116K 139K 162K }"
- "{ 185K 208K 232K 255K 278K }"
- "EndOfSegment"
- "NewSegment"
- "{ 301K }"
- "EndOfSegment";
- EXPECT_EQ(expected, ParseFile("sfx.adts", 512));
-}
-
-} // namespace media
diff --git a/media/formats/mpeg/mp3_stream_parser.cc b/media/formats/mpeg/mp3_stream_parser.cc
deleted file mode 100644
index 74d2f7d..0000000
--- a/media/formats/mpeg/mp3_stream_parser.cc
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// 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"
-
-namespace media {
-
-static const uint32 kMP3StartCodeMask = 0xffe00000;
-
-// Map that determines which bitrate_index & channel_mode combinations
-// are allowed.
-// Derived from: http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
-static const bool kIsAllowed[17][4] = {
- { true, true, true, true }, // free
- { true, false, false, false }, // 32
- { true, false, false, false }, // 48
- { true, false, false, false }, // 56
- { true, true, true, true }, // 64
- { true, false, false, false }, // 80
- { true, true, true, true }, // 96
- { true, true, true, true }, // 112
- { true, true, true, true }, // 128
- { true, true, true, true }, // 160
- { true, true, true, true }, // 192
- { false, true, true, true }, // 224
- { false, true, true, true }, // 256
- { false, true, true, true }, // 320
- { false, true, true, true }, // 384
- { false, false, false, false } // bad
-};
-
-// Maps version and layer information in the frame header
-// into an index for the |kBitrateMap|.
-// Derived from: http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
-static const int kVersionLayerMap[4][4] = {
- // { reserved, L3, L2, L1 }
- { 5, 4, 4, 3 }, // MPEG 2.5
- { 5, 5, 5, 5 }, // reserved
- { 5, 4, 4, 3 }, // MPEG 2
- { 5, 2, 1, 0 } // MPEG 1
-};
-
-// Maps the bitrate index field in the header and an index
-// from |kVersionLayerMap| to a frame bitrate.
-// Derived from: http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
-static const int kBitrateMap[16][6] = {
- // { V1L1, V1L2, V1L3, V2L1, V2L2 & V2L3, reserved }
- { 0, 0, 0, 0, 0, 0 },
- { 32, 32, 32, 32, 8, 0 },
- { 64, 48, 40, 48, 16, 0 },
- { 96, 56, 48, 56, 24, 0 },
- { 128, 64, 56, 64, 32, 0 },
- { 160, 80, 64, 80, 40, 0 },
- { 192, 96, 80, 96, 48, 0 },
- { 224, 112, 96, 112, 56, 0 },
- { 256, 128, 112, 128, 64, 0 },
- { 288, 160, 128, 144, 80, 0 },
- { 320, 192, 160, 160, 96, 0 },
- { 352, 224, 192, 176, 112, 0 },
- { 384, 256, 224, 192, 128, 0 },
- { 416, 320, 256, 224, 144, 0 },
- { 448, 384, 320, 256, 160, 0 },
- { 0, 0, 0, 0, 0}
-};
-
-// Maps the sample rate index and version fields from the frame header
-// to a sample rate.
-// Derived from: http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
-static const int kSampleRateMap[4][4] = {
- // { V2.5, reserved, V2, V1 }
- { 11025, 0, 22050, 44100 },
- { 12000, 0, 24000, 48000 },
- { 8000, 0, 16000, 32000 },
- { 0, 0, 0, 0 }
-};
-
-// 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;
-
-MP3StreamParser::MP3StreamParser()
- : MPEGAudioStreamParserBase(kMP3StartCodeMask, kCodecMP3) {}
-
-MP3StreamParser::~MP3StreamParser() {}
-
-int MP3StreamParser::ParseFrameHeader(const uint8* data,
- int size,
- int* frame_size,
- int* sample_rate,
- ChannelLayout* channel_layout,
- int* sample_count) const {
- DCHECK(data);
- DCHECK_GE(size, 0);
- DCHECK(frame_size);
-
- if (size < 4)
- return 0;
-
- BitReader reader(data, size);
- int sync;
- int version;
- int layer;
- int is_protected;
- int bitrate_index;
- int sample_rate_index;
- int has_padding;
- int is_private;
- int channel_mode;
- int other_flags;
-
- if (!reader.ReadBits(11, &sync) ||
- !reader.ReadBits(2, &version) ||
- !reader.ReadBits(2, &layer) ||
- !reader.ReadBits(1, &is_protected) ||
- !reader.ReadBits(4, &bitrate_index) ||
- !reader.ReadBits(2, &sample_rate_index) ||
- !reader.ReadBits(1, &has_padding) ||
- !reader.ReadBits(1, &is_private) ||
- !reader.ReadBits(2, &channel_mode) ||
- !reader.ReadBits(6, &other_flags)) {
- return -1;
- }
-
- DVLOG(2) << "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;
-
- if (sync != 0x7ff ||
- version == kVersionReserved ||
- 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;
- }
-
- 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;
- }
-
- 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;
- }
-
- 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;
- }
-
- if (sample_rate)
- *sample_rate = frame_sample_rate;
-
- // http://teslabs.com/openplayer/docs/docs/specs/mp3_structure2.pdf
- // Table 2.1.5
- int samples_per_frame;
- switch (layer) {
- case kLayer1:
- samples_per_frame = 384;
- break;
-
- case kLayer2:
- samples_per_frame = 1152;
- break;
-
- case kLayer3:
- if (version == kVersion2 || version == kVersion2_5)
- samples_per_frame = 576;
- else
- samples_per_frame = 1152;
- break;
-
- default:
- return -1;
- }
-
- if (sample_count)
- *sample_count = samples_per_frame;
-
- // http://teslabs.com/openplayer/docs/docs/specs/mp3_structure2.pdf
- // Text just below Table 2.1.5.
- if (layer == kLayer1) {
- // This formulation is a slight variation on the equation below,
- // 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);
- } else {
- *frame_size =
- ((samples_per_frame / 8) * bitrate * 1000) / frame_sample_rate;
- }
-
- if (has_padding)
- *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;
- }
-
- return 4;
-}
-
-} // namespace media
diff --git a/media/formats/mpeg/mp3_stream_parser.h b/media/formats/mpeg/mp3_stream_parser.h
deleted file mode 100644
index 209d263..0000000
--- a/media/formats/mpeg/mp3_stream_parser.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_FORMATS_MPEG_MP3_STREAM_PARSER_H_
-#define MEDIA_FORMATS_MPEG_MP3_STREAM_PARSER_H_
-
-#include "base/basictypes.h"
-#include "media/base/media_export.h"
-#include "media/formats/mpeg/mpeg_audio_stream_parser_base.h"
-
-namespace media {
-
-class MEDIA_EXPORT MP3StreamParser : public MPEGAudioStreamParserBase {
- public:
- MP3StreamParser();
- virtual ~MP3StreamParser();
-
- private:
- // MPEGAudioStreamParserBase overrides.
- virtual int ParseFrameHeader(const uint8* data,
- int size,
- int* frame_size,
- int* sample_rate,
- ChannelLayout* channel_layout,
- int* sample_count) const OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(MP3StreamParser);
-};
-
-} // namespace media
-
-#endif // MEDIA_FORMATS_MPEG_MP3_STREAM_PARSER_H_
diff --git a/media/formats/mpeg/mp3_stream_parser_unittest.cc b/media/formats/mpeg/mp3_stream_parser_unittest.cc
deleted file mode 100644
index eefadc5..0000000
--- a/media/formats/mpeg/mp3_stream_parser_unittest.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/formats/common/stream_parser_test_base.h"
-#include "media/formats/mpeg/mp3_stream_parser.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace media {
-
-class MP3StreamParserTest : public StreamParserTestBase, public testing::Test {
- public:
- MP3StreamParserTest()
- : StreamParserTestBase(
- scoped_ptr<StreamParser>(new MP3StreamParser()).Pass()) {}
- virtual ~MP3StreamParserTest() {}
-};
-
-// Test parsing with small prime sized chunks to smoke out "power of
-// 2" field size assumptions.
-TEST_F(MP3StreamParserTest, UnalignedAppend) {
- const std::string expected =
- "NewSegment"
- "{ 0K }"
- "{ 26K }"
- "{ 52K }"
- "{ 78K }"
- "{ 104K }"
- "{ 130K }"
- "{ 156K }"
- "{ 182K }"
- "EndOfSegment"
- "NewSegment"
- "{ 208K }"
- "{ 235K }"
- "{ 261K }"
- "EndOfSegment"
- "NewSegment"
- "{ 287K }"
- "{ 313K }"
- "EndOfSegment";
- EXPECT_EQ(expected, ParseFile("sfx.mp3", 17));
-}
-
-// Test parsing with a larger piece size to verify that multiple buffers
-// are passed to |new_buffer_cb_|.
-TEST_F(MP3StreamParserTest, UnalignedAppend512) {
- const std::string expected =
- "NewSegment"
- "{ 0K }"
- "{ 26K 52K 78K 104K }"
- "EndOfSegment"
- "NewSegment"
- "{ 130K 156K 182K }"
- "{ 208K 235K 261K 287K }"
- "{ 313K }"
- "EndOfSegment";
- EXPECT_EQ(expected, ParseFile("sfx.mp3", 512));
-}
-
-} // namespace media
diff --git a/media/media.gyp b/media/media.gyp
index 6638f5b..2fc8898 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -855,6 +855,8 @@
'formats/mp2t/ts_section_pmt.h',
'formats/mp2t/ts_section_psi.cc',
'formats/mp2t/ts_section_psi.h',
+ 'formats/mp3/mp3_stream_parser.cc',
+ 'formats/mp3/mp3_stream_parser.h',
'formats/mp4/aac.cc',
'formats/mp4/aac.h',
'formats/mp4/avc.cc',
@@ -871,14 +873,6 @@
'formats/mp4/mp4_stream_parser.h',
'formats/mp4/track_run_iterator.cc',
'formats/mp4/track_run_iterator.h',
- 'formats/mpeg/adts_constants.cc',
- 'formats/mpeg/adts_constants.h',
- 'formats/mpeg/adts_stream_parser.cc',
- 'formats/mpeg/adts_stream_parser.h',
- 'formats/mpeg/mp3_stream_parser.cc',
- 'formats/mpeg/mp3_stream_parser.h',
- 'formats/mpeg/mpeg_audio_stream_parser_base.cc',
- 'formats/mpeg/mpeg_audio_stream_parser_base.h',
],
}],
['toolkit_uses_gtk==1', {
@@ -1140,17 +1134,14 @@
}],
['proprietary_codecs==1', {
'sources': [
- 'formats/common/stream_parser_test_base.cc',
- 'formats/common/stream_parser_test_base.h',
'formats/mp2t/mp2t_stream_parser_unittest.cc',
+ 'formats/mp3/mp3_stream_parser_unittest.cc',
'formats/mp4/aac_unittest.cc',
'formats/mp4/avc_unittest.cc',
'formats/mp4/box_reader_unittest.cc',
'formats/mp4/es_descriptor_unittest.cc',
'formats/mp4/mp4_stream_parser_unittest.cc',
'formats/mp4/track_run_iterator_unittest.cc',
- 'formats/mpeg/adts_stream_parser_unittest.cc',
- 'formats/mpeg/mp3_stream_parser_unittest.cc',
],
}],
# TODO(wolenetz): Fix size_t to int truncations in win64. See