我们在Android N Audio播放三:prepare大揭秘介绍了在prepare的过程中会创建Extractor, Extractor的主要作用是从容器格式中把音频和视频剥离出来,为之后的解码提供音频流和视频流,要知道。音频和视频的解码是分离的, 所以Extractor这一步非常重要。
1. Extractor流程图
如惯例,我们还是先上流程图,对这个过程涉及到的类有个大概的了解。
2. 流程详解
接下来我们就按照流程图中的步骤一步一步来细看。
2.1 GenericSource
在prepare章节介绍过,在GenericSource的onPrepareAsync中会去创建Extractor.
./frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp#onPrepareAsync
void NuPlayer::GenericSource::onPrepareAsync() {
// delayed data source creation
if (mDataSource == NULL) {
ALOGE("onPrepareAsync mDataSource is null");
// set to false first, if the extractor
// comes back as secure, set it to true then.
mIsSecure = false;
.....
//JaychouNote1:创建Extractor
// init extractor from data source
status_t err = initFromDataSource();
if (err != OK) {
ALOGE("Failed to init from data source!");
notifyPreparedAndCleanup(err);
return;
}
......
}
01-02 10:52:29.113 E/GenericSource( 646): onPrepareAsync mDataSource is null
./frameworks/av/media/libmediaplayerservice/nuplayer/GenericSource.cpp#initFromDataSource
status_t NuPlayer::GenericSource::initFromDataSource() {
ALOGE("initFromDataSource");
sp<IMediaExtractor> extractor;
String8 mimeType;
float confidence;
sp<AMessage> dummy;
bool isWidevineStreaming = false;
CHECK(mDataSource != NULL);
......
//JaychouNote1: 我们这个例子既不是widewine也不是streaming
extractor = MediaExtractor::Create(mDataSource,
mimeType.isEmpty() ? NULL : mimeType.string());
}
if (extractor == NULL) {
return UNKNOWN_ERROR;
}
if (extractor->getDrmFlag()) {
checkDrmStatus(mDataSource);
}
mFileMeta = extractor->getMetaData();
if (mFileMeta != NULL) {
int64_t duration;
if (mFileMeta->findInt64(kKeyDuration, &duration)) {
mDurationUs = duration;
}
......
//JaychouNote2: 这里的mAudioTrack和mVideoTrack就是剥离出来的音频和视频
// Do the string compare immediately with "mime",
// we can't assume "mime" would stay valid after another
// extractor operation, some extractors might modify meta
// during getTrack() and make it invalid.
if (!strncasecmp(mime, "audio/", 6)) {
if (mAudioTrack.mSource == NULL) {
mAudioTrack.mIndex = i;
mAudioTrack.mSource = track;
mAudioTrack.mPackets =
new AnotherPacketSource(mAudioTrack.mSource->getFormat());
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
mAudioIsVorbis = true;
} else {
mAudioIsVorbis = false;
}
if (AVNuUtils::get()->isByteStreamModeEnabled(meta)) {
mIsByteMode = true;
}
}
} else if (!strncasecmp(mime, "video/", 6)) {
if (mVideoTrack.mSource == NULL) {
mVideoTrack.mIndex = i;
mVideoTrack.mSource = track;
mVideoTrack.mPackets =
new AnotherPacketSource(mVideoTrack.mSource->getFormat());
// check if the source requires secure buffers
int32_t secure;
if (meta->findInt32(kKeyRequiresSecureBuffers, &secure)
&& secure) {
mIsSecure = true;
if (mUIDValid) {
extractor->setUID(mUID);
}
}
}
}
......
return OK;
}
01-02 10:52:29.115 E/GenericSource( 646): initFromDataSource
这里我们看到做了两件比较重要的事情, 一是根据source去创建extractor, 二是根据创建的extractor拿到剥离出来的音频和视频,分别是mAudioTrack和mVideoTrack。
2.2 MediaExtractor
我们来看Create.
./frameworks/av/media/libstagefright/MediaExtractor#Create
sp<IMediaExtractor> MediaExtractor::Create(
const sp<DataSource> &source, const char *mime) {
ALOGV("MediaExtractor::Create %s", mime);
char value[PROPERTY_VALUE_MAX];
if (property_get("media.stagefright.extractremote", value, NULL)
&& (!strcmp("0", value) || !strcasecmp("false", value))) {
// local extractor
ALOGW("creating media extractor in calling process");
return CreateFromService(source, mime);
} else {
// Check if it's WVM, since WVMExtractor needs to be created in the media server process,
// not the extractor process.
String8 mime8;
float confidence;
sp<AMessage> meta;
if (SniffWVM(source, &mime8, &confidence, &meta) &&
!strcas