【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 4】【03】

2021/5/14 20:55:27

本文主要是介绍【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 4】【03】,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

承接上一章节分析:【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 4】【02】
本系列文章分析的安卓源码版本:【Android 10.0 版本】

【此章节小节编号就接着上一章节排列】
8.2.1、handleMessage(*it)处理消息实现分析:
OMXNodeInstance的该方法返回true才表明自身处理该事件类型
备注:FILL_BUFFER_DONE该事件其实就是编解码器将指定buffer id的buffer(已编码或已解码)数据填充完成事件
而EMPTY_BUFFER_DONE事件则是编解码器将指定buffer id的buffer(待编码或待解码)数据消耗完成事件
这两个事件将会在后续流程涉及时直接提示定位到给分析,所以该方法的分析将不会完全分析,等到后续再次分析,若是完全分析了也没关系,后续直接提示这里然后定位到后续流程即可

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
bool OMXNodeInstance::handleMessage(omx_message &msg) {
    if (msg.type == omx_message::FILL_BUFFER_DONE) {
    	// 获取buffer header类型结构数据对象,是用于记录扩展buffer数据,见下面的定义
    	// findBufferHeader实现,见8.2.1.1小节分析
        OMX_BUFFERHEADERTYPE *buffer =
            findBufferHeader(msg.u.extended_buffer_data.buffer, kPortIndexOutput);
        if (buffer == NULL) {
            ALOGE("b/25884056");
            return false;
        }

		// 该代码块处理的是debug相关可用数据,也就是记录和打印当前buffer内容情况
        {
            Mutex::Autolock _l(mDebugLock);
            mOutputBuffersWithCodec.remove(buffer);

            CLOG_BUMPED_BUFFER(
                    FBD, WITH_STATS(FULL_BUFFER(
                            msg.u.extended_buffer_data.buffer, buffer, msg.fenceFd)));

            unbumpDebugLevel_l(kPortIndexOutput);
        }

        BufferMeta *buffer_meta =
            static_cast<BufferMeta *>(buffer->pAppPrivate);

        if (buffer->nOffset + buffer->nFilledLen < buffer->nOffset
                || buffer->nOffset + buffer->nFilledLen > buffer->nAllocLen) {
            // 数据有误时错误打印
            CLOG_ERROR(onFillBufferDone, OMX_ErrorBadParameter,
                    FULL_BUFFER(NULL, buffer, msg.fenceFd));
        }
        // 根据方法名就可知,该功能就是复制OMX类型的数据buffer到指定buffer数据类型中
        // 见8.2.1.2小节分析
        buffer_meta->CopyFromOMX(buffer);

        // fix up the buffer info (especially timestamp) if needed
        // 若需要的话,则修复buffer数据相关信息,尤其是时间戳
        // 见8.2.1.2小节分析
        codecBufferFilled(msg);
    } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
    	// 同上分析
        OMX_BUFFERHEADERTYPE *buffer =
            findBufferHeader(msg.u.buffer_data.buffer, kPortIndexInput);
        if (buffer == NULL) {
            return false;
        }
		
		// 打印
        {
            Mutex::Autolock _l(mDebugLock);
            mInputBuffersWithCodec.remove(buffer);

            CLOG_BUMPED_BUFFER(
                    EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer, msg.fenceFd)));
        }

        // 由前面分析过,解码器(本地文件播放时)该对象为null,也就说提供数据源不是Input输入Surface,而是来自文件数据源
        const sp<IOMXBufferSource> bufferSource(getBufferSource());

		// 备注:因此可以看到该方法内返回true的流程只有此处,最终我们可以知道在我们使用MediaCodec时
		// 若没有设置输入Surface来提供数据源时,该方法将不会直接消耗任何事件消息,
		// 即OMX底层组件消息都将返回传递给上层来处理
        if (bufferSource != NULL) {
            // This is one of the buffers used exclusively by IOMXBufferSource.
            // Don't dispatch a message back to ACodec, since it doesn't
            // know that anyone asked to have the buffer emptied and will
            // be very confused.
            bufferSource->onInputBufferEmptied(
                    msg.u.buffer_data.buffer, OMXFenceParcelable(msg.fenceFd));
            return true;
        }
    } else if (msg.type == omx_message::EVENT &&
            msg.u.event_data.event == OMX_EventDataSpaceChanged) {
        // 数据空间信息改变时,其实前面分析过很多次,它讲的就是色彩空间描述信息的改变,
        // 比如色域值、基元色、矩阵系数、矩阵转换类型,指的是这几个数据变化。
        // 也就是说当前图像输入buffer使用了新的数据空间来编码数据时执行此处。
        // 也就是将会重新执行一遍以前配置编解码器时配置数据空间信息的处理,更新底层组件该信息的变化
        handleDataSpaceChanged(msg);
    }

    // 默认false,不拦截OMX消息
    return false;
}

