OMXCodec执行流程细节


.创建实例(AwesomePlayer调用SetDataSource())



        .调用OMXCodec:Create()
                .findMatchingCodecs()
                .InstantiateSoftwareDecoder()
                .omx->allocateNode()
                .如果成功后,new OMXCodec()初始化OMXCodec,设置mState为LOADED
                        .setComponentRole()->调用omx->setParameter(OMX_IndexParamStandardComponentRole)
                .configureCodec(),调用setVideoOutputFormat()
                        .对InputPort做mOMX->getParameter(OMX_IndexParamPortDefinition)后修改宽、高、压缩比、颜色格式后mOMX->setParameter(OMX_IndexParamPortDefinition)
                        .对OutputPort做mOMX->getParameter(OMX_IndexParamPortDefinition)后修改宽、高后mOMX->setParameter(OMX_IndexParamPortDefinition)




.预备解码(AwesomePlayer调用play()中的initVideoDecoder())



        .调用OMXCodec:start()
                .如果是在paused的状态,则:(如果是硬解码,当前mState必须为PAUSED状态。mOMX-sendCommand(set,Executing),并setState(IDLE_TO_EXECUTING),并等待至mState变成EXECUTING或者ERROR,然后drainInputBuffers();如果是软解码,则直接drainInputBuffers()),并return
                .否则默认mState当前必须是LOADED状态,调用压缩数据源DataSource->start()
                .调用OMXCodec:init()
                        .调用mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle),并设置mState为LOADED_TO_IDLE
                        .调用allocateBuffers(),先mOMX->getParameter(OMX_IndexParamPortDefinition)读取port信息,再根据port定义的buffer size去mOMX->allocateBuffer()申请内存,然后将申请好的内存放在mPortBuffers[portIndex]里
                        .一直忙等直到mState变为Executing或Error,这期间会收到下层消息并调用onStateChange(OMX_StateIdle),mOMX->sendCommand(Set, OMX_StateExecuting)并设置mState为IDLE_TO_EXECUTING,再收到onStateChange(OMX_StateExecuting),并将mState设置为EXECUTING




.开始解码(AwesomePlayer调用play()中的postVideoEvent_l()后激活onVideoEvent())



        .调用OMXCodec:read()
                .先读取ReadOptions看看是不是seek
                .如果不是seek,则当前mState必须是EXECUTING或者RECONFIGURING
                .如果是提交的第一帧,先调用drainInputBuffers()
                        .执行drainInputBuffers()必须是在mState为EXECUTING,RECONFIGURING和FLUSHING的状态。
                        .从mPortBuffers[input]里循环取出每个BufferInfo,并对每个info->mStatus等于OWNED_BY_US的buffer调用drainInputBuffer(info)
                                .drainInputBuffer(BufferInfo)要求buffer必须是OWNED_BY_US
                                .如果有未处理的mCodecSpecificData则先mOMX->emptyBuffer(info->Buffer,OMX_BUFFERFLAG_CODECCONFIG)处理这些配置数据
                                .如果mSignalledEOS或者mPaused为true则停止drain并return false
                                .循环调用mSource->read()读取压缩源srcBuffer,读取失败的话则设置mSignalledEOS为true,如果成功则将其copy进info->mData里去
                                .结果是info->mData里装着从mSource中多次读取出来的数据总和,并将timestampUs设为第一块数据的kKeyTime值
                                .设置flags为OMX_BUFFERFLAG_ENDOFFRAME,如果刚才遇到EOS则再并一个OMX_BUFFERFLAG_EOS
                                .调用mOMX->emptyBuffer(mNode, info->mBuffer, 0, offset,flags, timestampUs);
                                .如果emptyBuffer返回OK,则设置info->mStatus为OWNED_BY_COMPONENT并return true,否则设置mState为ERROR并返回false
                .再调用fillOutputBuffers()
                        .执行fillOutputBuffers()必须是在mState为EXECUTING,FLUSHING的状态
                        .从mPortBuffers[output]里循环取出每个BufferInfo,并对每个info->mStatus等于OWNED_BY_US的buffer调用fillOutputBuffer(info)
                                .如果mNoMoreOutputData为true则return
                                .如果info->mMediaBuffer不为空,则取出其中的GraphicBuffer,并调用mNativeWindow->lockBuffer(mNativeWindow,graphicBuffer)来锁定该buffer,出错则设置mState为ERROR
                                .调用mOMX->fillBuffer(mNode, info->mBuffer)
                                .如果emptyBuffer返回OK,则设置info->mStatus为OWNED_BY_COMPONENT,否则设置mState为ERROR,最后return
                .如果mState不为ERROR,并且mNoMoreOutputData为false,并且mFilledBuffers为空,并且mOutputPortSettingsChangedPending为false的情况下,则调用waitForBufferFilled_l(),让mBufferFilled去wait lock
                .从waitForBufferFilled_l()释放出来后,判断mFilledBuffers为空的话,如果mOutputPortSettingsChangedPending为true则去调用之前延迟执行的onPortSettingsChanged(),否则return EOS
                .取出mFilledBuffers的第一个buffer,该buffer的mStatus此时必须为OWNED_BY_US。
                .然后设置其为OWNED_BY_CLIENT,给该buffer的mMediaBuffer->add_ref()增加一个引用,并把该mMediaBuffer赋值给buffer并返回给AwesomePlayer








