Skip to content

Commit

Permalink
Implement experimental MP3 support for Media Source API.
Browse files Browse the repository at this point in the history
BUG=280550
TEST=PipelineIntegrationTest.MediaSource_MP3

Review URL: https://chromiumcodereview.appspot.com/23454006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221471 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
acolwell@chromium.org committed Sep 5, 2013
1 parent 51b8711 commit d536809
Show file tree
Hide file tree
Showing 12 changed files with 784 additions and 7 deletions.
1 change: 1 addition & 0 deletions content/browser/renderer_host/render_process_host_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableGPUClientLogging,
switches::kEnableGpuClientTracing,
switches::kEnableGpuBenchmarking,
switches::kEnableMP3StreamParser,
switches::kEnableMemoryBenchmarking,
switches::kEnableOverlayScrollbars,
switches::kEnableSkiaBenchmarking,
Expand Down
1 change: 1 addition & 0 deletions media/DEPS
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
include_rules = [
"+gpu",
"+jni",
"+net/http",
"+third_party/ffmpeg",
"+third_party/libvpx",
"+third_party/opus",
Expand Down
3 changes: 3 additions & 0 deletions media/base/media_switches.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const char kVideoThreads[] = "video-threads";
const char kOverrideEncryptedMediaCanPlayType[] =
"override-encrypted-media-canplaytype";

// Enables MP3 stream parser for Media Source Extensions.
const char kEnableMP3StreamParser[] = "enable-mp3-stream-parser";

#if defined(GOOGLE_TV)
// Use external video surface for video with more than or equal pixels to
// specified value. For example, value of 0 will enable external video surface
Expand Down
2 changes: 2 additions & 0 deletions media/base/media_switches.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ MEDIA_EXPORT extern const char kVideoThreads[];

MEDIA_EXPORT extern const char kOverrideEncryptedMediaCanPlayType[];

MEDIA_EXPORT extern const char kEnableMP3StreamParser[];

#if defined(GOOGLE_TV)
MEDIA_EXPORT extern const char kUseExternalVideoSurfaceThresholdInPixels[];
#endif
Expand Down
2 changes: 2 additions & 0 deletions media/base/run_all_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ void TestSuiteNoAtExit::Initialize() {
// Run this here instead of main() to ensure an AtExitManager is already
// present.
media::InitializeMediaLibraryForTesting();
CommandLine* cmd_line = CommandLine::ForCurrentProcess();
cmd_line->AppendSwitch(switches::kEnableMP3StreamParser);
}

int main(int argc, char** argv) {
Expand Down
49 changes: 44 additions & 5 deletions media/filters/pipeline_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "build/build_config.h"
#include "media/base/decoder_buffer.h"
#include "media/base/media_keys.h"
#include "media/base/media_switches.h"
#include "media/base/test_data_util.h"
#include "media/cdm/aes_decryptor.h"
#include "media/filters/chunk_demuxer.h"
Expand All @@ -33,6 +34,7 @@ static const char kMP4Video[] = "video/mp4; codecs=\"avc1.4D4041\"";
static const char kMP4Audio[] = "audio/mp4; codecs=\"mp4a.40.2\"";
static const char kMP4AudioType[] = "audio/mp4";
static const char kMP4VideoType[] = "video/mp4";
static const char kMP3[] = "audio/mpeg";

// Key used to encrypt test files.
static const uint8 kSecretKey[] = {
Expand Down Expand Up @@ -284,13 +286,29 @@ class MockMediaSource {
}

void DemuxerOpenedTask() {
// This code assumes that |mimetype_| is one of the following forms.
// 1. audio/mpeg
// 2. video/webm;codec="vorbis,vp8".
size_t semicolon = mimetype_.find(";");
std::string type = mimetype_.substr(0, semicolon);
size_t quote1 = mimetype_.find("\"");
size_t quote2 = mimetype_.find("\"", quote1 + 1);
std::string codecStr = mimetype_.substr(quote1 + 1, quote2 - quote1 - 1);
std::string type = mimetype_;
std::vector<std::string> codecs;
Tokenize(codecStr, ",", &codecs);
if (semicolon != std::string::npos) {
type = mimetype_.substr(0, semicolon);
size_t codecs_param_start = mimetype_.find("codecs=\"", semicolon);

CHECK_NE(codecs_param_start, std::string::npos);

codecs_param_start += 8; // Skip over the codecs=".

size_t codecs_param_end = mimetype_.find("\"", codecs_param_start);

CHECK_NE(codecs_param_end, std::string::npos);

std::string codecs_param =
mimetype_.substr(codecs_param_start,
codecs_param_end - codecs_param_start);
Tokenize(codecs_param, ",", &codecs);
}

CHECK_EQ(chunk_demuxer_->AddId(kSourceId, type, codecs), ChunkDemuxer::kOk);
AppendData(initial_append_size_);
Expand Down Expand Up @@ -627,6 +645,27 @@ TEST_F(PipelineIntegrationTest,
}

#if defined(USE_PROPRIETARY_CODECS)
TEST_F(PipelineIntegrationTest, MediaSource_MP3) {
MockMediaSource source("sfx.mp3", kMP3, kAppendWholeFile);
StartPipelineWithMediaSource(&source);
source.EndOfStream();

Play();

EXPECT_TRUE(WaitUntilOnEnded());
}


TEST_F(PipelineIntegrationTest, MediaSource_MP3_Icecast) {
MockMediaSource source("icy_sfx.mp3", kMP3, kAppendWholeFile);
StartPipelineWithMediaSource(&source);
source.EndOfStream();

Play();

EXPECT_TRUE(WaitUntilOnEnded());
}

TEST_F(PipelineIntegrationTest, MediaSource_ConfigChange_MP4) {
MockMediaSource source("bear-640x360-av_frag.mp4", kMP4, kAppendWholeFile);
StartPipelineWithMediaSource(&source);
Expand Down
43 changes: 42 additions & 1 deletion media/filters/stream_parser_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "base/strings/string_util.h"
#include "media/base/media_log.h"
#include "media/base/media_switches.h"
#include "media/mp3/mp3_stream_parser.h"
#include "media/webm/webm_stream_parser.h"

#if defined(USE_PROPRIETARY_CODECS)
Expand All @@ -28,6 +29,8 @@ struct CodecInfo {
AUDIO,
VIDEO
};

// Update tools/metrics/histograms/histograms.xml if new values are added.
enum HistogramTag {
HISTOGRAM_UNKNOWN,
HISTOGRAM_VP8,
Expand All @@ -37,6 +40,7 @@ struct CodecInfo {
HISTOGRAM_MPEG2AAC,
HISTOGRAM_MPEG4AAC,
HISTOGRAM_EAC3,
HISTOGRAM_MP3,
HISTOGRAM_MAX // Must be the last entry.
};

Expand Down Expand Up @@ -151,6 +155,7 @@ static const CodecInfo* kAudioMP4Codecs[] = {
static StreamParser* BuildMP4Parser(
const std::vector<std::string>& codecs, const LogCB& log_cb) {
std::set<int> audio_object_types;

bool has_sbr = false;
#if defined(ENABLE_EAC3_PLAYBACK)
bool enable_eac3 = CommandLine::ForCurrentProcess()->HasSwitch(
Expand Down Expand Up @@ -179,12 +184,28 @@ static StreamParser* BuildMP4Parser(

return new mp4::MP4StreamParser(audio_object_types, has_sbr);
}

static const CodecInfo kMP3CodecInfo = { NULL, CodecInfo::AUDIO, NULL,
CodecInfo::HISTOGRAM_MP3 };

static const CodecInfo* kAudioMP3Codecs[] = {
&kMP3CodecInfo,
NULL
};

static StreamParser* BuildMP3Parser(
const std::vector<std::string>& codecs, const LogCB& log_cb) {
return new MP3StreamParser();
}

#endif


static const SupportedTypeInfo kSupportedTypeInfo[] = {
{ "video/webm", &BuildWebMParser, kVideoWebMCodecs },
{ "audio/webm", &BuildWebMParser, kAudioWebMCodecs },
#if defined(USE_PROPRIETARY_CODECS)
{ "audio/mpeg", &BuildMP3Parser, kAudioMP3Codecs },
{ "video/mp4", &BuildMP4Parser, kVideoMP4Codecs },
{ "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs },
#endif
Expand Down Expand Up @@ -212,6 +233,7 @@ static bool VerifyCodec(
return false;
}
#endif

if (audio_codecs)
audio_codecs->push_back(codec_info->tag);
return true;
Expand Down Expand Up @@ -253,8 +275,26 @@ static bool CheckTypeAndCodecs(
for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
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(
switches::kEnableMP3StreamParser)) {
DVLOG(1) << "MP3StreamParser is not enabled.";
return false;
}
#endif

const CodecInfo* codec_info = type_info.codecs[0];
if (codec_info && !codec_info->pattern &&
VerifyCodec(codec_info, audio_codecs, video_codecs)) {

if (factory_function)
*factory_function = type_info.factory_function;
return true;
}

if (codecs.size() == 0u) {
MEDIA_LOG(log_cb) << "A codecs parameter must be provided for '"
<< type << "'";
return false;
Expand All @@ -275,6 +315,7 @@ static bool CheckTypeAndCodecs(
break; // Since only 1 pattern will match, no need to check others.
}
}

if (!found_codec) {
MEDIA_LOG(log_cb) << "Codec '" << codec_id
<< "' is not supported for '" << type << "'";
Expand Down
2 changes: 1 addition & 1 deletion media/filters/stream_parser_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class MEDIA_EXPORT StreamParserFactory {
// |has_video| is true if a video codec was specified.
// Returns NULL otherwise. The values of |has_audio| and |has_video| are
// undefined.
static scoped_ptr<media::StreamParser> Create(
static scoped_ptr<StreamParser> Create(
const std::string& type, const std::vector<std::string>& codecs,
const LogCB& log_cb, bool* has_audio, bool* has_video);
};
Expand Down
3 changes: 3 additions & 0 deletions media/media.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
'dependencies': [
'../base/base.gyp:base',
'../crypto/crypto.gyp:crypto',
'../net/net.gyp:net',
'../skia/skia.gyp:skia',
'../third_party/opus/opus.gyp:opus',
'../ui/ui.gyp:ui',
Expand Down Expand Up @@ -382,6 +383,8 @@
'midi/midi_manager_mac.h',
'midi/midi_port_info.cc',
'midi/midi_port_info.h',
'mp3/mp3_stream_parser.cc',
'mp3/mp3_stream_parser.h',
'video/capture/android/video_capture_device_android.cc',
'video/capture/android/video_capture_device_android.h',
'video/capture/fake_video_capture_device.cc',
Expand Down
Loading

0 comments on commit d536809

Please sign in to comment.