1 /* ====================================================================
2 * Texas Instruments OMAP(TM) Platform Software
3 * (c) Copyright Texas Instruments, Incorporated. All Rights Reserved.
5 * Use of this software is controlled by the terms and conditions found
6 * in the license agreement under which this software has been supplied.
7 * ==================================================================== */
9 #include <dlfcn.h> /* For dynamic loading */
14 #include <utils/Log.h>
17 #define LOG_TAG "TIOMX_CORE"
19 #include "OMX_Component.h"
21 #include "OMX_ComponentRegistry.h"
24 /** determine capabilities of a component before acually using it */
25 #include "ti_omx_config_parser.h"
28 /** size for the array of allocated components. Sets the maximum
29 * number of components that can be allocated at once */
31 #define MAXNAMESIZE (130)
32 #define EMPTY_STRING "\0"
34 /** Determine the number of elements in an array */
35 #define COUNTOF(x) (sizeof(x)/sizeof(x[0]))
37 /** Array to hold the DLL pointers for each allocated component */
38 static void* pModules[MAXCOMP] = {0};
40 /** Array to hold the component handles for each allocated component */
41 static void* pComponents[COUNTOF(pModules)] = {0};
43 /** count will be used as a reference counter for OMX_Init()
44 so all changes to count should be mutex protected */
46 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
49 ComponentTable componentTable[MAX_TABLE_SIZE];
50 char * sRoleArray[60][20];
51 char compName[60][200];
53 char *tComponentName[MAXCOMP][2] = {
54 /*video and image components */
55 //{"OMX.TI.JPEG.decoder", "image_decoder.jpeg" },
56 {"OMX.TI.JPEG.Encoder", "image_encoder.jpeg"},
57 //{"OMX.TI.Video.Decoder", "video_decoder.h263"},
58 {"OMX.TI.Video.Decoder", "video_decoder.avc"},
59 //{"OMX.TI.Video.Decoder", "video_decoder.mpeg2"},
60 {"OMX.TI.Video.Decoder", "video_decoder.mpeg4"},
61 {"OMX.TI.Video.Decoder", "video_decoder.wmv"},
62 {"OMX.TI.Video.encoder", "video_encoder.mpeg4"},
63 {"OMX.TI.Video.encoder", "video_encoder.h263"},
64 {"OMX.TI.Video.encoder", "video_encoder.avc"},
65 //{"OMX.TI.VPP", "iv_renderer.yuv.overlay"},
66 //{"OMX.TI.Camera", "camera.yuv"},
68 /* Speech components */
69 /* {"OMX.TI.G729.encode", NULL},
70 {"OMX.TI.G729.decode", NULL},
71 {"OMX.TI.G722.encode", NULL},
72 {"OMX.TI.G722.decode", NULL},
73 {"OMX.TI.G711.encode", NULL},
74 {"OMX.TI.G711.decode", NULL},
75 {"OMX.TI.G723.encode", NULL},
76 {"OMX.TI.G723.decode", NULL},
77 {"OMX.TI.G726.encode", NULL},
78 {"OMX.TI.G726.decode", NULL},
79 {"OMX.TI.GSMFR.encode", NULL},
80 {"OMX.TI.GSMFR.decode", NULL},
83 /* Audio components */
84 #ifdef BUILD_WITH_TI_AUDIO
85 {"OMX.TI.MP3.decode", "audio_decoder.mp3"},
86 {"OMX.TI.AAC.encode", "audio_encoder.aac"},
87 {"OMX.TI.AAC.decode", "audio_decoder.aac"},
88 {"OMX.TI.WMA.decode", "audio_decoder.wma"},
89 {"OMX.TI.WBAMR.decode", "audio_decoder.amrwb"},
90 {"OMX.TI.AMR.decode", "audio_decoder.amrnb"},
91 {"OMX.TI.AMR.encode", "audio_encoder.amrnb"},
92 {"OMX.TI.WBAMR.encode", "audio_encoder.amrwb"},
94 /* {"OMX.TI.PCM.encode", NULL},
95 {"OMX.TI.PCM.decode", NULL},
96 {"OMX.TI.RAG.decode", "audio_decoder.ra"},
97 {"OMX.TI.IMAADPCM.decode", NULL},
98 {"OMX.TI.IMAADPCM.encode", NULL},
101 /* terminate the table */
106 /******************************Public*Routine******************************\
109 * Description:This method will initialize the OMX Core. It is the
110 * responsibility of the application to call OMX_Init to ensure the proper
111 * set up of core resources.
113 * Returns: OMX_NOERROR Successful
117 \**************************************************************************/
118 OMX_ERRORTYPE TIOMX_Init()
120 OMX_ERRORTYPE eError = OMX_ErrorNone;
122 if(pthread_mutex_lock(&mutex) != 0)
124 LOGE("%d :: Core: Error in Mutex lock\n",__LINE__);
125 return OMX_ErrorUndefined;
129 LOGD("init count = %d\n", count);
133 eError = TIOMX_BuildComponentTable();
136 if(pthread_mutex_unlock(&mutex) != 0)
138 LOGE("%d :: Core: Error in Mutex unlock\n",__LINE__);
139 return OMX_ErrorUndefined;
143 /******************************Public*Routine******************************\
146 * Description: This method will create the handle of the COMPONENTTYPE
147 * If the component is currently loaded, this method will reutrn the
148 * hadle of existingcomponent or create a new instance of the component.
149 * It will call the OMX_ComponentInit function and then the setcallback
150 * method to initialize the callback functions
152 * @param[out] pHandle Handle of the loaded components
153 * @param[in] cComponentName Name of the component to load
154 * @param[in] pAppData Used to identify the callbacks of component
155 * @param[in] pCallBacks Application callbacks
157 * @retval OMX_ErrorUndefined
158 * @retval OMX_ErrorInvalidComponentName
159 * @retval OMX_ErrorInvalidComponent
160 * @retval OMX_ErrorInsufficientResources
161 * @retval OMX_NOERROR Successful
165 \**************************************************************************/
167 OMX_ERRORTYPE TIOMX_GetHandle( OMX_HANDLETYPE* pHandle, OMX_STRING cComponentName,
168 OMX_PTR pAppData, OMX_CALLBACKTYPE* pCallBacks)
170 static const char prefix[] = "lib";
171 static const char postfix[] = ".so";
172 OMX_ERRORTYPE (*pComponentInit)(OMX_HANDLETYPE*);
173 OMX_ERRORTYPE err = OMX_ErrorNone;
174 OMX_COMPONENTTYPE *componentType;
175 const char* pErr = dlerror();
177 if(pthread_mutex_lock(&mutex) != 0)
179 LOGE("%d :: Core: Error in Mutex lock\n",__LINE__);
180 return OMX_ErrorUndefined;
183 if ((NULL == cComponentName) || (NULL == pHandle) || (NULL == pCallBacks)) {
184 err = OMX_ErrorBadParameter;
188 /* Verify that the name is not too long and could cause a crash. Notice
189 * that the comparison is a greater than or equals. This is to make
190 * sure that there is room for the terminating NULL at the end of the
192 if(strlen(cComponentName) >= MAXNAMESIZE) {
193 err = OMX_ErrorInvalidComponentName;
196 /* Locate the first empty slot for a component. If no slots
197 * are available, error out */
199 for(i=0; i< COUNTOF(pModules); i++) {
200 if(pModules[i] == NULL) break;
202 if(i == COUNTOF(pModules)) {
203 err = OMX_ErrorInsufficientResources;
208 for (refIndex=0; refIndex < MAX_TABLE_SIZE; refIndex++) {
209 //get the index for the component in the table
210 if (strcmp(componentTable[refIndex].name, cComponentName) == 0) {
211 LOGD("Found component %s with refCount %d\n",
212 cComponentName, componentTable[refIndex].refCount);
214 /* check if the component is already loaded */
215 if (componentTable[refIndex].refCount >= MAX_CONCURRENT_INSTANCES) {
216 err = OMX_ErrorInsufficientResources;
217 LOGE("Max instances of component %s already created.\n", cComponentName);
219 } else { // we have not reached the limit yet
220 /* do what was done before need to limit concurrent instances of each component */
222 /* load the component and check for an error. If filename is not an
223 * absolute path (i.e., it does not begin with a "/"), then the
224 * file is searched for in the following locations:
226 * The LD_LIBRARY_PATH environment variable locations
227 * The library cache, /etc/ld.so.cache.
231 * If there is an error, we can't go on, so set the error code and exit */
233 /* the lengths are defined herein or have been
234 * checked already, so strcpy and strcat are
235 * are safe to use in this context. */
236 char buf[sizeof(prefix) + MAXNAMESIZE + sizeof(postfix)];
238 strcat(buf, cComponentName);
239 strcat(buf, postfix);
241 pModules[i] = dlopen(buf, RTLD_LAZY | RTLD_GLOBAL);
242 if( pModules[i] == NULL ) {
243 LOGE("dlopen %s failed because %s\n", buf, dlerror());
244 err = OMX_ErrorComponentNotFound;
248 /* Get a function pointer to the "OMX_ComponentInit" function. If
249 * there is an error, we can't go on, so set the error code and exit */
250 pComponentInit = dlsym(pModules[i], "OMX_ComponentInit");
252 if( (pErr != NULL) || (pComponentInit == NULL) ) {
253 LOGE("%d:: dlsym failed for module %p\n", __LINE__, pModules[i]);
254 err = OMX_ErrorInvalidComponent;
258 /* We now can access the dll. So, we need to call the "OMX_ComponentInit"
259 * method to load up the "handle" (which is just a list of functions to
260 * call) and we should be all set.*/
261 *pHandle = malloc(sizeof(OMX_COMPONENTTYPE));
262 if(*pHandle == NULL) {
263 err = OMX_ErrorInsufficientResources;
264 LOGE("%d:: malloc of pHandle* failed\n", __LINE__);
268 pComponents[i] = *pHandle;
269 componentType = (OMX_COMPONENTTYPE*) *pHandle;
270 componentType->nSize = sizeof(OMX_COMPONENTTYPE);
271 err = (*pComponentInit)(*pHandle);
272 if (OMX_ErrorNone == err) {
273 err = (componentType->SetCallbacks)(*pHandle, pCallBacks, pAppData);
274 if (err != OMX_ErrorNone) {
275 LOGE("%d :: Core: SetCallBack failed %d\n",__LINE__, err);
278 /* finally, OMX_ComponentInit() was successful and
279 SetCallbacks was successful, we have a valid instance,
280 so no we increment refCount */
281 componentTable[refIndex].pHandle[componentTable[refIndex].refCount] = *pHandle;
282 componentTable[refIndex].refCount += 1;
283 goto UNLOCK_MUTEX; // Component is found, and thus we are done
285 else if (err == OMX_ErrorInsufficientResources) {
286 LOGE("%d :: Core: Insufficient Resources for Component %d\n",__LINE__, err);
293 // If we are here, we have not found the component
294 err = OMX_ErrorComponentNotFound;
298 /* cover the case where we error out before malloc'd */
303 pComponents[i] = NULL;
304 dlclose(pModules[i]);
308 if(pthread_mutex_unlock(&mutex) != 0)
310 LOGE("%d :: Core: Error in Mutex unlock\n",__LINE__);
311 err = OMX_ErrorUndefined;
317 /******************************Public*Routine******************************\
320 * Description:This method will unload the OMX component pointed by
321 * OMX_HANDLETYPE. It is the responsibility of the calling method to ensure that
322 * the Deinit method of the component has been called prior to unloading component
325 * @param[in] hComponent the component to unload
327 * Returns: OMX_NOERROR Successful
331 \**************************************************************************/
332 OMX_ERRORTYPE TIOMX_FreeHandle (OMX_HANDLETYPE hComponent)
335 OMX_ERRORTYPE retVal = OMX_ErrorUndefined;
336 OMX_COMPONENTTYPE *pHandle = (OMX_COMPONENTTYPE *)hComponent;
338 if(pthread_mutex_lock(&mutex) != 0)
340 LOGE("%d :: Core: Error in Mutex lock\n",__LINE__);
341 return OMX_ErrorUndefined;
344 /* Locate the component handle in the array of handles */
346 for(i=0; i< COUNTOF(pModules); i++) {
347 if(pComponents[i] == hComponent) break;
350 if(i == COUNTOF(pModules)) {
351 LOGE("%d :: Core: component %p is not found\n", __LINE__, hComponent);
352 retVal = OMX_ErrorBadParameter;
356 retVal = pHandle->ComponentDeInit(hComponent);
357 if (retVal != OMX_ErrorNone) {
358 LOGE("%d :: ComponentDeInit failed %d\n",__LINE__, retVal);
362 int refIndex = 0, handleIndex = 0;
363 for (refIndex=0; refIndex < MAX_TABLE_SIZE; refIndex++) {
364 for (handleIndex=0; handleIndex < componentTable[refIndex].refCount; handleIndex++){
365 /* get the position for the component in the table */
366 if (componentTable[refIndex].pHandle[handleIndex] == hComponent){
367 LOGD("Found matching pHandle(%p) at index %d with refCount %d",
368 hComponent, refIndex, componentTable[refIndex].refCount);
369 if (componentTable[refIndex].refCount) {
370 componentTable[refIndex].refCount -= 1;
372 componentTable[refIndex].pHandle[handleIndex] = NULL;
373 dlclose(pModules[i]);
375 free(pComponents[i]);
376 pComponents[i] = NULL;
377 retVal = OMX_ErrorNone;
383 // If we are here, we have not found the matching component
384 retVal = OMX_ErrorComponentNotFound;
387 /* The unload is now complete, so set the error code to pass and exit */
388 if(pthread_mutex_unlock(&mutex) != 0)
390 LOGE("%d :: Core: Error in Mutex unlock\n",__LINE__);
391 return OMX_ErrorUndefined;
397 /******************************Public*Routine******************************\
400 * Description:This method will release the resources of the OMX Core. It is the
401 * responsibility of the application to call OMX_DeInit to ensure the clean up of these
404 * Returns: OMX_NOERROR Successful
408 \**************************************************************************/
409 OMX_ERRORTYPE TIOMX_Deinit()
411 if(pthread_mutex_lock(&mutex) != 0) {
412 LOGE("%d :: Core: Error in Mutex lock\n",__LINE__);
413 return OMX_ErrorUndefined;
420 LOGD("deinit count = %d\n", count);
422 if(pthread_mutex_unlock(&mutex) != 0) {
423 LOGE("%d :: Core: Error in Mutex unlock\n",__LINE__);
424 return OMX_ErrorUndefined;
427 return OMX_ErrorNone;
430 /*************************************************************************
433 * Description: Setup the specified tunnel the two components
436 * @param[in] hOutput Handle of the component to be accessed
437 * @param[in] nPortOutput Source port used in the tunnel
438 * @param[in] hInput Component to setup the tunnel with.
439 * @param[in] nPortInput Destination port used in the tunnel
441 * Returns: OMX_NOERROR Successful
445 **************************************************************************/
446 /* OMX_SetupTunnel */
447 OMX_API OMX_ERRORTYPE OMX_APIENTRY TIOMX_SetupTunnel(
448 OMX_IN OMX_HANDLETYPE hOutput,
449 OMX_IN OMX_U32 nPortOutput,
450 OMX_IN OMX_HANDLETYPE hInput,
451 OMX_IN OMX_U32 nPortInput)
453 OMX_ERRORTYPE eError = OMX_ErrorNotImplemented;
454 OMX_COMPONENTTYPE *pCompIn, *pCompOut;
455 OMX_TUNNELSETUPTYPE oTunnelSetup;
457 if (hOutput == NULL && hInput == NULL)
458 return OMX_ErrorBadParameter;
460 oTunnelSetup.nTunnelFlags = 0;
461 oTunnelSetup.eSupplier = OMX_BufferSupplyUnspecified;
463 pCompOut = (OMX_COMPONENTTYPE*)hOutput;
467 eError = pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, hInput, nPortInput, &oTunnelSetup);
471 if (eError == OMX_ErrorNone && hInput)
473 pCompIn = (OMX_COMPONENTTYPE*)hInput;
474 eError = pCompIn->ComponentTunnelRequest(hInput, nPortInput, hOutput, nPortOutput, &oTunnelSetup);
475 if (eError != OMX_ErrorNone && hOutput)
477 /* cancel tunnel request on output port since input port failed */
478 pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, NULL, 0, NULL);
485 /*************************************************************************
486 * OMX_ComponentNameEnum()
488 * Description: This method will provide the name of the component at the given nIndex
491 * @param[out] cComponentName The name of the component at nIndex
492 * @param[in] nNameLength The length of the component name
493 * @param[in] nIndex The index number of the component
495 * Returns: OMX_NOERROR Successful
499 **************************************************************************/
500 OMX_API OMX_ERRORTYPE OMX_APIENTRY TIOMX_ComponentNameEnum(
501 OMX_OUT OMX_STRING cComponentName,
502 OMX_IN OMX_U32 nNameLength,
503 OMX_IN OMX_U32 nIndex)
505 OMX_ERRORTYPE eError = OMX_ErrorNone;
507 if (nIndex >= tableCount)
509 eError = OMX_ErrorNoMore;
513 strcpy(cComponentName, componentTable[nIndex].name);
520 /*************************************************************************
521 * OMX_GetRolesOfComponent()
523 * Description: This method will query the component for its supported roles
526 * @param[in] cComponentName The name of the component to query
527 * @param[in] pNumRoles The number of roles supported by the component
528 * @param[in] roles The roles of the component
530 * Returns: OMX_NOERROR Successful
531 * OMX_ErrorBadParameter Faliure due to a bad input parameter
535 **************************************************************************/
536 OMX_API OMX_ERRORTYPE TIOMX_GetRolesOfComponent (
537 OMX_IN OMX_STRING cComponentName,
538 OMX_INOUT OMX_U32 *pNumRoles,
539 OMX_OUT OMX_U8 **roles)
542 OMX_ERRORTYPE eError = OMX_ErrorNone;
545 OMX_BOOL bFound = OMX_FALSE;
547 if (cComponentName == NULL || pNumRoles == NULL)
549 if (cComponentName == NULL)
551 LOGE("cComponentName is NULL\n");
553 if (pNumRoles == NULL)
555 LOGE("pNumRoles is NULL\n");
557 eError = OMX_ErrorBadParameter;
560 while (i < tableCount)
562 if (strcmp(cComponentName, componentTable[i].name) == 0)
\r
571 eError = OMX_ErrorComponentNotFound;
572 LOGE("component %s not found\n", cComponentName);
577 *pNumRoles = componentTable[i].nRoles;
581 /* must be second of two calls,
582 pNumRoles is input in this context.
583 If pNumRoles is < actual number of roles
584 than we return an error */
585 if (*pNumRoles >= componentTable[i].nRoles)
587 for (j = 0; j<componentTable[i].nRoles; j++)
589 strcpy((OMX_STRING)roles[j], componentTable[i].pRoleArray[j]);
591 *pNumRoles = componentTable[i].nRoles;
595 eError = OMX_ErrorBadParameter;
596 LOGE("pNumRoles (%d) is less than actual number (%d) of roles \
597 for this component %s\n", *pNumRoles, componentTable[i].nRoles, cComponentName);
604 /*************************************************************************
605 * OMX_GetComponentsOfRole()
607 * Description: This method will query the component for its supported roles
610 * @param[in] role The role name to query for
611 * @param[in] pNumComps The number of components supporting the given role
612 * @param[in] compNames The names of the components supporting the given role
614 * Returns: OMX_NOERROR Successful
618 **************************************************************************/
619 OMX_API OMX_ERRORTYPE TIOMX_GetComponentsOfRole (
620 OMX_IN OMX_STRING role,
621 OMX_INOUT OMX_U32 *pNumComps,
622 OMX_INOUT OMX_U8 **compNames)
624 OMX_ERRORTYPE eError = OMX_ErrorNone;
628 OMX_U32 compOfRoleCount = 0;
630 if (role == NULL || pNumComps == NULL)
634 LOGE("role is NULL");
636 if (pNumComps == NULL)
638 LOGE("pNumComps is NULL\n");
640 eError = OMX_ErrorBadParameter;
644 /* This implies that the componentTable is not filled */
647 eError = OMX_ErrorUndefined;
648 LOGE("Component table is empty. Please reload OMX Core\n");
652 /* no matter, we always want to know number of matching components
653 so this will always run */
654 for (i = 0; i < tableCount; i++)
656 for (j = 0; j < componentTable[i].nRoles; j++)
658 if (strcmp(componentTable[i].pRoleArray[j], role) == 0)
660 /* the first call to this function should only count the number
667 if (compOfRoleCount == 0)
669 eError = OMX_ErrorComponentNotFound;
670 LOGE("Component supporting role %s was not found\n", role);
672 if (compNames == NULL)
674 /* must be the first of two calls */
675 *pNumComps = compOfRoleCount;
679 /* must be the second of two calls */
680 if (*pNumComps < compOfRoleCount)
682 /* pNumComps is input in this context,
683 it can not be less, this would indicate
684 the array is not large enough
686 eError = OMX_ErrorBadParameter;
687 LOGE("pNumComps (%d) is less than the actual number (%d) of components \
688 supporting role %s\n", *pNumComps, compOfRoleCount, role);
693 for (i = 0; i < tableCount; i++)
695 for (j = 0; j < componentTable[i].nRoles; j++)
697 if (strcmp(componentTable[i].pRoleArray[j], role) == 0)
699 /* the second call compNames can be allocated
700 with the proper size for that number of roles.
702 compNames[k] = (OMX_U8*)componentTable[i].name;
704 if (k == compOfRoleCount)
706 /* there are no more components of this role
707 so we can exit here */
722 OMX_ERRORTYPE TIOMX_BuildComponentTable()
724 OMX_ERRORTYPE eError = OMX_ErrorNone;
725 OMX_CALLBACKTYPE sCallbacks;
730 for (i = 0, numFiles = 0; i < MAXCOMP; i ++) {
731 if (tComponentName[i][0] == NULL) {
734 if (numFiles <= MAX_TABLE_SIZE){
735 for (j = 0; j < numFiles; j ++) {
736 if (!strcmp(componentTable[j].name, tComponentName[i][0])) {
737 /* insert the role */
738 if (tComponentName[i][1] != NULL)
740 componentTable[j].pRoleArray[componentTable[j].nRoles] = tComponentName[i][1];
741 componentTable[j].pHandle[componentTable[j].nRoles] = NULL; //initilize the pHandle element
742 componentTable[j].nRoles ++;
747 if (j == numFiles) { /* new component */
748 if (tComponentName[i][1] != NULL){
749 componentTable[numFiles].pRoleArray[0] = tComponentName[i][1];
750 componentTable[numFiles].nRoles = 1;
752 strcpy(compName[numFiles], tComponentName[i][0]);
753 componentTable[numFiles].name = compName[numFiles];
754 componentTable[numFiles].refCount = 0; //initialize reference counter.
759 tableCount = numFiles;
760 if (eError != OMX_ErrorNone){
761 LOGE("Could not build Component Table\n");
767 OMX_BOOL TIOMXConfigParserRedirect(
768 OMX_PTR aInputParameters,
769 OMX_PTR aOutputParameters)
772 OMX_BOOL Status = OMX_FALSE;
774 Status = TIOMXConfigParser(aInputParameters, aOutputParameters);