. 暂停解码(AwesomePlayer调用pause()。本地播放只有audio会pause;而video只会clear "OnVideoEvent“, 只有在http streaming时才会调用pause)



        .调用OMXCodec::pause()
                .mState必须是EXECUTING状态,否则返回ERROR。如果当前是“中间状态“则waitlock。
                .如果当前是qcom解码器,则调用mOMX->sendCommand(Set, OMX_StatePause),并设置mState为PAUSING,设置mPaused为true。然后waitlock直到mState变成PAUSED或者ERROR
                        .下层执行完毕后调用omCmdComplete(),然后进入onStateChange(OMX_StatePause),断定当前mState必须是PAUSING,然后将其设置为PAUSED
                .如果不是qcom解码器则只设置mPaused为true并return






. 恢复解码(AwesomePlayer调用play(),onVideoEvent()恢复执行,AudioPlayer会调用resume())



        .调用OMXCodec:start() (只有audio会调用,video的会直接调用read())
        .当在paused的状态,则:(如果是硬解码,当前mState必须为PAUSED状态。mOMX-sendCommand(set,Executing),并setState(IDLE_TO_EXECUTING),并等待至mState变成EXECUTING或者ERROR,然后drainInputBuffers();如果是软解码,则直接drainInputBuffers()),并return
                .调用drainInputBuffers()-> drainInputBuffer(BufferInfo *info)......(同之前的drainInputBuffer()描述)






. Seek操作(AwesomePlayer调用seekTo方法)



        .从ReadOptions中取出seekTimeUs, seekMode,并设置seeking为true
        .如果当前seeking为true,并且mState为PAUSING或者PAUSED,并且解码器是qcom的,则:
                .如果mState是PAUSING,则waitlock,等到其为PAUSED,且必须为PAUSED
                .发送mOMX->sendCommand(Set, OMX_StateExecuting),并设置mState为IDLE_TO_EXECUTING,mPaused为false,并等待Executing状态设置成功后,执行drainInputBuffers()
        .如果当前mState不是EXECUTING或者RECONFIGURING的话,则直接返回UNKNOWN_ERROR
        .如果当前seeking为true,则:
                .当mState为RECONFIGURING,则一直忙等执行waitForBufferFilled_l(),即mBufferFilled一直waitlock,直到mState不为RECONFIGURING
                .如果mState不为EXECUTING,则return UNKNOWN_ERROR
                .设置mSignalledEOS为false,并清空mFilledBuffer
                .设置当前mState为FLUSHING
                .分别对output port和input port做flushPortAsync()
                        .flushPortAsync()执行时mState必须是EXECUTING 或者 RECONFIGURING 或者 EXECUTING_TO_IDLE 或者 FLUSHING
                        .断定当前mPortStatus[portIndex]必须是ENABLED,然后将mPortStatus设成SHUTTING_DOWN
                        .发送mOMX->sendCommand(OMX_CommandFlush, portIndex)
                .当mSeekTimeUs大于等于0,则waitForBufferFilled_l()直到mSeekTimeUs小于0;如果出错,并且当时mState为FLUSHING,则设置mState为EXECUTING
                .如果mState不为ERROR,并且mNoMoreOutputData为false,并且mFilledBuffers为空,并且mOutputPortSettingsChangedPending为false的情况下,则调用waitForBufferFilled_l(),让mBufferFilled去waitlock
                .如果seeking为true,则断定当前mState为FLUSHING,然后将其设置为EXECUTING
                .取出mFilledBuffers的第一个buffer,该buffer的mStatus此时必须为OWNED_BY_US。
                .然后设置其为OWNED_BY_CLIENT,给该buffer的mMediaBuffer->add_ref()增加一个引用,并把该mMediaBuffer赋值给buffer并返回给AwesomePlayer






. 停止解码(AwesomePlayer调用shutdownVideoDecoder_l())



        .调用OMXCodec:stop(),如果当前mState是中间状态,则waitlock等待
        .设置isError和forceFlush为false
        .如果当前mState状态为LOADED,则break
        .如果当前mState状态为ERROR,则:
                .如果当前的mPortStatus[output]为ENABLING,则freeBuffersOnPort(portIndex,onlyThoseWeOwn)去释放尽可能多的buffer,为保证析构能正常释放实例避免assert crash,设置mStatus为LOADED,并break
                .如果不是ENABLING,则mOMX->getState()获取当前状态,如果state不是Executing或者Pause的话,则设置forceFlush为true,并break,否则设置isError为true并fall through到下面来
        .如果当前mState状态为PAUSED或者EXECUTING,则:
                .设置mState为EXECUTING_TO_IDLE
                .设置mPortStatus[input/output]为SHUTTING_DOWN,并发送mOMX->sendCommand(Set, OMX_StateIdle),并waitlock直到mState为LOADED或ERROR
                        .底层通知onStateChange(Idle)成功,并断定当前mState为EXECUTING_TO_IDLE,并断定countBufferWeOwn()必须是mPortBuffers.size()
                        .发送mOMX->sendCommand(Set, OMX_StateLoaded),同时freeBuffersOnPort(in/out),设置mPortStatus[in/out]为ENABLED,并设置mState为IDLE_TO_LOADED
                                .freeBuffersOnPort()会循环断定每个buffer的mStatus必须为OWNED_BY_US或者OWNED_BY_NATIVE_WINDOW,或者OWNED_BY_COMPONENT但参数onlyThoseWeOwn为true
                                .freeBuffer()调用mOMX->freeBuffer(portIndex, info->mBuffer),并断定info->mMediaBuffer->refcount()为0,调用cancelBufferToNativeWindow(),并info->mMediaBuffer->release(),这将触发signalBufferReturned()
                        .收到onStateChange(Loaded),断定mState为IDLE_TO_LOADED,设置mState为LOADED
                .如果mState是ERROR,则设置forceFlush为true;如果isError为true,则设置mState为ERROR
                .如果forceFlush()为true,则调用flushBuffersOnError()
                        .通过mOMX->getState()返回OK断定component还活着,设置mPortStatus[in/out]为ENABLED,设置mState为EXCUTING_TO_IDLE
                        .flushPortAsync(in/out),设置mState为ERROR以滤掉所有EBD/FBD,然后循环15次查看mPortBuffers是否被收回
                        .将所有mStatus为OWNED_BY_US的buffer都执行一遍cancelBufferToNativeWindow()
        .最后将压缩源mSource->stop(),并return OK





. 注销实例(AwesomePlayer调用shutdownVideoDecoder_l())



        .断定当前mState必须为LOADED,ERROR或者LOADED_TO_IDLE
        .调用mOMX->freeNode()
        .releaseMediaBuffersOn(input/output)
        .设置mState为DEAD
        .清除mCodecSpecificData








. 底层通知on_message() -> omx_message::EMPTY_BUFFER_DONE



        .根据buffer_id获取对应的BufferInfo, 设置info->mStatus为OWNED_BY_US
        .如果info->mMediaBuffer不为空,则调用info->mMediaBuffer->release(),其会调用signalBufferReturned()
                .signalBufferReturned()首先断定mPortStatus[output]为ENABLED,并且info->mStatus为OWNED_BY_CLIENT, 然后设置info->mStatus为OWNED_BY_US
                .如果buffer的graphicBuffer为空并且mOutputPortSettingsChangedPending是false的话,则fillOutputBuffer()
                .否则获取kKeyRendered,如果为false则cancelBufferToNativeWindow(),设置info->mStatus为OWNED_BY_NATIVE_WINDOW
                        .如果mOutputPortSettingsChangedPending为false的话,dequeueBufferFromNativeWindow()获取下一个buffer,然后fillOutputBuffer(nextBufInfo)
                        .否则调用onPortSettingsChanged(ouput)
        .如果当前mPortStatus[input]为DISABLING,则调用freeBuffer()
        .或者如果mState不为ERROR,并且mPortStatus[input]不为SHUTTING_DOWN的话,断定mPortStatus[input]为ENABLED,并且drainInputBuffer()




. 底层通知on_message() -> omx_message::FILL_BUFFER_DONE



.根据buffer_id获取对应的BufferInfo, 设置info->mStatus为OWNED_BY_US
.如果当前mPortStatus[output]为DISABLING,则调用freeBuffer()
.或者如果mPortStatus[output]不为SHUTTING_DOWN的话
        .断定mPortStatus[input]为ENABLED
        .如果info->mMediaBuffer为空的话,则
                .断定mOMXLivesLocally为true,mQuirks包含kRequiresAllocateBufferOnOutputPorts和kDefersOutputBufferAllocation
                .info->mMediaBuffer=new MediaBuffer(),并且设置info->mMediaBuffer->setObserver为当前的OMXCodec实例
        .设置一堆info->mMediaBuffer的meta后,如果mTargetTimeUs大于等于0并且info的timestamp小于mTargetTimeUs的话,则skip这个buffer,调用fillOutputBuffer(info)后break;否则mFilledBuffers.push_back该buffer,然后mBufferFilled.signal()






. 底层通知on_message() -> onEvent() -> OMX_EventPortSettingsChanged



        .OMXCodec:onEvent(OMX_EventPortSettingsChanged)被调用,如果当前mState不是EXECUTING则忽略
        .如果port是ouput并且mFilledBuffers不为空则mDeferReason或上一个FILLED_BUFFERS_PRESENT,或者如果countOutputBuffers(OWNED_BY_CLIENT)>0则mDeferReason或上一个BUFFER_WITH_CLIENT,则设置mOutputPortSettingsChangedPending为true
        .如果mDeferReason不为空,则调用mBufferFilled.signal()激活waitforbufferfilled();如果为空,则调用onPortSettingsChanged()
                .onPortSettingsChanged首先断定mState为EXECUTING,port是output,并且mOutputPortSettingsChangedPending为false
                .如果mPortStatus[output]不是ENABLED,则延迟port setting change,设置mOutputPortSettingsChangedPending为ture并return
                .否则设置mState为RECONFIGURING,并调用disablePortAsync(portIndex)
                        .disablePortAsync()断定当前mState必须为EXECUTING或者RECONFIGURING,并且mPortStatus[portIndex]必须为ENABLED
                        .设置mPortStatus为DISABLING,并发送mOMX->sendCommand(OMX_CommandPortDisable),并调用freeBuffersOnPort(portIndex,onThoseWeOwn)
                                .收到底层onCmdComplete(OMX_CommandPortDisable)的消息
                                .断定mState为EXECUTING或者RECONFIGURING,断定mPortStatus为DISABLING,断定mPortBuffers.size()必须为0
                                .设置mPortStatus为DISABLED
                                .如果mState为RECONFIGURING,则调用initOutputFormat(),通过mOMX->getParameter/setParameter重新初始化参数
                                .调用enablePortAsync()
                                        .断定mState为EXECUTING或RECONFIGURING,断定mPortStatus为DISABLED,再设置其为ENABLING
                                        .发送mOMX->sendCommand(OMX_CommandPortEnable)
                                                .收到底层onCmdComplete(OMX_CommandPortEnable),断定mState为EXECUTING或者RECONFIGURING,断定mPortStatus为ENABLING,然后设置mPortStatus为ENABLED
                                                .如果mState是RECONFIGURING,则设置mState为EXECUTING,并执行fillOutputBuffers()
                                .如果enablePortAsync()返回OK,则allocateBuffersOnPort(),否则设置mState为ERROR






. 底层通知on_message() -> onEvent() -> onCmdComplete() -> OMX_CommandFlush



        .断定mPortStatus[index]为SHUTTING_DOWN,然后设置mPortStatus[index]为ENABLED
        .断定countBufferWeOwn()必须为mPortBuffers.size()
        .如果当前mState是RECONFIGURING,则调用disablePortAsync()
        .或者如果当前mState是EXECUTING_TO_IDLE,并且mPortStatus[in/out]都为ENABLED,则设置mPortStatus[in/out]为SHUTTING_DOWN,并发送mOMX->sendCommand(Set, OMX_StateIdle)
        .否则,当前应该是为seeking做准备而flush所有port(mState当前应该是FLUSHING)
                .如果mPort[in/out]都是ENABLED,则设置mPaused为false,并drainInputBuffers()和fillOutputBuffers()
                .如果mOutputPortSettingsChangedPending为true,则设置mOutputPortSettingsChangedPending为false
                        .如果countOutputBuffers(OWNED_BY_CLIENT) > 0则设置mOutputPortSettingsChangedPending为true,并mDeferReason或一个BUFFER_WITH_CLIENT后break
                        .否则断定mFilledBuffers为空,并且调用onPortSettingsChanged(kPortIndexOutput)


你可能感兴趣的:(Multimedia,Android,Platform)