技术开发 频道

Android OMAP平台OpenMax IL的硬件实现

  【IT168技术】本文主要个大家介绍OMAP平台OpenMax IL的硬件实现过程。其中包括TI OpenMax IL实现的结构和机制,TI OpenMax IL的核心和公共内容,一个TI OpenMax IL组件的实现三个部分。

  Android的开源代码中,已经包含了TI的OpenMax IL层的实现代码,其路径如下所示:

  hardware/ti/omap3/omx/

  其中包含的主要目录如下所示。

  system:OpenMax核心和公共部分

  audio:音频处理部分的OpenMax IL组件

  video:视频处理部分OpenMax IL组件

  image:图像处理部分OpenMax IL组件

  TI OpenMax IL实现的结构如图18-7所示。

  在TI OpenMax IL实现中,最上面的内容是OpenMax的管理者用于管理和初始化,中间层是各个编解码单元的OpenMax IL标准组件,下层是LCML层,供各个OpenMax IL标准组件所调用。

  TI OpenMax IL实现的公共部分在system/src/openmax_il/目录中,主要的内容如下所示。

  omx_core/src:OpenMax IL的核心,生成动态库libOMX_Core.so

  lcml/:LCML的工具库,生成动态库libLCML.so

  TI OpenMax IL的视频(Video)相关的组件在video/src/openmax_il/目录中,主要的内容如下所示。

  prepost_processor:Video数据的前处理和后处理,生成动态库libOMX.TI.VPP.so

  video_decode:Video解码器,生成动态库libOMX.TI.Video.Decoder.so

  video_encode:Video编码器,生成动态库libOMX.TI.Video.encoder.so

TI OpenMax IL实现的结构和机制

  ▲图18-7 TI OpenMax IL实现的结构

  TI OpenMax IL的音频(Audio)相关的组件在audio/src/openmax_il/目录中,主要的内容如下所示。

  g711_dec:G711解码器,生成动态库libOMX.TI.G711.decode.so

  g711_enc:G711编码器,生成动态库libOMX.TI.G711.encode.so

  g722_dec:G722解码器,生成动态库libOMX.TI.G722.decode.so

  g722_enc:G722编码器,生成动态库libOMX.TI.G722.encode.so

  g726_dec:G726解码器,生成动态库libOMX.TI.G726.decode.so

  g726_enc:G726编码器,生成动态库libOMX.TI.G726.encode.so

  g729_dec:G729解码器,生成动态库libOMX.TI.G729.decode.so

  g729_enc:G720编码器,生成动态库libOMX.TI.G729.encode.so

  nbamr_dec:AMR窄带解码器,生成动态库libOMX.TI.AMR.decode.so

  nbamr_enc:AMR窄带编码器,生成动态库libOMX.TI.AMR.encode.so

  wbamr_dec:AMR宽带解码器,生成动态库libOMX.TI.WBAMR.decode.so

  wbamr_enc:AMR宽带编码器,生成动态库libOMX.TI.WBAMR.encode.so

  mp3_dec:MP3解码器,生成动态库libOMX.TI.MP3.decode.so

  aac_dec:AAC解码器,生成动态库libOMX.TI.AAC.decode.so

  aac_enc:AAC编码器,生成动态库libOMX.TI.AAC.encode.so

  wma_dec:WMA解码器,生成动态库libOMX.TI.WMA.decode.so

  TI OpenMax IL的图像(Image)相关的组件在image/src/openmax_il/目录中,主要的内

  容如下所示。

  jpeg_enc:JPEG编码器,生成动态库libOMX.TI.JPEG.Encoder.so

  jpeg_dec:JPEG解码器,生成动态库libOMX.TI.JPEG.decoder.so

  TI OpenMax IL的核心和公共内容

  LCML的全称是“Linux Common Multimedia Layer”,是TI的Linux公共多媒体层。在OpenMax IL的实现中,这个内容在system/src/openmax_il/lcml/目录中,主要文件是子目录src中的LCML_DspCodec.c文件。通过调用DSPBridge的内容, 让ARM和DSP进行通信,然DSP进行编解码方面的处理。DSP的运行还需要固件的支持。

  TI OpenMax IL的核心实现在system/src/openmax_il/omx_core/目录中,生成TI OpenMax IL的核心库libOMX_Core.so。

  其中子目录src中的OMX_Core.c为主要文件,其中定义了编解码器的名称等,其片断如下所示:

