1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, 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
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON 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
25SOFTWARE, 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
43static 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
56static 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
68static 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
122static 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
155static 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
184static 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
210static 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
247static 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
282static 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
289static 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
296static 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
303static 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
310static 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
350static 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 *pHeader;
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
450static VCOS_ONCE_T loaded_eglIntOpenMAXILDoneMarker = VCOS_ONCE_INIT;
451static int (*local_eglIntOpenMAXILDoneMarker) (void* component_handle, void *egl_image) = NULL;
452
453static 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
474static 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
486static 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
496static 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
505static 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
555static 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
574static 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
619static 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
674static 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
702static 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
724OMX_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
743OMX_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.
756OMX_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
860void 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
873void 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 *pHeader = 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.
901void 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 *pHeader;
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