OMX_BUFFERHEADERTYPE结构定义:
扩展buffer数据结构,其英文注释比较明确指出每个字段的意思和作用

// [frameworks/native/headers/media_plugin/media/openmax/OMX_Core.h]

/** @ingroup buf */
typedef struct OMX_BUFFERHEADERTYPE
{
    OMX_U32 nSize;              /**< size of the structure in bytes */
    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
    OMX_U8* pBuffer;            /**< Pointer to actual block of memory
                                     that is acting as the buffer */
    // 当前整个buffer分配内存大小(单位字节)
    OMX_U32 nAllocLen;          /**< size of the buffer allocated, in bytes */
    // 当前buffer中填充的数据字节数(单位字节)
    OMX_U32 nFilledLen;         /**< number of bytes currently in the
                                     buffer */
    // 当前buffer中有效数据从缓冲区开始(起始位置)的起始偏移量(单位字节)
    OMX_U32 nOffset;            /**< start offset of valid data in bytes from
                                     the start of the buffer */
    // 上层程序关联该buffer的私有数据类型对象指针,可用于强转为目标正确的数据
    OMX_PTR pAppPrivate;        /**< pointer to any data the application
                                     wants to associate with this buffer */
    OMX_PTR pPlatformPrivate;   /**< pointer to any data the platform
                                     wants to associate with this buffer */
    OMX_PTR pInputPortPrivate;  /**< pointer to any data the input port
                                     wants to associate with this buffer */
    OMX_PTR pOutputPortPrivate; /**< pointer to any data the output port
                                     wants to associate with this buffer */
    OMX_HANDLETYPE hMarkTargetComponent; /**< The component that will generate a
                                              mark event upon processing this buffer. */
    OMX_PTR pMarkData;          /**< Application specific data associated with
                                     the mark sent on a mark event to disambiguate
                                     this mark from others. */
    OMX_U32 nTickCount;         /**< Optional entry that the component and
                                     application can update with a tick count
                                     when they access the component.  This
                                     value should be in microseconds.  Since
                                     this is a value relative to an arbitrary
                                     starting point, this value cannot be used
                                     to determine absolute time.  This is an
                                     optional entry and not all components
                                     will update it.*/
 OMX_TICKS nTimeStamp;          /**< Timestamp corresponding to the sample
                                     starting at the first logical sample
                                     boundary in the buffer. Timestamps of
                                     successive samples within the buffer may
                                     be inferred by adding the duration of the
                                     of the preceding buffer to the timestamp
                                     of the preceding buffer.*/
  OMX_U32     nFlags;           /**< buffer specific flags */
  OMX_U32 nOutputPortIndex;     /**< The index of the output port (if any) using
                                     this buffer */
  OMX_U32 nInputPortIndex;      /**< The index of the input port (if any) using
                                     this buffer */
} OMX_BUFFERHEADERTYPE;

