blob: fd6d7b12e7f5eeae62a9a5d50e8204509f2905ba [file] [log] [blame]
// Copyright 2012 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 "cobalt/media/base/mime_util_internal.h"
#include "base/command_line.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "build/build_config.h"
#include "cobalt/media/base/media.h"
#include "cobalt/media/base/video_codecs.h"
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
#include "cobalt/media/base/android/media_codec_util.h"
#endif
namespace cobalt {
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.
// 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
// ParseVp9CodecID().
{"mp3", MimeUtil::MP3},
// Following is the list of RFC 6381 compliant audio codec strings:
// mp4a.66 - MPEG-2 AAC MAIN
// mp4a.67 - MPEG-2 AAC LC
// mp4a.68 - MPEG-2 AAC SSR
// mp4a.69 - MPEG-2 extension to MPEG-1 (MP3)
// mp4a.6B - MPEG-1 audio (MP3)
// 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.29 - MPEG-4 HE-AAC v2 (AAC LC + SBR + PS)
{"mp4a.66", MimeUtil::MPEG2_AAC},
{"mp4a.67", MimeUtil::MPEG2_AAC},
{"mp4a.68", MimeUtil::MPEG2_AAC},
{"mp4a.69", MimeUtil::MP3},
{"mp4a.6B", MimeUtil::MP3},
{"mp4a.40.2", MimeUtil::MPEG4_AAC},
{"mp4a.40.02", MimeUtil::MPEG4_AAC},
{"mp4a.40.5", MimeUtil::MPEG4_AAC},
{"mp4a.40.05", MimeUtil::MPEG4_AAC},
{"mp4a.40.29", MimeUtil::MPEG4_AAC},
// 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},
{"vorbis", MimeUtil::VORBIS},
{"opus", MimeUtil::OPUS},
{"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().
};
static const char kHexString[] = "0123456789ABCDEF";
static char IntToHex(int i) {
DCHECK_GE(i, 0) << i << " not a hex value";
DCHECK_LE(i, 15) << i << " not a hex value";
return kHexString[i];
}
static std::string TranslateLegacyAvc1CodecIds(const std::string& codec_id) {
// Special handling for old, pre-RFC 6381 format avc1 strings, which are still
// being used by some HLS apps to preserve backward compatibility with older
// iOS devices. The old format was avc1.<profile>.<level>
// Where <profile> is H.264 profile_idc encoded as a decimal number, i.e.
// 66 is baseline profile (0x42)
// 77 is main profile (0x4d)
// 100 is high profile (0x64)
// And <level> is H.264 level multiplied by 10, also encoded as decimal number
// E.g. <level> 31 corresponds to H.264 level 3.1
// See, for example, http://qtdevseed.apple.com/qadrift/testcases/tc-0133.php
uint32_t level_start = 0;
std::string result;
if (StartsWithASCII(codec_id, "avc1.66.", true)) {
level_start = 8;
result = "avc1.4200";
} else if (StartsWithASCII(codec_id, "avc1.77.", true)) {
level_start = 8;
result = "avc1.4D00";
} else if (StartsWithASCII(codec_id, "avc1.100.", true)) {
level_start = 9;
result = "avc1.6400";
}
uint32_t level = 0;
if (level_start > 0 &&
base::StringToUint(codec_id.substr(level_start), &level) && level < 256) {
// This is a valid legacy avc1 codec id - return the codec id translated
// into RFC 6381 format.
result.push_back(IntToHex(level >> 4));
result.push_back(IntToHex(level & 0xf));
return result;
}
// This is not a valid legacy avc1 codec id - return the original codec id.
return codec_id;
}
static bool IsValidH264Level(uint8_t level_idc) {
// Valid levels taken from Table A-1 in ISO/IEC 14496-10.
// Level_idc represents the standard level represented as decimal number
// multiplied by ten, e.g. level_idc==32 corresponds to level==3.2
return ((level_idc >= 10 && level_idc <= 13) ||
(level_idc >= 20 && level_idc <= 22) ||
(level_idc >= 30 && level_idc <= 32) ||
(level_idc >= 40 && level_idc <= 42) ||
(level_idc >= 50 && level_idc <= 51));
}
// Handle parsing of vp9 codec IDs.
static bool ParseVp9CodecID(const std::string& mime_type_lower_case,
const std::string& codec_id,
VideoCodecProfile* profile) {
if (mime_type_lower_case == "video/webm") {
if (codec_id == "vp9" || codec_id == "vp9.0") {
// Profile is not included in the codec string. Assuming profile 0 to be
// backward compatible.
*profile = VP9PROFILE_PROFILE0;
return true;
}
// TODO(kqyang): Should we support new codec string in WebM?
return false;
} else if (mime_type_lower_case == "audio/webm") {
return false;
}
std::vector<std::string> fields;
base::SplitString(codec_id, '.', &fields);
if (fields.size() < 1) return false;
if (fields[0] != "vp09") return false;
if (fields.size() > 8) return false;
std::vector<int> values;
for (size_t i = 1; i < fields.size(); ++i) {
// Missing value is not allowed.
if (fields[i] == "") return false;
int value;
if (!base::StringToInt(fields[i], &value)) return false;
if (value < 0) return false;
values.push_back(value);
}
// The spec specifies 8 fields (7 values excluding the first codec field).
// We do not allow missing fields.
if (values.size() < 7) return false;
const int profile_idc = values[0];
switch (profile_idc) {
case 0:
*profile = VP9PROFILE_PROFILE0;
break;
case 1:
*profile = VP9PROFILE_PROFILE1;
break;
case 2:
*profile = VP9PROFILE_PROFILE2;
break;
case 3:
*profile = VP9PROFILE_PROFILE3;
break;
default:
return false;
}
const int bit_depth = values[2];
if (bit_depth != 8 && bit_depth != 10 && bit_depth != 12) return false;
const int color_space = values[3];
if (color_space > 7) return false;
const int chroma_subsampling = values[4];
if (chroma_subsampling > 3) return false;
const int transfer_function = values[5];
if (transfer_function > 1) return false;
const int video_full_range_flag = values[6];
if (video_full_range_flag > 1) return false;
return true;
}
MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) {
#if defined(OS_ANDROID)
platform_info_.is_unified_media_pipeline_enabled =
IsUnifiedMediaPipelineEnabled();
// When the unified media pipeline is enabled, we need support for both GPU
// video decoders and MediaCodec; indicated by HasPlatformDecoderSupport().
// When the Android pipeline is used, we only need access to MediaCodec.
platform_info_.has_platform_decoders = ArePlatformDecodersAvailable();
platform_info_.has_platform_vp8_decoder =
MediaCodecUtil::IsVp8DecoderAvailable();
platform_info_.has_platform_vp9_decoder =
MediaCodecUtil::IsVp9DecoderAvailable();
platform_info_.supports_opus = PlatformHasOpusSupport();
#endif
InitializeMimeTypeMaps();
}
MimeUtil::~MimeUtil() {}
VideoCodec MimeUtilToVideoCodec(MimeUtil::Codec codec) {
switch (codec) {
case MimeUtil::H264:
return kCodecH264;
case MimeUtil::HEVC:
return kCodecHEVC;
case MimeUtil::VP8:
return kCodecVP8;
case MimeUtil::VP9:
return kCodecVP9;
case MimeUtil::THEORA:
return kCodecTheora;
default:
break;
}
return kUnknownVideoCodec;
}
SupportsType MimeUtil::AreSupportedCodecs(
const CodecSet& supported_codecs, const std::vector<std::string>& codecs,
const std::string& mime_type_lower_case, bool is_encrypted) const {
DCHECK(!supported_codecs.empty());
DCHECK(!codecs.empty());
SupportsType result = IsSupported;
for (size_t i = 0; i < codecs.size(); ++i) {
bool is_ambiguous = 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)) {
return IsNotSupported;
}
VideoCodec video_codec = MimeUtilToVideoCodec(codec);
if (!IsCodecSupported(codec, mime_type_lower_case, is_encrypted) ||
supported_codecs.find(codec) == supported_codecs.end()) {
return IsNotSupported;
}
if (is_ambiguous) result = MayBeSupported;
}
return result;
}
void MimeUtil::InitializeMimeTypeMaps() {
#if defined(USE_PROPRIETARY_CODECS)
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();
}
// Each call to AddContainerWithCodecs() contains a media type
// (https://en.wikipedia.org/wiki/Media_type) and corresponding media codec(s)
// supported by these types/containers.
// TODO(ddorwin): Replace insert() calls with initializer_list when allowed.
void MimeUtil::AddSupportedMediaFormats() {
CodecSet implicit_codec;
CodecSet wav_codecs;
wav_codecs.insert(PCM);
CodecSet ogg_audio_codecs;
ogg_audio_codecs.insert(OPUS);
ogg_audio_codecs.insert(VORBIS);
CodecSet ogg_video_codecs;
#if !defined(OS_ANDROID)
ogg_video_codecs.insert(THEORA);
#endif // !defined(OS_ANDROID)
CodecSet ogg_codecs(ogg_audio_codecs);
ogg_codecs.insert(ogg_video_codecs.begin(), ogg_video_codecs.end());
CodecSet webm_audio_codecs;
webm_audio_codecs.insert(OPUS);
webm_audio_codecs.insert(VORBIS);
CodecSet webm_video_codecs;
webm_video_codecs.insert(VP8);
webm_video_codecs.insert(VP9);
CodecSet webm_codecs(webm_audio_codecs);
webm_codecs.insert(webm_video_codecs.begin(), webm_video_codecs.end());
CodecSet mp3_codecs;
mp3_codecs.insert(MP3);
CodecSet aac;
aac.insert(MPEG2_AAC);
aac.insert(MPEG4_AAC);
CodecSet avc_and_aac(aac);
avc_and_aac.insert(H264);
CodecSet mp4_audio_codecs(aac);
mp4_audio_codecs.insert(MP3);
mp4_audio_codecs.insert(AC3);
mp4_audio_codecs.insert(EAC3);
CodecSet mp4_video_codecs;
mp4_video_codecs.insert(H264);
mp4_video_codecs.insert(HEVC);
// Only VP9 with valid codec string vp09.xx.xx.xx.xx.xx.xx.xx is supported.
// See ParseVp9CodecID for details.
mp4_video_codecs.insert(VP9);
CodecSet mp4_codecs(mp4_audio_codecs);
mp4_codecs.insert(mp4_video_codecs.begin(), mp4_video_codecs.end());
AddContainerWithCodecs("audio/wav", wav_codecs, false);
AddContainerWithCodecs("audio/x-wav", wav_codecs, false);
AddContainerWithCodecs("audio/webm", webm_audio_codecs, false);
DCHECK(!webm_video_codecs.empty());
AddContainerWithCodecs("video/webm", webm_codecs, false);
AddContainerWithCodecs("audio/ogg", ogg_audio_codecs, false);
// video/ogg is only supported if an appropriate video codec is supported.
// Note: This assumes such codecs cannot be later excluded.
if (!ogg_video_codecs.empty())
AddContainerWithCodecs("video/ogg", ogg_codecs, false);
// TODO(ddorwin): Should the application type support Opus?
AddContainerWithCodecs("application/ogg", ogg_codecs, false);
AddContainerWithCodecs("audio/mpeg", mp3_codecs, true); // Allow "mp3".
AddContainerWithCodecs("audio/mp3", implicit_codec, true);
AddContainerWithCodecs("audio/x-mp3", implicit_codec, true);
AddContainerWithCodecs("audio/aac", implicit_codec, true); // AAC / ADTS.
AddContainerWithCodecs("audio/mp4", mp4_audio_codecs, true);
DCHECK(!mp4_video_codecs.empty());
AddContainerWithCodecs("video/mp4", mp4_codecs, true);
// These strings are supported for backwards compatibility only and thus only
// support the codecs needed for compatibility.
AddContainerWithCodecs("audio/x-m4a", aac, true);
AddContainerWithCodecs("video/x-m4v", avc_and_aac, true);
// TODO(ddorwin): Exactly which codecs should be supported?
DCHECK(!mp4_video_codecs.empty());
AddContainerWithCodecs("video/mp2t", mp4_codecs, true);
#if defined(OS_ANDROID)
// HTTP Live Streaming (HLS).
// TODO(ddorwin): Is any MP3 codec string variant included in real queries?
CodecSet hls_codecs(avc_and_aac);
hls_codecs.insert(MP3);
AddContainerWithCodecs("application/x-mpegurl", hls_codecs, true);
AddContainerWithCodecs("application/vnd.apple.mpegurl", hls_codecs, true);
#endif // defined(OS_ANDROID)
}
void MimeUtil::AddContainerWithCodecs(const std::string& mime_type,
const CodecSet& codecs,
bool is_proprietary_mime_type) {
media_format_map_[mime_type] = codecs;
if (is_proprietary_mime_type)
proprietary_media_containers_.push_back(mime_type);
}
bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
return media_format_map_.find(StringToLowerASCII(mime_type)) !=
media_format_map_.end();
}
void MimeUtil::ParseCodecString(const std::string& codecs,
std::vector<std::string>* codecs_out,
bool strip) {
std::string trimmed_codecs;
TrimString(codecs, "\"", &trimmed_codecs);
base::SplitString(trimmed_codecs, ',', codecs_out);
// Convert empty or all-whitespace input to 0 results.
if (codecs_out->size() == 1 && (*codecs_out)[0].empty()) codecs_out->clear();
if (!strip) return;
// Strip everything past the first '.'
for (std::vector<std::string>::iterator it = codecs_out->begin();
it != codecs_out->end(); ++it) {
size_t found = it->find_first_of('.');
if (found != std::string::npos) it->resize(found);
}
}
SupportsType MimeUtil::IsSupportedMediaFormat(
const std::string& mime_type, const std::vector<std::string>& codecs,
bool is_encrypted) const {
const std::string mime_type_lower_case = StringToLowerASCII(mime_type);
MediaFormatMappings::const_iterator it_media_format_map =
media_format_map_.find(mime_type_lower_case);
if (it_media_format_map == media_format_map_.end()) return IsNotSupported;
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()) {
// We get here if the mimetype expects to get a codecs parameter,
// but didn't get one. If |mime_type_lower_case| does not have a default
// 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))
return MayBeSupported;
return IsCodecSupported(default_codec, mime_type_lower_case, is_encrypted)
? IsSupported
: IsNotSupported;
}
if (mime_type_lower_case == "video/mp2t") {
std::vector<std::string> codecs_to_check;
for (size_t i = 0; i < codecs.size(); ++i) {
codecs_to_check.push_back(TranslateLegacyAvc1CodecIds(codecs[i]));
}
return AreSupportedCodecs(it_media_format_map->second, codecs_to_check,
mime_type_lower_case, is_encrypted);
}
return AreSupportedCodecs(it_media_format_map->second, codecs,
mime_type_lower_case, is_encrypted);
}
void MimeUtil::RemoveProprietaryMediaTypesAndCodecs() {
for (size_t i = 0; i < proprietary_media_containers_.size(); ++i)
media_format_map_.erase(proprietary_media_containers_[i]);
allow_proprietary_codecs_ = false;
}
// static
bool MimeUtil::IsCodecSupportedOnPlatform(
Codec codec, const std::string& mime_type_lower_case, bool is_encrypted,
const PlatformInfo& platform_info) {
DCHECK_NE(mime_type_lower_case, "");
// Encrypted block support is never available without platform decoders.
if (is_encrypted && !platform_info.has_platform_decoders) return false;
// NOTE: We do not account for Media Source Extensions (MSE) within these
// checks since it has its own isTypeSupported() which will handle platform
// specific codec rejections. See http://crbug.com/587303.
switch (codec) {
// ----------------------------------------------------------------------
// The following codecs are never supported.
// ----------------------------------------------------------------------
case INVALID_CODEC:
case AC3:
case EAC3:
case THEORA:
return false;
// ----------------------------------------------------------------------
// The remaining codecs may be supported depending on platform abilities.
// ----------------------------------------------------------------------
case PCM:
case MP3:
case MPEG4_AAC:
case VORBIS:
// These codecs are always supported; via a platform decoder (when used
// with MSE/EME), a software decoder (the unified pipeline), or with
// MediaPlayer.
DCHECK(!is_encrypted || platform_info.has_platform_decoders);
return true;
case MPEG2_AAC:
// MPEG-2 variants of AAC are not supported on Android unless the unified
// media pipeline can be used and the container is not HLS. These codecs
// will be decoded in software. See https:crbug.com/544268 for details.
if (mime_type_lower_case == "application/x-mpegurl" ||
mime_type_lower_case == "application/vnd.apple.mpegurl") {
return false;
}
return !is_encrypted && platform_info.is_unified_media_pipeline_enabled;
case OPUS:
// If clear, the unified pipeline can always decode Opus in software.
if (!is_encrypted && platform_info.is_unified_media_pipeline_enabled)
return true;
// Otherwise, platform support is required.
if (!platform_info.supports_opus) return false;
// MediaPlayer does not support Opus in ogg containers.
if (EndsWith(mime_type_lower_case, "ogg", true)) {
return false;
}
DCHECK(!is_encrypted || platform_info.has_platform_decoders);
return true;
case H264:
// When content is not encrypted we fall back to MediaPlayer, thus we
// always support H264. For EME we need MediaCodec.
return !is_encrypted || platform_info.has_platform_decoders;
case HEVC:
if (platform_info.is_unified_media_pipeline_enabled &&
!platform_info.has_platform_decoders) {
return false;
}
#if defined(OS_ANDROID)
// HEVC/H.265 is supported in Lollipop+ (API Level 21), according to
// http://developer.android.com/reference/android/media/MediaFormat.html
return base::android::BuildInfo::GetInstance()->sdk_int() >= 21;
#else
return true;
#endif // defined(OS_ANDROID)
case VP8:
// If clear, the unified pipeline can always decode VP8 in software.
if (!is_encrypted && platform_info.is_unified_media_pipeline_enabled)
return true;
if (is_encrypted) return platform_info.has_platform_vp8_decoder;
// MediaPlayer can always play VP8. Note: This is incorrect for MSE, but
// MSE does not use this code. http://crbug.com/587303.
return true;
case VP9: {
// If clear, the unified pipeline can always decode VP9 in software.
if (!is_encrypted && platform_info.is_unified_media_pipeline_enabled)
return true;
if (!platform_info.has_platform_vp9_decoder) return false;
// Encrypted content is demuxed so the container is irrelevant.
if (is_encrypted) return true;
// MediaPlayer only supports VP9 in WebM.
return mime_type_lower_case == "video/webm";
}
}
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 {
DCHECK(out_profile);
DCHECK(out_level);
*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;
return true;
}
// If |codec_id| is not in |string_to_codec_map_|, then we assume that it is
// either 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 parsing.
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;
}
return true;
}
if (ParseVp9CodecID(mime_type_lower_case, codec_id, out_profile)) {
*codec = MimeUtil::VP9;
*out_level = 1;
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;
}
return true;
}
if (ParseHEVCCodecId(codec_id, out_profile, out_level)) {
*codec = MimeUtil::HEVC;
*is_ambiguous = false;
return true;
}
DVLOG(4) << __func__ << ": Unrecognized codec id " << codec_id;
return false;
}
bool MimeUtil::IsCodecSupported(Codec codec,
const std::string& mime_type_lower_case,
bool is_encrypted) const {
DCHECK_NE(codec, INVALID_CODEC);
#if defined(OS_ANDROID)
if (!IsCodecSupportedOnPlatform(codec, mime_type_lower_case, is_encrypted,
platform_info_)) {
return false;
}
#endif
return allow_proprietary_codecs_ || !IsCodecProprietary(codec);
}
bool MimeUtil::IsCodecProprietary(Codec codec) const {
switch (codec) {
case INVALID_CODEC:
case AC3:
case EAC3:
case MP3:
case MPEG2_AAC:
case MPEG4_AAC:
case H264:
case HEVC:
return true;
case PCM:
case VORBIS:
case OPUS:
case VP8:
case VP9:
case THEORA:
return false;
}
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") {
*default_codec = MimeUtil::MP3;
return true;
}
if (mime_type_lower_case == "audio/aac") {
*default_codec = MimeUtil::MPEG4_AAC;
return true;
}
return false;
}
bool MimeUtil::IsDefaultCodecSupportedLowerCase(
const std::string& mime_type_lower_case, bool is_encrypted) const {
Codec default_codec = INVALID_CODEC;
if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec))
return false;
return IsCodecSupported(default_codec, mime_type_lower_case, is_encrypted);
}
} // namespace internal
} // namespace media
} // namespace cobalt