一、引言:

nuplayer播放器是使用MediaCodec来进行编解码的,而OMX组件则是MediaCodec的解码核心,但是因为涉及的面太过底层,往往是芯片公司才会涉及到这一块,所以就做一个简单分析,对通路有个大致了解就行。

二、流程跟踪:

从MediaCodec的api来分析下流程:

1.构造函数:

MediaCodec::CreateByType()和MediaCodec::CreateByComponentName()只是对外初始化MediaCodec的不同接口,前者是以接收mimetype来进行初始化,后者则是通过确定的codec名字来实例化,在构造了MediaCodec之后最终都会调入到MediaCodec::init中;

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

2.MediaCodec::init分析:

status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) {.../* 1.实例化ACodec */mCodec = new ACodec;.../* 2.注册hanlder用于消息处理 */mLooper->registerHandler(this);mCodec->setNotificationMessage(new AMessage(kWhatCodecNotify, id()));/* 3.处理kWhatInit消息 */sp<AMessage> msg = new AMessage(kWhatInit, id());msg->setString("name", name);msg->setInt32("nameIsType", nameIsType);if (nameIsType) {msg->setInt32("encoder", encoder);}sp<AMessage> response;return PostAndAwaitResponse(msg, &response);
}

先来看下ACodec的实例化,ACodec可以理解为Android对于解码器的封装层,对下衔接OMX解码组件,对上回调必要信息到MediaCodec:

ACodec::ACodec(): mQuirks(0),mNode(0),mSentFormat(false),mIsEncoder(false),mUseMetadataOnEncoderOutput(false),mFatalError(false),mShutdownInProgress(false),mExplicitShutdown(false),mEncoderDelay(0),mEncoderPadding(0),mRotationDegrees(0),mChannelMaskPresent(false),mChannelMask(0),mDequeueCounter(0),mStoreMetaDataInOutputBuffers(false),mMetaDataBuffersToSubmit(0),mRepeatFrameDelayUs(-1ll),mMaxPtsGapUs(-1ll),mTimePerFrameUs(-1ll),mTimePerCaptureUs(-1ll),mCreateInputBuffersSuspended(false),mTunneled(false) {mFastOutput = false;mHisiVdp = false;mIsVideo = false;mSaveES = false;mVideoFile = NULL;mAudioFile = NULL;mStats = false;sEnableLogcatV = false;char value[PROPERTY_VALUE_MAX];if (property_get("service.media.codec.logcat", value, "false")&& (!strcasecmp("true", value))) {sEnableLogcatV = true;}if (property_get("service.media.codec.savees", value, "false")&& (!strcasecmp("true", value))) {ALOGI("Will save ES streams");mSaveES = true;}if (property_get("service.media.codec.stats", value, "false")&& (!strcasecmp("true", value))) {mStats = true;}mUninitializedState = new UninitializedState(this);mLoadedState = new LoadedState(this);mLoadedToIdleState = new LoadedToIdleState(this);mIdleToExecutingState = new IdleToExecutingState(this);mExecutingState = new ExecutingState(this);mOutputPortSettingsChangedState =new OutputPortSettingsChangedState(this);mExecutingToIdleState = new ExecutingToIdleState(this);mIdleToLoadedState = new IdleToLoadedState(this);mFlushingState = new FlushingState(this);mPortEOS[kPortIndexInput] = mPortEOS[kPortIndexOutput] = false;mInputEOSResult = OK;changeState(mUninitializedState);
}

ACodec构造最主要的操作是实例化了各种状态值,通过消息机制来对OMX进行操作。最后再来看下kWhatInit消息的处理:

        case kWhatInit:{uint32_t replyID;CHECK(msg->senderAwaitsResponse(&replyID));if (mState != UNINITIALIZED) {PostReplyWithError(replyID, INVALID_OPERATION);break;}mReplyID = replyID;setState(INITIALIZING);AString name;CHECK(msg->findString("name", &name));int32_t nameIsType;int32_t encoder = false;CHECK(msg->findInt32("nameIsType", &nameIsType));if (nameIsType) {CHECK(msg->findInt32("encoder", &encoder));}sp<AMessage> format = new AMessage;if (nameIsType) {format->setString("mime", name.c_str());format->setInt32("encoder", encoder);} else {format->setString("componentName", name.c_str());}/* 调用组件初始化 */mCodec->initiateAllocateComponent(format);break;}

这里的mCodec即ACodec,看一下OMX组件初始化:

void ACodec::initiateAllocateComponent(const sp<AMessage> &msg) {msg->setWhat(kWhatAllocateComponent);msg->setTarget(id());msg->post();
}

