1/*Copyright (c) 2012-2014, 2016, The Linux Foundation. All rights reserved.
2
3Redistribution and use in source and binary forms, with or without
4modification, are permitted provided that the following conditions are
5met:
6    * Redistributions of source code must retain the above copyright
7      notice, this list of conditions and the following disclaimer.
8    * Redistributions in binary form must reproduce the above
9      copyright notice, this list of conditions and the following
10      disclaimer in the documentation and/or other materials provided
11      with the distribution.
12    * Neither the name of The Linux Foundation nor the names of its
13      contributors may be used to endorse or promote products derived
14      from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*/
27
28#define LOG_NDEBUG 0
29#define LOG_NIDEBUG 0
30#define LOG_TAG "qomx_image_core"
31
32// System dependencies
33#include <dlfcn.h>
34#include <malloc.h>
35#include <string.h>
36#include <utils/Log.h>
37
38// OpenMAX dependencies
39#include "qomx_core.h"
40
41#define BUFF_SIZE 255
42
43static omx_core_t *g_omxcore;
44static pthread_mutex_t g_omxcore_lock = PTHREAD_MUTEX_INITIALIZER;
45static int g_omxcore_cnt = 0;
46
47//Map the library name with the component name
48static const comp_info_t g_comp_info[] =
49{
50  { "OMX.qcom.image.jpeg.encoder", "libqomx_jpegenc.so" },
51  { "OMX.qcom.image.jpeg.decoder", "libqomx_jpegdec.so" },
52  { "OMX.qcom.image.jpeg.encoder_pipeline", "libqomx_jpegenc_pipe.so" }
53};
54
55static int get_idx_from_handle(OMX_IN OMX_HANDLETYPE *ahComp, int *acompIndex,
56  int *ainstanceIndex);
57
58/*==============================================================================
59* Function : OMX_Init
60* Parameters: None
61* Description: This is the first call that is made to the OMX Core
62* and initializes the OMX IL core
63==============================================================================*/
64OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Init()
65{
66  OMX_ERRORTYPE rc = OMX_ErrorNone;
67  int i = 0;
68  int comp_cnt = sizeof(g_comp_info)/sizeof(g_comp_info[0]);
69
70  pthread_mutex_lock(&g_omxcore_lock);
71
72  /* check if core is created */
73  if (g_omxcore) {
74    g_omxcore_cnt++;
75    pthread_mutex_unlock(&g_omxcore_lock);
76    return rc;
77  }
78
79  if (comp_cnt > OMX_COMP_MAX_NUM) {
80    ALOGE("%s:%d] cannot exceed max number of components",
81      __func__, __LINE__);
82    pthread_mutex_unlock(&g_omxcore_lock);
83    return OMX_ErrorUndefined;
84  }
85  /* create new global object */
86  g_omxcore = malloc(sizeof(omx_core_t));
87  if (g_omxcore) {
88    memset(g_omxcore, 0x0, sizeof(omx_core_t));
89
90    /* populate the library name and component name */
91    for (i = 0; i < comp_cnt; i++) {
92      g_omxcore->component[i].comp_name = g_comp_info[i].comp_name;
93      g_omxcore->component[i].lib_name = g_comp_info[i].lib_name;
94    }
95    g_omxcore->comp_cnt = comp_cnt;
96    g_omxcore_cnt++;
97  } else {
98    rc = OMX_ErrorInsufficientResources;
99  }
100  pthread_mutex_unlock(&g_omxcore_lock);
101  ALOGI("%s:%d] Complete %d", __func__, __LINE__, comp_cnt);
102  return rc;
103}
104
105/*==============================================================================
106* Function : OMX_Deinit
107* Parameters: None
108* Return Value : OMX_ERRORTYPE
109* Description: Deinit all the OMX components
110==============================================================================*/
111OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit()
112{
113  pthread_mutex_lock(&g_omxcore_lock);
114
115  if (g_omxcore_cnt == 1) {
116    if (g_omxcore) {
117      free(g_omxcore);
118      g_omxcore = NULL;
119    }
120  }
121  if (g_omxcore_cnt) {
122    g_omxcore_cnt--;
123  }
124
125  ALOGI("%s:%d] Complete", __func__, __LINE__);
126  pthread_mutex_unlock(&g_omxcore_lock);
127  return OMX_ErrorNone;
128}
129
130/*==============================================================================
131* Function : get_comp_from_list
132* Parameters: componentName
133* Return Value : component_index
134* Description: If the componnt is already present in the list, return the
135* component index. If not return the next index to create the component.
136==============================================================================*/
137static int get_comp_from_list(char *comp_name)
138{
139  int index = -1, i = 0;
140
141  if (NULL == comp_name)
142    return -1;
143
144  for (i = 0; i < g_omxcore->comp_cnt; i++) {
145    if (!strcmp(g_omxcore->component[i].comp_name, comp_name)) {
146      index = i;
147      break;
148    }
149  }
150  return index;
151}
152
153/*==============================================================================
154* Function : get_free_inst_idx
155* Parameters: p_comp
156* Return Value : The next instance index if available
157* Description: Get the next available index for to store the new instance of the
158*            component being created.
159*============================================================================*/
160static int get_free_inst_idx(omx_core_component_t *p_comp)
161{
162  int idx = -1, i = 0;
163
164  for (i = 0; i < OMX_COMP_MAX_INSTANCES; i++) {
165    if (NULL == p_comp->handle[i]) {
166      idx = i;
167      break;
168    }
169  }
170  return idx;
171}
172
173/*==============================================================================
174* Function : OMX_GetHandle
175* Parameters: handle, componentName, appData, callbacks
176* Return Value : OMX_ERRORTYPE
177* Description: Construct and load the requested omx library
178==============================================================================*/
179OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(
180  OMX_OUT OMX_HANDLETYPE* handle,
181  OMX_IN OMX_STRING componentName,
182  OMX_IN OMX_PTR appData,
183  OMX_IN OMX_CALLBACKTYPE* callBacks)
184{
185  OMX_ERRORTYPE rc = OMX_ErrorNone;
186  int comp_idx = 0, inst_idx = 0;
187  char libName[BUFF_SIZE] = {0};
188  void *p_obj = NULL;
189  OMX_COMPONENTTYPE *p_comp = NULL;
190  omx_core_component_t *p_core_comp = NULL;
191  OMX_BOOL close_handle = OMX_FALSE;
192
193  if (NULL == handle) {
194    ALOGE("%s:%d] Error invalid input ", __func__, __LINE__);
195    return OMX_ErrorBadParameter;
196  }
197
198  pthread_mutex_lock(&g_omxcore_lock);
199
200  comp_idx = get_comp_from_list(componentName);
201  if (comp_idx < 0) {
202    ALOGE("%s:%d] Cannot find the component", __func__, __LINE__);
203    pthread_mutex_unlock(&g_omxcore_lock);
204    return OMX_ErrorInvalidComponent;
205  }
206  p_core_comp = &g_omxcore->component[comp_idx];
207
208  *handle = NULL;
209
210  //If component already present get the instance index
211  inst_idx = get_free_inst_idx(p_core_comp);
212  if (inst_idx < 0) {
213    ALOGE("%s:%d] Cannot alloc new instance", __func__, __LINE__);
214    rc = OMX_ErrorInvalidComponent;
215    goto error;
216  }
217
218  if (FALSE == p_core_comp->open) {
219    /* load the library */
220    p_core_comp->lib_handle = dlopen(p_core_comp->lib_name, RTLD_NOW);
221    if (NULL == p_core_comp->lib_handle) {
222      ALOGE("%s:%d] Cannot load the library", __func__, __LINE__);
223      rc = OMX_ErrorInvalidComponent;
224      goto error;
225    }
226
227    p_core_comp->open = TRUE;
228    /* Init the component and get component functions */
229    p_core_comp->create_comp_func = dlsym(p_core_comp->lib_handle,
230      "create_component_fns");
231    p_core_comp->get_instance = dlsym(p_core_comp->lib_handle, "getInstance");
232
233    close_handle = OMX_TRUE;
234    if (!p_core_comp->create_comp_func || !p_core_comp->get_instance) {
235      ALOGE("%s:%d] Cannot maps the symbols", __func__, __LINE__);
236      rc = OMX_ErrorInvalidComponent;
237      goto error;
238    }
239  }
240
241  /* Call the function from the address to create the obj */
242  p_obj = (*p_core_comp->get_instance)();
243  ALOGI("%s:%d] get instance pts is %p", __func__, __LINE__, p_obj);
244  if (NULL == p_obj) {
245    ALOGE("%s:%d] Error cannot create object", __func__, __LINE__);
246    rc = OMX_ErrorInvalidComponent;
247    goto error;
248  }
249
250  /* Call the function from the address to get the func ptrs */
251  p_comp = (*p_core_comp->create_comp_func)(p_obj);
252  if (NULL == p_comp) {
253    ALOGE("%s:%d] Error cannot create component", __func__, __LINE__);
254    rc = OMX_ErrorInvalidComponent;
255    goto error;
256  }
257
258  *handle = p_core_comp->handle[inst_idx] = (OMX_HANDLETYPE)p_comp;
259
260  ALOGD("%s:%d] handle = %p Instanceindex = %d,"
261    "comp_idx %d g_ptr %p", __func__, __LINE__,
262    p_core_comp->handle[inst_idx], inst_idx,
263    comp_idx, g_omxcore);
264
265  p_comp->SetCallbacks(p_comp, callBacks, appData);
266  pthread_mutex_unlock(&g_omxcore_lock);
267  ALOGI("%s:%d] Success", __func__, __LINE__);
268  return OMX_ErrorNone;
269
270error:
271
272  if (OMX_TRUE == close_handle) {
273    dlclose(p_core_comp->lib_handle);
274    p_core_comp->lib_handle = NULL;
275  }
276  pthread_mutex_unlock(&g_omxcore_lock);
277  ALOGE("%s:%d] Error %d", __func__, __LINE__, rc);
278  return rc;
279}
280
281/*==============================================================================
282* Function : getIndexFromComponent
283* Parameters: handle,
284* Return Value : Component present - true or false, Instance Index, Component
285* Index
286* Description: Check if the handle is present in the list and get the component
287* index and instance index for the component handle.
288==============================================================================*/
289static int get_idx_from_handle(OMX_IN OMX_HANDLETYPE *ahComp, int *aCompIdx,
290  int *aInstIdx)
291{
292  int i = 0, j = 0;
293  for (i = 0; i < g_omxcore->comp_cnt; i++) {
294    for (j = 0; j < OMX_COMP_MAX_INSTANCES; j++) {
295      if ((OMX_COMPONENTTYPE *)g_omxcore->component[i].handle[j] ==
296        (OMX_COMPONENTTYPE *)ahComp) {
297        ALOGD("%s:%d] comp_idx %d inst_idx %d", __func__, __LINE__, i, j);
298        *aCompIdx = i;
299        *aInstIdx = j;
300        return TRUE;
301      }
302    }
303  }
304  return FALSE;
305}
306
307/*==============================================================================
308* Function : is_comp_active
309* Parameters: p_core_comp
310* Return Value : int
311* Description: Check if the component has any active instances
312==============================================================================*/
313static uint8_t is_comp_active(omx_core_component_t *p_core_comp)
314{
315  uint8_t i = 0;
316  for (i = 0; i < OMX_COMP_MAX_INSTANCES; i++) {
317    if (NULL != p_core_comp->handle[i]) {
318      return TRUE;
319    }
320  }
321  return FALSE;
322}
323
324/*==============================================================================
325* Function : OMX_FreeHandle
326* Parameters: hComp
327* Return Value : OMX_ERRORTYPE
328* Description: Deinit the omx component and remove it from the global list
329==============================================================================*/
330OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle(
331  OMX_IN OMX_HANDLETYPE hComp)
332{
333  OMX_ERRORTYPE rc = OMX_ErrorNone;
334  int comp_idx, inst_idx;
335  OMX_COMPONENTTYPE *p_comp = NULL;
336  omx_core_component_t *p_core_comp = NULL;
337
338  ALOGV("%s:%d] ", __func__, __LINE__);
339  if (hComp == NULL) {
340    return OMX_ErrorBadParameter;
341  }
342
343  pthread_mutex_lock(&g_omxcore_lock);
344
345  p_comp = (OMX_COMPONENTTYPE *)hComp;
346  if (FALSE == get_idx_from_handle(hComp, &comp_idx, &inst_idx)) {
347    ALOGE("%s:%d] Error invalid component", __func__, __LINE__);
348    pthread_mutex_unlock(&g_omxcore_lock);
349    return OMX_ErrorInvalidComponent;
350  }
351
352
353  //Deinit the component;
354  rc = p_comp->ComponentDeInit(hComp);
355  if (rc != OMX_ErrorNone) {
356    /* Remove the handle from the comp structure */
357    ALOGE("%s:%d] Error comp deinit failed", __func__, __LINE__);
358    pthread_mutex_unlock(&g_omxcore_lock);
359    return OMX_ErrorInvalidComponent;
360  }
361  p_core_comp = &g_omxcore->component[comp_idx];
362  p_core_comp->handle[inst_idx] = NULL;
363  if (!is_comp_active(p_core_comp)) {
364    rc = dlclose(p_core_comp->lib_handle);
365    p_core_comp->lib_handle = NULL;
366    p_core_comp->get_instance = NULL;
367    p_core_comp->create_comp_func = NULL;
368    p_core_comp->open = FALSE;
369  } else {
370    ALOGI("%s:%d] Error Component is still Active", __func__, __LINE__);
371  }
372  pthread_mutex_unlock(&g_omxcore_lock);
373  ALOGV("%s:%d] Success", __func__, __LINE__);
374  return rc;
375}
376