8.2.1.1、findBufferHeader(msg.u.extended_buffer_data.buffer, kPortIndexOutput)实现分析:
获取指定扩展buffer数据的buffer id对应的buffer头信息对象

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(
        IOMX::buffer_id buffer, OMX_U32 portIndex) {
    // buffer id为0则返回null 
    if (buffer == 0) {
        return NULL;
    }
    // 加锁即mBufferIDLockbuffer id锁
    Mutex::Autolock autoLock(mBufferIDLock);
    // 键值对集合对象,类似map对象定义:【该对象将在后续Codecs工作流程时添加映射数据】
    // KeyedVector<IOMX::buffer_id, OMX_BUFFERHEADERTYPE *> mBufferIDToBufferHeader;
    // 通过buffer id来查询对应的key列表中的key索引,小于0则表示不存在该id
    ssize_t index = mBufferIDToBufferHeader.indexOfKey(buffer);
    if (index < 0) {
        CLOGW("findBufferHeader: buffer %u not found", buffer);
        return NULL;
    }
    // 然后获取该id对应的buffer header扩展数据对象指针
    OMX_BUFFERHEADERTYPE *header = mBufferIDToBufferHeader.valueAt(index);
    
    // 然后强转【header->pAppPrivate】字段即上层程序私有对象指针为BufferMeta媒体元数据buffer对象指针
    // 备注:该对象后续涉及到时再详细分析
    BufferMeta *buffer_meta =
        static_cast<BufferMeta *>(header->pAppPrivate);
    // 然后判断该id对应的媒体元数据buffer的端口索引和请求的索引是否一致,不一致则错误返回null    
    if (buffer_meta->getPortIndex() != portIndex) {
        CLOGW("findBufferHeader: buffer %u found but with incorrect port index.", buffer);
        android_errorWriteLog(0x534e4554, "28816827");
        return NULL;
    }
    return header;
}

8.2.1.2、buffer_meta->CopyFromOMX(buffer)实现分析:
复制OMX类型的数据buffer到指定buffer数据类型中

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
struct BufferMeta {
	// 这只是其中一个通常使用的构造函数,还有另外两个不常用构造函数
    explicit BufferMeta(
            const sp<IMemory> &mem, const sp<IHidlMemory> &hidlMemory,
            OMX_U32 portIndex, bool copy, OMX_U8 *backup)
        : mMem(mem),
          mHidlMemory(hidlMemory),
          mCopyFromOmx(portIndex == kPortIndexOutput && copy),
          mCopyToOmx(portIndex == kPortIndexInput && copy),
          mPortIndex(portIndex),
          mBackup(backup) {
    }
    
    // 获取当前buffer数据访问起始位置地址的指针
    // 此处处理可知,该媒体元数据buffer对象接收两种不同的数据类型提供数据
    // 若都不存在则返回空指针
    OMX_U8 *getPointer() {
        return mMem.get() ? static_cast<OMX_U8*>(mMem->pointer()) :
                mHidlMemory.get() ? static_cast<OMX_U8*>(
                static_cast<void*>(mHidlMemory->getPointer())) : nullptr;
    }
    
    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
    	// 该参数的判断为其构造函数时初始化的:即是否允许拷贝OMX数据类型中的buffer数据
    	// mCopyFromOmx(portIndex == kPortIndexOutput && copy)
        if (!mCopyFromOmx) {
            return;
        }

        // 检查OMX组件返回的数据正确范围
        // OMX_BUFFERFLAG_EXTRADATA表示额外数据存在标志:有额外的数据附加到驻留在缓冲区中的数据流(后面)
        // check component returns proper range
        sp<ABuffer> codec = getBuffer(header,!(header->nFlags & OMX_BUFFERFLAG_EXTRADATA));

