Replace remaining Tokenize calls to SplitString
[chromium-blink-merge.git] / media / filters / stream_parser_factory.cc
blob9ea2b0e3a2dd7a68c0a923a13fa8aa9803dedbc0
1 // Copyright (c) 2013 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.
5 #include "media/filters/stream_parser_factory.h"
7 #include "base/command_line.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/pattern.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_util.h"
13 #include "media/base/media_switches.h"
14 #include "media/formats/mpeg/adts_stream_parser.h"
15 #include "media/formats/mpeg/mpeg1_audio_stream_parser.h"
16 #include "media/formats/webm/webm_stream_parser.h"
18 #if defined(OS_ANDROID)
19 #include "base/android/build_info.h"
20 #endif
22 #if defined(USE_PROPRIETARY_CODECS)
23 #if defined(ENABLE_MPEG2TS_STREAM_PARSER)
24 #include "media/formats/mp2t/mp2t_stream_parser.h"
25 #endif
26 #include "media/formats/mp4/es_descriptor.h"
27 #include "media/formats/mp4/mp4_stream_parser.h"
28 #endif
30 namespace media {
32 typedef bool (*CodecIDValidatorFunction)(
33 const std::string& codecs_id, const LogCB& log_cb);
35 struct CodecInfo {
36 enum Type {
37 UNKNOWN,
38 AUDIO,
39 VIDEO
42 // Update tools/metrics/histograms/histograms.xml if new values are added.
43 enum HistogramTag {
44 HISTOGRAM_UNKNOWN,
45 HISTOGRAM_VP8,
46 HISTOGRAM_VP9,
47 HISTOGRAM_VORBIS,
48 HISTOGRAM_H264,
49 HISTOGRAM_MPEG2AAC,
50 HISTOGRAM_MPEG4AAC,
51 HISTOGRAM_EAC3,
52 HISTOGRAM_MP3,
53 HISTOGRAM_OPUS,
54 HISTOGRAM_MAX = HISTOGRAM_OPUS // Must be equal to largest logged entry.
57 const char* pattern;
58 Type type;
59 CodecIDValidatorFunction validator;
60 HistogramTag tag;
63 typedef StreamParser* (*ParserFactoryFunction)(
64 const std::vector<std::string>& codecs,
65 const LogCB& log_cb);
67 struct SupportedTypeInfo {
68 const char* type;
69 const ParserFactoryFunction factory_function;
70 const CodecInfo** codecs;
73 static const CodecInfo kVP8CodecInfo = { "vp8", CodecInfo::VIDEO, NULL,
74 CodecInfo::HISTOGRAM_VP8 };
75 static const CodecInfo kVP9CodecInfo = { "vp9", CodecInfo::VIDEO, NULL,
76 CodecInfo::HISTOGRAM_VP9 };
77 static const CodecInfo kVorbisCodecInfo = { "vorbis", CodecInfo::AUDIO, NULL,
78 CodecInfo::HISTOGRAM_VORBIS };
79 static const CodecInfo kOpusCodecInfo = { "opus", CodecInfo::AUDIO, NULL,
80 CodecInfo::HISTOGRAM_OPUS };
82 static const CodecInfo* kVideoWebMCodecs[] = {
83 &kVP8CodecInfo,
84 &kVP9CodecInfo,
85 &kVorbisCodecInfo,
86 &kOpusCodecInfo,
87 NULL
90 static const CodecInfo* kAudioWebMCodecs[] = {
91 &kVorbisCodecInfo,
92 &kOpusCodecInfo,
93 NULL
96 static StreamParser* BuildWebMParser(
97 const std::vector<std::string>& codecs,
98 const LogCB& log_cb) {
99 return new WebMStreamParser();
102 #if defined(USE_PROPRIETARY_CODECS)
103 // AAC Object Type IDs that Chrome supports.
104 static const int kAACLCObjectType = 2;
105 static const int kAACSBRObjectType = 5;
106 static const int kAACPSObjectType = 29;
108 static int GetMP4AudioObjectType(const std::string& codec_id,
109 const LogCB& log_cb) {
110 // From RFC 6381 section 3.3 (ISO Base Media File Format Name Space):
111 // When the first element of a ['codecs' parameter value] is 'mp4a' ...,
112 // the second element is a hexadecimal representation of the MP4 Registration
113 // Authority ObjectTypeIndication (OTI). Note that MP4RA uses a leading "0x"
114 // with these values, which is omitted here and hence implied.
115 std::vector<base::StringPiece> tokens = base::SplitStringPiece(
116 codec_id, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
117 if (tokens.size() == 3 && tokens[0] == "mp4a" && tokens[1] == "40") {
118 // From RFC 6381 section 3.3:
119 // One of the OTI values for 'mp4a' is 40 (identifying MPEG-4 audio). For
120 // this value, the third element identifies the audio ObjectTypeIndication
121 // (OTI) ... expressed as a decimal number.
122 int audio_object_type;
123 if (base::StringToInt(tokens[2], &audio_object_type))
124 return audio_object_type;
127 MEDIA_LOG(DEBUG, log_cb) << "Malformed mimetype codec '" << codec_id << "'";
128 return -1;
131 bool ValidateMP4ACodecID(const std::string& codec_id, const LogCB& log_cb) {
132 int audio_object_type = GetMP4AudioObjectType(codec_id, log_cb);
133 if (audio_object_type == kAACLCObjectType ||
134 audio_object_type == kAACSBRObjectType ||
135 audio_object_type == kAACPSObjectType) {
136 return true;
139 MEDIA_LOG(DEBUG, log_cb) << "Unsupported audio object type "
140 << audio_object_type << " in codec '" << codec_id
141 << "'";
142 return false;
145 static const CodecInfo kH264AVC1CodecInfo = { "avc1.*", CodecInfo::VIDEO, NULL,
146 CodecInfo::HISTOGRAM_H264 };
147 static const CodecInfo kH264AVC3CodecInfo = { "avc3.*", CodecInfo::VIDEO, NULL,
148 CodecInfo::HISTOGRAM_H264 };
149 static const CodecInfo kMPEG4AACCodecInfo = { "mp4a.40.*", CodecInfo::AUDIO,
150 &ValidateMP4ACodecID,
151 CodecInfo::HISTOGRAM_MPEG4AAC };
152 static const CodecInfo kMPEG2AACLCCodecInfo = { "mp4a.67", CodecInfo::AUDIO,
153 NULL,
154 CodecInfo::HISTOGRAM_MPEG2AAC };
156 static const CodecInfo* kVideoMP4Codecs[] = {
157 &kH264AVC1CodecInfo,
158 &kH264AVC3CodecInfo,
159 &kMPEG4AACCodecInfo,
160 &kMPEG2AACLCCodecInfo,
161 NULL
164 static const CodecInfo* kAudioMP4Codecs[] = {
165 &kMPEG4AACCodecInfo,
166 &kMPEG2AACLCCodecInfo,
167 NULL
170 static StreamParser* BuildMP4Parser(
171 const std::vector<std::string>& codecs, const LogCB& log_cb) {
172 std::set<int> audio_object_types;
174 bool has_sbr = false;
175 for (size_t i = 0; i < codecs.size(); ++i) {
176 std::string codec_id = codecs[i];
177 if (base::MatchPattern(codec_id, kMPEG2AACLCCodecInfo.pattern)) {
178 audio_object_types.insert(mp4::kISO_13818_7_AAC_LC);
179 } else if (base::MatchPattern(codec_id, kMPEG4AACCodecInfo.pattern)) {
180 int audio_object_type = GetMP4AudioObjectType(codec_id, log_cb);
181 DCHECK_GT(audio_object_type, 0);
183 audio_object_types.insert(mp4::kISO_14496_3);
185 if (audio_object_type == kAACSBRObjectType ||
186 audio_object_type == kAACPSObjectType) {
187 has_sbr = true;
188 break;
193 return new mp4::MP4StreamParser(audio_object_types, has_sbr);
196 static const CodecInfo kMP3CodecInfo = { NULL, CodecInfo::AUDIO, NULL,
197 CodecInfo::HISTOGRAM_MP3 };
199 static const CodecInfo* kAudioMP3Codecs[] = {
200 &kMP3CodecInfo,
201 NULL
204 static StreamParser* BuildMP3Parser(
205 const std::vector<std::string>& codecs, const LogCB& log_cb) {
206 return new MPEG1AudioStreamParser();
209 static const CodecInfo kADTSCodecInfo = { NULL, CodecInfo::AUDIO, NULL,
210 CodecInfo::HISTOGRAM_MPEG4AAC };
211 static const CodecInfo* kAudioADTSCodecs[] = {
212 &kADTSCodecInfo,
213 NULL
216 static StreamParser* BuildADTSParser(
217 const std::vector<std::string>& codecs, const LogCB& log_cb) {
218 return new ADTSStreamParser();
221 #if defined(ENABLE_MPEG2TS_STREAM_PARSER)
222 static const CodecInfo* kVideoMP2TCodecs[] = {
223 &kH264AVC1CodecInfo,
224 &kH264AVC3CodecInfo,
225 &kMPEG4AACCodecInfo,
226 &kMPEG2AACLCCodecInfo,
227 NULL
230 static StreamParser* BuildMP2TParser(
231 const std::vector<std::string>& codecs, const media::LogCB& log_cb) {
232 bool has_sbr = false;
233 for (size_t i = 0; i < codecs.size(); ++i) {
234 std::string codec_id = codecs[i];
235 if (base::MatchPattern(codec_id, kMPEG4AACCodecInfo.pattern)) {
236 int audio_object_type = GetMP4AudioObjectType(codec_id, log_cb);
237 if (audio_object_type == kAACSBRObjectType ||
238 audio_object_type == kAACPSObjectType) {
239 has_sbr = true;
244 return new media::mp2t::Mp2tStreamParser(has_sbr);
246 #endif
247 #endif
250 static const SupportedTypeInfo kSupportedTypeInfo[] = {
251 { "video/webm", &BuildWebMParser, kVideoWebMCodecs },
252 { "audio/webm", &BuildWebMParser, kAudioWebMCodecs },
253 #if defined(USE_PROPRIETARY_CODECS)
254 { "audio/aac", &BuildADTSParser, kAudioADTSCodecs },
255 { "audio/mpeg", &BuildMP3Parser, kAudioMP3Codecs },
256 { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs },
257 { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs },
258 #if defined(ENABLE_MPEG2TS_STREAM_PARSER)
259 { "video/mp2t", &BuildMP2TParser, kVideoMP2TCodecs },
260 #endif
261 #endif
264 // Verify that |codec_info| is supported on this platform.
266 // Returns true if |codec_info| is a valid audio/video codec and is allowed.
267 // |audio_codecs| has |codec_info|.tag added to its list if |codec_info| is an
268 // audio codec. |audio_codecs| may be NULL, in which case it is not updated.
269 // |video_codecs| has |codec_info|.tag added to its list if |codec_info| is a
270 // video codec. |video_codecs| may be NULL, in which case it is not updated.
272 // Returns false otherwise, and |audio_codecs| and |video_codecs| not touched.
273 static bool VerifyCodec(
274 const CodecInfo* codec_info,
275 std::vector<CodecInfo::HistogramTag>* audio_codecs,
276 std::vector<CodecInfo::HistogramTag>* video_codecs) {
277 switch (codec_info->type) {
278 case CodecInfo::AUDIO:
279 if (audio_codecs)
280 audio_codecs->push_back(codec_info->tag);
281 return true;
282 case CodecInfo::VIDEO:
283 #if defined(OS_ANDROID)
284 // VP9 is only supported on KitKat+ (API Level 19).
285 if (codec_info->tag == CodecInfo::HISTOGRAM_VP9 &&
286 base::android::BuildInfo::GetInstance()->sdk_int() < 19) {
287 return false;
289 // Opus is only supported on Lollipop+ (API Level 21).
290 if (codec_info->tag == CodecInfo::HISTOGRAM_OPUS &&
291 base::android::BuildInfo::GetInstance()->sdk_int() < 21) {
292 return false;
294 #endif
295 if (video_codecs)
296 video_codecs->push_back(codec_info->tag);
297 return true;
298 default:
299 // Not audio or video, so skip it.
300 DVLOG(1) << "CodecInfo type of " << codec_info->type
301 << " should not be specified in a SupportedTypes list";
302 return false;
306 // Checks to see if the specified |type| and |codecs| list are supported.
308 // Returns true if |type| and all codecs listed in |codecs| are supported.
309 // |factory_function| contains a function that can build a StreamParser for this
310 // type. Value may be NULL, in which case it is not touched.
311 // |audio_codecs| is updated with the appropriate HistogramTags for matching
312 // audio codecs specified in |codecs|. Value may be NULL, in which case it is
313 // not touched.
314 // |video_codecs| is updated with the appropriate HistogramTags for matching
315 // video codecs specified in |codecs|. Value may be NULL, in which case it is
316 // not touched.
318 // Returns false otherwise. The values of |factory_function|, |audio_codecs|,
319 // and |video_codecs| are undefined.
320 static bool CheckTypeAndCodecs(
321 const std::string& type,
322 const std::vector<std::string>& codecs,
323 const LogCB& log_cb,
324 ParserFactoryFunction* factory_function,
325 std::vector<CodecInfo::HistogramTag>* audio_codecs,
326 std::vector<CodecInfo::HistogramTag>* video_codecs) {
328 // Search for the SupportedTypeInfo for |type|.
329 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
330 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
331 if (type == type_info.type) {
332 if (codecs.empty()) {
333 const CodecInfo* codec_info = type_info.codecs[0];
334 if (codec_info && !codec_info->pattern &&
335 VerifyCodec(codec_info, audio_codecs, video_codecs)) {
337 if (factory_function)
338 *factory_function = type_info.factory_function;
339 return true;
342 MEDIA_LOG(DEBUG, log_cb) << "A codecs parameter must be provided for '"
343 << type << "'";
344 return false;
347 // Make sure all the codecs specified in |codecs| are
348 // in the supported type info.
349 for (size_t j = 0; j < codecs.size(); ++j) {
350 // Search the type info for a match.
351 bool found_codec = false;
352 std::string codec_id = codecs[j];
353 for (int k = 0; type_info.codecs[k]; ++k) {
354 if (base::MatchPattern(codec_id, type_info.codecs[k]->pattern) &&
355 (!type_info.codecs[k]->validator ||
356 type_info.codecs[k]->validator(codec_id, log_cb))) {
357 found_codec =
358 VerifyCodec(type_info.codecs[k], audio_codecs, video_codecs);
359 break; // Since only 1 pattern will match, no need to check others.
363 if (!found_codec) {
364 MEDIA_LOG(DEBUG, log_cb) << "Codec '" << codec_id
365 << "' is not supported for '" << type << "'";
366 return false;
370 if (factory_function)
371 *factory_function = type_info.factory_function;
373 // All codecs were supported by this |type|.
374 return true;
378 // |type| didn't match any of the supported types.
379 return false;
382 bool StreamParserFactory::IsTypeSupported(
383 const std::string& type, const std::vector<std::string>& codecs) {
384 return CheckTypeAndCodecs(type, codecs, LogCB(), NULL, NULL, NULL);
387 scoped_ptr<StreamParser> StreamParserFactory::Create(
388 const std::string& type,
389 const std::vector<std::string>& codecs,
390 const LogCB& log_cb,
391 bool* has_audio,
392 bool* has_video) {
393 scoped_ptr<StreamParser> stream_parser;
394 ParserFactoryFunction factory_function;
395 std::vector<CodecInfo::HistogramTag> audio_codecs;
396 std::vector<CodecInfo::HistogramTag> video_codecs;
397 *has_audio = false;
398 *has_video = false;
400 if (CheckTypeAndCodecs(type,
401 codecs,
402 log_cb,
403 &factory_function,
404 &audio_codecs,
405 &video_codecs)) {
406 *has_audio = !audio_codecs.empty();
407 *has_video = !video_codecs.empty();
409 // Log the number of codecs specified, as well as the details on each one.
410 UMA_HISTOGRAM_COUNTS_100("Media.MSE.NumberOfTracks", codecs.size());
411 for (size_t i = 0; i < audio_codecs.size(); ++i) {
412 UMA_HISTOGRAM_ENUMERATION("Media.MSE.AudioCodec",
413 audio_codecs[i],
414 CodecInfo::HISTOGRAM_MAX + 1);
416 for (size_t i = 0; i < video_codecs.size(); ++i) {
417 UMA_HISTOGRAM_ENUMERATION("Media.MSE.VideoCodec",
418 video_codecs[i],
419 CodecInfo::HISTOGRAM_MAX + 1);
422 stream_parser.reset(factory_function(codecs, log_cb));
425 return stream_parser.Pass();
428 } // namespace media