mirror of
https://github.com/Qortal/Brooklyn.git
synced 2025-02-07 06:44:18 +00:00
918 lines
30 KiB
C
918 lines
30 KiB
C
/*
|
|
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);
|
|
}
|
|
}
|