Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(901)

Unified Diff: media/base/mime_util_internal.cc

Issue 2700893003: Various MimeUtil cleanups. (Closed)
Patch Set: Feedback Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/base/mime_util_internal.h ('k') | media/base/mime_util_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/base/mime_util_internal.cc
diff --git a/media/base/mime_util_internal.cc b/media/base/mime_util_internal.cc
index 7370198ec2419a0dd84f40d87a8139d0bfad2b40..2172a63ca365f04a8c3d43710779172b596868fb 100644
--- a/media/base/mime_util_internal.cc
+++ b/media/base/mime_util_internal.cc
@@ -4,6 +4,8 @@
#include "media/base/mime_util_internal.h"
+#include <map>
+
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -23,17 +25,11 @@
namespace media {
namespace internal {
-struct CodecIDMappings {
- const char* const codec_id;
- MimeUtil::Codec codec;
-};
-
-// List of codec IDs that provide enough information to determine the
-// codec and profile being requested.
-//
-// The "mp4a" strings come from RFC 6381.
-static const CodecIDMappings kUnambiguousCodecStringMap[] = {
- {"1", MimeUtil::PCM}, // We only allow this for WAV so it isn't ambiguous.
+// Wrapped to avoid static initializer startup cost.
+const std::map<std::string, MimeUtil::Codec>& GetStringToCodecMap() {
+ static const std::map<std::string, MimeUtil::Codec> kStringToCodecMap = {
+ // We only allow this for WAV so it isn't ambiguous.
+ {"1", MimeUtil::PCM},
// avc1/avc3.XXXXXX may be unambiguous; handled by ParseAVCCodecId().
// hev1/hvc1.XXXXXX may be unambiguous; handled by ParseHEVCCodecID().
// vp9, vp9.0, vp09.xx.xx.xx.xx.xx.xx.xx may be unambiguous; handled by
@@ -48,8 +44,8 @@ static const CodecIDMappings kUnambiguousCodecStringMap[] = {
// mp4a.40.2 - MPEG-4 AAC LC
// mp4a.40.02 - MPEG-4 AAC LC (leading 0 in aud-oti for compatibility)
// mp4a.40.5 - MPEG-4 HE-AAC v1 (AAC LC + SBR)
- // mp4a.40.05 - MPEG-4 HE-AAC v1 (AAC LC + SBR) (leading 0 in aud-oti for
- // compatibility)
+ // mp4a.40.05 - MPEG-4 HE-AAC v1 (AAC LC + SBR) (leading 0 in aud-oti
+ // for compatibility)
// mp4a.40.29 - MPEG-4 HE-AAC v2 (AAC LC + SBR + PS)
{"mp4a.66", MimeUtil::MPEG2_AAC},
{"mp4a.67", MimeUtil::MPEG2_AAC},
@@ -63,10 +59,10 @@ static const CodecIDMappings kUnambiguousCodecStringMap[] = {
{"mp4a.40.29", MimeUtil::MPEG4_AAC},
#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
+ // 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},
@@ -80,18 +76,11 @@ static const CodecIDMappings kUnambiguousCodecStringMap[] = {
{"flac", MimeUtil::FLAC},
{"vp8", MimeUtil::VP8},
{"vp8.0", MimeUtil::VP8},
- {"theora", MimeUtil::THEORA}};
-
-// List of codec IDs that are ambiguous and don't provide
-// enough information to determine the codec and profile.
-// The codec in these entries indicate the codec and profile
-// we assume the user is trying to indicate.
-static const CodecIDMappings kAmbiguousCodecStringMap[] = {
- {"mp4a.40", MimeUtil::MPEG4_AAC},
- {"avc1", MimeUtil::H264},
- {"avc3", MimeUtil::H264},
- // avc1/avc3.XXXXXX may be ambiguous; handled by ParseAVCCodecId().
-};
+ {"theora", MimeUtil::THEORA}
+ };
+
+ return kStringToCodecMap;
+}
static bool ParseVp9CodecID(const std::string& mime_type_lower_case,
const std::string& codec_id,
@@ -164,36 +153,56 @@ SupportsType MimeUtil::AreSupportedCodecs(
bool is_encrypted) const {
DCHECK(!supported_codecs.empty());
DCHECK(!codecs.empty());
+ DCHECK_EQ(base::ToLowerASCII(mime_type_lower_case), mime_type_lower_case);
+
+ SupportsType combined_result = IsSupported;
- SupportsType result = IsSupported;
for (size_t i = 0; i < codecs.size(); ++i) {
- bool is_ambiguous = true;
+ // Parse the string.
+ bool ambiguous_codec_string = false;
Codec codec = INVALID_CODEC;
VideoCodecProfile video_profile = VIDEO_CODEC_PROFILE_UNKNOWN;
uint8_t video_level = 0;
- if (!StringToCodec(mime_type_lower_case, codecs[i], &codec, &is_ambiguous,
- &video_profile, &video_level, is_encrypted)) {
+ if (!ParseCodecString(mime_type_lower_case, codecs[i], &codec,
+ &ambiguous_codec_string, &video_profile,
+ &video_level)) {
return IsNotSupported;
}
- VideoCodec video_codec = MimeUtilToVideoCodec(codec);
-
- if (GetMediaClient() && video_codec != kUnknownVideoCodec &&
- !GetMediaClient()->IsSupportedVideoConfig(video_codec, video_profile,
- video_level)) {
+ // Bail if codec not in supported list for given container.
+ if (supported_codecs.find(codec) == supported_codecs.end())
return IsNotSupported;
+
+ // Make conservative guesses to resolve ambiguity before checking platform
+ // support. H264 and VP9 are the only allowed ambiguous video codec. DO NOT
+ // ADD SUPPORT FOR MORE AMIBIGUOUS STRINGS.
+ if (codec == MimeUtil::H264 && ambiguous_codec_string) {
+ if (video_profile == VIDEO_CODEC_PROFILE_UNKNOWN)
+ video_profile = H264PROFILE_BASELINE;
+ if (!IsValidH264Level(video_level))
+ video_level = 10;
+ } else if (codec == MimeUtil::VP9 && video_level == 0) {
+ // Original VP9 content type (codecs="vp9") does not specify the level.
+ // TODO(chcunningham): Mark this string as ambiguous when new multi-part
+ // VP9 content type is published.
+ video_level = 10;
}
- if (!IsCodecSupported(codec, mime_type_lower_case, is_encrypted) ||
- supported_codecs.find(codec) == supported_codecs.end()) {
+ // Check platform support.
+ SupportsType result = IsCodecSupported(
+ mime_type_lower_case, codec, video_profile, video_level, is_encrypted);
+ if (result == IsNotSupported)
return IsNotSupported;
- }
- if (is_ambiguous)
- result = MayBeSupported;
+ // If any codec is "MayBeSupported", return Maybe for the combined result.
+ // Downgrade to MayBeSupported if we had to guess the meaning of one of the
+ // codec strings.
+ if (result == MayBeSupported ||
+ (result == IsSupported && ambiguous_codec_string))
+ combined_result = MayBeSupported;
}
- return result;
+ return combined_result;
}
void MimeUtil::InitializeMimeTypeMaps() {
@@ -201,16 +210,6 @@ void MimeUtil::InitializeMimeTypeMaps() {
allow_proprietary_codecs_ = true;
#endif
- for (size_t i = 0; i < arraysize(kUnambiguousCodecStringMap); ++i) {
- string_to_codec_map_[kUnambiguousCodecStringMap[i].codec_id] =
- CodecEntry(kUnambiguousCodecStringMap[i].codec, false);
- }
-
- for (size_t i = 0; i < arraysize(kAmbiguousCodecStringMap); ++i) {
- string_to_codec_map_[kAmbiguousCodecStringMap[i].codec_id] =
- CodecEntry(kAmbiguousCodecStringMap[i].codec, true);
- }
-
AddSupportedMediaFormats();
}
@@ -339,9 +338,9 @@ bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
media_format_map_.end();
}
-void MimeUtil::ParseCodecString(const std::string& codecs,
- std::vector<std::string>* codecs_out,
- bool strip) {
+void MimeUtil::SplitCodecsToVector(const std::string& codecs,
+ std::vector<std::string>* codecs_out,
+ bool strip) {
*codecs_out =
base::SplitString(base::TrimString(codecs, "\"", base::TRIM_ALL), ",",
base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
@@ -374,10 +373,11 @@ SupportsType MimeUtil::IsSupportedMediaFormat(
if (it_media_format_map->second.empty()) {
// We get here if the mimetype does not expect a codecs parameter.
- return (codecs.empty() && IsDefaultCodecSupportedLowerCase(
- mime_type_lower_case, is_encrypted))
- ? IsSupported
- : IsNotSupported;
+ if (codecs.empty()) {
+ return IsDefaultCodecSupported(mime_type_lower_case, is_encrypted);
+ } else {
+ return IsNotSupported;
+ }
}
if (codecs.empty()) {
@@ -386,12 +386,11 @@ SupportsType MimeUtil::IsSupportedMediaFormat(
// codec the best we can do is say "maybe" because we don't have enough
// information.
Codec default_codec = INVALID_CODEC;
- if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec))
+ if (!GetDefaultCodec(mime_type_lower_case, &default_codec))
return MayBeSupported;
- return IsCodecSupported(default_codec, mime_type_lower_case, is_encrypted)
- ? IsSupported
- : IsNotSupported;
+ return IsSimpleCodecSupported(mime_type_lower_case, default_codec,
+ is_encrypted);
}
#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
@@ -416,7 +415,7 @@ void MimeUtil::RemoveProprietaryMediaTypesAndCodecs() {
}
// static
-bool MimeUtil::IsCodecSupportedOnPlatform(
+bool MimeUtil::IsCodecSupportedOnAndroid(
Codec codec,
const std::string& mime_type_lower_case,
bool is_encrypted,
@@ -542,99 +541,156 @@ bool MimeUtil::IsCodecSupportedOnPlatform(
return false;
}
-bool MimeUtil::StringToCodec(const std::string& mime_type_lower_case,
- const std::string& codec_id,
- Codec* codec,
- bool* is_ambiguous,
- VideoCodecProfile* out_profile,
- uint8_t* out_level,
- bool is_encrypted) const {
+bool MimeUtil::ParseCodecString(const std::string& mime_type_lower_case,
+ const std::string& codec_id,
+ Codec* codec,
+ bool* ambiguous_codec_string,
+ VideoCodecProfile* out_profile,
+ uint8_t* out_level) const {
+ DCHECK_EQ(base::ToLowerASCII(mime_type_lower_case), mime_type_lower_case);
+ DCHECK(codec);
DCHECK(out_profile);
DCHECK(out_level);
+
+ *codec = INVALID_CODEC;
+ *ambiguous_codec_string = false;
*out_profile = VIDEO_CODEC_PROFILE_UNKNOWN;
*out_level = 0;
- StringToCodecMappings::const_iterator itr =
- string_to_codec_map_.find(codec_id);
- if (itr != string_to_codec_map_.end()) {
- *codec = itr->second.codec;
- *is_ambiguous = itr->second.is_ambiguous;
+ std::map<std::string, Codec>::const_iterator itr =
+ GetStringToCodecMap().find(codec_id);
+ if (itr != GetStringToCodecMap().end()) {
+ *codec = itr->second;
+
return true;
}
- // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is
+ // Check codec string against short list of allowed ambiguous codecs.
+ // Hard-coded to discourage expansion. DO NOT ADD TO THIS LIST. DO NOT
+ // INCREASE PLACES WHERE |ambiguous_codec_string| = true.
+ // NOTE: avc1/avc3.XXXXXX may be ambiguous handled after ParseAVCCodecId().
+ if (codec_id == "avc1" || codec_id == "avc3") {
+ *codec = MimeUtil::H264;
+ *ambiguous_codec_string = true;
+ return true;
+ } else if (codec_id == "mp4a.40") {
+ *codec = MimeUtil::MPEG4_AAC;
+ *ambiguous_codec_string = true;
+ return true;
+ }
+
+ // If |codec_id| is not in |kStringToCodecMap|, then we assume that it is
// either VP9, H.264 or HEVC/H.265 codec ID because currently those are the
- // only ones that are not added to the |string_to_codec_map_| and require
+ // only ones that are not added to the |kStringToCodecMap| and require
// parsing.
if (ParseVp9CodecID(mime_type_lower_case, codec_id, out_profile, out_level)) {
*codec = MimeUtil::VP9;
- switch (*out_profile) {
- case VP9PROFILE_PROFILE0:
- // Profile 0 should always be supported if VP9 is supported.
- *is_ambiguous = false;
- break;
- default:
- // We don't know if the underlying platform supports these profiles.
- // Need to add platform level querying to get supported profiles
- // (crbug/604566).
- *is_ambiguous = true;
- break;
- }
return true;
}
if (ParseAVCCodecId(codec_id, out_profile, out_level)) {
*codec = MimeUtil::H264;
- switch (*out_profile) {
-// HIGH10PROFILE is supported through fallback to the ffmpeg decoder
-// which is not available on Android, or if FFMPEG is not used.
-#if !defined(MEDIA_DISABLE_FFMPEG) && !defined(OS_ANDROID)
- case H264PROFILE_HIGH10PROFILE:
- if (is_encrypted) {
- // FFmpeg is not generally used for encrypted videos, so we do not
- // know whether 10-bit is supported.
- *is_ambiguous = true;
- break;
- }
-// Fall through.
-#endif
-
- case H264PROFILE_BASELINE:
- case H264PROFILE_MAIN:
- case H264PROFILE_HIGH:
- *is_ambiguous = !IsValidH264Level(*out_level);
- break;
- default:
- *is_ambiguous = true;
- }
+ // Allowed string ambiguity since 2014. DO NOT ADD NEW CASES FOR AMBIGUITY.
+ *ambiguous_codec_string = !IsValidH264Level(*out_level);
return true;
}
#if BUILDFLAG(ENABLE_HEVC_DEMUXING)
if (ParseHEVCCodecId(codec_id, out_profile, out_level)) {
*codec = MimeUtil::HEVC;
- *is_ambiguous = false;
return true;
}
#endif
- DVLOG(4) << __func__ << ": Unrecognized codec id " << codec_id;
+ DVLOG(2) << __func__ << ": Unrecognized codec id " << codec_id;
return false;
}
-bool MimeUtil::IsCodecSupported(Codec codec,
- const std::string& mime_type_lower_case,
- bool is_encrypted) const {
+SupportsType MimeUtil::IsSimpleCodecSupported(
+ const std::string& mime_type_lower_case,
+ Codec codec,
+ bool is_encrypted) const {
+ // Video codecs are not "simple" because they require a profile and level to
+ // be specified. There is no "default" video codec for a given container.
+ DCHECK_EQ(MimeUtilToVideoCodec(codec), kUnknownVideoCodec);
+
+ SupportsType result =
+ IsCodecSupported(mime_type_lower_case, codec, VIDEO_CODEC_PROFILE_UNKNOWN,
+ 0 /* video_level */, is_encrypted);
+
+ // Platform support should never be ambiguous for simple codecs (no range of
+ // profiles to consider).
+ DCHECK_NE(result, MayBeSupported);
+ return result;
+}
+
+SupportsType MimeUtil::IsCodecSupported(const std::string& mime_type_lower_case,
+ Codec codec,
+ VideoCodecProfile video_profile,
+ uint8_t video_level,
+ bool is_encrypted) const {
+ DCHECK_EQ(base::ToLowerASCII(mime_type_lower_case), mime_type_lower_case);
DCHECK_NE(codec, INVALID_CODEC);
+ VideoCodec video_codec = MimeUtilToVideoCodec(codec);
+ if (video_codec != kUnknownVideoCodec &&
+ // Theora and VP8 do not have profiles/levels.
+ video_codec != kCodecTheora && video_codec != kCodecVP8) {
+ DCHECK_NE(video_profile, VIDEO_CODEC_PROFILE_UNKNOWN);
+ DCHECK_GT(video_level, 0);
+ }
+
+ // Bail early for disabled proprietary codecs
+ if (!allow_proprietary_codecs_ && IsCodecProprietary(codec)) {
+ return IsNotSupported;
+ }
+
+ // Check for cases of ambiguous platform support.
+ // TODO(chcunningham): DELETE THIS. Platform should know its capabilities.
+ // Answer should come from MediaClient.
+ bool ambiguous_platform_support = false;
+ if (codec == MimeUtil::H264) {
+ switch (video_profile) {
+ // Always supported
+ case H264PROFILE_BASELINE:
+ case H264PROFILE_MAIN:
+ case H264PROFILE_HIGH:
+ break;
+// HIGH10PROFILE is supported through fallback to the ffmpeg decoder
+// which is not available on Android, or if FFMPEG is not used.
+#if !defined(MEDIA_DISABLE_FFMPEG) && !defined(OS_ANDROID)
+ case H264PROFILE_HIGH10PROFILE:
+ // FFmpeg is not generally used for encrypted videos, so we do not
+ // know whether 10-bit is supported.
+ ambiguous_platform_support = is_encrypted;
+ break;
+#endif
+ default:
+ ambiguous_platform_support = true;
+ }
+ } else if (codec == MimeUtil::VP9 && video_profile != VP9PROFILE_PROFILE0) {
+ // We don't know if the underlying platform supports these profiles. Need
+ // to add platform level querying to get supported profiles.
+ // https://crbug.com/604566
+ ambiguous_platform_support = true;
+ }
+
+ if (GetMediaClient() && video_codec != kUnknownVideoCodec &&
+ !GetMediaClient()->IsSupportedVideoConfig(video_codec, video_profile,
+ video_level)) {
+ return IsNotSupported;
+ }
+
#if defined(OS_ANDROID)
- if (!IsCodecSupportedOnPlatform(codec, mime_type_lower_case, is_encrypted,
- platform_info_)) {
- return false;
+ // TODO(chcunningham): Delete this. Android platform support should be
+ // handled by (android specific) MediaClient.
+ if (!IsCodecSupportedOnAndroid(codec, mime_type_lower_case, is_encrypted,
+ platform_info_)) {
+ return IsNotSupported;
}
#endif
- return allow_proprietary_codecs_ || !IsCodecProprietary(codec);
+ return ambiguous_platform_support ? MayBeSupported : IsSupported;
}
bool MimeUtil::IsCodecProprietary(Codec codec) const {
@@ -662,21 +718,20 @@ bool MimeUtil::IsCodecProprietary(Codec codec) const {
return true;
}
-bool MimeUtil::GetDefaultCodecLowerCase(const std::string& mime_type_lower_case,
- Codec* default_codec) const {
- if (mime_type_lower_case == "audio/mpeg" ||
- mime_type_lower_case == "audio/mp3" ||
- mime_type_lower_case == "audio/x-mp3") {
+bool MimeUtil::GetDefaultCodec(const std::string& mime_type,
+ Codec* default_codec) const {
+ if (mime_type == "audio/mpeg" || mime_type == "audio/mp3" ||
+ mime_type == "audio/x-mp3") {
*default_codec = MimeUtil::MP3;
return true;
}
- if (mime_type_lower_case == "audio/aac") {
+ if (mime_type == "audio/aac") {
*default_codec = MimeUtil::MPEG4_AAC;
return true;
}
- if (mime_type_lower_case == "audio/flac") {
+ if (mime_type == "audio/flac") {
*default_codec = MimeUtil::FLAC;
return true;
}
@@ -684,13 +739,12 @@ bool MimeUtil::GetDefaultCodecLowerCase(const std::string& mime_type_lower_case,
return false;
}
-bool MimeUtil::IsDefaultCodecSupportedLowerCase(
- const std::string& mime_type_lower_case,
- bool is_encrypted) const {
+SupportsType MimeUtil::IsDefaultCodecSupported(const std::string& mime_type,
+ bool is_encrypted) const {
Codec default_codec = Codec::INVALID_CODEC;
- if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec))
- return false;
- return IsCodecSupported(default_codec, mime_type_lower_case, is_encrypted);
+ if (!GetDefaultCodec(mime_type, &default_codec))
+ return IsNotSupported;
+ return IsSimpleCodecSupported(mime_type, default_codec, is_encrypted);
}
} // namespace internal
« no previous file with comments | « media/base/mime_util_internal.h ('k') | media/base/mime_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698