mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
917 lines
30 KiB
917 lines
30 KiB
/* |
|
Copyright (c) 2012, Broadcom Europe Ltd |
|
All rights reserved. |
|
|
|
Redistribution and use in source and binary forms, with or without |
|
modification, are permitted provided that the following conditions are met: |
|
* Redistributions of source code must retain the above copyright |
|
notice, this list of conditions and the following disclaimer. |
|
* Redistributions in binary form must reproduce the above copyright |
|
notice, this list of conditions and the following disclaimer in the |
|
documentation and/or other materials provided with the distribution. |
|
* Neither the name of the copyright holder nor the |
|
names of its contributors may be used to endorse or promote products |
|
derived from this software without specific prior written permission. |
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
|
|
#include <string.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <stdarg.h> |
|
#include <ctype.h> |
|
|
|
#include "interface/vchi/vchi.h" |
|
#include "interface/vcos/vcos_dlfcn.h" |
|
#include "interface/vmcs_host/khronos/IL/OMX_Component.h" |
|
#include "interface/vmcs_host/khronos/IL/OMX_ILCS.h" |
|
#include "interface/vmcs_host/vc_ilcs_defs.h" |
|
#include "interface/vmcs_host/vcilcs.h" |
|
#include "interface/vmcs_host/vcilcs_common.h" |
|
#include "interface/vcos/vcos_dlfcn.h" |
|
|
|
static VC_PRIVATE_PORT_T *find_port(VC_PRIVATE_COMPONENT_T *comp, OMX_U32 nPortIndex) |
|
{ |
|
OMX_U32 i=0; |
|
while (i<comp->numPorts && comp->port[i].port != nPortIndex) |
|
i++; |
|
|
|
if (i < comp->numPorts) |
|
return &comp->port[i]; |
|
|
|
return NULL; |
|
} |
|
|
|
#ifndef NDEBUG |
|
static int is_valid_hostside_buffer(OMX_BUFFERHEADERTYPE *pBuf) |
|
{ |
|
if (!pBuf) |
|
return 0; |
|
if (!pBuf->pBuffer) |
|
return 0; |
|
if ((unsigned long)pBuf->pBuffer < 0x100) |
|
return 0; // not believable |
|
return 1; |
|
} |
|
#endif |
|
|
|
static OMX_ERRORTYPE vcil_out_ComponentDeInit(OMX_IN OMX_HANDLETYPE hComponent) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_EXECUTE_HEADER_T exe; |
|
IL_RESPONSE_HEADER_T resp; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if(!pComp) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
exe.reference = comp->reference; |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_COMPONENT_DEINIT, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp) || |
|
resp.err == OMX_ErrorNone) |
|
{ |
|
// remove from list, assuming that we successfully managed to deinit |
|
// this component, or that ilcs has returned an error. The assumption |
|
// here is that if the component has managed to correctly signal an |
|
// error, it still exists, but if the transport has failed then we might |
|
// as well try and cleanup |
|
VC_PRIVATE_COMPONENT_T *list, *prev; |
|
|
|
vcos_semaphore_wait(&st->component_lock); |
|
|
|
list = st->component_list; |
|
prev = NULL; |
|
|
|
while (list != NULL && list != comp) |
|
{ |
|
prev = list; |
|
list = list->next; |
|
} |
|
|
|
// failing to find this component is not a good sign. |
|
if(vcos_verify(list)) |
|
{ |
|
if (prev == NULL) |
|
st->component_list = list->next; |
|
else |
|
prev->next = list->next; |
|
} |
|
|
|
vcos_semaphore_post(&st->component_lock); |
|
vcos_free(comp); |
|
} |
|
|
|
return resp.err; |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_GetComponentVersion(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_OUT OMX_STRING pComponentName, |
|
OMX_OUT OMX_VERSIONTYPE* pComponentVersion, |
|
OMX_OUT OMX_VERSIONTYPE* pSpecVersion, |
|
OMX_OUT OMX_UUIDTYPE* pComponentUUID) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_EXECUTE_HEADER_T exe; |
|
IL_GET_VERSION_RESPONSE_T resp; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if (!(pComp && pComponentName && pComponentVersion && pSpecVersion && pComponentUUID)) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
exe.reference = comp->reference; |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_GET_COMPONENT_VERSION, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
strncpy(pComponentName, resp.name, 128); |
|
pComponentName[127] = 0; |
|
*pComponentVersion = resp.component_version; |
|
*pSpecVersion = resp.spec_version; |
|
memcpy(pComponentUUID, resp.uuid, sizeof(OMX_UUIDTYPE)); |
|
|
|
return resp.err; |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_SetCallbacks(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_CALLBACKTYPE* pCallbacks, |
|
OMX_IN OMX_PTR pAppData) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_SET_CALLBACKS_EXECUTE_T exe; |
|
IL_RESPONSE_HEADER_T resp; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if(!(pComp && pCallbacks)) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
comp->callbacks = *pCallbacks; |
|
comp->callback_state = pAppData; |
|
|
|
exe.reference = comp->reference; |
|
exe.pAppData = pComp; |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_SET_CALLBACKS, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
return resp.err; |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_GetState(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_OUT OMX_STATETYPE* pState) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_EXECUTE_HEADER_T exe; |
|
IL_GET_STATE_RESPONSE_T resp; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if (!(pComp && pState)) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
exe.reference = comp->reference; |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_GET_STATE, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
*pState = resp.state; |
|
|
|
return resp.err; |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_get(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_INDEXTYPE nParamIndex, |
|
OMX_INOUT OMX_PTR pComponentParameterStructure, |
|
IL_FUNCTION_T func) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_GET_EXECUTE_T exe; |
|
IL_GET_RESPONSE_T resp; |
|
OMX_U32 size; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if (!(pComp && pComponentParameterStructure)) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
exe.reference = comp->reference; |
|
exe.index = nParamIndex; |
|
|
|
size = *((OMX_U32 *) pComponentParameterStructure); |
|
|
|
if(size > VC_ILCS_MAX_PARAM_SIZE) |
|
return OMX_ErrorHardware; |
|
|
|
memcpy(exe.param, pComponentParameterStructure, size); |
|
|
|
if(ilcs_execute_function(st->ilcs, func, &exe, size + IL_GET_EXECUTE_HEADER_SIZE, &resp, &rlen) < 0 || rlen > sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
memcpy(pComponentParameterStructure, resp.param, size); |
|
|
|
return resp.err; |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_set(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_INDEXTYPE nParamIndex, |
|
OMX_IN OMX_PTR pComponentParameterStructure, |
|
IL_FUNCTION_T func) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_SET_EXECUTE_T exe; |
|
IL_RESPONSE_HEADER_T resp; |
|
OMX_U32 size; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if (!(pComp && pComponentParameterStructure)) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
exe.reference = comp->reference; |
|
exe.index = nParamIndex; |
|
|
|
size = *((OMX_U32 *) pComponentParameterStructure); |
|
|
|
if(size > VC_ILCS_MAX_PARAM_SIZE) |
|
return OMX_ErrorHardware; |
|
|
|
memcpy(exe.param, pComponentParameterStructure, size); |
|
|
|
if(ilcs_execute_function(st->ilcs, func, &exe, size + IL_SET_EXECUTE_HEADER_SIZE, &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
return resp.err; |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_GetParameter(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_INDEXTYPE nParamIndex, |
|
OMX_INOUT OMX_PTR pComponentParameterStructure) |
|
{ |
|
return vcil_out_get(hComponent, nParamIndex, pComponentParameterStructure, IL_GET_PARAMETER); |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_SetParameter(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_INDEXTYPE nParamIndex, |
|
OMX_IN OMX_PTR pComponentParameterStructure) |
|
{ |
|
return vcil_out_set(hComponent, nParamIndex, pComponentParameterStructure, IL_SET_PARAMETER); |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_GetConfig(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_INDEXTYPE nParamIndex, |
|
OMX_INOUT OMX_PTR pComponentParameterStructure) |
|
{ |
|
return vcil_out_get(hComponent, nParamIndex, pComponentParameterStructure, IL_GET_CONFIG); |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_SetConfig(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_INDEXTYPE nParamIndex, |
|
OMX_IN OMX_PTR pComponentParameterStructure) |
|
{ |
|
return vcil_out_set(hComponent, nParamIndex, pComponentParameterStructure, IL_SET_CONFIG); |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_SendCommand(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_COMMANDTYPE Cmd, |
|
OMX_IN OMX_U32 nParam1, |
|
OMX_IN OMX_PTR pCmdData) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_SEND_COMMAND_EXECUTE_T exe; |
|
IL_RESPONSE_HEADER_T resp; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if (!pComp) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
exe.reference = comp->reference; |
|
exe.cmd = Cmd; |
|
exe.param = nParam1; |
|
|
|
if (Cmd == OMX_CommandMarkBuffer) |
|
{ |
|
exe.mark = *((OMX_MARKTYPE *) pCmdData); |
|
} |
|
else |
|
{ |
|
exe.mark.hMarkTargetComponent = 0; |
|
exe.mark.pMarkData = 0; |
|
} |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_SEND_COMMAND, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
return resp.err; |
|
} |
|
|
|
// Called to pass a buffer from the host-side across the interface to videcore. |
|
|
|
static OMX_ERRORTYPE vcil_out_addBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, |
|
OMX_IN OMX_U32 nPortIndex, |
|
OMX_IN OMX_PTR pAppPrivate, |
|
OMX_IN OMX_U32 nSizeBytes, |
|
OMX_IN OMX_U8* pBuffer, |
|
OMX_IN void *eglImage, |
|
IL_FUNCTION_T func) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_ADD_BUFFER_EXECUTE_T exe; |
|
IL_ADD_BUFFER_RESPONSE_T resp; |
|
OMX_BUFFERHEADERTYPE *pHeader; |
|
VC_PRIVATE_PORT_T *port; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if (!(pComp && ppBufferHdr)) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
port = find_port(comp, nPortIndex); |
|
if (!port) // bad port index |
|
return OMX_ErrorBadPortIndex; |
|
|
|
if (port->numBuffers > 0 && port->func != func) |
|
{ |
|
// inconsistent use of usebuffer/allocatebuffer/eglimage |
|
// all ports must receive all buffers by exactly one of these methods |
|
vc_assert(port->func != func); |
|
return OMX_ErrorInsufficientResources; |
|
} |
|
port->func = func; |
|
|
|
if (!VCHI_BULK_ALIGNED(pBuffer)) |
|
{ |
|
// cannot transfer this buffer across the host interface |
|
return OMX_ErrorBadParameter; |
|
} |
|
|
|
pHeader = vcos_malloc(sizeof(*pHeader), "vcout buffer header"); |
|
|
|
if (!pHeader) |
|
return OMX_ErrorInsufficientResources; |
|
|
|
if (func == IL_ALLOCATE_BUFFER) |
|
{ |
|
pBuffer = vcos_malloc_aligned(nSizeBytes, ILCS_ALIGN, "vcout mapping buffer"); |
|
if (!pBuffer) |
|
{ |
|
vcos_free(pHeader); |
|
return OMX_ErrorInsufficientResources; |
|
} |
|
} |
|
|
|
exe.reference = comp->reference; |
|
exe.bufferReference = pHeader; |
|
exe.port = nPortIndex; |
|
exe.size = nSizeBytes; |
|
exe.eglImage = eglImage; |
|
|
|
if(ilcs_execute_function(st->ilcs, func, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
resp.err = OMX_ErrorHardware; |
|
|
|
if (resp.err == OMX_ErrorNone) |
|
{ |
|
memcpy(pHeader, &resp.bufferHeader, sizeof(OMX_BUFFERHEADERTYPE)); |
|
if (port->dir == OMX_DirOutput) |
|
pHeader->pOutputPortPrivate = resp.reference; |
|
else |
|
pHeader->pInputPortPrivate = resp.reference; |
|
|
|
if (func == IL_USE_EGL_IMAGE) |
|
{ |
|
pHeader->pBuffer = (OMX_U8*)eglImage; |
|
port->bEGL = OMX_TRUE; |
|
} |
|
else |
|
{ |
|
pHeader->pBuffer = pBuffer; |
|
port->bEGL = OMX_FALSE; |
|
} |
|
|
|
pHeader->pAppPrivate = pAppPrivate; |
|
*ppBufferHdr = pHeader; |
|
port->numBuffers++; |
|
} |
|
else |
|
{ |
|
if (func == IL_ALLOCATE_BUFFER) |
|
vcos_free(pBuffer); |
|
vcos_free(pHeader); |
|
} |
|
|
|
return resp.err; |
|
} |
|
|
|
static VCOS_ONCE_T loaded_eglIntOpenMAXILDoneMarker = VCOS_ONCE_INIT; |
|
static int (*local_eglIntOpenMAXILDoneMarker) (void* component_handle, void *egl_image) = NULL; |
|
|
|
static void load_eglIntOpenMAXILDoneMarker(void) |
|
{ |
|
void *handle; |
|
|
|
/* First try to load from the current process, this will succeed |
|
* if something that is linked to libEGL is already loaded or |
|
* something explicitly loaded libEGL with RTLD_GLOBAL |
|
*/ |
|
handle = vcos_dlopen(NULL, VCOS_DL_GLOBAL); |
|
local_eglIntOpenMAXILDoneMarker = (void * )vcos_dlsym(handle, "eglIntOpenMAXILDoneMarker"); |
|
if (local_eglIntOpenMAXILDoneMarker == NULL) |
|
{ |
|
vcos_dlclose(handle); |
|
/* If that failed try to load libEGL.so explicitely */ |
|
handle = vcos_dlopen("libEGL.so", VCOS_DL_LAZY | VCOS_DL_LOCAL); |
|
vc_assert(handle != NULL); |
|
local_eglIntOpenMAXILDoneMarker = (void * )vcos_dlsym(handle, "eglIntOpenMAXILDoneMarker"); |
|
vc_assert(local_eglIntOpenMAXILDoneMarker != NULL); |
|
} |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_UseEGLImage(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, |
|
OMX_IN OMX_U32 nPortIndex, |
|
OMX_IN OMX_PTR pAppPrivate, |
|
OMX_IN void* eglImage) |
|
{ |
|
/* Load eglIntOpenMAXILDoneMarker() and libEGL here, it will be needed later */ |
|
vcos_once(&loaded_eglIntOpenMAXILDoneMarker, load_eglIntOpenMAXILDoneMarker); |
|
|
|
return vcil_out_addBuffer(hComponent, ppBufferHdr, nPortIndex, pAppPrivate, 0, NULL, eglImage, IL_USE_EGL_IMAGE); |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_UseBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, |
|
OMX_IN OMX_U32 nPortIndex, |
|
OMX_IN OMX_PTR pAppPrivate, |
|
OMX_IN OMX_U32 nSizeBytes, |
|
OMX_IN OMX_U8* pBuffer) |
|
{ |
|
return vcil_out_addBuffer(hComponent, ppBufferHdr, nPortIndex, pAppPrivate, nSizeBytes, pBuffer, NULL, IL_USE_BUFFER); |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_AllocateBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr, |
|
OMX_IN OMX_U32 nPortIndex, |
|
OMX_IN OMX_PTR pAppPrivate, |
|
OMX_IN OMX_U32 nSizeBytes) |
|
{ |
|
return vcil_out_addBuffer(hComponent, ppBufferHdr, nPortIndex, pAppPrivate, nSizeBytes, NULL, NULL, IL_ALLOCATE_BUFFER); |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_FreeBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_U32 nPortIndex, |
|
OMX_IN OMX_BUFFERHEADERTYPE* pBufferHdr) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_FREE_BUFFER_EXECUTE_T exe; |
|
IL_RESPONSE_HEADER_T resp; |
|
VC_PRIVATE_PORT_T *port; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if (!(pComp && pBufferHdr)) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
port = find_port(comp, nPortIndex); |
|
if (!port) |
|
return OMX_ErrorBadPortIndex; |
|
|
|
if (port->numBuffers == 0) |
|
return OMX_ErrorIncorrectStateTransition; |
|
|
|
exe.reference = comp->reference; |
|
exe.port = nPortIndex; |
|
if (port->dir == OMX_DirOutput) |
|
exe.bufferReference = pBufferHdr->pOutputPortPrivate; |
|
else |
|
exe.bufferReference = pBufferHdr->pInputPortPrivate; |
|
exe.func = port->func; |
|
exe.inputPrivate = NULL; |
|
exe.outputPrivate = NULL; |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_FREE_BUFFER, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
if (resp.err == OMX_ErrorNone) |
|
{ |
|
if (port->func == IL_ALLOCATE_BUFFER) |
|
vcos_free(pBufferHdr->pBuffer); |
|
vcos_free(pBufferHdr); |
|
port->numBuffers--; |
|
} |
|
|
|
return resp.err; |
|
} |
|
|
|
// Called on host-side to pass a buffer to VideoCore to be emptied |
|
static OMX_ERRORTYPE vcil_out_EmptyThisBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
ILCS_COMMON_T *st; |
|
|
|
if (!(pComp && pBuffer)) |
|
return (OMX_ErrorBadParameter); |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
return ilcs_pass_buffer(st->ilcs, IL_EMPTY_THIS_BUFFER, comp->reference, pBuffer); |
|
} |
|
|
|
// Called from ril_top as OMX_FillThisBuffer(). |
|
// ->pBuffer field is expected to be a memory handle. |
|
|
|
static OMX_ERRORTYPE vcil_out_FillThisBuffer(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) |
|
{ |
|
OMX_ERRORTYPE err; |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
VC_PRIVATE_PORT_T *port; |
|
ILCS_COMMON_T *st; |
|
|
|
if (!(pComp && pBuffer)) |
|
return (OMX_ErrorBadParameter); |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
port = find_port(comp, pBuffer->nOutputPortIndex); |
|
if(!port) |
|
return OMX_ErrorBadPortIndex; |
|
|
|
if(pBuffer->pBuffer == 0) |
|
return OMX_ErrorIncorrectStateOperation; |
|
|
|
vcos_assert(pComp != NULL && comp != NULL && port != NULL && st != NULL); |
|
|
|
// The lower layers will attempt to transfer the bytes specified if we don't |
|
// clear these - callers should ideally do this themselves, but it is not |
|
// mandated in the specification. |
|
pBuffer->nFilledLen = 0; |
|
pBuffer->nFlags = 0; |
|
|
|
vc_assert(port->bEGL == OMX_TRUE || is_valid_hostside_buffer(pBuffer)); |
|
|
|
err = ilcs_pass_buffer(st->ilcs, IL_FILL_THIS_BUFFER, comp->reference, pBuffer); |
|
|
|
if (err == OMX_ErrorNone && port->bEGL == OMX_TRUE) |
|
{ |
|
// If an output port is marked as an EGL port, we request EGL to notify the IL component |
|
// when it's allowed to render into the buffer/EGLImage. |
|
vc_assert(local_eglIntOpenMAXILDoneMarker != NULL); |
|
local_eglIntOpenMAXILDoneMarker(comp->reference, pBuffer->pBuffer); |
|
} |
|
|
|
return err; |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_ComponentTunnelRequest(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_U32 nPort, |
|
OMX_IN OMX_HANDLETYPE hTunneledComp, |
|
OMX_IN OMX_U32 nTunneledPort, |
|
OMX_INOUT OMX_TUNNELSETUPTYPE* pTunnelSetup) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_TUNNEL_REQUEST_EXECUTE_T exe; |
|
IL_TUNNEL_REQUEST_RESPONSE_T resp; |
|
VC_PRIVATE_COMPONENT_T *list; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if(!pComp) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
exe.reference = comp->reference; |
|
exe.port = nPort; |
|
exe.tunnel_port = nTunneledPort; |
|
if (pTunnelSetup) |
|
exe.setup = *pTunnelSetup; |
|
|
|
// the other component may be on the host or on VC. Look through our list |
|
// so we can tell, and tell ILCS on VC the details. |
|
vcos_semaphore_wait(&st->component_lock); |
|
|
|
list = st->component_list; |
|
while (list != NULL && list->comp != (void *) hTunneledComp) |
|
list = list->next; |
|
|
|
vcos_semaphore_post(&st->component_lock); |
|
|
|
if (list == NULL) |
|
{ |
|
exe.tunnel_ref = hTunneledComp; |
|
exe.tunnel_host = OMX_TRUE; |
|
} |
|
else |
|
{ |
|
exe.tunnel_ref = list->reference; |
|
exe.tunnel_host = OMX_FALSE; |
|
} |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_COMPONENT_TUNNEL_REQUEST, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
if (pTunnelSetup) |
|
*pTunnelSetup = resp.setup; |
|
return resp.err; |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_GetExtensionIndex(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_IN OMX_STRING cParameterName, |
|
OMX_OUT OMX_INDEXTYPE* pIndexType) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
IL_GET_EXTENSION_EXECUTE_T exe; |
|
IL_GET_EXTENSION_RESPONSE_T resp; |
|
ILCS_COMMON_T *st; |
|
int rlen = sizeof(resp); |
|
|
|
if (!(pComp && cParameterName && pIndexType)) |
|
return OMX_ErrorBadParameter; |
|
|
|
st = pComp->pApplicationPrivate; |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
exe.reference = comp->reference; |
|
strncpy(exe.name, cParameterName, 128); |
|
exe.name[127] = 0; |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_GET_EXTENSION_INDEX, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
*pIndexType = resp.index; |
|
return resp.err; |
|
} |
|
|
|
static OMX_ERRORTYPE vcil_out_ComponentRoleEnum(OMX_IN OMX_HANDLETYPE hComponent, |
|
OMX_OUT OMX_U8 *cRole, |
|
OMX_IN OMX_U32 nIndex) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
VC_PRIVATE_COMPONENT_T *comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
IL_COMPONENT_ROLE_ENUM_EXECUTE_T exe; |
|
IL_COMPONENT_ROLE_ENUM_RESPONSE_T resp; |
|
ILCS_COMMON_T *st = pComp->pApplicationPrivate; |
|
int rlen = sizeof(resp); |
|
|
|
exe.reference = comp->reference; |
|
exe.index = nIndex; |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_COMPONENT_ROLE_ENUM, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
strncpy((char *) cRole, (char *) resp.role, 128); |
|
cRole[127] = 0; |
|
return resp.err; |
|
} |
|
|
|
OMX_ERRORTYPE vcil_out_component_name_enum(ILCS_COMMON_T *st, OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex) |
|
{ |
|
IL_COMPONENT_NAME_ENUM_EXECUTE_T exe; |
|
IL_COMPONENT_NAME_ENUM_RESPONSE_T resp; |
|
int rlen = sizeof(resp); |
|
|
|
exe.index = nIndex; |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_COMPONENT_NAME_ENUM, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
if (sizeof(resp.name) < nNameLength) |
|
nNameLength = sizeof(resp.name); |
|
|
|
strncpy((char *)cComponentName, (char *) resp.name, nNameLength); |
|
cComponentName[127] = 0; |
|
return resp.err; |
|
} |
|
|
|
OMX_ERRORTYPE vcil_out_get_debug_information(ILCS_COMMON_T *st, OMX_STRING debugInfo, OMX_S32 *pLen) |
|
{ |
|
IL_GET_DEBUG_INFORMATION_EXECUTE_T exe; |
|
|
|
exe.len = *pLen; |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_GET_DEBUG_INFORMATION, &exe, sizeof(exe), debugInfo, (int *) pLen) < 0) |
|
return OMX_ErrorHardware; |
|
|
|
return OMX_ErrorNone; |
|
} |
|
|
|
// Called on the host side to create an OMX component. |
|
OMX_ERRORTYPE vcil_out_create_component(ILCS_COMMON_T *st, OMX_HANDLETYPE hComponent, OMX_STRING component_name) |
|
{ |
|
OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent; |
|
IL_CREATE_COMPONENT_EXECUTE_T exe; |
|
IL_CREATE_COMPONENT_RESPONSE_T resp; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
OMX_U32 i; |
|
int rlen = sizeof(resp); |
|
|
|
if (strlen(component_name) >= sizeof(exe.name)) |
|
return OMX_ErrorInvalidComponent; |
|
|
|
strcpy(exe.name, component_name); |
|
exe.mark = pComp; |
|
|
|
if(ilcs_execute_function(st->ilcs, IL_CREATE_COMPONENT, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp)) |
|
return OMX_ErrorHardware; |
|
|
|
if (resp.err != OMX_ErrorNone) |
|
return resp.err; |
|
|
|
comp = vcos_malloc(sizeof(VC_PRIVATE_COMPONENT_T) + (sizeof(VC_PRIVATE_PORT_T) * resp.numPorts), "ILCS Host Comp"); |
|
if (!comp) |
|
{ |
|
IL_EXECUTE_HEADER_T dexe; |
|
IL_RESPONSE_HEADER_T dresp; |
|
int dlen = sizeof(dresp); |
|
|
|
dexe.reference = resp.reference; |
|
|
|
ilcs_execute_function(st->ilcs, IL_COMPONENT_DEINIT, &dexe, sizeof(dexe), &dresp, &dlen); |
|
return OMX_ErrorInsufficientResources; |
|
} |
|
|
|
memset(comp, 0, sizeof(VC_PRIVATE_COMPONENT_T) + (sizeof(VC_PRIVATE_PORT_T) * resp.numPorts)); |
|
|
|
comp->reference = resp.reference; |
|
comp->comp = pComp; |
|
comp->numPorts = resp.numPorts; |
|
comp->port = (VC_PRIVATE_PORT_T *) ((unsigned char *) comp + sizeof(VC_PRIVATE_COMPONENT_T)); |
|
|
|
for (i=0; i<comp->numPorts; i++) |
|
{ |
|
if (i && !(i&0x1f)) |
|
{ |
|
IL_GET_EXECUTE_T gexe; |
|
IL_GET_RESPONSE_T gresp; |
|
OMX_PARAM_PORTSUMMARYTYPE *summary; |
|
int glen = sizeof(gresp); |
|
|
|
gexe.reference = comp->reference; |
|
gexe.index = OMX_IndexParamPortSummary; |
|
|
|
summary = (OMX_PARAM_PORTSUMMARYTYPE *) &gexe.param; |
|
summary->nSize = sizeof(OMX_PARAM_PORTSUMMARYTYPE); |
|
summary->nVersion.nVersion = OMX_VERSION; |
|
summary->reqSet = i>>5; |
|
|
|
ilcs_execute_function(st->ilcs, IL_GET_PARAMETER, &gexe, |
|
sizeof(OMX_PARAM_PORTSUMMARYTYPE)+IL_GET_EXECUTE_HEADER_SIZE, |
|
&gresp, &glen); |
|
|
|
summary = (OMX_PARAM_PORTSUMMARYTYPE *) &gresp.param; |
|
resp.portDir = summary->portDir; |
|
memcpy(resp.portIndex, summary->portIndex, sizeof(OMX_U32) * 32); |
|
} |
|
|
|
comp->port[i].port = resp.portIndex[i&0x1f]; |
|
comp->port[i].dir = ((resp.portDir >> (i&0x1f)) & 1) ? OMX_DirOutput : OMX_DirInput; |
|
} |
|
|
|
vcos_semaphore_wait(&st->component_lock); |
|
// insert into head of list |
|
comp->next = st->component_list; |
|
st->component_list = comp; |
|
vcos_semaphore_post(&st->component_lock); |
|
|
|
pComp->pComponentPrivate = comp; |
|
pComp->pApplicationPrivate = st; |
|
|
|
pComp->GetComponentVersion = vcil_out_GetComponentVersion; |
|
pComp->ComponentDeInit = vcil_out_ComponentDeInit; |
|
pComp->SetCallbacks = vcil_out_SetCallbacks; |
|
pComp->GetState = vcil_out_GetState; |
|
pComp->GetParameter = vcil_out_GetParameter; |
|
pComp->SetParameter = vcil_out_SetParameter; |
|
pComp->GetConfig = vcil_out_GetConfig; |
|
pComp->SetConfig = vcil_out_SetConfig; |
|
pComp->SendCommand = vcil_out_SendCommand; |
|
pComp->UseBuffer = vcil_out_UseBuffer; |
|
pComp->AllocateBuffer = vcil_out_AllocateBuffer; |
|
pComp->FreeBuffer = vcil_out_FreeBuffer; |
|
pComp->EmptyThisBuffer = vcil_out_EmptyThisBuffer; |
|
pComp->FillThisBuffer = vcil_out_FillThisBuffer; |
|
pComp->ComponentTunnelRequest = vcil_out_ComponentTunnelRequest; |
|
pComp->GetExtensionIndex = vcil_out_GetExtensionIndex; |
|
pComp->UseEGLImage = vcil_out_UseEGLImage; |
|
pComp->ComponentRoleEnum = vcil_out_ComponentRoleEnum; |
|
|
|
return resp.err; |
|
} |
|
|
|
/* callbacks */ |
|
|
|
void vcil_out_event_handler(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen) |
|
{ |
|
IL_EVENT_HANDLER_EXECUTE_T *exe = call; |
|
OMX_COMPONENTTYPE *pComp = exe->reference; |
|
VC_PRIVATE_COMPONENT_T *comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
*rlen = 0; |
|
|
|
vcos_assert(comp->callbacks.EventHandler); |
|
comp->callbacks.EventHandler(pComp, comp->callback_state, exe->event, exe->data1, exe->data2, exe->eventdata); |
|
} |
|
|
|
// Called on host side via RPC in response to empty buffer completing |
|
void vcil_out_empty_buffer_done(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen) |
|
{ |
|
IL_PASS_BUFFER_EXECUTE_T *exe = call; |
|
OMX_COMPONENTTYPE *pComp = exe->reference; |
|
VC_PRIVATE_COMPONENT_T *comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
OMX_BUFFERHEADERTYPE *pHeader = exe->bufferHeader.pOutputPortPrivate; |
|
OMX_U8 *pBuffer = pHeader->pBuffer; |
|
OMX_PTR *pAppPrivate = pHeader->pAppPrivate; |
|
OMX_PTR *pPlatformPrivate = pHeader->pPlatformPrivate; |
|
OMX_PTR *pInputPortPrivate = pHeader->pInputPortPrivate; |
|
OMX_PTR *pOutputPortPrivate = pHeader->pOutputPortPrivate; |
|
|
|
memcpy(pHeader, &exe->bufferHeader, sizeof(OMX_BUFFERHEADERTYPE)); |
|
|
|
pHeader->pBuffer = pBuffer; |
|
pHeader->pAppPrivate = pAppPrivate; |
|
pHeader->pPlatformPrivate = pPlatformPrivate; |
|
pHeader->pInputPortPrivate = pInputPortPrivate; |
|
pHeader->pOutputPortPrivate = pOutputPortPrivate; |
|
|
|
*rlen = 0; |
|
|
|
vcos_assert(comp->callbacks.EmptyBufferDone); |
|
comp->callbacks.EmptyBufferDone(pComp, comp->callback_state, pHeader); |
|
} |
|
|
|
// Called on host side via RPC in response to a fill-buffer completing |
|
// on the VideoCore side. ->pBuffer is a real pointer. |
|
void vcil_out_fill_buffer_done(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen) |
|
{ |
|
OMX_COMPONENTTYPE *pComp; |
|
VC_PRIVATE_COMPONENT_T *comp; |
|
OMX_BUFFERHEADERTYPE *pHeader; |
|
|
|
pHeader = ilcs_receive_buffer(st->ilcs, call, clen, &pComp); |
|
*rlen = 0; |
|
|
|
if(pHeader) |
|
{ |
|
comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate; |
|
|
|
vc_assert(comp->callbacks.FillBufferDone); |
|
comp->callbacks.FillBufferDone(pComp, comp->callback_state, pHeader); |
|
} |
|
}
|
|
|