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

Side by Side 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: 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/base/mime_util.h"
6
7 #include <map>
8
9 #include "base/lazy_instance.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12
13 namespace media {
14
15 class MimeUtil {
16 public:
17 bool IsSupportedMediaMimeType(const std::string& mime_type) const;
18
19 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) const;
20
21 void ParseCodecString(const std::string& codecs,
22 std::vector<std::string>* codecs_out,
23 bool strip);
24
25 bool IsStrictMediaMimeType(const std::string& mime_type) const;
26 SupportsType IsSupportedStrictMediaMimeType(
27 const std::string& mime_type,
28 const std::vector<std::string>& codecs) const;
29
30 void RemoveProprietaryMediaTypesAndCodecsForTests();
31
32 private:
33 friend struct base::DefaultLazyInstanceTraits<MimeUtil>;
34
35 typedef base::hash_set<std::string> MimeMappings;
36 typedef std::map<std::string, MimeMappings> StrictMappings;
37
38 typedef std::vector<std::string> MimeExpressionMappings;
39 typedef std::map<std::string, MimeExpressionMappings>
40 StrictExpressionMappings;
41
42 MimeUtil();
43
44 // Returns true if |codecs| is nonempty and all the items in it are present in
45 // |supported_codecs|.
46 static bool AreSupportedCodecs(const MimeMappings& supported_codecs,
47 const std::vector<std::string>& codecs);
48 // Returns true is |codecs| is nonempty and all the items in it match with the
49 // codecs expression in |supported_codecs|.
50 static bool AreSupportedCodecsWithProfile(
51 const MimeExpressionMappings& supported_codecs,
52 const std::vector<std::string>& codecs);
53
54 // For faster lookup, keep hash sets.
55 void InitializeMimeTypeMaps();
56
57 MimeMappings media_map_;
58 MimeMappings codecs_map_;
59
60 // A map of mime_types and hash map of the supported codecs for the mime_type.
61 StrictMappings strict_format_map_;
62 // A map of MP4 mime_types which expect codecs with profile parameter and
63 // vector of supported codecs expressions for the mime_type.
64 StrictExpressionMappings strict_mp4_format_map_;
65 };
66
67 // This variable is Leaky because we need to access it from WorkerPool threads.
68 static base::LazyInstance<MimeUtil>::Leaky g_mime_util =
69 LAZY_INSTANCE_INITIALIZER;
70
71
72 // A list of media types: http://en.wikipedia.org/wiki/Internet_media_type
73 // A comprehensive mime type list: http://plugindoc.mozdev.org/winmime.php
74 // This set of codecs is supported by all variations of Chromium.
75 static const char* const common_media_types[] = {
76 // Ogg.
77 "audio/ogg",
78 "application/ogg",
79 #if !defined(OS_ANDROID) // Android doesn't support Ogg Theora.
80 "video/ogg",
81 #endif
82
83 // WebM.
84 "video/webm",
85 "audio/webm",
86
87 // Wav.
88 "audio/wav",
89 "audio/x-wav",
90
91 #if defined(OS_ANDROID)
92 // HLS. Supported by Android ICS and above.
93 "application/vnd.apple.mpegurl",
94 "application/x-mpegurl",
95 #endif
96 };
97
98 // List of proprietary types only supported by Google Chrome.
99 static const char* const proprietary_media_types[] = {
100 // MPEG-4.
101 "video/mp4",
102 "video/x-m4v",
103 "audio/mp4",
104 "audio/x-m4a",
105
106 // MP3.
107 "audio/mp3",
108 "audio/x-mp3",
109 "audio/mpeg",
110 };
111
112 // List of supported codecs when passed in with <source type="...">.
113 // This set of codecs is supported by all variations of Chromium.
114 //
115 // Refer to http://wiki.whatwg.org/wiki/Video_type_parameters#Browser_Support
116 // for more information.
117 //
118 // The codecs for WAV are integers as defined in Appendix A of RFC2361:
119 // http://tools.ietf.org/html/rfc2361
120 static const char* const common_media_codecs[] = {
121 #if !defined(OS_ANDROID) // Android doesn't support Ogg Theora.
122 "theora",
123 #endif
124 "opus",
125 "vorbis",
126 "vp8",
127 "vp9",
128 "1" // WAVE_FORMAT_PCM.
129 };
130
131 // List of proprietary codecs only supported by Google Chrome.
132 static const char* const proprietary_media_codecs[] = {
133 "avc1",
134 "avc3",
135 "mp4a"
136 };
137
138 #if defined(OS_ANDROID)
139 static bool IsCodecSupportedOnAndroid(const std::string& codec) {
140 // Theora is not supported in Android
141 if (!codec.compare("theora"))
142 return false;
143
144 // VP9 is supported only in KitKat+ (API Level 19).
145 if ((!codec.compare("vp9") || !codec.compare("vp9.0")) &&
146 base::android::BuildInfo::GetInstance()->sdk_int() < 19) {
147 return false;
148 }
149
150 // TODO(vigneshv): Change this similar to the VP9 check once Opus is
151 // supported on Android (http://crbug.com/318436).
152 if (!codec.compare("opus")) {
153 return false;
154 }
155 return true;
156 }
157
158 static bool IsMimeTypeSupportedOnAndroid(const std::string& mimeType) {
159 // HLS codecs are supported in ICS and above (API level 14)
160 if ((!mimeType.compare("application/vnd.apple.mpegurl") ||
161 !mimeType.compare("application/x-mpegurl")) &&
162 base::android::BuildInfo::GetInstance()->sdk_int() < 14) {
163 return false;
164 }
165 return true;
166 }
167 #endif
168
169 struct MediaFormatStrict {
170 const char* mime_type;
171 const char* codecs_list;
172 };
173
174 static const MediaFormatStrict format_codec_mappings[] = {
175 { "video/webm", "opus,vorbis,vp8,vp8.0,vp9,vp9.0" },
176 { "audio/webm", "opus,vorbis" },
177 { "audio/wav", "1" },
178 { "audio/x-wav", "1" },
179 { "video/ogg", "opus,theora,vorbis" },
180 { "audio/ogg", "opus,vorbis" },
181 { "application/ogg", "opus,theora,vorbis" },
182 { "audio/mpeg", ",mp3" }, // Note: The comma before the 'mp3'results in an
183 // empty string codec ID and indicates
184 // a missing codecs= parameter is also valid.
185 // The presense of 'mp3' is not RFC compliant,
186 // but is common in the wild so it is a defacto
187 // standard.
188 { "audio/mp3", "" },
189 { "audio/x-mp3", "" }
190 };
191
192 // Following is the list of RFC 6381 compliant codecs:
193 // mp4a.6B - MPEG-1 audio
194 // mp4a.69 - MPEG-2 extension to MPEG-1
195 // mp4a.67 - MPEG-2 AAC
196 // mp4a.40.2 - MPEG-4 AAC
197 // mp4a.40.5 - MPEG-4 HE-AAC
198 //
199 // avc1.42E0xx - H.264 Baseline
200 // avc1.4D40xx - H.264 Main
201 // avc1.6400xx - H.264 High
202 //
203 // Additionally, several non-RFC compliant codecs are allowed, due to their
204 // existing use on web.
205 // mp4a.40
206 // avc1.xxxxxx
207 // avc3.xxxxxx
208 // mp4a.6x
209 static const char kProprietaryAudioCodecsExpression[] =
210 "mp4a.6?,mp4a.40,mp4a.40.?";
211 static const char kProprietaryCodecsExpression[] =
212 "avc1,avc3,avc1.??????,avc3.??????,mp4a.6?,mp4a.40,mp4a.40.?";
213
214 static const MediaFormatStrict format_mp4_codec_mappings[] = {
215 { "audio/mp4", kProprietaryAudioCodecsExpression },
216 { "audio/x-m4a", kProprietaryAudioCodecsExpression },
217 { "video/mp4", kProprietaryCodecsExpression },
218 { "video/x-m4v", kProprietaryCodecsExpression },
219 { "application/x-mpegurl", kProprietaryCodecsExpression },
220 { "application/vnd.apple.mpegurl", kProprietaryCodecsExpression }
221 };
222
223 MimeUtil::MimeUtil() {
224 InitializeMimeTypeMaps();
225 }
226
227 // static
228 bool MimeUtil::AreSupportedCodecs(const MimeMappings& supported_codecs,
229 const std::vector<std::string>& codecs) {
230 if (supported_codecs.empty())
231 return codecs.empty();
232
233 // If no codecs are specified in the mimetype, check to see if a missing
234 // codecs parameter is allowed.
235 if (codecs.empty())
236 return supported_codecs.find(std::string()) != supported_codecs.end();
237
238 for (size_t i = 0; i < codecs.size(); ++i) {
239 if (codecs[i].empty() ||
240 supported_codecs.find(codecs[i]) == supported_codecs.end()) {
241 return false;
242 }
243 }
244
245 return true;
246 }
247
248 // Checks all the codecs present in the |codecs| against the entries in
249 // |supported_codecs|. Returns true only if |codecs| is non-empty and all the
250 // codecs match |supported_codecs| expressions.
251 bool MimeUtil::AreSupportedCodecsWithProfile(
252 const MimeExpressionMappings& supported_codecs,
253 const std::vector<std::string>& codecs) {
254 DCHECK(!supported_codecs.empty());
255 for (size_t i = 0; i < codecs.size(); ++i) {
256 bool codec_matched = false;
257 for (size_t j = 0; j < supported_codecs.size(); ++j) {
258 if (!MatchPattern(base::StringPiece(codecs[i]),
259 base::StringPiece(supported_codecs[j]))) {
260 continue;
261 }
262 // If suffix exists, check whether it is hexadecimal.
263 for (size_t wildcard_pos = supported_codecs[j].find('?');
264 wildcard_pos != std::string::npos &&
265 wildcard_pos < supported_codecs[j].length();
266 wildcard_pos = supported_codecs[j].find('?', wildcard_pos + 1)) {
267 // Don't enforce case sensitivity, even though it's called for, as it
268 // would break some websites.
269 if (wildcard_pos >= codecs[i].length() ||
270 !IsHexDigit(codecs[i].at(wildcard_pos))) {
271 return false;
272 }
273 }
274 codec_matched = true;
275 break;
276 }
277 if (!codec_matched)
278 return false;
279 }
280 return !codecs.empty();
281 }
282
283 void MimeUtil::InitializeMimeTypeMaps() {
284 // Initialize the supported media types.
285 for (size_t i = 0; i < arraysize(common_media_types); ++i) {
286 #if defined(OS_ANDROID)
287 if (!IsMimeTypeSupportedOnAndroid(common_media_types[i]))
288 continue;
289 #endif
290 media_map_.insert(common_media_types[i]);
291 }
292 #if defined(USE_PROPRIETARY_CODECS)
293 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
294 media_map_.insert(proprietary_media_types[i]);
295 #endif
296
297 for (size_t i = 0; i < arraysize(common_media_codecs); ++i) {
298 #if defined(OS_ANDROID)
299 if (!IsCodecSupportedOnAndroid(common_media_codecs[i]))
300 continue;
301 #endif
302 codecs_map_.insert(common_media_codecs[i]);
303 }
304 #if defined(USE_PROPRIETARY_CODECS)
305 for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i)
306 codecs_map_.insert(proprietary_media_codecs[i]);
307 #endif
308
309 // Initialize the strict supported media types.
310 for (size_t i = 0; i < arraysize(format_codec_mappings); ++i) {
311 std::vector<std::string> mime_type_codecs;
312 ParseCodecString(format_codec_mappings[i].codecs_list,
313 &mime_type_codecs,
314 false);
315
316 MimeMappings codecs;
317 for (size_t j = 0; j < mime_type_codecs.size(); ++j) {
318 #if defined(OS_ANDROID)
319 if (!IsCodecSupportedOnAndroid(mime_type_codecs[j]))
320 continue;
321 #endif
322 codecs.insert(mime_type_codecs[j]);
323 }
324 strict_format_map_[format_codec_mappings[i].mime_type] = codecs;
325 }
326 for (size_t i = 0; i < arraysize(format_mp4_codec_mappings); ++i) {
327 std::vector<std::string> mime_type_codecs;
328 ParseCodecString(
329 format_mp4_codec_mappings[i].codecs_list, &mime_type_codecs, false);
330
331 MimeExpressionMappings codecs;
332 for (size_t j = 0; j < mime_type_codecs.size(); ++j)
333 codecs.push_back(mime_type_codecs[j]);
334 strict_mp4_format_map_[format_mp4_codec_mappings[i].mime_type] = codecs;
335 }
336 }
337
338 bool MimeUtil::IsSupportedMediaMimeType(const std::string& mime_type) const {
339 return media_map_.find(mime_type) != media_map_.end();
340 }
341
342 bool MimeUtil::AreSupportedMediaCodecs(
343 const std::vector<std::string>& codecs) const {
344 return AreSupportedCodecs(codecs_map_, codecs);
345 }
346
347 void MimeUtil::ParseCodecString(const std::string& codecs,
348 std::vector<std::string>* codecs_out,
349 bool strip) {
350 std::string no_quote_codecs;
351 base::TrimString(codecs, "\"", &no_quote_codecs);
352 base::SplitString(no_quote_codecs, ',', codecs_out);
353
354 if (!strip)
355 return;
356
357 // Strip everything past the first '.'
358 for (std::vector<std::string>::iterator it = codecs_out->begin();
359 it != codecs_out->end();
360 ++it) {
361 size_t found = it->find_first_of('.');
362 if (found != std::string::npos)
363 it->resize(found);
364 }
365 }
366
367 bool MimeUtil::IsStrictMediaMimeType(const std::string& mime_type) const {
368 if (strict_format_map_.find(mime_type) == strict_format_map_.end() &&
369 strict_mp4_format_map_.find(mime_type) == strict_mp4_format_map_.end())
370 return false;
371 return true;
372 }
373
374 SupportsType MimeUtil::IsSupportedStrictMediaMimeType(
375 const std::string& mime_type,
376 const std::vector<std::string>& codecs) const {
377 StrictMappings::const_iterator it_strict_map =
378 strict_format_map_.find(mime_type);
379 if ((it_strict_map != strict_format_map_.end()) &&
380 AreSupportedCodecs(it_strict_map->second, codecs)) {
381 return IsSupported;
382 }
383
384 StrictExpressionMappings::const_iterator it_expression_map =
385 strict_mp4_format_map_.find(mime_type);
386 if ((it_expression_map != strict_mp4_format_map_.end()) &&
387 AreSupportedCodecsWithProfile(it_expression_map->second, codecs)) {
388 return MayBeSupported;
389 }
390
391 if (codecs.empty())
392 return MayBeSupported;
393
394 return IsNotSupported;
395 }
396
397 void MimeUtil::RemoveProprietaryMediaTypesAndCodecsForTests() {
398 for (size_t i = 0; i < arraysize(proprietary_media_types); ++i)
399 media_map_.erase(proprietary_media_types[i]);
400
401 for (size_t i = 0; i < arraysize(proprietary_media_codecs); ++i)
402 codecs_map_.erase(proprietary_media_codecs[i]);
403 }
404
405 //----------------------------------------------------------------------------
406 // Wrappers for the singleton
407 //----------------------------------------------------------------------------
408
409 bool IsSupportedMediaMimeType(const std::string& mime_type) {
410 return g_mime_util.Get().IsSupportedMediaMimeType(mime_type);
411 }
412
413 bool AreSupportedMediaCodecs(const std::vector<std::string>& codecs) {
414 return g_mime_util.Get().AreSupportedMediaCodecs(codecs);
415 }
416
417 bool IsStrictMediaMimeType(const std::string& mime_type) {
418 return g_mime_util.Get().IsStrictMediaMimeType(mime_type);
419 }
420
421 SupportsType IsSupportedStrictMediaMimeType(
422 const std::string& mime_type,
423 const std::vector<std::string>& codecs) {
424 return g_mime_util.Get().IsSupportedStrictMediaMimeType(mime_type, codecs);
425 }
426
427 void ParseCodecString(const std::string& codecs,
428 std::vector<std::string>* codecs_out,
429 const bool strip) {
430 g_mime_util.Get().ParseCodecString(codecs, codecs_out, strip);
431 }
432
433 void RemoveProprietaryMediaTypesAndCodecsForTests() {
434 g_mime_util.Get().RemoveProprietaryMediaTypesAndCodecsForTests();
435 }
436
437
438
439 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698