公司网站建设推广方案模板,在线平台,网站的建设方法有哪些内容,秦皇岛开发区媒体编解码API使用示例
//获取相关格式文件的内容信息#xff0c;如轨道数量、获取MIME信息、视频的高度与宽度、语言格式、播放总时长等
MediaExtractor mediaExtractor new MediaExtractor();
try {mediaExtractor.setDataSource(path); // 设置数据源
} catch (IOExcept…媒体编解码API使用示例
//获取相关格式文件的内容信息如轨道数量、获取MIME信息、视频的高度与宽度、语言格式、播放总时长等
MediaExtractor mediaExtractor new MediaExtractor();
try {mediaExtractor.setDataSource(path); // 设置数据源
} catch (IOException e1) {e1.printStackTrace();
}String mimeType null; // video/mp4v-es - MPEG4 video audio/3gpp - AMR narrowband audio
for (int i 0; i mediaExtractor.getTrackCount(); i) { // 信道总数MediaFormat format mediaExtractor.getTrackFormat(i); // 音频文件信息mimeType format.getString(MediaFormat.KEY_MIME);if (mimeType.startsWith(video/)) { // 视频信道mediaExtractor.selectTrack(i); // 切换到视频信道try {mediaCodec MediaCodec.createDecoderByType(mimeType); // 创建解码器,提供数据输出} catch (IOException e) {e.printStackTrace();}mediaCodec.configure(format, surface, null, 0);break;}
}
mediaCodec.start(); // 启动MediaCodec 等待传入数据
1.createDecoderByType根据MimeType信息创建相匹配的解码器。
public static MediaCodec createDecoderByType(NonNull String type)throws IOException {return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
}private MediaCodec(NonNull String name, boolean nameIsType, boolean encoder) {Looper looper;if ((looper Looper.myLooper()) ! null) {mEventHandler new EventHandler(this, looper);} else if ((looper Looper.getMainLooper()) ! null) {mEventHandler new EventHandler(this, looper);} else {mEventHandler null;}mCallbackHandler mEventHandler;mOnFrameRenderedHandler mEventHandler;mBufferLock new Object();native_setup(name, nameIsType, encoder);
}
通过JNI调用到MediaCodec.cpp
static void android_media_MediaCodec_native_setup(spJMediaCodec codec new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
}JMediaCodec::JMediaCodec(JNIEnv *env, jobject thiz,const char *name, bool nameIsType, bool encoder): mClass(NULL),mObject(NULL) {
...if (nameIsType) {mCodec MediaCodec::CreateByType(mLooper, name, encoder, mInitStatus);} else {mCodec MediaCodec::CreateByComponentName(mLooper, name, mInitStatus);}CHECK((mCodec ! NULL) ! (mInitStatus ! OK));
}
2.CreateByType创建对应的MediaCodec并初始化
// frameworks\av\media\libstagefright\MediaCodec.cpp
spMediaCodec MediaCodec::CreateByType(const spALooper looper, const AString mime, bool encoder, status_t *err, pid_t pid,uid_t uid) {VectorAString matchingCodecs;// 1.根据mime获取对应的codecMediaCodecList::findMatchingCodecs(mime.c_str(),encoder,0,matchingCodecs);if (err ! NULL) {*err NAME_NOT_FOUND;}//2.创建对应的MediaCodec并初始化for (size_t i 0; i matchingCodecs.size(); i) {spMediaCodec codec new MediaCodec(looper, pid, uid);AString componentName matchingCodecs[i];status_t ret codec-init(componentName);if (err ! NULL) {*err ret;}if (ret OK) {return codec;}ALOGD(Allocating component %s failed (%d), try next one.,componentName.c_str(), ret);}return NULL;
}
3.findMatchingCodecs获取对应的codec
先获取支持的编解码器列表再匹配最佳的编解码器
//frameworks\av\media\libstagefright\MediaCodecList.cpp
void MediaCodecList::findMatchingCodecs(const char *mime, bool encoder, uint32_t flags,VectorAString *matches) {matches-clear();// 获取系统支持的编解码器列表const spIMediaCodecList list getInstance();if (list nullptr) {return;}//匹配最佳的编解码器size_t index 0;for (;;) {ssize_t matchIndex list-findCodecByType(mime, encoder, index);if (matchIndex 0) {break;}index matchIndex 1;const spMediaCodecInfo info list-getCodecInfo(matchIndex);CHECK(info ! nullptr);AString componentName info-getCodecName();if ((flags kHardwareCodecsOnly) isSoftwareCodec(componentName)) {ALOGV(skipping SW codec %s, componentName.c_str());} else {matches-push(componentName);ALOGV(matching %s, componentName.c_str());}}if (flags kPreferSoftwareCodecs ||property_get_bool(debug.stagefright.swcodec, false)) {matches-sort(compareSoftwareCodecsFirst);}
}
4.获取系统支持的Codec列表
先通过binder调到MediaPlayerService的getCodecList函数
//frameworks\av\media\libstagefright\MediaCodecList.cpp
spIMediaCodecList MediaCodecList::getInstance() {Mutex::Autolock _l(sRemoteInitMutex);if (sRemoteList nullptr) {spIBinder binder defaultServiceManager()-getService(String16(media.player));spIMediaPlayerService service interface_castIMediaPlayerService(binder);if (service.get() ! nullptr) {// 获取服务端的MediaCodecListsRemoteList service-getCodecList();if (sRemoteList ! nullptr) {sBinderDeathObserver new BinderDeathObserver();binder-linkToDeath(sBinderDeathObserver.get());}}if (sRemoteList nullptr) {// if failed to get remote list, create local listsRemoteList getLocalInstance();}}return sRemoteList;
}
可以看到又回到了MediaCodecList没错就是media/stagefright下的MediaCodecList 说明MediaCodecList的创建是在mediaplayerservice进程
//frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp
spIMediaCodecList MediaPlayerService::getCodecList() const {return MediaCodecList::getLocalInstance();
} GetBuilders()作为参数创建MediaCodecList单例并返回关键在于GetBuilders()函数
//frameworks\av\media\libstagefright\MediaCodecList.cpp
spIMediaCodecList 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;
}GetBuilders
std::vectorMediaCodecListBuilderBase * GetBuilders() {std::vectorMediaCodecListBuilderBase * builders;// if plugin provides the input surface, we cannot use OMX video encoders.// In this case, rely on plugin to provide list of OMX codecs that are usable.spPersistentSurface surfaceTest StagefrightPluginLoader::GetCCodecInstance()-createInputSurface();if (surfaceTest nullptr) {builders.push_back(sOmxInfoBuilder);}builders.push_back(GetCodec2InfoBuilder());return builders;
}
5.构造MediaCodecList
frameworks\av\media\libstagefright\MediaCodecList.cpp
MediaCodecList::MediaCodecList(std::vectorMediaCodecListBuilderBase* builders) {mGlobalSettings new AMessage();mCodecInfos.clear();MediaCodecListWriter writer;for (MediaCodecListBuilderBase *builder : builders) {if (builder nullptr) {ALOGD(ignored a null builder);continue;}// 进入build的buildMediaCodecList函数mInitCheck builder-buildMediaCodecList(writer);if (mInitCheck ! OK) {break;}}writer.writeGlobalSettings(mGlobalSettings);writer.writeCodecInfos(mCodecInfos);std::stable_sort(mCodecInfos.begin(),mCodecInfos.end(),[](const spMediaCodecInfo info1, const spMediaCodecInfo info2) {if (info2 nullptr) {return false;} else if (info1 nullptr) {return true;} else {return info1-rank() info2-rank();}});
}
通过OmxInfoBuilder创建MediaCodec列表途径一 1、通过HIDL调用到OmxStore.cpp, 通过OmxStore从xml解析支持的CodecList及Attributes 2、将支持的codec存储进swCodecName2Info, hwCodecName2Info
//frameworks\av\media\libstagefright\OmxInfoBuilder.cpp
status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {// Obtain IOmxStorespIOmxStore omxStore IOmxStore::getService();if (omxStore nullptr) {ALOGE(Cannot find an IOmxStore service.);return NO_INIT;}// List service attributes (global settings)Status status;hidl_vecIOmxStore::RoleInfo roles;// 通过HIDL获取inRoleListauto transStatus omxStore-listRoles([roles] (const hidl_vecIOmxStore::RoleInfo inRoleList) {roles inRoleList;});if (!transStatus.isOk()) {ALOGE(Fail to obtain codec roles from IOmxStore.);return NO_INIT;}hidl_vecIOmxStore::ServiceAttribute serviceAttributes;transStatus omxStore-listServiceAttributes([status, serviceAttributes] (Status inStatus,const hidl_vecIOmxStore::ServiceAttribute inAttributes) {status inStatus;serviceAttributes inAttributes;});if (!transStatus.isOk()) {ALOGE(Fail to obtain global settings from IOmxStore.);return NO_INIT;}if (status ! Status::OK) {ALOGE(IOmxStore reports parsing error.);return NO_INIT;}for (const auto p : serviceAttributes) {writer-addGlobalSetting(p.key.c_str(), p.value.c_str());}// Convert roles to lists of codecs// codec name - index into swCodecs/hwCodecsstd::maphidl_string, std::unique_ptrMediaCodecInfoWriterswCodecName2Info, hwCodecName2Info;char rank[PROPERTY_VALUE_MAX];uint32_t defaultRank 0x100;if (property_get(debug.stagefright.omx_default_rank, rank, nullptr)) {defaultRank std::strtoul(rank, nullptr, 10);}//将支持的codec存储进swCodecName2Info, hwCodecName2Infofor (const IOmxStore::RoleInfo role : roles) {const hidl_string typeName role.type;bool isEncoder role.isEncoder;bool preferPlatformNodes role.preferPlatformNodes;// If preferPlatformNodes is true, hardware nodes must be added after// platform (software) nodes. hwCodecs is used to hold hardware nodes// that need to be added after software nodes for the same role.std::vectorconst IOmxStore::NodeInfo* hwCodecs;for (const IOmxStore::NodeInfo node : role.nodes) {const hidl_string nodeName node.name;// OMX.google开头的都是软解码bool isSoftware hasPrefix(nodeName, OMX.google);MediaCodecInfoWriter* info;if (isSoftware) {auto c2i swCodecName2Info.find(nodeName);if (c2i swCodecName2Info.end()) {// Create a new MediaCodecInfo for a new node.c2i swCodecName2Info.insert(std::make_pair(nodeName, writer-addMediaCodecInfo())).first;info c2i-second.get();info-setName(nodeName.c_str());info-setOwner(node.owner.c_str());info-setEncoder(isEncoder);info-setRank(defaultRank);} else {// The node has been seen before. Simply retrieve the// existing MediaCodecInfoWriter.info c2i-second.get();}} else {auto c2i hwCodecName2Info.find(nodeName);if (c2i hwCodecName2Info.end()) {// Create a new MediaCodecInfo for a new node.if (!preferPlatformNodes) {c2i hwCodecName2Info.insert(std::make_pair(nodeName, writer-addMediaCodecInfo())).first;info c2i-second.get();info-setName(nodeName.c_str());info-setOwner(node.owner.c_str());info-setEncoder(isEncoder);info-setRank(defaultRank);} else {// If preferPlatformNodes is true, this node must be// added after all software nodes.hwCodecs.push_back(node);continue;}} else {// The node has been seen before. Simply retrieve the// existing MediaCodecInfoWriter.info c2i-second.get();}}std::unique_ptrMediaCodecInfo::CapabilitiesWriter caps info-addMime(typeName.c_str());if (queryCapabilities(node, typeName.c_str(), isEncoder, caps.get()) ! OK) {ALOGW(Fail to add mime %s to codec %s,typeName.c_str(), nodeName.c_str());info-removeMime(typeName.c_str());}}。。。}return OK;
}
通过OmxStore.cpp解析xml中的编解码器及属性 OmxStore.cpp读取的配置文件有 实际项目在 /vendor/etc 中
//frameworks\av\media\libstagefright\xmlparser\include\media\stagefright\xmlparser\MediaCodecsXmlParser.h
static constexpr char const* defaultSearchDirs[] {/odm/etc, /vendor/etc, /etc, nullptr};
static constexpr char const* defaultMainXmlName media_codecs.xml;
static constexpr char const* defaultPerformanceXmlName media_codecs_performance.xml;
static constexpr char const* defaultProfilingResultsXmlPath /data/misc/media/media_codecs_profiling_results.xml;获取对应解码器的查询能力实际为创建对应得解码器
//frameworks\av\media\libstagefright\OmxInfoBuilder.cpp
status_t queryCapabilities(const IOmxStore::NodeInfo node, const char* mime, bool isEncoder,MediaCodecInfo::CapabilitiesWriter* caps) {spACodec codec new ACodec();status_t err codec-queryCapabilities(node.owner.c_str(), node.name.c_str(), mime, isEncoder, caps); // ...
}
依靠binder机制调用OMX服务中的allocateNode()
//frameworks\av\media\libstagefright\ACodec.cpp
status_t ACodec::queryCapabilities(const char* owner, const char* name, const char* mime, bool isEncoder,MediaCodecInfo::CapabilitiesWriter* caps) {const char *role AVUtils::get()-getComponentRole(isEncoder, mime);if (role NULL) {return BAD_VALUE;}OMXClient client;// 获取名为“” Omx实现status_t err client.connect(owner);if (err ! OK) {return err;}// 获取omx bp代理对象spIOMX omx client.interface();spCodecObserver observer new CodecObserver;spIOMXNode omxNode;// hidl远程调用allocateNodeerr omx-allocateNode(name, observer, omxNoe);// ...
}
获取服务名为XXXX的OMX并以LWOmx封装返回
frameworks\av\media\libstagefright\OMXClient.cpp
status_t OMXClient::connect(const char* name) {using namespace ::android::hardware::media::omx::V1_0;if (name nullptr) {name default;}spIOmx tOmx IOmx::getService(name);if (tOmx.get() nullptr) {ALOGE(Cannot obtain IOmx service.);return NO_INIT;}if (!tOmx-isRemote()) {ALOGE(IOmx service running in passthrough mode.);return NO_INIT;}mOMX new utils::LWOmx(tOmx);ALOGI(IOmx service obtained);return OK;
}
6.allocateNode创建对应的解码器
LWOmx是代理具体的实现在libstagefright_omx.so
//frameworks\av\media\libmedia\omx\1.0\WOmx.cpp
status_t LWOmx::allocateNode(char const* name,spIOMXObserver const observer,spIOMXNode* omxNode) {status_t fnStatus;// allocateNodestatus_t transStatus toStatusT(mBase-allocateNode(name, new TWOmxObserver(observer),[fnStatus, omxNode](Status status, spIOmxNode const node) {fnStatus toStatusT(status);*omxNode new LWOmxNode(node);}));return transStatus NO_ERROR ? fnStatus : transStatus;
}
6.1 创建对应的OMXNodeInstance对象
OMXNodeInstance对象持有一些关键信息比如生成的节点id(mNodeID)、ACodec传递下来的observer、plugin里创建的解码组件handle和构造OMXNodeInstance时传入的omx对象等。还有关键的解码事件返回的kCallbacks。
//frameworks\av\media\libstagefright\omx\1.0\Omx.cpp
//libstagefright_omx.so
Returnvoid Omx::allocateNode(const hidl_string name,const spIOmxObserver observer,allocateNode_cb _hidl_cb) {using ::android::IOMXNode;using ::android::IOMXObserver;spOMXNodeInstance instance;{Mutex::Autolock autoLock(mLock);if (mLiveNodes.size() kMaxNodeInstances) {_hidl_cb(toStatus(NO_MEMORY), nullptr);return Void();}// 1. 实例化OMXNodeInstance对象存放node id、解码组件handle、ACodec传递下来的observer等instance new OMXNodeInstance(this, new LWOmxObserver(observer), name.c_str());OMX_COMPONENTTYPE *handle;// 2. master通知plugin创建对应的解码组件、并返回其操作句柄 OMX_ERRORTYPE err mMaster-makeComponentInstance(name.c_str(), OMXNodeInstance::kCallbacks,instance.get(), handle);if (err ! OMX_ErrorNone) {LOG(ERROR) Failed to allocate omx component name.c_str() err asString(err) (0x std::hex unsigned(err) );_hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);return Void();}instance-setHandle(handle);// Find quirks from mParserconst auto codec mParser.getCodecMap().find(name.c_str());if (codec mParser.getCodecMap().cend()) {LOG(WARNING) Failed to obtain quirks for omx component name.c_str() from XML files;} else {uint32_t quirks 0;for (const auto quirk : codec-second.quirkSet) {if (quirk requires-allocate-on-input-ports) {quirks | OMXNodeInstance::kRequiresAllocateBufferOnInputPorts;}if (quirk requires-allocate-on-output-ports) {quirks | OMXNodeInstance::kRequiresAllocateBufferOnOutputPorts;}}instance-setQuirks(quirks);}mLiveNodes.add(observer.get(), instance);mNode2Observer.add(instance.get(), observer.get());}observer-linkToDeath(this, 0);_hidl_cb(toStatus(OK), new TWOmxNode(instance));return Void();
}// frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp
// static
OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks {OnEvent, OnEmptyBufferDone, OnFillBufferDone
};
6.2 makeComponentInstance
OMXMaster是解码库加载的核心 先找到指定的plugin解码器组件有厂商定制的及AOSP的、再通知plugin去创建对应的解码组件。
frameworks\av\media\libstagefright\omx\OMXMaster.cpp
OMX_ERRORTYPE OMXMaster::makeComponentInstance(const char *name,const OMX_CALLBACKTYPE *callbacks,OMX_PTR appData,OMX_COMPONENTTYPE **component) {ALOGI(makeComponentInstance(%s) in %s process, name, mProcessName);Mutex::Autolock autoLock(mLock);*component NULL;// 找到对应的Pluginssize_t index mPluginByComponentName.indexOfKey(String8(name));if (index 0) {return OMX_ErrorInvalidComponentName;}OMXPluginBase *plugin mPluginByComponentName.valueAt(index);// 创建对应的解码组件OMX_ERRORTYPE err plugin-makeComponentInstance(name, callbacks, appData, component);if (err ! OMX_ErrorNone) {return err;}mPluginByInstance.add(*component, plugin);return err;
}这些解码器是在哪加载的呢回到OMXMaster构造函数
加载软硬编解码管理器中的所有解码器并存在mPluginByComponentName。 1.加载厂商编解码管理器libstagefrighthw.so 2.加载软编解码管理器SoftOMXPlugin
OMXMaster::OMXMaster(): mVendorLibHandle(NULL) {pid_t pid getpid();char filename[20];snprintf(filename, sizeof(filename), /proc/%d/comm, pid);int fd open(filename, O_RDONLY);if (fd 0) {ALOGW(couldnt determine process name);strlcpy(mProcessName, unknown, sizeof(mProcessName));} else {ssize_t len read(fd, mProcessName, sizeof(mProcessName));if (len 2) {ALOGW(couldnt determine process name);strlcpy(mProcessName, unknown, sizeof(mProcessName));} else {// the name is newline terminated, so erase the newlinemProcessName[len - 1] 0;}close(fd);}//加载厂商解码器SOaddVendorPlugin();//加载软解码器SOaddPlugin(new SoftOMXPlugin);
}void OMXMaster::addVendorPlugin() {addPlugin(libstagefrighthw.so);
}
7 实际创建对应解码器makeComponentInstance
如果是软件编解码器调用SoftOMXPlugin的makeComponentInstance 如果是硬件就调用QComOMXPlugin的makeComponentInstance Component可以理解为一个解码器实例。
7.1 软解码器
1.根据mime name匹配kComponents数据如 { OMX.google.aac.decoder, aacdec, audio_decoder.aac }, 2. 拿到的mLibNameSuffix值为aacdec最后拼接的libName是libstagefright_soft_aacdec.so 3. 从system/lib目录下加载libstagefright_soft_aacdec.so库 4. 调用其对应的createSoftOMXComponent函数创建SoftOMXComponent
// frameworks\av\media\libstagefright\omx\SoftOMXComponent.cpp
OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance(const char *name,const OMX_CALLBACKTYPE *callbacks,OMX_PTR appData,OMX_COMPONENTTYPE **component) {ALOGV(makeComponentInstance %s, name);for (size_t i 0; i kNumComponents; i) {// 1.根据name匹配kComponents数据// 如 { OMX.google.aac.decoder, aacdec, audio_decoder.aac },if (strcmp(name, kComponents[i].mName)) {continue;}// 2. 拿到的mLibNameSuffix值为aacdec最后拼接的libName是libstagefright_soft_aacdec.soAString libName libstagefright_soft_;libName.append(kComponents[i].mLibNameSuffix);libName.append(.so);// RTLD_NODELETE means we keep the shared library around forever.// this eliminates thrashing during sequences like loading soundpools.// It also leaves the rest of the logic around the dlopen()/dlclose()// calls in this file unchanged.//// Implications of the change:// -- the codec process (where this happens) will have a slightly larger// long-term memory footprint as it accumulates the loaded shared libraries.// This is expected to be a small amount of memory.// -- plugin codecs can no longer (and never should have) depend on a// free reset of any static data as the library would have crossed// a dlclose/dlopen cycle.//// 3. 从system/lib目录下加载libstagefright_soft_aacdec.so库void *libHandle dlopen(libName.c_str(), RTLD_NOW|RTLD_NODELETE);if (libHandle NULL) {ALOGE(unable to dlopen %s: %s, libName.c_str(), dlerror());return OMX_ErrorComponentNotFound;}typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)(const char *, const OMX_CALLBACKTYPE *,OMX_PTR, OMX_COMPONENTTYPE **);CreateSoftOMXComponentFunc createSoftOMXComponent (CreateSoftOMXComponentFunc)dlsym(libHandle,_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPEPvPP17OMX_COMPONENTTYPE);if (createSoftOMXComponent NULL) {dlclose(libHandle);libHandle NULL;return OMX_ErrorComponentNotFound;}// 4. 创建对应的SoftOMXComponentspSoftOMXComponent codec (*createSoftOMXComponent)(name, callbacks, appData, component);if (codec NULL) {dlclose(libHandle);libHandle NULL;return OMX_ErrorInsufficientResources;}OMX_ERRORTYPE err codec-initCheck();if (err ! OMX_ErrorNone) {dlclose(libHandle);libHandle NULL;return err;}codec-incStrong(this);codec-setLibHandle(libHandle);return OMX_ErrorNone;}return OMX_ErrorInvalidComponentName;
}
SoftOmxPlugin是google提供的原生的一套编解码器插件 即通常说的软解硬解中的软解。它支持市面上常用的音视频格式软解码支持的格式
// frameworks\av\media\libstagefright\omx\SoftOMXPlugin.cpp
static const struct {const char *mName;const char *mLibNameSuffix;const char *mRole;} kComponents[] {// two choices for aac decoding.// configurable in media/libstagefright/data/media_codecs_google_audio.xml// default implementation{ OMX.google.aac.decoder, aacdec, audio_decoder.aac },// alternate implementation{ OMX.google.xaac.decoder, xaacdec, audio_decoder.aac },{ OMX.google.aac.encoder, aacenc, audio_encoder.aac },{ OMX.google.amrnb.decoder, amrdec, audio_decoder.amrnb },{ OMX.google.amrnb.encoder, amrnbenc, audio_encoder.amrnb },{ OMX.google.amrwb.decoder, amrdec, audio_decoder.amrwb },{ OMX.google.amrwb.encoder, amrwbenc, audio_encoder.amrwb },{ OMX.google.h264.decoder, avcdec, video_decoder.avc },{ OMX.google.h264.encoder, avcenc, video_encoder.avc },{ OMX.google.hevc.decoder, hevcdec, video_decoder.hevc },{ OMX.google.g711.alaw.decoder, g711dec, audio_decoder.g711alaw },{ OMX.google.g711.mlaw.decoder, g711dec, audio_decoder.g711mlaw },{ OMX.google.mpeg2.decoder, mpeg2dec, video_decoder.mpeg2 },{ OMX.google.h263.decoder, mpeg4dec, video_decoder.h263 },{ OMX.google.h263.encoder, mpeg4enc, video_encoder.h263 },{ OMX.google.mpeg4.decoder, mpeg4dec, video_decoder.mpeg4 },{ OMX.google.mpeg4.encoder, mpeg4enc, video_encoder.mpeg4 },{ OMX.google.mp3.decoder, mp3dec, audio_decoder.mp3 },{ OMX.google.vorbis.decoder, vorbisdec, audio_decoder.vorbis },{ OMX.google.opus.decoder, opusdec, audio_decoder.opus },{ OMX.google.vp8.decoder, vpxdec, video_decoder.vp8 },{ OMX.google.vp9.decoder, vpxdec, video_decoder.vp9 },{ OMX.google.vp8.encoder, vpxenc, video_encoder.vp8 },{ OMX.google.vp9.encoder, vpxenc, video_encoder.vp9 },{ OMX.google.raw.decoder, rawdec, audio_decoder.raw },{ OMX.google.flac.decoder, flacdec, audio_decoder.flac },{ OMX.google.flac.encoder, flacenc, audio_encoder.flac },{ OMX.google.gsm.decoder, gsmdec, audio_decoder.gsm },
#ifdef QTI_FLAC_DECODER{ OMX.qti.audio.decoder.flac, qtiflacdec, audio_decoder.flac },
#endif
};
软解码器代码目录 frameworks\av\media\libstagefright\codecs编译会生成对应的so库 车机内软解码so所在的目录
软解码器的实现
是基于“OpenMax IL的标准接口”进行实际硬解码器也是如此。 以libstagefright_soft_aacdec为例子 libstagefright_soft_aacdec.so主体是SoftAAC2.cpp和SoftAAC2.h所以dlsym返回的createSoftOMXComponent值如下
//frameworks\av\media\libstagefright\codecs\aacdec\SoftAAC2.cpp
android::SoftOMXComponent *createSoftOMXComponent(const char *name, const OMX_CALLBACKTYPE *callbacks,OMX_PTR appData, OMX_COMPONENTTYPE **component) {return new android::SoftAAC2(name, callbacks, appData, component);
}
SoftAAC2继承自SimpleSoftOMXComponent
//frameworks\av\media\libstagefright\codecs\aacdec\SoftAAC2.cpp
SoftAAC2::SoftAAC2(const char *name,const OMX_CALLBACKTYPE *callbacks,OMX_PTR appData,OMX_COMPONENTTYPE **component): SimpleSoftOMXComponent(name, callbacks, appData, component),mAACDecoder(NULL),mStreamInfo(NULL),mIsADTS(false),mInputBufferCount(0),mOutputBufferCount(0),mSignalledError(false),mLastInHeader(NULL),mLastHeaderTimeUs(-1),mNextOutBufferTimeUs(0),mOutputPortSettingsChange(NONE) {initPorts();CHECK_EQ(initDecoder(), (status_t)OK);
}
SimpleSoftOMXComponent实现OpenMax IL的标准接口例如sendCommand、setParameter
//frameworks\av\media\stagefright\omx\SimpleSoftOMXComponent.cpp
SimpleSoftOMXComponent::SimpleSoftOMXComponent(const char *name,const OMX_CALLBACKTYPE *callbacks,OMX_PTR appData,OMX_COMPONENTTYPE **component): SoftOMXComponent(name, callbacks, appData, component),mLooper(new ALooper),mHandler(new AHandlerReflectorSimpleSoftOMXComponent(this)),mState(OMX_StateLoaded),mTargetState(OMX_StateLoaded) {mLooper-setName(name);mLooper-registerHandler(mHandler);mLooper-start(false, // runOnCallingThreadfalse, // canCallJavaANDROID_PRIORITY_VIDEO);
}SoftOMXComponent里有对OpenMax接口的
// frameworks\av\media\stagefright\omx\SoftOMXComponent.cpp
// OMX_Component.h为 OpenMax IL version 1.1.2的接口头文件
#include OMX_Component.h
SoftOMXComponent::SoftOMXComponent(const char *name,const OMX_CALLBACKTYPE *callbacks,OMX_PTR appData,OMX_COMPONENTTYPE **component): mName(name),mCallbacks(callbacks),mComponent(new OMX_COMPONENTTYPE),mLibHandle(NULL) {mComponent-nSize sizeof(*mComponent);mComponent-nVersion.s.nVersionMajor 1;mComponent-nVersion.s.nVersionMinor 0;mComponent-nVersion.s.nRevision 0;mComponent-nVersion.s.nStep 0;mComponent-pComponentPrivate this;mComponent-pApplicationPrivate appData; 。。。*component mComponent;
}7.2 硬解码器
调用mGetHandle函数指针而该函数指针是在该类构造时初始化。
//hardware\qcom\media\libstagefrighthw\QComOMXPlugin.cpp
OMX_ERRORTYPE QComOMXPlugin::makeComponentInstance(const char *name,const OMX_CALLBACKTYPE *callbacks,OMX_PTR appData,OMX_COMPONENTTYPE **component) {if (mLibHandle NULL) {return OMX_ErrorUndefined;}return (*mGetHandle)(reinterpret_castOMX_HANDLETYPE *(component),const_castchar *(name),appData, const_castOMX_CALLBACKTYPE *(callbacks));
}
可以看到原来mGetHandle就是libOmxCore.so库中的OMX_GetHandle函数
//hardware\qcom\media\libstagefrighthw\QComOMXPlugin.cpp
QComOMXPlugin::QComOMXPlugin(): mLibHandle(dlopen(libOmxCore.so, RTLD_NOW)),mInit(NULL),mDeinit(NULL),mComponentNameEnum(NULL),mGetHandle(NULL),mFreeHandle(NULL),mGetRolesOfComponentHandle(NULL) {if (mLibHandle ! NULL) {mInit (InitFunc)dlsym(mLibHandle, OMX_Init);mDeinit (DeinitFunc)dlsym(mLibHandle, OMX_Deinit);mComponentNameEnum (ComponentNameEnumFunc)dlsym(mLibHandle, OMX_ComponentNameEnum);mGetHandle (GetHandleFunc)dlsym(mLibHandle, OMX_GetHandle);mFreeHandle (FreeHandleFunc)dlsym(mLibHandle, OMX_FreeHandle);mGetRolesOfComponentHandle (GetRolesOfComponentFunc)dlsym(mLibHandle, OMX_GetRolesOfComponent);if (!mInit || !mDeinit || !mComponentNameEnum || !mGetHandle ||!mFreeHandle || !mGetRolesOfComponentHandle) {dlclose(mLibHandle);mLibHandle NULL;} else(*mInit)();}
}OMX_GetHandle函数 1、如果是avc解码器加载libOmxVideoDSMode.so库,判断是否有dsmode 2、视频预处理开启情况需要加载vpp库 3、动态加载对应的编解码so
//hardware\qcom\media\mm-core\src\common\qc_omx_core.c
// libOmxCore.so
OMX_API OMX_ERRORTYPE OMX_APIENTRY
OMX_GetHandle(OMX_OUT OMX_HANDLETYPE* handle,OMX_IN OMX_STRING componentName,OMX_IN OMX_PTR appData,OMX_IN OMX_CALLBACKTYPE* callBacks)
{OMX_ERRORTYPE eRet OMX_ErrorNone;int cmp_index -1;int hnd_index -1;int vpp_cmp_index -1;DEBUG_PRINT(OMXCORE API : GetHandle %p %s %p\n, handle,componentName,appData);pthread_mutex_lock(lock_core);if(handle){*handle NULL;char optComponentName[OMX_MAX_STRINGNAME_SIZE];strlcpy(optComponentName, componentName, OMX_MAX_STRINGNAME_SIZE);// 如果是avc解码器加载libOmxVideoDSMode.so库,判断是否有dsmodeif(strstr(componentName, avc) strstr(componentName, decoder)){void *libhandle dlopen(libOmxVideoDSMode.so, RTLD_NOW);if(libhandle){int (*fn_ptr)() dlsym(libhandle, isDSModeActive);dlclose(libhandle);}else{DEBUG_PRINT_ERROR(Failed to load dsmode library);}}if(cmp_index 0){cmp_index get_cmp_index(componentName);strlcpy(optComponentName, componentName, OMX_MAX_STRINGNAME_SIZE);}if(cmp_index 0){char value[PROPERTY_VALUE_MAX];DEBUG_PRINT(getting fn pointer\n);// Load VPP omx component for decoder if vpp// property is enabled// 视频预处理开启情况需要加载vppif ((property_get(vendor.media.vpp.enable, value, NULL)) (!strcmp(1, value) || !strcmp(true, value))) {DEBUG_PRINT(VPP property is enabled);if (!strcmp(core[cmp_index].so_lib_name, libOmxVdec.so)|| !strcmp(core[cmp_index].so_lib_name, libOmxSwVdec.so)) {vpp_cmp_index get_cmp_index(OMX.qti.vdec.vpp);if (vpp_cmp_index 0) {DEBUG_PRINT_ERROR(Unable to find VPP OMX lib in registry );} else {DEBUG_PRINT(Loading vpp for vdec);cmp_index vpp_cmp_index;}}}// dynamically load the socore[cmp_index].fn_ptr omx_core_load_cmp_library(core[cmp_index].so_lib_name,core[cmp_index].so_lib_handle);。。。。
}加载对应的SO库
// /hardware\qcom\media\mm-core\src\common\qc_omx_core.c
static create_qc_omx_component
omx_core_load_cmp_library(char *libname, void **handle_ptr)
{create_qc_omx_component fn_ptr NULL;if(handle_ptr){DEBUG_PRINT(Dynamically Loading the library : %s\n,libname);if (!strcmp(libname, libOmxVpp.so))*handle_ptr dlopen(libname, RTLD_NOW|RTLD_GLOBAL);else*handle_ptr dlopen(libname, RTLD_NOW);if(*handle_ptr){fn_ptr dlsym(*handle_ptr, get_omx_component_factory_fn);if(fn_ptr NULL){DEBUG_PRINT(Error: Library %s incompatible as QCOM OMX component loader - %s\n,libname, dlerror());*handle_ptr NULL;}}else{DEBUG_PRINT(Error: Couldnt load %s: %s\n,libname,dlerror());}}return fn_ptr;
}高通平台支持的硬解码器 注意里边有一些是软解码包含Sw字符的
omx_core_cb_type core[]
{//Common entriesOMX_REGISTRY_ENTRY(OMX.qcom.video.decoder.avc, libOmxVdec.so, video_decoder.avc),OMX_REGISTRY_ENTRY(OMX.qcom.video.decoder.avc.secure, libOmxVdec.so, video_decoder.avc),OMX_REGISTRY_ENTRY(OMX.qcom.video.decoder.mpeg2, libOmxVdec.so, video_decoder.mpeg2),OMX_REGISTRY_ENTRY(OMX.qcom.video.decoder.mpeg2.secure, libOmxVdec.so, video_decoder.mpeg2),OMX_REGISTRY_ENTRY(OMX.qcom.video.decoder.hevc, libOmxVdec.so, video_decoder.hevc),OMX_REGISTRY_ENTRY(OMX.qcom.video.decoder.hevc.secure, libOmxVdec.so, video_decoder.hevc),OMX_REGISTRY_ENTRY(OMX.qcom.video.decoder.vp8, libOmxVdec.so, video_decoder.vp8),OMX_REGISTRY_ENTRY(OMX.qcom.video.decoder.vp9, libOmxVdec.so, video_decoder.vp9),OMX_REGISTRY_ENTRY(OMX.qcom.video.decoder.vp9.secure, libOmxVdec.so, video_decoder.vp9),OMX_REGISTRY_ENTRY(OMX.qti.video.decoder.mpeg4sw, libOmxSwVdec.so, video_decoder.mpeg4),OMX_REGISTRY_ENTRY(OMX.qti.video.decoder.divxsw, libOmxSwVdec.so, video_decoder.divx),OMX_REGISTRY_ENTRY(OMX.qti.video.decoder.divx4sw, libOmxSwVdec.so, DIVX4_MIME),OMX_REGISTRY_ENTRY(OMX.qti.video.decoder.h263sw, libOmxSwVdec.so, video_decoder.h263),OMX_REGISTRY_ENTRY(OMX.qcom.video.encoder.mpeg4sw, libOmxSwVencMpeg4.so, video_encoder.mpeg4),OMX_REGISTRY_ENTRY(OMX.qcom.video.encoder.h263sw, libOmxSwVencMpeg4.so, video_encoder.h263),OMX_REGISTRY_ENTRY(OMX.qcom.video.encoder.avc, libOmxVenc.so, video_encoder.avc),OMX_REGISTRY_ENTRY(OMX.qcom.video.encoder.avc.secure, libOmxVenc.so, video_encoder.avc),OMX_REGISTRY_ENTRY(OMX.qcom.video.encoder.vp8, libOmxVenc.so, video_encoder.vp8),OMX_REGISTRY_ENTRY(OMX.qcom.video.encoder.hevc, libOmxVenc.so, video_encoder.hevc),OMX_REGISTRY_ENTRY(OMX.qcom.video.encoder.hevc.secure, libOmxVenc.so, video_encoder.hevc),OMX_REGISTRY_ENTRY(OMX.qcom.video.encoder.heic, libOmxVenc.so, image_encoder.heic),OMX_REGISTRY_ENTRY(OMX.qcom.audio.decoder.Qcelp13, libOmxQcelp13Dec.so, audio_decoder.Qcelp13),OMX_REGISTRY_ENTRY(OMX.qcom.audio.decoder.evrc, libOmxEvrcDec.so, audio_decoder.evrc),OMX_REGISTRY_ENTRY(OMX.qcom.audio.decoder.wma, libOmxWmaDec.so, audio_decoder.wma),OMX_REGISTRY_ENTRY(OMX.qcom.audio.decoder.wma10Pro, libOmxWmaDec.so, audio_decoder.wma),OMX_REGISTRY_ENTRY(OMX.qcom.audio.decoder.wmaLossLess, libOmxWmaDec.so, audio_decoder.wma),OMX_REGISTRY_ENTRY(OMX.qcom.audio.decoder.amrwbplus, libOmxAmrwbplusDec.so, audio_decoder.awbplus),OMX_REGISTRY_ENTRY(OMX.qcom.audio.decoder.alac, libOmxAlacDec.so, audio_decoder.alac),OMX_REGISTRY_ENTRY(OMX.qti.audio.decoder.alac.sw, libOmxAlacDecSw.so, audio_decoder.alac),。。。。。
};
硬解码器的实现位置 Audio encodehardware\qcom\audio\mm-audio Audio decode\vendor\qcom\proprietary\mm-audio\omx Video encode/decode: hardware\qcom\media\mm-video-v4l2
对比Audio每个解码器均有一个soVideo采用v4l2框架实现只有libOmxVenc.solibOmxSwVencMpeg4libOmxSwVdeclibOmxVdec.so 这4个库。
部分缩写含义
1.VPP 视频预处理 2.avc 就是H264 3.v4l2 是:video for linux version2,是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口.凡是内核中的子系统都有抽象底层硬件的差异,为上层提供统一的接口和提取出公共代码避免代码冗余等好处.