跟进消息:

case ACodec::kWhatAllocateComponent:
{onAllocateComponent(msg);handled = true;break;
}
bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {ALOGV("onAllocateComponent");CHECK(mCodec->mNode == NULL);/* 1.获取OMX的binder对象 */OMXClient client;CHECK_EQ(client.connect(), (status_t)OK);sp<IOMX> omx = client.interface();  .../* 2.找到底层支持的解码器 */OMXCodec::findMatchingCodecs(mime.c_str(),encoder, // createEncoderNULL,  // matchComponentName0,     // flags&matchingCodecs);.../* 3.申请omx组件 */status_t err = omx->allocateNode(componentName.c_str(), observer, &node); .../* 4.回调通知MediaCodec */{sp<AMessage> notify = mCodec->mNotify->dup();notify->setInt32("what", CodecBase::kWhatComponentAllocated);notify->setString("componentName", mCodec->mComponentName.c_str());notify->post();}/* 切换ACodec的状态 */mCodec->changeState(mCodec->mLoadedState);
}

这里需要注意下,OMX的Bn端在OMX.CPP中,看一下allocateNode实现:

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

status_t OMX::allocateNode(const char *name, const sp<IOMXObserver> &observer, node_id *node) {Mutex::Autolock autoLock(mLock);*node = 0;/* 实例化instance */OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name);OMX_COMPONENTTYPE *handle;/* 获取组件 */OMX_ERRORTYPE err = mMaster->makeComponentInstance(name, &OMXNodeInstance::kCallbacks,instance, &handle);if (err != OMX_ErrorNone) {ALOGE("FAILED to allocate omx component '%s'", name);instance->onGetHandleFailed();return UNKNOWN_ERROR;}*node = makeNodeID(instance);mDispatchers.add(*node, new CallbackDispatcher(instance));instance->setHandle(*node, handle);mLiveNodes.add(observer->asBinder(), instance);observer->asBinder()->linkToDeath(this);return OK;
}

这里有一个特别需要注意的点是,omx组件是可以由芯片厂商自行扩展的,所以,在OMXMaster中会决定是加载Android原生的软解码还是芯片厂商的硬解码,我所调试的环境为海思平台,故加载的为海思插件。

3.configure分析:

status_t MediaCodec::configure(const sp<AMessage> &format,const sp<Surface> &nativeWindow,const sp<ICrypto> &crypto,uint32_t flags) {sp<AMessage> msg = new AMessage(kWhatConfigure, id());msg->setMessage("format", format);msg->setInt32("flags", flags);...sp<AMessage> response;status_t err = PostAndAwaitResponse(msg, &response);...
}

看下kWhatConfigure消息处理:

        case kWhatConfigure:{...mCodec->initiateConfigureComponent(format);break;}

再看下MediaCodec中initiateConfigureComponent函数的消息:

void ACodec::initiateConfigureComponent(const sp<AMessage> &msg) {msg->setWhat(kWhatConfigureComponent);msg->setTarget(id());msg->post();
}
case ACodec::kWhatConfigureComponent:
{onConfigureComponent(msg);handled = true;break;
}

onConfigureComponent函数非常长,主要是为了给omx组件设置参数,这里就不去具体分析了。

4.start函数分析:

status_t MediaCodec::start() {sp<AMessage> msg = new AMessage(kWhatStart, id());sp<AMessage> response;return PostAndAwaitResponse(msg, &response);
}
        case kWhatStart:{uint32_t replyID;CHECK(msg->senderAwaitsResponse(&replyID));if (mState == FLUSHED) {setState(STARTED);mCodec->signalResume();PostReplyWithError(replyID, OK);break;} else if (mState != CONFIGURED) {PostReplyWithError(replyID, INVALID_OPERATION);break;}mReplyID = replyID;setState(STARTING);mCodec->initiateStart();break;}

和之前的逻辑一样,MediaCodec对start的逻辑也是先更新自己维护的状态,然后再调用到ACodec中:

void ACodec::initiateStart() {(new AMessage(kWhatStart, id()))->post();
}
        case ACodec::kWhatStart:{onStart();handled = true;break;}
void ACodec::LoadedState::onStart() {ALOGV("onStart");CHECK_EQ(mCodec->mOMX->sendCommand(mCodec->mNode, OMX_CommandStateSet, OMX_StateIdle),(status_t)OK);mCodec->changeState(mCodec->mLoadedToIdleState);
}

这里就会调用到下层OMX组件中,由组件来执行响应的操作了。MediaCodec对到OMX组件的流程比较绕,Android在这里弄的比较复杂,对于不是芯片厂商的开发人员而言会比较难理解一些,在这里对这些流程也只是一个简单跟踪,里面还有很多内容没有详细扩展,需要根据工作中的具体情况去做分析了。