        // 此处将获取到的【ABuffer】对象中有效数据buffer放入到相对于起始地址的
        // 【header->nOffset】该偏移量地址之后的后续数据位置地址
        memcpy(getPointer() + header->nOffset, codec->data(), codec->size());
    }

    // return the codec buffer
    sp<ABuffer> getBuffer(const OMX_BUFFERHEADERTYPE *header, bool limit) {
    	// limit参数根据上面分析可知,若header数据中没有OMX_BUFFERFLAG_EXTRADATA标志,则为true,有的话则为false
    	// 创建ABuffer来管理数据buffer
    	// 备注:关于ABuffer源码实现请查看早前流程中的分析
        sp<ABuffer> buf = new ABuffer(header->pBuffer, header->nAllocLen);
        if (limit) {
        	// limi限制标志位true时,将会重新计算ABuffer中真正可读的解码器输出数据(已编码或已解码数据)的可读数据访问
            if (header->nOffset + header->nFilledLen > header->nOffset
                    && header->nOffset + header->nFilledLen <= header->nAllocLen) {
                // 设置ABuffer中可读数据的有效范围    
                buf->setRange(header->nOffset, header->nFilledLen);
            } else {
            	// 这种情况时,表示数据异常了,因此将不能读取任何的有效数据
                buf->setRange(0, 0);
            }
        }
        return buf;
    }
}

8.2.1.2、codecBufferFilled(msg)实现分析:
若需要的话,则修复buffer数据相关信息,尤其是时间戳

// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
void OMXNodeInstance::codecBufferFilled(omx_message &msg) {
	// 加锁
    Mutex::Autolock autoLock(mLock);

    if (mMaxTimestampGapUs == 0LL || mRestorePtsFailed) {
    	// 若最大间隔时间戳为0或者恢复PTS(显示时间戳)失败,则return
        return;
    }

    // 该Buffer的标志位
    OMX_U32 &flags = msg.u.extended_buffer_data.flags;
    // 时间戳信息结构对象,注意它是个结构OMX_TICKS,是将一个64位表示的时间戳分为高低位两部分来存储表示
    OMX_TICKS &timestamp = msg.u.extended_buffer_data.timestamp;

    if (!(flags & OMX_BUFFERFLAG_CODECCONFIG)) {
    	// 此处是编码器时才会进入处理
    	// 若没有该标志,如音频MP3或AAC数据封装使用ADTS模式时就不会有该标志位,而应该正常展示该数据流,
    	// 也就是该数据流每帧数据开始都有一个特殊帧头信息。
        ssize_t index = mOriginalTimeUs.indexOfKey(timestamp);
        if (index >= 0) {
            ALOGV("OUT timestamp: %lld -> %lld",
                    static_cast<long long>(timestamp),
                    static_cast<long long>(mOriginalTimeUs[index]));
            // 更新时间戳并在原始时间戳列表中移除该时间        
            timestamp = mOriginalTimeUs[index];
            mOriginalTimeUs.removeItemsAt(index);
        } else {
        	// 未存在该时间戳时
        	// 英文意思就是:放弃努力吧,因为编码器似乎并没有维护PTS值,因此标记恢复PTS失败
            // giving up the effort as encoder doesn't appear to preserve pts
            ALOGW("giving up limiting timestamp gap (pts = %lld)", timestamp);
            mRestorePtsFailed = true;
        }
    }
}

8.2.2、mObserver->onMessages(messages)实现分析:
执行此前创建OMXNodeInstance时传入的回调监听实现类对象
备注:其实在OMXNode类中该对象mObserver实际上只是个Bp代理对象,它最终会调用Bn实现端BnOMXObserver的子类CodecObserver,该类在ACodec中声明和定义的,并且该mObserver是在另外章节分析过的即Android MediaPlayer整体架构源码分析 -【MediaCodec编解码器插件模块化注册和创建处理流程】【Part 8】章节部分中详细分析初始化过程。
关于这两个Bp和Bn之间的实现是在IOMX.cpp中,前面我们分析过非常多的Binder实现机制,因此我们不再详细分析关于中间调用转换,直接定位到实现类的对应方法即可。

