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 | |
28 | #include <string.h> |
29 | #include <stdio.h> |
30 | #include <stdlib.h> |
31 | #include <stdarg.h> |
32 | #include <ctype.h> |
33 | |
34 | #include "interface/vchi/vchi.h" |
35 | #include "interface/vcos/vcos_dlfcn.h" |
36 | #include "interface/vmcs_host/khronos/IL/OMX_Component.h" |
37 | #include "interface/vmcs_host/khronos/IL/OMX_ILCS.h" |
38 | #include "interface/vmcs_host/vc_ilcs_defs.h" |
39 | #include "interface/vmcs_host/vcilcs.h" |
40 | #include "interface/vmcs_host/vcilcs_common.h" |
41 | #include "interface/vcos/vcos_dlfcn.h" |
42 | |
43 | static VC_PRIVATE_PORT_T *find_port(VC_PRIVATE_COMPONENT_T *comp, OMX_U32 nPortIndex) |
44 | { |
45 | OMX_U32 i=0; |
46 | while (i<comp->numPorts && comp->port[i].port != nPortIndex) |
47 | i++; |
48 | |
49 | if (i < comp->numPorts) |
50 | return &comp->port[i]; |
51 | |
52 | return NULL; |
53 | } |
54 | |
55 | #ifndef NDEBUG |
56 | static int is_valid_hostside_buffer(OMX_BUFFERHEADERTYPE *pBuf) |
57 | { |
58 | if (!pBuf) |
59 | return 0; |
60 | if (!pBuf->pBuffer) |
61 | return 0; |
62 | if ((unsigned long)pBuf->pBuffer < 0x100) |
63 | return 0; // not believable |
64 | return 1; |
65 | } |
66 | #endif |
67 | |
68 | static OMX_ERRORTYPE vcil_out_ComponentDeInit(OMX_IN OMX_HANDLETYPE hComponent) |
69 | { |
70 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
71 | VC_PRIVATE_COMPONENT_T *comp; |
72 | IL_EXECUTE_HEADER_T exe; |
73 | IL_RESPONSE_HEADER_T resp; |
74 | ILCS_COMMON_T *st; |
75 | int rlen = sizeof(resp); |
76 | |
77 | if(!pComp) |
78 | return OMX_ErrorBadParameter; |
79 | |
80 | st = pComp->pApplicationPrivate; |
81 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
82 | |
83 | exe.reference = comp->reference; |
84 | |
85 | if(ilcs_execute_function(st->ilcs, IL_COMPONENT_DEINIT, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp) || |
86 | resp.err == OMX_ErrorNone) |
87 | { |
88 | // remove from list, assuming that we successfully managed to deinit |
89 | // this component, or that ilcs has returned an error. The assumption |
90 | // here is that if the component has managed to correctly signal an |
91 | // error, it still exists, but if the transport has failed then we might |
92 | // as well try and cleanup |
93 | VC_PRIVATE_COMPONENT_T *list, *prev; |
94 | |
95 | vcos_semaphore_wait(&st->component_lock); |
96 | |
97 | list = st->component_list; |
98 | prev = NULL; |
99 | |
100 | while (list != NULL && list != comp) |
101 | { |
102 | prev = list; |
103 | list = list->next; |
104 | } |
105 | |
106 | // failing to find this component is not a good sign. |
107 | if(vcos_verify(list)) |
108 | { |
109 | if (prev == NULL) |
110 | st->component_list = list->next; |
111 | else |
112 | prev->next = list->next; |
113 | } |
114 | |
115 | vcos_semaphore_post(&st->component_lock); |
116 | vcos_free(comp); |
117 | } |
118 | |
119 | return resp.err; |
120 | } |
121 | |
122 | static OMX_ERRORTYPE vcil_out_GetComponentVersion(OMX_IN OMX_HANDLETYPE hComponent, |
123 | OMX_OUT OMX_STRING pComponentName, |
124 | OMX_OUT OMX_VERSIONTYPE* pComponentVersion, |
125 | OMX_OUT OMX_VERSIONTYPE* pSpecVersion, |
126 | OMX_OUT OMX_UUIDTYPE* pComponentUUID) |
127 | { |
128 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
129 | VC_PRIVATE_COMPONENT_T *comp; |
130 | IL_EXECUTE_HEADER_T exe; |
131 | IL_GET_VERSION_RESPONSE_T resp; |
132 | ILCS_COMMON_T *st; |
133 | int rlen = sizeof(resp); |
134 | |
135 | if (!(pComp && pComponentName && pComponentVersion && pSpecVersion && pComponentUUID)) |
136 | return OMX_ErrorBadParameter; |
137 | |
138 | st = pComp->pApplicationPrivate; |
139 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
140 | |
141 | exe.reference = comp->reference; |
142 | |
143 | if(ilcs_execute_function(st->ilcs, IL_GET_COMPONENT_VERSION, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
144 | return OMX_ErrorHardware; |
145 | |
146 | strncpy(pComponentName, resp.name, 128); |
147 | pComponentName[127] = 0; |
148 | *pComponentVersion = resp.component_version; |
149 | *pSpecVersion = resp.spec_version; |
150 | memcpy(pComponentUUID, resp.uuid, sizeof(OMX_UUIDTYPE)); |
151 | |
152 | return resp.err; |
153 | } |
154 | |
155 | static OMX_ERRORTYPE vcil_out_SetCallbacks(OMX_IN OMX_HANDLETYPE hComponent, |
156 | OMX_IN OMX_CALLBACKTYPE* pCallbacks, |
157 | OMX_IN OMX_PTR pAppData) |
158 | { |
159 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
160 | VC_PRIVATE_COMPONENT_T *comp; |
161 | IL_SET_CALLBACKS_EXECUTE_T exe; |
162 | IL_RESPONSE_HEADER_T resp; |
163 | ILCS_COMMON_T *st; |
164 | int rlen = sizeof(resp); |
165 | |
166 | if(!(pComp && pCallbacks)) |
167 | return OMX_ErrorBadParameter; |
168 | |
169 | st = pComp->pApplicationPrivate; |
170 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
171 | |
172 | comp->callbacks = *pCallbacks; |
173 | comp->callback_state = pAppData; |
174 | |
175 | exe.reference = comp->reference; |
176 | exe.pAppData = pComp; |
177 | |
178 | if(ilcs_execute_function(st->ilcs, IL_SET_CALLBACKS, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
179 | return OMX_ErrorHardware; |
180 | |
181 | return resp.err; |
182 | } |
183 | |
184 | static OMX_ERRORTYPE vcil_out_GetState(OMX_IN OMX_HANDLETYPE hComponent, |
185 | OMX_OUT OMX_STATETYPE* pState) |
186 | { |
187 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
188 | VC_PRIVATE_COMPONENT_T *comp; |
189 | IL_EXECUTE_HEADER_T exe; |
190 | IL_GET_STATE_RESPONSE_T resp; |
191 | ILCS_COMMON_T *st; |
192 | int rlen = sizeof(resp); |
193 | |
194 | if (!(pComp && pState)) |
195 | return OMX_ErrorBadParameter; |
196 | |
197 | st = pComp->pApplicationPrivate; |
198 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
199 | |
200 | exe.reference = comp->reference; |
201 | |
202 | if(ilcs_execute_function(st->ilcs, IL_GET_STATE, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
203 | return OMX_ErrorHardware; |
204 | |
205 | *pState = resp.state; |
206 | |
207 | return resp.err; |
208 | } |
209 | |
210 | static OMX_ERRORTYPE vcil_out_get(OMX_IN OMX_HANDLETYPE hComponent, |
211 | OMX_IN OMX_INDEXTYPE nParamIndex, |
212 | OMX_INOUT OMX_PTR pComponentParameterStructure, |
213 | IL_FUNCTION_T func) |
214 | { |
215 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
216 | VC_PRIVATE_COMPONENT_T *comp; |
217 | IL_GET_EXECUTE_T exe; |
218 | IL_GET_RESPONSE_T resp; |
219 | OMX_U32 size; |
220 | ILCS_COMMON_T *st; |
221 | int rlen = sizeof(resp); |
222 | |
223 | if (!(pComp && pComponentParameterStructure)) |
224 | return OMX_ErrorBadParameter; |
225 | |
226 | st = pComp->pApplicationPrivate; |
227 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
228 | |
229 | exe.reference = comp->reference; |
230 | exe.index = nParamIndex; |
231 | |
232 | size = *((OMX_U32 *) pComponentParameterStructure); |
233 | |
234 | if(size > VC_ILCS_MAX_PARAM_SIZE) |
235 | return OMX_ErrorHardware; |
236 | |
237 | memcpy(exe.param, pComponentParameterStructure, size); |
238 | |
239 | if(ilcs_execute_function(st->ilcs, func, &exe, size + IL_GET_EXECUTE_HEADER_SIZE, &resp, &rlen) < 0 || rlen > sizeof(resp)) |
240 | return OMX_ErrorHardware; |
241 | |
242 | memcpy(pComponentParameterStructure, resp.param, size); |
243 | |
244 | return resp.err; |
245 | } |
246 | |
247 | static OMX_ERRORTYPE vcil_out_set(OMX_IN OMX_HANDLETYPE hComponent, |
248 | OMX_IN OMX_INDEXTYPE nParamIndex, |
249 | OMX_IN OMX_PTR pComponentParameterStructure, |
250 | IL_FUNCTION_T func) |
251 | { |
252 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
253 | VC_PRIVATE_COMPONENT_T *comp; |
254 | IL_SET_EXECUTE_T exe; |
255 | IL_RESPONSE_HEADER_T resp; |
256 | OMX_U32 size; |
257 | ILCS_COMMON_T *st; |
258 | int rlen = sizeof(resp); |
259 | |
260 | if (!(pComp && pComponentParameterStructure)) |
261 | return OMX_ErrorBadParameter; |
262 | |
263 | st = pComp->pApplicationPrivate; |
264 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
265 | |
266 | exe.reference = comp->reference; |
267 | exe.index = nParamIndex; |
268 | |
269 | size = *((OMX_U32 *) pComponentParameterStructure); |
270 | |
271 | if(size > VC_ILCS_MAX_PARAM_SIZE) |
272 | return OMX_ErrorHardware; |
273 | |
274 | memcpy(exe.param, pComponentParameterStructure, size); |
275 | |
276 | if(ilcs_execute_function(st->ilcs, func, &exe, size + IL_SET_EXECUTE_HEADER_SIZE, &resp, &rlen) < 0 || rlen != sizeof(resp)) |
277 | return OMX_ErrorHardware; |
278 | |
279 | return resp.err; |
280 | } |
281 | |
282 | static OMX_ERRORTYPE vcil_out_GetParameter(OMX_IN OMX_HANDLETYPE hComponent, |
283 | OMX_IN OMX_INDEXTYPE nParamIndex, |
284 | OMX_INOUT OMX_PTR pComponentParameterStructure) |
285 | { |
286 | return vcil_out_get(hComponent, nParamIndex, pComponentParameterStructure, IL_GET_PARAMETER); |
287 | } |
288 | |
289 | static OMX_ERRORTYPE vcil_out_SetParameter(OMX_IN OMX_HANDLETYPE hComponent, |
290 | OMX_IN OMX_INDEXTYPE nParamIndex, |
291 | OMX_IN OMX_PTR pComponentParameterStructure) |
292 | { |
293 | return vcil_out_set(hComponent, nParamIndex, pComponentParameterStructure, IL_SET_PARAMETER); |
294 | } |
295 | |
296 | static OMX_ERRORTYPE vcil_out_GetConfig(OMX_IN OMX_HANDLETYPE hComponent, |
297 | OMX_IN OMX_INDEXTYPE nParamIndex, |
298 | OMX_INOUT OMX_PTR pComponentParameterStructure) |
299 | { |
300 | return vcil_out_get(hComponent, nParamIndex, pComponentParameterStructure, IL_GET_CONFIG); |
301 | } |
302 | |
303 | static OMX_ERRORTYPE vcil_out_SetConfig(OMX_IN OMX_HANDLETYPE hComponent, |
304 | OMX_IN OMX_INDEXTYPE nParamIndex, |
305 | OMX_IN OMX_PTR pComponentParameterStructure) |
306 | { |
307 | return vcil_out_set(hComponent, nParamIndex, pComponentParameterStructure, IL_SET_CONFIG); |
308 | } |
309 | |
310 | static OMX_ERRORTYPE vcil_out_SendCommand(OMX_IN OMX_HANDLETYPE hComponent, |
311 | OMX_IN OMX_COMMANDTYPE Cmd, |
312 | OMX_IN OMX_U32 nParam1, |
313 | OMX_IN OMX_PTR pCmdData) |
314 | { |
315 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
316 | VC_PRIVATE_COMPONENT_T *comp; |
317 | IL_SEND_COMMAND_EXECUTE_T exe; |
318 | IL_RESPONSE_HEADER_T resp; |
319 | ILCS_COMMON_T *st; |
320 | int rlen = sizeof(resp); |
321 | |
322 | if (!pComp) |
323 | return OMX_ErrorBadParameter; |
324 | |
325 | st = pComp->pApplicationPrivate; |
326 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
327 | |
328 | exe.reference = comp->reference; |
329 | exe.cmd = Cmd; |
330 | exe.param = nParam1; |
331 | |
332 | if (Cmd == OMX_CommandMarkBuffer) |
333 | { |
334 | exe.mark = *((OMX_MARKTYPE *) pCmdData); |
335 | } |
336 | else |
337 | { |
338 | exe.mark.hMarkTargetComponent = 0; |
339 | exe.mark.pMarkData = 0; |
340 | } |
341 | |
342 | if(ilcs_execute_function(st->ilcs, IL_SEND_COMMAND, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
343 | return OMX_ErrorHardware; |
344 | |
345 | return resp.err; |
346 | } |
347 | |
348 | // Called to pass a buffer from the host-side across the interface to videcore. |
349 | |
350 | static OMX_ERRORTYPE vcil_out_addBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
351 | OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, |
352 | OMX_IN OMX_U32 nPortIndex, |
353 | OMX_IN OMX_PTR pAppPrivate, |
354 | OMX_IN OMX_U32 nSizeBytes, |
355 | OMX_IN OMX_U8* pBuffer, |
356 | OMX_IN void *eglImage, |
357 | IL_FUNCTION_T func) |
358 | { |
359 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
360 | VC_PRIVATE_COMPONENT_T *comp; |
361 | IL_ADD_BUFFER_EXECUTE_T exe; |
362 | IL_ADD_BUFFER_RESPONSE_T resp; |
363 | OMX_BUFFERHEADERTYPE *; |
364 | VC_PRIVATE_PORT_T *port; |
365 | ILCS_COMMON_T *st; |
366 | int rlen = sizeof(resp); |
367 | |
368 | if (!(pComp && ppBufferHdr)) |
369 | return OMX_ErrorBadParameter; |
370 | |
371 | st = pComp->pApplicationPrivate; |
372 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
373 | |
374 | port = find_port(comp, nPortIndex); |
375 | if (!port) // bad port index |
376 | return OMX_ErrorBadPortIndex; |
377 | |
378 | if (port->numBuffers > 0 && port->func != func) |
379 | { |
380 | // inconsistent use of usebuffer/allocatebuffer/eglimage |
381 | // all ports must receive all buffers by exactly one of these methods |
382 | vc_assert(port->func != func); |
383 | return OMX_ErrorInsufficientResources; |
384 | } |
385 | port->func = func; |
386 | |
387 | if (!VCHI_BULK_ALIGNED(pBuffer)) |
388 | { |
389 | // cannot transfer this buffer across the host interface |
390 | return OMX_ErrorBadParameter; |
391 | } |
392 | |
393 | pHeader = vcos_malloc(sizeof(*pHeader), "vcout buffer header" ); |
394 | |
395 | if (!pHeader) |
396 | return OMX_ErrorInsufficientResources; |
397 | |
398 | if (func == IL_ALLOCATE_BUFFER) |
399 | { |
400 | pBuffer = vcos_malloc_aligned(nSizeBytes, ILCS_ALIGN, "vcout mapping buffer" ); |
401 | if (!pBuffer) |
402 | { |
403 | vcos_free(pHeader); |
404 | return OMX_ErrorInsufficientResources; |
405 | } |
406 | } |
407 | |
408 | exe.reference = comp->reference; |
409 | exe.bufferReference = pHeader; |
410 | exe.port = nPortIndex; |
411 | exe.size = nSizeBytes; |
412 | exe.eglImage = eglImage; |
413 | |
414 | if(ilcs_execute_function(st->ilcs, func, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
415 | resp.err = OMX_ErrorHardware; |
416 | |
417 | if (resp.err == OMX_ErrorNone) |
418 | { |
419 | memcpy(pHeader, &resp.bufferHeader, sizeof(OMX_BUFFERHEADERTYPE)); |
420 | if (port->dir == OMX_DirOutput) |
421 | pHeader->pOutputPortPrivate = resp.reference; |
422 | else |
423 | pHeader->pInputPortPrivate = resp.reference; |
424 | |
425 | if (func == IL_USE_EGL_IMAGE) |
426 | { |
427 | pHeader->pBuffer = (OMX_U8*)eglImage; |
428 | port->bEGL = OMX_TRUE; |
429 | } |
430 | else |
431 | { |
432 | pHeader->pBuffer = pBuffer; |
433 | port->bEGL = OMX_FALSE; |
434 | } |
435 | |
436 | pHeader->pAppPrivate = pAppPrivate; |
437 | *ppBufferHdr = pHeader; |
438 | port->numBuffers++; |
439 | } |
440 | else |
441 | { |
442 | if (func == IL_ALLOCATE_BUFFER) |
443 | vcos_free(pBuffer); |
444 | vcos_free(pHeader); |
445 | } |
446 | |
447 | return resp.err; |
448 | } |
449 | |
450 | static VCOS_ONCE_T loaded_eglIntOpenMAXILDoneMarker = VCOS_ONCE_INIT; |
451 | static int (*local_eglIntOpenMAXILDoneMarker) (void* component_handle, void *egl_image) = NULL; |
452 | |
453 | static void load_eglIntOpenMAXILDoneMarker(void) |
454 | { |
455 | void *handle; |
456 | |
457 | /* First try to load from the current process, this will succeed |
458 | * if something that is linked to libEGL is already loaded or |
459 | * something explicitly loaded libEGL with RTLD_GLOBAL |
460 | */ |
461 | handle = vcos_dlopen(NULL, VCOS_DL_GLOBAL); |
462 | local_eglIntOpenMAXILDoneMarker = (void * )vcos_dlsym(handle, "eglIntOpenMAXILDoneMarker" ); |
463 | if (local_eglIntOpenMAXILDoneMarker == NULL) |
464 | { |
465 | vcos_dlclose(handle); |
466 | /* If that failed try to load libEGL.so explicitely */ |
467 | handle = vcos_dlopen("libEGL.so" , VCOS_DL_LAZY | VCOS_DL_LOCAL); |
468 | vc_assert(handle != NULL); |
469 | local_eglIntOpenMAXILDoneMarker = (void * )vcos_dlsym(handle, "eglIntOpenMAXILDoneMarker" ); |
470 | vc_assert(local_eglIntOpenMAXILDoneMarker != NULL); |
471 | } |
472 | } |
473 | |
474 | static OMX_ERRORTYPE vcil_out_UseEGLImage(OMX_IN OMX_HANDLETYPE hComponent, |
475 | OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, |
476 | OMX_IN OMX_U32 nPortIndex, |
477 | OMX_IN OMX_PTR pAppPrivate, |
478 | OMX_IN void* eglImage) |
479 | { |
480 | /* Load eglIntOpenMAXILDoneMarker() and libEGL here, it will be needed later */ |
481 | vcos_once(&loaded_eglIntOpenMAXILDoneMarker, load_eglIntOpenMAXILDoneMarker); |
482 | |
483 | return vcil_out_addBuffer(hComponent, ppBufferHdr, nPortIndex, pAppPrivate, 0, NULL, eglImage, IL_USE_EGL_IMAGE); |
484 | } |
485 | |
486 | static OMX_ERRORTYPE vcil_out_UseBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
487 | OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, |
488 | OMX_IN OMX_U32 nPortIndex, |
489 | OMX_IN OMX_PTR pAppPrivate, |
490 | OMX_IN OMX_U32 nSizeBytes, |
491 | OMX_IN OMX_U8* pBuffer) |
492 | { |
493 | return vcil_out_addBuffer(hComponent, ppBufferHdr, nPortIndex, pAppPrivate, nSizeBytes, pBuffer, NULL, IL_USE_BUFFER); |
494 | } |
495 | |
496 | static OMX_ERRORTYPE vcil_out_AllocateBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
497 | OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, |
498 | OMX_IN OMX_U32 nPortIndex, |
499 | OMX_IN OMX_PTR pAppPrivate, |
500 | OMX_IN OMX_U32 nSizeBytes) |
501 | { |
502 | return vcil_out_addBuffer(hComponent, ppBufferHdr, nPortIndex, pAppPrivate, nSizeBytes, NULL, NULL, IL_ALLOCATE_BUFFER); |
503 | } |
504 | |
505 | static OMX_ERRORTYPE vcil_out_FreeBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
506 | OMX_IN OMX_U32 nPortIndex, |
507 | OMX_IN OMX_BUFFERHEADERTYPE* pBufferHdr) |
508 | { |
509 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
510 | VC_PRIVATE_COMPONENT_T *comp; |
511 | IL_FREE_BUFFER_EXECUTE_T exe; |
512 | IL_RESPONSE_HEADER_T resp; |
513 | VC_PRIVATE_PORT_T *port; |
514 | ILCS_COMMON_T *st; |
515 | int rlen = sizeof(resp); |
516 | |
517 | if (!(pComp && pBufferHdr)) |
518 | return OMX_ErrorBadParameter; |
519 | |
520 | st = pComp->pApplicationPrivate; |
521 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
522 | |
523 | port = find_port(comp, nPortIndex); |
524 | if (!port) |
525 | return OMX_ErrorBadPortIndex; |
526 | |
527 | if (port->numBuffers == 0) |
528 | return OMX_ErrorIncorrectStateTransition; |
529 | |
530 | exe.reference = comp->reference; |
531 | exe.port = nPortIndex; |
532 | if (port->dir == OMX_DirOutput) |
533 | exe.bufferReference = pBufferHdr->pOutputPortPrivate; |
534 | else |
535 | exe.bufferReference = pBufferHdr->pInputPortPrivate; |
536 | exe.func = port->func; |
537 | exe.inputPrivate = NULL; |
538 | exe.outputPrivate = NULL; |
539 | |
540 | if(ilcs_execute_function(st->ilcs, IL_FREE_BUFFER, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
541 | return OMX_ErrorHardware; |
542 | |
543 | if (resp.err == OMX_ErrorNone) |
544 | { |
545 | if (port->func == IL_ALLOCATE_BUFFER) |
546 | vcos_free(pBufferHdr->pBuffer); |
547 | vcos_free(pBufferHdr); |
548 | port->numBuffers--; |
549 | } |
550 | |
551 | return resp.err; |
552 | } |
553 | |
554 | // Called on host-side to pass a buffer to VideoCore to be emptied |
555 | static OMX_ERRORTYPE vcil_out_EmptyThisBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
556 | OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) |
557 | { |
558 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
559 | VC_PRIVATE_COMPONENT_T *comp; |
560 | ILCS_COMMON_T *st; |
561 | |
562 | if (!(pComp && pBuffer)) |
563 | return (OMX_ErrorBadParameter); |
564 | |
565 | st = pComp->pApplicationPrivate; |
566 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
567 | |
568 | return ilcs_pass_buffer(st->ilcs, IL_EMPTY_THIS_BUFFER, comp->reference, pBuffer); |
569 | } |
570 | |
571 | // Called from ril_top as OMX_FillThisBuffer(). |
572 | // ->pBuffer field is expected to be a memory handle. |
573 | |
574 | static OMX_ERRORTYPE vcil_out_FillThisBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
575 | OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) |
576 | { |
577 | OMX_ERRORTYPE err; |
578 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
579 | VC_PRIVATE_COMPONENT_T *comp; |
580 | VC_PRIVATE_PORT_T *port; |
581 | ILCS_COMMON_T *st; |
582 | |
583 | if (!(pComp && pBuffer)) |
584 | return (OMX_ErrorBadParameter); |
585 | |
586 | st = pComp->pApplicationPrivate; |
587 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
588 | |
589 | port = find_port(comp, pBuffer->nOutputPortIndex); |
590 | if(!port) |
591 | return OMX_ErrorBadPortIndex; |
592 | |
593 | if(pBuffer->pBuffer == 0) |
594 | return OMX_ErrorIncorrectStateOperation; |
595 | |
596 | vcos_assert(pComp != NULL && comp != NULL && port != NULL && st != NULL); |
597 | |
598 | // The lower layers will attempt to transfer the bytes specified if we don't |
599 | // clear these - callers should ideally do this themselves, but it is not |
600 | // mandated in the specification. |
601 | pBuffer->nFilledLen = 0; |
602 | pBuffer->nFlags = 0; |
603 | |
604 | vc_assert(port->bEGL == OMX_TRUE || is_valid_hostside_buffer(pBuffer)); |
605 | |
606 | err = ilcs_pass_buffer(st->ilcs, IL_FILL_THIS_BUFFER, comp->reference, pBuffer); |
607 | |
608 | if (err == OMX_ErrorNone && port->bEGL == OMX_TRUE) |
609 | { |
610 | // If an output port is marked as an EGL port, we request EGL to notify the IL component |
611 | // when it's allowed to render into the buffer/EGLImage. |
612 | vc_assert(local_eglIntOpenMAXILDoneMarker != NULL); |
613 | local_eglIntOpenMAXILDoneMarker(comp->reference, pBuffer->pBuffer); |
614 | } |
615 | |
616 | return err; |
617 | } |
618 | |
619 | static OMX_ERRORTYPE vcil_out_ComponentTunnelRequest(OMX_IN OMX_HANDLETYPE hComponent, |
620 | OMX_IN OMX_U32 nPort, |
621 | OMX_IN OMX_HANDLETYPE hTunneledComp, |
622 | OMX_IN OMX_U32 nTunneledPort, |
623 | OMX_INOUT OMX_TUNNELSETUPTYPE* pTunnelSetup) |
624 | { |
625 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
626 | VC_PRIVATE_COMPONENT_T *comp; |
627 | IL_TUNNEL_REQUEST_EXECUTE_T exe; |
628 | IL_TUNNEL_REQUEST_RESPONSE_T resp; |
629 | VC_PRIVATE_COMPONENT_T *list; |
630 | ILCS_COMMON_T *st; |
631 | int rlen = sizeof(resp); |
632 | |
633 | if(!pComp) |
634 | return OMX_ErrorBadParameter; |
635 | |
636 | st = pComp->pApplicationPrivate; |
637 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
638 | |
639 | exe.reference = comp->reference; |
640 | exe.port = nPort; |
641 | exe.tunnel_port = nTunneledPort; |
642 | if (pTunnelSetup) |
643 | exe.setup = *pTunnelSetup; |
644 | |
645 | // the other component may be on the host or on VC. Look through our list |
646 | // so we can tell, and tell ILCS on VC the details. |
647 | vcos_semaphore_wait(&st->component_lock); |
648 | |
649 | list = st->component_list; |
650 | while (list != NULL && list->comp != (void *) hTunneledComp) |
651 | list = list->next; |
652 | |
653 | vcos_semaphore_post(&st->component_lock); |
654 | |
655 | if (list == NULL) |
656 | { |
657 | exe.tunnel_ref = hTunneledComp; |
658 | exe.tunnel_host = OMX_TRUE; |
659 | } |
660 | else |
661 | { |
662 | exe.tunnel_ref = list->reference; |
663 | exe.tunnel_host = OMX_FALSE; |
664 | } |
665 | |
666 | if(ilcs_execute_function(st->ilcs, IL_COMPONENT_TUNNEL_REQUEST, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
667 | return OMX_ErrorHardware; |
668 | |
669 | if (pTunnelSetup) |
670 | *pTunnelSetup = resp.setup; |
671 | return resp.err; |
672 | } |
673 | |
674 | static OMX_ERRORTYPE vcil_out_GetExtensionIndex(OMX_IN OMX_HANDLETYPE hComponent, |
675 | OMX_IN OMX_STRING cParameterName, |
676 | OMX_OUT OMX_INDEXTYPE* pIndexType) |
677 | { |
678 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
679 | VC_PRIVATE_COMPONENT_T *comp; |
680 | IL_GET_EXTENSION_EXECUTE_T exe; |
681 | IL_GET_EXTENSION_RESPONSE_T resp; |
682 | ILCS_COMMON_T *st; |
683 | int rlen = sizeof(resp); |
684 | |
685 | if (!(pComp && cParameterName && pIndexType)) |
686 | return OMX_ErrorBadParameter; |
687 | |
688 | st = pComp->pApplicationPrivate; |
689 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
690 | |
691 | exe.reference = comp->reference; |
692 | strncpy(exe.name, cParameterName, 128); |
693 | exe.name[127] = 0; |
694 | |
695 | if(ilcs_execute_function(st->ilcs, IL_GET_EXTENSION_INDEX, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
696 | return OMX_ErrorHardware; |
697 | |
698 | *pIndexType = resp.index; |
699 | return resp.err; |
700 | } |
701 | |
702 | static OMX_ERRORTYPE vcil_out_ComponentRoleEnum(OMX_IN OMX_HANDLETYPE hComponent, |
703 | OMX_OUT OMX_U8 *cRole, |
704 | OMX_IN OMX_U32 nIndex) |
705 | { |
706 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
707 | VC_PRIVATE_COMPONENT_T *comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
708 | IL_COMPONENT_ROLE_ENUM_EXECUTE_T exe; |
709 | IL_COMPONENT_ROLE_ENUM_RESPONSE_T resp; |
710 | ILCS_COMMON_T *st = pComp->pApplicationPrivate; |
711 | int rlen = sizeof(resp); |
712 | |
713 | exe.reference = comp->reference; |
714 | exe.index = nIndex; |
715 | |
716 | if(ilcs_execute_function(st->ilcs, IL_COMPONENT_ROLE_ENUM, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
717 | return OMX_ErrorHardware; |
718 | |
719 | strncpy((char *) cRole, (char *) resp.role, 128); |
720 | cRole[127] = 0; |
721 | return resp.err; |
722 | } |
723 | |
724 | OMX_ERRORTYPE vcil_out_component_name_enum(ILCS_COMMON_T *st, OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex) |
725 | { |
726 | IL_COMPONENT_NAME_ENUM_EXECUTE_T exe; |
727 | IL_COMPONENT_NAME_ENUM_RESPONSE_T resp; |
728 | int rlen = sizeof(resp); |
729 | |
730 | exe.index = nIndex; |
731 | |
732 | if(ilcs_execute_function(st->ilcs, IL_COMPONENT_NAME_ENUM, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
733 | return OMX_ErrorHardware; |
734 | |
735 | if (sizeof(resp.name) < nNameLength) |
736 | nNameLength = sizeof(resp.name); |
737 | |
738 | strncpy((char *)cComponentName, (char *) resp.name, nNameLength); |
739 | cComponentName[127] = 0; |
740 | return resp.err; |
741 | } |
742 | |
743 | OMX_ERRORTYPE vcil_out_get_debug_information(ILCS_COMMON_T *st, OMX_STRING debugInfo, OMX_S32 *pLen) |
744 | { |
745 | IL_GET_DEBUG_INFORMATION_EXECUTE_T exe; |
746 | |
747 | exe.len = *pLen; |
748 | |
749 | if(ilcs_execute_function(st->ilcs, IL_GET_DEBUG_INFORMATION, &exe, sizeof(exe), debugInfo, (int *) pLen) < 0) |
750 | return OMX_ErrorHardware; |
751 | |
752 | return OMX_ErrorNone; |
753 | } |
754 | |
755 | // Called on the host side to create an OMX component. |
756 | OMX_ERRORTYPE vcil_out_create_component(ILCS_COMMON_T *st, OMX_HANDLETYPE hComponent, OMX_STRING component_name) |
757 | { |
758 | OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
759 | IL_CREATE_COMPONENT_EXECUTE_T exe; |
760 | IL_CREATE_COMPONENT_RESPONSE_T resp; |
761 | VC_PRIVATE_COMPONENT_T *comp; |
762 | OMX_U32 i; |
763 | int rlen = sizeof(resp); |
764 | |
765 | if (strlen(component_name) >= sizeof(exe.name)) |
766 | return OMX_ErrorInvalidComponent; |
767 | |
768 | strcpy(exe.name, component_name); |
769 | exe.mark = pComp; |
770 | |
771 | if(ilcs_execute_function(st->ilcs, IL_CREATE_COMPONENT, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
772 | return OMX_ErrorHardware; |
773 | |
774 | if (resp.err != OMX_ErrorNone) |
775 | return resp.err; |
776 | |
777 | comp = vcos_malloc(sizeof(VC_PRIVATE_COMPONENT_T) + (sizeof(VC_PRIVATE_PORT_T) * resp.numPorts), "ILCS Host Comp" ); |
778 | if (!comp) |
779 | { |
780 | IL_EXECUTE_HEADER_T dexe; |
781 | IL_RESPONSE_HEADER_T dresp; |
782 | int dlen = sizeof(dresp); |
783 | |
784 | dexe.reference = resp.reference; |
785 | |
786 | ilcs_execute_function(st->ilcs, IL_COMPONENT_DEINIT, &dexe, sizeof(dexe), &dresp, &dlen); |
787 | return OMX_ErrorInsufficientResources; |
788 | } |
789 | |
790 | memset(comp, 0, sizeof(VC_PRIVATE_COMPONENT_T) + (sizeof(VC_PRIVATE_PORT_T) * resp.numPorts)); |
791 | |
792 | comp->reference = resp.reference; |
793 | comp->comp = pComp; |
794 | comp->numPorts = resp.numPorts; |
795 | comp->port = (VC_PRIVATE_PORT_T *) ((unsigned char *) comp + sizeof(VC_PRIVATE_COMPONENT_T)); |
796 | |
797 | for (i=0; i<comp->numPorts; i++) |
798 | { |
799 | if (i && !(i&0x1f)) |
800 | { |
801 | IL_GET_EXECUTE_T gexe; |
802 | IL_GET_RESPONSE_T gresp; |
803 | OMX_PARAM_PORTSUMMARYTYPE *summary; |
804 | int glen = sizeof(gresp); |
805 | |
806 | gexe.reference = comp->reference; |
807 | gexe.index = OMX_IndexParamPortSummary; |
808 | |
809 | summary = (OMX_PARAM_PORTSUMMARYTYPE *) &gexe.param; |
810 | summary->nSize = sizeof(OMX_PARAM_PORTSUMMARYTYPE); |
811 | summary->nVersion.nVersion = OMX_VERSION; |
812 | summary->reqSet = i>>5; |
813 | |
814 | ilcs_execute_function(st->ilcs, IL_GET_PARAMETER, &gexe, |
815 | sizeof(OMX_PARAM_PORTSUMMARYTYPE)+IL_GET_EXECUTE_HEADER_SIZE, |
816 | &gresp, &glen); |
817 | |
818 | summary = (OMX_PARAM_PORTSUMMARYTYPE *) &gresp.param; |
819 | resp.portDir = summary->portDir; |
820 | memcpy(resp.portIndex, summary->portIndex, sizeof(OMX_U32) * 32); |
821 | } |
822 | |
823 | comp->port[i].port = resp.portIndex[i&0x1f]; |
824 | comp->port[i].dir = ((resp.portDir >> (i&0x1f)) & 1) ? OMX_DirOutput : OMX_DirInput; |
825 | } |
826 | |
827 | vcos_semaphore_wait(&st->component_lock); |
828 | // insert into head of list |
829 | comp->next = st->component_list; |
830 | st->component_list = comp; |
831 | vcos_semaphore_post(&st->component_lock); |
832 | |
833 | pComp->pComponentPrivate = comp; |
834 | pComp->pApplicationPrivate = st; |
835 | |
836 | pComp->GetComponentVersion = vcil_out_GetComponentVersion; |
837 | pComp->ComponentDeInit = vcil_out_ComponentDeInit; |
838 | pComp->SetCallbacks = vcil_out_SetCallbacks; |
839 | pComp->GetState = vcil_out_GetState; |
840 | pComp->GetParameter = vcil_out_GetParameter; |
841 | pComp->SetParameter = vcil_out_SetParameter; |
842 | pComp->GetConfig = vcil_out_GetConfig; |
843 | pComp->SetConfig = vcil_out_SetConfig; |
844 | pComp->SendCommand = vcil_out_SendCommand; |
845 | pComp->UseBuffer = vcil_out_UseBuffer; |
846 | pComp->AllocateBuffer = vcil_out_AllocateBuffer; |
847 | pComp->FreeBuffer = vcil_out_FreeBuffer; |
848 | pComp->EmptyThisBuffer = vcil_out_EmptyThisBuffer; |
849 | pComp->FillThisBuffer = vcil_out_FillThisBuffer; |
850 | pComp->ComponentTunnelRequest = vcil_out_ComponentTunnelRequest; |
851 | pComp->GetExtensionIndex = vcil_out_GetExtensionIndex; |
852 | pComp->UseEGLImage = vcil_out_UseEGLImage; |
853 | pComp->ComponentRoleEnum = vcil_out_ComponentRoleEnum; |
854 | |
855 | return resp.err; |
856 | } |
857 | |
858 | /* callbacks */ |
859 | |
860 | void vcil_out_event_handler(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen) |
861 | { |
862 | IL_EVENT_HANDLER_EXECUTE_T *exe = call; |
863 | OMX_COMPONENTTYPE *pComp = exe->reference; |
864 | VC_PRIVATE_COMPONENT_T *comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
865 | |
866 | *rlen = 0; |
867 | |
868 | vcos_assert(comp->callbacks.EventHandler); |
869 | comp->callbacks.EventHandler(pComp, comp->callback_state, exe->event, exe->data1, exe->data2, exe->eventdata); |
870 | } |
871 | |
872 | // Called on host side via RPC in response to empty buffer completing |
873 | void vcil_out_empty_buffer_done(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen) |
874 | { |
875 | IL_PASS_BUFFER_EXECUTE_T *exe = call; |
876 | OMX_COMPONENTTYPE *pComp = exe->reference; |
877 | VC_PRIVATE_COMPONENT_T *comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
878 | OMX_BUFFERHEADERTYPE * = exe->bufferHeader.pOutputPortPrivate; |
879 | OMX_U8 *pBuffer = pHeader->pBuffer; |
880 | OMX_PTR *pAppPrivate = pHeader->pAppPrivate; |
881 | OMX_PTR *pPlatformPrivate = pHeader->pPlatformPrivate; |
882 | OMX_PTR *pInputPortPrivate = pHeader->pInputPortPrivate; |
883 | OMX_PTR *pOutputPortPrivate = pHeader->pOutputPortPrivate; |
884 | |
885 | memcpy(pHeader, &exe->bufferHeader, sizeof(OMX_BUFFERHEADERTYPE)); |
886 | |
887 | pHeader->pBuffer = pBuffer; |
888 | pHeader->pAppPrivate = pAppPrivate; |
889 | pHeader->pPlatformPrivate = pPlatformPrivate; |
890 | pHeader->pInputPortPrivate = pInputPortPrivate; |
891 | pHeader->pOutputPortPrivate = pOutputPortPrivate; |
892 | |
893 | *rlen = 0; |
894 | |
895 | vcos_assert(comp->callbacks.EmptyBufferDone); |
896 | comp->callbacks.EmptyBufferDone(pComp, comp->callback_state, pHeader); |
897 | } |
898 | |
899 | // Called on host side via RPC in response to a fill-buffer completing |
900 | // on the VideoCore side. ->pBuffer is a real pointer. |
901 | void vcil_out_fill_buffer_done(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen) |
902 | { |
903 | OMX_COMPONENTTYPE *pComp; |
904 | VC_PRIVATE_COMPONENT_T *comp; |
905 | OMX_BUFFERHEADERTYPE *; |
906 | |
907 | pHeader = ilcs_receive_buffer(st->ilcs, call, clen, &pComp); |
908 | *rlen = 0; |
909 | |
910 | if(pHeader) |
911 | { |
912 | comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
913 | |
914 | vc_assert(comp->callbacks.FillBufferDone); |
915 | comp->callbacks.FillBufferDone(pComp, comp->callback_state, pHeader); |
916 | } |
917 | } |
918 | |