如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓

MediaCodec对接到OMX的简单分析相关推荐

  1. x264源代码简单分析:宏块分析(Analysis)部分-帧间宏块(Inter)

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  2. Nginx介绍及原理简单分析

    快速入门 ------------------------ 关于Nginx,我们可以到其官网 http://nginx.org/  以及WIKI http://wiki.nginx.org 进行下载和 ...

  3. 网络故障简单分析指导

    网络故障简单分析指导网络管理 网管  网络管理员每天都会遇到各种各样的问题,面对故障如何分析故障原因进行排故呢?本文列出了62种常见故障并给出了相应的分析和排故建议.     1. 故障现象:网络适配 ...

  4. R语言splines包构建基于logistic回归的自然样条分析:南非心脏病数据集、非线性:基函数展开和样条分析、你简单分析的不重要特征,可能只是线性不显著、而非线性是显著的

    R语言splines包构建基于logistic回归的自然样条分析:南非心脏病数据集.非线性:基函数展开和样条分析.你简单分析的不重要特征,可能只是线性不显著.而非线性是显著的 目录

  5. [EntLib]微软企业库5.0 学习之路——第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—上篇...

    在完成了后,今天开始介绍企业库中的新模块:Cryptographer(加密模块),这个模块在日常的大多数项目的作用非常重要,例如:网站会员密码.身份证号.网站配置等,通过对信息进行加密可以保证项目数据 ...

  6. FFmpeg资料来源简单分析:libswscale的sws_getContext()

    ===================================================== FFmpeg库函数的源代码的分析文章: [骨架] FFmpeg源码结构图 - 解码 FFmp ...

  7. howdoi 简单分析

    对howdoi的一个简单分析. 曾经看到过下面的这样一段js代码: try{doSth(); } catch (e){ask_url = "https://stackoverflow.com ...

  8. Mac与Phy组成原理的简单分析

    Mac与Phy组成原理的简单分析 2011-12-28 15:30:43 //http://blog.chinaunix.net/uid-20528014-id-3050217.html 本文乃fir ...

  9. python做数据可视化的代码_Python数据可视化正态分布简单分析及实现代码

    Python说来简单也简单,但是也不简单,尤其是再跟高数结合起来的时候... 正态分布(Normaldistribution),也称"常态分布",又名高斯分布(Gaussiandi ...

最新文章

  1. 【学习笔记】ABAP OOD设计模式 - 观察者模式
  2. hdu 1874 Dijkstra算法模板
  3. yum安装时出现:Cannot retrieve metalink for repository: epel. Please verify its path and try again...
  4. 高通骁龙cpu排行_高通骁龙865深度解读:CPU、GPU、内存全新升级
  5. 前端学习(2327):angular之双向绑定
  6. JDBC_设计架构_驱动类加载_建立Connection_效率测试
  7. ubuntu复制文件到另一个文件夹_简单介绍一下电脑中的文件或文件夹的复制、移动及删除的操作方式...
  8. 怎么在mysql查询自己建的表格_oracle数据库中怎么查询自己建的表
  9. Java快速入门学习笔记9 | Java语言中的方法
  10. SIP协议栈读书笔记1
  11. 2017.9.24 虔诚的墓主人 思考记录
  12. 命令查询每个文件文件数
  13. apache日志文件 accesslog
  14. 用友凭证打印页面边距设置会同步
  15. svn 服务器日志位置,svn服务器查看日志
  16. 高频课设-基于STM32的温度无线监测系统
  17. Android 音乐资源管理与播放
  18. 关于北京市电气火灾综合治理实施方案通知的解读
  19. 【领域泛化论文阅读】Birds of A Feather Flock Together:Category-Divergence Guidance for DomainAdaptiveSegmentat
  20. MySQL中的limit分页的使用

热门文章

  1. IPV6地址-格式和讲解
  2. OneNote2007产品密钥及激活方法
  3. 清爽蓝色个人求职简历PPT模板
  4. 打造Android的中文Siri语音助手(一)——小I机器人的接口
  5. 程序员表白专用: 5 种实用表白方法!帮你快速攻陷心仪女生
  6. 连续创造OTT赛道新神话,论酷开科技的持久力
  7. 360linux网卡驱动,驱动下载
  8. java集合框架02——ArrayList和源码分析
  9. 神经网络学习笔记4——GNN图神经和GCN图卷积网络
  10. 操作系统系列笔记(四) - 进程,线程及CPU调度