Android_ics openmax in stagefright 学习记录------2

2023-10-24 23:48

本文主要是介绍Android_ics openmax in stagefright 学习记录------2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

/
//4,回到awesomeplayer initVideoDecoder()中
/mVideoSource = OMXCodec::Create(mClient.interface(), mVideoTrack->getFormat(),false, // createEncodermVideoTrack,NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);if (mVideoSource != NULL) {int64_t durationUs;if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {Mutex::Autolock autoLock(mMiscStateLock);if (mDurationUs < 0 || durationUs > mDurationUs) {mDurationUs = durationUs;}}//这里的mVideoSource就是上面返回的OMXCodec类型,所以mVideoSource->start()的函数定义如下,但是这里的OMXCodec类型靠node_id来标示,而且OMXCodec(mVideoSource)所扮演的角色类型也不同(setComponentRole())。status_t err = mVideoSource->start();status_t OMXCodec::start(MetaData *meta) {CODEC_LOGV("OMXCodec::start ");Mutex::Autolock autoLock(mLock);if(mPaused) {if (!strncmp(mComponentName, "OMX.qcom.", 9)) {while (isIntermediateState(mState)) {mAsyncCompletion.wait(mLock);}CHECK_EQ(mState, (status_t)PAUSED);status_t err = mOMX->sendCommand(mNode,OMX_CommandStateSet, OMX_StateExecuting);CHECK_EQ(err, (status_t)OK);setState(IDLE_TO_EXECUTING);mPaused = false;while (mState != EXECUTING && mState != ERROR) {mAsyncCompletion.wait(mLock);}drainInputBuffers();return mState == ERROR ? UNKNOWN_ERROR : OK;} else {   // SW CodecmPaused = false;return OK;}}if (mState != LOADED) {return UNKNOWN_ERROR;}sp<MetaData> params = new MetaData;if (mQuirks & kWantsNALFragments) {params->setInt32(kKeyWantsNALFragments, true);}if (meta) {int64_t startTimeUs = 0;int64_t timeUs;if (meta->findInt64(kKeyTime, &timeUs)) {startTimeUs = timeUs;}params->setInt64(kKeyTime, startTimeUs);}//第一次跳过前面的代码,走到这里,注意这里的mSource是OMXCodec构造函数中传进来的。追根溯源会发 现这里的mSource其实是mVideoTrack(awesomeplayer的成员变量),而mVideoTrack又是在AwesomePlayer::setVideoSource中被赋值的,在awesomeplayer的setdatasource()函数中setVideoSource(extractor->getTrack(i));所以这里的mSource应该是一个具体的XXXExtractor.getTrack(i)之后得到的。最终发现,mSource实际上是某种格式的一段媒体流。例如MPEG4Source等等。所以这个start函数的做用是根据这段媒体流的实际需要,分配一个合适大小的buf供以后使用。status_t err = mSource->start(params.get());if (err != OK) {return err;}mCodecSpecificDataIndex = 0;mInitialBufferSubmit = true;mSignalledEOS = false;mNoMoreOutputData = false;mOutputPortSettingsHaveChanged = false;mSeekTimeUs = -1;mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;mTargetTimeUs = -1;mFilledBuffers.clear();mPaused = false;//从这个函数开始通过OMX和OMX的components通信了return init();
}status_t OMXCodec::init() {// mLock is held.CHECK_EQ((int)mState, (int)LOADED);status_t err;//mQuirks是一些和具体编解码组件相关的特性参数,他描述了该组件在工作时候需要的一些注意事项//mQuirks主要很硬件编解码组件有关if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {//向特定的node放送Command,这个node有node_id即mNode表示,后面会详细介绍-------------    1 err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);CHECK_EQ(err, (status_t)OK);setState(LOADED_TO_IDLE);}//为不同的nodeInstance分配其输入和输出端口上的buffer,并确定分配大小和分配策略err = allocateBuffers();if (err != (status_t)OK) {CODEC_LOGE("Allocate Buffer failed - error = %d", err);setState(ERROR);return err;}if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);CHECK_EQ(err, (status_t)OK);setState(LOADED_TO_IDLE);}while (mState != EXECUTING && mState != ERROR) {mAsyncCompletion.wait(mLock);}return mState == ERROR ? UNKNOWN_ERROR : OK;
}///
//5,看看mOMX->sendCommand(mNode,...,...)做了什么
///
在OMXCodec会通过OMX服务去调用://该函数会查找node_id号所对应的nodeInstance,然后去调用这个nodeInstance的sendCommand函数。
status_t OMX::sendCommand(node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {return findInstance(node)->sendCommand(cmd, param);
}|||V
//注意这里这个OMXNodeInstance对应就是具体node了,OMX_SendCommand函数中的第一个参数就是在instance->setHandle(*node, handle)传进出的,而且这个handle是由mMaster->makeComponentInstance传出的,上面有提到。
status_t OMXNodeInstance::sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {Mutex::Autolock autoLock(mLock);OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);return StatusFromOMXError(err);
}//OMX_SendCommand由下面的宏定义,可以看到最后调用的就是那个mHandle的SendCommand方法
#define OMX_SendCommand(                                    \hComponent,                                        \Cmd,                                               \nParam,                                            \pCmdData)                                          \((OMX_COMPONENTTYPE*)hComponent)->SendCommand(         \hComponent,                                        \Cmd,                                               \nParam,                                            \pCmdData)                          /* Macro End *///特别要注意的地方是上面((OMX_COMPONENTTYPE*)hComponent)->SendCommand函数实际上是调用的过程是,首先通过
SoftOMXComponent::SendCommandWrapper----->SoftOMXComponent *me =(SoftOMXComponent *)((OMX_COMPONENTTYPE *)component)->pComponentPrivate;(me被转换成一个this指针)---->me->sendCommand(cmd, param, data);(这个me->sendCommand调用的肯定是SimpleSoftOMXComponent::sendCommand) 
注意一个继承关系   SoftMPEG4--->SimpleSoftOMXComponent--->SoftOMXComponent  (箭头理解为继承于)//sendCommand的函数实现如下:
OMX_ERRORTYPE SimpleSoftOMXComponent::sendCommand(OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data) {CHECK(data == NULL);sp<AMessage> msg = new AMessage(kWhatSendCommand, mHandler->id());msg->setInt32("cmd", cmd);msg->setInt32("param", param);//消息被投递出去了msg->post();------------------------------------------------------- 1return OMX_ErrorNone;
}//消息投递出去之后,什么时候得到处理呢?看下 SimpleSoftOMXComponent的构造函数就明白了
SimpleSoftOMXComponent::SimpleSoftOMXComponent(const char *name,const OMX_CALLBACKTYPE *callbacks,OMX_PTR appData,OMX_COMPONENTTYPE **component): SoftOMXComponent(name, callbacks, appData, component),mLooper(new ALooper),mHandler(new AHandlerReflector<SimpleSoftOMXComponent>(this)),mState(OMX_StateLoaded),mTargetState(OMX_StateLoaded) {mLooper->setName(name);mLooper->registerHandler(mHandler);mLooper->start(false, // runOnCallingThreadfalse, // canCallJavaANDROID_PRIORITY_FOREGROUND);
}//在 SimpleSoftOMXComponent中有一个mHandler(new AHandlerReflector<SimpleSoftOMXComponent>(this)),---注意这个mHandle的参数,其中 SimpleSoftOMXComponent做为这个mHandle的投递目标,也就是消息将有 SimpleSoftOMXComponent处理。
最终,消息会被投递到mLooper中的mEventQueue,并在消息循环(也就是mLooper.loop()函数中,被deliverMessage,然后被相应的hanler处理,也就是SimpleSoftOMXComponent::onMessageReceived函数)。


在来看一个继承关系图。


这个继承关系图,也许能说明一些问题。最右边的是具体的软件编/解码模块的实现的代码,在openmanx框架中,为了实现动态绑定,这些moudle最终会被编译成libstagefright_soft_XXXX.so。具体的编译步骤,可以去看相关路径下的Android.mk文件。可以说明一点的是,这些libstagefright_soft_XXXX.so是首先由一些编解码的srcfile编译出一个类似于libstagefright_m4vh263dec的静态库,然后这个静态库再被编译进一个.so里。

        在这个继承关系图上,位于中间的SimpleSoftOMXComponent,完成了大部分的工作,它负责sendCommand的同时又要将一些反馈信息notify到其父类SoftOMXCodec来处理。这些反馈的信息包括,组件状态的变化,ports的状态的变化等等。父类SoftOMXComponent来处理的notify的信息,其主要的工作是,找到具体的handler然后调用适当的CallBacks。


关于组建的结构再来看一张图,下面是一张组件的模型图:


说的简单一点,command从组件的外部进来,在组件内进行一系列的传递和处理(组件内部自己处理)之后,再将反馈信息传回组件外部,传递给OMXCodec框架层。


说点废话,把时序图再贴一次:




首先,可以明确一点的是,整个stagefright框架都是事件驱动模式的。上面的时序图主要描述了,收到onPrepareAsyncEvent时间后,OMX框架是如何是如何建立自己的编解码组件。上面的时序图中,要明确两点 1,事件驱动模式是异步的 2,时序图的末端 CallbackDispatcher也是异步分派的从上面的时序图中还有一点没有办法看出来。就是对应于具体的编解码组件,编解码的过程时候时候发生。下面就这个问题,展开讨论。//
//下面的研究将围绕三个问题
/
1,待解码的原始数据问题  
2,具体编解码组件是如何完成编解码工作的  
3,解码之后的数据处理问题


以上的三个问题,在我的《数据流向分析》中有介绍。


OK,备忘做完了,还是那句话,菜鸟们请批判性的看,comments are very welcome.

 

 

 

这篇关于Android_ics openmax in stagefright 学习记录------2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/278581

相关文章

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Servlet中配置和使用过滤器的步骤记录

《Servlet中配置和使用过滤器的步骤记录》:本文主要介绍在Servlet中配置和使用过滤器的方法,包括创建过滤器类、配置过滤器以及在Web应用中使用过滤器等步骤,文中通过代码介绍的非常详细,需... 目录创建过滤器类配置过滤器使用过滤器总结在Servlet中配置和使用过滤器主要包括创建过滤器类、配置过滤

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

python与QT联合的详细步骤记录

《python与QT联合的详细步骤记录》:本文主要介绍python与QT联合的详细步骤,文章还展示了如何在Python中调用QT的.ui文件来实现GUI界面,并介绍了多窗口的应用,文中通过代码介绍... 目录一、文章简介二、安装pyqt5三、GUI页面设计四、python的使用python文件创建pytho

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06