什么是OpenMAX技术分析OpenMAX
什么是OpenMAX技术分析OpenMAX
OpenMAX是统一的抽象层,它允许访问否则需要供应商特定API的硬件。
Broadcom的MMAL(多媒体抽象层API)。
因此,OpenMAX允许使用此类硬件的软件的(某种)便携式实现。本文概述Raspberry Pi的硬件媒体功能以及如何使用OpenMAX访问它。Raspberry Pi Foundation提供的官方OpenMAX IL 1.1.2文档和IL组件文档构成了本文的基础。(Khronos宣布OpenMAX为无效标准。无论如何。OpenMAX提供了对硬件的抽象,该硬件能够对多媒体(音频,图像和视频)执行操作。就像OpenGL(现在是Vulkan,所有这些都由同一个组织Khronos指定)一样,它通过专门用于游戏等实时3D渲染的硬件进行抽象。(有趣的事实:Vulkan是星际迷航中Spock先生的家行星Vulcan的拼写错误,就像Khronos听起来像Klingon帝国的家乡Qo'nos一样)。硬件一次只能处于一种状态,因此它类似于状态机。OpenMAX映射到该状态机,并提供一个API对其进行操作。由于它与硬件的紧密绑定,因此只有在相应的硬件处于特定状态时才能发出许多命令。
这是根据对Raspberry Pi的观察得出的结果,不知道它们是否适用于其他OpenMAX设备。因此更精确。有些命令以错误的状态发出时会引发错误。其他人不会提出错误,但也不会执行该操作,直到满足状态要求为止。这导致(至少在Raspberry Pi上)一些已发布的命令(几乎)立即(几乎)立即调用相应的事件处理程序,而另一些则要等到首先发出更多的命令后,才会产生这样的效果。因此,应该通过一条黄金路径发出命令来克服OpenMAX API的异步特性。如果离开该路径,则必须处理同步并在发出下一个命令之前等待回调处理程序被调用。使用OpenMAX
每个硬件功能都类似于OpenMAX中的一个组件。可以在Raspberry Pi Foundation的git存储库中全面了解Broadcom提供的所有组件。组件可视为具有输入和/或输出的数学函数。同样,每个组件都可以分配到四个域之一:音频,图像,视频和其他。最简单的情况是一(1)个输入端口和一(1)个输出端口。可以传入数据,处理后的数据就会出来。例如,可以是视频编码器。将原始图像流传递到输入端口,并在输出上获得h.264编码的流。也可以将一个组件的输出端口链接到另一组件的输入端口。所谓的隧道,允许链接组件,并且只处理一个输入端口和一个输出端口,而不必处理中间结果。因此,OpenMAX允许形成一条管道并配置许多方面,以便可以通过它流传输数据。
在VMCS-X OpenMAX IL组件概述中,输入端口和输出端口必须位于同一域中(由端口的颜色指示)。该页面显示了Rasbian中所有可用的组件,而VideoCore IV中不是全部可用,因为并非所有组件都可以使用,因为它们需要VC作为主要SoC来运行,并且可以访问像image_read这样的文件系统。该文档仍然存在,但未在index.html中链接。所有端口都有一些要配置的参数。带有链接的链接指向特定于Broadcoms VideoCore IV的参数。
假设有一个网络摄像头,并且想要在的网站上提供多部分JPEG图像(也称为MJPEG)。有些网络摄像头可以自动执行此操作,但是有些则不能,在后一种情况下,将不得不获取图像并反复运行JPEG编码。这是一项CPU繁重的任务,因为通常对每个图像使用相同的大小和压缩率,所以这是重复性的。使用OpenMAX,可以设置一个JPEG编码器组件来为完成此任务,然后CPU只需将原始图像数据铲入并拉出编码的JPEG图像。
本文代码保持在最低水平,但在更高层次上还是要讨论。所有真正的C语言代码都可以在的git存储库OMXPlayground中找到。当前,由于具有多个频繁循环,因此这些实现并不理想。但是OpenMAX标准规定,调用必须在指定的毫秒数内返回。例如,回调是阻塞组件的调用,因此,客户端(此代码)应在5毫秒(3.1.2.9.1-3.1.2.9.3)内从回调中返回。要求未处理任何缓冲区的OpenMAX调用必须在20毫秒和5毫秒内返回(否则为3.2)。image_encode
这是较简单的情况之一,将在以后看到。它以从Alpha格式的16/24/32位RGB到YUV和CrCbY的变体的各种格式拍摄原始图像。输出可以是下面列出的任何受支持的压缩图像格式。
该组件非常容易,因为可以完全控制输入和输出格式,并且支持多种格式。因此,基本上只需要配置输入和输出端口,就可以开始向其上扔数据了。
基本步骤:
- 获取EmptyBufferDone和FillBufferDone的回调的句柄。
- 禁用端口340和341。
- 将手柄切换到空闲状态。
- 为端口340配置,启用和分配bufferX。
- 配置,启用和分配341端口的bufferY。
- 将句柄切换为执行。
- 遍历数据:
- 从bufferY复制压缩的数据。
- 填充缓冲区Y。
- 将图像数据复制到bufferX。
- 空缓冲区X。
- 将手柄切换到空闲状态。
- 为端口340禁用和取消分配bufferX。
- 为端口341禁用和取消分配bufferY。
- 将手柄切换到已加载。
- 免费切换。
为回调EmptyBufferDone和FillBufferDone需要推动循环的数据。如果OMX_EmptyThisBuffer尚未完成处理,则无法将数据传递到组件中。因为此调用没有阻止,所以必须等待EmptyBufferDone回调。OMX_FillThisBuffer通话类似。必须等待FillBufferDone回调,然后才能从组件获取结果数据。
设置输出端口时,如果所选数据格式支持,则可以提供所需的颜色格式。还可以为JPEG数据格式设置压缩率或量化因子(Q因子)。对于JPEG,还可以定义使用libjpeg的IJG量化表。
通过设置端口来配置端口OMX_IndexParamPortDefinition。nBufferSize将根据改变format.image.nFrameWidth,format.image.nSliceHeight和format.image.eColorFormat(每像素的字节数)。因此,设置后,OMX_IndexParamPortDefinition应该对其进行查询以获取更新nBufferSize。同样,大多数图像组件都支持16像素切片或一次完整图像的图像处理。
输入颜色格式 |
OMX_COLOR_Format16bitRGB565 |
OMX_COLOR_Format24bitBGR888 |
OMX_COLOR_Format24bitRGB888 |
OMX_COLOR_Format32bitABGR8888 |
OMX_COLOR_Format32bitARGB8888 |
OMX_COLOR_FormatYUV420PackedPlanar |
OMX_COLOR_FormatYUV422PackedPlanar |
OMX_COLOR_FormatYCbYCr |
OMX_COLOR_FormatYCrYCb |
OMX_COLOR_FormatCrYCbY |
OMX_COLOR_FormatCbYCrY |
输出图像格式 |
颜色格式 |
OMX_IMAGE_CodingGIF |
OMX_COLOR_Format8bitPalette |
OMX_IMAGE_CodingBMP |
? |
OMX_IMAGE_CodingJPEG |
? |
OMX_IMAGE_CodingPNG |
? |
OMX_IMAGE_CodingPPM |
? |
OMX_IMAGE_CodingTGA |
? |
image_decode
输入口 |
组件名称 |
输出口 |
320 |
image_decode |
321 |
该组件从各种压缩数据格式解码图像,并返回解压缩的图像。必须告诉组件使用哪个解码器,并且输出颜色格式取决于此。由于没有内部转换,因此如果解码JPEG,则将不会获得RGB图像数据,因为JPEG固有的颜色格式是YUV(420?)。
如果要更改输出颜色格式,则必须通过image_resize组件运行结果数据。可以在这两个组件之间建立管道,因此只需处理一个输入和一个输出,而不必处理中间数据。但这是更高级的,将在以后看到。
由于此组件不提供输出颜色格式的转换,因此必须处理图像数据,因为它会出来,因此无法配置输出端口。输出端口将自动配置为输入。因此,将必须将数据传递到组件中,并使其相应地更改输出。
基本步骤:
- 获取EmptyBufferDone和FillBufferDone的回调的句柄。
- 禁用端口320和321。
- 将手柄切换到空闲状态。
- 为端口320配置,启用并分配bufferX [3]。
- 将端口321配置为自动检测。
- 将句柄切换为执行。
- 将图像数据复制到bufferX [i = 0]。
- 空bufferX [i]。
- 等待 OMX_EventPortSettingsChanged
- 为端口321启用并分配bufferY。
- 遍历数据:
- 从bufferY复制解码的图像数据
- 填充缓冲区Y
- 将压缩的图像数据复制到bufferX [i =(i + 1)%3]
- 空缓冲区X [i]
- 将手柄切换到空闲状态。
- 为端口340禁用和取消分配bufferX [3]。
- 为端口341禁用和取消分配bufferY。
- 将手柄切换到已加载。
- 免费提手。
如所见,执行在配置输出之前开始。传递到输入的数据不会丢失,而是会缓冲在组件中,直到完全设置输出为止。这就是为什么必须等待传递新数据的原因之一。当输出端口准备就绪时,它将调用FillBufferDone回调并让获取解压缩的图像数据。
支持的输入格式:?
支持的输出格式:?_resize
输入口 |
组件名称 |
输出口 |
60 |
image_resize |
61 |
该组件可用于裁剪和调整图像大小以及更改颜色格式。可以在输入上配置裁剪,并为输出指定任意大小。该组件与组件一样直接,image_encode因为可以完全控制输入和输出端口,并且可以独立设置它们。Broadcom实施中的一个特殊之处在于,它仅支持处理16像素切片或整个像素中的输入。
基本步骤:
- 获取EmptyBufferDone和FillBufferDone的回调的句柄。
- 禁用端口60和61。
- 将手柄切换到空闲状态。
- 配置包括裁剪,启用并为端口60分配bufferX。
- 为端口61配置,启用和分配bufferY。
- 将句柄切换为执行。
- 遍历数据:
- 从bufferY复制转换后的图像数据。
- 填充缓冲区Y。
- 将图像数据复制到bufferX。
- 空缓冲区X。
- 将手柄切换到空闲状态。
- 禁用和取消分配端口60的bufferX。
- 禁用和取消分配端口61的bufferY。
- 将手柄切换到已加载。
- 免费切换。
除了裁剪以外,其他步骤与相同image_encode。同样,可以通过在中设置宽度和高度OMX_IndexParamPortDefinition或通过来设置输出大小调整OMX_IndexParamResize。
支持的输入格式:?
支持的输出格式:?
- 端口只能在禁用的情况下进行配置。
- 只能在已启用的端口上分配缓冲区。
- 仅当至少输入端口已准备就绪(配置,启用和分配)时,句柄才能进入执行状态。
- 如果打电话给OMX_SetParameter不要使用在随后的呼叫和计算中传递的数据。数据很可能会发生变化,因此请OMX_GetParameter在继续之前先致电。