Chromium Code Reviews| 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..6683cc6d73af65d9011948edf00b66cb0ec1680b 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,16 +25,7 @@ |
| 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[] = { |
| +static const std::map<std::string, MimeUtil::Codec> kStringToCodecMap = { |
|
DaleCurtis
2017/02/17 23:39:03
Can't do this since it's a static initializer.
chcunningham
2017/02/20 22:25:05
Fixed! thanks
|
| {"1", MimeUtil::PCM}, // We only allow this for WAV so it isn't ambiguous. |
| // avc1/avc3.XXXXXX may be unambiguous; handled by ParseAVCCodecId(). |
| // hev1/hvc1.XXXXXX may be unambiguous; handled by ParseHEVCCodecID(). |
| @@ -82,17 +75,6 @@ static const CodecIDMappings kUnambiguousCodecStringMap[] = { |
| {"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(). |
| -}; |
| - |
| static bool ParseVp9CodecID(const std::string& mime_type_lower_case, |
| const std::string& codec_id, |
| VideoCodecProfile* out_profile, |
| @@ -167,29 +149,40 @@ SupportsType MimeUtil::AreSupportedCodecs( |
| SupportsType result = IsSupported; |
| for (size_t i = 0; i < codecs.size(); ++i) { |
| - bool is_ambiguous = true; |
| + // Parse the string. |
| + bool ambiguous_codec_string = true; |
| 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 is 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; |
| } |
| - if (!IsCodecSupported(codec, mime_type_lower_case, is_encrypted) || |
| - supported_codecs.find(codec) == supported_codecs.end()) { |
| + // Check platform support. |
| + result = IsCodecSupported(mime_type_lower_case, codec, video_profile, |
| + video_level, is_encrypted); |
| + if (result == IsNotSupported) |
| return IsNotSupported; |
| - } |
| - if (is_ambiguous) |
| + // Downgrade to MayBeSupported if we had to guess the meaning of the codec |
| + // string. |
| + if (result == IsSupported && ambiguous_codec_string) |
| result = MayBeSupported; |
| } |
| @@ -201,16 +194,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 +322,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 +357,12 @@ 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 IsDefaultCodecSupportedLowerCase(mime_type_lower_case, |
| + is_encrypted); |
| + } else { |
| + return IsNotSupported; |
| + } |
| } |
| if (codecs.empty()) { |
| @@ -389,9 +374,8 @@ SupportsType MimeUtil::IsSupportedMediaFormat( |
| if (!GetDefaultCodecLowerCase(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 +400,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 +526,151 @@ 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(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 = |
| + kStringToCodecMap.find(codec_id); |
| + if (itr != kStringToCodecMap.end()) { |
| + *codec = itr->second; |
| + return true; |
| + } |
| + |
| + // 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 |string_to_codec_map_|, then we assume that it is |
| + // 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; |
| + LOG(WARNING) << __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_NE(codec, INVALID_CODEC); |
| + VideoCodec video_codec = MimeUtilToVideoCodec(codec); |
| + if (video_codec != kUnknownVideoCodec) { |
| + 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 { |
| @@ -684,13 +720,14 @@ bool MimeUtil::GetDefaultCodecLowerCase(const std::string& mime_type_lower_case, |
| return false; |
| } |
| -bool MimeUtil::IsDefaultCodecSupportedLowerCase( |
| +SupportsType MimeUtil::IsDefaultCodecSupportedLowerCase( |
| const std::string& mime_type_lower_case, |
| 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); |
| + return IsNotSupported; |
| + return IsSimpleCodecSupported(mime_type_lower_case, default_codec, |
| + is_encrypted); |
| } |
| } // namespace internal |