This source file includes following definitions.
- BuildWebMParser
- GetMP4AudioObjectType
- ValidateMP4ACodecID
- BuildMP4Parser
- BuildMP3Parser
- BuildADTSParser
- BuildMP2TParser
- VerifyCodec
- CheckTypeAndCodecs
- IsTypeSupported
- Create
#include "media/filters/stream_parser_factory.h"
#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "media/base/media_log.h"
#include "media/base/media_switches.h"
#include "media/formats/mpeg/adts_stream_parser.h"
#include "media/formats/mpeg/mp3_stream_parser.h"
#include "media/formats/webm/webm_stream_parser.h"
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
#endif
#if defined(USE_PROPRIETARY_CODECS)
#if defined(ENABLE_MPEG2TS_STREAM_PARSER)
#include "media/formats/mp2t/mp2t_stream_parser.h"
#endif
#include "media/formats/mp4/es_descriptor.h"
#include "media/formats/mp4/mp4_stream_parser.h"
#endif
namespace media {
typedef bool (*CodecIDValidatorFunction)(
const std::string& codecs_id, const LogCB& log_cb);
struct CodecInfo {
enum Type {
UNKNOWN,
AUDIO,
VIDEO
};
enum HistogramTag {
HISTOGRAM_UNKNOWN,
HISTOGRAM_VP8,
HISTOGRAM_VP9,
HISTOGRAM_VORBIS,
HISTOGRAM_H264,
HISTOGRAM_MPEG2AAC,
HISTOGRAM_MPEG4AAC,
HISTOGRAM_EAC3,
HISTOGRAM_MP3,
HISTOGRAM_OPUS,
HISTOGRAM_MAX = HISTOGRAM_OPUS
};
const char* pattern;
Type type;
CodecIDValidatorFunction validator;
HistogramTag tag;
};
typedef StreamParser* (*ParserFactoryFunction)(
const std::vector<std::string>& codecs,
const LogCB& log_cb);
struct SupportedTypeInfo {
const char* type;
const ParserFactoryFunction factory_function;
const CodecInfo** codecs;
};
static const CodecInfo kVP8CodecInfo = { "vp8", CodecInfo::VIDEO, NULL,
CodecInfo::HISTOGRAM_VP8 };
static const CodecInfo kVP9CodecInfo = { "vp9", CodecInfo::VIDEO, NULL,
CodecInfo::HISTOGRAM_VP9 };
static const CodecInfo kVorbisCodecInfo = { "vorbis", CodecInfo::AUDIO, NULL,
CodecInfo::HISTOGRAM_VORBIS };
static const CodecInfo kOpusCodecInfo = { "opus", CodecInfo::AUDIO, NULL,
CodecInfo::HISTOGRAM_OPUS };
static const CodecInfo* kVideoWebMCodecs[] = {
&kVP8CodecInfo,
&kVP9CodecInfo,
&kVorbisCodecInfo,
&kOpusCodecInfo,
NULL
};
static const CodecInfo* kAudioWebMCodecs[] = {
&kVorbisCodecInfo,
&kOpusCodecInfo,
NULL
};
static StreamParser* BuildWebMParser(
const std::vector<std::string>& codecs,
const LogCB& log_cb) {
return new WebMStreamParser();
}
#if defined(USE_PROPRIETARY_CODECS)
static const int kAACLCObjectType = 2;
static const int kAACSBRObjectType = 5;
static int GetMP4AudioObjectType(const std::string& codec_id,
const LogCB& log_cb) {
int audio_object_type;
std::vector<std::string> tokens;
if (Tokenize(codec_id, ".", &tokens) != 3 ||
tokens[0] != "mp4a" || tokens[1] != "40" ||
!base::HexStringToInt(tokens[2], &audio_object_type)) {
MEDIA_LOG(log_cb) << "Malformed mimetype codec '" << codec_id << "'";
return -1;
}
return audio_object_type;
}
bool ValidateMP4ACodecID(const std::string& codec_id, const LogCB& log_cb) {
int audio_object_type = GetMP4AudioObjectType(codec_id, log_cb);
if (audio_object_type == kAACLCObjectType ||
audio_object_type == kAACSBRObjectType) {
return true;
}
MEDIA_LOG(log_cb) << "Unsupported audio object type "
<< "0x" << std::hex << audio_object_type
<< " in codec '" << codec_id << "'";
return false;
}
static const CodecInfo kH264AVC1CodecInfo = { "avc1.*", CodecInfo::VIDEO, NULL,
CodecInfo::HISTOGRAM_H264 };
static const CodecInfo kH264AVC3CodecInfo = { "avc3.*", CodecInfo::VIDEO, NULL,
CodecInfo::HISTOGRAM_H264 };
static const CodecInfo kMPEG4AACCodecInfo = { "mp4a.40.*", CodecInfo::AUDIO,
&ValidateMP4ACodecID,
CodecInfo::HISTOGRAM_MPEG4AAC };
static const CodecInfo kMPEG2AACLCCodecInfo = { "mp4a.67", CodecInfo::AUDIO,
NULL,
CodecInfo::HISTOGRAM_MPEG2AAC };
static const CodecInfo* kVideoMP4Codecs[] = {
&kH264AVC1CodecInfo,
&kH264AVC3CodecInfo,
&kMPEG4AACCodecInfo,
&kMPEG2AACLCCodecInfo,
NULL
};
static const CodecInfo* kAudioMP4Codecs[] = {
&kMPEG4AACCodecInfo,
&kMPEG2AACLCCodecInfo,
NULL
};
static StreamParser* BuildMP4Parser(
const std::vector<std::string>& codecs, const LogCB& log_cb) {
std::set<int> audio_object_types;
bool has_sbr = false;
for (size_t i = 0; i < codecs.size(); ++i) {
std::string codec_id = codecs[i];
if (MatchPattern(codec_id, kMPEG2AACLCCodecInfo.pattern)) {
audio_object_types.insert(mp4::kISO_13818_7_AAC_LC);
} else if (MatchPattern(codec_id, kMPEG4AACCodecInfo.pattern)) {
int audio_object_type = GetMP4AudioObjectType(codec_id, log_cb);
DCHECK_GT(audio_object_type, 0);
audio_object_types.insert(mp4::kISO_14496_3);
if (audio_object_type == kAACSBRObjectType) {
has_sbr = true;
break;
}
}
}
return new mp4::MP4StreamParser(audio_object_types, has_sbr);
}
static const CodecInfo kMP3CodecInfo = { NULL, CodecInfo::AUDIO, NULL,
CodecInfo::HISTOGRAM_MP3 };
static const CodecInfo* kAudioMP3Codecs[] = {
&kMP3CodecInfo,
NULL
};
static StreamParser* BuildMP3Parser(
const std::vector<std::string>& codecs, const LogCB& log_cb) {
return new MP3StreamParser();
}
static const CodecInfo kADTSCodecInfo = { NULL, CodecInfo::AUDIO, NULL,
CodecInfo::HISTOGRAM_MPEG4AAC };
static const CodecInfo* kAudioADTSCodecs[] = {
&kADTSCodecInfo,
NULL
};
static StreamParser* BuildADTSParser(
const std::vector<std::string>& codecs, const LogCB& log_cb) {
return new ADTSStreamParser();
}
#if defined(ENABLE_MPEG2TS_STREAM_PARSER)
static const CodecInfo* kVideoMP2TCodecs[] = {
&kH264AVC1CodecInfo,
&kH264AVC3CodecInfo,
&kMPEG4AACCodecInfo,
&kMPEG2AACLCCodecInfo,
NULL
};
static StreamParser* BuildMP2TParser(
const std::vector<std::string>& codecs, const media::LogCB& log_cb) {
bool has_sbr = false;
for (size_t i = 0; i < codecs.size(); ++i) {
std::string codec_id = codecs[i];
if (MatchPattern(codec_id, kMPEG4AACCodecInfo.pattern) &&
GetMP4AudioObjectType(codec_id, log_cb) == kAACSBRObjectType) {
has_sbr = true;
}
}
return new media::mp2t::Mp2tStreamParser(has_sbr);
}
#endif
#endif
static const SupportedTypeInfo kSupportedTypeInfo[] = {
{ "video/webm", &BuildWebMParser, kVideoWebMCodecs },
{ "audio/webm", &BuildWebMParser, kAudioWebMCodecs },
#if defined(USE_PROPRIETARY_CODECS)
{ "audio/aac", &BuildADTSParser, kAudioADTSCodecs },
{ "audio/mpeg", &BuildMP3Parser, kAudioMP3Codecs },
{ "video/mp4", &BuildMP4Parser, kVideoMP4Codecs },
{ "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs },
#if defined(ENABLE_MPEG2TS_STREAM_PARSER)
{ "video/mp2t", &BuildMP2TParser, kVideoMP2TCodecs },
#endif
#endif
};
static bool VerifyCodec(
const CodecInfo* codec_info,
std::vector<CodecInfo::HistogramTag>* audio_codecs,
std::vector<CodecInfo::HistogramTag>* video_codecs) {
switch (codec_info->type) {
case CodecInfo::AUDIO:
#if defined(ENABLE_EAC3_PLAYBACK)
if (codec_info->tag == CodecInfo::HISTOGRAM_EAC3) {
const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
if (!cmd_line->HasSwitch(switches::kEnableEac3Playback))
return false;
}
#endif
if (audio_codecs)
audio_codecs->push_back(codec_info->tag);
return true;
case CodecInfo::VIDEO:
#if defined(OS_ANDROID)
if (codec_info->tag == CodecInfo::HISTOGRAM_VP9 &&
base::android::BuildInfo::GetInstance()->sdk_int() < 19) {
return false;
}
#endif
if (video_codecs)
video_codecs->push_back(codec_info->tag);
return true;
default:
DVLOG(1) << "CodecInfo type of " << codec_info->type
<< " should not be specified in a SupportedTypes list";
return false;
}
}
static bool CheckTypeAndCodecs(
const std::string& type,
const std::vector<std::string>& codecs,
const LogCB& log_cb,
ParserFactoryFunction* factory_function,
std::vector<CodecInfo::HistogramTag>* audio_codecs,
std::vector<CodecInfo::HistogramTag>* video_codecs) {
for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
if (type == type_info.type) {
if (codecs.empty()) {
#if defined(USE_PROPRIETARY_CODECS)
if (type_info.codecs == kAudioADTSCodecs &&
!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableADTSStreamParser)) {
DVLOG(1) << "ADTSStreamParser is not enabled.";
return false;
}
#endif
const CodecInfo* codec_info = type_info.codecs[0];
if (codec_info && !codec_info->pattern &&
VerifyCodec(codec_info, audio_codecs, video_codecs)) {
if (factory_function)
*factory_function = type_info.factory_function;
return true;
}
MEDIA_LOG(log_cb) << "A codecs parameter must be provided for '"
<< type << "'";
return false;
}
for (size_t j = 0; j < codecs.size(); ++j) {
bool found_codec = false;
std::string codec_id = codecs[j];
for (int k = 0; type_info.codecs[k]; ++k) {
if (MatchPattern(codec_id, type_info.codecs[k]->pattern) &&
(!type_info.codecs[k]->validator ||
type_info.codecs[k]->validator(codec_id, log_cb))) {
found_codec =
VerifyCodec(type_info.codecs[k], audio_codecs, video_codecs);
break;
}
}
if (!found_codec) {
MEDIA_LOG(log_cb) << "Codec '" << codec_id
<< "' is not supported for '" << type << "'";
return false;
}
}
if (factory_function)
*factory_function = type_info.factory_function;
return true;
}
}
return false;
}
bool StreamParserFactory::IsTypeSupported(
const std::string& type, const std::vector<std::string>& codecs) {
return CheckTypeAndCodecs(type, codecs, LogCB(), NULL, NULL, NULL);
}
scoped_ptr<StreamParser> StreamParserFactory::Create(
const std::string& type,
const std::vector<std::string>& codecs,
const LogCB& log_cb,
bool* has_audio,
bool* has_video) {
scoped_ptr<StreamParser> stream_parser;
ParserFactoryFunction factory_function;
std::vector<CodecInfo::HistogramTag> audio_codecs;
std::vector<CodecInfo::HistogramTag> video_codecs;
*has_audio = false;
*has_video = false;
if (CheckTypeAndCodecs(type,
codecs,
log_cb,
&factory_function,
&audio_codecs,
&video_codecs)) {
*has_audio = !audio_codecs.empty();
*has_video = !video_codecs.empty();
UMA_HISTOGRAM_COUNTS_100("Media.MSE.NumberOfTracks", codecs.size());
for (size_t i = 0; i < audio_codecs.size(); ++i) {
UMA_HISTOGRAM_ENUMERATION("Media.MSE.AudioCodec",
audio_codecs[i],
CodecInfo::HISTOGRAM_MAX + 1);
}
for (size_t i = 0; i < video_codecs.size(); ++i) {
UMA_HISTOGRAM_ENUMERATION("Media.MSE.VideoCodec",
video_codecs[i],
CodecInfo::HISTOGRAM_MAX + 1);
}
stream_parser.reset(factory_function(codecs, log_cb));
}
return stream_parser.Pass();
}
}