/*
* Copyright (c) 2013, Texas Instruments Incorporated
* 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 Texas Instruments Incorporated 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 OWNER 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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <semaphore.h>
/* IPC Headers */
#include <ti/ipc/mm/MmRpc.h>
/* DCE Headers */
#include "libdce.h"
#include "dce_rpc.h"
#include "dce_priv.h"
#include "memplugin.h"
/***************** GLOBALS ***************************/
/* Handle used for Remote Communication */
MmRpc_Handle MmRpcHandle[MAX_REMOTEDEVICES] = { NULL};
Engine_Handle gEngineHandle[MAX_INSTANCES][MAX_REMOTEDEVICES] = { {NULL, NULL}};
MmRpc_Handle MmRpcCallbackHandle = NULL;
static int MmRpcCallback_count = 0;
#ifdef BUILDOS_LINUX
pthread_mutex_t ipc_mutex;
pthread_mutex_t dce_callback_mutex;
#else
pthread_mutex_t ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t dce_callback_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
static int __ClientCount[MAX_REMOTEDEVICES] = {0};
int dce_debug = DCE_DEBUG_LEVEL;
const String DCE_DEVICE_NAME[MAX_REMOTEDEVICES]= {"rpmsg-dce","rpmsg-dce-dsp"};
const String DCE_CALLBACK_NAME = "dce-callback";
typedef struct {
XDAS_UInt32 codec_handle;
XDM_DataSyncHandle local_dataSyncHandle;
XDM_DataSyncDesc *local_dataSyncDesc;
XDAS_Int32 getDataFlag;
XDM_DataSyncGetFxn (*local_get_DataFxn) (XDM_DataSyncHandle, XDM_DataSyncDesc*);
XDAS_Int32 putDataFlag;
XDM_DataSyncGetFxn (*local_put_DataFxn) (XDM_DataSyncHandle, XDM_DataSyncDesc*);
XDAS_Int32 getBufferFlag;
pthread_t getDataFxn_thread;
pthread_t putDataFxn_thread;
sem_t sem_dec_row_mode;
sem_t sem_enc_row_mode;
int row_mode;
int first_control;
int receive_numBlocks;
int total_numBlocks;
} CallbackFlag;
static CallbackFlag callbackmsg[MAX_INSTANCES];
/***************** INLINE FUNCTIONS ******************/
static inline int get_callback(Uint32 codec)
{
int i;
for (i = 0; i < MAX_INSTANCES; i++) {
if( callbackmsg[i].codec_handle == codec ) {
return i;
}
}
return -1;
}
static inline int update_clients_table(Engine_Handle engine, int core)
{
int i;
for(i = 0; i < MAX_INSTANCES; i++)
{
if( gEngineHandle[i][core] == 0 ) {
gEngineHandle[i][core] = engine;
return i;
}
}
return -1;
}
static inline void Fill_MmRpc_fxnCtx(MmRpc_FxnCtx *fxnCtx, int fxn_id, int num_params, int num_xlts, MmRpc_Xlt *xltAry)
{
fxnCtx->fxn_id = fxn_id;
fxnCtx->num_params = num_params;
fxnCtx->num_xlts = num_xlts;
fxnCtx->xltAry = xltAry;
}
static inline void Fill_MmRpc_fxnCtx_OffPtr_Params(MmRpc_Param *mmrpc_params, int size, void *base, int offset, size_t handle)
{
mmrpc_params->type = MmRpc_ParamType_OffPtr;
mmrpc_params->param.offPtr.size = (size_t)size;
mmrpc_params->param.offPtr.base = (size_t)base;
mmrpc_params->param.offPtr.offset = (size_t)offset;
mmrpc_params->param.offPtr.handle = handle;
}
static inline void Fill_MmRpc_fxnCtx_Ptr_Params(MmRpc_Param *mmrpc_params, int size, void *addr, size_t handle)
{
mmrpc_params->type = MmRpc_ParamType_Ptr;
mmrpc_params->param.ptr.size = size;
mmrpc_params->param.ptr.addr = (size_t)addr;
mmrpc_params->param.ptr.handle = handle;
}
static inline void Fill_MmRpc_fxnCtx_Scalar_Params(MmRpc_Param *mmrpc_params, int size, int data)
{
mmrpc_params->type = MmRpc_ParamType_Scalar;
mmrpc_params->param.scalar.size = size;
mmrpc_params->param.scalar.data = (size_t)data;
}
static inline void Fill_MmRpc_fxnCtx_Xlt_Array(MmRpc_Xlt *mmrpc_xlt, int index, int32_t offset, size_t base, size_t handle)
{
/* index : index of params filled in FxnCtx */
/* offset : calculated from address of index */
mmrpc_xlt->index = index;
mmrpc_xlt->offset = offset;
mmrpc_xlt->base = base;
mmrpc_xlt->handle = handle;
}
static int __inline getCoreIndexFromName(String name)
{
if( name == NULL )
return INVALID_CORE;
if( !strcmp(name,"ivahd_vidsvr") )
return IPU;
else if( !strcmp(name, "dsp_vidsvr") )
return DSP;
else
return INVALID_CORE;
}
static int __inline getCoreIndexFromCodec(int codec_id)
{
if( codec_id == OMAP_DCE_VIDENC2 || codec_id == OMAP_DCE_VIDDEC3 )
return IPU;
else if( codec_id == OMAP_DCE_VIDDEC2 )
return DSP;
else
return INVALID_CORE;
}
static int __inline getCoreIndexFromEngine(Engine_Handle engine, int *tabIdx)
{
int i;
int core = INVALID_CORE;
*tabIdx = -1;
for(i = 0; i < MAX_INSTANCES ; i++) {
if( engine == gEngineHandle[i][IPU] ) {
core = IPU;
*tabIdx = i;
break;
}
else if( engine == gEngineHandle[i][DSP] ) {
*tabIdx = i;
core = DSP;
break;
}
}
return core;
}
/***************** FUNCTIONS ********************************************/
/* Interface for QNX/Linux for parameter buffer allocation */
/* These interfaces are implemented to maintain Backward Compatability */
void *dce_alloc(int sz)
{
/*
Beware: The last argument is a bit field. As of now only core ID
is considered to be there in the last 4 bits of the word
*/
return (memplugin_alloc(sz, 1, DEFAULT_REGION, 0, IPU));
}
void dce_free(void *ptr)
{
memplugin_free(ptr);
}
/* dce_callback_putDataFxn is a callback function that runs on different Thread id. */
/* It is an infinite loop notifying client when partial output data is available when outputDataMode = IVIDEO_ROWMODE. */
int dce_callback_putDataFxn(void *codec)
{
MmRpc_FxnCtx fxnCtx;
int32_t fxnRet;
int32_t return_callback;
dce_error_status eError = DCE_EOK;
XDM_DataSyncHandle *codec_handle = (XDM_DataSyncHandle *) codec;
int id;
DEBUG("======================START======================== codec_handle 0x%x", (unsigned int) *codec_handle);
id = get_callback((Uint32) *codec_handle);
if( id < 0 ) {
ERROR("Cannot find the entry in callbackmsg");
} else {
(callbackmsg[id]).local_dataSyncHandle = *codec_handle;
/* This is called from VIDDEC3_process, so we can start telling client to get the output data and provide the numBlocks info. */
/* Call the callback function specified in the dynParams->putDataFxn */
while (1) {
if( (callbackmsg[id]).putDataFlag == 1 ) {
DEBUG("lock (callbackmsg[%d]).putDataFxn_thread 0x%x (callbackmsg[%d]).local_dataSyncHandle 0x%x",
id, (callbackmsg[id]).putDataFxn_thread, id, (unsigned int) (callbackmsg[id]).local_dataSyncHandle);
pthread_mutex_lock(&dce_callback_mutex);
if( (callbackmsg[id]).row_mode ) {
/* Marshall function arguments into the send callback information to codec for put_DataFxn */
Fill_MmRpc_fxnCtx(&fxnCtx, DCE_CALLBACK_RPC_PUT_DATAFXN, 2, 0, NULL);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[0]), sizeof(int32_t), (int32_t) (callbackmsg[id]).local_dataSyncHandle);
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[1]), GetSz((callbackmsg[id]).local_dataSyncDesc), (void *) P2H((callbackmsg[id]).local_dataSyncDesc),
sizeof(MemHeader), memplugin_share((callbackmsg[id]).local_dataSyncDesc));
DEBUG("Calling MmRpc_call on MmRpcCallbackHandle %p", MmRpcCallbackHandle);
eError = MmRpc_call(MmRpcCallbackHandle, &fxnCtx, &fxnRet);
_ASSERT(eError == DCE_EOK, DCE_EIPC_CALL_FAIL);
/* When this return it means that Codec has called DCE Server with putDataFxn callback that has the numBlock information. */
/* At this point, codec should have filled the outputBuffer pointer that is passed in VIDDEC3_process. */
DEBUG("From codec (callbackmsg[%d]).local_dataSyncHandle %p (callbackmsg[%d]).local_dataSyncDesc->numBlocks %d ",
id, (callbackmsg[id]).local_dataSyncHandle, id, (int32_t) (callbackmsg[id]).local_dataSyncDesc->numBlocks);
if( (callbackmsg[id]).local_dataSyncDesc->numBlocks ) {
(callbackmsg[id]).receive_numBlocks += (callbackmsg[id]).local_dataSyncDesc->numBlocks;
return_callback = (int32_t) ((callbackmsg[id]).local_put_DataFxn)((callbackmsg[id]).local_dataSyncHandle, (callbackmsg[id]).local_dataSyncDesc);
if( return_callback < 0 ) {
/* dce_callback_putDataFxn getting no output data saved when calling the callback. Ignore and continue. */
ERROR("Received return_callback %d when asking client to save the output Data of (callbackmsg[%d]).numBlock %d",
return_callback, id, (callbackmsg[id]).local_dataSyncDesc->numBlocks);
}
DEBUG("(callbackmsg[%d]).local_dataSyncHandle %p (callbackmsg[%d]).receive_numBlocks %d >= (callbackmsg[%d]).total_numBlocks %d (callbackmsg[%d]).putDataFlag %d",
id, (callbackmsg[id]).local_dataSyncHandle, id, (callbackmsg[id]).receive_numBlocks, id, (callbackmsg[id]).total_numBlocks, id, (callbackmsg[id]).putDataFlag);
} else {
/* dce_callback_putDataFxn getting 0 numBlocks from DCE server. Need to stop the loop as it indicates VIDDEC3_process will be returned*/
DEBUG("dce_callback_putDataFxn is getting (callbackmsg[%d]).numBlock %d when calling putDataFxn callback",
id, (callbackmsg[id]).local_dataSyncDesc->numBlocks);
(callbackmsg[id]).putDataFlag = 0;
}
DEBUG("unlock (callbackmsg[%d]).putDataFxn_thread 0x%x (callbackmsg[%d]).local_dataSyncHandle %p",
id, (callbackmsg[id]).putDataFxn_thread, id, (callbackmsg[id]).local_dataSyncHandle);
pthread_mutex_unlock(&dce_callback_mutex);
}
} else if( (callbackmsg[id]).putDataFlag == 2 ) {
/* Receive an indication to clean up and exit the thread. */
DEBUG("CLEAN UP indication due to (callbackmsg[%d]).putDataFlag %d is set.", id, (callbackmsg[id]).putDataFlag);
pthread_exit(0);
} else {
DEBUG("Do nothing (callbackmsg[%d]).local_dataSyncHandle 0x%x because (callbackmsg[%d]).putDataFlag %d is not 1.",
id, (unsigned int)(callbackmsg[id]).local_dataSyncHandle, id, (callbackmsg[id]).putDataFlag);
if ((callbackmsg[id]).receive_numBlocks) {
(callbackmsg[id]).receive_numBlocks = 0;
DEBUG("Signal sem_dec_row_mode as VIDDEC3_process might wait before returning to client.");
sem_post(&((callbackmsg[id]).sem_dec_row_mode));
}
sem_wait(&((callbackmsg[id]).sem_dec_row_mode));
}
}
}
EXIT:
DEBUG("======================END======================== codec_handle 0x%x", (unsigned int) *codec_handle);
return (0);
}
/* dce_callback_getDataFxn is running on different Thread id. */
/* It is an infinite loop request to client for more input data when inputDataMode = IVIDEO_ROWMODE. */
int dce_callback_getDataFxn(void *codec)
{
MmRpc_FxnCtx fxnCtx;
int32_t fxnRet;
int32_t return_callback;
dce_error_status eError = DCE_EOK;
XDM_DataSyncHandle *codec_handle = (XDM_DataSyncHandle *) codec;
int id;
DEBUG("======================START========================");
DEBUG(" >> dce_callback_getDataFxn codec_handle 0x%x", (unsigned int) *codec_handle);
id = get_callback((Uint32) *codec_handle);
if( id < 0 ) {
ERROR("Cannot find the entry in callbackmsg");
} else {
(callbackmsg[id]).local_dataSyncHandle = *codec_handle;
/* This is called from VIDENC2_process, so we can start request client to fill in input and provide the row information written. */
/* Call the callback function specified in the dynParams->getDataFxn */
while( 1 ) {
if( (callbackmsg[id]).getDataFlag == 1 ) {
DEBUG("lock (callbackmsg[%d]).getDataFxn_thread 0x%x (callbackmsg[%d]).local_dataSyncHandle %p",
id, (callbackmsg[id]).getDataFxn_thread, id, (callbackmsg[id]).local_dataSyncHandle);
pthread_mutex_lock(&dce_callback_mutex);
if( (callbackmsg[id]).row_mode ) {
/* Calling client callback function to pass data received from IVA-HD codec */
return_callback = (int32_t) ((callbackmsg[id]).local_get_DataFxn)((callbackmsg[id]).local_dataSyncHandle, (callbackmsg[id]).local_dataSyncDesc);
if( return_callback < 0 ) {
/* dce_callback_getDataFxn getting error when calling the callback. Ignore and re-try. */
ERROR("dce_callback_getDataFxn is getting return_callback %d when calling getDataFxn callback. Retry callback for more data.", return_callback);
} else {
(callbackmsg[id]).receive_numBlocks += (callbackmsg[id]).local_dataSyncDesc->numBlocks;
if( (callbackmsg[id]).local_dataSyncDesc->numBlocks ) {
/* Marshall function arguments into the send callback information to codec for get_dataFxn */
Fill_MmRpc_fxnCtx(&fxnCtx, DCE_CALLBACK_RPC_GET_DATAFXN, 2, 0, NULL);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[0]), sizeof(int32_t), (int32_t) (callbackmsg[id]).local_dataSyncHandle);
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[1]), GetSz((callbackmsg[id]).local_dataSyncDesc), (void *) P2H((callbackmsg[id]).local_dataSyncDesc),
sizeof(MemHeader), memplugin_share((callbackmsg[id]).local_dataSyncDesc));
eError = MmRpc_call(MmRpcCallbackHandle, &fxnCtx, &fxnRet);
_ASSERT(eError == DCE_EOK, DCE_EIPC_CALL_FAIL);
DEBUG("(callbackmsg[%d]).local_dataSyncHandle %p (callbackmsg[%d]).receive_numBlocks %d >= (callbackmsg[%d]).total_numBlocks %d",
id, (callbackmsg[id]).local_dataSyncHandle, id, (callbackmsg[id]).receive_numBlocks, id, (callbackmsg[id]).total_numBlocks);
if( (callbackmsg[id]).receive_numBlocks >= (callbackmsg[id]).total_numBlocks ) {
/* one full frame has been sent to codec. Need to stop the callback call to client. */
/* it will be resumed once VIDENC2_process for the next one. */
(callbackmsg[id]).receive_numBlocks = 0;
(callbackmsg[id]).getDataFlag = 0;
DEBUG("Setting the (callbackmsg[%d]).getDataFlag to 0 to stop calling client to fill", id);
}
} else {
/* dce_callback_getDataFxn getting 0 numBlocks when calling the callback. Ignore and re-try. */
DEBUG("Received dataSyncDesc->numBlocks == 0 meaning the callback thread has no data -ignore.");
}
}
DEBUG("unlock (callbackmsg[%d]).getDataFxn_thread 0x%x (callbackmsg[%d]).local_dataSyncHandle %p",
id, (callbackmsg[id]).getDataFxn_thread, id, (callbackmsg[id]).local_dataSyncHandle);
pthread_mutex_unlock(&dce_callback_mutex);
}
} else if( (callbackmsg[id]).getDataFlag == 2 ) {
/* Receive an indication to clean up and exit the thread. */
DEBUG("CLEAN UP indication due to (callbackmsg[%d]).getDataFlag %d is set.", id, (callbackmsg[id]).getDataFlag);
pthread_exit(0);
} else {
DEBUG("Do nothing (callbackmsg[%d]).local_dataSyncHandle 0x%x because msg-getDataFlag %d is not 1.",
id, (unsigned int)(callbackmsg[id]).local_dataSyncHandle, (callbackmsg[id]).getDataFlag);
sem_wait(&((callbackmsg[id]).sem_enc_row_mode));
}
}
}
EXIT:
DEBUG(" << dce_callback_getDataFxn COMPLETE");
DEBUG("======================END========================");
return (0);
}
/*=====================================================================================*/
/** dce_ipc_init : Initialize MmRpc. This function is called within Engine_open().
*
* @ return : Error Status.
*/
int dce_ipc_init(int core)
{
MmRpc_Params args;
dce_error_status eError = DCE_EOK;
DEBUG(" >> dce_ipc_init\n");
/*First check if maximum clients are already using ipc*/
if( __ClientCount[core] >= MAX_INSTANCES ) {
eError = DCE_EXDM_UNSUPPORTED;
return (eError);
}
/* Create remote server insance */
__ClientCount[core]++;
if( __ClientCount[core] > 1 ) {
goto EXIT;
}
MmRpc_Params_init(&args);
eError = MmRpc_create(DCE_DEVICE_NAME[core], &args, &MmRpcHandle[core]);
_ASSERT_AND_EXECUTE(eError == DCE_EOK, DCE_EIPC_CREATE_FAIL, __ClientCount[core]--);
DEBUG("open(/dev/%s]) -> 0x%x\n", DCE_DEVICE_NAME[core], (int)MmRpcHandle[core]);
EXIT:
return (eError);
}
/*=====================================================================================*/
/** dce_ipc_deinit : DeInitialize MmRpc. This function is called within
* Engine_close().
*/
void dce_ipc_deinit(int core, int tableIdx)
{
if( __ClientCount[core] == 0 ) {
DEBUG("Nothing to be done: a spurious call\n");
return;
}
__ClientCount[core]--;
if ( tableIdx >= 0 )
gEngineHandle[tableIdx][core] = 0;
if( __ClientCount[core] > 0 ) {
goto EXIT;
}
if( MmRpcHandle[core] != NULL ) {
MmRpc_delete(&MmRpcHandle[core]);
MmRpcHandle[core] = NULL;
}
EXIT:
return;
}
/*===============================================================*/
/** Engine_open : Open Codec Engine.
*
* @ param attrs [in] : Engine Attributes. This param is not passed to Remote core.
* @ param name [in] : Name of Encoder or Decoder codec.
* @ param ec [out] : Error returned by Codec Engine.
* @ return : Codec Engine Handle is returned to be used to create codec.
* In case of error, NULL is returned as Engine Handle.
*/
Engine_Handle Engine_open(String name, Engine_Attrs *attrs, Engine_Error *ec)
{
MmRpc_FxnCtx fxnCtx;
dce_error_status eError = DCE_EOK;
dce_engine_open *engine_open_msg = NULL;
Engine_Attrs *engine_attrs = NULL;
Engine_Handle engine_handle = NULL;
int coreIdx = INVALID_CORE;
int tabIdx = -1;
DEBUG("START Engine_open ipc_mutex 0x%x", (unsigned int) &ipc_mutex);
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
_ASSERT(name != '\0', DCE_EINVALID_INPUT);
coreIdx = getCoreIndexFromName(name);
_ASSERT(coreIdx != INVALID_CORE, DCE_EINVALID_INPUT);
/* Initialize IPC. In case of Error Deinitialize them */
_ASSERT(dce_ipc_init(coreIdx) == DCE_EOK, DCE_EIPC_CREATE_FAIL);
INFO(">> Engine_open Params::name = %s size = %d\n", name, strlen(name));
/* Allocate Shared memory for the engine_open rpc msg structure*/
/* Tiler Memory preferred in QNX */
engine_open_msg = memplugin_alloc(sizeof(dce_engine_open), 1, DEFAULT_REGION, 0, coreIdx);
_ASSERT_AND_EXECUTE(engine_open_msg != NULL, DCE_EOUT_OF_MEMORY, engine_handle = NULL);
if( attrs ) {
engine_attrs = memplugin_alloc(sizeof(Engine_Attrs), 1, DEFAULT_REGION, 0, coreIdx);
_ASSERT_AND_EXECUTE(engine_attrs != NULL, DCE_EOUT_OF_MEMORY, engine_handle = NULL);
*engine_attrs = *attrs;
}
/* Populating the msg structure with all the params */
/* Populating all params into a struct avoid individual address translations of name, ec */
strncpy(engine_open_msg->name, name, strlen(name));
engine_open_msg->engine_attrs = engine_attrs;
/* Marshall function arguments into the send buffer */
Fill_MmRpc_fxnCtx(&fxnCtx, DCE_RPC_ENGINE_OPEN, 1, 0, NULL);
Fill_MmRpc_fxnCtx_OffPtr_Params(fxnCtx.params, GetSz(engine_open_msg), (void *)P2H(engine_open_msg),
sizeof(MemHeader), memplugin_share(engine_open_msg));
/* Invoke the Remote function through MmRpc */
eError = MmRpc_call(MmRpcHandle[coreIdx], &fxnCtx, (int32_t *)(&engine_handle));
if( ec ) {
*ec = engine_open_msg->error_code;
}
/* In case of Error, the Application will get a NULL Engine Handle */
_ASSERT_AND_EXECUTE(eError == DCE_EOK, DCE_EIPC_CALL_FAIL, engine_handle = NULL);
/*Update table*/
tabIdx = update_clients_table(engine_handle, coreIdx);
_ASSERT((tabIdx != -1), DCE_EINVALID_INPUT);
EXIT:
memplugin_free(engine_open_msg);
if( engine_attrs ) {
memplugin_free(engine_attrs);
}
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
DEBUG("END Engine_open ipc_mutex 0x%x", (unsigned int) &ipc_mutex);
return ((Engine_Handle)engine_handle);
}
/*===============================================================*/
/** Engine_close : Close Engine.
*
* @ param engine [in] : Engine Handle obtained in Engine_open() call.
*/
Void Engine_close(Engine_Handle engine)
{
MmRpc_FxnCtx fxnCtx;
int32_t fxnRet;
dce_error_status eError = DCE_EOK;
int32_t coreIdx = INVALID_CORE;
int tableIdx = -1;
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
_ASSERT(engine != NULL, DCE_EINVALID_INPUT);
/* Marshall function arguments into the send buffer */
Fill_MmRpc_fxnCtx(&fxnCtx, DCE_RPC_ENGINE_CLOSE, 1, 0, NULL);
Fill_MmRpc_fxnCtx_Scalar_Params(fxnCtx.params, sizeof(Engine_Handle), (int32_t)engine);
coreIdx = getCoreIndexFromEngine(engine, &tableIdx);
_ASSERT(coreIdx != INVALID_CORE,DCE_EINVALID_INPUT);
/* Invoke the Remote function through MmRpc */
eError = MmRpc_call(MmRpcHandle[coreIdx], &fxnCtx, &fxnRet);
_ASSERT(eError == DCE_EOK, DCE_EIPC_CALL_FAIL);
EXIT:
if( coreIdx != INVALID_CORE )
dce_ipc_deinit(coreIdx, tableIdx);
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
return;
}
/*===============================================================*/
/** get_rproc_info : Get Information from the Remote proc.
*
* @ param engine [in] : Engine Handle obtained in Engine_open() call.
* @ param info_type [in] : Information type as defined in the rproc_info_type
+ */
int32_t get_rproc_info(Engine_Handle engine, rproc_info_type info_type)
{
MmRpc_FxnCtx fxnCtx;
int32_t fxnRet;
dce_error_status eError = DCE_EOK;
int32_t coreIdx = INVALID_CORE;
int tableIdx = -1;
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
_ASSERT(engine != NULL, DCE_EINVALID_INPUT);
/* Marshall function arguments into the send buffer */
Fill_MmRpc_fxnCtx(&fxnCtx, DCE_RPC_GET_INFO, 1, 0, NULL);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[0]), sizeof(rproc_info_type), (int32_t)info_type);
coreIdx = getCoreIndexFromEngine(engine, &tableIdx);
_ASSERT(coreIdx != INVALID_CORE,DCE_EINVALID_INPUT);
/* Invoke the Remote function through MmRpc */
eError = MmRpc_call(MmRpcHandle[coreIdx], &fxnCtx, &fxnRet);
_ASSERT(eError == DCE_EOK, DCE_EIPC_CALL_FAIL);
EXIT:
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
return fxnRet;
}
/*===============================================================*/
/** Functions create(), control(), get_version(), process(), delete() are common codec
* glue function signatures which are same for both encoder and decoder
*/
/*===============================================================*/
/** create : Create Encoder/Decoder codec.
*
* @ param engine [in] : Engine Handle obtained in Engine_open() call.
* @ param name [in] : Name of Encoder or Decoder codec.
* @ param params [in] : Static parameters of codec.
* @ param codec_id [in] : To differentiate between Encoder and Decoder codecs.
* @ return : Codec Handle is returned to be used for control, process, delete calls.
* In case of error, NULL is returned.
*/
static void *create(Engine_Handle engine, String name, void *params, dce_codec_type codec_id)
{
MmRpc_FxnCtx fxnCtx;
dce_error_status eError = DCE_EOK;
void *codec_handle = NULL;
char *codec_name = NULL;
int coreIdx = INVALID_CORE;
_ASSERT(name != '\0', DCE_EINVALID_INPUT);
_ASSERT(engine != NULL, DCE_EINVALID_INPUT);
_ASSERT(params != NULL, DCE_EINVALID_INPUT);
coreIdx = getCoreIndexFromCodec(codec_id);
_ASSERT(coreIdx != INVALID_CORE, DCE_EINVALID_INPUT);
/* Allocate shared memory for translating codec name to IPU */
codec_name = memplugin_alloc(MAX_NAME_LENGTH * sizeof(char), 1, DEFAULT_REGION, 0, coreIdx);
_ASSERT_AND_EXECUTE(codec_name != NULL, DCE_EOUT_OF_MEMORY, codec_handle = NULL);
strncpy(codec_name, name, strlen(name));
/* Marshall function arguments into the send buffer */
Fill_MmRpc_fxnCtx(&fxnCtx, DCE_RPC_CODEC_CREATE, 4, 0, NULL);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[0]), sizeof(int32_t), codec_id);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[1]), sizeof(Engine_Handle), (int32_t)engine);
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[2]), GetSz(codec_name), P2H(codec_name),
sizeof(MemHeader), memplugin_share(codec_name));
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[3]), GetSz(params), P2H(params),
sizeof(MemHeader), memplugin_share(params));
/* Invoke the Remote function through MmRpc */
eError = MmRpc_call(MmRpcHandle[coreIdx], &fxnCtx, (int32_t *)(&codec_handle));
/* In case of Error, the Application will get a NULL Codec Handle */
_ASSERT_AND_EXECUTE(eError == DCE_EOK, DCE_EIPC_CALL_FAIL, codec_handle = NULL);
EXIT:
memplugin_free(codec_name);
return ((void *)codec_handle);
}
/*===============================================================*/
/** control : Codec control call.
*
* @ param codec [in] : Codec Handle obtained in create() call.
* @ param id [in] : Command id for XDM control operation.
* @ param dynParams [in] : Dynamic input parameters to Codec.
* @ param status [out] : Codec returned status parameters.
* @ param codec_id [in] : To differentiate between Encoder and Decoder codecs.
* @ return : Status of control() call is returned.
* #XDM_EOK [0] : Success.
* #XDM_EFAIL [-1] : Failure.
* #IPC_FAIL [-2] : MmRpc Call failed.
* #XDM_EUNSUPPORTED [-3] : Unsupported request.
* #OUT_OF_MEMORY [-4] : Out of Shared Memory.
*/
static XDAS_Int32 control(void *codec, int id, void *dynParams, void *status, dce_codec_type codec_id)
{
MmRpc_FxnCtx fxnCtx;
int32_t fxnRet = XDM_EFAIL;
dce_error_status eError = DCE_EOK;
int coreIdx = INVALID_CORE;
_ASSERT(codec != NULL, DCE_EINVALID_INPUT);
_ASSERT(dynParams != NULL, DCE_EINVALID_INPUT);
_ASSERT(status != NULL, DCE_EINVALID_INPUT);
coreIdx = getCoreIndexFromCodec(codec_id);
_ASSERT(coreIdx != INVALID_CORE, DCE_EINVALID_INPUT);
/* Marshall function arguments into the send buffer */
Fill_MmRpc_fxnCtx(&fxnCtx, DCE_RPC_CODEC_CONTROL, 5, 0, NULL);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[0]), sizeof(int32_t), codec_id);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[1]), sizeof(int32_t), (int32_t)codec);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[2]), sizeof(int32_t), (int32_t)id);
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[3]), GetSz(dynParams), P2H(dynParams),
sizeof(MemHeader), memplugin_share(dynParams));
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[4]), GetSz(status), P2H(status),
sizeof(MemHeader), memplugin_share(status));
/* Invoke the Remote function through MmRpc */
eError = MmRpc_call(MmRpcHandle[coreIdx], &fxnCtx, &fxnRet);
_ASSERT(eError == DCE_EOK, DCE_EIPC_CALL_FAIL);
EXIT:
return (fxnRet);
}
/*===============================================================*/
/** get_version : Codec control call to get the codec version. This call has been made
* separate from control call because it involves an additional version
* buffer translation.
*
* @ param codec [in] : Codec Handle obtained in create() call.
* @ param id [in] : Command id for XDM control operation.
* @ param dynParams [in] : Dynamic input parameters to Codec.
* @ param status [out] : Codec returned status parameters.
* @ param codec_id [in] : To differentiate between Encoder and Decoder codecs.
* @ return : Status of control() call is returned.
* #XDM_EOK [0] : Success.
* #XDM_EFAIL [-1] : Failure.
* #IPC_FAIL [-2] : MmRpc Call failed.
* #XDM_EUNSUPPORTED [-3] : Unsupported request.
* #OUT_OF_MEMORY [-4] : Out of Shared Memory.
*/
static XDAS_Int32 get_version(void *codec, void *dynParams, void *status, dce_codec_type codec_id)
{
MmRpc_FxnCtx fxnCtx;
MmRpc_Xlt xltAry;
void * *version_buf = NULL;
int32_t fxnRet = XDM_EFAIL;
dce_error_status eError = DCE_EOK;
int coreIdx = INVALID_CORE;
_ASSERT(codec != NULL, DCE_EINVALID_INPUT);
_ASSERT(dynParams != NULL, DCE_EINVALID_INPUT);
_ASSERT(status != NULL, DCE_EINVALID_INPUT);
coreIdx = getCoreIndexFromCodec(codec_id);
_ASSERT(coreIdx != INVALID_CORE, DCE_EINVALID_INPUT);
if( codec_id == OMAP_DCE_VIDDEC3 ) {
version_buf = (void * *)(&(((IVIDDEC3_Status *)status)->data.buf));
} else if( codec_id == OMAP_DCE_VIDENC2 ) {
version_buf = (void * *)(&(((IVIDENC2_Status *)status)->data.buf));
} else if( codec_id == OMAP_DCE_VIDDEC2 ) {
version_buf = (void * *)(&(((IVIDDEC2_Status *)status)->data.buf));
}
_ASSERT(*version_buf != NULL, DCE_EINVALID_INPUT);
/* Marshall function arguments into the send buffer */
Fill_MmRpc_fxnCtx(&fxnCtx, DCE_RPC_CODEC_GET_VERSION, 4, 1, &xltAry);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[0]), sizeof(int32_t), codec_id);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[1]), sizeof(int32_t), (int32_t)codec);
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[2]), GetSz(dynParams), P2H(dynParams),
sizeof(MemHeader), memplugin_share(dynParams));
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[3]), GetSz(status), P2H(status),
sizeof(MemHeader), memplugin_share(status));
/* Address Translation needed for buffer for version Info */
Fill_MmRpc_fxnCtx_Xlt_Array(fxnCtx.xltAry, 3,
MmRpc_OFFSET((int32_t)status, (int32_t)version_buf),
(size_t)P2H(*version_buf), memplugin_share(*version_buf));
/* Invoke the Remote function through MmRpc */
eError = MmRpc_call(MmRpcHandle[coreIdx], &fxnCtx, &fxnRet);
_ASSERT(eError == DCE_EOK, DCE_EIPC_CALL_FAIL);
EXIT:
return (fxnRet);
}
typedef enum process_call_params {
CODEC_ID_INDEX = 0,
CODEC_HANDLE_INDEX,
INBUFS_INDEX,
OUTBUFS_INDEX,
INARGS_INDEX,
OUTARGS_INDEX,
OUTBUFS_PTR_INDEX
} process_call_params;
#define LUMA_BUF 0
#define CHROMA_BUF 1
/*===============================================================*/
/** process : Encode/Decode process.
*
* @ param codec [in] : Codec Handle obtained in create() call.
* @ param inBufs [in] : Input buffer details.
* @ param outBufs [in] : Output buffer details.
* @ param inArgs [in] : Input arguments.
* @ param outArgs [out] : Output arguments.
* @ param codec_id [in] : To differentiate between Encoder and Decoder codecs.
* @ return : Status of the process call.
* #XDM_EOK [0] : Success.
* #XDM_EFAIL [-1] : Failure.
* #IPC_FAIL [-2] : MmRpc Call failed.
* #XDM_EUNSUPPORTED [-3] : Unsupported request.
*/
static XDAS_Int32 process(void *codec, void *inBufs, void *outBufs,
void *inArgs, void *outArgs, dce_codec_type codec_id)
{
MmRpc_FxnCtx fxnCtx;
MmRpc_Xlt xltAry[MAX_TOTAL_BUF];
int fxnRet, count, total_count, numInBufs = 0, numOutBufs = 0;
dce_error_status eError = DCE_EOK;
void **data_buf = NULL;
void **buf_arry = NULL;
void **bufSize_arry = NULL;
int numXltAry, numParams;
int coreIdx = INVALID_CORE;
#ifdef BUILDOS_ANDROID
int32_t inbuf_offset[MAX_INPUT_BUF];
int32_t outbuf_offset[MAX_OUTPUT_BUF];
#endif
_ASSERT(codec != NULL, DCE_EINVALID_INPUT);
_ASSERT(inBufs != NULL, DCE_EINVALID_INPUT);
_ASSERT(outBufs != NULL, DCE_EINVALID_INPUT);
_ASSERT(inArgs != NULL, DCE_EINVALID_INPUT);
_ASSERT(outArgs != NULL, DCE_EINVALID_INPUT);
coreIdx = getCoreIndexFromCodec(codec_id);
_ASSERT(coreIdx != INVALID_CORE, DCE_EINVALID_INPUT);
if( codec_id == OMAP_DCE_VIDDEC3 ) {
numInBufs = ((XDM2_BufDesc *)inBufs)->numBufs;
numOutBufs = ((XDM2_BufDesc *)outBufs)->numBufs;
numXltAry = numInBufs + numOutBufs;
numParams = 6;
} else if( codec_id == OMAP_DCE_VIDENC2 ) {
numInBufs = ((IVIDEO2_BufDesc *)inBufs)->numPlanes;
numOutBufs = ((XDM2_BufDesc *)outBufs)->numBufs;
numXltAry = numInBufs + numOutBufs;
numParams = 6;
} else if( codec_id == OMAP_DCE_VIDDEC2 ) {
numInBufs = ((XDM1_BufDesc *)inBufs)->numBufs;
numOutBufs = ((XDM_BufDesc *)outBufs)->numBufs;
numXltAry = numInBufs + numOutBufs + MAX_OUTPUT_BUFPTRS;/* 2 extra needed for bufs and bufSizes */
numParams = 7;
} else{
eError = DCE_EXDM_UNSUPPORTED;
return eError;
}
/* marshall function arguments into the send buffer */
/* Approach [2] as explained in "Notes" used for process */
Fill_MmRpc_fxnCtx(&fxnCtx, DCE_RPC_CODEC_PROCESS, numParams, numXltAry, xltAry);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[CODEC_ID_INDEX]), sizeof(int32_t), codec_id);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[CODEC_HANDLE_INDEX]), sizeof(int32_t), (int32_t)codec);
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[INBUFS_INDEX]), GetSz(inBufs), P2H(inBufs),
sizeof(MemHeader), memplugin_share(inBufs));
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[OUTBUFS_INDEX]), GetSz(outBufs), P2H(outBufs),
sizeof(MemHeader), memplugin_share(outBufs));
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[INARGS_INDEX]), GetSz(inArgs), P2H(inArgs),
sizeof(MemHeader), memplugin_share(inArgs));
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[OUTARGS_INDEX]), GetSz(outArgs), P2H(outArgs),
sizeof(MemHeader), memplugin_share(outArgs));
/* InBufs, OutBufs, InArgs, OutArgs buffer need translation but since they have been */
/* individually mentioned as fxnCtx Params, they need not be mentioned below again */
/* Input and Output Buffers have to be mentioned for translation */
for( count = 0, total_count = 0; count < numInBufs; count++, total_count++ ) {
if( codec_id == OMAP_DCE_VIDDEC3 ) {
data_buf = (void * *)(&(((XDM2_BufDesc *)inBufs)->descs[count].buf));
} else if( codec_id == OMAP_DCE_VIDENC2 ) {
data_buf = (void * *)(&(((IVIDEO2_BufDesc *)inBufs)->planeDesc[count].buf));
} else if( codec_id == OMAP_DCE_VIDDEC2 ) {
data_buf = (void * *)(&(((XDM1_BufDesc *)inBufs)->descs[count].buf));
}
#ifdef BUILDOS_ANDROID
inbuf_offset[count] = ((MemHeader*)(*data_buf))->offset;
Fill_MmRpc_fxnCtx_Xlt_Array(&(fxnCtx.xltAry[total_count]), INBUFS_INDEX, MmRpc_OFFSET((int32_t)inBufs,
(int32_t)data_buf), (size_t)(*data_buf),
(size_t)(((MemHeader*)(*data_buf))->dma_buf_fd));
*data_buf += inbuf_offset[count];
#else
Fill_MmRpc_fxnCtx_Xlt_Array(&(fxnCtx.xltAry[total_count]), INBUFS_INDEX,
MmRpc_OFFSET((int32_t)inBufs, (int32_t)data_buf),
(size_t)*data_buf, (size_t)*data_buf);
#ifdef BUILDOS_LINUX
/*Single planar input buffer for Encoder. No adjustments needed for Multiplanar case*/
if( count == CHROMA_BUF && codec_id == OMAP_DCE_VIDENC2 && ((IVIDEO2_BufDesc *)inBufs)->planeDesc[LUMA_BUF].buf == ((IVIDEO2_BufDesc *)inBufs)->planeDesc[CHROMA_BUF].buf ) {
if( ((IVIDEO2_BufDesc *)inBufs)->planeDesc[count].memType == XDM_MEMTYPE_RAW ||
((IVIDEO2_BufDesc *)inBufs)->planeDesc[count].memType == XDM_MEMTYPE_TILEDPAGE )
*data_buf += ((IVIDEO2_BufDesc *)inBufs)->planeDesc[LUMA_BUF].bufSize.bytes;
else
*data_buf += ((IVIDEO2_BufDesc *)inBufs)->planeDesc[LUMA_BUF].bufSize.tileMem.width *
((IVIDEO2_BufDesc *)inBufs)->planeDesc[LUMA_BUF].bufSize.tileMem.height;
}
#endif //BUILDOS_LINUX
#endif //BUILDOS_ANDROID
}
/* Output Buffers */
for( count = 0; count < numOutBufs; count++, total_count++ ) {
if( codec_id == OMAP_DCE_VIDENC2 || codec_id == OMAP_DCE_VIDDEC3 ) {
if( ((XDM2_BufDesc *)outBufs)->descs[LUMA_BUF].buf != ((XDM2_BufDesc *)outBufs)->descs[CHROMA_BUF].buf ) {
/* Either Encode usecase or MultiPlanar Buffers for Decode usecase */
data_buf = (void * *)(&(((XDM2_BufDesc *)outBufs)->descs[count].buf));
#ifdef BUILDOS_ANDROID
outbuf_offset[count] = ((MemHeader*)(*data_buf))->offset;
Fill_MmRpc_fxnCtx_Xlt_Array(&(fxnCtx.xltAry[total_count]), OUTBUFS_INDEX, MmRpc_OFFSET((int32_t)outBufs,
(int32_t)data_buf), (size_t)(*data_buf),
(size_t)(((MemHeader*)(*data_buf))->dma_buf_fd));
*data_buf += outbuf_offset[count];
#else
Fill_MmRpc_fxnCtx_Xlt_Array(&(fxnCtx.xltAry[total_count]), OUTBUFS_INDEX,
MmRpc_OFFSET((int32_t)outBufs, (int32_t)data_buf),
(size_t)*data_buf, (size_t)*data_buf);
#endif
}
#if defined(BUILDOS_LINUX)
else {
/* SinglePlanar Buffers for Decode usecase*/
data_buf = (void * *)(&(((XDM2_BufDesc *)outBufs)->descs[count].buf));
Fill_MmRpc_fxnCtx_Xlt_Array(&(fxnCtx.xltAry[total_count]), OUTBUFS_INDEX,
MmRpc_OFFSET((int32_t)outBufs, (int32_t)data_buf),
(size_t)*data_buf, (size_t)*data_buf);
if( count == CHROMA_BUF ) {
if( ((XDM2_BufDesc *)outBufs)->descs[count].memType == XDM_MEMTYPE_RAW ||
((XDM2_BufDesc *)outBufs)->descs[count].memType == XDM_MEMTYPE_TILEDPAGE ) {
*data_buf += ((XDM2_BufDesc *)outBufs)->descs[LUMA_BUF].bufSize.bytes;
} else {
*data_buf += ((XDM2_BufDesc *)outBufs)->descs[LUMA_BUF].bufSize.tileMem.width *
((XDM2_BufDesc *)outBufs)->descs[LUMA_BUF].bufSize.tileMem.height;
}
}
}
#endif
} else if( codec_id == OMAP_DCE_VIDDEC2 ) {
if( count == LUMA_BUF ) {
buf_arry = (void * *)(&(((XDM_BufDesc *)outBufs)->bufs));
Fill_MmRpc_fxnCtx_Xlt_Array(&(fxnCtx.xltAry[total_count]), OUTBUFS_INDEX,
MmRpc_OFFSET((int32_t)outBufs, (int32_t)buf_arry),
(size_t)P2H(*buf_arry), (size_t)memplugin_share(*buf_arry));
total_count++;
bufSize_arry = (void * *)(&(((XDM_BufDesc *)outBufs)->bufSizes));
Fill_MmRpc_fxnCtx_Xlt_Array(&(fxnCtx.xltAry[total_count]), OUTBUFS_INDEX,
MmRpc_OFFSET((int32_t)outBufs, (int32_t)bufSize_arry),
(size_t)P2H(*bufSize_arry), (size_t)memplugin_share(*bufSize_arry));
total_count++;
}
Fill_MmRpc_fxnCtx_OffPtr_Params(&(fxnCtx.params[OUTBUFS_PTR_INDEX]), GetSz(*buf_arry), P2H(*buf_arry),
sizeof(MemHeader), memplugin_share(*buf_arry));
data_buf = (void * *)(&(((XDM_BufDesc *)outBufs)->bufs[count]));
Fill_MmRpc_fxnCtx_Xlt_Array(&(fxnCtx.xltAry[total_count]), OUTBUFS_PTR_INDEX,
MmRpc_OFFSET((int32_t)*buf_arry, (int32_t)data_buf), (size_t)*data_buf, (size_t)*data_buf);
}
}
/* Invoke the Remote function through MmRpc */
eError = MmRpc_call(MmRpcHandle[coreIdx], &fxnCtx, &fxnRet);
_ASSERT(eError == DCE_EOK, DCE_EIPC_CALL_FAIL);
#ifdef BUILDOS_ANDROID
for( count = 0; count < numInBufs; count++ ) {
if( codec_id == OMAP_DCE_VIDDEC3 ) {
/* restore the actual buf ptr before returing to the mmf */
data_buf = (void * *)(&(((XDM2_BufDesc *)inBufs)->descs[count].buf));
} else if( codec_id == OMAP_DCE_VIDDEC2 ) {
/* restore the actual buf ptr before returing to the mmf */
data_buf = (void * *)(&(((XDM1_BufDesc *)inBufs)->descs[count].buf));
}
*data_buf -= inbuf_offset[count];
}
for (count = 0; count < numOutBufs; count++){
data_buf = (void * *)(&(((XDM2_BufDesc *)outBufs)->descs[count].buf));
*data_buf -= outbuf_offset[count];
}
#endif
eError = (dce_error_status)(fxnRet);
EXIT:
return (eError);
}
/*===============================================================*/
/** delete : Delete Encode/Decode codec instance.
*
* @ param codec [in] : Codec Handle obtained in create() call.
* @ param codec_id [in] : To differentiate between Encoder and Decoder codecs.
* @ return : None.
*/
static void delete(void *codec, dce_codec_type codec_id)
{
MmRpc_FxnCtx fxnCtx;
int32_t fxnRet;
dce_error_status eError = DCE_EOK;
int coreIdx = INVALID_CORE;
_ASSERT(codec != NULL, DCE_EINVALID_INPUT);
coreIdx = getCoreIndexFromCodec(codec_id);
_ASSERT(coreIdx != INVALID_CORE, DCE_EINVALID_INPUT);
/* Marshall function arguments into the send buffer */
Fill_MmRpc_fxnCtx(&fxnCtx, DCE_RPC_CODEC_DELETE, 2, 0, NULL);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[0]), sizeof(int32_t), codec_id);
Fill_MmRpc_fxnCtx_Scalar_Params(&(fxnCtx.params[1]), sizeof(int32_t), (int32_t)codec);
/* Invoke the Remote function through MmRpc */
eError = MmRpc_call(MmRpcHandle[coreIdx], &fxnCtx, &fxnRet);
_ASSERT(eError == DCE_EOK, DCE_EIPC_CALL_FAIL);
EXIT:
return;
}
/***************** VIDDEC3 Decoder Codec Engine Functions ****************/
VIDDEC3_Handle VIDDEC3_create(Engine_Handle engine, String name,
VIDDEC3_Params *params)
{
VIDDEC3_Handle codec = NULL;
MmRpc_Params args;
dce_error_status eError = DCE_EOK;
int id;
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
id = get_callback(0);
if (id < 0) {
/* This is depended on the MAX_INSTANCE, by default it handles only 5 instances of codec instance (full frame or low latency) */
ERROR("Failed because too many codec clients, Max is %d. MAX_INSTANCES default needs to be changed if required.", MAX_INSTANCES);
goto EXIT;
} else { /* Found empty array to be populated */
if( params->outputDataMode == IVIDEO_NUMROWS ) {
(callbackmsg[id]).row_mode = 1;
(callbackmsg[id]).first_control = TRUE;
(callbackmsg[id]).total_numBlocks = params->maxHeight / 16;
DEBUG("callbackmsg[%d]->total_numBlocks %d", id, (callbackmsg[id]).total_numBlocks);
(callbackmsg[id]).local_dataSyncDesc = memplugin_alloc(sizeof(XDM_DataSyncDesc), 1, DEFAULT_REGION, 0, IPU);
DEBUG("Checking local_dataSyncDesc %p local_put_DataFxn %p local_dataSyncHandle %p",
(callbackmsg[id]).local_dataSyncDesc, (callbackmsg[id]).local_put_DataFxn, (callbackmsg[id]).local_dataSyncHandle);
if( (callbackmsg[id]).local_dataSyncDesc == NULL ) {
goto EXIT;
}
/* Create sem_dec_row_mode */
sem_init(&((callbackmsg[id]).sem_dec_row_mode), 0, 0);
DEBUG("MmRpcCallbackHandle 0x%x MmRpcCallback_count %d", (int)MmRpcCallbackHandle, MmRpcCallback_count);
if( !MmRpcCallbackHandle ) {
/* Need to create another MmRpcHandle for codec callback */
MmRpc_Params_init(&args);
eError = MmRpc_create(DCE_CALLBACK_NAME, &args, &MmRpcCallbackHandle);
_ASSERT_AND_EXECUTE(eError == DCE_EOK, DCE_EIPC_CREATE_FAIL, MmRpcCallbackHandle = NULL);
DEBUG("open(/dev/%s]) -> 0x%x\n", DCE_CALLBACK_NAME, (int)MmRpcCallbackHandle);
}
MmRpcCallback_count++;
} else if( params->outputDataMode == IVIDEO_ENTIREFRAME ) {
(callbackmsg[id]).row_mode = 0; /* full frame; the other parameters are not used in full frame mode */
} else {
ERROR("outputDataMode %d is not supported.", params->outputDataMode);
goto EXIT;
}
DEBUG("Checking row_mode %d first_control %d",
(callbackmsg[id]).row_mode, (callbackmsg[id]).first_control);
}
DEBUG(">> engine=%p, name=%s, params=%p", engine, name, params);
codec = create(engine, name, params, OMAP_DCE_VIDDEC3);
DEBUG("<< codec=%p", codec);
if( params->outputDataMode == IVIDEO_NUMROWS ) {
(callbackmsg[id]).codec_handle = (XDAS_UInt32) codec;
DEBUG("Saving the codec %p to (callbackmsg[%d]).codec_handle = 0x%x", codec, id, (unsigned int) (callbackmsg[id]).codec_handle);
}
EXIT:
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
return (codec);
}
XDAS_Int32 VIDDEC3_control(VIDDEC3_Handle codec, VIDDEC3_Cmd cmd_id,
VIDDEC3_DynamicParams *dynParams, VIDDEC3_Status *status)
{
XDAS_Int32 ret;
int id;
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
id = get_callback((Uint32) codec);
if( id < 0 ) {
DEBUG("Could not find the entry; control on full frame mode");
} else {
DEBUG("Checking codec_handle 0x%x row_mode %d first_control %d",
(unsigned int) (callbackmsg[id]).codec_handle, (callbackmsg[id]).row_mode, (callbackmsg[id]).first_control);
if( (callbackmsg[id]).row_mode && (callbackmsg[id]).first_control ) {
/* dynParams has the function callback; store the information as it will get overwritten by the M4 codec for their own callback Fxn. */
(callbackmsg[id]).local_put_DataFxn = (void*) dynParams->putDataFxn;
(callbackmsg[id]).local_dataSyncHandle = dynParams->putDataHandle;
(callbackmsg[id]).first_control = FALSE;
DEBUG("Set callback pointer local_get_dataFxn %p local_dataSyncHandle %p",
(callbackmsg[id]).local_put_DataFxn, (callbackmsg[id]).local_dataSyncHandle);
}
if( cmd_id == XDM_FLUSH ) {
DEBUG("FLUSH HAS BEEN ORDERED");
}
}
DEBUG(">> codec=%p, cmd_id=%d, dynParams=%p, status=%p",
codec, cmd_id, dynParams, status);
if( cmd_id == XDM_GETVERSION ) {
ret = get_version(codec, dynParams, status, OMAP_DCE_VIDDEC3);
} else {
ret = control(codec, cmd_id, dynParams, status, OMAP_DCE_VIDDEC3);
}
DEBUG("dynParams->putDataFxn %p", dynParams->putDataFxn);
DEBUG("<< ret=%d", ret);
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
return (ret);
}
XDAS_Int32 VIDDEC3_process(VIDDEC3_Handle codec,
XDM2_BufDesc *inBufs, XDM2_BufDesc *outBufs,
VIDDEC3_InArgs *inArgs, VIDDEC3_OutArgs *outArgs)
{
XDAS_Int32 ret;
pthread_attr_t attr;
int id;
DEBUG(">> codec=%p, inBufs=%p, outBufs=%p, inArgs=%p, outArgs=%p",
codec, inBufs, outBufs, inArgs, outArgs);
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
id = get_callback((Uint32) codec);
if( id < 0 ) {
DEBUG("Received VIDDEC3_process for ENTIRE/FULL FRAME decoding.");
} else {
pthread_mutex_lock(&dce_callback_mutex);
DEBUG("Checking row_mode %d SETTING (callbackmsg[id]).putDataFlag = 0", (callbackmsg[id]).row_mode);
if( (callbackmsg[id]).row_mode ) {
(callbackmsg[id]).putDataFlag = 0;
DEBUG("Checking callbackmsg[%d]->putDataFxn_thread %p", id, (void*) (callbackmsg[id]).putDataFxn_thread);
if( !(callbackmsg[id]).putDataFxn_thread ) {
/* Need to start a new thread for the callback handling to request for data - process call will be synchronous. */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if( pthread_create(&((callbackmsg[id]).putDataFxn_thread), &attr, (void*)dce_callback_putDataFxn, (void*) &codec) ) {
pthread_mutex_unlock(&ipc_mutex);
return DCE_EXDM_FAIL;
}
}
DEBUG("Checking thread callbackmsg[%d]->putDataFxn_thread %p", id, (void*) (callbackmsg[id]).putDataFxn_thread);
/* Start the callback to get putDataFxn from codec to client. */
(callbackmsg[id]).putDataFlag = 1;
sem_post(&((callbackmsg[id]).sem_dec_row_mode));
DEBUG("Start the callback to client callbackmsg[%d]->putDataFlag %d on callbackmsg[%d]->local_dataSyncHandle 0x%x",
id, (callbackmsg[id]).putDataFlag, id, (unsigned int) (callbackmsg[id]).local_dataSyncHandle);
}
pthread_mutex_unlock(&dce_callback_mutex);
}
ret = process(codec, inBufs, outBufs, inArgs, outArgs, OMAP_DCE_VIDDEC3);
DEBUG("<< ret=%d", ret);
if( (id >= 0) && ((callbackmsg[id]).row_mode) ) {
DEBUG("(callbackmsg[%d]).receive_numBlocks %d >= (callbackmsg[%d]).total_numBlocks %d",
id, (callbackmsg[id]).receive_numBlocks, id, (callbackmsg[id]).total_numBlocks);
if( (callbackmsg[id]).receive_numBlocks >= (callbackmsg[id]).total_numBlocks ) {
DEBUG("Stop the callback to client callbackmsg[%d]->putDataFlag %d reach full frame (callbackmsg[%d]).receive_numBlocks %d",
id, (callbackmsg[id]).putDataFlag, id, (callbackmsg[id]).receive_numBlocks);
(callbackmsg[id]).putDataFlag = 0;
if ((callbackmsg[id]).receive_numBlocks) {
DEBUG("Waiting for dce_callback_putDataFxn to be in waiting case.");
sem_wait(&((callbackmsg[id]).sem_dec_row_mode));
}
}
}
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
return (ret);
}
Void VIDDEC3_delete(VIDDEC3_Handle codec)
{
void *res;
int id;
DEBUG(">> codec=%p", codec);
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
id = get_callback((Uint32) codec);
if( id < 0 ) {
DEBUG("Delete decode instance in full frame mode");
} else {
if( (callbackmsg[id]).row_mode ) {
MmRpcCallback_count--;
/* Exit the callback thread to request to client */
(callbackmsg[id]).putDataFlag = 2;
DEBUG("Exit the callback to client callbackmsg[%d]->getDataFlag %d callbackmsg[%d]->getDataFxn_thread %p",
id, (callbackmsg[id]).putDataFlag, id, (void*) ((callbackmsg[id]).putDataFxn_thread));
sem_post(&((callbackmsg[id]).sem_dec_row_mode));
pthread_join((callbackmsg[id]).putDataFxn_thread, (void*) &res);
DEBUG("PTHREAD_JOIN res %d", (int) res);
/* Clean up the allocation earlier. */
memplugin_free((callbackmsg[id]).local_dataSyncDesc);
/* Destroy sem_dec_row_mode */
sem_destroy(&((callbackmsg[id]).sem_dec_row_mode));
DEBUG("Checking on MmRpcCallback_count %d MmRpcCallbackHandle 0x%x", MmRpcCallback_count, (unsigned int) MmRpcCallbackHandle);
if( MmRpcCallback_count == 0 && MmRpcCallbackHandle != NULL ) {
MmRpc_delete(&MmRpcCallbackHandle);
MmRpcCallbackHandle = NULL;
}
}
}
delete(codec, OMAP_DCE_VIDDEC3);
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
DEBUG("<<");
}
/***************** VIDENC2 Encoder Codec Engine Functions ****************/
VIDENC2_Handle VIDENC2_create(Engine_Handle engine, String name,
VIDENC2_Params *params)
{
VIDENC2_Handle codec = NULL;
MmRpc_Params args;
dce_error_status eError = DCE_EOK;
int id;
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
id = get_callback(0);
if( id < 0 ) {
/* This is depended on the MAX_INSTANCE, by default it handles only 5 instances of codec instance (full frame or low latency) */
ERROR("Failed because too many codec clients, Max is %d. MAX_INSTANCES default needs to be changed if required.", MAX_INSTANCES);
goto EXIT;
} else { /* Found empty array to be populated */
if( params->inputDataMode == IVIDEO_NUMROWS ) {
(callbackmsg[id]).row_mode = 1;
(callbackmsg[id]).first_control = TRUE;
(callbackmsg[id]).total_numBlocks = params->maxHeight / 16;
DEBUG("callbackmsg[%d]->total_numBlocks %d", id, (callbackmsg[id]).total_numBlocks);
/* Create sem_dec_row_mode */
sem_init(&((callbackmsg[id]).sem_enc_row_mode), 0, 0);
(callbackmsg[id]).local_dataSyncDesc = memplugin_alloc(sizeof(XDM_DataSyncDesc), 1, DEFAULT_REGION, 0, IPU);
DEBUG("Checking local_dataSyncDesc %p local_get_DataFxn %p local_dataSyncHandle %p",
(callbackmsg[id]).local_dataSyncDesc, (callbackmsg[id]).local_get_DataFxn, (callbackmsg[id]).local_dataSyncHandle);
if( (callbackmsg[id]).local_dataSyncDesc == NULL ) {
goto EXIT;
}
if( !MmRpcCallbackHandle ) {
/* Need to create another MmRpcHandle for codec callback */
MmRpc_Params_init(&args);
eError = MmRpc_create(DCE_CALLBACK_NAME, &args, &MmRpcCallbackHandle);
_ASSERT_AND_EXECUTE(eError == DCE_EOK, DCE_EIPC_CREATE_FAIL, MmRpcCallbackHandle = NULL);
DEBUG("open(/dev/%s]) -> 0x%x\n", DCE_CALLBACK_NAME, (int)MmRpcCallbackHandle);
}
MmRpcCallback_count++;
} else if( params->inputDataMode == IVIDEO_ENTIREFRAME ) {
(callbackmsg[id]).row_mode = 0; /* full frame; the other parameters are not used in full frame mode */
} else {
ERROR("inputDataMode %d is not supported.", params->inputDataMode);
goto EXIT;
}
DEBUG("Checking row_mode %d first_control %d", (callbackmsg[id]).row_mode, (callbackmsg[id]).first_control);
}
DEBUG(">> engine=%p, name=%s, params=%p", engine, name, params);
codec = create(engine, name, params, OMAP_DCE_VIDENC2);
DEBUG("<< codec=%p", codec);
if( params->inputDataMode == IVIDEO_NUMROWS ) {
(callbackmsg[id]).codec_handle = (XDAS_UInt32) codec;
}
EXIT:
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
return (codec);
}
XDAS_Int32 VIDENC2_control(VIDENC2_Handle codec, VIDENC2_Cmd cmd_id,
VIDENC2_DynamicParams *dynParams, VIDENC2_Status *status)
{
XDAS_Int32 ret;
int id;
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
id = get_callback((Uint32) codec);
if( id < 0 ) {
DEBUG("Could not find the entry in callbackmsg array; might not be rowmode; should be full frame mode");
} else {
DEBUG("Checking row_mode %d first_control %d", (callbackmsg[id]).row_mode, (callbackmsg[id]).first_control);
if( (callbackmsg[id]).row_mode && (callbackmsg[id]).first_control ) {
/* dynParams has the function callback; store the information as it will get overwritten by the M4 codec for their own callback Fxn. */
(callbackmsg[id]).local_get_DataFxn = (void*) dynParams->getDataFxn;
(callbackmsg[id]).local_dataSyncHandle = dynParams->getDataHandle;
(callbackmsg[id]).first_control = FALSE;
DEBUG("Set callback pointer local_get_dataFxn %p local_dataSyncHandle %p", (callbackmsg[id]).local_get_DataFxn, (callbackmsg[id]).local_dataSyncHandle);
}
}
DEBUG(">> codec=%p, cmd_id=%d, dynParams=%p, status=%p",
codec, cmd_id, dynParams, status);
if( cmd_id == XDM_GETVERSION ) {
ret = get_version(codec, dynParams, status, OMAP_DCE_VIDENC2);
} else {
ret = control(codec, cmd_id, dynParams, status, OMAP_DCE_VIDENC2);
}
DEBUG("<< ret=%d", ret);
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
return (ret);
}
XDAS_Int32 VIDENC2_process(VIDENC2_Handle codec,
IVIDEO2_BufDesc *inBufs, XDM2_BufDesc *outBufs,
VIDENC2_InArgs *inArgs, VIDENC2_OutArgs *outArgs)
{
XDAS_Int32 ret = 0;
pthread_attr_t attr;
int id;
DEBUG(">> codec=%p, inBufs=%p, outBufs=%p, inArgs=%p, outArgs=%p",
codec, inBufs, outBufs, inArgs, outArgs);
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
id = get_callback((Uint32) codec);
if( id < 0 ) {
DEBUG("Received VIDENC2_process for ENTIRE FRAME encoding because no entry found in callbackmsg");
} else {
DEBUG("Checking row_mode %d", (callbackmsg[id]).row_mode);
if( (callbackmsg[id]).row_mode ) {
(callbackmsg[id]).getDataFlag = 0;
DEBUG("Checking callbackmsg[%d]->getDataFxn_thread 0x%x", id, (callbackmsg[id]).getDataFxn_thread);
if( !(callbackmsg[id]).getDataFxn_thread ) {
/* Need to start a new thread for the callback handling to request for data - process call will be synchronous. */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if( pthread_create(&((callbackmsg[id]).getDataFxn_thread), &attr, (void*)dce_callback_getDataFxn, (void*) &codec) ) {
pthread_mutex_unlock(&ipc_mutex);
return DCE_EXDM_FAIL;
}
}
DEBUG("Create thread callbackmsg[%d]->getDataFxn_thread 0x%x", id, (unsigned int) (callbackmsg[id]).getDataFxn_thread);
/* Start the callback to request to client */
(callbackmsg[id]).getDataFlag = 1;
sem_post(&((callbackmsg[id]).sem_enc_row_mode));
DEBUG("Start the callback to client (callbackmsg[%d]).getDataFlag %d on (callbackmsg[%d]).local_dataSyncHandle 0x%x",
id, (callbackmsg[id]).getDataFlag, id, (unsigned int) (callbackmsg[id]).local_dataSyncHandle);
}
}
ret = process(codec, inBufs, outBufs, inArgs, outArgs, OMAP_DCE_VIDENC2);
DEBUG("<< ret=%d", ret);
if( (id >= 0) && ((callbackmsg[id]).row_mode) ) {
/* Stop the callback to request to client */
DEBUG("Stop the callback to client callbackmsg[%d]->getDataFlag %d", id, (callbackmsg[id]).getDataFlag);
(callbackmsg[id]).getDataFlag = 0;
}
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
return (ret);
}
Void VIDENC2_delete(VIDENC2_Handle codec)
{
void *res;
int id;
DEBUG(">> codec=%p", codec);
/*Acquire permission to use IPC*/
pthread_mutex_lock(&ipc_mutex);
id = get_callback((Uint32) codec);
if( id < 0 ) {
DEBUG("Delete encode instance in full frame mode");
} else {
if( (callbackmsg[id]).row_mode ) {
MmRpcCallback_count--;
/* Exit the callback thread to request to client */
(callbackmsg[id]).getDataFlag = 2;
DEBUG("Exit the callback to client (callbackmsg[%d]).getDataFlag %d (callbackmsg[%d]).getDataFxn_thread 0x%x",
id, (callbackmsg[id]).getDataFlag, id, (unsigned int) (callbackmsg[id]).getDataFxn_thread);
sem_post(&((callbackmsg[id]).sem_enc_row_mode));
pthread_join((callbackmsg[id]).getDataFxn_thread, (void*) &res);
DEBUG("PTHREAD_JOIN res %d", (int) res);
/* Clean up the allocation earlier. */
memplugin_free((callbackmsg[id]).local_dataSyncDesc);
/* Destroy sem_dec_row_mode */
sem_destroy(&((callbackmsg[id]).sem_enc_row_mode));
DEBUG("Check on MmRpcCallback_count %d", MmRpcCallback_count);
if( MmRpcCallback_count == 0 && MmRpcCallbackHandle != NULL ) {
MmRpc_delete(&MmRpcCallbackHandle);
MmRpcCallbackHandle = NULL;
}
}
}
delete(codec, OMAP_DCE_VIDENC2);
/*Relinquish IPC*/
pthread_mutex_unlock(&ipc_mutex);
DEBUG("<<");
}
/***************** VIDDEC2 Decoder Codec Engine Functions ****************/
VIDDEC2_Handle VIDDEC2_create(Engine_Handle engine, String name,
VIDDEC2_Params *params)
{
VIDDEC2_Handle codec;
DEBUG(">> engine=%p, name=%s, params=%p", engine, name, params);
codec = create(engine, name, params, OMAP_DCE_VIDDEC2);
DEBUG("<< codec=%p", codec);
return (codec);
}
XDAS_Int32 VIDDEC2_control(VIDDEC2_Handle codec, VIDDEC2_Cmd id,
VIDDEC2_DynamicParams *dynParams, VIDDEC2_Status *status)
{
XDAS_Int32 ret;
DEBUG(">> codec=%p, id=%d, dynParams=%p, status=%p",
codec, id, dynParams, status);
if( id == XDM_GETVERSION ) {
ret = get_version(codec, dynParams, status, OMAP_DCE_VIDDEC2);
} else {
ret = control(codec, id, dynParams, status, OMAP_DCE_VIDDEC2);
}
DEBUG("<< ret=%d", ret);
return (ret);
}
XDAS_Int32 VIDDEC2_process(VIDDEC2_Handle codec,
XDM1_BufDesc *inBufs, XDM_BufDesc *outBufs,
VIDDEC2_InArgs *inArgs, VIDDEC2_OutArgs *outArgs)
{
XDAS_Int32 ret;
DEBUG(">> codec=%p, inBufs=%p, outBufs=%p, inArgs=%p, outArgs=%p",
codec, inBufs, outBufs, inArgs, outArgs);
ret = process(codec, inBufs, outBufs, inArgs, outArgs, OMAP_DCE_VIDDEC2);
DEBUG("<< ret=%d", ret);
return (ret);
}
Void VIDDEC2_delete(VIDDEC2_Handle codec)
{
DEBUG(">> codec=%p", codec);
delete(codec, OMAP_DCE_VIDDEC2);
DEBUG("<<");
}