在 prepare 阶段 GenericSource 中有调用 initFromDataSource 来解析源文件 :
status_t NuPlayer::GenericSource::initFromDataSource() {
sp<IMediaExtractor> extractor;
sp<DataSource> dataSource;
{
Mutex::Autolock _l_d(mDisconnectLock);
dataSource = mDataSource;
}
CHECK(dataSource != NULL);
mLock.unlock();
// This might take long time if data source is not reliable.
extractor = MediaExtractorFactory::Create(dataSource, NULL);
if (extractor == NULL) {
ALOGE("initFromDataSource, cannot create extractor!");
mLock.lock();
return UNKNOWN_ERROR;
}
sp<MetaData> fileMeta = extractor->getMetaData();
size_t numtracks = extractor->countTracks();
if (numtracks == 0) {
ALOGE("initFromDataSource, source has no track!");
mLock.lock();
return UNKNOWN_ERROR;
}
mLock.lock();
mFileMeta = fileMeta;
if (mFileMeta != NULL) {
int64_t duration;
if (mFileMeta->findInt64(kKeyDuration, &duration)) {
mDurationUs = duration;
}
}
int32_t totalBitrate = 0;
mMimes.clear();
for (size_t i = 0; i < numtracks; ++i) {
sp<IMediaSource> track = extractor->getTrack(i);
if (track == NULL) {
continue;
}
sp<MetaData> meta = extractor->getTrackMetaData(i);
if (meta == NULL) {
ALOGE("no metadata for track %zu", i);
return UNKNOWN_ERROR;
}
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
ALOGV("initFromDataSource track[%zu]: %s", i, mime);
// 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;
}
mMimes.add(String8(mime));
}
} else if (!strncasecmp(mime, "video/", 6)) {
if (mVideoTrack.mSource == NULL) {
mVideoTrack.mIndex = i;
mVideoTrack.mSource = track;
mVideoTrack.mPackets =
new AnotherPacketSource(mVideoTrack.mSource->getFormat());
// video always at the beginning
mMimes.insertAt(String8(mime), 0);
}
}
mSources.push(track);
int64_t durationUs;
if (meta->findInt64(kKeyDuration, &durationUs)) {
if (durationUs > mDurationUs) {
mDurationUs = durationUs;
}
}
int32_t bitrate;
if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
totalBitrate += bitrate;
} else {
totalBitrate = -1;
}
}
ALOGV("initFromDataSource mSources.size(): %zu mIsSecure: %d mime[0]: %s", mSources.size(),
mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string()));
if (mSources.size() == 0) {
ALOGE("b/23705695");
return UNKNOWN_ERROR;
}
// Modular DRM: The return value doesn't affect source initialization.
(void)checkDrmInfo();
mBitrate = totalBitrate;
return OK;
}
MediaExtractorFactory::Create
先来看 extractor = MediaExtractorFactory::Create(dataSource, NULL);
frameworks/av/media/libstagefright/MediaExtractorFactory.cpp
sp<IMediaExtractor> MediaExtractorFactory::Create(
const sp<DataSource> &source, const char *mime) {
ALOGV("MediaExtractorFactory::Create %s", mime);
if (!property_get_bool("media.stagefright.extractremote", true)) {
// local extractor
ALOGW("creating media extractor in calling process");
return CreateFromService(source, mime);
} else {
// remote extractor
ALOGV("get service manager");
sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
if (binder != 0) {
sp<IMediaExtractorService> mediaExService(
interface_cast<IMediaExtractorService>(binder));
sp<IMediaExtractor> ex;
mediaExService->makeExtractor(
CreateIDataSourceFromDataSource(source),
mime ? std::make_unique<std::string>(mime) : nullptr,
&ex);
return ex;
} else {
ALOGE("extractor service not running");
return NULL;
}
}
return NULL;
}
默认 media.stagefright.extractremote 为空,所以会到 else 中使用 remote extractor, 获取到MediaExtractorService 的代理之后, 调用 makeExtractor
frameworks/av/services/mediaextractor/MediaExtractorService.cpp
::android::binder::Status MediaExtractorService::makeExtractor(
const ::android::sp<::android::IDataSource>& remoteSource,
const ::std::unique_ptr< ::std::string> &mime,
::android::sp<::android::IMediaExtractor>* _aidl_return) {
ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime.get()->c_str());
sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
MediaBuffer::useSharedMemory();
sp<IMediaExtractor> extractor = MediaExtractorFactory::CreateFromService(
localSource,
mime.get() ? mime.get()->c_str() : nullptr);
ALOGV("extractor service created %p (%s)",
extractor.get(),
extractor == nullptr ? "" : extractor->name());
if (extractor != nullptr) {
registerMediaExtractor(extractor, localSource, mime.get() ? mime.get()->c_str() : nullptr);
}
*_aidl_return = extractor; //返回创建好的 extractor
return binder::Status::ok();
}
这里将 IDataSource 转换为 DataSource 之后重点在 MediaExtractorFactory::CreateFromService
sp<IMediaExtractor> MediaExtractorFactory::CreateFromService(
const sp<DataSource> &source, const char *mime) {
ALOGV("MediaExtractorFactory::CreateFromService %s", mime);
void *meta = nullptr;
void *creator = NULL;
FreeMetaFunc freeMeta = nullptr;
float confidence;
sp<ExtractorPlugin> plugin;
uint32_t creatorVersion = 0;
creator = sniff(source, &confidence, &meta, &freeMeta, plugin, &creatorVersion);
if (!creator) {
ALOGV("FAILED to autodetect media content.");
return NULL;
}
MediaExtractor *ex = nullptr;
if (creatorVersion == EXTRACTORDEF_VERSION_NDK_V1 ||
creatorVersion == EXTRACTORDEF_VERSION_NDK_V2) {
CMediaExtractor *ret = ((CreatorFunc)creator)(source->wrap(), meta);
if (meta != nullptr && freeMeta != nullptr) {
freeMeta(meta);
}
ex = ret != nullptr ? new MediaExtractorCUnwrapper(ret) : nullptr;
}
ALOGV("Created an extractor '%s' with confidence %.2f",
ex != nullptr ? ex->name() : "<null>", confidence);
return CreateIMediaExtractorFromMediaExtractor(ex, source, plugin);
}
先来看这里的 sniff 函数
void *MediaExtractorFactory::sniff(
const sp<DataSource> &source, float *confidence, void **meta,
FreeMetaFunc *freeMeta, sp<ExtractorPlugin> &plugin, uint32_t *creatorVersion) {
*confidence = 0.0f;
*meta = nullptr;
std::shared_ptr<std::list<sp<ExtractorPlugin>>> plugins;
{
Mutex::Autolock autoLock(gPluginMutex);
if (!gPluginsRegistered) {
return NULL;
}
plugins = gPlugins;
}
void *bestCreator = NULL;
for (auto it = plugins->begin(); it != plugins->end(); ++it) {
ALOGV("sniffing %s", (*it)->def.extractor_name);
float newConfidence;
void *newMeta = nullptr;
FreeMetaFunc newFreeMeta = nullptr;
void *curCreator = NULL;
if ((*it)->def.def_version == EXTRACTORDEF_VERSION_NDK_V1) {
curCreator = (void*) (*it)->def.u.v2.sniff(
source->wrap(), &newConfidence, &newMeta, &newFreeMeta);
} else if ((*it)->def.def_version == EXTRACTORDEF_VERSION_NDK_V2) {
curCreator = (void*) (*it)->def.u.v3.sniff(
source->wrap(), &newConfidence, &newMeta, &newFreeMeta);
}
if (curCreator) {
if (newConfidence > *confidence) {
*confidence = newConfidence;
if (*meta != nullptr && *freeMeta != nullptr) {
(*freeMeta)(*meta);
}
*meta = newMeta;
*freeMeta = newFreeMeta;
plugin = *it;
bestCreator = curCreator;
*creatorVersion = (*it)->def.def_version;
} else {
if (newMeta != nullptr && newFreeMeta != nullptr) {
newFreeMeta(newMeta);
}
}
}
}
return bestCreator;
}
这里需要注意到一个变量 gPlugins , 他是 MediaExtractorService 实例化时加载的 extractor 列表,实际log 有:
MediaExtractorService: extractor service created 0xb4000077be868a50 (MMParserExtractor) MediaExtractorFactory: sniffing MP4 Extractor MediaExtractorFactory: sniffing MPEG2-PS/TS Extractor MediaExtractorFactory: sniffing Matroska Extractor MediaExtractorFactory: sniffing Ogg Extractor MediaExtractorFactory: sniffing QCOM Extractor MediaExtractorFactory: sniffing WAV Extractor MediaExtractorFactory: Created an extractor ‘MMParserExtractor’ with confidence 0.80
这里会根据各个 extractor 的 sniff 方法获得一个分数值,最后使用分数最高的 extractor , 这里获得的就是 某个extractor 的实例, 而 meta 这是由具体的 extractor 来写入,但并不是都会写入,所以有的返回值会为null.
在获得 extractor 之后在用 在 CreateFromService 会调用 CreateIMediaExtractorFromMediaExtractor 在做一层封装这样就可以跨进程访问MediaExtractor .
最后回到 makeExtractor 中调用 registerMediaExtractor 将创建好的 extractor 保存到 MediaExtractorService 中方便以后使用, 其中也会保存 caller 的 pid .