char *tComponentName[MAXCOMP][2] = {
    {
"OMX.TI.JPEG.decoder", "image_decoder.jpeg"},  /* 图像和视频编解码器 */
    {
"OMX.TI.JPEG.Encoder", "image_encoder.jpeg"},
    {
"OMX.TI.Video.Decoder", "video_decoder.avc"},
    {
"OMX.TI.Video.Decoder", "video_decoder.mpeg4"},
    {
"OMX.TI.Video.Decoder", "video_decoder.wmv"},
    {
"OMX.TI.Video.encoder", "video_encoder.mpeg4"},
    {
"OMX.TI.Video.encoder", "video_encoder.h263"},
    {
"OMX.TI.Video.encoder", "video_encoder.avc"},
    
/* ......省略 ,语音相关组件*/
#ifdef BUILD_WITH_TI_AUDIO                              
/* 音频编解码器 */
    {
"OMX.TI.MP3.decode", "audio_decoder.mp3"},
    {
"OMX.TI.AAC.encode", "audio_encoder.aac"},
    {
"OMX.TI.AAC.decode", "audio_decoder.aac"},
    {
"OMX.TI.WMA.decode", "audio_decoder.wma"},
    {
"OMX.TI.WBAMR.decode", "audio_decoder.amrwb"},
    {
"OMX.TI.AMR.decode", "audio_decoder.amrnb"},
    {
"OMX.TI.AMR.encode", "audio_encoder.amrnb"},
    {
"OMX.TI.WBAMR.encode", "audio_encoder.amrwb"},
#endif
    {
NULL, NULL},
};

  tComponentName数组的各个项中,第一个表示编解码库内容,第二个表示库所实现的功能。

  其中,TIOMX_GetHandle()函数用于获得各个组建的句柄,其实现的主要片断如下所示:

OMX_ERRORTYPE TIOMX_GetHandle( OMX_HANDLETYPE* pHandle, OMX_STRING cComponentName,
    OMX_PTR pAppData, OMX_CALLBACKTYPE
* pCallBacks)
{
    static
const char prefix[] = "lib";
    static
const char postfix[] = ".so";
    OMX_ERRORTYPE (
*pComponentInit)(OMX_HANDLETYPE*);
    OMX_ERRORTYPE err
= OMX_ErrorNone;
    OMX_COMPONENTTYPE
*componentType;
    
const char* pErr = dlerror();
// ...... 省略错误处理内容
    
int i = 0;
    
for(i=0; i< COUNTOF(pModules); i++) {       // 循环查找
        
if(pModules[i] == NULL) break;
    }
// ...... 省略错误处理内容
    
int refIndex = 0;
    
for (refIndex=0; refIndex < MAX_TABLE_SIZE; refIndex++) {            
// 循环查找组件列表
        
if (strcmp(componentTable[refIndex].name, cComponentName) == 0) {
            
if (componentTable[refIndex].refCount >= MAX_CONCURRENT_INSTANCES) {
// ...... 省略错误处理内容
            }
else {
                char buf[sizeof(prefix)
+ MAXNAMESIZE + sizeof(postfix)];
                strcpy(buf, prefix);
                strcat(buf, cComponentName);
                strcat(buf, postfix);
                pModules[i]
= dlopen(buf, RTLD_LAZY | RTLD_GLOBAL);
            
// ...... 省略错误处理内容
            
// 动态取出初始化的符号
                pComponentInit
= dlsym(pModules[i], "OMX_ComponentInit");  
                pErr
= dlerror();
            
// ...... 省略错误处理内容
                
*pHandle = malloc(sizeof(OMX_COMPONENTTYPE));
            
// ...... 省略错误处理内容
                pComponents[i]
= *pHandle;
                componentType
= (OMX_COMPONENTTYPE*) *pHandle;
                componentType
->nSize = sizeof(OMX_COMPONENTTYPE);
                err
= (*pComponentInit)(*pHandle);   // 执行初始化工作
            
// ...... 省略部分内容
            }
        }
    }
    err
= OMX_ErrorComponentNotFound;
    
goto UNLOCK_MUTEX;
// ...... 省略部分内容
    return (err);
}

  在TIOMX_GetHandle()函数中,根据tComponentName数组中动态库的名称,动态打开各个编解码实现的动态库,取出其中的OMX_ComponentInit符号来执行各个组件的初始化。

  一个TI OpenMax IL组件的实现

  TI OpenMax IL中各个组件都是通过调用LCML来实现的,实现的方式基本类似。主要都是实现了名称为OMX_ComponentInit的初始化函数,实现OMX_COMPONENTTYPE类型的结构体中的各个成员。各个组件其目录结构和文件结构也类似。

  以MP3解码器的实现为例,在audio/src/openmax_il/mp3_dec/src目录中,主要包含以下文件。

  OMX_Mp3Decoder.c:MP3解码器组件实现

  OMX_Mp3Dec_CompThread.c:MP3解码器组件的线程循环

  OMX_Mp3Dec_Utils.c:MP3解码器的相关工具,调用LCML实现真正的MP3解码的功能

  OMX_Mp3Decoder.c中的OMX_ComponentInit()函数负责组件的初始化,返回的内容再从参数中得到,这个函数的主要片断如下所示:

