admin管理员组文章数量:1516870
承接上一章节分析:
本系列文章分析的安卓源码版本:【Android 10.0 版本】
推荐涉及到的知识点:
Binder机制实现原理:
ALooper机制实现原理:
Binder异常关闭监听:
在前面章节流程完毕后,底层编解码器组件在接收到输入输出端口Buffer(输入Buffer递交给组件流程此前已分析)后,将会执行【*mCallbacks->EmptyBufferDone】和【*mCallbacks->FillBufferDone】回调,即将会触发回调OMXNode中回调监听类【OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks】的onEmptyBufferDone消耗输入Buffer完成事件方法被执行和onFillBufferDone填充输出buffer完毕事件方法被执行。
也就是说此前我们终于完成了编解码器获取数据和输出数据的完整过程了!
因此本章节接下来分析这两个底层组件消耗输入buffer或填充输出buffer完成事件回调流程分析:
先分析onEmptyBufferDone,后分析onFillBufferDone
1、onEmptyBufferDone() 消耗输入Buffer完成事件方法实现分析:
// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]// static
OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
OMX_IN OMX_HANDLETYPE /* hComponent */,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer){
if(pAppData ==NULL){
ALOGE("b/25884056");return OMX_ErrorBadParameter;}// 强转
OMXNodeInstance *instance =static_cast<OMXNodeInstance *>(pAppData);if(instance->mDying){
// OMXNode死亡中,但还是返回无错误return OMX_ErrorNone;}// 从输出端口元数据中获取Fence描述符// 见1.1小节分析int fenceFd = instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput);// 创建OMX消息
omx_message msg;// 标记当前消息类型【EMPTY_BUFFER_DONE】
msg.type = omx_message::EMPTY_BUFFER_DONE;// 缓存fence描述符
msg.fenceFd = fenceFd;// 根据Buffer header来查询Buffer ID// 见1.2小节分析
msg.u.buffer_data.buffer = instance->findBufferID(pBuffer);// OMX消息分发// 见1.3小节分析
instance->mDispatcher->post(msg);// 返回成功return OMX_ErrorNone;}
1.1、instance->retrieveFenceFromMeta_l(pBuffer, kPortIndexOutput)实现分析:
从输出端口元数据中获取Fence描述符
// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]int OMXNodeInstance::retrieveFenceFromMeta_l(
OMX_BUFFERHEADERTYPE *header, OMX_U32 portIndex){
// 根据端口类别获取分配元数据大小
OMX_U32 metaSize = portIndex == kPortIndexInput ? header->nAllocLen : header->nFilledLen;int fenceFd =-1;// 判断端口元数据Buffer类型if(mMetadataType[portIndex]== kMetadataBufferTypeANWBuffer
&& header->nAllocLen >=sizeof(VideoNativeMetadata)){
// 是【VideoNativeMetadata】这种元数据类型时
VideoNativeMetadata &nativeMeta =*(VideoNativeMetadata *)(header->pBuffer);// 再判断元数据内部Buffer类型if(nativeMeta.eType == kMetadataBufferTypeANWBuffer){
// 直接获取该值,并重置-1
fenceFd = nativeMeta.nFenceFd;
nativeMeta.nFenceFd =-1;}if(metaSize <sizeof(nativeMeta)&& fenceFd >=0){
// 这种情况发生时为错误,也就是空数据/无效数据时CLOG_ERROR(foundFenceInEmptyMeta, BAD_VALUE,FULL_BUFFER(NULL, header, nativeMeta.nFenceFd));// 重置-1
fenceFd =-1;}}// 返回return fenceFd;}
1.2、instance->findBufferID(pBuffer)实现分析:
根据Buffer header来查询Buffer ID
如下,实际实现很简单就是在此前分配Buffer时缓存的映射map对象中获取对应ID
// [frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp]
IOMX::buffer_id OMXNodeInstance::findBufferID(OMX_BUFFERHEADERTYPE *bufferHeader){
if(bufferHeader ==NULL){
return0;}// 加锁访问
Mutex::Autolock autoLock(mBufferIDLock);
ssize_t index = mBufferHeaderToBufferID.indexOfKey(bufferHeader);if(index <0){
CLOGW("findBufferID: bufferHeader %p not found", bufferHeader);return0;}return mBufferHeaderToBufferID.valueAt(index);}
1.3、instance->mDispatcher->post(msg)实现分析:
消耗输入Buffer完成事件的OMX消息分发
关于该方法调用执行流程分析,我们已经在此前
章节中已有分析了,它将会最终执行到【ACodec::BaseState::onOMXMessage】该方法中,如下【省略其他代码】
// [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:// 省略其他代码 case omx_message::EMPTY_BUFFER_DONE:// Codec组件消耗输入Buffer完成事件{
IOMX::buffer_id bufferID;int32_t fenceFd;// 获取参数CHECK(msg->findInt32("buffer",(int32_t*)&bufferID));CHECK(msg->findInt32("fence_fd",&fenceFd));returnonOMXEmptyBufferDone(bufferID, fenceFd);}// 省略其他代码case omx_message::FILL_BUFFER_DONE:case omx_message::FRAME_RENDERED:default:ALOGE("Unexpected message type: %d", type);returnfalse;}}
onOMXEmptyBufferDone(bufferID, fenceFd)实现分析:
Codec组件消耗输入Buffer完成事件处理
也就是Codec组件递交输入Buffer返回,交还给上层继续去填充输入Buffer
版权声明:本文标题:探究AndroidMediaPlayer中的音频解码危机——当输出格式意外变化时 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.betaflare.com/biancheng/1773286371a3277469.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。


发表评论