这一节我们要了解 MediaCodecList 中的信息是如何加载的,以及这些信息是如何使用到的。
// static
sp<IMediaCodecList> MediaCodecList::getLocalInstance() {
Mutex::Autolock autoLock(sInitMutex);
if (sCodecList == nullptr) {
MediaCodecList *codecList = new MediaCodecList(GetBuilders());
if (codecList->initCheck() == OK) {
sCodecList = codecList;
if (isProfilingNeeded()) {
ALOGV("Codec profiling needed, will be run in separated thread.");
pthread_t profiler;
if (pthread_create(&profiler, nullptr, profilerThreadWrapper, nullptr) != 0) {
ALOGW("Failed to create thread for codec profiling.");
}
}
} else {
// failure to initialize may be temporary. retry on next call.
delete codecList;
}
}
return sCodecList;
}
sp<IMediaCodecList> MediaCodecList::sRemoteList;
sp<MediaCodecList::BinderDeathObserver> MediaCodecList::sBinderDeathObserver;
sp<IBinder> MediaCodecList::sMediaPlayer; // kept since linked to death
void MediaCodecList::BinderDeathObserver::binderDied(const wp<IBinder> &who __unused) {
Mutex::Autolock _l(sRemoteInitMutex);
sRemoteList.clear();
sBinderDeathObserver.clear();
}
// static
sp<IMediaCodecList> MediaCodecList::getInstance() {
Mutex::Autolock _l(sRemoteInitMutex);
if (sRemoteList == nullptr) {
sMediaPlayer = defaultServiceManager()->getService(String16("media.player"));
sp<IMediaPlayerService> service =
interface_cast<IMediaPlayerService>(sMediaPlayer);
if (service.get() != nullptr) {
sRemoteList = service->getCodecList();
if (sRemoteList != nullptr) {
sBinderDeathObserver = new BinderDeathObserver();
sMediaPlayer->linkToDeath(sBinderDeathObserver.get());
}
}
if (sRemoteList == nullptr) {
// if failed to get remote list, create local list
sRemoteList = getLocalInstance();
}
}
return sRemoteList;
}
MediaCodecList::MediaCodecList(std::vector<MediaCodecListBuilderBase*> builders) {
mGlobalSettings = new AMessage();
mCodecInfos.clear();
MediaCodecListWriter writer;
for (MediaCodecListBuilderBase *builder : builders) {
if (builder == nullptr) {
ALOGD("ignored a null builder");
continue;
}
auto currentCheck = builder->buildMediaCodecList(&writer);
if (currentCheck != OK) {
ALOGD("ignored failed builder");
continue;
} else {
mInitCheck = currentCheck;
}
}
writer.writeGlobalSettings(mGlobalSettings);
writer.writeCodecInfos(&mCodecInfos);
std::stable_sort(
mCodecInfos.begin(),
mCodecInfos.end(),
[](const sp<MediaCodecInfo> &info1, const sp<MediaCodecInfo> &info2) {
// null is lowest
return info1 == nullptr
|| (info2 != nullptr && info1->getRank() < info2->getRank());
});
// remove duplicate entries
bool dedupe = property_get_bool("debug.stagefright.dedupe-codecs", true);
if (dedupe) {
std::set<std::string> codecsSeen;
for (auto it = mCodecInfos.begin(); it != mCodecInfos.end(); ) {
std::string codecName = (*it)->getCodecName();
if (codecsSeen.count(codecName) == 0) {
codecsSeen.emplace(codecName);
it++;
} else {
it = mCodecInfos.erase(it);
}
}
}
}
MediaCodecList::~MediaCodecList() {
}
status_t MediaCodecList::initCheck() const {
return mInitCheck;
}