omxil: Activate mpeg2 on broadcom omx.
[vlc.git] / modules / codec / omxil / omxil_core.c
1 /*****************************************************************************
2  * omxil.c: Video decoder module making use of OpenMAX IL components.
3  *****************************************************************************
4  * Copyright (C) 2010 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <dlfcn.h>
32 #if defined(USE_IOMX)
33 /* On dll_open, just check that the OMX_Init symbol already is loaded */
34 # define dll_open(name) dlsym(RTLD_DEFAULT, "OMX_Init")
35 # define dll_close(handle) do { } while (0)
36 # define dlsym(handle, name) dlsym(RTLD_DEFAULT, "I" name)
37 #else
38 # define dll_open(name) dlopen( name, RTLD_NOW )
39 # define dll_close(handle) dlclose(handle)
40 #endif
41
42 #include <vlc_common.h>
43 #include <vlc_plugin.h>
44 #include <vlc_codec.h>
45 #include <vlc_block_helper.h>
46 #include <vlc_cpu.h>
47
48 #include "omxil.h"
49 #include "omxil_core.h"
50
51 /*****************************************************************************
52  * List of OpenMAX IL core we will try in order
53  *****************************************************************************/
54 static const char *ppsz_dll_list[] =
55 {
56 #if defined(USE_IOMX)
57     "libiomx.so", /* Not used when using IOMX, the lib should already be loaded */
58 #elif defined(RPI_OMX)
59     "/opt/vc/lib/libopenmaxil.so",  /* Broadcom IL core */
60 #else
61     "libOMX_Core.so", /* TI OMAP IL core */
62     "libOmxCore.so", /* Qualcomm IL core */
63     "libomxil-bellagio.so",  /* Bellagio IL core */
64     "libnvomx.so", /* Tegra3 IL core */
65 #endif
66     0
67 };
68
69 #ifdef RPI_OMX
70 static const char *ppsz_extra_dll_list[] =
71 {
72     "/opt/vc/lib/libbcm_host.so",  /* Broadcom host library */
73     0
74 };
75 #endif
76
77 /*****************************************************************************
78  * Global OMX Core instance, shared between module instances
79  *****************************************************************************/
80 static vlc_mutex_t omx_core_mutex = VLC_STATIC_MUTEX;
81 static unsigned int omx_refcount = 0;
82 static void *dll_handle;
83 OMX_ERRORTYPE (*pf_init) (void);
84 OMX_ERRORTYPE (*pf_deinit) (void);
85 OMX_ERRORTYPE (*pf_get_handle) (OMX_HANDLETYPE *, OMX_STRING,
86                                 OMX_PTR, OMX_CALLBACKTYPE *);
87 OMX_ERRORTYPE (*pf_free_handle) (OMX_HANDLETYPE);
88 OMX_ERRORTYPE (*pf_component_enum)(OMX_STRING, OMX_U32, OMX_U32);
89 OMX_ERRORTYPE (*pf_get_roles_of_component)(OMX_STRING, OMX_U32 *, OMX_U8 **);
90
91 #ifdef RPI_OMX
92 static void *extra_dll_handle;
93 static void (*pf_host_init)(void);
94 static void (*pf_host_deinit)(void);
95
96 static void CloseExtraDll()
97 {
98     if (pf_host_deinit)
99         pf_host_deinit();
100     // Intentionally not unloading the host library, since it cannot be
101     // unloaded cleanly after it has been initialized.
102 }
103 #else
104 #define CloseExtraDll()
105 #endif
106
107 int InitOmxCore(vlc_object_t *p_this)
108 {
109     int i;
110     vlc_mutex_lock( &omx_core_mutex );
111     if( omx_refcount > 0 ) {
112         omx_refcount++;
113         vlc_mutex_unlock( &omx_core_mutex );
114         return VLC_SUCCESS;
115     }
116
117 #ifdef RPI_OMX
118     /* Load an extra library first, if available */
119     extra_dll_handle = NULL;
120     for( i = 0; ppsz_extra_dll_list[i]; i++ )
121     {
122         extra_dll_handle = dll_open( ppsz_extra_dll_list[i] );
123         if( extra_dll_handle ) break;
124     }
125     if( extra_dll_handle )
126     {
127         pf_host_init = dlsym( extra_dll_handle, "bcm_host_init" );
128         pf_host_deinit = dlsym( extra_dll_handle, "bcm_host_deinit" );
129         if (pf_host_init)
130             pf_host_init();
131     }
132 #endif
133
134     /* Load the OMX core */
135     for( i = 0; ppsz_dll_list[i]; i++ )
136     {
137         dll_handle = dll_open( ppsz_dll_list[i] );
138         if( dll_handle ) break;
139     }
140     if( !dll_handle )
141     {
142         CloseExtraDll();
143         vlc_mutex_unlock( &omx_core_mutex );
144         return VLC_EGENERIC;
145     }
146
147     pf_init = dlsym( dll_handle, "OMX_Init" );
148     pf_deinit = dlsym( dll_handle, "OMX_Deinit" );
149     pf_get_handle = dlsym( dll_handle, "OMX_GetHandle" );
150     pf_free_handle = dlsym( dll_handle, "OMX_FreeHandle" );
151     pf_component_enum = dlsym( dll_handle, "OMX_ComponentNameEnum" );
152     pf_get_roles_of_component = dlsym( dll_handle, "OMX_GetRolesOfComponent" );
153     if( !pf_init || !pf_deinit || !pf_get_handle || !pf_free_handle ||
154         !pf_component_enum || !pf_get_roles_of_component )
155     {
156         msg_Warn( p_this, "cannot find OMX_* symbols in `%s' (%s)",
157                   ppsz_dll_list[i], dlerror() );
158         dll_close(dll_handle);
159         CloseExtraDll();
160         vlc_mutex_unlock( &omx_core_mutex );
161         return VLC_EGENERIC;
162     }
163
164     /* Initialise the OMX core */
165     OMX_ERRORTYPE omx_error = pf_init();
166     if(omx_error != OMX_ErrorNone)
167     {
168         msg_Warn( p_this, "OMX_Init failed (%x: %s)", omx_error,
169                   ErrorToString(omx_error) );
170         dll_close(dll_handle);
171         CloseExtraDll();
172         vlc_mutex_unlock( &omx_core_mutex );
173         return VLC_EGENERIC;
174     }
175     omx_refcount++;
176     vlc_mutex_unlock( &omx_core_mutex );
177     return VLC_SUCCESS;
178 }
179
180 void DeinitOmxCore(void)
181 {
182     vlc_mutex_lock( &omx_core_mutex );
183     omx_refcount--;
184     if( omx_refcount == 0 )
185     {
186         pf_deinit();
187         dll_close( dll_handle );
188         CloseExtraDll();
189     }
190     vlc_mutex_unlock( &omx_core_mutex );
191 }
192
193 /*****************************************************************************
194  * CreateComponentsList: creates a list of components matching the given role
195  *****************************************************************************/
196
197 static const struct
198 {
199     const char *psz_role;
200     const char *psz_name;
201 } role_mappings[] =
202 {
203 #ifdef RPI_OMX
204     { "video_decoder.avc", "OMX.broadcom.video_decode" },
205     { "video_decoder.mpeg2", "OMX.broadcom.video_decode" },
206     { "iv_renderer", "OMX.broadcom.video_render" },
207 #endif
208     { 0, 0 }
209 };
210
211 int CreateComponentsList(vlc_object_t *p_this, const char *psz_role,
212                          char ppsz_components[MAX_COMPONENTS_LIST_SIZE][OMX_MAX_STRINGNAME_SIZE])
213 {
214     char psz_name[OMX_MAX_STRINGNAME_SIZE];
215     OMX_ERRORTYPE omx_error;
216     OMX_U32 roles = 0;
217     OMX_U8 **ppsz_roles = 0;
218     unsigned int i, j, components = 0;
219
220     if(!psz_role) goto end;
221
222     for( i = 0; ; i++ )
223     {
224         bool b_found = false;
225
226         omx_error = pf_component_enum(psz_name, OMX_MAX_STRINGNAME_SIZE, i);
227         if(omx_error != OMX_ErrorNone) break;
228
229         msg_Dbg(p_this, "component %s", psz_name);
230
231         for( unsigned int j = 0; role_mappings[j].psz_role; j++ ) {
232             if( !strcmp( psz_role, role_mappings[j].psz_role ) &&
233                 !strcmp( psz_name, role_mappings[j].psz_name ) ) {
234                 goto found;
235             }
236         }
237
238         omx_error = pf_get_roles_of_component(psz_name, &roles, 0);
239         if(omx_error != OMX_ErrorNone || !roles) continue;
240
241         ppsz_roles = malloc(roles * (sizeof(OMX_U8*) + OMX_MAX_STRINGNAME_SIZE));
242         if(!ppsz_roles) continue;
243
244         for( j = 0; j < roles; j++ )
245             ppsz_roles[j] = ((OMX_U8 *)(&ppsz_roles[roles])) +
246                 j * OMX_MAX_STRINGNAME_SIZE;
247
248         omx_error = pf_get_roles_of_component(psz_name, &roles, ppsz_roles);
249         if(omx_error != OMX_ErrorNone) roles = 0;
250
251         for(j = 0; j < roles; j++)
252         {
253             msg_Dbg(p_this, "  - role: %s", ppsz_roles[j]);
254             if(!strcmp((char *)ppsz_roles[j], psz_role)) b_found = true;
255         }
256
257         free(ppsz_roles);
258
259         if(!b_found) continue;
260
261 found:
262         if(components >= MAX_COMPONENTS_LIST_SIZE)
263         {
264             msg_Dbg(p_this, "too many matching components");
265             continue;
266         }
267
268         strncpy(ppsz_components[components], psz_name,
269                 OMX_MAX_STRINGNAME_SIZE-1);
270         components++;
271     }
272
273  end:
274     msg_Dbg(p_this, "found %i matching components for role %s",
275             components, psz_role);
276     for( i = 0; i < components; i++ )
277         msg_Dbg(p_this, "- %s", ppsz_components[i]);
278
279     return components;
280 }
281