Android多媒體框架--14:NuPlayer->MediaCodec->ACodec->OMX的整體流程與狀態(tài)轉(zhuǎn)換

"本文轉(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)寝蹈。下面先看一下整體的框架流程圖慧域。

01.png

上面的是整體的NuPlayer的框架圖,涉及的了很多的代碼流程片拍,下面將分成幾個部分逐步分析煌集。

2.1 從start到配置解碼器

02.png

(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)用。

03.png

??首先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)用。

04.png

??產(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)用赛不。

05.png

??產(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

06.png

(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):

207.png

3.2 fillBuffer

08.png

(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):

09.png

4.三者之間的狀態(tài)轉(zhuǎn)換

10.png

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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末受楼,一起剝皮案震驚了整個濱河市垦搬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌艳汽,老刑警劉巖猴贰,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異河狐,居然都是意外死亡米绕,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門馋艺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來栅干,“玉大人,你說我怎么就攤上這事捐祠〖盍郏” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵踱蛀,是天一觀的道長窿给。 經(jīng)常有香客問我贵白,道長,這世上最難降的妖魔是什么崩泡? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任禁荒,我火速辦了婚禮,結(jié)果婚禮上角撞,老公的妹妹穿的比我還像新娘呛伴。我一直安慰自己,他們只是感情好谒所,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布热康。 她就那樣靜靜地躺著,像睡著了一般劣领。 火紅的嫁衣襯著肌膚如雪褐隆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天剖踊,我揣著相機與錄音,去河邊找鬼衫贬。 笑死德澈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的固惯。 我是一名探鬼主播梆造,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼葬毫!你這毒婦竟也來了镇辉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤贴捡,失蹤者是張志新(化名)和其女友劉穎忽肛,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烂斋,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡屹逛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了汛骂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罕模。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖帘瞭,靈堂內(nèi)的尸體忽然破棺而出淑掌,到底是詐尸還是另有隱情,我是刑警寧澤蝶念,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布抛腕,位于F島的核電站芋绸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏兽埃。R本人自食惡果不足惜侥钳,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望柄错。 院中可真熱鬧舷夺,春花似錦、人聲如沸售貌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颂跨。三九已至敢伸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間恒削,已是汗流浹背池颈。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钓丰,地道東北人缓淹。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓靴姿,卻偏偏與公主長得像翔脱,于是被迫代替她去往敵國和親焚碌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容