生活随笔
收集整理的這篇文章主要介紹了
Android多媒体开发-- android中OpenMax的实现整体框架
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
1.android中用openmax來干啥?
android中的?AwesomePlayer就 是用openmax來做(code)編解碼,其實在openmax接口設(shè)計中,他不光能用來當編解碼。通過他的組件可以組成一個完整的播放器,包括 sourc、demux、decode、output。但是為什么android只用他來做code呢?我認為有以下幾方面:
1.在整個播放器中,解碼器不得不說是最重要的一部分,而且也是最耗資源的一塊。 如果全靠軟解,直接通過cpu來運算,特別是高清視頻。別的事你就可以啥都不干了。所以解碼器是最需要硬件提供加速的部分。現(xiàn)在的高清解碼芯片都是主芯 片+DSP結(jié)構(gòu),解碼的工作都是通過DSP來做,不會在過多的占用主芯片。所有將芯片中DSP硬件編解碼的能力通過openmax標準接口呈現(xiàn)出來,提供 上層播放器來用。我認為這塊是openmax最重要的意義。
2.source 主要是和協(xié)議打交道,demux 分解容器部分,大多數(shù)的容器格式的分解是不需要通過硬件來支持。只是ts流這種格式最可能用到硬件的支持。因為ts格式比較特殊,單包的大小太小了,只有 188字節(jié)。所以也是為什么現(xiàn)在常見的解碼芯片都會提供硬件ts demux 的支持。
3.音視頻輸出部分video\audio output 這塊和操作系統(tǒng)關(guān)系十分緊密。可以看看著名開源播放器vlc。vlc 在mac、linux、Windows都有,功能上差別也不大。所以說他是跨平臺的,他跨平臺跨在哪?主要的工作量還是在音視頻解碼完之后的輸出模塊。因 為各個系統(tǒng)的圖像渲染和音頻輸出實現(xiàn)方法不同,所以vlc需要針對每個平臺實現(xiàn)不同的output。這部分內(nèi)容放在openmax來顯然不合適。
所以openmax 中硬件抽象的編解碼是最為常用的,也是為什么android中只用它來抽象code。 2.android中openmax實現(xiàn)框架
1.上面已經(jīng)說過了,android系統(tǒng)中只用openmax來做code,所以android向上抽象了一層OMXCodec,提供給上層播放器用。 播放器中音視頻解碼器mVideosource、mAudiosource都是OMXCodec的實例。
2.OMXCodec通過IOMX 依賴binder機制 獲得 OMX服務(wù),OMX服務(wù) 才是openmax 在android中 實現(xiàn)。
3. OMX把軟編解碼和硬件編解碼統(tǒng)一看作插件的形式管理起來。 AwesomePlayer 中有個變量?
[cpp] view plaincopy
OMXClient?mClient;?? 讓我們看看?? OMXClient? [cpp] view plaincopy
class?OMXClient?{??public:??????OMXClient();????????status_t?connect();??????void?disconnect();????????sp<IOMX>?interface()?{??????????return?mOMX;??????}????private:??????sp<IOMX>?mOMX;????????OMXClient(const?OMXClient?&);??????OMXClient?&operator=(const?OMXClient?&);??};?? OMXClient 有個IOMX 的變量 mOMX ,這個就是和OMX服務(wù)進行binder通訊的。 在?AwesomePlayer 的構(gòu)造函數(shù)中會調(diào)用? [cpp] view plaincopy
CHECK_EQ(mClient.connect(),?(status_t)OK);?? [cpp] view plaincopy
status_t?OMXClient::connect()?{??????sp<IServiceManager>?sm?=?defaultServiceManager();??????sp<IBinder>?binder?=?sm->getService(String16("media.player"));??????sp<IMediaPlayerService>?service?=?interface_cast<IMediaPlayerService>(binder);????????CHECK(service.get()?!=?NULL);????????mOMX?=?service->getOMX();??????CHECK(mOMX.get()?!=?NULL);????????if?(!mOMX->livesLocally(NULL?????????ALOGI("Using?client-side?OMX?mux.");??????????mOMX?=?new?MuxOMX(mOMX);??????}????????return?OK;??}?? [cpp] view plaincopy
sp<IOMX>?MediaPlayerService::getOMX()?{??????Mutex::Autolock?autoLock(mLock);????????if?(mOMX.get()?==?NULL)?{??????????mOMX?=?new?OMX;??????}????????return?mOMX;??}??
OMXClient::connect函數(shù)是通過binder機制 獲得到MediaPlayerService,然后通過MediaPlayerService來創(chuàng)建OMX的實例。這樣OMXClient就獲得到了OMX的入口,接下來就可以通過binder機制來獲得OMX提供的服務(wù)。 也就是說OMXClient 是android中 openmax 的入口。 在創(chuàng)建音視頻解碼mVideoSource、mAudioSource的時候會把OMXClient中的sp<IOMX> mOMX的實例 傳給mVideoSource、mAudioSource來共享使用這個OMX的入口。 也就是說一個AwesomePlayer對應(yīng)著 一個IOMX 變量,AwesomePlayer中的音視頻解碼器共用這個IOMX變量來獲得OMX服務(wù)。 [cpp] view plaincopy
sp<IOMX>?interface()?{????????return?mOMX;????}?? [cpp] view plaincopy
mAudioSource?=?OMXCodec::Create(??????????????????mClient.interface(),?mAudioTrack->getFormat(),??????????????????false,?????????????????mAudioTrack);?? [cpp] view plaincopy
mVideoSource?=?OMXCodec::Create(??????????????mClient.interface(),?mVideoTrack->getFormat(),??????????????false,?????????????mVideoTrack,??????????????NULL,?flags,?USE_SURFACE_ALLOC???mNativeWindow?:?NULL);?? [cpp] view plaincopy
? 通過上文知道了,每個AwesomePlayer 只有一個OMX服務(wù)的入口,但是AwesomePlayer不一定就只需要1種解碼器。有可能音視頻都有,或者有很多種。這個時候這些解碼器都需要OMX的服務(wù),也就是OMX那頭需要建立不同的解碼器的組件來對應(yīng)著AwesomePlayer中不同的code。OMX中非常重要的2個成員就是?OMXMaster 和?OMXNodeInstance。OMX通過這倆個成員來創(chuàng)建和維護不同的openmax 解碼器組件,為AwesomePlayer中不同解碼提供服務(wù)。讓我們看看他們是怎么實現(xiàn)這些工作的。
1. OMX中?OMXNodeInstance 負責創(chuàng)建并維護不同的實例,這些實例是根據(jù)上面需求創(chuàng)建的,以node作為唯一標識。這樣播放器中每個OMXCodec在OMX服務(wù)端都對應(yīng)有了自己的OMXNodeInstance實例。
2.OMXMaster 維護底層軟硬件解碼庫,根據(jù)OMXNodeInstance中想要的解碼器來創(chuàng)建解碼實體組件。
接下來我們假設(shè)視頻解碼器需要的是AVC,來看看解碼器創(chuàng)建的流程。
(默認走軟解碼)
1.準備工作初始化OMXMaster
OMX構(gòu)造函數(shù)中會進行初始化。
[cpp] view plaincopy
OMXMaster?*mMaster;?? [cpp] view plaincopy
OMX::OMX()??????:?mMaster(new?OMXMaster),????????mNodeCounter(0)?{??}?? [cpp] view plaincopy
OMXMaster::OMXMaster()??????:?mVendorLibHandle(NULL)?{??????addVendorPlugin();??????addPlugin(new?SoftOMXPlugin);??}?? OMXMaster 負責OMX中編解碼器插件管理,軟件解碼和硬件解碼都是
使用OMX標準,掛載plugins的方式來進行管理。 軟解通過 addPlugin(new SoftOMXPlugin);會把這些編解碼器的名字都放在mPluginByComponentName中。 android 默認會提供一系列的軟件解碼器。目前支持這些格式的軟編解碼。 [cpp] view plaincopy
kComponents[]?=?{??????{?"OMX.google.aac.decoder",?"aacdec",?"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",?"h264dec",?"video_decoder.avc"?},??????{?"OMX.google.h264.encoder",?"h264enc",?"video_encoder.avc"?},??????{?"OMX.google.g711.alaw.decoder",?"g711dec",?"audio_decoder.g711alaw"?},??????{?"OMX.google.g711.mlaw.decoder",?"g711dec",?"audio_decoder.g711mlaw"?},??????{?"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.vpx.decoder",?"vpxdec",?"video_decoder.vpx"?},??????{?"OMX.google.raw.decoder",?"rawdec",?"audio_decoder.raw"?},??????{?"OMX.google.flac.encoder",?"flacenc",?"audio_encoder.flac"?},??};?? 硬件編解碼是通過 addVendorPlugin();加載libstagefrighthw.so.各個芯片平臺可以遵循openmax 標準,生成libstagefrighthw.so的庫來提供android應(yīng)用。 [cpp] view plaincopy
void?OMXMaster::addVendorPlugin()?{??????addPlugin("libstagefrighthw.so");??}?? 然后通過dlopen、dlsym來調(diào)用庫中的函數(shù)。
這部分準備工作是在AwesomePlayer的構(gòu)造函數(shù)中 CHECK_EQ(mClient.connect(), (status_t)OK); 已經(jīng)完成了。 2.創(chuàng)建mVideoSource
有了上面的OMX,接下來會在AwesomePlayer::initVideoDecoder中創(chuàng)建mVideoSource 實例,下面代碼只保留的主要部分: [cpp] view plaincopy
status_t?AwesomePlayer::initVideoDecoder(uint32_t?flags)?{??????ATRACE_CALL();??????mVideoSource?=?OMXCodec::Create(??????????????mClient.interface(),?mVideoTrack->getFormat(),??????????????false,?????????????mVideoTrack,??????????????NULL,?flags,?USE_SURFACE_ALLOC???mNativeWindow?:?NULL);??????status_t?err?=?mVideoSource->start();??????return?mVideoSource?!=?NULL???OK?:?UNKNOWN_ERROR;??}?? 保留主要部分,去除編碼相關(guān) [cpp] view plaincopy
sp<MediaSource>?OMXCodec::Create(??????????const?sp<IOMX>?&omx,??????????const?sp<MetaData>?&meta,?bool?createEncoder,??????????const?sp<MediaSource>?&source,??????????const?char?*matchComponentName,??????????uint32_t?flags,??????????const?sp<ANativeWindow>?&nativeWindow)?{??????int32_t?requiresSecureBuffers;????????????const?char?*mime;??????bool?success?=?meta->findCString(kKeyMIMEType,?&mime);??????CHECK(success);????????Vector<String8>?matchingCodecs;??????Vector<uint32_t>?matchingCodecQuirks;??????findMatchingCodecs(??????????????mime,?createEncoder,?matchComponentName,?flags,??????????????&matchingCodecs,?&matchingCodecQuirks);????????sp<OMXCodecObserver>?observer?=?new?OMXCodecObserver;??????IOMX::node_id?node?=?0;????????for?(size_t?i?=?0;?i?<?matchingCodecs.size();?++i)?{??????????const?char?*componentNameBase?=?matchingCodecs[i].string();??????????uint32_t?quirks?=?matchingCodecQuirks[i];??????????const?char?*componentName?=?componentNameBase;????????????AString?tmp;???????????????status_t?err?=?omx->allocateNode(componentName,?observer,?&node);??????????if?(err?==?OK)?{??????????????ALOGV("Successfully?allocated?OMX?node?'%s'",?componentName);????????????????sp<OMXCodec>?codec?=?new?OMXCodec(??????????????????????omx,?node,?quirks,?flags,??????????????????????createEncoder,?mime,?componentName,??????????????????????source,?nativeWindow);????????????????observer->setCodec(codec);????????????????err?=?codec->configureCodec(meta);????????????????if?(err?==?OK)?{??????????????????if?(!strcmp("OMX.Nvidia.mpeg2v.decode",?componentName))?{??????????????????????codec->mFlags?|=?kOnlySubmitOneInputBufferAtOneTime;??????????????????}????????????????????return?codec;??????????????}????????????????ALOGV("Failed?to?configure?codec?'%s'",?componentName);??????????}??????}????????return?NULL;??}?? 1.根據(jù)mVideoTrack傳進來的視頻信息,查找相匹配的解碼器。
[cpp] view plaincopy
bool?success?=?meta->findCString(kKeyMIMEType,?&mime);??findMatchingCodecs(?????????????mime,?createEncoder,?matchComponentName,?flags,?????????????&matchingCodecs,?&matchingCodecQuirks);?? 2. 創(chuàng)建OMXCodecObserver 實例,OMXCodecObserver功能后續(xù)會詳細介紹。創(chuàng)建一個node 并初始化為0.
[cpp] view plaincopy
sp<OMXCodecObserver>?observer?=?new?OMXCodecObserver;??????IOMX::node_id?node?=?0;?? 3. 通過omx入口 依靠binder 機制調(diào)用OMX服務(wù)中的allocateNode(),這一步把匹配得到的解碼器組件名、OMXCodecObserver實例和初始化為0的node一并傳入。
[cpp] view plaincopy
status_t?err?=?omx->allocateNode(componentName,?observer,?&node);?? 這個allocateNode 就是文章最開始講的,在OMX那頭創(chuàng)建一個和mVideoSource相匹配的解碼實例。用node值作為唯一標識。
讓我們來看看真正的omx中allocateNode做了啥?
[cpp] view plaincopy
status_t?OMX::allocateNode(??????????const?char?*name,?const?sp<IOMXObserver>?&observer,?node_id?*node)?{??????Mutex::Autolock?autoLock(mLock);????????*node?=?0;????????OMXNodeInstance?*instance?=?new?OMXNodeInstance(this,?observer);????????OMX_COMPONENTTYPE?*handle;??????OMX_ERRORTYPE?err?=?mMaster->makeComponentInstance(??????????????name,?&OMXNodeInstance::kCallbacks,??????????????instance,?&handle);????????if?(err?!=?OMX_ErrorNone)?{??????????ALOGV("FAILED?to?allocate?omx?component?'%s'",?name);????????????instance->onGetHandleFailed();????????????return?UNKNOWN_ERROR;??????}????????*node?=?makeNodeID(instance);??????mDispatchers.add(*node,?new?CallbackDispatcher(instance));????????instance->setHandle(*node,?handle);????????mLiveNodes.add(observer->asBinder(),?instance);??????observer->asBinder()->linkToDeath(this);????????return?OK;??}?? 創(chuàng)建一個OMXNodeInstance實例。 通過mMaster->makeComponentInstance創(chuàng)建真正解碼器的組件,并通過handle與OMXNodeInstance關(guān)聯(lián)。 所以說mMaster->makeComponentInstance這里是建立解碼器組件的核心。會把
mVideoSource需要的解碼器name一直傳遞下去。 [cpp] view plaincopy
OMX_ERRORTYPE?OMXMaster::makeComponentInstance(??????????const?char?*name,??????????const?OMX_CALLBACKTYPE?*callbacks,??????????OMX_PTR?appData,??????????OMX_COMPONENTTYPE?**component)?{??????Mutex::Autolock?autoLock(mLock);????????*component?=?NULL;????????ssize_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通過?addPlugin(new SoftOMXPlugin);把支持的軟解碼放在mPluginByComponentName中,在makeComponentInstance中通過上面?zhèn)飨聛淼慕獯a器的name值從mPluginByComponentName找到相對應(yīng)的plugin,然后調(diào)用? plugin->makeComponentInstance(name, callbacks, appData, component); 這里的plugin 值得就是軟解SoftOMXPlugin 也就是調(diào)用了 [cpp] view plaincopy
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)?{??????????if?(strcmp(name,?kComponents[i].mName))?{??????????????continue;??????????}????????????AString?libName?=?"libstagefright_soft_";??????????libName.append(kComponents[i].mLibNameSuffix);??????????libName.append(".so");????????????void?*libHandle?=?dlopen(libName.c_str(),?RTLD_NOW);????????????if?(libHandle?==?NULL)?{??????????????ALOGE("unable?to?dlopen?%s",?libName.c_str());????????????????return?OMX_ErrorComponentNotFound;??????????}????????????typedef?SoftOMXComponent?*(*CreateSoftOMXComponentFunc)(??????????????????const?char?*,?const?OMX_CALLBACKTYPE?*,??????????????????OMX_PTR,?OMX_COMPONENTTYPE?**);????????????CreateSoftOMXComponentFunc?createSoftOMXComponent?=??????????????(CreateSoftOMXComponentFunc)dlsym(??????????????????????libHandle,??????????????????????"_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE"??????????????????????"PvPP17OMX_COMPONENTTYPE");????????????if?(createSoftOMXComponent?==?NULL)?{??????????????dlclose(libHandle);??????????????libHandle?=?NULL;????????????????return?OMX_ErrorComponentNotFound;??????????}????????????sp<SoftOMXComponent>?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;??}?? 通過上面?zhèn)飨聛淼慕獯a器的name,找到對應(yīng)庫的名字。假如是264的話,要加載的庫就是 libstagefright_soft_h264dec.so,也就是對應(yīng)上層264解碼的話,omx解碼組件會加載對應(yīng)的 libstagefright_soft_h264dec.so庫。相對應(yīng)的軟解代碼在 Android4.1.1\frameworks\av\media\libstagefright\codecs\on2\h264dec 中。 加載完264解碼庫后 通過dlopen、dlsym來調(diào)用庫中函數(shù)。 通過調(diào)用 SoftAVC 中的 createSoftOMXComponent 來創(chuàng)建真正264解碼器實例SoftOMXComponent。以后真正視頻解碼的工作都是通過avc 這個SoftAVC實例完成的 [cpp] view plaincopy
android::SoftOMXComponent?*createSoftOMXComponent(??????????const?char?*name,?const?OMX_CALLBACKTYPE?*callbacks,??????????OMX_PTR?appData,?OMX_COMPONENTTYPE?**component)?{??????return?new?android::SoftAVC(name,?callbacks,?appData,?component);??}??
經(jīng)過這一路下來,終于完成了解碼器的創(chuàng)建工作。簡單總結(jié)一下。 1.AwesomePlayer中通過initVideoDecoder 來創(chuàng)建video解碼器mVideoSource 2.mVideoSource 中通過上部分demux后的視頻流 mVideoTrack來獲得解碼器的類型,通過類型調(diào)用omx->allocateNode 創(chuàng)建omx node實例與自己對應(yīng)。以后都是通過node實例來操作解碼器。 3.在 omx->allocateNode中 通過mMaster->makeComponentInstance 來創(chuàng)建真正對應(yīng)的解碼器組件。這個解碼器組件是完成之后解碼實際工作的。 4.在創(chuàng)建mMaster->makeComponentInstance過程中,也是通過上面mVideoTrack 過來的解碼器類型名,找到相對應(yīng)的解碼器的庫,然后實例化。
轉(zhuǎn)載于:https://www.cnblogs.com/shakin/p/4096536.html
總結(jié)
以上是生活随笔為你收集整理的Android多媒体开发-- android中OpenMax的实现整体框架的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。