summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/media/media_canplaytype_browsertest.cc140
-rw-r--r--media/BUILD.gn6
-rw-r--r--media/base/android/demuxer_stream_player_params.cc2
-rw-r--r--media/base/audio_decoder_config.cc4
-rw-r--r--media/base/audio_decoder_config.h5
-rw-r--r--media/base/mime_util.cc33
-rw-r--r--media/ffmpeg/ffmpeg_common.cc66
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc33
-rw-r--r--media/filters/stream_parser_factory.cc49
-rw-r--r--media/formats/mp4/es_descriptor.h6
-rw-r--r--media/formats/mp4/fourccs.h6
-rw-r--r--media/formats/mp4/mp4_stream_parser.cc44
-rw-r--r--media/formats/mp4/mp4_stream_parser_unittest.cc23
-rw-r--r--media/media.gyp7
-rw-r--r--media/media_options.gni8
-rw-r--r--media/mojo/interfaces/media_types.mojom5
-rw-r--r--media/mojo/services/media_type_converters.cc2
-rw-r--r--media/test/data/README11
-rw-r--r--media/test/data/bear-ac3-only-frag.mp4bin0 -> 26082 bytes
-rw-r--r--media/test/data/bear-eac3-only-frag.mp4bin0 -> 27117 bytes
-rw-r--r--tools/metrics/histograms/histograms.xml3
21 files changed, 413 insertions, 40 deletions
diff --git a/content/browser/media/media_canplaytype_browsertest.cc b/content/browser/media/media_canplaytype_browsertest.cc
index 58c4b6d..5b99d6f 100644
--- a/content/browser/media/media_canplaytype_browsertest.cc
+++ b/content/browser/media/media_canplaytype_browsertest.cc
@@ -56,6 +56,19 @@ const char* kMp2tsMaybe = kNot;
const char* kMp2tsProbably = kNot;
#endif
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+const char* kAc3Eac3Probably = kPropProbably;
+#else
+const char* kAc3Eac3Probably = kNot;
+#endif
+
+#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) && \
+ BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+const char* kMp2tsAc3Eac3Probably = kPropProbably;
+#else
+const char* kMp2tsAc3Eac3Probably = kNot;
+#endif
+
namespace content {
class MediaCanPlayTypeTest : public MediaBrowserTest {
@@ -220,6 +233,23 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"avc3x\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4ax\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac-\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec-\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac-2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec-2\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac-4\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec-4\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a4\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a7\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a5.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a6.\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a5.1\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a6.1\"'"));
+
EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"unknown\"'"));
// Don't allow incomplete/ambiguous codec ids for HEVC.
@@ -300,6 +330,13 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, mp4a.40.2\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, mp4a.40.02\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.A6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a6\"'"));
+
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"1\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"theora, 1\"'"));
@@ -349,6 +386,13 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp8.0, mp4a.40\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"vp9.0, mp4a.40\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.A6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a6\"'"));
+
// Codecs are case sensitive.
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"VP8, Vorbis\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"VP8.0, Opus\"'"));
@@ -388,6 +432,13 @@ class MediaCanPlayTypeTest : public MediaBrowserTest {
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.2\"'"));
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"mp4a.40.02\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.A6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'" + mime + "; codecs=\"mp4a.a6\"'"));
+
// Unknown codec.
EXPECT_EQ(kNot, CanPlay("'" + mime +"; codecs=\"unknown\"'"));
}
@@ -596,6 +647,31 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kPropProbably,
CanPlay("'video/mp4; codecs=\"avc3.42E01E, mp4a.40.29\"'"));
+ // AC3 and EAC3 (aka Dolby Digital Plus, DD+) audio codecs.
+ // TODO(servolk): Strictly speaking only mp4a.A5 and mp4a.A6 codec ids are
+ // valid according to RFC 6381 section 3.3, 3.4. Lower-case oti (mp4a.a5 and
+ // mp4a.a6) should be rejected. But we used to allow those in older versions
+ // of Chromecast firmware and some apps (notably MPL) depend on those codec
+ // types being supported, so they should be allowed for now (crbug.com/564960)
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/mp4; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/mp4; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/mp4; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/mp4; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/mp4; codecs=\"mp4a.a6\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/mp4; codecs=\"mp4a.A6\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/mp4; codecs=\"avc1.640028,ac-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/mp4; codecs=\"avc1.640028,mp4a.a5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/mp4; codecs=\"avc1.640028,mp4a.A5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/mp4; codecs=\"avc1.640028,ec-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/mp4; codecs=\"avc1.640028,mp4a.a6\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/mp4; codecs=\"avc1.640028,mp4a.A6\"'"));
+
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, mp4a.40.2\"'"));
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc1, mp4a.40.02\"'"));
EXPECT_EQ(kPropMaybe, CanPlay("'video/mp4; codecs=\"avc3, mp4a.40.2\"'"));
@@ -670,6 +746,25 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kHevcSupported,
CanPlay("'video/x-m4v; codecs=\"hvc1.1.6.L93.B0, mp4a.40.5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"mp4a.a6\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'video/x-m4v; codecs=\"mp4a.A6\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/x-m4v; codecs=\"avc1.640028,ac-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.a5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.A5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/x-m4v; codecs=\"avc1.640028,ec-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.a6\"'"));
+ EXPECT_EQ(kAc3Eac3Probably,
+ CanPlay("'video/x-m4v; codecs=\"avc1.640028,mp4a.A6\"'"));
+
TestMPEGUnacceptableCombinations("video/x-m4v");
EXPECT_EQ(kPropMaybe, CanPlay("'audio/mp4'"));
@@ -694,6 +789,13 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"hev1.1.6.L93.B0,mp4a.40.5\"'"));
EXPECT_EQ(kNot, CanPlay("'audio/mp4; codecs=\"hvc1.1.6.L93.B0,mp4a.40.5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/mp4; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/mp4; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/mp4; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/mp4; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/mp4; codecs=\"mp4a.a6\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/mp4; codecs=\"mp4a.A6\"'"));
+
TestMPEGUnacceptableCombinations("audio/mp4");
EXPECT_EQ(kPropMaybe, CanPlay("'audio/x-m4a'"));
@@ -720,6 +822,13 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_mp4) {
EXPECT_EQ(kNot,
CanPlay("'audio/x-m4a; codecs=\"hvc1.1.6.L93.B0, mp4a.40.5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"mp4a.a6\"'"));
+ EXPECT_EQ(kAc3Eac3Probably, CanPlay("'audio/x-m4a; codecs=\"mp4a.A6\"'"));
+
TestMPEGUnacceptableCombinations("audio/x-m4a");
}
@@ -1106,6 +1215,13 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_HLS) {
EXPECT_EQ(kNot,
CanPlay("'application/x-mpegurl; codecs=\"hvc1.1.6.L93.B0,mp4a.40.5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"mp4a.A6\"'"));
+ EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'application/x-mpegurl; codecs=\"mp4a.a6\"'"));
+
EXPECT_EQ(maybeCanPlayHLS,
CanPlay("'application/x-mpegurl; codecs=\"avc1, mp4a.40.2\"'"));
EXPECT_EQ(maybeCanPlayHLS,
@@ -1189,6 +1305,17 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_HLS) {
CanPlay("'application/vnd.apple.mpegurl; "
"codecs=\"hvc1.1.6.L93.B0,mp4a.40.5\"'"));
+ EXPECT_EQ(kNot, CanPlay("'application/vnd.apple.mpegurl; codecs=\"ac-3\"'"));
+ EXPECT_EQ(kNot, CanPlay("'application/vnd.apple.mpegurl; codecs=\"ec-3\"'"));
+ EXPECT_EQ(kNot,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.A5\"'"));
+ EXPECT_EQ(kNot,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.A6\"'"));
+ EXPECT_EQ(kNot,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.a5\"'"));
+ EXPECT_EQ(kNot,
+ CanPlay("'application/vnd.apple.mpegurl; codecs=\"mp4a.a6\"'"));
+
TestMPEGUnacceptableCombinations("application/vnd.apple.mpegurl");
}
@@ -1218,6 +1345,19 @@ IN_PROC_BROWSER_TEST_F(MediaCanPlayTypeTest, CodecSupportTest_Mpeg2Ts) {
CanPlay("'video/mp2t; codecs=\"avc1.4D401E,mp4a.40.2\"'"));
EXPECT_EQ(kMp2tsProbably,
CanPlay("'video/mp2t; codecs=\"avc1.640028,mp4a.40.2\"'"));
+ // H.264 + AC3/EAC3 audio combinations
+ EXPECT_EQ(kMp2tsAc3Eac3Probably,
+ CanPlay("'video/mp2t; codecs=\"avc1.640028,ac-3\"'"));
+ EXPECT_EQ(kMp2tsAc3Eac3Probably,
+ CanPlay("'video/mp2t; codecs=\"avc1.640028,ec-3\"'"));
+ EXPECT_EQ(kMp2tsAc3Eac3Probably,
+ CanPlay("'video/mp2t; codecs=\"avc1.640028,mp4a.A5\"'"));
+ EXPECT_EQ(kMp2tsAc3Eac3Probably,
+ CanPlay("'video/mp2t; codecs=\"avc1.640028,mp4a.A6\"'"));
+ EXPECT_EQ(kMp2tsAc3Eac3Probably,
+ CanPlay("'video/mp2t; codecs=\"avc1.640028,mp4a.a5\"'"));
+ EXPECT_EQ(kMp2tsAc3Eac3Probably,
+ CanPlay("'video/mp2t; codecs=\"avc1.640028,mp4a.a6\"'"));
TestMPEGUnacceptableCombinations("video/mp2t");
}
diff --git a/media/BUILD.gn b/media/BUILD.gn
index 7d03d4d..b356a33 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -14,8 +14,10 @@ import("//testing/test.gni")
buildflag_header("media_features") {
header = "media_features.h"
- flags =
- [ "ENABLE_MSE_MPEG2TS_STREAM_PARSER=$enable_mse_mpeg2ts_stream_parser" ]
+ flags = [
+ "ENABLE_AC3_EAC3_AUDIO_DEMUXING=$enable_ac3_eac3_audio_demuxing",
+ "ENABLE_MSE_MPEG2TS_STREAM_PARSER=$enable_mse_mpeg2ts_stream_parser",
+ ]
}
# Common configuration for targets in the media directory.
diff --git a/media/base/android/demuxer_stream_player_params.cc b/media/base/android/demuxer_stream_player_params.cc
index 2452711..3ce2a76 100644
--- a/media/base/android/demuxer_stream_player_params.cc
+++ b/media/base/android/demuxer_stream_player_params.cc
@@ -66,8 +66,10 @@ const char* AsString(AudioCodec codec) {
RETURN_STRING(kCodecPCM_S16BE);
RETURN_STRING(kCodecPCM_S24BE);
RETURN_STRING(kCodecOpus);
+ RETURN_STRING(kCodecEAC3);
RETURN_STRING(kCodecPCM_ALAW);
RETURN_STRING(kCodecALAC);
+ RETURN_STRING(kCodecAC3);
}
NOTREACHED();
return nullptr; // crash early
diff --git a/media/base/audio_decoder_config.cc b/media/base/audio_decoder_config.cc
index 17f039f..91dc9a6 100644
--- a/media/base/audio_decoder_config.cc
+++ b/media/base/audio_decoder_config.cc
@@ -122,8 +122,12 @@ std::string AudioDecoderConfig::GetHumanReadableCodecName() const {
return "opus";
case kCodecPCM_ALAW:
return "pcm_alaw";
+ case kCodecEAC3:
+ return "eac3";
case kCodecALAC:
return "alac";
+ case kCodecAC3:
+ return "ac3";
}
NOTREACHED();
return "";
diff --git a/media/base/audio_decoder_config.h b/media/base/audio_decoder_config.h
index e88c0eb..7205e56 100644
--- a/media/base/audio_decoder_config.h
+++ b/media/base/audio_decoder_config.h
@@ -36,16 +36,17 @@ enum AudioCodec {
kCodecPCM_S16BE = 10,
kCodecPCM_S24BE = 11,
kCodecOpus = 12,
- // kCodecEAC3 = 13,
+ kCodecEAC3 = 13,
kCodecPCM_ALAW = 14,
kCodecALAC = 15,
+ kCodecAC3 = 16,
// DO NOT ADD RANDOM AUDIO CODECS!
//
// The only acceptable time to add a new codec is if there is production code
// that uses said codec in the same CL.
// Must always be equal to the largest entry ever logged.
- kAudioCodecMax = kCodecALAC,
+ kAudioCodecMax = kCodecAC3,
};
// TODO(dalecurtis): FFmpeg API uses |bytes_per_channel| instead of
diff --git a/media/base/mime_util.cc b/media/base/mime_util.cc
index 01422b2..9abd15a 100644
--- a/media/base/mime_util.cc
+++ b/media/base/mime_util.cc
@@ -30,6 +30,8 @@ class MimeUtil {
INVALID_CODEC,
PCM,
MP3,
+ AC3,
+ EAC3,
MPEG2_AAC_LC,
MPEG2_AAC_MAIN,
MPEG2_AAC_SSR,
@@ -152,6 +154,11 @@ static bool IsCodecSupportedOnAndroid(MimeUtil::Codec codec) {
case MimeUtil::VP8:
return true;
+ case MimeUtil::AC3:
+ case MimeUtil::EAC3:
+ // TODO(servolk): Revisit this for AC3/EAC3 support on AndroidTV
+ return false;
+
case MimeUtil::MPEG2_AAC_LC:
case MimeUtil::MPEG2_AAC_MAIN:
case MimeUtil::MPEG2_AAC_SSR:
@@ -210,6 +217,11 @@ struct MediaFormat {
// avc1.6400xx - H.264 High
static const char kMP4AudioCodecsExpression[] =
"mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5,"
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ // Only one variant each of ac3 and eac3 codec string is sufficient here,
+ // since these strings are parsed and mapped to MimeUtil::Codec enum values.
+ "ac-3,ec-3,"
+#endif
"mp4a.40.05,mp4a.40.29";
static const char kMP4VideoCodecsExpression[] =
// This is not a complete list of supported avc1 codecs. It is simply used
@@ -225,6 +237,11 @@ static const char kMP4VideoCodecsExpression[] =
"hev1.1.6.L93.B0,"
#endif
"mp4a.66,mp4a.67,mp4a.68,mp4a.69,mp4a.6B,mp4a.40.2,mp4a.40.02,mp4a.40.5,"
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ // Only one variant each of ac3 and eac3 codec string is sufficient here,
+ // since these strings are parsed and mapped to MimeUtil::Codec enum values.
+ "ac-3,ec-3,"
+#endif
"mp4a.40.05,mp4a.40.29";
#endif // USE_PROPRIETARY_CODECS
@@ -291,6 +308,20 @@ static const CodecIDMappings kUnambiguousCodecStringMap[] = {
{"mp4a.40.5", MimeUtil::MPEG4_AAC_SBR_v1},
{"mp4a.40.05", MimeUtil::MPEG4_AAC_SBR_v1},
{"mp4a.40.29", MimeUtil::MPEG4_AAC_SBR_PS_v2},
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ // TODO(servolk): Strictly speaking only mp4a.A5 and mp4a.A6 codec ids are
+ // valid according to RFC 6381 section 3.3, 3.4. Lower-case oti (mp4a.a5 and
+ // mp4a.a6) should be rejected. But we used to allow those in older versions
+ // of Chromecast firmware and some apps (notably MPL) depend on those codec
+ // types being supported, so they should be allowed for now
+ // (crbug.com/564960).
+ {"ac-3", MimeUtil::AC3},
+ {"mp4a.a5", MimeUtil::AC3},
+ {"mp4a.A5", MimeUtil::AC3},
+ {"ec-3", MimeUtil::EAC3},
+ {"mp4a.a6", MimeUtil::EAC3},
+ {"mp4a.A6", MimeUtil::EAC3},
+#endif
{"vorbis", MimeUtil::VORBIS},
{"opus", MimeUtil::OPUS},
{"vp8", MimeUtil::VP8},
@@ -638,6 +669,8 @@ bool MimeUtil::IsCodecSupported(Codec codec) const {
bool MimeUtil::IsCodecProprietary(Codec codec) const {
switch (codec) {
case INVALID_CODEC:
+ case AC3:
+ case EAC3:
case MP3:
case MPEG2_AAC_LC:
case MPEG2_AAC_MAIN:
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 3d3a8b8..b65cedd 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -14,6 +14,7 @@
#include "media/base/decoder_buffer.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_util.h"
+#include "media/media_features.h"
namespace media {
@@ -67,6 +68,12 @@ static AudioCodec CodecIDToAudioCodec(AVCodecID codec_id) {
switch (codec_id) {
case AV_CODEC_ID_AAC:
return kCodecAAC;
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ case AV_CODEC_ID_AC3:
+ return kCodecAC3;
+ case AV_CODEC_ID_EAC3:
+ return kCodecEAC3;
+#endif
case AV_CODEC_ID_MP3:
return kCodecMP3;
case AV_CODEC_ID_VORBIS:
@@ -309,18 +316,37 @@ bool AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context,
codec_context->channel_layout, codec_context->channels);
int sample_rate = codec_context->sample_rate;
- if (codec == kCodecOpus) {
- // |codec_context->sample_fmt| is not set by FFmpeg because Opus decoding is
- // not enabled in FFmpeg. It doesn't matter what value is set here, so long
- // as it's valid, the true sample format is selected inside the decoder.
- sample_format = kSampleFormatF32;
-
- // Always use 48kHz for OPUS. Technically we should match to the highest
- // supported hardware sample rate among [8, 12, 16, 24, 48] kHz, but we
- // don't know the hardware sample rate at this point and those rates are
- // rarely used for output. See the "Input Sample Rate" section of the spec:
- // http://tools.ietf.org/html/draft-terriberry-oggopus-01#page-11
- sample_rate = 48000;
+ switch (codec) {
+ case kCodecOpus:
+ // |codec_context->sample_fmt| is not set by FFmpeg because Opus decoding
+ // is not enabled in FFmpeg. It doesn't matter what value is set here, so
+ // long as it's valid, the true sample format is selected inside the
+ // decoder.
+ sample_format = kSampleFormatF32;
+
+ // Always use 48kHz for OPUS. Technically we should match to the highest
+ // supported hardware sample rate among [8, 12, 16, 24, 48] kHz, but we
+ // don't know the hardware sample rate at this point and those rates are
+ // rarely used for output. See the "Input Sample Rate" section of the
+ // spec: http://tools.ietf.org/html/draft-terriberry-oggopus-01#page-11
+ sample_rate = 48000;
+ break;
+
+ // For AC3/EAC3 we enable only demuxing, but not decoding, so FFmpeg does
+ // not fill |sample_fmt|.
+ case kCodecAC3:
+ case kCodecEAC3:
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ // The spec for AC3/EAC3 audio is ETSI TS 102 366. According to sections
+ // F.3.1 and F.5.1 in that spec the sample_format for AC3/EAC3 must be 16.
+ sample_format = kSampleFormatS16;
+#else
+ NOTREACHED();
+#endif
+ break;
+
+ default:
+ break;
}
base::TimeDelta seek_preroll;
@@ -353,9 +379,19 @@ bool AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context,
seek_preroll,
codec_context->delay);
- if (codec != kCodecOpus) {
- DCHECK_EQ(av_get_bytes_per_sample(codec_context->sample_fmt) * 8,
- config->bits_per_channel());
+ // Verify that AudioConfig.bits_per_channel was calculated correctly for
+ // codecs that have |sample_fmt| set by FFmpeg.
+ switch (codec) {
+ case kCodecOpus:
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ case kCodecAC3:
+ case kCodecEAC3:
+#endif
+ break;
+ default:
+ DCHECK_EQ(av_get_bytes_per_sample(codec_context->sample_fmt) * 8,
+ config->bits_per_channel());
+ break;
}
return true;
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index 1869b7a..2d1a868 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -24,6 +24,7 @@
#include "media/filters/ffmpeg_demuxer.h"
#include "media/filters/file_data_source.h"
#include "media/formats/mp4/avc.h"
+#include "media/media_features.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::AnyNumber;
@@ -1132,4 +1133,36 @@ TEST_F(FFmpegDemuxerTest, HEVC_in_MP4_container) {
}
#endif
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+TEST_F(FFmpegDemuxerTest, Read_AC3_Audio) {
+ CreateDemuxer("bear-ac3-only-frag.mp4");
+ InitializeDemuxer();
+
+ // Attempt a read from the audio stream and run the message loop until done.
+ DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
+
+ // Read the first two frames and check that we are getting expected data
+ audio->Read(NewReadCB(FROM_HERE, 834, 0, true));
+ message_loop_.Run();
+
+ audio->Read(NewReadCB(FROM_HERE, 836, 34830, true));
+ message_loop_.Run();
+}
+
+TEST_F(FFmpegDemuxerTest, Read_EAC3_Audio) {
+ CreateDemuxer("bear-eac3-only-frag.mp4");
+ InitializeDemuxer();
+
+ // Attempt a read from the audio stream and run the message loop until done.
+ DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
+
+ // Read the first two frames and check that we are getting expected data
+ audio->Read(NewReadCB(FROM_HERE, 870, 0, true));
+ message_loop_.Run();
+
+ audio->Read(NewReadCB(FROM_HERE, 872, 34830, true));
+ message_loop_.Run();
+}
+#endif // ENABLE_AC3_EAC3_AUDIO_DEMUXING
+
} // namespace media
diff --git a/media/filters/stream_parser_factory.cc b/media/filters/stream_parser_factory.cc
index db626c5..43e0079 100644
--- a/media/filters/stream_parser_factory.cc
+++ b/media/filters/stream_parser_factory.cc
@@ -58,7 +58,8 @@ struct CodecInfo {
HISTOGRAM_MP3,
HISTOGRAM_OPUS,
HISTOGRAM_HEVC,
- HISTOGRAM_MAX = HISTOGRAM_HEVC // Must be equal to largest logged entry.
+ HISTOGRAM_AC3,
+ HISTOGRAM_MAX = HISTOGRAM_AC3 // Must be equal to largest logged entry.
};
const char* pattern;
@@ -166,6 +167,26 @@ static const CodecInfo kMPEG4AACCodecInfo = { "mp4a.40.*", CodecInfo::AUDIO,
static const CodecInfo kMPEG2AACLCCodecInfo = { "mp4a.67", CodecInfo::AUDIO,
NULL,
CodecInfo::HISTOGRAM_MPEG2AAC };
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+// The 'ac-3' and 'ec-3' are mime codec ids for AC3 and EAC3 according to
+// http://www.mp4ra.org/codecs.html
+// The object types for AC3 and EAC3 in MP4 container are 0xa5 and 0xa6, so
+// according to RFC 6381 this corresponds to codec ids 'mp4a.A5' and 'mp4a.A6'.
+// Codec ids with lower case oti (mp4a.a5 and mp4a.a6) are supported for
+// backward compatibility.
+static const CodecInfo kAC3CodecInfo1 = {"ac-3", CodecInfo::AUDIO, NULL,
+ CodecInfo::HISTOGRAM_AC3};
+static const CodecInfo kAC3CodecInfo2 = {"mp4a.a5", CodecInfo::AUDIO, NULL,
+ CodecInfo::HISTOGRAM_AC3};
+static const CodecInfo kAC3CodecInfo3 = {"mp4a.A5", CodecInfo::AUDIO, NULL,
+ CodecInfo::HISTOGRAM_AC3};
+static const CodecInfo kEAC3CodecInfo1 = {"ec-3", CodecInfo::AUDIO, NULL,
+ CodecInfo::HISTOGRAM_EAC3};
+static const CodecInfo kEAC3CodecInfo2 = {"mp4a.a6", CodecInfo::AUDIO, NULL,
+ CodecInfo::HISTOGRAM_EAC3};
+static const CodecInfo kEAC3CodecInfo3 = {"mp4a.A6", CodecInfo::AUDIO, NULL,
+ CodecInfo::HISTOGRAM_EAC3};
+#endif
static const CodecInfo* kVideoMP4Codecs[] = {
&kH264AVC1CodecInfo,
@@ -179,11 +200,17 @@ static const CodecInfo* kVideoMP4Codecs[] = {
NULL
};
-static const CodecInfo* kAudioMP4Codecs[] = {
- &kMPEG4AACCodecInfo,
- &kMPEG2AACLCCodecInfo,
- NULL
-};
+static const CodecInfo* kAudioMP4Codecs[] = {&kMPEG4AACCodecInfo,
+ &kMPEG2AACLCCodecInfo,
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ &kAC3CodecInfo1,
+ &kAC3CodecInfo2,
+ &kAC3CodecInfo3,
+ &kEAC3CodecInfo1,
+ &kEAC3CodecInfo2,
+ &kEAC3CodecInfo3,
+#endif
+ NULL};
static StreamParser* BuildMP4Parser(const std::vector<std::string>& codecs,
const scoped_refptr<MediaLog>& media_log) {
@@ -205,6 +232,16 @@ static StreamParser* BuildMP4Parser(const std::vector<std::string>& codecs,
has_sbr = true;
break;
}
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ } else if (base::MatchPattern(codec_id, kAC3CodecInfo1.pattern) ||
+ base::MatchPattern(codec_id, kAC3CodecInfo2.pattern) ||
+ base::MatchPattern(codec_id, kAC3CodecInfo3.pattern)) {
+ audio_object_types.insert(mp4::kAC3);
+ } else if (base::MatchPattern(codec_id, kEAC3CodecInfo1.pattern) ||
+ base::MatchPattern(codec_id, kEAC3CodecInfo2.pattern) ||
+ base::MatchPattern(codec_id, kEAC3CodecInfo3.pattern)) {
+ audio_object_types.insert(mp4::kEAC3);
+#endif
}
}
diff --git a/media/formats/mp4/es_descriptor.h b/media/formats/mp4/es_descriptor.h
index 26ca86d..9066291 100644
--- a/media/formats/mp4/es_descriptor.h
+++ b/media/formats/mp4/es_descriptor.h
@@ -21,8 +21,10 @@ namespace mp4 {
// objectTypeIndication Values. Only values currently in use are included.
enum ObjectType {
kForbidden = 0,
- kISO_14496_3 = 0x40, // MPEG4 AAC
- kISO_13818_7_AAC_LC = 0x67 // MPEG2 AAC-LC
+ kISO_14496_3 = 0x40, // MPEG4 AAC
+ kISO_13818_7_AAC_LC = 0x67, // MPEG2 AAC-LC
+ kAC3 = 0xa5, // AC3
+ kEAC3 = 0xa6 // EAC3 / Dolby Digital Plus
};
// This class parse object type and decoder specific information from an
diff --git a/media/formats/mp4/fourccs.h b/media/formats/mp4/fourccs.h
index fd97797..38834fb 100644
--- a/media/formats/mp4/fourccs.h
+++ b/media/formats/mp4/fourccs.h
@@ -7,11 +7,17 @@
#include <string>
+#include "media/media_features.h"
+
namespace media {
namespace mp4 {
enum FourCC {
FOURCC_NULL = 0,
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ FOURCC_AC3 = 0x61632d33, // "ac-3"
+ FOURCC_EAC3 = 0x65632d33, // "ec-3"
+#endif
FOURCC_AVC1 = 0x61766331,
FOURCC_AVC3 = 0x61766333,
FOURCC_AVCC = 0x61766343,
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index ee88ea1..966d250 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -220,9 +220,18 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx];
const AAC& aac = entry.esds.aac;
- if (!(entry.format == FOURCC_MP4A ||
- (entry.format == FOURCC_ENCA &&
- entry.sinf.format.format == FOURCC_MP4A))) {
+ // For encrypted audio streams entry.format is FOURCC_ENCA and actual
+ // format is in entry.sinf.format.format.
+ FourCC audio_format = (entry.format == FOURCC_ENCA)
+ ? entry.sinf.format.format
+ : entry.format;
+
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ if (audio_format != FOURCC_MP4A && audio_format != FOURCC_AC3 &&
+ audio_format != FOURCC_EAC3) {
+#else
+ if (audio_format != FOURCC_MP4A) {
+#endif
MEDIA_LOG(ERROR, media_log_) << "Unsupported audio format 0x"
<< std::hex << entry.format
<< " in stsd box.";
@@ -230,12 +239,20 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
}
uint8_t audio_type = entry.esds.object_type;
- DVLOG(1) << "audio_type " << std::hex << static_cast<int>(audio_type);
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ if (audio_type == kForbidden) {
+ if (audio_format == FOURCC_AC3)
+ audio_type = kAC3;
+ if (audio_format == FOURCC_EAC3)
+ audio_type = kEAC3;
+ }
+#endif
+ DVLOG(1) << "audio_type 0x" << std::hex << static_cast<int>(audio_type);
if (audio_object_types_.find(audio_type) == audio_object_types_.end()) {
MEDIA_LOG(ERROR, media_log_)
- << "audio object type 0x" << std::hex << audio_type
- << " does not match what is specified in the"
- << " mimetype.";
+ << "audio object type 0x" << std::hex
+ << static_cast<int>(audio_type)
+ << " does not match what is specified in the mimetype.";
return false;
}
@@ -252,9 +269,20 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
#if defined(OS_ANDROID)
extra_data = aac.codec_specific_data();
#endif
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+ } else if (audio_type == kAC3) {
+ codec = kCodecAC3;
+ channel_layout = GuessChannelLayout(entry.channelcount);
+ sample_per_second = entry.samplerate;
+ } else if (audio_type == kEAC3) {
+ codec = kCodecEAC3;
+ channel_layout = GuessChannelLayout(entry.channelcount);
+ sample_per_second = entry.samplerate;
+#endif
} else {
MEDIA_LOG(ERROR, media_log_) << "Unsupported audio object type 0x"
- << std::hex << audio_type << " in esds.";
+ << std::hex << static_cast<int>(audio_type)
+ << " in esds.";
return false;
}
diff --git a/media/formats/mp4/mp4_stream_parser_unittest.cc b/media/formats/mp4/mp4_stream_parser_unittest.cc
index 79f68c1..eec9824 100644
--- a/media/formats/mp4/mp4_stream_parser_unittest.cc
+++ b/media/formats/mp4/mp4_stream_parser_unittest.cc
@@ -22,6 +22,7 @@
#include "media/base/video_decoder_config.h"
#include "media/formats/mp4/es_descriptor.h"
#include "media/formats/mp4/mp4_stream_parser.h"
+#include "media/media_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -341,5 +342,27 @@ TEST_F(MP4StreamParserTest, NaturalSizeWithPASP) {
EXPECT_EQ(gfx::Size(639, 360), video_decoder_config_.natural_size());
}
+#if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
+TEST_F(MP4StreamParserTest, DemuxingAC3) {
+ std::set<int> audio_object_types;
+ audio_object_types.insert(kAC3);
+ parser_.reset(new MP4StreamParser(audio_object_types, false));
+ InitializeParserAndExpectLiveness(DemuxerStream::LIVENESS_RECORDED);
+ scoped_refptr<DecoderBuffer> buffer =
+ ReadTestDataFile("bear-ac3-only-frag.mp4");
+ EXPECT_TRUE(AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
+}
+
+TEST_F(MP4StreamParserTest, DemuxingEAC3) {
+ std::set<int> audio_object_types;
+ audio_object_types.insert(kEAC3);
+ parser_.reset(new MP4StreamParser(audio_object_types, false));
+ InitializeParserAndExpectLiveness(DemuxerStream::LIVENESS_RECORDED);
+ scoped_refptr<DecoderBuffer> buffer =
+ ReadTestDataFile("bear-eac3-only-frag.mp4");
+ EXPECT_TRUE(AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
+}
+#endif
+
} // namespace mp4
} // namespace media
diff --git a/media/media.gyp b/media/media.gyp
index 620a77a..b8d7b9e 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -33,9 +33,13 @@
}, {
'use_low_memory_buffer%': 0,
}],
- ['chromecast == 1', {
+ ['proprietary_codecs==1 and chromecast==1', {
+ # Enable AC3/EAC3 audio demuxing. Actual decoding must be provided by
+ # the platform (or HDMI sink in Chromecast for audio pass-through case).
+ 'enable_ac3_eac3_audio_demuxing%': 1,
'enable_mse_mpeg2ts_stream_parser%': 1,
}, {
+ 'enable_ac3_eac3_audio_demuxing%': 0,
'enable_mse_mpeg2ts_stream_parser%': 0,
}],
['chromecast==1', {
@@ -59,6 +63,7 @@
'variables': {
'buildflag_header_path': 'media/media_features.h',
'buildflag_flags': [
+ "ENABLE_AC3_EAC3_AUDIO_DEMUXING=<(enable_ac3_eac3_audio_demuxing)",
"ENABLE_MSE_MPEG2TS_STREAM_PARSER=<(enable_mse_mpeg2ts_stream_parser)",
],
},
diff --git a/media/media_options.gni b/media/media_options.gni
index fa01d0f..635c4d2 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import("//build/config/chromecast_build.gni")
+import("//build/config/features.gni")
import("//build/config/headless_build.gni")
declare_args() {
@@ -48,7 +49,12 @@ declare_args() {
# Use low-memory buffers on non-Android builds of Chromecast.
use_low_memory_buffer = is_chromecast && !is_android
- enable_mse_mpeg2ts_stream_parser = is_chromecast
+ # Enables AC3/EAC3 audio demuxing. This is enabled only on Chromecast, since
+ # it only provides demuxing, and is only useful for AC3/EAC3 audio
+ # pass-through to HDMI sink on Chromecast.
+ enable_ac3_eac3_audio_demuxing = proprietary_codecs && is_chromecast
+
+ enable_mse_mpeg2ts_stream_parser = proprietary_codecs && is_chromecast
# Enable HEVC/H265 demuxing. Actual decoding must be provided by the
# platform. Enable by default for Chromecast.
diff --git a/media/mojo/interfaces/media_types.mojom b/media/mojo/interfaces/media_types.mojom
index befd80a..3890b2a 100644
--- a/media/mojo/interfaces/media_types.mojom
+++ b/media/mojo/interfaces/media_types.mojom
@@ -29,10 +29,11 @@ enum AudioCodec {
PCM_S16BE = 10,
PCM_S24BE = 11,
Opus = 12,
- // EAC3 = 13,
+ EAC3 = 13,
PCM_ALAW = 14,
ALAC = 15,
- MAX = ALAC,
+ AC3 = 16,
+ MAX = AC3,
};
// See media/base/channel_layout.h for descriptions.
diff --git a/media/mojo/services/media_type_converters.cc b/media/mojo/services/media_type_converters.cc
index d3cc1e3..679accf 100644
--- a/media/mojo/services/media_type_converters.cc
+++ b/media/mojo/services/media_type_converters.cc
@@ -54,8 +54,10 @@ ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, GSM_MS);
ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, PCM_S16BE);
ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, PCM_S24BE);
ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, Opus);
+ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, EAC3);
ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, PCM_ALAW);
ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, ALAC);
+ASSERT_ENUM_EQ(AudioCodec, kCodec, AUDIO_CODEC_, AC3);
ASSERT_ENUM_EQ_RAW(AudioCodec, kAudioCodecMax, AUDIO_CODEC_MAX);
// ChannelLayout.
diff --git a/media/test/data/README b/media/test/data/README
index 773ff84..8ab8273 100644
--- a/media/test/data/README
+++ b/media/test/data/README
@@ -196,4 +196,13 @@ media/test/data/bear-640x360-non_square_pixel-with_pasp.mp4
media/test/data/bear-640x360-non_square_pixel-without_pasp.mp4
Size in TKHD is (639.2x360) and size in STSD is (470x360). No PASP box is
- present. \ No newline at end of file
+ present.
+
+// MP4 files with AC3 and EAC3 audio
+media/test/data/bear-ac3-only-frag.mp4
+ AC3 audio in framented MP4, generated with
+ ffmpeg -i bear.ac3 -acodec copy -movflags frag_keyframe bear-ac3-only-frag.mp4
+
+media/test/data/bear-eac3-only-frag.mp4
+ EAC3 audio in framented MP4, generated with
+ ffmpeg -i bear.eac3 -acodec copy -movflags frag_keyframe bear-eac3-only-frag.mp4
diff --git a/media/test/data/bear-ac3-only-frag.mp4 b/media/test/data/bear-ac3-only-frag.mp4
new file mode 100644
index 0000000..669c407
--- /dev/null
+++ b/media/test/data/bear-ac3-only-frag.mp4
Binary files differ
diff --git a/media/test/data/bear-eac3-only-frag.mp4 b/media/test/data/bear-eac3-only-frag.mp4
new file mode 100644
index 0000000..1530fd1
--- /dev/null
+++ b/media/test/data/bear-eac3-only-frag.mp4
Binary files differ
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 26ec39a..d19089e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -56612,8 +56612,10 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
<int value="10" label="kCodecPCM_S16BE"/>
<int value="11" label="kCodecPCM_S24BE"/>
<int value="12" label="kCodecOpus"/>
+ <int value="13" label="kCodecEAC3"/>
<int value="14" label="kCodecPCM_ALAW"/>
<int value="15" label="kCodecALAC"/>
+ <int value="16" label="kCodecAC3"/>
</enum>
<enum name="AudioFramesPerBuffer" type="int">
@@ -70926,6 +70928,7 @@ To add a new entry, add it with any value and run test to compute valid value.
<int value="8" label="MP3"/>
<int value="9" label="OPUS"/>
<int value="10" label="HEVC"/>
+ <int value="11" label="AC3"/>
</enum>
<enum name="MultiProfileSessionMode" type="int">