什么情况会导this.openldap 导入ldif

Linux open系统调用流程 - CSDN博客
Linux open系统调用流程
http://blog.csdn.net/chenjin_zhong/article/details/8452453&
我们知道,Linux把设备看成特殊的文件,称为设备文件。在操作文件之前,首先必须打开文件,打开文件的函数是通过open系统调用来实现的。而简单的文件打开操作,在Linux内核实现却是非常的复杂。open函数打开原理就是将进程files_struct结构体和文件对象file相关联。那么具体是怎么实现的呢?让我们一起走进Linux内核文件打开流程。
2. 首先,通过系统调用sys_open函数:
这个函数进行了简单的处理,调用do_sys_open函数:
这个函数主要完成以下几件事情:
(1)调用get_unused_fd得到一个没有使用的文件描述符,这是为读,写准备的,每个打开的文件都有一个文件描述符。
& (2)& 调用do_filp_open构建 struct file文件对象,并填充相关信息,这个函数非常复杂,我们以后再看。
& (3)& 调用fd_install将文件对象和进程的files_struct对象关联。
&首先看一下get_unused_fd函数:
在第7行,得到当前进程的files指针。 在第16-18行,返回打开文件表,在打开的文件描述符集open_ds的fds_bits数组查找对应位置为0的位图,返回位置,表示这个文件描述符没有被使用。接下来,在41-43行,分别将open_fds的fd位置的位图置位,并将fd+1赋值给下一下文件描述符。如果这个文件描述符被占用,就将fdt-&fd[fd]=NULL. 最后返回文件描述符fd.
接下来,调do_filp_open函数,其主要功能是返回一个已经填充好的文件对象指针。这个函数比较复杂,在下一节进行分析。
最后,分析一下fd_install函数,传入参数文件描述符fd和文件对象f,具体如下:
这个函数首先得到files_struct对象指针,然后调用rcu_assign_pointer,将文件对象file赋给fdt-&fd[fd], 这样,文件对象就和进程相关联起来了。
因此,不同的进程打开相同的文件,每次打开都会构建一个struct file文件对象,然后将这个对象和具体的进程相关联。其实open调用可以概括如下:
(1)得到一个未使用的文件描述符
(2)构建文件对象struct file
(3)将文件对象和进程相关联
在下一节中,我们将深入理解非常复杂的do_filp_open操作。
/-------------------------------------------------------------------------------------------------------
http://blog.csdn.net/chenjin_zhong/article/details/8452487http://blog.csdn.net/chenjin_zhong/article/details/8452487
http://blog.csdn.net/chenjin_zhong/article/details/8452487&
1. 书结上文,继续分析do_filp_open函数,其传入4个参数:
dfd:相对目录
tmp:文件路径名,例如要打开/usr/src/kernels/linux-2.6.30
flags:打开标志
mode:打开模式
初看起来,寥寥几行代码,貌似简单。其实不然,一会就知道了。此函数调用了open_namei和nameidata_to_filp. 后一个函数通过名字就可以猜出来,是将nameidata结构转化为filp,也就是利用nd结构赋值给文件指针file,然后返回这个文件指针。而open_namei肯定是填充nd结构体,具体功能可表述为: 根据上级目录项对象,查询下一级的目录项对象,如果在目录项缓存找到下一级的目录项对象,则直接返回,并填充nd的挂载点对象和目录项对象。否则,构建一个子目录项对象,并利用iget函数分配一个新的inode结构,将子目录项对象和inode结构相关联。这样,一直循环到最后一下分量。最后返回的是最后一个分量的目录项对象和挂载点对象。可以看到,在这两个函数中,都利用了nameidata结构,具体看一下神奇的结构:
open_intent文件对象就是最后返回的文件对象。
由于namidata_to_filp比较简单,先看一下:
首先取得文件对象指针,然后判断文件对象是否已经初始化,如果没有初始化,就调用__dentry_open函数,对文件对象进行初始化。
首先,设置文件打开标志f-&f_flags. 然后初始化地址空间对象,目录项对象,挂载点对象,文件指针位置,文件相关操作。需要说明两点:
(1)地址空间对象和索引节点相关联,在构建索引节点时已经赋值了。它涉及到具体的磁盘块操作,在后面的章节将会解释。
&& (2)f_op这个非常重要,也是在构建索引节点时,将具体文件系统的文件操作函数集的指针赋给索引节点的i_fop域。对于打开文件,目录,符号链接,对应的操作函数集是不相同的。
&接下来,第31行-38行,如果是普通文件,可能不需要打开。如果是设备文件,就需要打开操作。例如SCSI设备的sg_open函数。
最后,对文件预读进行初始化。
在说完nameidata_to_filp函数之后,需要解释open_namei函数:
首先进行文件打开设置工作,第40行,如果是打开操作,则调用path_lookup_open函数。第53行,如果文件不存在,就创建一个文件,调用path_lookup_create函数。在第88行,如果是创建文件,需要建立磁盘上的索引节点,即调用open_namei_create函数。我们逐一解释:
首先path_lookup_open函数:
封装了__path_lookup_intent_open函数。
path_lookup_create函数:
也封装了__path_lookup_intent_open函数,只是增加了创建标志LOOKUP_CREATE, 在create操作的lookup_flags设置了LOOKUP_PARENT,接下来,将看到这个标志的作用。
继续跟踪__path_lookup_intent_open函数:
static int __path_lookup_intent_open(int dfd, const char *name,
首先调用get_empty_flip函数分配一个空闲的文件对象filp, 设置intent.open的相关域,包括“想要打开的文件”,打开标志和创建模式。最后,调用do_path_lookup对文件路径进行解析,并填充nd。
第11-14行,设置初始化nd-&last_type, flags和depth. 其中depth表示符号链接的深度。由于符号链接可以链接自己,因此需要限制链接的深度。
第16行,如果第一个字符为/,表示从根目录开始解析,设置nd-&mnt为根挂载点对象,nd-&dentry为根目录项对象,然后增加引用计数。
第34行,如果是从当前目录开始,将nd-&mnt设置为当前目录的挂载点对象,nd-&dentry设置为当前目录的目录项对象。
第41行,否则,将nd-&mnt和nd-&dentry分别设置为f_path.mnt和f_pat.dentry.&
接下来,第63行,初始化符号链接总数,调用实际文件系统的路径分解函数link_path_walk.
首先,备份挂载点对象和目录项对象,然后调用__link_path_walk解析.
这个函数也比较复杂,在下一节中继续分析!
/////////////////////////////////////////////////////////////----------------------------------------------------------------------------------------------
http://blog.csdn.net/chenjin_zhong/article/details/8452640&
分类:&&1131人阅读&&&
1. 闲言少叙,继续分析__link_path_walk函数:
这个函数主要做三件事:
(1)解析已经存在的文件路径,即打开标志
(2)解析不存在的文件路径,即创建文件标志,这样,需要得到父目录项对象和安装点对象
(3)解析符号链接,第一次找到符号链接的文件路径,第二次解析路径名
第23-26行,只有/,跳至return_reval. 这里多个根当作一个根处理,如//
第31-32行,设置符号链接标志。
第39行,定义qstr结构,这个结构包括hash值,分量长度和分量名。
第43-46行,进行权限检查,遍厍目录,必须具有执行权限。
第55-60行,计算每个分量的hash值。
第68行,如果解析到最后一个分量,跳至last_component.
第72行,如果遇到类似/proc/的目录,跳至last_with_slashes.
第80行,如果分量的第一个字符是.,但第二个字符不是.,则正常解析。
第88行,当第二个字符也是. ,说明是父目录,调用follow_dotdot进行回溯。
我们分析一下这个函数:
第11-16行,如果回溯的是进程的根目录,则不允许,调用follow_mount函数。
第19-23行,如果目录项对象不是根目录,则通过nd-&dentry=dget(nd-&dentry-&d_parent)返回上一级目录项对象。
不管怎么样,最终会调用follow_mount函数。有时,人的好奇心是很强的,同样,对于Linux内核源码,也需要好奇心。哈哈,看一下follow_mount函数:
这个函数首先判断一下dentry目录项是不是挂载点,如果是,调用lookup_mnt函数返回子挂载点。在第11行,将mnt赋值mounted,接着,寻找子挂载点。最终,找到一个没有其它文件系统安装在其之上的文件系统挂载点。这里,需要解释一下,如果/dev/sda1和/dev/sda2先后挂载在/usr目录下,那么/dev/sda1的相关目录将会被隐藏,而/dev/sda2的父挂载点是/dev/sda1. 而上面的过程是通过父挂载点找子挂载点,直到找到一个没有挂载其它文件系统的挂载点为止。这个,文件系统称暂且称为底层文件系统。也不知道,这么叫对不对,或许是顶层文件系统。总之,follow_dotdot回溯到了上一级目录。
接着__link_path_walk解释,
第97行,如果底层文件系统具有计算hash值的函数,则调用。
第106行,查找分量的目录项对象函数do_lookup,这个函数一会分析。
第119行,判断是否是符号链接,调用do_follow_link处理符号链接,稍后分析。
第142行,处理最后一个分量。
第167行,调用do_lookup函数,找到一个最后分量的目录项对象和挂载点对象。
第172行,如果最后一个分量是符号链接,调用do_follow_link进一步处理。
第190行,当只是建立文件时,跳至lookup_parent.&
第192-205行,最后一个分量名和分量类型,此时,nd保存了上一个分量的目录项对象和挂载点对象。
如果正确解析,返回0.
下面,分析一下do_lookup函数:
这个函数的主要功能是查询目录项对象,并将挂载点和目录项对象保存在nameidata结构。具体如下:
第10行,nd保存了上一个目录项对象和挂载点对象。
第12行,首先在目录项缓存dentry cache查找,如果缓存不存在,跳转到need_lookup,调用real_lookup在内存分配一个dentry,并将dentry和索引节点关联。
第17行,如果存在,需要验证目录项对象是否有效,跳至34行,如果有效,将mnt和dentry赋值给path. 在__link_path_walk会将path值赋给nd.
继续跟踪__do_lookup函数:
第4-7行,赋值len,hash和name,并取得head指针,为下面比较做准备。
第14行,判断hash值是是否相同。
第20行,判断父目录项parent是否相同。
第39行,匹配分量名。
如果找到,返回目录项对象。
从这个查找过程,可以看出,是用目录名或是文件名计算hash值,然后返回对应的目录项对象。这也是为什么目录名或文件名不放在索引节点而放在目录项对象的原因。
如果目录项缓存没有,继续跟踪real_lookup函数:
在第33行,重新搜索一下目录项缓存,由于进程在查找过程中可能阻塞,在这期间,目录项可能已经加入了dentry cache,所以需要重新查找一下。
第34行,如果没有找到,调用d_alloc分配一个目录项对象。
第35行,具体的文件系统索引节点查找函数,读取磁盘索引节点信息,并将索引节点和目录项对象关联。在iget索引节点时,将索引节点加入了inode cache. 在关联inode节点时,将目录项对象加入了dentry cache.
在第53行,验证目录项对象是否有效,最终返回目录项对象。
可以看到,此时返回的目录项对象已经加入到了dentry cache,并关联了索引节点。即dentry-&d_innode=inode.
我们继续跟踪上面的两个函数,首先跟踪d_alloc函数:
第16行,为目录项对象分配内存。
第29-32行,设置名称,长度和hash值。
第48-51行,初始化相关链表。
第53行,如果父目录项对象存在,就设置父目录项对象和超级块对象。这样,就建立了一个子目录项对象。
接着跟踪lookup函数,以ext3为例,ext3_lookup:
第11行,得到ext3_dir_entry_2对象,该对象包含了索引节点号。
第13-16行,判断索引节点号是否合法。
第21行,创建内存索引节点,并填充相关信息,将索引节点加入inode cache.
第28行,将目录项对象和索引节点关联。
首先,跟踪iget函数:
首先调用iget_locked分配内存索引节点。如果是新分配的,需要调用read_inode调用磁盘上的索引节点填充相关信息。
继续跟踪iget_locked函数:
第28行,在inode cache查找,如果没有,调用get_new_inode_fast分配一个索引节点并插入inode cache.
ifind_fast留给读者自行分析吧!
分析一下,get_new_inode_fast函数:
第9行,分配索引节点。
第17-28行,索引节点的初始化。包括:
(1)设置索引节点号
(2)加入inode_in_use链表
(3)加入inode_hashtable,即加入inode cache
(4)设置状态为I_NEW
返回索引节点。
接下来,继续分析iget函数中的第二个函数read_inode.
简单说一下功能:
第19行,读取磁盘上原始索引节点,用来填充新分配的索引节点。
第20-32行,inode相关域设置。
第104行,如果是文件,则将文件相关操作的指针赋给inode-&i_fop,这非常重要,因为,最后将i_fop赋给了文件对象file-&f_op. 表示了文件的相关操作。
第109-111行,目录相关操作。
第112-118行,符号链接相关操作。
第119-128行,设备相关操作。具体就不分析了。
到此为止,我们已经得到了一个inode节点,并且填充了相关域。
iget函数返回,ext3_lookup继续往下走,调用d_splice_alias函数:
第37行,将目录项对象和索引节点相关联。
第42行,将目录项对象加入到目录项缓存。
最后,返回dentry.
如果,你现在仍然很清醒,那么恭喜你,你已经基本了解了整个过程。
lookup函数返回,在__link_path_walk函数调用path_to_nameidata将path-&mnt和path-&dentry赋给nd-&mnt和nd-&dentry.表示找到的目录项对象和挂载点对象。
接下来,处理符号链接,调用do_follow_link函数:
这个函数首先松果符号链接数,不能超过MAX_NESTED_LINKS.
最终调用__do_follow_link进行处理。
第15行,取出符号链接的路径,放到nd-&saved_names可以看出,符号链接有自己的inode节点,并且inode节点保存的内容是真正的文件路径。所以,符号链接可以跨文件系统。
第22行,调用__vfs_follow_link解析路径名。
第15行,调用link_path_walk. 看到这个函数,松了一口气,因为前面已经分析过了。
当__link_path_walk返回时,link_path_walk也跟着返回,之后do_path_lookup也返回了,最终回到open_namei函数。
如果是打开文件,返回即可。
如果是创建文件,还需调用open_namei_create函数:
封装了vfs_create函数:
调用inode的create方法创建索引节点。以ext3为例,调用ext3_create函数:
第26行,创建索引节点。
第29-33行,inode-&i_op和inode-&i_fop赋值。
之后,还会将索引节点标识为脏,需要回写到磁盘上,具体实现就不分析了。
当open_namei函数返回时,open系统调用也就分析完了。
(1)建立一个struct file结构体,将nameidata相关域填充到这个结构体,最重要的两个域mnt, dentry. 从dentry可得到inode,从而将i_fop赋给文件对象。
(2)在路径查找时,通过父目录项建立子目录项,然后将子目录项关联inode节点。
(3)打开文件和建立文件不同。打开文件,只需要找到目录项对象,然后关联索引节点即可,因为索引节点存在。而建立文件时,由于文件不存在,首先找到目录的目录项对象,然后建立子目录项对象和索引节点对象,最后索引节点对象需要同步到磁盘上。
(4)有两个缓存,dentry cache和inode cache,分别用来缓存目录项对象和索引节点对象。
(5)将文件对象和进程的files_struct相关联。
(6)对于普通文件,不需要打开操作,而对于设备文件,需要打开操作,例如SCSI设备的sg_open函数。
(7)主要处理三种情形:打开文件,建立文件和符号链接
参考文献: &深入理解Linux内核第3版&
本文已收录于以下专栏:
相关文章推荐
当我们打开一个文件的时候,需要获得文件的问价描述符,
1.          引言
      从事Linux环境工作2年有余,一直懵懵懂懂,1年前拜读了《莱昂氏UNIX源代码分析》一书,感觉自己的学习道路漫漫且修远。最近受chinaunix的精华文帖...
头文件:#include
   #include
   #include
定义函数:
    int open(const char * pathname, int flags);
    i...
转自:/kernel-book/ch08/8.7.1.htm
资料:深入分析linux内核源码——/kernel-book/
从前面 的例子可以看到,我们在操作一个调和时都 是通过open系统调用先去打开这个设备,不管是设备还是文件,我们要访问它都要称通过open函数来先打开, 这样才能调用其它的函数如read、write来...
一、 乐曲的基本组成 
一首完整的乐曲是由一些固定的音乐单元组成,分清这些音乐单元,对于学习乐理是非常有好处的。一首完整的曲子,由很多不同时值的音符组成不同的小节,再由这些小节组成不同的乐句,由不同...
Open系统调用
下面看看open_namei函数:
这个函数的基本的功能是:
首先我们知道filename,也就是知道路径了,那么我们可以根据上级目录项对象,查询下一级的目录项对象,如...
linux-2.6.30.4/arch/arm/kernel/entry-common.S
linux-2.6.30.4/arch/arm/kernel/calls.S
在entry-com...
使用 hdparm 获得硬盘的生产厂家,类型等基本信息,这里我们之提供简单的使用,以后
hdparm -i /dev/sda
通过 smartctl命令来获取硬盘的详细信息:
smartct...
这次讲讲openwrt的结构.
1. 代码上来看有几个重要目录package, target, build_root, bin, dl....
---build_dir/hos...
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)OpenMAX介绍(总括) - CSDN博客
OpenMAX介绍(总括)
一、OpenMax简介
&&&&OpenMAX是一个多媒体应用程序的标准。由NVIDIA公司和Khronos(TM)在2006年推出。
&&&&它是无授权费的、跨平台的C语言程序接口序列,这些接口对音频、视频、静态图片的常用操作进行封装。
&&&&它包括三层,分别是应用层(AI)、集成层(IL)和开发层(DL)。其中IL层已经成为了事实上的多媒体框架标准。嵌入式处理器或者多媒体编解码模块的硬件生产者,通常提供标准的OpenMax IL层的软件接口,这样软件的开发者就可以基于这个层次的标准化接口进行多媒体程序的开发。
二、OpenMax在Android中的位置
&&&&&&&&在Android中,OpenMax IL层,通常可以用于多媒体引擎的插件,Android的多媒体引擎OpenCore和StageFright都可以使用OpenMax作为插件,主要用于编解码(Codec)处理。在Android的框架层,也定义了由Android封装的OpenMax接口,和标准的接口概念基本相同,但是使用C++类型的接口,并且使用了Android的Binder IPC机制。Android封装OpenMax的接口被StageFright使用,OpenCore没有使用这个接口,而是使用其他形式对OpenMax
IL层接口进行封装。
三、OpenMax的主要概念
客户端(Client):访问IL core或IL component的软件层,可能是位于GUI应用程序的下层,如GStreamer。IL client是一个典型的功能块,如filter graph multimedia framework, OpenMAX AL, 或application都可以调用它。IL client与OpenMAX IL core进行交互,利用IL core加载和卸载组件、在组件间建立直接通信以及获得组件方法的入口。
core:相关平台的代码,具有将IL component载入主存储器的功能,当应用程序不再需要某组件时,IL core将负责把该组件从存储器卸去。一般来说,组件一旦载入存储器,IL core将不在参与应用程序与组件之间的通信。
端口(Port):组件的输入输出接口 组件(Component):OpenMax IL的单元,每一个组件实现一种功能。组件按照端口可分类为Source(只有一个输出端口)、Sink(只有一个输入端口)和Host组件(一个输入端口和一个输出端口),此外有一个Accelerator组件,它具有一个输入端口,调用了硬件的编解码器,加速主要体现在这个环节上。
隧道化(Tunneled):让两个组件直接连接的方式。通过隧道化可以将不同的组件的一个输入端口和一个输出端口连接到一起,在这种情况下,两个组件的处理过程合并,共同处理。尤其对于单输入和单输出的组件,两个组件将作为类似一个使用。
四、OpenMax的工作方式
&&&&&&&&首先,搭建好OpenMax的工作环境:设置组件端口、加载组件,建立连接方式等等。
&&&&&&&&然后通过输入端口消耗Buffer,通过输出端口填充Buffer,由此多组件相联接可以构成流式的处理。
五、OpenMax的测试方式
参考《Build OpenCORE 2.05 on x86 Linux.PDF》和《omx_decoder_test_app_guide.pdf》
六、OpenMax接口和集成过程(以android平台的为例)
七、android中支持的组件和Role
根据pv_omxregistry.cpp,得到如下表格(其中黄绿色部分表示没有相应编码器)
OMX.PV.mpeg4dec
video_decoder.mpeg4
libomx_m4vdec_sharedlibrary
OMX.PV.h263dec
video_decoder.h263
libomx_m4vdec_sharedlibrary
OMX.PV.avcdec
video_decoder.avc
libomx_avcdec_sharedlibrary
OMX.PV.wmvdec
video_decoder.wmv
libomx_wmvdec_sharedlibrary
OMX.PV.rvdec
video_decoder.rv
libomx_rvdec_sharedlibrary
OMX.PV.aacdec
audio_decoder.aac
libomx_aacdec_sharedlibrary
OMX.PV.amrdec
audio_decoder.amr
audio_decoder.amrnb
audio_decoder.amrwb
libomx_amrdec_sharedlibrary
OMX.PV.mp3dec
audio_decoder.mp3
libomx_mp3dec_sharedlibrary
OMX.PV.wmadec
audio_decoder.wma
libomx_wmadec_sharedlibrary
OMX.PV.radec
audio_decoder.ra
libomx_radec_sharedlibrary
OMX.PV.amrencnb
audio_encoder.amrnb
libomx_amrenc_sharedlibrary
OMX.PV.mpeg4enc
video_encoder.mpeg4
libomx_m4venc_sharedlibrary
OMX.PV.h263enc
video_encoder.h263
libomx_m4venc_sharedlibrary
OMX.PV.avcenc
video_encoder.avc
libomx_avcenc_sharedlibrary
OMX.PV.aacenc
audio_encoder.aac
libomx_aacenc_sharedlibrary
八、Openmax 一些函数的简单介绍
1 OMX core methods
1)OMX_Init
2)OMX_Deinit
3)OMX_GetHandle
4)OMX_FreeHandle
5)OMX_ComponentNameEnum
6)OMX_GetComponentsOfRole
7)OMX_GetRolesOfComponent
8)OMX_SetupTunnel
9)OMX_GetContentPipe
2 The configuration parser API
除了以上methods,强烈推荐OMX核心插件库包含此API
2.1函数原型
OMX_BOOL OMXConfigParser ( OMX_PTR aInputParameters,OMX_PTR aOutputParameters);
2.2 传递参数
aInputParameters 指向如下结构
typedef struct
OMX_U8* inP&&& //codec 配置头部指针
OMX_U32 inB&& //codec 配置头部长度
OMX_STRING cComponentR //OMX codec类型 eg &video_decoder.mpeg4&
OMX_STRING cComponentN //OMX 组件名称
} OMXConfigParserI
2.3 返回值
OMX_FALSE : 处理codec配置头部错误或不支持该格式
OMX_TURE : 正确处理codec配置头部
2.4 函数作用
填充aOutputParameters,有两种选择:audio coded or vedio codec
typedef struct
OMX_U16 C&& //通道:单声道、立体声、5.1
OMX_U16 BitsPerS&& //位宽(eg16)
OMX_U32 SamplesPerS&& //采样率
} AudioOMXConfigParserO
typedef struct
OMX_U32&&& //检测到的视频剪辑宽度
OMX_U32&&& //检测到的视频剪辑高度
OMX_U32&& //参数
OMX_U32&&& //级别?
} VideoOMXConfigParserO
3 动态加载OMX内核
解释了\system\system\etc\pvplayer.cfg文件中最后一行的含义
(0xax22c5,0x412e,0x19,0x17,0x87,0x4c,0x1a,0x19,0xd4,0x5f),&libomx_sharedlibrary.so&
作用:将OMX内核动态加载进OpenCORE框架
位置:\system\system\etc\pvplayer.cfg
形式:(OMX Core API OsclUuid), “shared library name.so”
eg:(0xax22c5,0x412e,0x19,0x17,0x87,0x4c,0x1a,0x19,0xd4,0x5f),&libomx_core_vendorXYZ.so&
注意:(0xax22c5,0x412e,0x19,0x17,0x87,0x4c,0x1a,0x19,0xd4,0x5f) 提供独立API ID,不可修改
数据格式及OMX输入缓冲细节
1.1 帧起始代码
一般不用,H.264可能使用。
1.2 OMX缓冲区
三个值得信赖的关键参数
nFilledLen 缓冲区长度
nTimestamp 缓冲区时间戳
OMX_BUFFERLAG_ENDOFFRAME 缓冲区结束标志位
1.3多帧合并输入缓冲
一些音频信息,单帧过小(eg ARM),将其合并作为一个缓冲区处理。
nFilledLen为所有帧总长度,nTimestamp指向缓冲区第一帧时间。
视频解码单帧过大情况下,可能将单帧拆分后传递给缓冲区。
部分帧情况下,只有最后一帧的缓冲区才拥有OMX_BUFFERLAG_ENDOFFRAME。
部分帧缓冲区不会包含两帧信息。
流媒体可能包含多帧。
部分帧的nTimestamp应当相同。
总结:OMX输出缓冲区可能包含
——完整多帧
——完整单帧
——部分帧
1.5 错误的数据封装
多帧的部分帧封装 eg wrong(Frame1+Frame2 part)
1.6 Codec配置数据
Codec配置缓冲区使用OMX_BUFFERLAG_ENDOFFRAME 和OMX_BUFFERFLAG_CODECCONFIG标志位。
H.264的SPS和PPS使用独立的OMX输入缓冲区。
2 H264/AVC 解码器格式
Codec配置头部:
SPS和PPS NAL单元位于起始的OMX输入缓冲区。
SPS和PPS NALs使用独立的OMX输入缓冲区,并使用OMX_BUFFERLAG_ENDOFFRAME 和OMX_BUFFERFLAG_CODECCONFIG标记。
2.1 AVC NAL模式与AVC Frame模式
通过设置iOMXComponentUsesFullAVCFrame标志位,可以决定AVC数据使用哪种模式解码。
默认使用NAL模式,此种模式下OpenCORE框架同时提供完整单帧和部分帧输入缓冲区。
在Frame模式下,OpenCORE框架积累NALs并提供完整单帧给输入缓冲区。
OMX_OTHER_EXTRADATA结构体用来区分NAL边界。
如果iOMXComponentUsesFullAVCFrame和iOMXComponentUsesNALStratCodes都被置为OMX_TRUE,
NAL边界可被start codes区分,此时OMX_OTHER_EXTRADATA无用。
数据结构——NAL模式:
输入缓冲区包含一个或多个NAL,但只包含同一帧的NAL,一帧最后一个NAL才含有OMX_BUFFERLAG_ENDOFFRAME标志位。
数据结构——Frame模式:
每个输入缓冲区包含完整帧。
如果使用NAL start codes,可通过读取NAL start codes区分NAL边界。
否则使用OMX_OTHER_EXTRADATA结构体区分NAL边界。
在Frame模式中,每个缓冲区都含有OMX_BUFFERLAG_ENDOFFRAME标志位。
在Frame模式中,每个缓冲区都含有位于OMX_BUFFERLAGHEADERTYPE结构体nFlags区域的OMX_BUFFERLAG_EXTRADATA标志位。
缓冲区最后包含AVC frame,追加以下数据:
OMX_OTHER_EXTRADATATYPE
OMX_OTHER_EXTRADATATYPE
extra.eType = OMX_ExtraDataNALSizeA
extra.nSize = 20+4*(number of NALs in the frame); // 20 is the size of
OMX_OTHER_EXTRADATATYPE structure + 4 bytes per NAL size
extra.nDataSize = 4 * (number of NALs in the frame)
extra.data[4*i] = size of the i-th NAL (data is declared as byte array – so offset is 4*i, since 4 bytes
is assigned to signal the size of each NAL unit)
terminator.eType = OMX_ExtraDataN
terminator.nSize = 20;
terminator.nDataSize = 0;
#define OMX_ExtraDataNALSizeArray 0x7F123321
通过获取OMX_OTHER_EXTRADATA结构体信息,可以得知每一帧包含NAL单元的数目并确定NAL边界。
一个例子:AVC Frame模式,包含2个NAL,包含extra数据结构
1)每个缓冲区都含有位于OMX_BUFFERLAGHEADERTYPE结构体nFlags区域的OMX_BUFFERLAG_EXTRADATA标志位
2)每个NAL的长度应当使用独立的4byte无符号整型数表示(eg OMX_U32)
3)所有NAL的长度被编码成OMX_U32的数组存放在buffer最后。
4)包含完整帧的缓冲区必须含有位于OMX_BUFFERLAGHEADERTYPE结构体nFlags区域的OMX_BUFFERLAG_ENDOFFRAME标志位。
5)一个独立的缓冲区不包含多帧数据。
3 YUV和RGB数据格式
OMX编码组件中,生肉提供YUV或者RGB格式,OpenCORE框架将提供一帧完成的YUR或RGB数据给OMX组件。
OpenMax 调用顺序(OpenMax Call Sequences)
1 OMX 核心初始化 _OMX_MasterInit
1)调用OMX_Init函数
-&OsclInit::Init(error, &select); //init all Oscl layers except Oscl scheduler.
-&_Try_OMX_Create(error, data); //create the OMX singleton
-&OsclSingletonRegistry::registerInstanceAndUnlock(data, OSCL_SINGLETON_ID_OMX, error); //Release the singleton.
-&_Try_OMX_Init(error, status); //If create succeeded, then init the OMX globals.
2)PV框架列举所有OMX
OMX_ComponentNameEnum //列举所有组件的名称
-&OsclSingletonRegistry::getInstance(OSCL_SINGLETON_ID_OMX, error);
-&oscl_strncpy(cComponentName, (data-&ipRegTemplateList[Index])-&ComponentName, nNameLength);
OMX_GetRolesOfComponent // 通过组件名称找到组件,返回其角色(role)
-&OsclSingletonRegistry::getInstance(OSCL_SINGLETON_ID_OMX, error);
-&data-&ipRegTemplateList[ii])-&GetRolesOfComponent(RoleString)
-&oscl_strncpy((OMX_STRING) roles[ii], (OMX_STRING)RoleString[ii], oscl_strlen((OMX_STRING)RoleString[ii]) + 1);
2 OMX组件实例、功能及端口
OMX核心初始化后,下一步为列举每个组件的功能和端口。
1)调用OMX_GetHandle获取所需的OMX组件信息。
2)调用OMX_GetParameter及“PV_OMX_CAPABILITY_TYPE_INDEX”这个index去获取组件的功能。
万一组件不是OpenMax全兼容或者OpenMax的特性不明确,以上获取的功能决定了OMX是否支持输入/输出端口“UseBufeer”和“AllocateBuffer”调用,以及OMX是否支持部分帧等等。
注意:如果OMX组件返回“OMX_ErrorUnsupportedIndex”给index(或其他比如“OMX_ErrorNone”),PV框架将为组件功能赋默认值。
3)调用OMX_GetParameter,针对视频组件再调用“OMX_IndexVideoInit”,针对音频组件则调用“OMX_IndexAudioIni”以获取可用的端口号。
4)循环查找可用的端口号以找到输入端口。
5)循环查找可用的端口号以找到输出端口。
Index “PV_OMX_CAPABILITY_TYPE_INDEX” is defined as:
#define PV_OMX_COMPONENT_CAPABILITY_TYPE_INDEX 0xFF7A347
The OMX_GetParameter call expects the following structure to be filled for this index:
typedef struct PV_OMXComponentCapabilityFlagsType
////////////////// OMX COMPONENT CAPABILITY RELATED MEMBERS
OMX_BOOL iIsOMXComponentMultiT
OMX_BOOL iOMXComponentSupportsExternalOutputBufferA
OMX_BOOL iOMXComponentSupportsExternalInputBufferA
OMX_BOOL iOMXComponentSupportsMovableInputB
OMX_BOOL iOMXComponentSupportsPartialF
OMX_BOOL iOMXComponentUsesNALStartC
OMX_BOOL iOMXComponentCanHandleIncompleteF
OMX_BOOL iOMXComponentUsesFullAVCF
} PV_OMXComponentCapabilityFlagsT
功能参数的默认值:
1)iIsOMXComponentMultiThreaded ——默认值OMX_TRUE。
OMX组件一般运行与独立的线程(与PV框架线程不同),有可能将OMX组件集成进PV框架线程(e.g.,通过同步调用)。
2)iOMXComponentSupportsExternalOutputBufferAlloc ——默认值OMX_TRUE。
OMX规范要求OMX组件支持外部分配输出缓冲(就是输出缓冲的OMX_UseBuffer调用)。
如果组件不支持,必须通知PV框架,以便其调用“OMX_AllocateBuffer”代替。
3)iOMXComponentSupportsExternalInputBufferAlloc ——默认值OMX_TRUE。
OMX规范要求OMX组件支持外部分配输入缓冲(就是输入缓冲的OMX_UseBuffer调用)。
如果组件不支持,必须通知PV框架,以便其调用“OMX_AllocateBuffer”代替。
4)iOMXComponentSupportsMovableInputBuffers ——默认值OMX_TRUE。
如果OMX缓冲是外部分配的,为了提高稳定性和优化性能,可以分离OMX缓冲头部信息(OMX_BUFFERHEADERTYPE)与数据区(“pBuffer”)。换句话说,使OMX缓冲更有“移动性”,当传递一个输入缓冲到OMX组件时,“pBuffer”区域和头部信息不一定指向相同的缓冲区。因此,可以分配更多的数据缓冲在框架中循环工作,只有在需要把缓冲传递到OMX组件时才附加到头部信息去。如果OMX组件要求头部和数据一直指向相同的缓冲,则iOMXComponentSupportsMovableInputBuffers应该被置为OMX_FALSE。
5)iOMXComponentSupportsPartialFrames ——默认值OMX_TRUE。
OMX规范要求OMX组件支持将任意数据打包进OMX缓冲,包括独立单帧、NAL和被拆分到多个缓冲区的解码单元。PV框架支持“OMX_BUFFERFLAG_ENDOFFRAME”标记去组装部分帧。然而,如果OMX组件不支持组装部分帧,也就是OMX组件要求PV框架来组装部分帧并提供给OMX组件完整单帧或NAL,此时iOMXComponentSupportsPartialFrames需要被设置为OMX_FALSE。
注意:设置为OMX_FALSE将影响性能。
6)iOMXComponentUsesNALStartCode ——默认值OMX_FALSE。
这个标志位将影响H264解码。PV框架提供所有信息以重建立H264 NALs(通过OMX缓冲的大小和OMX_BUFFERFLAG_ENDOFFRAME的大小)。因此没有必要由OMX组件解码输出流来获取0x0001的NAL初始代码。如果OMX的H264组件及解码单元需要NAL起始代码,可将iOMXComponentUsesNALStartCode置为OMX_TRUE。
7)iOMXComponentCanHandleIncompleteFrames ——默认值OMX_TRUE。
如果丢失部分数据流(比如数据包丢失),假定OMX组件及解码单元可以解决这个问题。如果不可以,则将iOMXComponentCanHandleIncompleteFrames 设置为OMX_FALSE。当“iOMXComponentSupportsPartialFrames”也被设置为OMX_FALSE时,这点相当重要,因为OMX组件不提供组装部分帧,也就是说PV框架必须提供组装好的frame/NALs,因此需要通知OMX组件不完整的帧数据是否可以传递进来。
8)iOMXComponentUsesFullAVCFrames ——默认值OMX_FALSE。
这个标志位决定AVC解码中使用NAL模式还是frame模式。AVC数据可由以上两种模式提供给OMX组件。默认为NAL模式(设置为OMX_FALSE),此模式下OpenCore框架可以为OMX输入缓冲同时提供完整或者部分AVC NAL。Frame模式下(OMX_TRUE),OpenCore框架积累NAL,并提供给OMX输入缓冲一帧完整的数据。
NAL边界的问起前面讨论过了,此处省略。
3 OMX组件输入输出缓冲协商
在任何数据交换前,输入输出缓冲需要进行协商。PV框架需要做以下工作:、
1)调用OMX_GetParameter获取输入端口缓冲参数(最小/实际缓冲数,缓冲区大小等等)
2)检查有效的输入缓冲参数(修改一些参数,比如帧的长度和宽度,以及缓冲区的数目等等)
3)调用OMX_SetParameter函数设置输入缓冲参数
4)调用OMX_GetParameter获取输出端口缓冲参数(最小/实际缓冲数,缓冲区大小等等)
5)检查有效的输出缓冲参数(修改一些参数,比如帧的长度和宽度,以及缓冲区的数目等等)
6)调用OMX_SetParameter函数设置输出缓冲参数
过程如图三(省略)
一些设想:
1)缓冲区尺寸的设想:
对于编码器组件,最终分配的输出缓冲区尺寸可能小于profile/level/target比特率所要求的最大帧尺寸。出于内存消耗考虑,OMX编码器组件应当能够输出frame或NAL的比特流划分到多个输出缓冲区去。老调重弹,最后一个部分缓冲区使用“OMX_BUFFERFLAG_ENDOFFRAME”标记结尾。
对于解码器组件,最终分配的输入缓冲区尺寸可能小于profile/level/target比特率所要求的最大帧尺寸。出于内存消耗考虑,PV框架在适当的时候提供采用“OMX_BUFFERFLAG_ENDOFFRAME”标记结尾的输入缓冲区。如果输入缓冲包含完整帧(H264也可能是NAL单元 )或多帧,“OMX_BUFFERFLAG_ENDOFFRAME”将会用来标记一帧的结尾。如果完整的frame/NAL不能放入一个输入缓冲区,则会被拆分放入多个缓冲区。包含部分信息的缓冲区,“OMX_BUFFERFLAG_ENDOFFRAME”标记位将会被置为0。一帧数据的最后一个缓冲区中“OMX_BUFFERFLAG_ENDOFFRAME”才会被置为1。通过这种做法,组件可以方便的重构一帧数据。
如果OMX解码器组件不兼容组长部分帧,PV框架将负责做这件事情。
2)输入/输出缓冲区数量。
框架或许希望分配比OMX要求更多的的输入/输出缓冲区以提供更优的性能(比如解码器输出缓冲或编码器输入缓冲——缓冲更多的数据可以提高性能)。尽管性能提升了,但无法送到OMX组件去(不太理解,应该还是协商不好的意思)。
4 OMX状态变换 加载-&空闲
如果部分已分配的缓冲区进入空闲状态,缓冲区分配将挂起。在变化过程中,PV框架将“
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StateLoaded改变为OMX_StateIdle
2)调用一系列“OMX_UseBuffer” 或者“OMX_AllocateBuffer”通知OMX组件。这些调用使用NumInputBuffer记录输入输入端口的数目,使用NumOutputBuffer记录输入输入端口的数目。
3)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)
一些设想与推荐参数:
根据OMX规范,兼容的OMX组件必须同时支持OMX_UseBuffer 和 OMX_AllocateBuffer调用。然而,出于一些内在原因,完全实现是不可能的,组件应当通知PV框架其所具有的功能。
推荐将INPUT缓冲分配在OMX组件外部,这样可以减少额外的内存拷贝(也就是说输入缓冲使用OMX_UseBuffer)。
5 变换到“执行”状态与数据交换
状态变化到执行时才开始真正处理数据。本步骤中,PV框架将:
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StateIdle改变为OMX_StateExecuting。
2)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。
3)通过OMX_EmptyThisBuffer调用将输入缓冲发送给OMX组件,通过OMX_FillThisBuffer调用将输出缓冲发送给OMX组件,组件使用合适的回调函数返回缓冲区。
1)在任意时刻OMX组件如果拥有所有输入缓冲区(也就是所有的输入缓冲都通过EmptyThisBuffer调用传给了OMX组件),此时将不能再传递任何输入缓冲区给OMX组件,知道OMX通过EmptyBufferDone释放一个缓冲。对于输出缓冲区同样。
2)如果PV框架没有及时将缓冲区发给OMX框架,OMX组件不会多次返回同一个缓冲区(也就是一旦OMX框架返回一个缓冲区,只有PV框架再次调用这个缓冲,OMX组件才可使用)。这是OMX缓冲交换APSs所规定的基本规则。
PV框架常见的功能包括暂停和恢复,PV框架将:
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StateExecuting改变为OMX_StatePause。
2)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。
PV框架向OMX组件发送暂停命令后,立刻停止发送输入输出缓冲。
有暂停就有恢复,PV框架将:
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StatePause改变为OMX_StateExecuting。
2)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。
PV框架的状态恢复到执行后,将恢复发送OMX输入输出缓冲。
7 端口刷新(如果可用)
端口刷新调用一般用于重新配置解码器组件,这样会清空所有数据。在此情况下,PV框架将:
1)通过“OMX_SendCommand”调用发送刷新全部端口指令。
2)等待输入缓冲的输出缓冲的两个EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。
刷新命令来了之后,PV框架立刻停止向OMX组件发送输入/输出缓冲。当组件接收到2个回调函数后,PV框架开始恢复发送输入/输出缓冲。
端口刷新的顺序和通告并不相关。
过程如图7。
为了防止动态端口被重复配置,也可以先于OMX IL用户关闭OMX组件端口调用端口刷新指令。
8 停止/变化到“IDLE”状态
为了停止处理过程,PV框架将:
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StatePause改变为OMX_StateIdle。
2)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。
过程见图8。
一些设想:
当命令完成“IDEL”态的回调后,PV框架假设所有输入输出缓冲按照OMX规范要求那样返回。
9 OMX组件状态转换 IDLE-&Loaded State和 De-initialization
当PV框架结束与一个OMX组件的所有交互后,将:
1)通过“OMX_SendCommand”调用发送命令给OMX组件,将状态由OMX_StateIdle改变为OMX_StateLoaded。
2)向OMX组件发送一系列“OMX_FreeBuffer”调用。
3)等待OMX组件的EventHandler事件回调,通知框架状态变换完成(OMX_EventCmdComplete)。使用NumInputBuffer记录输入输入端口的数目,使用NumOutputBuffer记录输入输入端口的数目。
4)对OMX核心执行OMX_FreeHandle调用,释放组件句柄。
流程图见图9
注意:在向OMX组件发送卸载命令之前,PV框架一直在等待OMX组件返回的输入输出缓冲。由于回调的过程的不同步性,一些EmptyBufferDone/FillBufferDone的回调有可能在OMX组件状态由“executing” 到 “idle”之后才到达。
10 OMX Core 卸载
PV框架调用函数OMX_Deinit()。
OMX_Init()
没有什么好说的,初始化函数,一定要运行的.
OMX_GetHandle
得到某一个组件的句柄
OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(
&&& OMX_OUT OMX_HANDLETYPE* pHandle,
&&& OMX_IN& OMX_STRING cComponentName,
&&& OMX_IN& OMX_PTR pAppData,
&&& OMX_IN& OMX_CALLBACKTYPE* pCallBacks);
OMX_GetExtensionIndex
除了标准OMX_INDEXTYPE中定义的以外,返回用户自定义的一些参数(第二个参数)对应的index(第三个参数,用在OMX_SetParameter...里面),用来configur或者parameter.
这些参数往往被定义在用户特殊的extension interface里面
#define OMX_GetExtensionIndex(&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& hComponent,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& cParameterName,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& pIndexType)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&& ((OMX_COMPONENTTYPE*)hComponent)-&GetExtensionIndex(&&& /
&&&&&&& hComponent,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& cParameterName,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& pIndexType)&&&&&&&&&&&&&&&&&&&& /* Macro End */
OMX_SetParameter
设定某个参数对应的值
#define OMX_SetParameter(&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& hComponent,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& nParamIndex,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& pComponentParameterStructure)&&&&&&&&&&&&&&&&&&&&&&& /
&&& ((OMX_COMPONENTTYPE*)hComponent)-&SetParameter(&&&&&&&& /
&&&&&&& hComponent,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& nParamIndex,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& pComponentParameterStructure)&&& /* Macro End */
OMX_SetConfig
设定某个config值
#define OMX_SetConfig(&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& hComponent,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& nConfigIndex,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& pComponentConfigStructure)&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&& ((OMX_COMPONENTTYPE*)hComponent)-&SetConfig(&&&&&&&&&&& /
&&&&&&& hComponent,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& nConfigIndex,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& pComponentConfigStructure)&&&&&& /* Macro End */
注意有时候,需要先停止某个组件(的某些端口),才能设置config 成功
OMX_SendCommand
一般的命令有:
OMX_CommandStateSet 、OMX_CommandFlush、OMX_CommandPortDisable&&、 &OMX_CommandPortEnable、CommandMarkBuffer
#define OMX_SendCommand(&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&&& hComponent,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&&& Cmd,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&&& nParam,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&&& pCmdData)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&& ((OMX_COMPONENTTYPE*)hComponent)-&SendCommand(&&&&&&&& /
&&&&&&&& hComponent,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&&& Cmd,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&&& nParam,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&&& pCmdData)&&&&&&&&&&&&&&&&&&&&&&&&& /* Macro End */
&例子:OMXSAFE(OMX_SendCommand(vrenderer, OMX_CommandPortEnable, 1, 0)); // 停下1对应的端口
OMX_SetupTunnel
将两个组件连接起来,实际会引起调用每个组件的ComponentTunnelRequest
OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel(
&&& OMX_IN& OMX_HANDLETYPE hOutput,
&&& OMX_IN& OMX_U32 nPortOutput,
&&& OMX_IN& OMX_HANDLETYPE hInput,
&&& OMX_IN& OMX_U32 nPortInput);
OMXSAFE(OMX_SetupTunnel(reader,&& 0, vdecoder,& 0)); // reader的0端口为出,vdecoder的0端口为入,连接成一个Tunnel
准备好后,就可以设置OMX_StateExecuting,来让这个流程活动起来了。
再以后,就可以通过OMX_StateIdle 来停下。
OMX_GetState
#define OMX_GetState(&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& hComponent,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& pState)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&& ((OMX_COMPONENTTYPE*)hComponent)-&GetState(&&&&&&&&&&&& /
&&&&&&& hComponent,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& /
&&&&&&& pState)&&&&&&&&&&&&&&&&&&&&&&&& /* Macro End */
&一些新补充:
OMX_PARAM_PORTDEFINITIONTYPE decOutputPortD
&& INIT_PARAM(decOutputPortDef);
&&& decOutputPortDef.nPortIndex = 0;
&&& err = OMX_GetParameter(pCtx-&hReaderComp,
&&&&&&&&&&&&&&&&&&&&&&&&&& OMX_IndexParamPortDefinition,
&&&&&&&&&&&&&&&&&&&&&&&&&& &decOutputPortDef); // 利用IndexParamPortDefinition来得到组件的输出端口的属性
&&& videoWidth = decOutputPortDef.format.video.nFrameW&
&&& videoHeight = decOutputPortDef.format.video.nFrameH
2:OMX_BUFFERHEADERTYPE *pOmxBufferH
// tell decoder output port that it will be using our buffer
&&&&&&& err = OMX_UseBuffer(hDecodeComp,
&&&&&&&&&&&&&&&&&&&&&&&&&&& &pOmxBufferHeader,& //out
&&&&&&&&&&&&&&&&&&&&&&&&&&& OMX_DECODE_OUTPUT_PORT,
&&&&&&&&&&&&&&&&&&&&&&&&&&& NULL,
&&&&&&&&&&&&&&&&&&&&&&&&&&& outSize,
&&&&&&&&&&&&&&&&&&&&&&&&&&& (NvU8*)pOut);
&将分配好的pOut指针和他的大小outSize,配成一个OMX_BUF, 并给pOmxBufferHeader,这样就通过OMX_UseBuffer,来得到一个以后能给他用的Buffer,指针用我们分配的。
&OMXErr = OMX_FillThisBuffer(hDecodeComp, pOmxBufferHeader);
让hDecodeComp将pOmxBufferHeader的数据准备好(就是输出数据),pOmxBufferHeader就是通过UseBuffer来组装的。
通过nFilledLen,可以得到具体数据填充情况。
如果OMX_FillThisBuffer是异步函数的话,那真正的返回是要靠:Callback_FillBufferDone 来设置真正数据ready信号
本文已收录于以下专栏:
相关文章推荐
供应传神网站翻译关键词语汉语翻译、汉语翻译公司、北京汉语翻译、英语翻译、英语翻译公司、北京英语翻译、日语翻译、日语翻译公司、北京日语翻译、德语翻译、德语翻译公司、北京德语翻译、法语翻译、法语翻译公司、...
MP4(MPEG-4 Part 14)是一种常见的多媒体容器格式,它是在“ISO/IEC 14496-14”标准文件中定义的,属于MPEG-4的一部分,是“ISO/IEC 14496-12(MPEG-...
【内容导航】
·                     &#160...
ARMV7架构包含:
16个通用寄存器(32bit),R0-R1516个NEON寄存器(128bit),Q0-Q15(同时也可以被视为32个64bit的寄存器,D0-D31)
android StageFright框架解读
android多媒体框架
MediaPlayerService
Stagefright
底层openmax
每个AwesomePlayer 只有一个OMX服务的入口,但是AwesomePlayer不一定就只需要1种解码器。有可能音视频都有,或者有很多种。这个时候这些解码器都需要OMX的服务,也就是OMX那头...
首先用工具分析一个flv文件,flv是一种封装格式,是adobe公司推出的。官方文档可以参考:video_file_format_spec_v10_1,本文根据官方文档总结。FLV 文件格式FLV格式...
NuPlayer是谷歌新研发的。
AwesomePlayer存在BUG,谷歌早已在android m 版本中弃用。
spMediaPlayerBase& MediaPlayerService:...
Android多媒体开发-- android中OpenMax的实现整体框架
1.android中用openmax来干啥?
android中的 AwesomePlayer就
NEON是适用于ARM
Cortex-A系列处理器的一种128位SIMD(Single Instruction, Multiple Data,单指令、多数据)扩展结构。从智能手机和移...
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 this app cant open 的文章

 

随机推荐