"本文轉(zhuǎn)載自:[yanbixing123]的Android MultiMedia框架完全解析 - 從NuPlayer到MediaCodec到ACodec到OMX的整體流程與狀態(tài)轉(zhuǎn)換"
1.概述
??前面的文檔已經(jīng)對Nuplayer架構(gòu)不同的部分進行了詳細的分析,這里再重新總結(jié)一下NuPlayer整體框架厌杜。同時也補充上MediaCodec获雕,ACodec與OMX Plugin之間的狀態(tài)切換關(guān)系忿薇。
2. 初始化過程
??這里的初始化過程從NuPlayer開始牌废,因為上層MediaPlayer只是一個“殼”,實際的播放器功能由NuPlayer實現(xiàn)寝蹈。下面先看一下整體的框架流程圖慧域。
上面的是整體的NuPlayer的框架圖,涉及的了很多的代碼流程片拍,下面將分成幾個部分逐步分析煌集。
2.1 從start到配置解碼器
(1)NuPlayer::start()時產(chǎn)生一個kWhatStart,在消息處理函數(shù)中如果是暫停后的開始就調(diào)用NuPlayer::onResume()【只需mSource->resume()和mRenderer->resume()】捌省,否則調(diào)用NuPlayer::onStart()苫纤。
(2)在函數(shù)NuPlayer::onStart()中會先后進行如下操作:(設(shè)置Source狀態(tài)、初始化Renderer、初始化Decoder卷拘,并將三者關(guān)聯(lián)起來)喊废。
(3)若mSource【source類對象】沒有開始,則mSource->start()栗弟,來啟動音視頻包讀取污筷。
(4)創(chuàng)建Render和并為其創(chuàng)建一個名為mRendererLooper的ALooper,這里通過setPlaybackSettings函數(shù)乍赫,來為Renderer設(shè)置時鐘頻率瓣蛀,與MediaClock關(guān)聯(lián)起來,這個時鐘在音視頻同步中很重要耿焊。然后獲取Framerate揪惦,設(shè)置到Renderer中,并使用setRenderer方法將Render與Decoder關(guān)聯(lián)起來(這里需要講音頻Decoder和視頻Decoder都與Renderer關(guān)聯(lián)起來)罗侯。
(5)調(diào)用NuPlayer::postScanSources()器腋,然后其中生成kWhatScanSources消息,在消息處理中會根據(jù)情況調(diào)用NuPlayer::instantiateDecoder(…)初始化video或者audio解碼器【需要在audio解碼器之前實例化video解碼器钩杰,因為成功初始化視頻解碼器可能會改變音頻解碼器的深度緩沖模式】纫塌。
(6)在instantiateDecoder中,根據(jù)情況用new Decoder(…)創(chuàng)建音視頻解碼器(NuPlayer::Decoder)讲弄,為其創(chuàng)建名為mCodecLooper的ALooper【其父類NuPlayer::DecoderBase的構(gòu)造中則會創(chuàng)建mDecoderLooper】措左。
(7)對該解碼器進行init()操作,調(diào)用NuPlayer::DecoderBase::init()為mDecoderLooper注冊handler【init()和configure()都是NuPlayerDecoder繼承自NuPlayer::DecoderBase的方法】
(8)對該解碼器進行configure(format)操作避除,調(diào)用NuPlayer::DecoderBase::configure(…)產(chǎn)生一個kWhatConfigure消息怎披,然后消息處理中調(diào)用NuPlayer::Decoder::onConfigure(…),在onConfigure中瓶摆,首先會調(diào)用MediaCodec::CreateByType(…)或者MediaCodec::CreateByComponentName(…)根據(jù)情況創(chuàng)建MediaCodec凉逛,接著調(diào)用MediaCodec::init(…);隨后調(diào)用MediaCodec::configure(…)對MediaCodec進行配置使其轉(zhuǎn)入Configured狀態(tài)群井;然后又調(diào)用MediaCodec::start()使MediaCodec轉(zhuǎn)入Started狀態(tài)状飞。
2.2 解碼器創(chuàng)建
??MediaCodec::createByType()/MediaCodec::CreateByComponentName()的調(diào)用。
??首先new一個MediaCodec书斜,之后就調(diào)用MediaCodec的構(gòu)造函數(shù)诬辈,設(shè)置MediaCodec的狀態(tài)為UNINITIALIZED。調(diào)用codec->init()函數(shù)荐吉,在這個函數(shù)中焙糟,通過GetCodecBase來創(chuàng)建ACodec,然后發(fā)送kWhatInit消息样屠,在消息處理中酬荞,設(shè)置MediaCodec狀態(tài)為INITIALIZING搓劫,之后通過mCodec->initiateAllocateComponent(format)調(diào)用到ACodec的ACodec::initiateAllocateComponent()函數(shù),這個函數(shù)發(fā)送kWhatAllocateComponent消息混巧,在消息處理函數(shù)中,通過onAllocateComponent()里面的omx->allocateNode()函數(shù)來創(chuàng)建OMX插件勤揩,之后設(shè)置ACodec狀態(tài)為Loaded咧党,同時ACodec向MediaCodec返回CodecBase::kWhatComponentAllocated消息,在這個消息處理函數(shù)中陨亡,設(shè)置MediaCodec狀態(tài)為INITIALIZED傍衡。(MediaCodec狀態(tài)從INITIALIZING轉(zhuǎn)換為INITIALIZED)
2.3 解碼器配置
??MediaCodec::configure(…)的調(diào)用。
??產(chǎn)生kWhatConfigure消息负蠕,在消息處理中調(diào)用ACodec::initiateConfigureComponent(…)又產(chǎn)生消息kWhatConfigureComponent蛙埂,然后該消息處理中又調(diào)用了ACodec::LoadedState::onConfigureComponent(…)。然后在其中又會先調(diào)用ACodec::configureCodec(…)遮糖,在configureCodec中會對IOMX進行一系列的設(shè)置以及配置操作绣的,通過Binder通信就對OMXNodeInstance進行相應(yīng)的設(shè)置和配置操作,最終就對OMX組件進行了相應(yīng)的設(shè)置和配置欲账。然后向MediaCodec發(fā)送kWhatComponentConfigured消息屡江,在消息處理中將MediaCodec狀態(tài)設(shè)為CONFIGURED;(MediaCodec狀態(tài)從CONFIGURING轉(zhuǎn)換為CONFIGURED)
2.4 解碼器啟動
??MediaCodec::start()的調(diào)用赛不。
??產(chǎn)生kWhatStart消息惩嘉,消息處理中先將MediaCodec狀態(tài)設(shè)為STARTING,然后調(diào)用ACodec::initiateStart()產(chǎn)生kWhatStart消息踢故,在其消息處理中又調(diào)用ACodec::LoadedState::onStart()文黎,然后在其中首先向IOMX發(fā)送狀態(tài)轉(zhuǎn)換命令,經(jīng)過OMXNodeInstance最終對將OMX組件狀態(tài)轉(zhuǎn)換成Idle(轉(zhuǎn)換完成時OMX會發(fā)送OMX_EventCmdComplete事件)殿较,接著對ACodec進行changeState至LoadedToIdleState耸峭。而在changeState過程中會調(diào)用ACodec::LoadedToIdleState::stateEntered() => ACodec::LoadedToIdleState::allocateBuffers() => ACodec::allocateBuffersOnPort(…),其中會為OMX組件端口分配緩沖斜脂,并向MediaCodec發(fā)送消息kWhatBuffersAllocated抓艳,消息處理中將MediaCodec狀態(tài)設(shè)為STARTED,而若allocateBuffers失敗則由IOMX經(jīng)OMXNodeInstance將OMX組件轉(zhuǎn)換回Loaded狀態(tài)帚戳,同時把ACodec狀態(tài)轉(zhuǎn)換回LoadedState玷或。(MediaCodec狀態(tài)從STARTING轉(zhuǎn)換為STARTED)
3.數(shù)據(jù)處理流程
3.1 emptyBuffer
(1)MediaCodec::start()之后ACodec此時處于LoadedToIdleState狀態(tài),此時若ACodec::LoadedToIdleState::onOMXEvent(…)接收到OMX組件轉(zhuǎn)換至Idle狀態(tài)后的OMX_EventCmdComplete事件片任,會向IOMX發(fā)送狀態(tài)轉(zhuǎn)換命令偏友,將組件狀態(tài)轉(zhuǎn)換成Executing,經(jīng)過OMXNodeInstance最終對將OMX組件狀態(tài)轉(zhuǎn)換成Executing狀態(tài)(這里如果OMX組件狀態(tài)轉(zhuǎn)換完成后对供,會向ACodec發(fā)送OMX_EventCmdComplete事件)位他,然后ACodec進行changeState至IdleToExecutingState氛濒。
(2)此時ACodec::IdleToExecutingState::onOMXEvent(…)檢測到上面的OMX_EventCmdComplete事件后,會首先調(diào)用函數(shù)ACodec::ExecutingState::resume()鹅髓,然后對ACodec進行changeState至ExecutingState舞竿。
(3)在函數(shù)ACodec::ExecutingState::resume()中會調(diào)用ACodec::BaseState::postFillThisBuffer(…),然后其中會先向MediaCodec發(fā)送kWhatFillThisBuffer消息窿冯,消息處理中在滿足相應(yīng)的條件下就會去調(diào)用函數(shù)MediaCodec::onInputBufferAvailable()來通知NuPlayer::Decoder有可用的input buffer骗奖;然后再生成kWhatInputBufferFilled消息,消息處理中調(diào)用ACodec::BaseState::onInputBufferFilled(…)醒串。
【此時產(chǎn)生了兩個消息执桌,一個是向上(MediaCodec)處理的postFillThisBuffer消息,一個向下(OMX)處理的kWhatInputBufferFilled消息芜赌,分別對應(yīng)上圖的步驟7仰挣,8】
(4)MediaCodec::onInputBufferAvailable()的調(diào)用:
??其中會先調(diào)用函數(shù)MediaCodec::dequeuePortBuffer(…)獲取buffer的索引,然后將一個新消息發(fā)送給NuPlayer::Decoder缠沈,并設(shè)置消息的callbackID為CB_INPUT_AVAILABLE膘壶,同時設(shè)置index,接著NuPlayer::Decoder接收到該CB_INPUT_AVAILABLE消息博烂,在消息處理中調(diào)用NuPlayer::Decoder::handleAnInputBuffer(…)香椎,其會:
先通過MediaCodec::getInputBuffer(…) -> MediaCodec::getBufferAndFormat(…)獲取該buffer。
然后調(diào)用NuPlayer::Decoder::onInputBufferFetched(…)執(zhí)行內(nèi)存拷貝將buffer拷貝到編解碼器禽篱,然后又調(diào)用了MediaCodec::queueInputBuffer(…)將buffer提交給解碼器畜伐,其會產(chǎn)生消息kWhatQueueInputBuffer,消息處理中調(diào)用MediaCodec::onQueueInputBuffer(…)躺率。
之后調(diào)用函數(shù)NuPlayer::DecoderBase::onRequestInputBuffers()玛界,處理是否需要更多的數(shù)據(jù)。其中會調(diào)用NuPlayer::Decoder::doRequestBuffers悼吱,若返回true則需要更多的數(shù)據(jù)慎框,則會產(chǎn)生新消息kWhatRequestInputBuffers,消息處理中又將調(diào)用onRequestInputBuffers后添。(實際獲取更多緩沖的操作在下面ACodec部分完成)笨枯。
(5)ACodec::BaseState::onInputBufferFilled(…)的調(diào)用:
??因為當(dāng)前ACodec在ExecutingState,所以PortMode為RESUBMIT_BUFFERS遇西,故會調(diào)用IOMX的emptyBuffer(…)方法馅精,經(jīng)過進程間通信調(diào)用到OMX::emptyBuffer(…),并最終調(diào)用OMXNodeInstance::emptyBuffer(…)粱檀,其中又會調(diào)用到函數(shù)OMXNodeInstance::emptyBuffer_l(…)洲敢,其則會調(diào)用OMX_EmptyThisBuffer宏對OMX組件進行相關(guān)的操作(根據(jù)需要選擇相應(yīng)的軟解組件或者硬解組件)。對于軟解組件SoftOMXComponent茄蚯。
其的構(gòu)造函數(shù)的初始化列表中有mComponent->EmptyThisBuffer = EmptyThisBufferWrapper;故實際會調(diào)用其EmptyThisBufferWrapper(…)函數(shù)压彭,而其中調(diào)用SoftOMXComponent的虛函數(shù)emptyThisBuffer睦优。
所以調(diào)用子類的emptyThisBuffer即SimpleSoftOMXComponent::emptyThisBuffer(…)產(chǎn)生kWhatEmptyThisBuffer消息,消息處理中實際的解碼器就要調(diào)用onQueueFilled(…)函數(shù)【實際組件繼承自SimpleSoftOMXComponent】
接著會調(diào)用SoftOMXComponent::notifyEmptyBufferDone(…)使用OMX的回調(diào)機制壮不,閉環(huán)發(fā)送消息到OMX客戶端ACodec汗盘。
調(diào)用到OMXNodeInstance::OnEmptyBufferDone(…),其又會調(diào)用OMX::OnEmptyBufferDone(…)忆畅,然后在其中會發(fā)送omx_message::EMPTY_BUFFER_DONE消息衡未,ACodec中收到該消息【CodecObserver中先收到,但只設(shè)置消息】調(diào)用ACodec::BaseState::onOMXEmptyBufferDone(…)
在onOMXEmptyBufferDone中獲取PortMode家凯,為RESUBMIT_BUFFERS則ACodec::BaseState::postFillThisBuffer(…)被調(diào)用,從而又從(3)中的postFillThisBuffer開始循環(huán)執(zhí)行相關(guān)操作以處理更多的輸入緩沖如失。
??這個流程就是圖中左邊的循環(huán):
3.2 fillBuffer
(1) 在上面OMX組件向ACodec發(fā)送OMX_EventCmdComplete事件后會調(diào)用到ACodec::ExecutingState::resume()函數(shù)绊诲,在resume()中調(diào)用ACodec::BaseState::postFillThisBuffer(…)前會先調(diào)用函數(shù)ACodec::ExecutingState::submitOutputBuffers(),即在獲取輸入數(shù)據(jù)前會先把輸出端的數(shù)據(jù)提交出去褪贵。
(2)在submitOutputBuffers()中調(diào)用ACodec::ExecutingState::submitRegularOutputBuffers()掂之,其中又會調(diào)用到IOMX的fillBuffer (…)方法,經(jīng)過進程間通信調(diào)用到OMX:: fillBuffer (…)脆丁,并最終調(diào)用OMXNodeInstance:: fillBuffer (…)世舰,其中又會調(diào)用到OMX_FillThisBuffer宏對OMX組件進行相關(guān)的操作(同樣根據(jù)需要選擇相應(yīng)的軟解組件或者硬解組件)。對于軟解組件SoftOMXComponent:(下面的操作與emptyBuffer時類似)
(3)在其構(gòu)造函數(shù)的初始化列表中有mComponent->FillThisBuffer = FillThisBufferWrapper;所以實際會調(diào)用到其FillThisBufferWrapper (…)函數(shù)槽卫;
(4)然后調(diào)用SimpleSoftOMXComponent::fillThisBuffer(…)產(chǎn)生kWhatFillThisBuffer消息跟压,消息處理中實際的組件就要調(diào)用onQueueFilled(…)函數(shù)【實際組件繼承自SimpleSoftOMXComponent】;
(5)接著會調(diào)用SoftOMXComponent::notifyFillBufferDone(…)使用OMX的回調(diào)機制歼培,閉環(huán)發(fā)送消息到OMX客戶端ACodec震蒋;
(6)之后調(diào)用到OMXNodeInstance:: OnFillBufferDone (…)函數(shù),其又會調(diào)用OMX:: OnFillBufferDone (…)躲庄,然后在其中會發(fā)送omx_message:: FILL_BUFFER_DONE消息查剖,ACodec中收到該消息【CodecObserver中先收到,但只設(shè)置消息】調(diào)用ACodec::BaseState:: onOMXFillBufferDone (…)噪窘;
(7)在onOMXFillBufferDone中獲取PortMode笋庄,為RESUBMIT_BUFFERS則首先如果需要繼續(xù)調(diào)用到IOMX的fillBuffer (…)填充輸出緩沖重復(fù)做相關(guān)操作,接著ACodec又會生成一個kWhatOutputBufferDrained消息存在reply中倔监,作為kWhatDrainThisBuffer消息的返回消息【notify->setMessage("reply", reply);】直砂,然后向MediaCodec發(fā)送消息kWhatDrainThisBuffer,消息處理中調(diào)用函數(shù)MediaCodec::onOutputBufferAvailable()通知NuPlayer::Decoder有可用的output buffer丐枉,其中會設(shè)置消息的callbackID為CB_OUTPUT_AVAILABLE哆键,同時設(shè)置index,接著NuPlayer::Decoder接收到該CB_OUTPUT_AVAILABLE消息瘦锹,在消息處理中調(diào)用NuPlayer::Decoder::handleAnOutputBuffer(…)籍嘹,在其中會進行如下處理:
先通過MediaCodec:: getOutputBuffer (…) -> MediaCodec::getBufferAndFormat(…)獲取該buffer的信息闪盔;
若Renderer非空則會調(diào)用NuPlayer::Renderer::queueBuffer(…)進行Renderer的相關(guān)處理同時消耗產(chǎn)生的kWhatRenderBuffer消息。queueBuffer()會產(chǎn)生kWhatQueueBuffer消息辱士,消息處理中會調(diào)用函數(shù)NuPlayer::Renderer::onQueueBuffer(…) –> NuPlayer::Renderer::postDrainVideoQueue() 【另外有audio的相關(guān)處理】泪掀,其中產(chǎn)生kWhatDrainVideoQueue消息,消息處理中調(diào)用先NuPlayer::Renderer::onDrainVideoQueue()在VideoQueue中取相關(guān)數(shù)據(jù)颂碘,再調(diào)用NuPlayer::Renderer::postDrainVideoQueue()循環(huán)取video數(shù)據(jù)异赫,接著還會發(fā)送kWhatRenderBuffer消息;
在kWhatRenderBuffer消息處理中會調(diào)用NuPlayer::Decoder::onRenderBuffer(…)头岔,在其中根據(jù)情況調(diào)用函數(shù)MediaCodec::renderOutputBufferAndRelease(..)渲染并釋放塔拳,或者調(diào)用MediaCodec::releaseOutputBuffer(…)不渲染直接釋放,兩中情況都會產(chǎn)生kWhatReleaseOutputBuffer消息峡竣,該消息處理中調(diào)用函數(shù)MediaCodec::onReleaseOutputBuffer(…)靠抑,其中判斷若SoftRenderer非空則進行軟件渲染,不然就會通過5)中的reply讓ACodec去硬件渲染适掰,在kWhatOutputBufferDrained消息處理就會中調(diào)用到函數(shù)ACodec::BaseState::onOutputBufferDrained(…)進行真正的硬件渲染颂碧。
??這個流程就是圖中右邊的循環(huán):
4.三者之間的狀態(tài)轉(zhuǎn)換
5.Sequence圖的代碼
在線畫圖鏈接:https://www.websequencediagrams.com/
5.1 NuPlayer Start Sequence
title NuPlayer Start Sequence
participant NuPlayerDriver as npd
participant NuPlayer as np
participant NuPlayerSource as nps
participant NuPlayerDecoder as d
participant MediaCodec as mc
participant ACodec as ac
npd->+np:start()
np-->np:KWhatStart
np->+np:onStart()
np->nps:start()
activate nps
deactivate nps
np->+np:postScanSources()
np-->np:kWhatScanSource
np->+np:InstantiateDecoder()
np->d:new Decoder()
activate d
deactivate d
np->d:init()
activate d
deactivate d
np->+d:configure(format)
note right of d:init()和configure()都是NuPlayer::Decoder\n 繼承自NuPlayer::DecoderBase的方法
d-->d:kWhatConfigure
d->+d:onConfigure()
d->+mc:CreateByType/CreateByComponentName()
mc->+mc:init()
mc->+mc:GetCodecBase()
mc->+ac:new ACodec
deactivate mc
mc-->mc:kWhatInit
mc->+mc:setState(INITIALIZING)
note right of ac:ACodec的構(gòu)造函數(shù)
deactivate mc
ac->+ac:changeState(UninitializedState)
deactivate ac
deactivate ac
deactivate mc
mc->+ac:initiateAllocateComponent()
ac-->ac:kWhatAllocateComponent
ac->+ac:onAllocateComponent()
ac->+IOMX:allocateNode()
ac-->-mc:CodecBase::kWhatComponentAllocated
deactivate IOMX
ac->+ac:changeState(LoadedState)
deactivate ac
deactivate ac
mc->+mc:setState(INITIALIZED)
deactivate mc
deactivate mc
d->+mc:mCodec->configure()
mc-->+mc:kWhatConfigure
mc->+mc:setState(CONFIGURING)
deactivate mc
mc->+ac:initiateConfigureComponent()
ac-->ac:kWhatConfigureComponent
opt ACodec Loaded狀態(tài)下的相應(yīng)方法
ac->+ac:onConfigureComponent()
ac->+ac:configureCodec()
ac->+IOMX:get/setParameter()...
deactivate ac
ac->mc:CodecBase::kWhatComponentConfigured
end
deactivate IOMX
deactivate ac
deactivate ac
mc->+mc:setState(CONFIGURED)
deactivate mc
deactivate mc
deactivate mc
d->+mc:mCodec->start()
mc-->+mc:kWhatStart()
mc->+mc:setState(STARTING)
deactivate mc
mc->+ac:initiateStart()
ac-->ac:kWhatStart
opt ACodec Loaded狀態(tài)下的相應(yīng)方法
ac->+ac:onStart()
ac->+IOMX:sendCommand(OMX_CommandStateSet, OMX_StateIdle)
IOMX-->-ac:OMX_EventCmdComplete
ac->+ac:changeState(LoadedToIdle)
end
opt ACodec LoadedToIdle 狀態(tài)下的相應(yīng)方法
ac->+ac:stateEnter()
ac->+ac:allocBuffers()
ac->+ac:allocBuffersOnPort()
ac->+IOMX:useBuffer()/allocateSecureBuffer()
deactivate IOMX
deactivate ac
deactivate ac
deactivate ac
ac-->-mc:CodecBase::kWhatBuffersAllocated
end
deactivate ac
deactivate ac
mc->+mc:setState(STARTED)
deactivate mc
deactivate mc
deactivate mc
deactivate d
deactivate d
deactivate np
deactivate np
deactivate np
deactivate np
5.2 NuPlayer Start Sequence--1
title NuPlayer Start Sequence--1
participant NuPlayerDriver as npd
participant NuPlayer as np
participant NuPlayerSource as nps
participant NuPlayerDecoder as d
npd->+np:start()
np-->np:KWhatStart
np->+np:onStart()
np->nps:start()
activate nps
deactivate nps
np->+np:postScanSources()
np-->np:kWhatScanSource
np->+np:InstantiateDecoder()
np->d:new Decoder()
activate d
deactivate d
np->d:init()
activate d
deactivate d
np->+d:configure(format)
note right of d:init()和configure()都是NuPlayer::Decoder\n 繼承自NuPlayer::DecoderBase的方法
d-->d:kWhatConfigure
d->+d:onConfigure()
deactivate mc
deactivate mc
deactivate mc
deactivate d
deactivate d
deactivate np
deactivate np
deactivate np
deactivate np
5.3 NuPlayer Start Sequence--2
title NuPlayer Start Sequence--2
participant NuPlayerDecoder as d
participant MediaCodec as mc
participant ACodec as ac
d->+mc:CreateByType/CreateByComponentName()
mc->+mc:init()
mc->+mc:GetCodecBase()
mc->+ac:new ACodec
deactivate mc
mc-->mc:kWhatInit
mc->+mc:setState(INITIALIZING)
note right of ac:ACodec的構(gòu)造函數(shù)
deactivate mc
ac->+ac:changeState(UninitializedState)
deactivate ac
deactivate ac
deactivate mc
mc->+ac:initiateAllocateComponent()
ac-->ac:kWhatAllocateComponent
ac->+ac:onAllocateComponent()
ac->+IOMX:allocateNode()
ac-->-mc:CodecBase::kWhatComponentAllocated
deactivate IOMX
ac->+ac:changeState(LoadedState)
deactivate ac
deactivate ac
mc->+mc:setState(INITIALIZED)
deactivate mc
deactivate mc
deactivate mc
deactivate d
deactivate d
deactivate np
deactivate np
deactivate np
deactivate np
5.4 NuPlayer Start Sequence--3
title NuPlayer Start Sequence--3
participant NuPlayerDecoder as d
participant MediaCodec as mc
participant ACodec as ac
d->+mc:mCodec->configure()
mc-->+mc:kWhatConfigure
mc->+mc:setState(CONFIGURING)
deactivate mc
mc->+ac:initiateConfigureComponent()
ac-->ac:kWhatConfigureComponent
opt ACodec Loaded狀態(tài)下的相應(yīng)方法
ac->+ac:onConfigureComponent()
ac->+ac:configureCodec()
ac->+IOMX:get/setParameter()...
deactivate ac
ac->mc:CodecBase::kWhatComponentConfigured
end
deactivate IOMX
deactivate ac
deactivate ac
mc->+mc:setState(CONFIGURED)
deactivate mc
deactivate mc
deactivate mc
deactivate mc
deactivate mc
deactivate mc
deactivate d
deactivate d
deactivate np
deactivate np
deactivate np
deactivate np
5.5 NuPlayer Start Sequence--4
title NuPlayer Start Sequence--4
participant NuPlayerDecoder as d
participant MediaCodec as mc
participant ACodec as ac
d->+mc:mCodec->start()
mc-->+mc:kWhatStart()
mc->+mc:setState(STARTING)
deactivate mc
mc->+ac:initiateStart()
ac-->ac:kWhatStart
opt ACodec Loaded狀態(tài)下的相應(yīng)方法
ac->+ac:onStart()
ac->+IOMX:sendCommand(OMX_CommandStateSet, OMX_StateIdle)
IOMX-->-ac:OMX_EventCmdComplete
ac->+ac:changeState(LoadedToIdle)
end
opt ACodec LoadedToIdle 狀態(tài)下的相應(yīng)方法
ac->+ac:stateEnter()
ac->+ac:allocBuffers()
ac->+ac:allocBuffersOnPort()
ac->+IOMX:useBuffer()/allocateSecureBuffer()
deactivate IOMX
deactivate ac
deactivate ac
deactivate ac
ac-->-mc:CodecBase::kWhatBuffersAllocated
end
deactivate ac
deactivate ac
mc->+mc:setState(STARTED)
deactivate mc
deactivate mc
deactivate mc
deactivate d
deactivate d
deactivate np
deactivate np
deactivate np
deactivate np
5.6 Empty Buffer Sequence
title Empty Buffer Sequence
participant GenerSource as gs
participant NuPlayerDecoder as d
participant MediaCodec as mc
participant ACodec as ac
participant IOMX as omx
opt ACodec LoadedToIdle狀態(tài)下的相應(yīng)方法
note right of omx:這個消息是發(fā)送讓組件轉(zhuǎn)換成\nIdle狀態(tài)的命令后,組件反饋回來的
omx-->+ac:1\. OMX_EventCmdComplete
ac->+omx:2\. sendCommand[OMX_Executing]
ac->+ac:3\. changeState[IdleToExecting]
deactivate ac
deactivate ac
end
opt ACodec IdeToExecuting狀態(tài)下的相應(yīng)方法
omx-->+ac:2.1 OMX_EventCmdComplete
note right of omx:同理类浪,這個也是發(fā)送讓組件狀態(tài)轉(zhuǎn)換\n為Executing命令后载城,組件反饋回來的
deactivate omx
end
opt ACodec Executing狀態(tài)下的相應(yīng)方法
ac->+ac:4\. resume()
ac->+ac:5\. submitOutputBuffers()
deactivate ac
ac->+ac:6\. postFillThisBuffer
note left of mc:在enptyBuffer前總是需要\n進行fillBuffer操作,先將\n組件輸出端的數(shù)據(jù)交出去\n后费就,才能為新輸入的數(shù)據(jù)\n解碼后騰出來地方
ac-->mc:7\. kWhatFillThisBuffer
mc->+mc:7.1 onInputBufferAvaliable()
mc-->+d:7.2 CB_INPUT_AVAILABLE
d->+d:7.3 handleAnInputBuffer()
d->+d:7.4 onRequestInputBuffer()
d->+d:7.5 doRequestBuffers()
loop 不斷循環(huán)地從Source獲取輸入數(shù)據(jù)
d->+d:7.6 fetchInputData()
d-->+gs:7.7 dequeueAccessUnit()
gs->+gs:7.8 postReadBuffer()
gs-->+gs:7.9 kWhatReadBuffer()
gs->+gs:7.10 onreadBuffer()
end
deactivate gs
deactivate gs
deactivate gs
deactivate gs
deactivate d
d->+d:7.11 onInputBufferFetched()
d->+mc:7.12 queueInputBuffer()
mc-->mc:7.13 kWhatQueueInputBuffer
mc->+mc:7.14 onQueueInputBuffer()
deactivate mc
deactivate mc
deactivate mc
deactivate ac
ac-->+ac:8\. kWhatInputBufferFilled
ac->+ac:8.1 onInputBufferFilled()
ac->+omx:8.2 emptyBuffer()
omx-->ac:8.3 EMPTY_BUFFER_DONE
deactivate omx
note right of omx:就是這個EMPTY_BUFFER_DONE诉瓦,ACodec\n收到這個消息后會調(diào)用ACodec::BaseState::\nonOMXEmptyBufferDone()函數(shù),然后再次\n調(diào)用ACodec::BaseState::postFillThsiBuffer()\n形成循環(huán)
deactivate ac
deactivate ac
deactivate ac
end
ac->+ac:9\. changeState[Executing]
5.7 Fille Buffer Sequence
title Fille Buffer Sequence
participant NuPlayerRenderer as npr
participant NuPlayerDecoder as d
participant MediaCodec as mc
participant ACodec as ac
participant IOMX as omx
participant SoftRenderer as sr
ac->+ac:1\. resume()
ac->+ac:2\. submitOutputBuffers()
ac->+ac:3\. submitRegularOutputBuffers()
ac->+omx:4\. fillBuffer()
deactivate ac
deactivate ac
omx-->+ac:5\. FILL_BUFFER_DONE
deactivate omx
ac->+ac:6\. onOMXFillBufferDone()
ac-->+mc:7\. kWhatDrainThisBuffer
deactivate ac
mc->+mc:8\. onOutputBufferAvailiable()
mc-->+d:9\. CB_OUTPUT_AVAILABLE
d->+d:10\. handleAnOutputBuffer()
d->+npr:11\. queueBuffer()
npr-->npr:11.1 kWhatQueueBuffer
npr->+npr:11.2 onQueueBuffer
npr->+npr:11.3 postDrainVideoQueue()
npr-->npr:11.4 kWhatDrainVideoQueue
npr->+npr:11.5 onDrainVideoQueue()
npr-->d:11.6 kWhatRenderBuffer
d->+d:12\. onRenderBuffer()
deactivate npr
d->+mc:12.1 renderOutputBufferAndRelease()\nreleaseOutputBuffer()
mc-->mc:12.2 kWhatReleaseOutputBuffer
mc->+mc:12.3 onReleaseOutputBuffer()
note right of ac: 軟件渲染
mc->+sr:12.4 render()
deactivate sr
deactivate mc
deactivate mc
deactivate mc
mc-->ac:12.5 kWhatOutputBufferDrained
deactivate mc
deactivate d
deactivate d
deactivate d
ac->+ac:12.6 onOutputBufferDrained()
note right of ac:硬件渲染
ac->+omx:12.7 fillBuffer()
deactivate omx