Initial version of libomxil-vc4 for RPI3
[platform/adaptation/broadcom/libomxil-vc4.git] / interface / vmcs_host / vcilcs_out.c
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 *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
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 *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.
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 *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 }