/* ==================================================================== * Texas Instruments OMAP(TM) Platform Software * (c) Copyright Texas Instruments, Incorporated. All Rights Reserved. * * Use of this software is controlled by the terms and conditions found * in the license agreement under which this software has been supplied. * ==================================================================== */ #include <dlfcn.h> /* For dynamic loading */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <pthread.h> #include <utils/Log.h> #undef LOG_TAG #define LOG_TAG "TIOMX_CORE" #include "OMX_Component.h" #include "OMX_Core.h" #include "OMX_ComponentRegistry.h" #ifndef NO_OPENCORE /** determine capabilities of a component before acually using it */ #include "ti_omx_config_parser.h" #endif /** size for the array of allocated components. Sets the maximum * number of components that can be allocated at once */ #define MAXCOMP (50) #define MAXNAMESIZE (130) #define EMPTY_STRING "\0" /** Determine the number of elements in an array */ #define COUNTOF(x) (sizeof(x)/sizeof(x[0])) /** Array to hold the DLL pointers for each allocated component */ static void* pModules[MAXCOMP] = {0}; /** Array to hold the component handles for each allocated component */ static void* pComponents[COUNTOF(pModules)] = {0}; /** count will be used as a reference counter for OMX_Init() so all changes to count should be mutex protected */ int count = 0; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int tableCount = 0; ComponentTable componentTable[MAX_TABLE_SIZE]; char * sRoleArray[60][20]; char compName[60][200]; char *tComponentName[MAXCOMP][2] = { /*video and image components */ //{"OMX.TI.JPEG.decoder", "image_decoder.jpeg" }, {"OMX.TI.JPEG.Encoder", "image_encoder.jpeg"}, //{"OMX.TI.Video.Decoder", "video_decoder.h263"}, {"OMX.TI.Video.Decoder", "video_decoder.avc"}, //{"OMX.TI.Video.Decoder", "video_decoder.mpeg2"}, {"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"}, //{"OMX.TI.VPP", "iv_renderer.yuv.overlay"}, //{"OMX.TI.Camera", "camera.yuv"}, /* Speech components */ /* {"OMX.TI.G729.encode", NULL}, {"OMX.TI.G729.decode", NULL}, {"OMX.TI.G722.encode", NULL}, {"OMX.TI.G722.decode", NULL}, {"OMX.TI.G711.encode", NULL}, {"OMX.TI.G711.decode", NULL}, {"OMX.TI.G723.encode", NULL}, {"OMX.TI.G723.decode", NULL}, {"OMX.TI.G726.encode", NULL}, {"OMX.TI.G726.decode", NULL}, {"OMX.TI.GSMFR.encode", NULL}, {"OMX.TI.GSMFR.decode", NULL}, */ /* Audio components */ #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 /* {"OMX.TI.PCM.encode", NULL}, {"OMX.TI.PCM.decode", NULL}, {"OMX.TI.RAG.decode", "audio_decoder.ra"}, {"OMX.TI.IMAADPCM.decode", NULL}, {"OMX.TI.IMAADPCM.encode", NULL}, */ /* terminate the table */ {NULL, NULL}, }; /******************************Public*Routine******************************\ * OMX_Init() * * Description:This method will initialize the OMX Core. It is the * responsibility of the application to call OMX_Init to ensure the proper * set up of core resources. * * Returns: OMX_NOERROR Successful * * Note * \**************************************************************************/ OMX_ERRORTYPE TIOMX_Init() { OMX_ERRORTYPE eError = OMX_ErrorNone; if(pthread_mutex_lock(&mutex) != 0) { LOGE("%d :: Core: Error in Mutex lock\n",__LINE__); return OMX_ErrorUndefined; } count++; LOGD("init count = %d\n", count); if (count == 1) { eError = TIOMX_BuildComponentTable(); } if(pthread_mutex_unlock(&mutex) != 0) { LOGE("%d :: Core: Error in Mutex unlock\n",__LINE__); return OMX_ErrorUndefined; } return eError; } /******************************Public*Routine******************************\ * OMX_GetHandle * * Description: This method will create the handle of the COMPONENTTYPE * If the component is currently loaded, this method will reutrn the * hadle of existingcomponent or create a new instance of the component. * It will call the OMX_ComponentInit function and then the setcallback * method to initialize the callback functions * Parameters: * @param[out] pHandle Handle of the loaded components * @param[in] cComponentName Name of the component to load * @param[in] pAppData Used to identify the callbacks of component * @param[in] pCallBacks Application callbacks * * @retval OMX_ErrorUndefined * @retval OMX_ErrorInvalidComponentName * @retval OMX_ErrorInvalidComponent * @retval OMX_ErrorInsufficientResources * @retval OMX_NOERROR Successful * * Note * \**************************************************************************/ 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(); if(pthread_mutex_lock(&mutex) != 0) { LOGE("%d :: Core: Error in Mutex lock\n",__LINE__); return OMX_ErrorUndefined; } if ((NULL == cComponentName) || (NULL == pHandle) || (NULL == pCallBacks)) { err = OMX_ErrorBadParameter; goto UNLOCK_MUTEX; } /* Verify that the name is not too long and could cause a crash. Notice * that the comparison is a greater than or equals. This is to make * sure that there is room for the terminating NULL at the end of the * name. */ if(strlen(cComponentName) >= MAXNAMESIZE) { err = OMX_ErrorInvalidComponentName; goto UNLOCK_MUTEX; } /* Locate the first empty slot for a component. If no slots * are available, error out */ int i = 0; for(i=0; i< COUNTOF(pModules); i++) { if(pModules[i] == NULL) break; } if(i == COUNTOF(pModules)) { err = OMX_ErrorInsufficientResources; goto UNLOCK_MUTEX; } int refIndex = 0; for (refIndex=0; refIndex < MAX_TABLE_SIZE; refIndex++) { //get the index for the component in the table if (strcmp(componentTable[refIndex].name, cComponentName) == 0) { LOGD("Found component %s with refCount %d\n", cComponentName, componentTable[refIndex].refCount); /* check if the component is already loaded */ if (componentTable[refIndex].refCount >= MAX_CONCURRENT_INSTANCES) { err = OMX_ErrorInsufficientResources; LOGE("Max instances of component %s already created.\n", cComponentName); goto UNLOCK_MUTEX; } else { // we have not reached the limit yet /* do what was done before need to limit concurrent instances of each component */ /* load the component and check for an error. If filename is not an * absolute path (i.e., it does not begin with a "/"), then the * file is searched for in the following locations: * * The LD_LIBRARY_PATH environment variable locations * The library cache, /etc/ld.so.cache. * /lib * /usr/lib * * If there is an error, we can't go on, so set the error code and exit */ /* the lengths are defined herein or have been * checked already, so strcpy and strcat are * are safe to use in this context. */ char buf[sizeof(prefix) + MAXNAMESIZE + sizeof(postfix)]; strcpy(buf, prefix); strcat(buf, cComponentName); strcat(buf, postfix); pModules[i] = dlopen(buf, RTLD_LAZY | RTLD_GLOBAL); if( pModules[i] == NULL ) { LOGE("dlopen %s failed because %s\n", buf, dlerror()); err = OMX_ErrorComponentNotFound; goto UNLOCK_MUTEX; } /* Get a function pointer to the "OMX_ComponentInit" function. If * there is an error, we can't go on, so set the error code and exit */ pComponentInit = dlsym(pModules[i], "OMX_ComponentInit"); pErr = dlerror(); if( (pErr != NULL) || (pComponentInit == NULL) ) { LOGE("%d:: dlsym failed for module %p\n", __LINE__, pModules[i]); err = OMX_ErrorInvalidComponent; goto CLEAN_UP; } /* We now can access the dll. So, we need to call the "OMX_ComponentInit" * method to load up the "handle" (which is just a list of functions to * call) and we should be all set.*/ *pHandle = malloc(sizeof(OMX_COMPONENTTYPE)); if(*pHandle == NULL) { err = OMX_ErrorInsufficientResources; LOGE("%d:: malloc of pHandle* failed\n", __LINE__); goto CLEAN_UP; } pComponents[i] = *pHandle; componentType = (OMX_COMPONENTTYPE*) *pHandle; componentType->nSize = sizeof(OMX_COMPONENTTYPE); err = (*pComponentInit)(*pHandle); if (OMX_ErrorNone == err) { err = (componentType->SetCallbacks)(*pHandle, pCallBacks, pAppData); if (err != OMX_ErrorNone) { LOGE("%d :: Core: SetCallBack failed %d\n",__LINE__, err); goto CLEAN_UP; } /* finally, OMX_ComponentInit() was successful and SetCallbacks was successful, we have a valid instance, so no we increment refCount */ componentTable[refIndex].pHandle[componentTable[refIndex].refCount] = *pHandle; componentTable[refIndex].refCount += 1; goto UNLOCK_MUTEX; // Component is found, and thus we are done } else if (err == OMX_ErrorInsufficientResources) { LOGE("%d :: Core: Insufficient Resources for Component %d\n",__LINE__, err); goto CLEAN_UP; } } } } // If we are here, we have not found the component err = OMX_ErrorComponentNotFound; goto UNLOCK_MUTEX; CLEAN_UP: if(*pHandle != NULL) /* cover the case where we error out before malloc'd */ { free(*pHandle); *pHandle = NULL; } pComponents[i] = NULL; dlclose(pModules[i]); pModules[i] = NULL; UNLOCK_MUTEX: if(pthread_mutex_unlock(&mutex) != 0) { LOGE("%d :: Core: Error in Mutex unlock\n",__LINE__); err = OMX_ErrorUndefined; } return (err); } /******************************Public*Routine******************************\ * OMX_FreeHandle() * * Description:This method will unload the OMX component pointed by * OMX_HANDLETYPE. It is the responsibility of the calling method to ensure that * the Deinit method of the component has been called prior to unloading component * * Parameters: * @param[in] hComponent the component to unload * * Returns: OMX_NOERROR Successful * * Note * \**************************************************************************/ OMX_ERRORTYPE TIOMX_FreeHandle (OMX_HANDLETYPE hComponent) { OMX_ERRORTYPE retVal = OMX_ErrorUndefined; OMX_COMPONENTTYPE *pHandle = (OMX_COMPONENTTYPE *)hComponent; if(pthread_mutex_lock(&mutex) != 0) { LOGE("%d :: Core: Error in Mutex lock\n",__LINE__); return OMX_ErrorUndefined; } /* Locate the component handle in the array of handles */ int i = 0; for(i=0; i< COUNTOF(pModules); i++) { if(pComponents[i] == hComponent) break; } if(i == COUNTOF(pModules)) { LOGE("%d :: Core: component %p is not found\n", __LINE__, hComponent); retVal = OMX_ErrorBadParameter; goto EXIT; } retVal = pHandle->ComponentDeInit(hComponent); if (retVal != OMX_ErrorNone) { LOGE("%d :: ComponentDeInit failed %d\n",__LINE__, retVal); goto EXIT; } int refIndex = 0, handleIndex = 0; for (refIndex=0; refIndex < MAX_TABLE_SIZE; refIndex++) { for (handleIndex=0; handleIndex < componentTable[refIndex].refCount; handleIndex++){ /* get the position for the component in the table */ if (componentTable[refIndex].pHandle[handleIndex] == hComponent){ LOGD("Found matching pHandle(%p) at index %d with refCount %d", hComponent, refIndex, componentTable[refIndex].refCount); if (componentTable[refIndex].refCount) { componentTable[refIndex].refCount -= 1; } componentTable[refIndex].pHandle[handleIndex] = NULL; dlclose(pModules[i]); pModules[i] = NULL; free(pComponents[i]); pComponents[i] = NULL; retVal = OMX_ErrorNone; goto EXIT; } } } // If we are here, we have not found the matching component retVal = OMX_ErrorComponentNotFound; EXIT: /* The unload is now complete, so set the error code to pass and exit */ if(pthread_mutex_unlock(&mutex) != 0) { LOGE("%d :: Core: Error in Mutex unlock\n",__LINE__); return OMX_ErrorUndefined; } return retVal; } /******************************Public*Routine******************************\ * OMX_DeInit() * * Description:This method will release the resources of the OMX Core. It is the * responsibility of the application to call OMX_DeInit to ensure the clean up of these * resources. * * Returns: OMX_NOERROR Successful * * Note * \**************************************************************************/ OMX_ERRORTYPE TIOMX_Deinit() { if(pthread_mutex_lock(&mutex) != 0) { LOGE("%d :: Core: Error in Mutex lock\n",__LINE__); return OMX_ErrorUndefined; } if (count) { count--; } LOGD("deinit count = %d\n", count); if(pthread_mutex_unlock(&mutex) != 0) { LOGE("%d :: Core: Error in Mutex unlock\n",__LINE__); return OMX_ErrorUndefined; } return OMX_ErrorNone; } /************************************************************************* * OMX_SetupTunnel() * * Description: Setup the specified tunnel the two components * * Parameters: * @param[in] hOutput Handle of the component to be accessed * @param[in] nPortOutput Source port used in the tunnel * @param[in] hInput Component to setup the tunnel with. * @param[in] nPortInput Destination port used in the tunnel * * Returns: OMX_NOERROR Successful * * Note * **************************************************************************/ /* OMX_SetupTunnel */ OMX_API OMX_ERRORTYPE OMX_APIENTRY TIOMX_SetupTunnel( OMX_IN OMX_HANDLETYPE hOutput, OMX_IN OMX_U32 nPortOutput, OMX_IN OMX_HANDLETYPE hInput, OMX_IN OMX_U32 nPortInput) { OMX_ERRORTYPE eError = OMX_ErrorNotImplemented; OMX_COMPONENTTYPE *pCompIn, *pCompOut; OMX_TUNNELSETUPTYPE oTunnelSetup; if (hOutput == NULL && hInput == NULL) return OMX_ErrorBadParameter; oTunnelSetup.nTunnelFlags = 0; oTunnelSetup.eSupplier = OMX_BufferSupplyUnspecified; pCompOut = (OMX_COMPONENTTYPE*)hOutput; if (hOutput) { eError = pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, hInput, nPortInput, &oTunnelSetup); } if (eError == OMX_ErrorNone && hInput) { pCompIn = (OMX_COMPONENTTYPE*)hInput; eError = pCompIn->ComponentTunnelRequest(hInput, nPortInput, hOutput, nPortOutput, &oTunnelSetup); if (eError != OMX_ErrorNone && hOutput) { /* cancel tunnel request on output port since input port failed */ pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, NULL, 0, NULL); } } return eError; } /************************************************************************* * OMX_ComponentNameEnum() * * Description: This method will provide the name of the component at the given nIndex * *Parameters: * @param[out] cComponentName The name of the component at nIndex * @param[in] nNameLength The length of the component name * @param[in] nIndex The index number of the component * * Returns: OMX_NOERROR Successful * * Note * **************************************************************************/ OMX_API OMX_ERRORTYPE OMX_APIENTRY TIOMX_ComponentNameEnum( OMX_OUT OMX_STRING cComponentName, OMX_IN OMX_U32 nNameLength, OMX_IN OMX_U32 nIndex) { OMX_ERRORTYPE eError = OMX_ErrorNone; if (nIndex >= tableCount) { eError = OMX_ErrorNoMore; } else { strcpy(cComponentName, componentTable[nIndex].name); } return eError; } /************************************************************************* * OMX_GetRolesOfComponent() * * Description: This method will query the component for its supported roles * *Parameters: * @param[in] cComponentName The name of the component to query * @param[in] pNumRoles The number of roles supported by the component * @param[in] roles The roles of the component * * Returns: OMX_NOERROR Successful * OMX_ErrorBadParameter Faliure due to a bad input parameter * * Note * **************************************************************************/ OMX_API OMX_ERRORTYPE TIOMX_GetRolesOfComponent ( OMX_IN OMX_STRING cComponentName, OMX_INOUT OMX_U32 *pNumRoles, OMX_OUT OMX_U8 **roles) { OMX_ERRORTYPE eError = OMX_ErrorNone; OMX_U32 i = 0; OMX_U32 j = 0; OMX_BOOL bFound = OMX_FALSE; if (cComponentName == NULL || pNumRoles == NULL) { if (cComponentName == NULL) { LOGE("cComponentName is NULL\n"); } if (pNumRoles == NULL) { LOGE("pNumRoles is NULL\n"); } eError = OMX_ErrorBadParameter; goto EXIT; } while (i < tableCount) { if (strcmp(cComponentName, componentTable[i].name) == 0) { bFound = OMX_TRUE; break; } i++; } if (!bFound) { eError = OMX_ErrorComponentNotFound; LOGE("component %s not found\n", cComponentName); goto EXIT; } if (roles == NULL) { *pNumRoles = componentTable[i].nRoles; } else { /* must be second of two calls, pNumRoles is input in this context. If pNumRoles is < actual number of roles than we return an error */ if (*pNumRoles >= componentTable[i].nRoles) { for (j = 0; j<componentTable[i].nRoles; j++) { strcpy((OMX_STRING)roles[j], componentTable[i].pRoleArray[j]); } *pNumRoles = componentTable[i].nRoles; } else { eError = OMX_ErrorBadParameter; LOGE("pNumRoles (%d) is less than actual number (%d) of roles \ for this component %s\n", *pNumRoles, componentTable[i].nRoles, cComponentName); } } EXIT: return eError; } /************************************************************************* * OMX_GetComponentsOfRole() * * Description: This method will query the component for its supported roles * *Parameters: * @param[in] role The role name to query for * @param[in] pNumComps The number of components supporting the given role * @param[in] compNames The names of the components supporting the given role * * Returns: OMX_NOERROR Successful * * Note * **************************************************************************/ OMX_API OMX_ERRORTYPE TIOMX_GetComponentsOfRole ( OMX_IN OMX_STRING role, OMX_INOUT OMX_U32 *pNumComps, OMX_INOUT OMX_U8 **compNames) { OMX_ERRORTYPE eError = OMX_ErrorNone; OMX_U32 i = 0; OMX_U32 j = 0; OMX_U32 k = 0; OMX_U32 compOfRoleCount = 0; if (role == NULL || pNumComps == NULL) { if (role == NULL) { LOGE("role is NULL"); } if (pNumComps == NULL) { LOGE("pNumComps is NULL\n"); } eError = OMX_ErrorBadParameter; goto EXIT; } /* This implies that the componentTable is not filled */ if (!tableCount) { eError = OMX_ErrorUndefined; LOGE("Component table is empty. Please reload OMX Core\n"); goto EXIT; } /* no matter, we always want to know number of matching components so this will always run */ for (i = 0; i < tableCount; i++) { for (j = 0; j < componentTable[i].nRoles; j++) { if (strcmp(componentTable[i].pRoleArray[j], role) == 0) { /* the first call to this function should only count the number of roles */ compOfRoleCount++; } } } if (compOfRoleCount == 0) { eError = OMX_ErrorComponentNotFound; LOGE("Component supporting role %s was not found\n", role); } if (compNames == NULL) { /* must be the first of two calls */ *pNumComps = compOfRoleCount; } else { /* must be the second of two calls */ if (*pNumComps < compOfRoleCount) { /* pNumComps is input in this context, it can not be less, this would indicate the array is not large enough */ eError = OMX_ErrorBadParameter; LOGE("pNumComps (%d) is less than the actual number (%d) of components \ supporting role %s\n", *pNumComps, compOfRoleCount, role); } else { k = 0; for (i = 0; i < tableCount; i++) { for (j = 0; j < componentTable[i].nRoles; j++) { if (strcmp(componentTable[i].pRoleArray[j], role) == 0) { /* the second call compNames can be allocated with the proper size for that number of roles. */ compNames[k] = (OMX_U8*)componentTable[i].name; k++; if (k == compOfRoleCount) { /* there are no more components of this role so we can exit here */ *pNumComps = k; goto EXIT; } } } } } } EXIT: return eError; } OMX_ERRORTYPE TIOMX_BuildComponentTable() { OMX_ERRORTYPE eError = OMX_ErrorNone; OMX_CALLBACKTYPE sCallbacks; int j = 0; int numFiles = 0; int i; for (i = 0, numFiles = 0; i < MAXCOMP; i ++) { if (tComponentName[i][0] == NULL) { break; } if (numFiles <= MAX_TABLE_SIZE){ for (j = 0; j < numFiles; j ++) { if (!strcmp(componentTable[j].name, tComponentName[i][0])) { /* insert the role */ if (tComponentName[i][1] != NULL) { componentTable[j].pRoleArray[componentTable[j].nRoles] = tComponentName[i][1]; componentTable[j].pHandle[componentTable[j].nRoles] = NULL; //initilize the pHandle element componentTable[j].nRoles ++; } break; } } if (j == numFiles) { /* new component */ if (tComponentName[i][1] != NULL){ componentTable[numFiles].pRoleArray[0] = tComponentName[i][1]; componentTable[numFiles].nRoles = 1; } strcpy(compName[numFiles], tComponentName[i][0]); componentTable[numFiles].name = compName[numFiles]; componentTable[numFiles].refCount = 0; //initialize reference counter. numFiles ++; } } } tableCount = numFiles; if (eError != OMX_ErrorNone){ LOGE("Could not build Component Table\n"); } return eError; } OMX_BOOL TIOMXConfigParserRedirect( OMX_PTR aInputParameters, OMX_PTR aOutputParameters) { OMX_BOOL Status = OMX_FALSE; #ifndef NO_OPENCORE Status = TIOMXConfigParser(aInputParameters, aOutputParameters); #endif return Status; }