// [frameworks/av/media/libstagefright/ACodec.cpp]
struct CodecObserver : public BnOMXObserver {
    // from IOMXObserver
    virtual void onMessages(const std::list<omx_message> &messages) {
        if (messages.empty()) {
            return;
        }
		// 根据前面创建章节流程可知,mNotify是一个【kWhatOMXMessageList】事件通知的消息对象,ACodec自己接收该消息处理。
        sp<AMessage> notify = mNotify->dup();
        // 创建本地消息列表对象
        // 备注:该类实现很简单因此不详细分析,实现原理为,
        // 内部创建了std::list<sp<AMessage> > mList;即消息列表对象来存储消息的。
        // 也就是说下面的处理其实就是将OMX消息对象类型转换给上层的AMessage消息类型而已。
        sp<MessageList> msgList = new MessageList();
        for (std::list<omx_message>::const_iterator it = messages.cbegin();
              it != messages.cend(); ++it) {
            const omx_message &omx_msg = *it;

            // 创建AMessage消息对象来转存OMX消息对象中的数据
            sp<AMessage> msg = new AMessage;
            msg->setInt32("type", omx_msg.type);
            switch (omx_msg.type) {
                case omx_message::EVENT:
                {
                    msg->setInt32("event", omx_msg.u.event_data.event);
                    msg->setInt32("data1", omx_msg.u.event_data.data1);
                    msg->setInt32("data2", omx_msg.u.event_data.data2);
                    break;
                }

                case omx_message::EMPTY_BUFFER_DONE:
                {
                    msg->setInt32("buffer", omx_msg.u.buffer_data.buffer);
                    msg->setInt32("fence_fd", omx_msg.fenceFd);
                    break;
                }

                case omx_message::FILL_BUFFER_DONE:
                {
                    msg->setInt32(
                            "buffer", omx_msg.u.extended_buffer_data.buffer);
                    msg->setInt32(
                            "range_offset",
                            omx_msg.u.extended_buffer_data.range_offset);
                    msg->setInt32(
                            "range_length",
                            omx_msg.u.extended_buffer_data.range_length);
                    msg->setInt32(
                            "flags",
                            omx_msg.u.extended_buffer_data.flags);
                    msg->setInt64(
                            "timestamp",
                            omx_msg.u.extended_buffer_data.timestamp);
                    msg->setInt32(
                            "fence_fd", omx_msg.fenceFd);
                    break;
                }

                case omx_message::FRAME_RENDERED:
                {
                    msg->setInt64(
                            "media_time_us", omx_msg.u.render_data.timestamp);
                    msg->setInt64(
                            "system_nano", omx_msg.u.render_data.nanoTime);
                    break;
                }

                default:
                    ALOGE("Unrecognized message type: %d", omx_msg.type);
                    break;
            }
            // 添加该消息对象到消息列表中
            msgList->getList().push_back(msg);
        }
        // 最后缓存设置给【kWhatOMXMessageList】事件通知的消息对象,并立即发送
        // 该消息事件接收处理见下面的分析
        notify->setObject("messages", msgList);
        notify->post();
    }
}

【kWhatOMXMessageList】事件通知消息接收处理:

// [frameworks/av/media/libstagefright/ACodec.cpp]
bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case ACodec::kWhatOMXMessageList:
        {
            // 见下面分析,消息无效则直接返回true,有效则执行处理消息流程
            return checkOMXMessage(msg) ? onOMXMessageList(msg) : true;
        }
    }
}

checkOMXMessage(msg)实现分析:
检查OMX消息有效性,返回true即有效

// [frameworks/av/media/libstagefright/ACodec.cpp]
bool ACodec::BaseState::checkOMXMessage(const sp<AMessage> &msg) {
    // there is a possibility that this is an outstanding message for a
    // codec that we have already destroyed
    if (mCodec->mOMXNode == NULL) {
    	// 若当前OMXNode节点实例不存在即组件已被释放时则忽略已过期事件
        ALOGI("ignoring message as already freed component: %s",
                msg->debugString().c_str());
        return false;
    }

    // 此处检查此前该【kWhatOMXMessageList】事件通知的消息对象创建时传入的代数值,
    // 也就是说当前事件消息对象是否已经过期或被更新了
    int32_t generation;
    CHECK(msg->findInt32("generation", (int32_t*)&generation));
    if (generation != mCodec->mNodeGeneration) {
    	// 过期返回false则丢弃这些消息
        ALOGW("Unexpected message for component: %s, gen %u, cur %u",
                msg->debugString().c_str(), generation, mCodec->mNodeGeneration);
        return false;
    }
    return true;
}

