美文网首页
Android多媒体框架--14:NuPlayer->Media

Android多媒体框架--14:NuPlayer->Media

作者: DarcyZhou | 来源:发表于2023-04-28 07:45 被阅读0次

    "本文转载自:[yanbixing123]的Android MultiMedia框架完全解析 - 从NuPlayer到MediaCodec到ACodec到OMX的整体流程与状态转换"

    1.概述

      前面的文档已经对Nuplayer架构不同的部分进行了详细的分析,这里再重新总结一下NuPlayer整体框架。同时也补充上MediaCodec,ACodec与OMX Plugin之间的状态切换关系。

    2. 初始化过程

      这里的初始化过程从NuPlayer开始,因为上层MediaPlayer只是一个“壳”,实际的播放器功能由NuPlayer实现。下面先看一下整体的框架流程图。

    01.png

    上面的是整体的NuPlayer的框架图,涉及的了很多的代码流程,下面将分成几个部分逐步分析。

    2.1 从start到配置解码器

    02.png

    (1)NuPlayer::start()时产生一个kWhatStart,在消息处理函数中如果是暂停后的开始就调用NuPlayer::onResume()【只需mSource->resume()和mRenderer->resume()】,否则调用NuPlayer::onStart()。

    (2)在函数NuPlayer::onStart()中会先后进行如下操作:(设置Source状态、初始化Renderer、初始化Decoder,并将三者关联起来)。

    (3)若mSource【source类对象】没有开始,则mSource->start(),来启动音视频包读取。

    (4)创建Render和并为其创建一个名为mRendererLooper的ALooper,这里通过setPlaybackSettings函数,来为Renderer设置时钟频率,与MediaClock关联起来,这个时钟在音视频同步中很重要。然后获取Framerate,设置到Renderer中,并使用setRenderer方法将Render与Decoder关联起来(这里需要讲音频Decoder和视频Decoder都与Renderer关联起来)。

    (5)调用NuPlayer::postScanSources(),然后其中生成kWhatScanSources消息,在消息处理中会根据情况调用NuPlayer::instantiateDecoder(…)初始化video或者audio解码器【需要在audio解码器之前实例化video解码器,因为成功初始化视频解码器可能会改变音频解码器的深度缓冲模式】。

    (6)在instantiateDecoder中,根据情况用new Decoder(…)创建音视频解码器(NuPlayer::Decoder),为其创建名为mCodecLooper的ALooper【其父类NuPlayer::DecoderBase的构造中则会创建mDecoderLooper】。

    (7)对该解码器进行init()操作,调用NuPlayer::DecoderBase::init()为mDecoderLooper注册handler【init()和configure()都是NuPlayerDecoder继承自NuPlayer::DecoderBase的方法】

    (8)对该解码器进行configure(format)操作,调用NuPlayer::DecoderBase::configure(…)产生一个kWhatConfigure消息,然后消息处理中调用NuPlayer::Decoder::onConfigure(…),在onConfigure中,首先会调用MediaCodec::CreateByType(…)或者MediaCodec::CreateByComponentName(…)根据情况创建MediaCodec,接着调用MediaCodec::init(…);随后调用MediaCodec::configure(…)对MediaCodec进行配置使其转入Configured状态;然后又调用MediaCodec::start()使MediaCodec转入Started状态。

    2.2 解码器创建

      MediaCodec::createByType()/MediaCodec::CreateByComponentName()的调用。

    03.png

      首先new一个MediaCodec,之后就调用MediaCodec的构造函数,设置MediaCodec的状态为UNINITIALIZED。调用codec->init()函数,在这个函数中,通过GetCodecBase来创建ACodec,然后发送kWhatInit消息,在消息处理中,设置MediaCodec状态为INITIALIZING,之后通过mCodec->initiateAllocateComponent(format)调用到ACodec的ACodec::initiateAllocateComponent()函数,这个函数发送kWhatAllocateComponent消息,在消息处理函数中,通过onAllocateComponent()里面的omx->allocateNode()函数来创建OMX插件,之后设置ACodec状态为Loaded,同时ACodec向MediaCodec返回CodecBase::kWhatComponentAllocated消息,在这个消息处理函数中,设置MediaCodec状态为INITIALIZED。(MediaCodec状态从INITIALIZING转换为INITIALIZED)

    2.3 解码器配置

      MediaCodec::configure(…)的调用。

    04.png

      产生kWhatConfigure消息,在消息处理中调用ACodec::initiateConfigureComponent(…)又产生消息kWhatConfigureComponent,然后该消息处理中又调用了ACodec::LoadedState::onConfigureComponent(…)。然后在其中又会先调用ACodec::configureCodec(…),在configureCodec中会对IOMX进行一系列的设置以及配置操作,通过Binder通信就对OMXNodeInstance进行相应的设置和配置操作,最终就对OMX组件进行了相应的设置和配置。然后向MediaCodec发送kWhatComponentConfigured消息,在消息处理中将MediaCodec状态设为CONFIGURED;(MediaCodec状态从CONFIGURING转换为CONFIGURED)

    2.4 解码器启动

      MediaCodec::start()的调用。

    05.png

      产生kWhatStart消息,消息处理中先将MediaCodec状态设为STARTING,然后调用ACodec::initiateStart()产生kWhatStart消息,在其消息处理中又调用ACodec::LoadedState::onStart(),然后在其中首先向IOMX发送状态转换命令,经过OMXNodeInstance最终对将OMX组件状态转换成Idle(转换完成时OMX会发送OMX_EventCmdComplete事件),接着对ACodec进行changeState至LoadedToIdleState。而在changeState过程中会调用ACodec::LoadedToIdleState::stateEntered() => ACodec::LoadedToIdleState::allocateBuffers() => ACodec::allocateBuffersOnPort(…),其中会为OMX组件端口分配缓冲,并向MediaCodec发送消息kWhatBuffersAllocated,消息处理中将MediaCodec状态设为STARTED,而若allocateBuffers失败则由IOMX经OMXNodeInstance将OMX组件转换回Loaded状态,同时把ACodec状态转换回LoadedState。(MediaCodec状态从STARTING转换为STARTED)

    3.数据处理流程

    3.1 emptyBuffer

    06.png

    (1)MediaCodec::start()之后ACodec此时处于LoadedToIdleState状态,此时若ACodec::LoadedToIdleState::onOMXEvent(…)接收到OMX组件转换至Idle状态后的OMX_EventCmdComplete事件,会向IOMX发送状态转换命令,将组件状态转换成Executing,经过OMXNodeInstance最终对将OMX组件状态转换成Executing状态(这里如果OMX组件状态转换完成后,会向ACodec发送OMX_EventCmdComplete事件),然后ACodec进行changeState至IdleToExecutingState。

    (2)此时ACodec::IdleToExecutingState::onOMXEvent(…)检测到上面的OMX_EventCmdComplete事件后,会首先调用函数ACodec::ExecutingState::resume(),然后对ACodec进行changeState至ExecutingState。

    (3)在函数ACodec::ExecutingState::resume()中会调用ACodec::BaseState::postFillThisBuffer(…),然后其中会先向MediaCodec发送kWhatFillThisBuffer消息,消息处理中在满足相应的条件下就会去调用函数MediaCodec::onInputBufferAvailable()来通知NuPlayer::Decoder有可用的input buffer;然后再生成kWhatInputBufferFilled消息,消息处理中调用ACodec::BaseState::onInputBufferFilled(…)。

    【此时产生了两个消息,一个是向上(MediaCodec)处理的postFillThisBuffer消息,一个向下(OMX)处理的kWhatInputBufferFilled消息,分别对应上图的步骤7,8】

    (4)MediaCodec::onInputBufferAvailable()的调用:

      其中会先调用函数MediaCodec::dequeuePortBuffer(…)获取buffer的索引,然后将一个新消息发送给NuPlayer::Decoder,并设置消息的callbackID为CB_INPUT_AVAILABLE,同时设置index,接着NuPlayer::Decoder接收到该CB_INPUT_AVAILABLE消息,在消息处理中调用NuPlayer::Decoder::handleAnInputBuffer(…),其会:

    • 先通过MediaCodec::getInputBuffer(…) -> MediaCodec::getBufferAndFormat(…)获取该buffer。

    • 然后调用NuPlayer::Decoder::onInputBufferFetched(…)执行内存拷贝将buffer拷贝到编解码器,然后又调用了MediaCodec::queueInputBuffer(…)将buffer提交给解码器,其会产生消息kWhatQueueInputBuffer,消息处理中调用MediaCodec::onQueueInputBuffer(…)。

    • 之后调用函数NuPlayer::DecoderBase::onRequestInputBuffers(),处理是否需要更多的数据。其中会调用NuPlayer::Decoder::doRequestBuffers,若返回true则需要更多的数据,则会产生新消息kWhatRequestInputBuffers,消息处理中又将调用onRequestInputBuffers。(实际获取更多缓冲的操作在下面ACodec部分完成)。

    (5)ACodec::BaseState::onInputBufferFilled(…)的调用:

      因为当前ACodec在ExecutingState,所以PortMode为RESUBMIT_BUFFERS,故会调用IOMX的emptyBuffer(…)方法,经过进程间通信调用到OMX::emptyBuffer(…),并最终调用OMXNodeInstance::emptyBuffer(…),其中又会调用到函数OMXNodeInstance::emptyBuffer_l(…),其则会调用OMX_EmptyThisBuffer宏对OMX组件进行相关的操作(根据需要选择相应的软解组件或者硬解组件)。对于软解组件SoftOMXComponent。

    • 其的构造函数的初始化列表中有mComponent->EmptyThisBuffer = EmptyThisBufferWrapper;故实际会调用其EmptyThisBufferWrapper(…)函数,而其中调用SoftOMXComponent的虚函数emptyThisBuffer。

    • 所以调用子类的emptyThisBuffer即SimpleSoftOMXComponent::emptyThisBuffer(…)产生kWhatEmptyThisBuffer消息,消息处理中实际的解码器就要调用onQueueFilled(…)函数【实际组件继承自SimpleSoftOMXComponent】

    • 接着会调用SoftOMXComponent::notifyEmptyBufferDone(…)使用OMX的回调机制,闭环发送消息到OMX客户端ACodec。

    • 调用到OMXNodeInstance::OnEmptyBufferDone(…),其又会调用OMX::OnEmptyBufferDone(…),然后在其中会发送omx_message::EMPTY_BUFFER_DONE消息,ACodec中收到该消息【CodecObserver中先收到,但只设置消息】调用ACodec::BaseState::onOMXEmptyBufferDone(…)

    • 在onOMXEmptyBufferDone中获取PortMode,为RESUBMIT_BUFFERS则ACodec::BaseState::postFillThisBuffer(…)被调用,从而又从(3)中的postFillThisBuffer开始循环执行相关操作以处理更多的输入缓冲。

      这个流程就是图中左边的循环:

    207.png

    3.2 fillBuffer

    08.png

    (1) 在上面OMX组件向ACodec发送OMX_EventCmdComplete事件后会调用到ACodec::ExecutingState::resume()函数,在resume()中调用ACodec::BaseState::postFillThisBuffer(…)前会先调用函数ACodec::ExecutingState::submitOutputBuffers(),即在获取输入数据前会先把输出端的数据提交出去。

    (2)在submitOutputBuffers()中调用ACodec::ExecutingState::submitRegularOutputBuffers(),其中又会调用到IOMX的fillBuffer (…)方法,经过进程间通信调用到OMX:: fillBuffer (…),并最终调用OMXNodeInstance:: fillBuffer (…),其中又会调用到OMX_FillThisBuffer宏对OMX组件进行相关的操作(同样根据需要选择相应的软解组件或者硬解组件)。对于软解组件SoftOMXComponent:(下面的操作与emptyBuffer时类似)

    (3)在其构造函数的初始化列表中有mComponent->FillThisBuffer = FillThisBufferWrapper;所以实际会调用到其FillThisBufferWrapper (…)函数;

    (4)然后调用SimpleSoftOMXComponent::fillThisBuffer(…)产生kWhatFillThisBuffer消息,消息处理中实际的组件就要调用onQueueFilled(…)函数【实际组件继承自SimpleSoftOMXComponent】;

    (5)接着会调用SoftOMXComponent::notifyFillBufferDone(…)使用OMX的回调机制,闭环发送消息到OMX客户端ACodec;

    (6)之后调用到OMXNodeInstance:: OnFillBufferDone (…)函数,其又会调用OMX:: OnFillBufferDone (…),然后在其中会发送omx_message:: FILL_BUFFER_DONE消息,ACodec中收到该消息【CodecObserver中先收到,但只设置消息】调用ACodec::BaseState:: onOMXFillBufferDone (…);

    (7)在onOMXFillBufferDone中获取PortMode,为RESUBMIT_BUFFERS则首先如果需要继续调用到IOMX的fillBuffer (…)填充输出缓冲重复做相关操作,接着ACodec又会生成一个kWhatOutputBufferDrained消息存在reply中,作为kWhatDrainThisBuffer消息的返回消息【notify->setMessage("reply", reply);】,然后向MediaCodec发送消息kWhatDrainThisBuffer,消息处理中调用函数MediaCodec::onOutputBufferAvailable()通知NuPlayer::Decoder有可用的output buffer,其中会设置消息的callbackID为CB_OUTPUT_AVAILABLE,同时设置index,接着NuPlayer::Decoder接收到该CB_OUTPUT_AVAILABLE消息,在消息处理中调用NuPlayer::Decoder::handleAnOutputBuffer(…),在其中会进行如下处理:

    • 先通过MediaCodec:: getOutputBuffer (…) -> MediaCodec::getBufferAndFormat(…)获取该buffer的信息;

    • 若Renderer非空则会调用NuPlayer::Renderer::queueBuffer(…)进行Renderer的相关处理同时消耗产生的kWhatRenderBuffer消息。queueBuffer()会产生kWhatQueueBuffer消息,消息处理中会调用函数NuPlayer::Renderer::onQueueBuffer(…) –> NuPlayer::Renderer::postDrainVideoQueue() 【另外有audio的相关处理】,其中产生kWhatDrainVideoQueue消息,消息处理中调用先NuPlayer::Renderer::onDrainVideoQueue()在VideoQueue中取相关数据,再调用NuPlayer::Renderer::postDrainVideoQueue()循环取video数据,接着还会发送kWhatRenderBuffer消息;

    • 在kWhatRenderBuffer消息处理中会调用NuPlayer::Decoder::onRenderBuffer(…),在其中根据情况调用函数MediaCodec::renderOutputBufferAndRelease(..)渲染并释放,或者调用MediaCodec::releaseOutputBuffer(…)不渲染直接释放,两中情况都会产生kWhatReleaseOutputBuffer消息,该消息处理中调用函数MediaCodec::onReleaseOutputBuffer(…),其中判断若SoftRenderer非空则进行软件渲染,不然就会通过5)中的reply让ACodec去硬件渲染,在kWhatOutputBufferDrained消息处理就会中调用到函数ACodec::BaseState::onOutputBufferDrained(…)进行真正的硬件渲染。

      这个流程就是图中右边的循环:

    09.png

    4.三者之间的状态转换

    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的构造函数
    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状态下的相应方法
        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状态下的相应方法
        ac->+ac:onStart()
        ac->+IOMX:sendCommand(OMX_CommandStateSet, OMX_StateIdle)
    
        IOMX-->-ac:OMX_EventCmdComplete
    ac->+ac:changeState(LoadedToIdle)
    end
    
    opt ACodec LoadedToIdle 状态下的相应方法
        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的构造函数
    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状态下的相应方法
        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状态下的相应方法
        ac->+ac:onStart()
        ac->+IOMX:sendCommand(OMX_CommandStateSet, OMX_StateIdle)
    
        IOMX-->-ac:OMX_EventCmdComplete
    ac->+ac:changeState(LoadedToIdle)
    end
    
    opt ACodec LoadedToIdle 状态下的相应方法
        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状态下的相应方法
        note right of omx:这个消息是发送让组件转换成\nIdle状态的命令后,组件反馈回来的
        omx-->+ac:1\. OMX_EventCmdComplete
        ac->+omx:2\. sendCommand[OMX_Executing]
        ac->+ac:3\. changeState[IdleToExecting]
        deactivate ac
        deactivate ac
    end
    
    opt ACodec IdeToExecuting状态下的相应方法
        omx-->+ac:2.1 OMX_EventCmdComplete
        note right of omx:同理,这个也是发送让组件状态转换\n为Executing命令后,组件反馈回来的
        deactivate omx
    end
    
    opt ACodec Executing状态下的相应方法
        ac->+ac:4\. resume()
        ac->+ac:5\. submitOutputBuffers()
        deactivate ac
    
        ac->+ac:6\. postFillThisBuffer
    
    note left of mc:在enptyBuffer前总是需要\n进行fillBuffer操作,先将\n组件输出端的数据交出去\n后,才能为新输入的数据\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 不断循环地从Source获取输入数据
        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收到这个消息后会调用ACodec::BaseState::\nonOMXEmptyBufferDone()函数,然后再次\n调用ACodec::BaseState::postFillThsiBuffer()\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
    

    相关文章

      网友评论

          本文标题:Android多媒体框架--14:NuPlayer->Media

          本文链接:https://www.haomeiwen.com/subject/wioxjdtx.html