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/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "media/base/media_log.h"
12 #include "media/base/media_switches.h"
13 #include "media/mp3/mp3_stream_parser.h"
14 #include "media/webm/webm_stream_parser.h"
16 #if defined(USE_PROPRIETARY_CODECS)
17 #if defined(ENABLE_MPEG2TS_STREAM_PARSER)
18 #include "media/mp2t/mp2t_stream_parser.h"
20 #include "media/mp4/es_descriptor.h"
21 #include "media/mp4/mp4_stream_parser.h"
26 typedef bool (*CodecIDValidatorFunction)(
27 const std::string& codecs_id, const LogCB& log_cb);
36 // Update tools/metrics/histograms/histograms.xml if new values are added.
48 HISTOGRAM_MAX // Must be the last entry.
53 CodecIDValidatorFunction validator;
57 typedef StreamParser* (*ParserFactoryFunction)(
58 const std::vector<std::string>& codecs,
61 struct SupportedTypeInfo {
63 const ParserFactoryFunction factory_function;
64 const CodecInfo** codecs;
67 static const CodecInfo kVP8CodecInfo = { "vp8", CodecInfo::VIDEO, NULL,
68 CodecInfo::HISTOGRAM_VP8 };
69 #if !defined(OS_ANDROID)
70 static const CodecInfo kVP9CodecInfo = { "vp9", CodecInfo::VIDEO, NULL,
71 CodecInfo::HISTOGRAM_VP9 };
73 static const CodecInfo kVorbisCodecInfo = { "vorbis", CodecInfo::AUDIO, NULL,
74 CodecInfo::HISTOGRAM_VORBIS };
75 static const CodecInfo kOpusCodecInfo = { "opus", CodecInfo::AUDIO, NULL,
76 CodecInfo::HISTOGRAM_OPUS };
78 static const CodecInfo* kVideoWebMCodecs[] = {
80 #if !defined(OS_ANDROID)
81 // TODO(wonsik): crbug.com/285016 query Android platform for codec
90 static const CodecInfo* kAudioWebMCodecs[] = {
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;
107 static int GetMP4AudioObjectType(const std::string& codec_id,
108 const LogCB& log_cb) {
109 int audio_object_type;
110 std::vector<std::string> tokens;
111 if (Tokenize(codec_id, ".", &tokens) != 3 ||
112 tokens[0] != "mp4a" || tokens[1] != "40" ||
113 !base::HexStringToInt(tokens[2], &audio_object_type)) {
114 MEDIA_LOG(log_cb) << "Malformed mimetype codec '" << codec_id << "'";
119 return audio_object_type;
122 bool ValidateMP4ACodecID(const std::string& codec_id, const LogCB& log_cb) {
123 int audio_object_type = GetMP4AudioObjectType(codec_id, log_cb);
124 if (audio_object_type == kAACLCObjectType ||
125 audio_object_type == kAACSBRObjectType) {
129 MEDIA_LOG(log_cb) << "Unsupported audio object type "
130 << "0x" << std::hex << audio_object_type
131 << " in codec '" << codec_id << "'";
135 static const CodecInfo kH264AVC1CodecInfo = { "avc1.*", CodecInfo::VIDEO, NULL,
136 CodecInfo::HISTOGRAM_H264 };
137 static const CodecInfo kH264AVC3CodecInfo = { "avc3.*", CodecInfo::VIDEO, NULL,
138 CodecInfo::HISTOGRAM_H264 };
139 static const CodecInfo kMPEG4AACCodecInfo = { "mp4a.40.*", CodecInfo::AUDIO,
140 &ValidateMP4ACodecID,
141 CodecInfo::HISTOGRAM_MPEG4AAC };
142 static const CodecInfo kMPEG2AACLCCodecInfo = { "mp4a.67", CodecInfo::AUDIO,
144 CodecInfo::HISTOGRAM_MPEG2AAC };
146 #if defined(ENABLE_EAC3_PLAYBACK)
147 static const CodecInfo kEAC3CodecInfo = { "mp4a.a6", CodecInfo::AUDIO, NULL,
148 CodecInfo::HISTOGRAM_EAC3 };
151 static const CodecInfo* kVideoMP4Codecs[] = {
155 &kMPEG2AACLCCodecInfo,
159 static const CodecInfo* kAudioMP4Codecs[] = {
161 &kMPEG2AACLCCodecInfo,
162 #if defined(ENABLE_EAC3_PLAYBACK)
168 static StreamParser* BuildMP4Parser(
169 const std::vector<std::string>& codecs, const LogCB& log_cb) {
170 std::set<int> audio_object_types;
172 bool has_sbr = false;
173 #if defined(ENABLE_EAC3_PLAYBACK)
174 bool enable_eac3 = CommandLine::ForCurrentProcess()->HasSwitch(
175 switches::kEnableEac3Playback);
177 for (size_t i = 0; i < codecs.size(); ++i) {
178 std::string codec_id = codecs[i];
179 if (MatchPattern(codec_id, kMPEG2AACLCCodecInfo.pattern)) {
180 audio_object_types.insert(mp4::kISO_13818_7_AAC_LC);
181 } else if (MatchPattern(codec_id, kMPEG4AACCodecInfo.pattern)) {
182 int audio_object_type = GetMP4AudioObjectType(codec_id, log_cb);
183 DCHECK_GT(audio_object_type, 0);
185 audio_object_types.insert(mp4::kISO_14496_3);
187 if (audio_object_type == kAACSBRObjectType) {
191 #if defined(ENABLE_EAC3_PLAYBACK)
192 } else if (enable_eac3 && MatchPattern(codec_id, kEAC3CodecInfo.pattern)) {
193 audio_object_types.insert(mp4::kEAC3);
198 return new mp4::MP4StreamParser(audio_object_types, has_sbr);
201 static const CodecInfo kMP3CodecInfo = { NULL, CodecInfo::AUDIO, NULL,
202 CodecInfo::HISTOGRAM_MP3 };
204 static const CodecInfo* kAudioMP3Codecs[] = {
209 static StreamParser* BuildMP3Parser(
210 const std::vector<std::string>& codecs, const LogCB& log_cb) {
211 return new MP3StreamParser();
214 #if defined(ENABLE_MPEG2TS_STREAM_PARSER)
215 static const CodecInfo* kVideoMP2TCodecs[] = {
218 &kMPEG2AACLCCodecInfo,
222 static StreamParser* BuildMP2TParser(
223 const std::vector<std::string>& codecs, const media::LogCB& log_cb) {
224 return new media::mp2t::Mp2tStreamParser();
230 static const SupportedTypeInfo kSupportedTypeInfo[] = {
231 { "video/webm", &BuildWebMParser, kVideoWebMCodecs },
232 { "audio/webm", &BuildWebMParser, kAudioWebMCodecs },
233 #if defined(USE_PROPRIETARY_CODECS)
234 { "audio/mpeg", &BuildMP3Parser, kAudioMP3Codecs },
235 { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs },
236 { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs },
237 #if defined(ENABLE_MPEG2TS_STREAM_PARSER)
238 { "video/mp2t", &BuildMP2TParser, kVideoMP2TCodecs },
243 // Verify that |codec_info| is supported on this platform.
245 // Returns true if |codec_info| is a valid audio/video codec and is allowed.
246 // |audio_codecs| has |codec_info|.tag added to its list if |codec_info| is an
247 // audio codec. |audio_codecs| may be NULL, in which case it is not updated.
248 // |video_codecs| has |codec_info|.tag added to its list if |codec_info| is a
249 // video codec. |video_codecs| may be NULL, in which case it is not updated.
251 // Returns false otherwise, and |audio_codecs| and |video_codecs| not touched.
252 static bool VerifyCodec(
253 const CodecInfo* codec_info,
254 std::vector<CodecInfo::HistogramTag>* audio_codecs,
255 std::vector<CodecInfo::HistogramTag>* video_codecs) {
256 switch (codec_info->type) {
257 case CodecInfo::AUDIO:
258 #if defined(ENABLE_EAC3_PLAYBACK)
259 if (codec_info->tag == CodecInfo::HISTOGRAM_EAC3) {
260 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
261 if (!cmd_line->HasSwitch(switches::kEnableEac3Playback))
265 if (codec_info->tag == CodecInfo::HISTOGRAM_OPUS) {
266 const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
267 if (!cmd_line->HasSwitch(switches::kEnableOpusPlayback))
271 audio_codecs->push_back(codec_info->tag);
273 case CodecInfo::VIDEO:
275 video_codecs->push_back(codec_info->tag);
278 // Not audio or video, so skip it.
279 DVLOG(1) << "CodecInfo type of " << codec_info->type
280 << " should not be specified in a SupportedTypes list";
285 // Checks to see if the specified |type| and |codecs| list are supported.
287 // Returns true if |type| and all codecs listed in |codecs| are supported.
288 // |factory_function| contains a function that can build a StreamParser for this
289 // type. Value may be NULL, in which case it is not touched.
290 // |audio_codecs| is updated with the appropriate HistogramTags for matching
291 // audio codecs specified in |codecs|. Value may be NULL, in which case it is
293 // |video_codecs| is updated with the appropriate HistogramTags for matching
294 // video codecs specified in |codecs|. Value may be NULL, in which case it is
297 // Returns false otherwise. The values of |factory_function|, |audio_codecs|,
298 // and |video_codecs| are undefined.
299 static bool CheckTypeAndCodecs(
300 const std::string& type,
301 const std::vector<std::string>& codecs,
303 ParserFactoryFunction* factory_function,
304 std::vector<CodecInfo::HistogramTag>* audio_codecs,
305 std::vector<CodecInfo::HistogramTag>* video_codecs) {
307 // Search for the SupportedTypeInfo for |type|.
308 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
309 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
310 if (type == type_info.type) {
311 if (codecs.empty()) {
313 #if defined(USE_PROPRIETARY_CODECS)
314 if (type_info.codecs == kAudioMP3Codecs &&
315 !CommandLine::ForCurrentProcess()->HasSwitch(
316 switches::kEnableMP3StreamParser)) {
317 DVLOG(1) << "MP3StreamParser is not enabled.";
322 const CodecInfo* codec_info = type_info.codecs[0];
323 if (codec_info && !codec_info->pattern &&
324 VerifyCodec(codec_info, audio_codecs, video_codecs)) {
326 if (factory_function)
327 *factory_function = type_info.factory_function;
331 MEDIA_LOG(log_cb) << "A codecs parameter must be provided for '"
336 // Make sure all the codecs specified in |codecs| are
337 // in the supported type info.
338 for (size_t j = 0; j < codecs.size(); ++j) {
339 // Search the type info for a match.
340 bool found_codec = false;
341 std::string codec_id = codecs[j];
342 for (int k = 0; type_info.codecs[k]; ++k) {
343 if (MatchPattern(codec_id, type_info.codecs[k]->pattern) &&
344 (!type_info.codecs[k]->validator ||
345 type_info.codecs[k]->validator(codec_id, log_cb))) {
347 VerifyCodec(type_info.codecs[k], audio_codecs, video_codecs);
348 break; // Since only 1 pattern will match, no need to check others.
353 MEDIA_LOG(log_cb) << "Codec '" << codec_id
354 << "' is not supported for '" << type << "'";
359 if (factory_function)
360 *factory_function = type_info.factory_function;
362 // All codecs were supported by this |type|.
367 // |type| didn't match any of the supported types.
371 bool StreamParserFactory::IsTypeSupported(
372 const std::string& type, const std::vector<std::string>& codecs) {
373 return CheckTypeAndCodecs(type, codecs, LogCB(), NULL, NULL, NULL);
376 scoped_ptr<StreamParser> StreamParserFactory::Create(
377 const std::string& type,
378 const std::vector<std::string>& codecs,
382 scoped_ptr<StreamParser> stream_parser;
383 ParserFactoryFunction factory_function;
384 std::vector<CodecInfo::HistogramTag> audio_codecs;
385 std::vector<CodecInfo::HistogramTag> video_codecs;
389 if (CheckTypeAndCodecs(type,
395 *has_audio = !audio_codecs.empty();
396 *has_video = !video_codecs.empty();
398 // Log the number of codecs specified, as well as the details on each one.
399 UMA_HISTOGRAM_COUNTS_100("Media.MSE.NumberOfTracks", codecs.size());
400 for (size_t i = 0; i < audio_codecs.size(); ++i) {
401 UMA_HISTOGRAM_ENUMERATION(
402 "Media.MSE.AudioCodec", audio_codecs[i], CodecInfo::HISTOGRAM_MAX);
404 for (size_t i = 0; i < video_codecs.size(); ++i) {
405 UMA_HISTOGRAM_ENUMERATION(
406 "Media.MSE.VideoCodec", video_codecs[i], CodecInfo::HISTOGRAM_MAX);
409 stream_parser.reset(factory_function(codecs, log_cb));
412 return stream_parser.Pass();