OMX_ERRORTYPE OMX_ComponentInit (OMX_HANDLETYPE hComp)
{    
    OMX_ERRORTYPE eError
= OMX_ErrorNone;
    OMX_COMPONENTTYPE
*pHandle = (OMX_COMPONENTTYPE*) hComp;
    OMX_PARAM_PORTDEFINITIONTYPE
*pPortDef_ip = NULL, *pPortDef_op = NULL;
    OMX_AUDIO_PARAM_PORTFORMATTYPE
*pPortFormat = NULL;
    OMX_AUDIO_PARAM_MP3TYPE
*mp3_ip = NULL;
    OMX_AUDIO_PARAM_PCMMODETYPE
*mp3_op = NULL;
    MP3DEC_COMPONENT_PRIVATE
*pComponentPrivate = NULL;
    MP3D_AUDIODEC_PORT_TYPE
*pCompPort = NULL;
    MP3D_BUFFERLIST
*pTemp = NULL;
    
int i=0;

    MP3D_OMX_CONF_CHECK_CMD(pHandle,
1,1);
/* ......省略,初始化OMX_COMPONENTTYPE类型的指针pHandle */
    OMX_MALLOC_GENERIC(pHandle
->pComponentPrivate,MP3DEC_COMPONENT_PRIVATE);
    pComponentPrivate
= pHandle->pComponentPrivate;  /* 私有指针互相指向 */
    pComponentPrivate
->pHandle = pHandle;
/* ......略,初始化似有数据指针pComponentPrivate */
    
/* 设置输入端口(OMX_PARAM_PORTDEFINITIONTYPE类型)的默认值 */
    pPortDef_ip
->nSize                   = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
    pPortDef_ip
->nPortIndex             = MP3D_INPUT_PORT;
    pPortDef_ip
->eDir                    = OMX_DirInput;
    pPortDef_ip
->nBufferCountActual    = MP3D_NUM_INPUT_BUFFERS;
    pPortDef_ip
->nBufferCountMin        = MP3D_NUM_INPUT_BUFFERS;
    pPortDef_ip
->nBufferSize             = MP3D_INPUT_BUFFER_SIZE;
    pPortDef_ip
->nBufferAlignment       = DSP_CACHE_ALIGNMENT;
    pPortDef_ip
->bEnabled                 = OMX_TRUE;
    pPortDef_ip
->bPopulated               = OMX_FALSE;
    pPortDef_ip
->eDomain                   = OMX_PortDomainAudio;
    pPortDef_ip
->format.audio.eEncoding = OMX_AUDIO_CodingMP3;
    pPortDef_ip
->format.audio.cMIMEType = NULL;
    pPortDef_ip
->format.audio.pNativeRender           = NULL;
    pPortDef_ip
->format.audio.bFlagErrorConcealment = OMX_FALSE;
    
/* 设置输出端口(OMX_PARAM_PORTDEFINITIONTYPE类型)的默认值 */
    pPortDef_op
->nSize                 = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
    pPortDef_op
->nPortIndex           = MP3D_OUTPUT_PORT;
    pPortDef_op
->eDir                  = OMX_DirOutput;
    pPortDef_op
->nBufferCountMin     = MP3D_NUM_OUTPUT_BUFFERS;
    pPortDef_op
->nBufferCountActual  = MP3D_NUM_OUTPUT_BUFFERS;
    pPortDef_op
->nBufferSize          = MP3D_OUTPUT_BUFFER_SIZE;
    pPortDef_op
->nBufferAlignment    = DSP_CACHE_ALIGNMENT;
    pPortDef_op
->bEnabled              = OMX_TRUE;
    pPortDef_op
->bPopulated            = OMX_FALSE;
    pPortDef_op
->eDomain               = OMX_PortDomainAudio;
    pPortDef_op
->format.audio.eEncoding      = OMX_AUDIO_CodingPCM;
    pPortDef_op
->format.audio.cMIMEType      = NULL;
    pPortDef_op
->format.audio.pNativeRender = NULL;
    pPortDef_op
->format.audio.bFlagErrorConcealment = OMX_FALSE;
/* ......省略,分配端口 */
    
/* 设置输入端口的默认格式 */
    pPortFormat
= pComponentPrivate->pCompPort[MP3D_INPUT_PORT]->pPortFormat;
    OMX_CONF_INIT_STRUCT(pPortFormat, OMX_AUDIO_PARAM_PORTFORMATTYPE);
    pPortFormat
->nPortIndex         = MP3D_INPUT_PORT;
    pPortFormat
->nIndex             = OMX_IndexParamAudioMp3;
    pPortFormat
->eEncoding          = OMX_AUDIO_CodingMP3;
    
/* 设置输出端口的默认格式 */
    pPortFormat
= pComponentPrivate->pCompPort[MP3D_OUTPUT_PORT]->pPortFormat;
    OMX_CONF_INIT_STRUCT(pPortFormat, OMX_AUDIO_PARAM_PORTFORMATTYPE);
    pPortFormat
->nPortIndex         = MP3D_OUTPUT_PORT;
    pPortFormat
->nIndex             = OMX_IndexParamAudioPcm;
    pPortFormat
->eEncoding          = OMX_AUDIO_CodingPCM;
/* ......省略部分内容 */
    eError
= Mp3Dec_StartCompThread(pHandle);   // 启动MP3解码线程
/* ......省略部分内容 */
    return eError;
}

  这个组件是OpenMax的标准实现方式,对外的接口的内容只有一个初始化函数。完成OMX_COMPONENTTYPE类型的初始化。输入端口的编号为MP3D_INPUT_PORT(==0),类型为OMX_PortDomainAudio,格式为OMX_AUDIO_CodingMP3。输出端口的编号是MP3D_OUTPUT_PORT(==1),类型为OMX_PortDomainAudio,格式为OMX_AUDIO_ CodingPCM。

  OMX_Mp3Dec_CompThread.c中定义了MP3DEC_ComponentThread()函数,用于创建MP3解码的线程的执行函数。

  OMX_Mp3Dec_Utils.c中的Mp3Dec_StartCompThread()函数,调用了POSIX的线程库建立MP3解码的线程,如下所示:

  nRet = pthread_create (&(pComponentPrivate->ComponentThread), NULL,

  MP3DEC_ComponentThread, pComponentPrivate);

  Mp3Dec_StartCompThread()函数就是在组件初始化函数OMX_ComponentInit()最后调用的内容。MP3线程的开始并不表示解码过程开始,线程需要等待通过pipe机制获得命令和数据(cmdPipe和dataPipe),在适当的时候开始工作。这个pipe在MP3解码组件的SendCommand等实现写操作,在线程中读取其内容。

0
相关文章