onOMXMessageList(msg)实现分析:

// [frameworks/av/media/libstagefright/ACodec.cpp]
bool ACodec::BaseState::onOMXMessageList(const sp<AMessage> &msg) {
	// 获取前面设置的消息列表对象指针,并强制转换
    sp<RefBase> obj;
    CHECK(msg->findObject("messages", &obj));
    sp<MessageList> msgList = static_cast<MessageList *>(obj.get());

    // 该标识表示是否接受到已渲染事件,true为已接受到该事件
    bool receivedRenderedEvents = false;
    // 循环接收处理每一个事件消息
    for (std::list<sp<AMessage>>::const_iterator it = msgList->getList().cbegin();
          it != msgList->getList().cend(); ++it) {
        // 设置每个事件类型为【ACodec::kWhatOMXMessageItem】,也就是它将会被ACodec自己接收处理
        (*it)->setWhat(ACodec::kWhatOMXMessageItem);
        // ACodec接收处理每一个【ACodec::kWhatOMXMessageItem】事件消息
        // 见下面的分析
        mCodec->handleMessage(*it);
        int32_t type;
        CHECK((*it)->findInt32("type", &type));
        if (type == omx_message::FRAME_RENDERED) {
            receivedRenderedEvents = true;
        }
    }

    if (receivedRenderedEvents) {
        // NOTE: all buffers are rendered in this case
        mCodec->notifyOfRenderedFrames();
    }
    return true;
}

mCodec->handleMessage(*it)实现分析:
ACodec接收处理每一个【ACodec::kWhatOMXMessageItem】事件消息
注意:该方法在ACodec初始化流程中已分析过,请查看此前分析章节,它最终将会执行当前状态机实现者的【onMessageReceived】方法,而对于当前事件消息的处理统一都在父类状态实现的,如下

// [frameworks/av/media/libstagefright/ACodec.cpp]
bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) {
    switch (msg->what()) {
        case ACodec::kWhatOMXMessageItem:
        {
            // 此处的英文注释意思是:不需要再次检查该消息事件的有效性了,因为前面已经检查过了
            // no need to check as we already did it for kWhatOMXMessageList
            return onOMXMessage(msg);
        }
    }
}

onOMXMessage(msg)实现分析:
接收处理每一个OMX消息事件,从下面实现可以看来还是通过OMX消息类型来处理不同结构参数,以此不同处理。
注意:该方法的 bool 返回值的作用在早前相关章节中分析到过,就是用于ACodec的状态机当前状态实现链判断是否该消息事件被当前状态实现者接收处理了,若为true则表示当前状态实现者能够处理该消息,否则不能处理它将会忽略该消息。
目前OMX消息类型只有四个类型上传到ACodec来处理,并且根据我们前面分析的流程来看,目前若是根据代码执行流程来分析,那么以下分析目前只需要分析【EVENT】消息处理流程,因为该流程处理之后就在接下来状态机状态扭转为【ExecutingState】即编解码器正在执行任务状态实现者了,并且注意当前状态实际上一定是【LoadedToIdleState】状态实现,因为前面【ACodec::LoadedState::onStart()】实现的代码中可能我们觉得【OMX_StateIdle】状态命令执行完毕再执行的【changeState(mCodec->mLoadedToIdleState)】扭转状态,其实并非如此,因为根据前面分析我们可知并且也提到过这两个流程的执行在该状态命令到达底层组件接收到该命令处理流程时将会在组件内部线程中执行后续流程,因此onStart()中将会继续往下执行,也就是可以先看8.3小节的执行流程,再来看接下来mLoadedToIdleState状态实现者的【onOMXEvent】方法实现流程,最终将会进入扭转到【ExecutingState】,该分析流程将后续的分析中

