Android OMAP4 Ducati 和 OpenMax IL介绍
Update
TI 发布的这个文章,个人感觉特别好,想研究的朋友可以看一下:
http://processors.wiki.ti.com/index.php/OMX_EZSDK_Examples
转载一篇很好的文章,地址: http://book.51cto.com/art/201101/243147.htm
,感谢分享
文章主要个大家介绍OMAP平台OpenMax IL的硬件实现过程。其中包括TI OpenMax IL实现的结构和机制,TI OpenMax IL的核心和公共内容,一个TI OpenMax IL组件的实现三个部分。
来源于一本书:Android系统级深入开发--移植与调试
这里说说TI 的OMAP4 Ducati
转载一篇介绍Ducati 的文章,写的也不错: http://www.61ic.com/Article/DaVinci/OMAP3x/201111/39340.html
同样感谢分享,共同进步
当然TI官网资料是最好的了解Ducati 的资料: http://omappedia.com/wiki/Ducati_For_Dummies
我想着重看的在这里:
ISS Overview
The Imaging Sub System (ISS) deals with the processing of pixel data coming from an external image sensor or from memory. ISS as a component forms part of still image capture, camera viewfinder and video record use-cases. Figure below shows the Imaging subsystem constituents.
ISS subparts include:
- Two CSI2: Receives data from sensor.
- CCP2: Receives data from sensor or reads from memory.
- ISP: Pre/post processing operations on pixel data (received from sensor or from memory).
- SIMCOP: Imaging accelerator.
- BTE: Burst Translation Engine. Converts from raster to 2D tiled order and vice versa, for data write and data read respectively.
- CBUFF: Circular Buffer for linear space, physically located in memory.
Among these, ISP and SIMCOP are the two major processing blocks.
IPC on Ducati
DOMX
it
Distributed OpenMAX? Integration Layer (IL) framework (DOMX) is the multimedia framework used for Inter Processor Communication (IPC) on OMAP4 to enable easy and transparent use of OpenMAX IL (OMX) components, on remote processing cores like Ducati. It is built upon Remote Procedure Call (RPC) concepts.
On OMAP4, many of the (high performance) video/imaging codecs and algorithms execute on the hardware accelerator subsystem (Ducati), but the application/client which invokes these codecs and algorithms executes on the host processor (Cortex A9). The IPC between Cortex A9 and Ducati is handled by SysLink. The only interface that Ducati exposes to Cortex A9 is OMX.
DOMX framework provides a seamless abstraction for Cortex A9 and Ducati to communicate via SysLink. This framework abstracts all details like buffer address translations, maintaining cache-external memory coherence, exact mechanisms used to communicate to remote cores, etc.
IPC Overview
Based on the functionalities involved, DOMX is layered into OMX-Proxy, OMX-RPC (OpenMAX API specific Remote Procedure Call) and RCM (Remote Command Message is a generic RPC service maintained by SysLink).
All IPC between Cortex A9 and Ducati has to pass through these layers. Figure below shows a block diagram of communication between these two processing cores by means of DOMX. Note that the Host processor is Cortex A9 and Remote processor is Ducati sub system. There are proxies for each component (H.264 encoder, MPEG-4 Visual decoder, JPEG decoder, etc.) The code common to all these proxies is extracted into Proxy Common block, with only the component specific parts in the individual proxies.
A Proxy is a thin component that provides OpenMAX interface APIs for peer OpenMAX components and clients. A proxy component as the name suggests is a ‘Proxy’ on local core that corresponds to a real component implemented on a remote core. It is a thin layer exporting the OpenMAX interfaces.
The proxy component’s principal functionality is to forward calls to remote component using RPC Stub functions and RCM Client-Server infrastructure. Proxies also forward client call backs to the IL Client for calls that originated on the remote core. All buffer address mapping, maintenance, etc. are the responsibility of the proxy component.
OMX-RPC layer implements Stubs (packing the information of an API call) and Skeletons (unpacking the information of an API call) for all the OpenMAX APIs. For calls originating on local core RPC Stub allocates message, packs the arguments and invokes appropriate remote function based on OpenMAX API using RCM layer.
The RPC Skeleton (on the remote core) receives the packed data, unpacks it and invokes appropriate remote function with the unpacked arguments. RPC Skeleton is also responsible for packing any return values associated with the remote call and sending it back to the local core. On the return path, the RPC Stub extracts the remote invocation ‘Return’ value, frees the message and returns the remote invocation ‘Return’ value to the caller.
The RCM layer is provided by SysLink and abstracts core specific IPC and transport layers and manages the messaging between processing cores. RCM is implemented on Client-Server paradigm. RCM client implements the transport mechanism to send a message to a given server. The server is identified by a name that is unique across the entire system. On reception of the message the RCM Server extracts the function index from it and invokes the associated remote function. To enable index based remote invocation the server maintains an Index-Remote Function table that is populated at initialization or by registration. The client will discover the index for a given remote function by querying the server by the remote function name.
All communication from host to remote OMX component goes via a proxy which exposes the same OMX interface as the real component. The proxy sends message to RPC layer which packs data and uses the RCM client-server model to send this data to remote core via SysLink. On remote core, the RPC layer unpacks the message received and sends it to the real OMX component. Callbacks if any, follow a similar path in reverse direction.
Thus the DOMX layer ensures that OMX components and the clients which invoke these components remain unaware of any IPC involved. As far as the components and their clients are concerned there is no difference between a local and remote call. DOMX framework ensures that a remote call is executed in the same way as a local call.
Here is a sequence of all the OMX API calls that the hello_video sample program makes (from raspberry pi raspbian sample image).
- OMX_Init()
- OMX_GetHandle(pHandleDecode, "OMX.broadcom.video_decode", pAppData, &callbacks)
- OMX_GetComponentVersion(pHandleDecode, pszNameArray, pCompVersion, pSpecVersion, pUID) name: "OMX.broadcom.video_decode:22", version: 0's, spec version: 1.1.2, uid same as name
- OMX_GetParameter(pHandleDecode, OMX_IndexParamAudioInit, &pPorts) (nPorts returned as 0)
- OMX_GetParameter(pHandleDecode, OMX_IndexParamVideoInit, &pPorts) (nPorts returned 2) (ports.nStartPortNumber returned 130)
- OMX_SendCommand(pHandleDecode, OMX_CommandPortDisable, 130, NULL)
- (waits for event callback to fire in other thread to indicate that port has been disabled)
- OMX_SendCommand(pHandleDecode, OMX_CommandPortDisable, 131, NULL)
- (waits for event callback to fire in other thread to indicate that port has been disabled)
- OMX_GetHandle(pHandleRender, "OMX.broadcom.video_render", pAppData, &callbacks)
- OMX_GetComponentVersion(pHandleRender, ...)
- OMX_GetParameter(pHandleRender, OMX_IndexParamAudioInit, &pPorts) (nPorts returned as 0)
- OMX_GetParameter(pHandleRender, OMX_IndexParamVideoInit, &pPorts) (nPorts returned 1) (ports.nStartPortNumber returned 90)
- OMX_GetHandle(pHandleClock, "OMX.broadcom.clock", ...)
- OMX_GetParameter(pHandleClock, OMX_IndexParamOtherInit, ...) (nPorts returned as 6) (ports.nStartPortNumber returned UNKNOWN, FIND OUT)
- OMX_SetParameter(pHandleClock?, OMX_IndexConfigTimeClockState, &cState)
- OMX_GetHandle(pHandleSched, "OMX.broadcom.video_scheduler", ...)
- OMX_GetParameter(pHandleSched, OMX_IndexParamVideoInit, &pPorts) (nPorts returned 2) (ports.nStartPortNumber returned 10)
- OMX_GetParameter(pHandleSched, OMX_IndexParamAudioInit, &pPorts) (nPorts returned 1) (ports.nStartPortNumber returned 12)
- OMX_GetState(pHandleClock, &state) (returns state of OMX_StateLoaded)
- OMX_SendCommand(pHandleClock, OMX_CommandStateSet, OMX_StateIdle, NULL)
- (waits for command to complete)
- OMX_SendCommand(pHandleClock, OMX_CommandPortDisable, 80, NULL)
- OMX_SendCommand(pHandleSched, OMX_CommandPortDisable, 12, NULL)
- (waits for both previous commands to finish)
- OMX_GetParameter(pHandleClock, OMX_IndexParamNumAvailableStreams, ¶m) (returned an error because source port does not use streams)
- OMX_SetupTunnel(pHandleClock, 80, pHandleSched, 12);
- OMX_SendCommand(pHandleClock, OMX_CommandPortEnable, 80, NULL);
- OMX_SendCommand(pHandleSched, OMX_CommandPortEnable, 12, NULL);
- OMX_GetState(pHandleSched, &state) (returns OMX_StateLoaded)
- (wait for enable tunnel command to complete for pHandeSched)
- OMX_SendCommand(pHandleSched, OMX_CommandStateSet, OMX_StateIdle, NULL)
- (wait for state change command to complete)
- (wait for enable tunnel to complete for pHandleClock)
- OMX_SendCommand(pHandleClock, OMX_CommandStateSet, OMX_StateExecute, NULL)
- OMX_SendCommand(pHandleDecode, OMX_CommandStateSet, OMX_StateIdle, NULL)
- OMX_SetParameter(pHandleDecode, OMX_IndexParamVideoPortFormat, &format)
- OMX_GetParameter(pHandleDecode, OMX_IndexParamPortDefinition, &portdef) (index is 130)
- (portdef.bEnabled == OMX_FALSE, portdef.nBufferCountActual == 20, portdef.nBufferSize == 81920, portdef.nBufferAlignment == 16, portdef.eDir == OMX_DirInput, portdef.eDomain == OMX_PortDomainVideo)
- OMX_GetState(pHandleDecode, &state) (state is OMX_StateIdle)
- OMX_SendCommand(pHandleDecode, OMX_CommandPortEnable, 130, NULL)
- (allocates buffer of 81920 bytes in size)
- OMX_UseBuffer(pHandleDecode, ?, 130, NULL, 81920, bufThatWasAllocated)
- (this allocation of buffer followed by the OMX_UseBuffer call loops 20 times)
- OMX_SendCommand(pHandleDecode, OMX_CommandStateSet, OMX_StateExecuting, NULL)
- (get a unique buffer.. somehow.. lol)
- (fread video stream into buffer)
- (set buf->nFilledLen to the bytes we read, buf->nOffset = 0, buf->nFlags = OMX_BUFFERFLAG_STARTTIME)
- OMX_EmptyThisBuffer(pHandleDecode, buf) where buf points to a OMX_BUFFERHEADTYPE struct
- Keep doing the former starting with getting the unique buffer until we notice that port 131 has received a OMX_EventPortSettingsChanged event
- begin one-time step
- Set up tunnel from port 131 (decode) to port 10 (scheduler)
- change video scheduler's state to executing
- Set up tunnel from port 11 (scheduler) to port 90 (render)
- change render state to executing
- end of the one-time-step
- continue looping (getting a unique buffer, etc) until fread gets end-of-file
- OMX_EmptyThisBuffer(pHandleDecode, buf) where buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS and nFilledLen is 0
- Wait for event from video render, where the event is OMX_EventBufferFlag of OMX_BUFFERFLAG_EOS
- flush tunnels so that decoder can disable its input port by doing the following:
- OMX_SendCommand(pHandleDecode, OMX_CommandFlush, 131, NULL)
- OMX_SendCommand(pHandleSched, OMX_CommandFlush, 10, NULL)
- wait for two flush events to be received
- OMX_SendCommand(pHandleSched, OMX_CommandFlush, 11, NULL)
- OMX_SendCommand(pHandleRender, OMX_CommandFlush, 90, NULL)
- wait for two flush events to be received
- OMX_SendCommand(pHandleClock, OMX_CommandFlush, 80, NULL)
- OMX_SendCommand(pHandleSched, OMX_CommandFlush, 12, NULL)
- wait for two flush events to be received
- OMX_GetParameter(pHandleDecode, OMX_IndexParamPortDefinition, &portdef) (where port is 130)
- OMX_SendCommand(pHandleDecode, OMX_CommandPortDisable, 130, NULL)
- OMX_FreeBuffer(pHandleDecode, 130, ?) <-- loop 20 times for each buffer
- wait for port disable to finish
- OMX_SendCommand(pHandleDecode, OMX_CommandPortDisable, 131, NULL)
- OMX_SendCommand(pHandleSched, OMX_CommandPortDisable, 10, NULL)
- wait for port disable to finish
- OMX_SendCommand(pHandleSched, OMX_CommandPortDisable, 11, NULL)
- OMX_SendCommand(pHandleRender, OMX_CommandPortDisable, 90, NULL)
- wait for port disable to finish
- OMX_SendCommand(pHandleClock, OMX_CommandPortDisable, 80, NULL)
- OMX_SendCommand(pHandleSched, OMX_CommandPortDisable, 12, NULL)
- wait for port disable to finish
- OMX_SetupTunnel(pHandleDecode, 131, NULL, 0)
- OMX_SetupTunnel(pHandleSched, 10, NULL, 0)
- OMX_SetupTunnel(pHandleSched, 11, NULL, 0)
- OMX_SetupTunnel(pHandleRender, 90, NULL, 0)
- OMX_SetupTunnel(pHandleClock, 80, NULL, 0)
- OMX_SetupTunnel(pHandleSched, 12, NULL, 0)
- change state of every handle to OMX_StateIdle (in random order for some unexplained reason)
- change state of every handle to OMX_StateLoaded (in random order for some unexplained reason)
- OMX_FreeHandle(pHandleDecode)
- OMX_FreeHandle(pHandleRender)
- OMX_FreeHandle(pHandleClock)
- OMX_FreeHandle(pHandleSched)
- OMX_Deinit()