1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions are met: |
7 | * Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | * Redistributions in binary form must reproduce the above copyright |
10 | notice, this list of conditions and the following disclaimer in the |
11 | documentation and/or other materials provided with the distribution. |
12 | * Neither the name of the copyright holder nor the |
13 | names of its contributors may be used to endorse or promote products |
14 | derived from this software without specific prior written permission. |
15 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | #include <stdio.h> |
28 | #include <stdarg.h> |
29 | |
30 | //includes |
31 | #include <memory.h> |
32 | #include <stdio.h> |
33 | #include <stdlib.h> |
34 | #include <string.h> |
35 | |
36 | #include "interface/vmcs_host/khronos/IL/OMX_Component.h" |
37 | #include "interface/vmcs_host/vcilcs.h" |
38 | #include "interface/vmcs_host/vchost.h" |
39 | #include "interface/vmcs_host/vcilcs_common.h" |
40 | |
41 | #include "host_ilcore.h" |
42 | |
43 | |
44 | #ifdef WANT_OMX_NAME_MANGLE |
45 | #define OMX_Deinit host_OMX_Deinit |
46 | #define OMX_Init host_OMX_Init |
47 | #define OMX_SetupTunnel host_OMX_SetupTunnel |
48 | #define OMX_FreeHandle host_OMX_FreeHandle |
49 | #define OMX_GetHandle host_OMX_GetHandle |
50 | #define OMX_GetRolesOfComponent host_OMX_GetRolesOfComponent |
51 | #define OMX_GetComponentsOfRole host_OMX_GetComponentsOfRole |
52 | #define OMX_ComponentNameEnum host_OMX_ComponentNameEnum |
53 | #define OMX_GetDebugInformation host_OMX_GetDebugInformation |
54 | #endif |
55 | |
56 | #ifdef WANT_LOCAL_OMX |
57 | // xxx: we need to link to local OpenMAX IL core as well |
58 | OMX_API OMX_ERRORTYPE OMX_APIENTRY vc_OMX_Init(void); |
59 | OMX_API OMX_ERRORTYPE OMX_APIENTRY vc_OMX_Deinit(void); |
60 | OMX_API OMX_ERRORTYPE OMX_APIENTRY vc_OMX_GetHandle( |
61 | OMX_OUT OMX_HANDLETYPE* pHandle, |
62 | OMX_IN OMX_STRING cComponentName, |
63 | OMX_IN OMX_PTR pAppData, |
64 | OMX_IN OMX_CALLBACKTYPE* pCallBacks); |
65 | OMX_API OMX_ERRORTYPE OMX_APIENTRY vc_OMX_FreeHandle( |
66 | OMX_IN OMX_HANDLETYPE hComponent); |
67 | #endif |
68 | |
69 | static int coreInit = 0; |
70 | static int nActiveHandles = 0; |
71 | static ILCS_SERVICE_T *ilcs_service = NULL; |
72 | static VCOS_MUTEX_T lock; |
73 | static VCOS_ONCE_T once = VCOS_ONCE_INIT; |
74 | |
75 | /* Atomic creation of lock protecting shared state */ |
76 | static void initOnce(void) |
77 | { |
78 | VCOS_STATUS_T status; |
79 | status = vcos_mutex_create(&lock, VCOS_FUNCTION); |
80 | vcos_demand(status == VCOS_SUCCESS); |
81 | } |
82 | |
83 | /* OMX_Init */ |
84 | OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void) |
85 | { |
86 | VCOS_STATUS_T status; |
87 | OMX_ERRORTYPE err = OMX_ErrorNone; |
88 | |
89 | status = vcos_once(&once, initOnce); |
90 | vcos_demand(status == VCOS_SUCCESS); |
91 | |
92 | vcos_mutex_lock(&lock); |
93 | |
94 | #ifdef WANT_LOCAL_OMX |
95 | vc_OMX_Init(); // initialise local core first |
96 | #endif |
97 | |
98 | if(coreInit == 0) |
99 | { |
100 | // we need to connect via an ILCS connection to VideoCore |
101 | VCHI_INSTANCE_T initialise_instance; |
102 | VCHI_CONNECTION_T *connection; |
103 | ILCS_CONFIG_T config; |
104 | |
105 | vc_host_get_vchi_state(&initialise_instance, &connection); |
106 | |
107 | vcilcs_config(&config); |
108 | #ifdef USE_VCHIQ_ARM |
109 | ilcs_service = ilcs_init((VCHIQ_INSTANCE_T) initialise_instance, (void **) &connection, &config, 0); |
110 | #else |
111 | ilcs_service = ilcs_init((VCHIQ_STATE_T *) initialise_instance, (void **) &connection, &config, 0); |
112 | #endif |
113 | |
114 | if(ilcs_service == NULL) |
115 | { |
116 | err = OMX_ErrorHardware; |
117 | goto end; |
118 | } |
119 | |
120 | coreInit = 1; |
121 | } |
122 | #ifdef USE_VCHIQ_ARM |
123 | else |
124 | coreInit++; |
125 | #endif |
126 | |
127 | end: |
128 | vcos_mutex_unlock(&lock); |
129 | return err; |
130 | } |
131 | |
132 | /* OMX_Deinit */ |
133 | OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit(void) |
134 | { |
135 | if(coreInit == 0) // || (coreInit == 1 && nActiveHandles > 0)) |
136 | return OMX_ErrorNotReady; |
137 | |
138 | vcos_mutex_lock(&lock); |
139 | |
140 | #ifdef USE_VCHIQ_ARM |
141 | coreInit--; |
142 | #endif |
143 | |
144 | if(coreInit == 0) |
145 | { |
146 | // we need to teardown the ILCS connection to VideoCore |
147 | ilcs_deinit(ilcs_service); |
148 | ilcs_service = NULL; |
149 | } |
150 | |
151 | #ifdef WANT_LOCAL_OMX |
152 | vc_OMX_Deinit(); // deinitialise local core as well |
153 | #endif |
154 | |
155 | vcos_mutex_unlock(&lock); |
156 | |
157 | return OMX_ErrorNone; |
158 | } |
159 | |
160 | |
161 | /* OMX_ComponentNameEnum */ |
162 | OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum( |
163 | OMX_OUT OMX_STRING cComponentName, |
164 | OMX_IN OMX_U32 nNameLength, |
165 | OMX_IN OMX_U32 nIndex) |
166 | { |
167 | if(ilcs_service == NULL) |
168 | return OMX_ErrorBadParameter; |
169 | |
170 | return vcil_out_component_name_enum(ilcs_get_common(ilcs_service), cComponentName, nNameLength, nIndex); |
171 | } |
172 | |
173 | |
174 | /* OMX_GetHandle */ |
175 | OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle( |
176 | OMX_OUT OMX_HANDLETYPE* pHandle, |
177 | OMX_IN OMX_STRING cComponentName, |
178 | OMX_IN OMX_PTR pAppData, |
179 | OMX_IN OMX_CALLBACKTYPE* pCallBacks) |
180 | { |
181 | OMX_ERRORTYPE eError; |
182 | OMX_COMPONENTTYPE *pComp; |
183 | OMX_HANDLETYPE hHandle = 0; |
184 | |
185 | if (pHandle == NULL || cComponentName == NULL || pCallBacks == NULL || ilcs_service == NULL) |
186 | { |
187 | if(pHandle) |
188 | *pHandle = NULL; |
189 | return OMX_ErrorBadParameter; |
190 | } |
191 | |
192 | #if defined(WANT_LOCAL_OMX) && 0 |
193 | if ((eError = vc_OMX_GetHandle(pHandle, cComponentName, pAppData, pCallBacks)) != OMX_ErrorNone) |
194 | #endif |
195 | { |
196 | pComp = (OMX_COMPONENTTYPE *)malloc(sizeof(OMX_COMPONENTTYPE)); |
197 | if (!pComp) |
198 | { |
199 | vcos_assert(0); |
200 | return OMX_ErrorInsufficientResources; |
201 | } |
202 | memset(pComp, 0, sizeof(OMX_COMPONENTTYPE)); |
203 | hHandle = (OMX_HANDLETYPE)pComp; |
204 | pComp->nSize = sizeof(OMX_COMPONENTTYPE); |
205 | pComp->nVersion.nVersion = OMX_VERSION; |
206 | eError = vcil_out_create_component(ilcs_get_common(ilcs_service), hHandle, cComponentName); |
207 | |
208 | if (eError == OMX_ErrorNone) { |
209 | // Check that all function pointers have been filled in. |
210 | // All fields should be non-zero. |
211 | int i; |
212 | uint32_t *p = (uint32_t *) pComp; |
213 | for(i=0; i<sizeof(OMX_COMPONENTTYPE)>>2; i++) |
214 | if(*p++ == 0) |
215 | eError = OMX_ErrorInvalidComponent; |
216 | |
217 | if(eError != OMX_ErrorNone && pComp->ComponentDeInit) |
218 | pComp->ComponentDeInit(hHandle); |
219 | } |
220 | |
221 | if (eError == OMX_ErrorNone) { |
222 | eError = pComp->SetCallbacks(hHandle,pCallBacks,pAppData); |
223 | if (eError != OMX_ErrorNone) |
224 | pComp->ComponentDeInit(hHandle); |
225 | } |
226 | if (eError == OMX_ErrorNone) { |
227 | *pHandle = hHandle; |
228 | } |
229 | else { |
230 | *pHandle = NULL; |
231 | free(pComp); |
232 | } |
233 | } |
234 | |
235 | if (eError == OMX_ErrorNone) { |
236 | vcos_mutex_lock(&lock); |
237 | nActiveHandles++; |
238 | vcos_mutex_unlock(&lock); |
239 | } |
240 | |
241 | return eError; |
242 | } |
243 | |
244 | /* OMX_FreeHandle */ |
245 | OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle( |
246 | OMX_IN OMX_HANDLETYPE hComponent) |
247 | { |
248 | OMX_ERRORTYPE eError = OMX_ErrorNone; |
249 | OMX_COMPONENTTYPE *pComp; |
250 | |
251 | if (hComponent == NULL || ilcs_service == NULL) |
252 | return OMX_ErrorBadParameter; |
253 | |
254 | pComp = (OMX_COMPONENTTYPE*)hComponent; |
255 | |
256 | #ifdef WANT_LOCAL_OMX |
257 | // xxx: a bit of a bodge, we rely on knowing that |
258 | // the local core doesn't make use of this field but |
259 | // ILCS does... |
260 | if (pComp->pApplicationPrivate == NULL) |
261 | return vc_OMX_FreeHandle(hComponent); |
262 | #endif |
263 | |
264 | if (ilcs_service == NULL) |
265 | return OMX_ErrorBadParameter; |
266 | |
267 | eError = (pComp->ComponentDeInit)(hComponent); |
268 | if (eError == OMX_ErrorNone) { |
269 | vcos_mutex_lock(&lock); |
270 | --nActiveHandles; |
271 | vcos_mutex_unlock(&lock); |
272 | free(pComp); |
273 | } |
274 | |
275 | vcos_assert(nActiveHandles >= 0); |
276 | |
277 | return eError; |
278 | } |
279 | |
280 | /* OMX_SetupTunnel */ |
281 | OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel( |
282 | OMX_IN OMX_HANDLETYPE hOutput, |
283 | OMX_IN OMX_U32 nPortOutput, |
284 | OMX_IN OMX_HANDLETYPE hInput, |
285 | OMX_IN OMX_U32 nPortInput) |
286 | { |
287 | OMX_ERRORTYPE eError = OMX_ErrorNone; |
288 | OMX_COMPONENTTYPE *pCompIn, *pCompOut; |
289 | OMX_TUNNELSETUPTYPE oTunnelSetup; |
290 | |
291 | if ((hOutput == NULL && hInput == NULL) || ilcs_service == NULL) |
292 | return OMX_ErrorBadParameter; |
293 | |
294 | oTunnelSetup.nTunnelFlags = 0; |
295 | oTunnelSetup.eSupplier = OMX_BufferSupplyUnspecified; |
296 | |
297 | pCompOut = (OMX_COMPONENTTYPE*)hOutput; |
298 | |
299 | if (hOutput){ |
300 | eError = pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, hInput, nPortInput, &oTunnelSetup); |
301 | } |
302 | |
303 | if (eError == OMX_ErrorNone && hInput) { |
304 | pCompIn = (OMX_COMPONENTTYPE*)hInput; |
305 | eError = pCompIn->ComponentTunnelRequest(hInput, nPortInput, hOutput, nPortOutput, &oTunnelSetup); |
306 | |
307 | if (eError != OMX_ErrorNone && hOutput) { |
308 | /* cancel tunnel request on output port since input port failed */ |
309 | pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, NULL, 0, NULL); |
310 | } |
311 | } |
312 | return eError; |
313 | } |
314 | |
315 | /* OMX_GetComponentsOfRole */ |
316 | OMX_ERRORTYPE OMX_GetComponentsOfRole ( |
317 | OMX_IN OMX_STRING role, |
318 | OMX_INOUT OMX_U32 *pNumComps, |
319 | OMX_INOUT OMX_U8 **compNames) |
320 | { |
321 | OMX_ERRORTYPE eError = OMX_ErrorNone; |
322 | |
323 | *pNumComps = 0; |
324 | return eError; |
325 | } |
326 | |
327 | /* OMX_GetRolesOfComponent */ |
328 | OMX_ERRORTYPE OMX_GetRolesOfComponent ( |
329 | OMX_IN OMX_STRING compName, |
330 | OMX_INOUT OMX_U32 *pNumRoles, |
331 | OMX_OUT OMX_U8 **roles) |
332 | { |
333 | OMX_ERRORTYPE eError = OMX_ErrorNone; |
334 | |
335 | *pNumRoles = 0; |
336 | return eError; |
337 | } |
338 | |
339 | /* OMX_GetDebugInformation */ |
340 | OMX_ERRORTYPE OMX_GetDebugInformation ( |
341 | OMX_OUT OMX_STRING debugInfo, |
342 | OMX_INOUT OMX_S32 *pLen) |
343 | { |
344 | if(ilcs_service == NULL) |
345 | return OMX_ErrorBadParameter; |
346 | |
347 | return vcil_out_get_debug_information(ilcs_get_common(ilcs_service), debugInfo, pLen); |
348 | } |
349 | |
350 | |
351 | |
352 | /* File EOF */ |
353 | |
354 | |