// [frameworks/av/media/libstagefright/ACodec.cpp]
bool ACodec::BaseState::onOMXMessage(const sp<AMessage> &msg) {
    int32_t type;
    CHECK(msg->findInt32("type", &type));

    switch (type) {
        case omx_message::EVENT:
        {
            int32_t event, data1, data2;
            CHECK(msg->findInt32("event", &event));
            CHECK(msg->findInt32("data1", &data1));
            CHECK(msg->findInt32("data2", &data2));

            if (event == OMX_EventCmdComplete
                    && data1 == OMX_CommandFlush
                    && data2 == (int32_t)OMX_ALL) {
                // Use of this notification is not consistent across
                // implementations. We'll drop this notification and rely
                // on flush-complete notifications on the individual port
                // indices instead.

                // 此处可知,底层组件在所有的OMX buffer端口都执行Flush命令完成事件,
                // 则直接在此处接收它,不需要下个流程接收处理,也就是是否需要将该事件消息给子类【onOMXEvent】方法接收处理。
                // 原因正如英文注释所述,应该接收单一buffer索引的flush完成事件通知。
                return true;
            }

            // 接收处理执行
            // 见8.2.2.1小节分析
            return onOMXEvent(
                    static_cast<OMX_EVENTTYPE>(event),
                    static_cast<OMX_U32>(data1),
                    static_cast<OMX_U32>(data2));
        }
		
		// 下面三个OMX消息类型也非常重要,但目前先不分析,将会在后续涉及这些流程处理时直接定位此处分析 TODO

        case omx_message::EMPTY_BUFFER_DONE:
        {
            IOMX::buffer_id bufferID;
            int32_t fenceFd;

            CHECK(msg->findInt32("buffer", (int32_t*)&bufferID));
            CHECK(msg->findInt32("fence_fd", &fenceFd));

            return onOMXEmptyBufferDone(bufferID, fenceFd);
        }

        case omx_message::FILL_BUFFER_DONE:
        {
            IOMX::buffer_id bufferID;
            CHECK(msg->findInt32("buffer", (int32_t*)&bufferID));

            int32_t rangeOffset, rangeLength, flags, fenceFd;
            int64_t timeUs;

            CHECK(msg->findInt32("range_offset", &rangeOffset));
            CHECK(msg->findInt32("range_length", &rangeLength));
            CHECK(msg->findInt32("flags", &flags));
            CHECK(msg->findInt64("timestamp", &timeUs));
            CHECK(msg->findInt32("fence_fd", &fenceFd));

            return onOMXFillBufferDone(
                    bufferID,
                    (size_t)rangeOffset, (size_t)rangeLength,
                    (OMX_U32)flags,
                    timeUs,
                    fenceFd);
        }

        case omx_message::FRAME_RENDERED:
        {
            int64_t mediaTimeUs, systemNano;

            CHECK(msg->findInt64("media_time_us", &mediaTimeUs));
            CHECK(msg->findInt64("system_nano", &systemNano));

            return onOMXFrameRendered(
                    mediaTimeUs, systemNano);
        }

        default:
            ALOGE("Unexpected message type: %d", type);
            return false;
    }
}

8.2.2.1、onOMXEvent()接收处理执行:
前面小节已分析过该方法可以是BaseState父类状态的具体子类状态实现者进行重写,处理自身业务。但也会有默认父类该方法处理。

由于该部分分析较长,因此单独拎出后续章节分析,请查看:
【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 7】
TODO

8.3、mCodec->changeState(mCodec->mLoadedToIdleState)实现分析:
扭转状态机状态为IDLE状态机实现者,根据最开始状态机实现分析可知,将会执行该状态实现的进入方法
备注:该流程和前面的8.2流程将会在8.2流程进入到具体组件后同步执行,因为8.2中命令到达组件后组件内部是异步线程回调通知的。

由于本章节接下来内容篇幅过长,因此必须放入另一章节分析,请查看:
TODO 【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 4】【04】



这篇关于【六】Android MediaPlayer整体架构源码分析 -【start请求播放处理流程】【Part 4】【03】的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程