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

Unified Diff: media/base/mime_util.cc

Issue 401523002: Move media related mimetype functionality out of net/ and into media/. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase and add content/common/mime_util.h for realz Created 6 years, 5 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
Index: media/base/mime_util.cc
diff --git a/media/base/mime_util.cc b/media/base/mime_util.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3ed33ca5260852aa98254e3c00d9d5fcec3f8134
--- /dev/null
+++ b/media/base/mime_util.cc
@@ -0,0 +1,441 @@
+// Copyright 2014 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 "media/base/mime_util.h"
+
+#include <map>
+
+#include "base/lazy_instance.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
+namespace media {
+
+class MimeUtil {
+ public:
+ bool IsSupportedMediaMimeType(const std::string& mime_type) const;
+
+ bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const;
+
+ void ParseCodecString(const std::string& codecs,
+ std::vector<std::string>* codecs_out,
+ bool strip);
+
+ bool IsStrictMediaMimeType(const std::string& mime_type) const;
+ SupportsType IsSupportedStrictMediaMimeType(
+ const std::string& mime_type,
+ const std::vector<std::string>& codecs) const;
+
+ void RemoveProprietaryMediaTypesAndCodecsForTests();
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
+
+ typedef base::hash_set<std::string> MimeMappings;
+ typedef std::map<std::string, MimeMappings> StrictMappings;
+
+ typedef std::vector<std::string> MimeExpressionMappings;
+ typedef std::map<std::string, MimeExpressionMappings>
+ StrictExpressionMappings;
+
+ MimeUtil();
+
+ // Returns true if |codecs| is nonempty and all the items in it are present in
+ // |supported_codecs|.
+ static bool AreSupportedCodecs(const MimeMappings& supported_codecs,
+ const std::vector<std::string>& codecs);
+ // Returns true is |codecs| is nonempty and all the items in it match with the
+ // codecs expression in |supported_codecs|.
+ static bool AreSupportedCodecsWithProfile(
+ const MimeExpressionMappings& supported_codecs,
+ const std::vector<std::string>& codecs);
+
+ // For faster lookup, keep hash sets.
+ void InitializeMimeTypeMaps();
+
+ MimeMappings media_map_;
+ MimeMappings codecs_map_;
+
+ // A map of mime_types and hash map of the supported codecs for the mime_type.
+ StrictMappings strict_format_map_;
+ // A map of MP4 mime_types which expect codecs with profile parameter and
+ // vector of supported codecs expressions for the mime_type.
+ StrictExpressionMappings strict_mp4_format_map_;
+};
+
+// This variable is Leaky because we need to access it from WorkerPool threads.
+static base::LazyInstance<MimeUtil>::Leaky g_mime_util =
+ LAZY_INSTANCE_INITIALIZER;
+
+
+// A list of media types: http://en.wikipedia.org/wiki/Internet_media_type
+// A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php
+// This set of codecs is supported by all variations of Chromium.
+static const char* const common_media_types[] = {
+ // Ogg.
+ "audio/ogg",
+ "application/ogg",
+#if !defined(OS_ANDROID) // Android doesn't support Ogg Theora.
+ "video/ogg",
+#endif
+
+ // WebM.
+ "video/webm",
+ "audio/webm",
+
+ // Wav.
+ "audio/wav",
+ "audio/x-wav",
+
+#if defined(OS_ANDROID)
+ // HLS. Supported by Android ICS and above.
+ "application/vnd.apple.mpegurl",
+ "application/x-mpegurl",
+#endif
+};
+
+// List of proprietary types only supported by Google Chrome.
+static const char* const proprietary_media_types[] = {
+ // MPEG-4.
+ "video/mp4",
+ "video/x-m4v",
+ "audio/mp4",
+ "audio/x-m4a",
+
+ // MP3.
+ "audio/mp3",
+ "audio/x-mp3",
+ "audio/mpeg",
+};
+
+// List of supported codecs when passed in with <source type="...">.
+// This set of codecs is supported by all variations of Chromium.
+//
+// Refer to http://wiki.whatwg.org/wiki/Video_type_parameters#Browser_Support
+// for more information.
+//
+// The codecs for WAV are integers as defined in Appendix A of RFC2361:
+// http://tools.ietf.org/html/rfc2361
+static const char* const common_media_codecs[] = {
+#if !defined(OS_ANDROID) // Android doesn't support Ogg Theora.
+ "theora",
+#endif
+ "opus",
+ "vorbis",
+ "vp8",
+ "vp9",
+ "1" // WAVE_FORMAT_PCM.
+};
+
+// List of proprietary codecs only supported by Google Chrome.
+static const char* const proprietary_media_codecs[] = {
+ "avc1",
+ "avc3",
+ "mp4a"
+};
+
+#if defined(OS_ANDROID)
+static bool IsCodecSupportedOnAndroid(const std::string& codec) {
+ // Theora is not supported in Android
+ if (!codec.compare("theora"))
+ return false;
+
+ // VP9 is supported only in KitKat+ (API Level 19).
+ if ((!codec.compare("vp9") || !codec.compare("vp9.0")) &&
+ base::android::BuildInfo::GetInstance()->sdk_int() < 19) {
+ return false;
+ }
+
+ // TODO(vigneshv): Change this similar to the VP9 check once Opus is
+ // supported on Android (http://crbug.com/318436).
+ if (!codec.compare("opus")) {
+ return false;
+ }
+ return true;
+}
+
+static bool IsMimeTypeSupportedOnAndroid(const std::string& mimeType) {
+ // HLS codecs are supported in ICS and above (API level 14)
+ if ((!mimeType.compare("application/vnd.apple.mpegurl") ||
+ !mimeType.compare("application/x-mpegurl")) &&
+ base::android::BuildInfo::GetInstance()->sdk_int() < 14) {
+ return false;
+ }
+ return true;
+}
+#endif
+
+struct MediaFormatStrict {
+ const char* mime_type;
+ const char* codecs_list;
+};
+
+static const MediaFormatStrict format_codec_mappings[] = {
+ { "video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0" },
+ { "audio/webm", "opus,vorbis" },
+ { "audio/wav", "1" },
+ { "audio/x-wav", "1" },
+ { "video/ogg", "opus,theora,vorbis" },
+ { "audio/ogg", "opus,vorbis" },
+ { "application/ogg", "opus,theora,vorbis" },
+ { "audio/mpeg", ",mp3" }, // Note: The comma before the 'mp3'results in an
+ // empty string codec ID and indicates
+ // a missing codecs= parameter is also valid.
+ // The presense of 'mp3' is not RFC compliant,
+ // but is common in the wild so it is a defacto
+ // standard.
+ { "audio/mp3", "" },
+ { "audio/x-mp3", "" }
+};
+
+// Following is the list of RFC 6381 compliant codecs:
+// mp4a.6B - MPEG-1 audio
+// mp4a.69 - MPEG-2 extension to MPEG-1
+// mp4a.67 - MPEG-2 AAC
+// mp4a.40.2 - MPEG-4 AAC
+// mp4a.40.5 - MPEG-4 HE-AAC
+//
+// avc1.42E0xx - H.264 Baseline
+// avc1.4D40xx - H.264 Main
+// avc1.6400xx - H.264 High
+//
+// Additionally, several non-RFC compliant codecs are allowed, due to their
+// existing use on web.
+// mp4a.40
+// avc1.xxxxxx
+// avc3.xxxxxx
+// mp4a.6x
+static const char kProprietaryAudioCodecsExpression[] =
+ "mp4a.6?,mp4a.40,mp4a.40.?";
+static const char kProprietaryCodecsExpression[] =
+ "avc1,avc3,avc1.??????,avc3.??????,mp4a.6?,mp4a.40,mp4a.40.?";
+
+static const MediaFormatStrict format_mp4_codec_mappings[] = {
+ { "audio/mp4", kProprietaryAudioCodecsExpression },
+ { "audio/x-m4a", kProprietaryAudioCodecsExpression },
+ { "video/mp4", kProprietaryCodecsExpression },
+ { "video/x-m4v", kProprietaryCodecsExpression },
+ { "application/x-mpegurl", kProprietaryCodecsExpression },
+ { "application/vnd.apple.mpegurl", kProprietaryCodecsExpression }
+};
+
+MimeUtil::MimeUtil() {
+ InitializeMimeTypeMaps();
+}
+
+// static
+bool MimeUtil::AreSupportedCodecs(const MimeMappings& supported_codecs,
+ const std::vector<std::string>& codecs) {
+ if (supported_codecs.empty())
+ return codecs.empty();
+
+ // If no codecs are specified in the mimetype, check to see if a missing
+ // codecs parameter is allowed.
+ if (codecs.empty())
+ return supported_codecs.find(std::string()) != supported_codecs.end();
+
+ for (size_t i = 0; i < codecs.size(); ++i) {
+ if (codecs[i].empty() ||
+ supported_codecs.find(codecs[i]) == supported_codecs.end()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Checks all the codecs present in the |codecs| against the entries in
+// |supported_codecs|. Returns true only if |codecs| is non-empty and all the
+// codecs match |supported_codecs| expressions.
+bool MimeUtil::AreSupportedCodecsWithProfile(
+ const MimeExpressionMappings& supported_codecs,
+ const std::vector<std::string>& codecs) {
+ DCHECK(!supported_codecs.empty());
+ for (size_t i = 0; i < codecs.size(); ++i) {
+ bool codec_matched = false;
+ for (size_t j = 0; j < supported_codecs.size(); ++j) {
+ if (!MatchPattern(base::StringPiece(codecs[i]),
+ base::StringPiece(supported_codecs[j]))) {
+ continue;
+ }
+ // If suffix exists, check whether it is hexadecimal.
+ for (size_t wildcard_pos = supported_codecs[j].find('?');
+ wildcard_pos != std::string::npos &&
+ wildcard_pos < supported_codecs[j].length();
+ wildcard_pos = supported_codecs[j].find('?', wildcard_pos + 1)) {
+ // Don't enforce case sensitivity, even though it's called for, as it
+ // would break some websites.
+ if (wildcard_pos >= codecs[i].length() ||
+ !IsHexDigit(codecs[i].at(wildcard_pos))) {
+ return false;
+ }
+ }
+ codec_matched = true;
+ break;
+ }
+ if (!codec_matched)
+ return false;
+ }
+ return !codecs.empty();
+}
+
+void MimeUtil::InitializeMimeTypeMaps() {
+ // Initialize the supported media types.
+ for (size_t i = 0; i < arraysize(common_media_types); ++i) {
+#if defined(OS_ANDROID)
+ if (!IsMimeTypeSupportedOnAndroid(common_media_types[i]))
+ continue;
+#endif
+ media_map_.insert(common_media_types[i]);
+ }
+#if defined(USE_PROPRIETARY_CODECS)
+ for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
+ media_map_.insert(proprietary_media_types[i]);
+#endif
+
+ for (size_t i = 0; i < arraysize(common_media_codecs); ++i) {
+#if defined(OS_ANDROID)
+ if (!IsCodecSupportedOnAndroid(common_media_codecs[i]))
+ continue;
+#endif
+ codecs_map_.insert(common_media_codecs[i]);
+ }
+#if defined(USE_PROPRIETARY_CODECS)
+ for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i)
+ codecs_map_.insert(proprietary_media_codecs[i]);
+#endif
+
+ // Initialize the strict supported media types.
+ for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) {
+ std::vector<std::string> mime_type_codecs;
+ ParseCodecString(format_codec_mappings[i].codecs_list,
+ &mime_type_codecs,
+ false);
+
+ MimeMappings codecs;
+ for (size_t j = 0; j < mime_type_codecs.size(); ++j) {
+#if defined(OS_ANDROID)
+ if (!IsCodecSupportedOnAndroid(mime_type_codecs[j]))
+ continue;
+#endif
+ codecs.insert(mime_type_codecs[j]);
+ }
+ strict_format_map_[format_codec_mappings[i].mime_type] = codecs;
+ }
+ for (size_t i = 0; i < arraysize(format_mp4_codec_mappings); ++i) {
+ std::vector<std::string> mime_type_codecs;
+ ParseCodecString(
+ format_mp4_codec_mappings[i].codecs_list, &mime_type_codecs, false);
+
+ MimeExpressionMappings codecs;
+ for (size_t j = 0; j < mime_type_codecs.size(); ++j)
+ codecs.push_back(mime_type_codecs[j]);
+ strict_mp4_format_map_[format_mp4_codec_mappings[i].mime_type] = codecs;
+ }
+}
+
+bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
+ return media_map_.find(mime_type) != media_map_.end();
+}
+
+bool MimeUtil::AreSupportedMediaCodecs(
+ const std::vector<std::string>& codecs) const {
+ return AreSupportedCodecs(codecs_map_, codecs);
+}
+
+void MimeUtil::ParseCodecString(const std::string& codecs,
+ std::vector<std::string>* codecs_out,
+ bool strip) {
+ std::string no_quote_codecs;
+ base::TrimString(codecs, "\"", &no_quote_codecs);
+ base::SplitString(no_quote_codecs, ',', codecs_out);
+
+ 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);
+ }
+}
+
+bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const {
+ if (strict_format_map_.find(mime_type) == strict_format_map_.end() &&
+ strict_mp4_format_map_.find(mime_type) == strict_mp4_format_map_.end())
+ return false;
+ return true;
+}
+
+SupportsType MimeUtil::IsSupportedStrictMediaMimeType(
+ const std::string& mime_type,
+ const std::vector<std::string>& codecs) const {
+ StrictMappings::const_iterator it_strict_map =
+ strict_format_map_.find(mime_type);
+ if ((it_strict_map != strict_format_map_.end()) &&
+ AreSupportedCodecs(it_strict_map->second, codecs)) {
+ return IsSupported;
+ }
+
+ StrictExpressionMappings::const_iterator it_expression_map =
+ strict_mp4_format_map_.find(mime_type);
+ if ((it_expression_map != strict_mp4_format_map_.end()) &&
+ AreSupportedCodecsWithProfile(it_expression_map->second, codecs)) {
+ return MayBeSupported;
+ }
+
+ if (codecs.empty())
+ return MayBeSupported;
+
+ return IsNotSupported;
+}
+
+void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() {
+ for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
+ media_map_.erase(proprietary_media_types[i]);
+
+ for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i)
+ codecs_map_.erase(proprietary_media_codecs[i]);
+}
+
+//----------------------------------------------------------------------------
+// Wrappers for the singleton
+//----------------------------------------------------------------------------
+
+bool IsSupportedMediaMimeType(const std::string& mime_type) {
+ return g_mime_util.Get().IsSupportedMediaMimeType(mime_type);
+}
+
+bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
+ return g_mime_util.Get().AreSupportedMediaCodecs(codecs);
+}
+
+bool IsStrictMediaMimeType(const std::string& mime_type) {
+ return g_mime_util.Get().IsStrictMediaMimeType(mime_type);
+}
+
+SupportsType IsSupportedStrictMediaMimeType(
+ const std::string& mime_type,
+ const std::vector<std::string>& codecs) {
+ return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs);
+}
+
+void ParseCodecString(const std::string& codecs,
+ std::vector<std::string>* codecs_out,
+ const bool strip) {
+ g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
+}
+
+void RemoveProprietaryMediaTypesAndCodecsForTests() {
+ g_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests();
+}
+
+} // namespace media

Powered by Google App Engine
This is Rietveld 408576698