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

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

Powered by Google App Engine
This is Rietveld 408576698