sdk-hwV1.3/external/eyesee-mpp/middleware/sun8iw21/media/component/AudioDec_Component.c

2791 lines
109 KiB
C
Executable File

/******************************************************************************
Copyright (C), 2001-2016, Allwinner Tech. Co., Ltd.
******************************************************************************
File Name : AudioDec_Component.c
Version : Initial Draft
Author : Allwinner BU3-PD2 Team
Created : 2016/08/28
Last Modified :
Description : mpp component implement
Function List :
History :
******************************************************************************/
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioDec_Component"
#include <utils/plat_log.h>
//ref platform headers
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/prctl.h>
#include <assert.h>
#include "plat_type.h"
#include "plat_errno.h"
#include "plat_defines.h"
#include "plat_math.h"
#include "cdx_list.h"
//media api headers to app
#include "SystemBase.h"
#include "mm_common.h"
#include "mm_comm_adec.h"
#include "mpi_adec.h"
//media internal common headers.
#include "media_common.h"
#include <media_common_acodec.h>
#include "mm_component.h"
#include "ComponentCommon.h"
#include "tmessage.h"
#include "tsemaphore.h"
#include "adecoder.h"
#include <AdecCompStream.h>
#include <AdecStream.h>
#include <EncodedStream.h>
#include <DemuxCompStream.h>
#include "AudioDec_Component.h"
#include <CDX_Common.h>
#include <CdxTypes.h>
//------------------------------------------------------------------------------------
//#define DEBUG_INPORT_BUFFER_INFO
static void* ComponentThread(void* pThreadData);
static void* InputThread(void* pThreadData);
#define INPUT_BUF_COUNT (1)
ERRORTYPE AudioDec_InputDataInit(AUDIODEC_INPUT_DATA *pInputData, AUDIODECDATATYPE *pAudioDecData)
{
ERRORTYPE eError = SUCCESS;
memset(pInputData, 0x0, sizeof(AUDIODEC_INPUT_DATA));
// Init input thread data
pInputData->state = COMP_StateLoaded;
pthread_mutex_init(&pInputData->mStateLock, NULL);
pthread_condattr_t condAttr;
pthread_condattr_init(&condAttr);
pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
int err = pthread_cond_init(&pInputData->mStateCond, &condAttr);
if (err != 0)
{
aloge("fatal error! input thread mStateCond init fail!");
}
err = pthread_cond_init(&pInputData->mAbsFullCond, &condAttr);
if (err != 0)
{
aloge("fatal error! pthread cond init fail!");
}
pInputData->mWaitAbsValidFlag = FALSE;
pInputData->nRequestLen = 0;
INIT_LIST_HEAD(&pInputData->mIdleAbsList);
INIT_LIST_HEAD(&pInputData->mReadyAbsList);
INIT_LIST_HEAD(&pInputData->mUsingAbsList);
pthread_mutex_init(&pInputData->mAbsListLock, NULL);
DMXPKT_NODE_T *pNode;
int i;
pthread_mutex_lock(&pInputData->mAbsListLock);
for (i = 0; i < INPUT_BUF_COUNT; i++)
{
pNode = (DMXPKT_NODE_T*)malloc(sizeof(DMXPKT_NODE_T));
if(pNode == NULL)
{
aloge("fatal error! malloc fail!");
eError = ERR_ADEC_NOMEM;
pthread_mutex_unlock(&pInputData->mAbsListLock);
goto EXIT6;
}
memset(pNode, 0, sizeof(DMXPKT_NODE_T));
list_add_tail(&pNode->mList, &pInputData->mIdleAbsList);
pInputData->mNodeNum++;
}
pthread_mutex_unlock(&pInputData->mAbsListLock);
pInputData->pAudioDecData = pAudioDecData;
if (message_create(&pInputData->cmd_queue)<0)
{
aloge("create input cmd queue error!");
eError = ERR_ADEC_NOMEM;
goto EXIT6;
}
err = pthread_create(&pInputData->thread_id, NULL, InputThread, pInputData);
if (err || !pInputData->thread_id)
{
eError = ERR_ADEC_NOMEM;
goto EXIT7;
}
pthread_condattr_destroy(&condAttr);
return SUCCESS;
EXIT7:
message_destroy(&pInputData->cmd_queue);
EXIT6:
{
DMXPKT_NODE_T *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pInputData->mIdleAbsList, mList)
{
list_del(&pEntry->mList);
free(pEntry);
}
}
pthread_mutex_destroy(&pInputData->mStateLock);
pthread_condattr_destroy(&condAttr);
pthread_cond_destroy(&pInputData->mStateCond);
pthread_cond_destroy(&pInputData->mAbsFullCond);
pthread_mutex_destroy(&pInputData->mAbsListLock);
return eError;
}
ERRORTYPE AudioDec_InputDataDestroy(AUDIODEC_INPUT_DATA *pInputData)
{
ERRORTYPE eError = SUCCESS;
message_t msg;
msg.command = Stop;
put_message(&pInputData->cmd_queue, &msg);
// Wait for thread to exit so we can get the status into "error"
pthread_join(pInputData->thread_id, (void*)&eError);
message_destroy(&pInputData->cmd_queue);
DMXPKT_NODE_T *pEntry, *pTmp;
pthread_mutex_lock(&pInputData->mAbsListLock);
if (!list_empty(&pInputData->mIdleAbsList))
{
list_for_each_entry_safe(pEntry, pTmp, &pInputData->mIdleAbsList, mList)
{
list_del(&pEntry->mList);
free(pEntry);
}
}
if (!list_empty(&pInputData->mReadyAbsList))
{
list_for_each_entry_safe(pEntry, pTmp, &pInputData->mReadyAbsList, mList)
{
list_del(&pEntry->mList);
free(pEntry);
}
}
if (!list_empty(&pInputData->mUsingAbsList))
{
list_for_each_entry_safe(pEntry, pTmp, &pInputData->mUsingAbsList, mList)
{
list_del(&pEntry->mList);
free(pEntry);
}
}
pthread_mutex_unlock(&pInputData->mAbsListLock);
pthread_mutex_destroy(&pInputData->mAbsListLock);
pthread_mutex_destroy(&pInputData->mStateLock);
pthread_cond_destroy(&pInputData->mStateCond);
pthread_cond_destroy(&pInputData->mAbsFullCond);
return SUCCESS;
}
/*****************************************************************************/
ERRORTYPE AudioDecSendCommand(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_COMMANDTYPE Cmd,
PARAM_IN unsigned int nParam1,
PARAM_IN void* pCmdData)
{
ERRORTYPE eError = SUCCESS;
// Get component private data
AUDIODECDATATYPE* pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if (!pAudioDecData)
{
eError = ERR_ADEC_ILLEGAL_PARAM;
goto COMP_CONF_CMD_FAIL;
}
// Check state
if (pAudioDecData->state == COMP_StateInvalid)
{
eError = ERR_ADEC_SYS_NOTREADY;
goto COMP_CONF_CMD_FAIL;
}
// Trans command
CompInternalMsgType eCmd;
switch (Cmd)
{
case COMP_CommandStateSet:
eCmd = SetState;
if(nParam1 == COMP_StateLoaded)
pAudioDecData->force_exit = 1;
break;
case COMP_CommandFlush:
eCmd = Flush;
break;
case COMP_CommandPortDisable:
eCmd = StopPort;
break;
case COMP_CommandPortEnable:
eCmd = RestartPort;
break;
default:
alogw("impossible comp_command[0x%x]", Cmd);
eCmd = -1;
break;
}
message_t msg;
msg.command = eCmd;
msg.para0 = nParam1;
put_message(&pAudioDecData->cmd_queue, &msg);
COMP_CONF_CMD_FAIL:
return eError;
}
ERRORTYPE AudioDecGetPortDefinition(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_INOUT COMP_PARAM_PORTDEFINITIONTYPE *pPortDef)
{
ERRORTYPE eError = SUCCESS;
// Get component private data
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if (pPortDef->nPortIndex == pAudioDecData->sInPortDef.nPortIndex)
{
memcpy(pPortDef, &pAudioDecData->sInPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
}
else if (pPortDef->nPortIndex == pAudioDecData->sOutPortDef.nPortIndex)
{
memcpy(pPortDef, &pAudioDecData->sOutPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
}
else
{
eError = ERR_ADEC_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE AudioDecGetPortExtraDefinition(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_INOUT COMP_PARAM_PORTEXTRADEFINITIONTYPE *pPortExtraDef)
{
ERRORTYPE eError = SUCCESS;
//Get component private data
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if (pPortExtraDef->nPortIndex == pAudioDecData->sInPortExtraDef.nPortIndex)
{
memcpy(pPortExtraDef, &pAudioDecData->sInPortExtraDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
}
else if (pPortExtraDef->nPortIndex == pAudioDecData->sOutPortExtraDef.nPortIndex)
{
pAudioDecData->sOutPortExtraDef.pVendorInfo = pAudioDecData->sInPortExtraDef.pVendorInfo;
memcpy(pPortExtraDef, &pAudioDecData->sOutPortExtraDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
}
else
{
eError = ERR_ADEC_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE AudioDecSetPortDefinition(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_INOUT COMP_PARAM_PORTDEFINITIONTYPE *pPortDef)
{
ERRORTYPE eError = SUCCESS;
// Get component private data
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if (pPortDef->nPortIndex == pAudioDecData->sInPortDef.nPortIndex)
{
memcpy(&pAudioDecData->sInPortDef, pPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
}
else if (pPortDef->nPortIndex == pAudioDecData->sOutPortDef.nPortIndex)
{
memcpy(&pAudioDecData->sOutPortDef, pPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
}
else
{
eError = ERR_ADEC_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE AudioDecGetCompBufferSupplier(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_INOUT COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier)
{
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
//find nPortIndex
BOOL bFindFlag = FALSE;
int i;
for (i = 0; i < MAX_ADECODER_PORTS; i++)
{
if (pAudioDecData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex)
{
bFindFlag = TRUE;
memcpy(pPortBufSupplier, &pAudioDecData->sPortBufSupplier[i], sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE));
break;
}
}
if (bFindFlag)
{
eError = SUCCESS;
}
else
{
eError = ERR_ADEC_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE AudioDecSetCompBufferSupplier(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier)
{
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
//find nPortIndex
BOOL bFindFlag = FALSE;
int i;
for(i=0; i<MAX_ADECODER_PORTS; i++)
{
if(pAudioDecData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex)
{
bFindFlag = TRUE;
memcpy(&pAudioDecData->sPortBufSupplier[i], pPortBufSupplier, sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE));
break;
}
}
if(bFindFlag)
{
eError = SUCCESS;
}
else
{
eError = ERR_ADEC_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE AudioDecGetMPPChannelInfo(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT MPP_CHN_S *pChn)
{
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
copy_MPP_CHN_S(pChn, &pAudioDecData->mMppChnInfo);
return SUCCESS;
}
ERRORTYPE AudioDecSetMPPChannelInfo(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN MPP_CHN_S *pChn)
{
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
copy_MPP_CHN_S(&pAudioDecData->mMppChnInfo, pChn);
return SUCCESS;
}
ERRORTYPE AudioDecGetChnAttr(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT ADEC_CHN_ATTR_S *pChnAttr)
{
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
*pChnAttr = pAudioDecData->mADecChnAttr;
return SUCCESS;
}
ERRORTYPE AudioDecSetChnAttr(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN ADEC_CHN_ATTR_S *pChnAttr)
{
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
pAudioDecData->mADecChnAttr = *pChnAttr;
return SUCCESS;
}
ERRORTYPE AudioDecResetChannel(PARAM_IN COMP_HANDLETYPE hComponent)
{
// Get component private data
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
// Ensure component is in Idle state
if (pAudioDecData->state != COMP_StateIdle)
{
aloge("fatal error! must reset channel in stateIdle!");
return ERR_ADEC_NOT_PERM;
}
// wait all outFrame return.
alogd("wait ADec idleOutFrameList full");
struct list_head *pList;
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
pAudioDecData->mWaitOutFrameFullFlag = TRUE;
while (1)
{
int cnt = 0;
list_for_each(pList, &pAudioDecData->mIdleOutFrameList)
{
cnt++;
}
if (cnt < pAudioDecData->mFrameNodeNum)
{
alogd("wait idleOutFrameList [%d]nodes to home", pAudioDecData->mFrameNodeNum - cnt);
pthread_cond_wait(&pAudioDecData->mOutFrameFullCondition, &pAudioDecData->mOutFrameListMutex);
}
else
{
break;
}
}
pAudioDecData->mWaitOutFrameFullFlag = FALSE;
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
alogd("wait ADec idleOutFrameList full done");
return SUCCESS;
}
ERRORTYPE AudioDecGetTunnelInfo(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_INOUT COMP_INTERNAL_TUNNELINFOTYPE *pTunnelInfo)
{
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
ERRORTYPE eError = ERR_ADEC_UNEXIST;
if(pAudioDecData->sInPortTunnelInfo.nPortIndex == pTunnelInfo->nPortIndex)
{
memcpy(pTunnelInfo, &pAudioDecData->sInPortTunnelInfo, sizeof(COMP_INTERNAL_TUNNELINFOTYPE));
eError = SUCCESS;
}
else if(pAudioDecData->sOutPortTunnelInfo.nPortIndex == pTunnelInfo->nPortIndex)
{
memcpy(pTunnelInfo, &pAudioDecData->sOutPortTunnelInfo, sizeof(COMP_INTERNAL_TUNNELINFOTYPE));
eError = SUCCESS;
}
else
{
eError = ERR_ADEC_UNEXIST;
}
return eError;
}
/*****************************************************************************/
ERRORTYPE AudioDecGetState(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT COMP_STATETYPE* pState)
{
AUDIODECDATATYPE *pAudioDecData;
ERRORTYPE eError = SUCCESS;
pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
*pState = pAudioDecData->state;
return eError;
}
/*****************************************************************************/
ERRORTYPE AudioDecSetCallbacks(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_CALLBACKTYPE* pCallbacks,
PARAM_IN void* pAppData)
{
AUDIODECDATATYPE *pAudioDecData;
ERRORTYPE eError = SUCCESS;
pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if (!pAudioDecData || !pCallbacks || !pAppData)
{
eError = ERR_ADEC_ILLEGAL_PARAM;
goto COMP_CONF_CMD_FAIL;
}
pAudioDecData->pCallbacks = pCallbacks;
pAudioDecData->pAppData = pAppData;
COMP_CONF_CMD_FAIL: return eError;
}
/*****************************************************************************/
ERRORTYPE AudioDecGetCacheState(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT COMP_BUFFERSTATE* pBufState)
{
AUDIODECDATATYPE *pAudioDecData;
ERRORTYPE eError = SUCCESS;
int validPercent;
int nElementInVbv;
pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
BsQueryQuality(pAudioDecData->pDecoder, &validPercent, &nElementInVbv);
pBufState->nElementCounter = nElementInVbv;
pBufState->nValidSizePercent = validPercent;
return eError;
}
static ERRORTYPE config_AUDIO_FRAME_S_by_ADecCompOutputFrame(AUDIO_FRAME_S *dst, ADecCompOutputFrame *src)
{
dst->mpAddr = src->mpPcmBuf;
dst->mLen = src->mSize;
dst->mTimeStamp = src->mTimeStamp;
dst->mId = src->mId;
dst->mBitwidth = (AUDIO_BIT_WIDTH_E)(src->mBitsPerSample / 8 - 1);
dst->mSoundmode = (src->mChannelNum == 1)?AUDIO_SOUND_MODE_MONO : AUDIO_SOUND_MODE_STEREO;
dst->mSamplerate= src->mSampleRate;
return SUCCESS;
}
ERRORTYPE AudioDecSetStreamEof(PARAM_IN COMP_HANDLETYPE hComponent)
{
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
alogv("adec end flag is set");
pAudioDecData->priv_flag |= CDX_comp_PRIV_FLAGS_STREAMEOF;
message_t msg;
msg.command = ADecComp_AbsAvailable;
put_message(&pAudioDecData->cmd_queue, &msg);
return SUCCESS;
}
ERRORTYPE AudioDecClearStreamEof(PARAM_IN COMP_HANDLETYPE hComponent)
{
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
alogv("adec end flag is clear");
pAudioDecData->priv_flag &= ~(CDX_comp_PRIV_FLAGS_STREAMEOF);
return SUCCESS;
}
/**
* send stream to Adeclib, can used in tunnel/non-tunnel mode.
* currently, non-tunnel use EmptyThisBuffer(), tunnel use RequstBuffer() and ReleaseBuffer()
*
* @return SUCCESS
* @param hComponent adecComp handle.
* @param pBuffer stream info.
*/
ERRORTYPE AudioDecEmptyThisBuffer(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_BUFFERHEADERTYPE *pBuffer)
{
ERRORTYPE eError = SUCCESS;
int cmddata;
CompInternalMsgType cmd;
message_t cmd_msg;
DMXPKT_NODE_T* pEntry = NULL;
// Get component private data
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
AUDIODEC_INPUT_DATA* pInputData = pAudioDecData->pInputData;
pthread_mutex_lock(&pAudioDecData->mStateLock);
// Ensure component is in Executing or Pause state
if (pAudioDecData->state != COMP_StateExecuting && pAudioDecData->state != COMP_StatePause)
{
alogw("send stream when adec state[0x%x] is not executing/pause", pInputData->state);
}
// pass bs buffer to Decode lib in inport tunnel-mode
// Notes: data struct is different in tunnel and non-tunnel mode!
if (pAudioDecData->mInputPortTunnelFlag)
{
// check port index
if (pBuffer->nInputPortIndex == pAudioDecData->sInPortTunnelInfo.nPortIndex)
{
// Get buffer pointer from demux component
EncodedStream* pDmxOutBuf = (EncodedStream*)pBuffer->pOutputPortPrivate;
// Check it is the same buffer in mUsingAbsList
pthread_mutex_lock(&pInputData->mAbsListLock);
if (list_empty(&pInputData->mUsingAbsList))
{
pthread_mutex_unlock(&pInputData->mAbsListLock);
pthread_mutex_unlock(&pAudioDecData->mStateLock);
aloge("fatal error! Calling EmptyThisBuffer while mUsingAbsList is empty!");
return FAILURE;
}
pEntry = list_first_entry(&pInputData->mUsingAbsList, DMXPKT_NODE_T, mList);
if ( (pEntry->stEncodedStream.pBuffer != pDmxOutBuf->pBuffer)
|| (pEntry->stEncodedStream.pBufferExtra != pDmxOutBuf->pBufferExtra)
)
{
pthread_mutex_unlock(&pInputData->mAbsListLock);
pthread_mutex_unlock(&pAudioDecData->mStateLock);
aloge("fatal error! the buffer in EmptyThisBuffer param is not same as in mUsingAbsList");
return FAILURE;
}
if (-1 == pDmxOutBuf->nFilledLen)
{// buffer is not enough for component A
alogv("adec lib buffer is not enough for component A (nTobeFillLen = %d)", pDmxOutBuf->nTobeFillLen);
pInputData->nRequestLen = pDmxOutBuf->nTobeFillLen;
// Move node from mUsingAbsList to mIdleAbsList
if (!list_empty(&pInputData->mUsingAbsList))
{// moving from mReadyAbsList to mIdleAbsList
pEntry = list_first_entry(&pInputData->mUsingAbsList, DMXPKT_NODE_T, mList);
memset(&pEntry->stEncodedStream, 0, sizeof(EncodedStream));
list_move_tail(&pEntry->mList, &pInputData->mIdleAbsList);
}
// Send Abs Valid message to input thread
if (pInputData->mWaitAbsValidFlag)
{
pInputData->mWaitAbsValidFlag = FALSE;
message_t msg;
msg.command = ADecComp_AbsAvailable;
put_message(&pInputData->cmd_queue, &msg);
}
// signal when all abs return to idleList
if(pInputData->mbWaitAbsFullFlag)
{
struct list_head *pList;
int cnt = 0;
list_for_each(pList, &pInputData->mIdleAbsList) { cnt++; }
if (cnt >= pInputData->mNodeNum)
{
pInputData->mbWaitAbsFullFlag = FALSE;
pthread_cond_signal(&pInputData->mAbsFullCond);
}
}
pthread_mutex_unlock(&pInputData->mAbsListLock);
pthread_mutex_unlock(&pAudioDecData->mStateLock);
return eError;
}
//alogd("======= nFilledLen[%d] nTimeStamp[%lld] nOffset[%d]",pDmxOutBuf->nFilledLen,pDmxOutBuf->nTimeStamp,pBuffer->nOffset);
pthread_mutex_lock(&pAudioDecData->mAbsInputMutex);
int adecRet = ParserUpdateBsBuffer
(pAudioDecData->pDecoder
,pDmxOutBuf->nFilledLen
,pDmxOutBuf->nTimeStamp
,pBuffer->nOffset
);
pthread_mutex_unlock(&pAudioDecData->mAbsInputMutex);
if (adecRet == 0)
{// Send buf to decode lib success
eError = SUCCESS;
if (!list_empty(&pInputData->mUsingAbsList))
{
// Move node from mUsingAbsList to mIdleAbsList
pEntry = list_first_entry(&pInputData->mUsingAbsList, DMXPKT_NODE_T, mList);
list_move_tail(&pEntry->mList, &pInputData->mIdleAbsList);
pthread_mutex_unlock(&pInputData->mAbsListLock);
// Send Abs Valid message to work thread
if (pAudioDecData->mWaitAbsInputFlag)
{
pAudioDecData->mWaitAbsInputFlag = FALSE;
message_t msg;
msg.command = ADecComp_AbsAvailable;
put_message(&pAudioDecData->cmd_queue, &msg);
}
// Send Abs Valid message to input thread
if (pInputData->mWaitAbsValidFlag)
{
pInputData->mWaitAbsValidFlag = FALSE;
message_t msg;
msg.command = ADecComp_AbsAvailable;
put_message(&pInputData->cmd_queue, &msg);
}
// signal when all abs return to idleList
if(pInputData->mbWaitAbsFullFlag)
{
struct list_head *pList;
int cnt = 0;
list_for_each(pList, &pInputData->mIdleAbsList) { cnt++; }
if (cnt >= pInputData->mNodeNum)
{
pInputData->mbWaitAbsFullFlag = FALSE;
pthread_cond_signal(&pInputData->mAbsFullCond);
}
}
}
else
{
pthread_mutex_unlock(&pInputData->mAbsListLock);
pthread_mutex_unlock(&pAudioDecData->mStateLock);
aloge("fatal error! No Using Abs node while calling EmptyThisBuffer!");
return FAILURE;
}
}
else
{
aloge("fatal error! submit data fail, check code!");
eError = FAILURE;
}
}
else
{
aloge("fatal error! PortIndex[%u][%u]! fill Abs fail!", pBuffer->nInputPortIndex, pAudioDecData->sInPortTunnelInfo.nPortIndex);
eError = FAILURE;
}
pthread_mutex_unlock(&pAudioDecData->mStateLock);
return eError;
}
else
{
AdecInputStream *pInputStream = (AdecInputStream*)pBuffer->pAppPrivate;
AUDIO_STREAM_S *pStream = pInputStream->pStream;
int nMilliSec = pInputStream->nMilliSec;
if (0 == pStream->mLen)
{
alogd("indicate EndOfStream");
AudioDecSetStreamEof(hComponent);
pthread_mutex_unlock(&pAudioDecData->mStateLock);
return FAILURE;
}
EncodedStream DmxOutBuf;
memset(&DmxOutBuf, 0, sizeof(EncodedStream));
// send stream to adeclib.
pthread_mutex_lock(&pAudioDecData->mAbsInputMutex);
_TryToRequestAbs:
#ifdef DEBUG_INPORT_BUFFER_INFO
int bsValidSize = AudioStreamDataSize(pAudioDecData->pDecoder); // inport bs data_size that can be decode but have not be decoded
int bsTotalSize = AudioStreamBufferSize(pAudioDecData->pDecoder); // inport bs space total size: 128KB
int bsEmptySize = bsTotalSize - bsValidSize;
alogd("request ADecLib bs buffer. totalSz:%d, validSz:%d, emptySz:%d, requestSz:%d", bsTotalSize, bsValidSize, bsEmptySize, pStream->mLen);
#endif
// Request buffer from decode lib
DmxOutBuf.nTobeFillLen = pStream->mLen;
int ret = ParserRequestBsBuffer
(pAudioDecData->pDecoder
,DmxOutBuf.nTobeFillLen
,&DmxOutBuf.pBuffer
,(int*)&DmxOutBuf.nBufferLen
,&DmxOutBuf.pBufferExtra
,(int*)&DmxOutBuf.nBufferExtraLen
,(int *)&pBuffer->nOffset
);
if (0 == ret)
{
if (pStream->mLen > DmxOutBuf.nBufferLen)
{
memcpy(DmxOutBuf.pBuffer, pStream->pStream, DmxOutBuf.nBufferLen);
memcpy(DmxOutBuf.pBufferExtra, pStream->pStream + DmxOutBuf.nBufferLen, pStream->mLen - DmxOutBuf.nBufferLen);
}
else
{
memcpy(DmxOutBuf.pBuffer, pStream->pStream, pStream->mLen);
}
// Send data to decode lib
ret = ParserUpdateBsBuffer(pAudioDecData->pDecoder, DmxOutBuf.nTobeFillLen, pStream->mTimeStamp, pBuffer->nOffset);
if (pAudioDecData->mWaitAbsInputFlag)
{
pAudioDecData->mWaitAbsInputFlag = FALSE;
message_t msg;
msg.command = ADecComp_AbsAvailable;
put_message(&pAudioDecData->cmd_queue, &msg);
}
eError = SUCCESS;
}
else
{// get buffer from decode lib fail, try again
if (0 == nMilliSec)
{
eError = ERR_ADEC_BUF_FULL;
}
else if (nMilliSec < 0)
{
pAudioDecData->mWaitEmptyAbsFlag = TRUE;
pAudioDecData->mRequestAbsLen = pStream->mLen;
pthread_cond_wait(&pAudioDecData->mEmptyAbsCondition, &pAudioDecData->mAbsInputMutex);
pAudioDecData->mWaitEmptyAbsFlag = FALSE;
goto _TryToRequestAbs;
}
else
{
pAudioDecData->mWaitEmptyAbsFlag = TRUE;
pAudioDecData->mRequestAbsLen = pStream->mLen;
int waitRet = pthread_cond_wait_timeout(&pAudioDecData->mEmptyAbsCondition, &pAudioDecData->mAbsInputMutex, nMilliSec);
if (ETIMEDOUT == waitRet)
{
alogv("wait empty abs buffer timeout[%d]ms, ret[%d]", nMilliSec, waitRet);
eError = ERR_ADEC_BUF_FULL;
pAudioDecData->mWaitEmptyAbsFlag = FALSE;
}
else if (0 == waitRet)
{
pAudioDecData->mWaitEmptyAbsFlag = FALSE;
goto _TryToRequestAbs;
}
else
{
aloge("fatal error! pthread cond wait timeout ret[%d]", waitRet);
eError = ERR_ADEC_BUF_FULL;
pAudioDecData->mWaitEmptyAbsFlag = FALSE;
}
}
}
pthread_mutex_unlock(&pAudioDecData->mAbsInputMutex);
pthread_mutex_unlock(&pAudioDecData->mStateLock);
return eError;
}
}
/**
* get frame, used in non-tunnel mode.
*
* @return SUCCESS.
* @param hComponent adec component.
* @param pAFrame store frame info, caller malloc.
* @param nMilliSec 0:return immediately, <0:wait forever, >0:wait some time.
*/
ERRORTYPE AudioDecGetFrame(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT AUDIO_FRAME_S *pAFrame,
PARAM_IN int nMilliSec)
{
ERRORTYPE eError;
int ret;
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
if ( COMP_StateIdle != pAudioDecData->state
&& COMP_StateExecuting != pAudioDecData->state
&& COMP_StatePause != pAudioDecData->state
)
{
alogw("call getStream in wrong state[0x%x]", pAudioDecData->state);
return ERR_ADEC_NOT_PERM;
}
if (pAudioDecData->mOutputPortTunnelFlag)
{
aloge("fatal error! can't call getStream() in tunnel mode!");
return ERR_ADEC_NOT_PERM;
}
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
_TryToGetOutFrame:
if (!list_empty(&pAudioDecData->mReadyOutFrameList))
{
ADecCompOutputFrame *pOutFrame = list_first_entry(&pAudioDecData->mReadyOutFrameList, ADecCompOutputFrame, mList);
config_AUDIO_FRAME_S_by_ADecCompOutputFrame(pAFrame, pOutFrame);
list_move_tail(&pOutFrame->mList, &pAudioDecData->mUsedOutFrameList);
eError = SUCCESS;
}
else
{
if (0 == nMilliSec)
{
eError = ERR_ADEC_BUF_EMPTY;
}
else if (nMilliSec < 0)
{
pAudioDecData->mWaitReadyFrameFlag = TRUE;
while (list_empty(&pAudioDecData->mReadyOutFrameList))
{
pthread_cond_wait(&pAudioDecData->mReadyFrameCondition, &pAudioDecData->mOutFrameListMutex);
}
pAudioDecData->mWaitReadyFrameFlag = FALSE;
goto _TryToGetOutFrame;
}
else
{
pAudioDecData->mWaitReadyFrameFlag = TRUE;
ret = pthread_cond_wait_timeout(&pAudioDecData->mReadyFrameCondition, &pAudioDecData->mOutFrameListMutex, nMilliSec);
if (ETIMEDOUT == ret)
{
alogv("wait output frame timeout[%d]ms, ret[%d]", nMilliSec, ret);
eError = ERR_ADEC_BUF_EMPTY;
pAudioDecData->mWaitReadyFrameFlag = FALSE;
}
else if (0 == ret)
{
pAudioDecData->mWaitReadyFrameFlag = FALSE;
goto _TryToGetOutFrame;
}
else
{
aloge("fatal error! pthread cond wait timeout ret[%d]", ret);
eError = ERR_ADEC_BUF_EMPTY;
pAudioDecData->mWaitReadyFrameFlag = FALSE;
}
}
}
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
return eError;
}
/**
* release frame, used in non-tunnel mode.
*
* @return SUCCESS.
* @param hComponent adec component.
* @param pFrameInfo frame info, caller malloc.
*/
ERRORTYPE AudioDecReleaseFrame(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN AUDIO_FRAME_S *pFrame)
{
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
if (COMP_StateIdle != pAudioDecData->state && COMP_StateExecuting != pAudioDecData->state &&
COMP_StatePause != pAudioDecData->state)
{
alogw("call getStream in wrong state[0x%x]", pAudioDecData->state);
return ERR_ADEC_NOT_PERM;
}
if (pAudioDecData->mOutputPortTunnelFlag) {
aloge("fatal error! can't call releaseFrame() in tunnel mode!");
return ERR_ADEC_NOT_PERM;
}
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
if (!list_empty(&pAudioDecData->mUsedOutFrameList))
{
int ret;
int nFindFlag = 0;
ADecCompOutputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pAudioDecData->mUsedOutFrameList, mList)
{
if ((pEntry->mId==pFrame->mId) && (pEntry->mTimeStamp==pFrame->mTimeStamp))
{
ret = PlybkUpdatePcmBuffer(pAudioDecData->pDecoder, pEntry->mSize);
if (ret != 0)
{
aloge("fatal error! return pcm fail ret[%d]", ret);
}
list_move_tail(&pEntry->mList, &pAudioDecData->mIdleOutFrameList);
if (pAudioDecData->mWaitPcmBufFlag == TRUE)
{
pAudioDecData->mWaitPcmBufFlag = FALSE;
message_t msg;
msg.command = ADecComp_PcmBufAvailable,
put_message(&pAudioDecData->cmd_queue, &msg);
}
nFindFlag = 1;
break;
}
}
if (0 == nFindFlag)
{
aloge("fatal error! adec frameId[0x%x] is not match UsedOutFrameList", pFrame->mId);
eError = ERR_ADEC_ILLEGAL_PARAM;
}
}
else
{
aloge("fatal error! adec frameId[0x%x] is not find in UsedOutFrameList", pFrame->mId);
eError = ERR_ADEC_ILLEGAL_PARAM;
}
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
return eError;
}
#if 0
/**
* request abs buf and len from AdecLib, used in tunnel mode.
*
* @return SUCCESS.
* @param hComponent adec component.
* @param nPortIndex indicate abs inputPort index.
* @param pBuffer contain abs data struct which need to be filled, pBuffer, nBufferLen, etc.
*/
ERRORTYPE AudioDecRequstBuffer(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_INOUT COMP_BUFFERHEADERTYPE* pBuffer)
{
alogw("Be careful! old method, should not use now.");
ERRORTYPE eError = SUCCESS;
// Get component private data
AUDIODECDATATYPE* pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
// Get buffer pointer from demux component
EncodedStream *pDmxOutBuf = pBuffer->pOutputPortPrivate;
// Request buffer from Decode lib
if (pBuffer->nInputPortIndex == pAudioDecData->sInPortDef.nPortIndex)
{
eError = ParserRequestBsBuffer(pAudioDecData->pDecoder,
pDmxOutBuf->nTobeFillLen,
(unsigned char**)&pDmxOutBuf->pBuffer,
(int*)&pDmxOutBuf->nBufferLen,
(unsigned char**)&pDmxOutBuf->pBufferExtra,
(int*)&pDmxOutBuf->nBufferExtraLen,
(int*)&pBuffer->nOffset);
}
else
{
aloge("fatal error! portIndex[%u][%u]! RequstBsBuffer fail!", pBuffer->nInputPortIndex, pAudioDecData->sInPortDef.nPortIndex);
eError = FAILURE;
}
return eError;
}
/**
* update abs data to AdecLib, used in tunnel mode.
*
* @return SUCCESS.
* @param hComponent adec component.
* @param nPortIndex indicate abs inputPort index.
* @param pBuffer contain abs data struct.
*/
ERRORTYPE AudioDecReleaseBuffer(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_BUFFERHEADERTYPE* pBuffer)
{
alogw("Be careful! old method, should not use now.");
ERRORTYPE eError = SUCCESS;
// Get component private data
AUDIODECDATATYPE* pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
// Get buffer pointer from demux component
EncodedStream* pDmxOutBuf = (EncodedStream*)pBuffer->pOutputPortPrivate;
// Return buffer to Decode lib
if (pBuffer->nInputPortIndex == pAudioDecData->sInPortDef.nPortIndex)
{
pthread_mutex_lock(&pAudioDecData->mAbsInputMutex);
eError = ParserUpdateBsBuffer(pAudioDecData->pDecoder, pDmxOutBuf->nFilledLen, pDmxOutBuf->nTimeStamp, pBuffer->nOffset);
if (pAudioDecData->mWaitAbsInputFlag)
{
pAudioDecData->mWaitAbsInputFlag = FALSE;
message_t msg;
msg.command = ADecComp_AbsAvailable;
put_message(&pAudioDecData->cmd_queue, &msg);
}
pthread_mutex_unlock(&pAudioDecData->mAbsInputMutex);
}
else
{
aloge("fatal error! portIndex[%u][%u]! UpdataBsBuffer fail!", pBuffer->nInputPortIndex, pAudioDecData->sInPortDef.nPortIndex);
eError = FAILURE;
}
return eError;
}
#endif
/**
mainly clean adeclib buffer.
when outputPort is in non-tunnel mode, must clear readyOutFrameList, return all ready frames to adeclib.
*/
ERRORTYPE AudioDecSeek(PARAM_IN COMP_HANDLETYPE hComponent)
{
ERRORTYPE ret = SUCCESS;
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if(COMP_StatePause != pAudioDecData->state)
{
alogw("fatal error! adec seek in state:%d, check code!", pAudioDecData->state);
}
if (FALSE == pAudioDecData->mOutputPortTunnelFlag)
{
alogd("must clear readyOut list in outputPort non-tunnel mode.");
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
if(!list_empty(&pAudioDecData->mUsedOutFrameList))
{
aloge("fatal error! user do not return all outFrames! seek fail");
ret = ERR_ADEC_NOT_PERM;
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
goto _err0;
}
if(!list_empty(&pAudioDecData->mReadyOutFrameList))
{
int ret;
ADecCompOutputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pAudioDecData->mReadyOutFrameList, mList)
{
ret = PlybkUpdatePcmBuffer(pAudioDecData->pDecoder, pEntry->mSize);
if (ret != 0)
{
aloge("fatal error! return pcm fail ret[%d]", ret);
}
list_move_tail(&pEntry->mList, &pAudioDecData->mIdleOutFrameList);
if (pAudioDecData->mWaitPcmBufFlag == TRUE)
{
alogd("adec wait pcmBuf when seek");
pAudioDecData->mWaitPcmBufFlag = FALSE;
//in this situation, adec thread is pause state, no need to send message
//message_t msg;
//msg.command = ADecComp_PcmBufAvailable,
//put_message(&pAudioDecData->cmd_queue, &msg);
}
}
}
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
}
alogd("ADec seek. flush the bs and pcm buf!");
AudioDecoderSeek(pAudioDecData->pDecoder, 0);
pAudioDecData->mbEof = FALSE;
message_t msg;
msg.command = ADecComp_AbsAvailable;
put_message(&pAudioDecData->cmd_queue, &msg);
return SUCCESS;
_err0:
return ret;
}
//1.aac
const int stdSampleRate[13] = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350};
static ERRORTYPE generate_ExtraData_by_ADEC_CHN_ATTR_S(int *pLen, char **pData, ADEC_CHN_ATTR_S *pAttr)
{
int i;
BOOL findFlag = FALSE;
for (i=0; i<sizeof(stdSampleRate)/sizeof(int); i++) {
if (pAttr->sampleRate == stdSampleRate[i]) {
findFlag = TRUE;
break;
}
}
if (TRUE == findFlag) {
*pLen = 2;
*pData = malloc(*pLen);
memset(*pData, 0, *pLen);
**pData = 0x10; // AACLC
**pData |=i>>1;
*(*pData+1) |=i<<7;
*(*pData+1) |= (pAttr->channels&0xf)<<3;
} else {
*pLen = 5;
*pData = malloc(*pLen);
memset(*pData, 0, *pLen);
**pData = 0x10; // AACLC
**pData |=0x7;//set 4bits 0xf;
*(*pData+1) =0x80;
*(*pData+1) |= (pAttr->sampleRate>>(24-7))&0x7f;
*(*pData+2) = (pAttr->sampleRate>>(24-15))&0xff;
*(*pData+3) = (pAttr->sampleRate>>(24-23))&0xff;
*(*pData+4) = (pAttr->sampleRate&0x01)<<7;
*(*pData+4) |= (pAttr->channels&0xf)<<3;
}
return SUCCESS;
}
static ERRORTYPE config_AudioStreamInfo_by_ADEC_CHN_ATTR_S(AUDIODECDATATYPE *pAudioDecData)
{
ADEC_CHN_ATTR_S *pAttr = &pAudioDecData->mADecChnAttr;
AudioStreamInfo *pInfo = &pAudioDecData->mAudioStreamInfo;
pInfo->eCodecFormat = map_PAYLOAD_TYPE_E_to_EAUDIOCODECFORMAT(pAttr->mType);
pInfo->nChannelNum = pAttr->channels;
pInfo->nBitsPerSample = pAttr->bitsPerSample;
pInfo->nSampleRate = pAttr->sampleRate;
pInfo->nAvgBitrate = pAttr->bitRate;
// if(pInfo->eCodecFormat == AUDIO_CODEC_FORMAT_G726)
// {
// pInfo->g726_enc_law = pAttr->g726_src_enc_type;
// pInfo->g726_src_bit_rate = pAttr->g726_src_bit_rate;
// }
if (AUDIO_CODEC_FORMAT_MPEG_AAC_LC == pInfo->eCodecFormat) {
generate_ExtraData_by_ADEC_CHN_ATTR_S(&pInfo->nCodecSpecificDataLen, &pInfo->pCodecSpecificData, pAttr);
}
return SUCCESS;
}
ERRORTYPE AudioDecGetConfig(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_INDEXTYPE nIndex,
PARAM_IN void* pComponentConfigStructure)
{
ERRORTYPE eError = SUCCESS;
switch(nIndex)
{
case COMP_IndexParamPortDefinition:
{
eError = AudioDecGetPortDefinition(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorParamPortExtraDefinition:
{
eError = AudioDecGetPortExtraDefinition(hComponent, pComponentConfigStructure);
break;
}
case COMP_IndexParamCompBufferSupplier:
{
eError = AudioDecGetCompBufferSupplier(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorMPPChannelInfo:
{
eError = AudioDecGetMPPChannelInfo(hComponent, (MPP_CHN_S*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorAdecChnAttr:
{
eError = AudioDecGetChnAttr(hComponent, (ADEC_CHN_ATTR_S*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorTunnelInfo:
{
eError = AudioDecGetTunnelInfo(hComponent, (COMP_INTERNAL_TUNNELINFOTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorAdecChnPriority:
{
alogw("unsupported temporary get adec chn priority!");
eError = ERR_ADEC_NOT_SUPPORT;
break;
}
case COMP_IndexVendorAdecChnState:
{
alogw("unsupported temporary COMP_IndexVendorAdecChnState!");
// eError = AudioDecGetAdecChnState(hComponent, (ADEC_CHN_STAT_S*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorAdecCacheState:
{
eError = AudioDecGetCacheState(hComponent, (COMP_BUFFERSTATE*)pComponentConfigStructure);
break;
}
// case COMP_IndexVendorConfigInputBuffer:
// {
// eError = AudioDecRequstBuffer(hComponent, (COMP_BUFFERHEADERTYPE*)pComponentConfigStructure);
// break;
// }
case COMP_IndexVendorAdecGetFrame:
{
AdecOutputFrame *pFrame = (AdecOutputFrame *)pComponentConfigStructure;
eError = AudioDecGetFrame(hComponent, pFrame->pFrame, pFrame->nMilliSec);
break;
}
default:
{
aloge("fatal error! unknown getConfig Index[0x%x]", nIndex);
eError = ERR_ADEC_NOT_SUPPORT;
break;
}
}
return eError;
}
ERRORTYPE AudioDecSetConfig(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_INDEXTYPE nIndex,
PARAM_IN void* pComponentConfigStructure)
{
AUDIODECDATATYPE *pAudioDecData;
ERRORTYPE eError = SUCCESS;
pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
switch (nIndex)
{
case COMP_IndexParamPortDefinition:
{
eError = AudioDecSetPortDefinition(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexParamCompBufferSupplier:
{
eError = AudioDecSetCompBufferSupplier(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorMPPChannelInfo:
{
eError = AudioDecSetMPPChannelInfo(hComponent, (MPP_CHN_S*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorAdecChnAttr:
{
eError = AudioDecSetChnAttr(hComponent, (ADEC_CHN_ATTR_S*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorAdecChnPriority:
{
alogw("unsupported temporary set adec chn priority!");
eError = ERR_ADEC_NOT_SUPPORT;
break;
}
case COMP_IndexVendorAdecResetChannel:
{
eError = AudioDecResetChannel(hComponent);
break;
}
case COMP_IndexVendorDemuxType:
{
pAudioDecData->demux_type = *((int *)pComponentConfigStructure);
pAudioDecData->demux_type &= 0xffff;
break;
}
case COMP_IndexVendorAdecSetDecodeMode:
{
pAudioDecData->decode_mode = *(int*)pComponentConfigStructure;
pAudioDecData->is_raw_music_mode = (pAudioDecData->decode_mode == CDX_DECODER_MODE_RAWMUSIC);
break;
}
case COMP_IndexVendorAdecSwitchAudio:
{
pAudioDecData->priv_flag |= CDX_comp_PRIV_FLAGS_REINIT;
break;
}
case COMP_IndexVendorAdecSelectAudioOut:
{
aloge("not support COMP_IndexVendorAdecSelectAudioOut");
// pAudioDecData->enable_resample = *(int*)pComponentConfigStructure == CDX_AUDIO_OUT_I2S;
break;
}
case COMP_IndexVendorAdecSetVolume:
{
pAudioDecData->volumegain = *(int*)pComponentConfigStructure;
break;
}
case COMP_IndexVendorAdecSetAudioChannelMute:
{
pAudioDecData->mute = *(int*)pComponentConfigStructure;
break;
}
case COMP_IndexVendorAdecSwitchAuioChannnel:
{
pAudioDecData->audio_channel = *(int*)pComponentConfigStructure;
alogv("audio channel %d", pAudioDecData->audio_channel);
break;
}
// case COMP_IndexVendorConfigInputBuffer:
// {
// eError = AudioDecReleaseBuffer(hComponent, pComponentConfigStructure);
// break;
// }
case COMP_IndexVendorSetStreamEof:
{
eError = AudioDecSetStreamEof(hComponent);
break;
}
case COMP_IndexVendorClearStreamEof:
{
eError = AudioDecClearStreamEof(hComponent);
break;
}
case COMP_IndexVendorSeekToPosition:
{
eError = AudioDecSeek(hComponent);
break;
}
case COMP_IndexVendorAdecReleaseFrame:
{
eError = AudioDecReleaseFrame(hComponent, ((AdecOutputFrame *)pComponentConfigStructure)->pFrame);
break;
}
default:
{
aloge("fatal error! unknown setConfig Index[0x%x]", nIndex);
eError = ERR_ADEC_NOT_SUPPORT;
break;
}
}
return eError;
}
/**
* return frame to adeclib in tunnel mode.
*
* @return SUCCESS
* @param hComponent adecComp handle.
* @param pBuffer frame buffer info.
*/
ERRORTYPE AudioDecFillThisBuffer(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_BUFFERHEADERTYPE* pBuffer)
{
int ret;
ERRORTYPE eError = SUCCESS;
AUDIODECDATATYPE * pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if (pBuffer->nOutputPortIndex == pAudioDecData->sOutPortDef.nPortIndex)
{
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
AUDIO_FRAME_S *pAFrame = (AUDIO_FRAME_S*)pBuffer->pOutputPortPrivate;
ADecCompOutputFrame *pEntry, *pOutFrame;
BOOL bFindFlag = FALSE;
list_for_each_entry(pEntry, &pAudioDecData->mUsedOutFrameList, mList)
{
if (pEntry->mTimeStamp == pAFrame->mTimeStamp)
{
if (FALSE == bFindFlag)
{
bFindFlag = TRUE;
pOutFrame = pEntry;
}
else
{
aloge("fatal error! find same framePTS[%lld] again!", pEntry->mTimeStamp);
}
}
}
if(!bFindFlag)
{
aloge("fatal error! can't find frameId[%d], pts[%llu], check code!", pAFrame->mId, pAFrame->mTimeStamp);
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
return ERR_ADEC_ILLEGAL_PARAM;
}
ret = PlybkUpdatePcmBuffer(pAudioDecData->pDecoder, pOutFrame->mSize);
if (ret != 0)
{
aloge("fatal error! return pcmBuffer fail! ret[%d]", ret);
eError = FAILURE;
}
list_move_tail(&pOutFrame->mList, &pAudioDecData->mIdleOutFrameList);
if (pAudioDecData->mWaitPcmBufFlag)
{
pAudioDecData->mWaitPcmBufFlag = FALSE;
message_t msg;
msg.command = ADecComp_PcmBufAvailable;
put_message(&pAudioDecData->cmd_queue, &msg);
}
if (pAudioDecData->mWaitOutFrameFullFlag)
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pAudioDecData->mIdleOutFrameList)
{
cnt++;
}
if (cnt >= pAudioDecData->mFrameNodeNum)
{
pthread_cond_signal(&pAudioDecData->mOutFrameFullCondition);
}
}
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
}
else
{
aloge("fatal error! PortIndex[%u][%u]! Release PcmBuf fail!", pBuffer->nOutputPortIndex, pAudioDecData->sOutPortDef.nPortIndex);
eError = FAILURE;
}
return eError;
}
ERRORTYPE AudioDecComponentTunnelRequest(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN unsigned int nPort,
PARAM_IN COMP_HANDLETYPE hTunneledComp,
PARAM_IN unsigned int nTunneledPort,
PARAM_INOUT COMP_TUNNELSETUPTYPE* pTunnelSetup)
{
ERRORTYPE eError = SUCCESS;
AUDIODECDATATYPE *pAudioDecData = (AUDIODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if (pAudioDecData->state == COMP_StateExecuting)
{
alogw("Be careful! tunnel request may be some danger in StateExecuting");
}
else if(pAudioDecData->state != COMP_StateIdle)
{
aloge("fatal error! tunnel request can't be in state[0x%x]", pAudioDecData->state);
eError = ERR_ADEC_INCORRECT_STATE_OPERATION;
goto COMP_CMD_FAIL;
}
COMP_PARAM_PORTDEFINITIONTYPE *pPortDef = NULL;
COMP_PARAM_PORTEXTRADEFINITIONTYPE *pPortExtraDef = NULL;
COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo = NULL;
COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier = NULL;
BOOL bFindFlag;
int i;
bFindFlag = FALSE;
if(pAudioDecData->sInPortDef.nPortIndex == nPort)
{
pPortDef = &pAudioDecData->sInPortDef;
pPortExtraDef = &pAudioDecData->sInPortExtraDef;
bFindFlag = TRUE;
}
if(FALSE == bFindFlag)
{
if(pAudioDecData->sOutPortDef.nPortIndex == nPort)
{
pPortDef = &pAudioDecData->sOutPortDef;
bFindFlag = TRUE;
}
}
if(FALSE == bFindFlag)
{
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_ADEC_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
bFindFlag = FALSE;
if(pAudioDecData->sInPortTunnelInfo.nPortIndex == nPort)
{
pPortTunnelInfo = &pAudioDecData->sInPortTunnelInfo;
bFindFlag = TRUE;
}
if(FALSE == bFindFlag)
{
if(pAudioDecData->sOutPortTunnelInfo.nPortIndex == nPort)
{
pPortTunnelInfo = &pAudioDecData->sOutPortTunnelInfo;
bFindFlag = TRUE;
}
}
if(FALSE == bFindFlag)
{
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_ADEC_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
bFindFlag = FALSE;
for(i=0; i<MAX_ADECODER_PORTS; i++)
{
if(pAudioDecData->sPortBufSupplier[i].nPortIndex == nPort)
{
pPortBufSupplier = &pAudioDecData->sPortBufSupplier[i];
bFindFlag = TRUE;
break;
}
}
if(FALSE == bFindFlag)
{
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_ADEC_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
pPortTunnelInfo->nPortIndex = nPort;
pPortTunnelInfo->hTunnel = hTunneledComp;
pPortTunnelInfo->nTunnelPortIndex = nTunneledPort;
pPortTunnelInfo->eTunnelType = (pPortDef->eDomain == COMP_PortDomainOther) ? TUNNEL_TYPE_CLOCK : TUNNEL_TYPE_COMMON;
if(NULL==hTunneledComp && 0==nTunneledPort && NULL==pTunnelSetup)
{
alogd("omx_core cancel setup tunnel on port[%d]", nPort);
eError = SUCCESS;
if(pPortDef->eDir == COMP_DirOutput)
{
pAudioDecData->mOutputPortTunnelFlag = FALSE;
}
else
{
pAudioDecData->mInputPortTunnelFlag = FALSE;
}
goto COMP_CMD_FAIL;
}
if(pPortDef->eDir == COMP_DirOutput)
{
if (pAudioDecData->mOutputPortTunnelFlag) {
aloge("ADec_Comp outport already bind, why bind again?!");
eError = FAILURE;
goto COMP_CMD_FAIL;
}
pTunnelSetup->nTunnelFlags = 0;
pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier;
pAudioDecData->mOutputPortTunnelFlag = TRUE;
}
else
{
if (pAudioDecData->mInputPortTunnelFlag) {
aloge("ADec_Comp inport already bind, why bind again?!");
eError = FAILURE;
goto COMP_CMD_FAIL;
}
//Check the data compatibility between the ports using one or more GetParameter calls.
//B checks if its input port is compatible with the output port of component A.
COMP_PARAM_PORTDEFINITIONTYPE out_port_def;
out_port_def.nPortIndex = nTunneledPort;
((MM_COMPONENTTYPE*)hTunneledComp)->GetConfig(hTunneledComp, COMP_IndexParamPortDefinition, &out_port_def);
if(out_port_def.eDir != COMP_DirOutput)
{
aloge("fatal error! tunnel port index[%d] direction is not output!", nTunneledPort);
eError = ERR_ADEC_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
pPortDef->format = out_port_def.format;
//pPortDef->pVendorInfo = out_port_def.pVendorInfo;
COMP_PARAM_PORTEXTRADEFINITIONTYPE out_port_extra_def;
memset(&out_port_extra_def, 0, sizeof(COMP_PARAM_PORTEXTRADEFINITIONTYPE));
out_port_extra_def.nPortIndex = nTunneledPort;
((MM_COMPONENTTYPE*)hTunneledComp)->GetConfig(hTunneledComp, COMP_IndexVendorParamPortExtraDefinition, &out_port_extra_def);
pPortExtraDef->pVendorInfo = out_port_extra_def.pVendorInfo;
//The component B informs component A about the final result of negotiation.
if(pTunnelSetup->eSupplier != pPortBufSupplier->eBufferSupplier)
{
alogw("Low probability! use input portIndex[%d] buffer supplier[%d] as final!", nPort, pPortBufSupplier->eBufferSupplier);
pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier;
}
COMP_PARAM_BUFFERSUPPLIERTYPE oSupplier;
oSupplier.nPortIndex = nTunneledPort;
((MM_COMPONENTTYPE*)hTunneledComp)->GetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier);
oSupplier.eBufferSupplier = pTunnelSetup->eSupplier;
((MM_COMPONENTTYPE*)hTunneledComp)->SetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier);
pAudioDecData->mInputPortTunnelFlag = TRUE;
}
COMP_CMD_FAIL:
return eError;
}
ERRORTYPE AudioDecLibInit(AUDIODECDATATYPE *pAudioDecData)
{
AudioStreamInfo *pAudioStreamInfo = NULL;
if (TRUE == pAudioDecData->mInputPortTunnelFlag)
{
// streamInfo from demux, use it directly!
pAudioStreamInfo = (AudioStreamInfo *)(pAudioDecData->sInPortExtraDef.pVendorInfo);
if (NULL == pAudioStreamInfo) {
alogw("audio stream info has not got, can't init ADecLib now.");
return FAILURE;
}
}
else
{
// set streamInfo by hand!
config_AudioStreamInfo_by_ADEC_CHN_ATTR_S(pAudioDecData);
pAudioStreamInfo = &pAudioDecData->mAudioStreamInfo;
}
pAudioDecData->pDecoder = CreateAudioDecoder();
if(pAudioDecData->pDecoder == NULL)
{
aloge("Audiodec_Comp create Audiodecoder fail!");
assert(0);
return FAILURE;
}
memset(&pAudioDecData->ad_cedar_info, 0, sizeof(BsInFor));
AudioDecBufInfo stAudioDecBufInfo;
memset(&stAudioDecBufInfo, 0, sizeof(AudioDecBufInfo));
stAudioDecBufInfo.mInBufSize = pAudioDecData->mADecChnAttr.mInBufSize;
stAudioDecBufInfo.mOutBufSize = pAudioDecData->mADecChnAttr.mOutBufSize;
if(InitializeAudioDecoder(pAudioDecData->pDecoder, pAudioStreamInfo, &pAudioDecData->ad_cedar_info, &stAudioDecBufInfo) != 0)
{
aloge("Initialize AudioDecoder fail!");
DestroyAudioDecoder(pAudioDecData->pDecoder);
//pAudioDecData->pDecoder = NULL;
assert(0);
return FAILURE;
}
SetRawPlayParam(pAudioDecData->pDecoder, (void*)pAudioDecData, 0);
//alogd("adec inPort and outPort share same pVendorInfo!");
//TODO just transfer it audio dec may update it!
//pAudioDecData->sOutPortExtraDef.pVendorInfo = pAudioDecData->sInPortExtraDef.pVendorInfo;
return SUCCESS;
}
/*****************************************************************************/
ERRORTYPE AudioDecComponentDeInit(PARAM_IN COMP_HANDLETYPE hComponent)
{
ERRORTYPE eError = SUCCESS;
CompInternalMsgType eCmd = Stop;
message_t msg;
alogd("AudioDec Component DeInit");
AUDIODECDATATYPE* pAudioDecData = (AUDIODECDATATYPE *)(((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
msg.command = eCmd;
put_message(&pAudioDecData->cmd_queue, &msg);
alogd("wait component exit!...");
pAudioDecData->force_exit = 1;
pthread_join(pAudioDecData->thread_id, (void*)&eError);
AudioDec_InputDataDestroy(pAudioDecData->pInputData);
message_destroy(&pAudioDecData->cmd_queue);
// if (pAudioDecData->pDecoder != NULL)
// {
// int ret = DestroyAudioDecoder(pAudioDecData->pDecoder);
// pAudioDecData->pDecoder = NULL;
// if ((FALSE==pAudioDecData->mInputPortTunnelFlag) && (pAudioDecData->mAudioStreamInfo.pCodecSpecificData))
// free(pAudioDecData->mAudioStreamInfo.pCodecSpecificData);
// }
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
int nodeNum = 0;
if(!list_empty(&pAudioDecData->mIdleOutFrameList))
{
ADecCompOutputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pAudioDecData->mIdleOutFrameList, mList)
{
list_del(&pEntry->mList);
free(pEntry);
nodeNum++;
}
}
if(nodeNum!=pAudioDecData->mFrameNodeNum)
{
aloge("Fatal error! AudioDec frame_node number is not match[%d][%d]", nodeNum, pAudioDecData->mFrameNodeNum);
}
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
pthread_mutex_destroy(&pAudioDecData->mStateLock);
pthread_mutex_destroy(&pAudioDecData->mAbsInputMutex);
pthread_mutex_destroy(&pAudioDecData->mOutFrameListMutex);
pthread_cond_destroy(&pAudioDecData->mOutFrameFullCondition);
pthread_cond_destroy(&pAudioDecData->mReadyFrameCondition);
pthread_cond_destroy(&pAudioDecData->mEmptyAbsCondition);
if (pAudioDecData->pInputData)
{
free(pAudioDecData->pInputData);
}
if (pAudioDecData)
{
free(pAudioDecData);
}
alogd("AudioDec component exited!");
return eError;
}
/*****************************************************************************/
ERRORTYPE AudioDecComponentInit(PARAM_IN COMP_HANDLETYPE hComponent)
{
ERRORTYPE eError = SUCCESS;
unsigned int err;
int i = 0;
// Create component private data
MM_COMPONENTTYPE* pComp = (MM_COMPONENTTYPE *) hComponent;
AUDIODECDATATYPE* pAudioDecData = (AUDIODECDATATYPE *) malloc(sizeof(AUDIODECDATATYPE));
memset(pAudioDecData, 0x0, sizeof(AUDIODECDATATYPE));
pComp->pComponentPrivate = (void*)pAudioDecData;
pAudioDecData->state = COMP_StateLoaded;
pthread_mutex_init(&pAudioDecData->mStateLock, NULL);
pAudioDecData->hSelf = hComponent;
pAudioDecData->mAudioInfoVersion = -1;
pAudioDecData->mWaitAbsInputFlag = FALSE;
pAudioDecData->mWaitPcmBufFlag = FALSE;
pAudioDecData->mWaitOutFrameFullFlag = FALSE;
pAudioDecData->mWaitReadyFrameFlag = FALSE;
pAudioDecData->mWaitEmptyAbsFlag = FALSE;
INIT_LIST_HEAD(&pAudioDecData->mIdleOutFrameList);
INIT_LIST_HEAD(&pAudioDecData->mReadyOutFrameList);
INIT_LIST_HEAD(&pAudioDecData->mUsedOutFrameList);
for(i = 0; i < ADEC_FRAME_COUNT; i++)
{
ADecCompOutputFrame *pNode = (ADecCompOutputFrame*)malloc(sizeof(ADecCompOutputFrame));
if (NULL == pNode)
{
aloge("fatal error! malloc fail[%s]!", strerror(errno));
break;
}
list_add_tail(&pNode->mList, &pAudioDecData->mIdleOutFrameList);
pAudioDecData->mFrameNodeNum++;
}
err = pthread_mutex_init(&pAudioDecData->mAbsInputMutex, NULL);
if(err!=0)
{
aloge("fatal error! pthread mutex init fail!");
eError = ERR_ADEC_SYS_NOTREADY;
goto EXIT;
}
err = pthread_mutex_init(&pAudioDecData->mOutFrameListMutex, NULL);
if(err!=0)
{
aloge("fatal error! pthread mutex init fail!");
eError = ERR_ADEC_SYS_NOTREADY;
goto EXIT;
}
pthread_condattr_t condAttr;
pthread_condattr_init(&condAttr);
pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
err = 0;
err += pthread_cond_init(&pAudioDecData->mOutFrameFullCondition, &condAttr);
err += pthread_cond_init(&pAudioDecData->mReadyFrameCondition, &condAttr);
err += pthread_cond_init(&pAudioDecData->mEmptyAbsCondition, &condAttr);
if (err != 0)
{
aloge("fatal error! pthread mutex init fail!");
eError = ERR_ADEC_SYS_NOTREADY;
goto EXIT;
}
// Fill in function pointers
pComp->SetCallbacks = AudioDecSetCallbacks;
pComp->SendCommand = AudioDecSendCommand;
pComp->GetConfig = AudioDecGetConfig;
pComp->SetConfig = AudioDecSetConfig;
pComp->GetState = AudioDecGetState;
pComp->ComponentTunnelRequest = AudioDecComponentTunnelRequest;
pComp->ComponentDeInit = AudioDecComponentDeInit;
pComp->FillThisBuffer = AudioDecFillThisBuffer;
pComp->EmptyThisBuffer = AudioDecEmptyThisBuffer;
// Initialize component data structures to default values
pAudioDecData->sPortParam.nPorts = 0x2;
pAudioDecData->sPortParam.nStartPortNumber = 0x0;
// Initialize the audio parameters for input port
pAudioDecData->sInPortDef.nPortIndex =
pAudioDecData->sInPortExtraDef.nPortIndex = ADEC_PORT_INDEX_DEMUX;
pAudioDecData->sInPortDef.bEnabled = TRUE;
pAudioDecData->sInPortDef.eDomain = COMP_PortDomainAudio;
pAudioDecData->sInPortDef.eDir = COMP_DirInput;
pAudioDecData->sInPortDef.format.audio.cMIMEType = "AAC";
pAudioDecData->sInPortDef.format.audio.eEncoding = PT_AAC;
// Initialize the audio parameters for output port
pAudioDecData->sOutPortDef.nPortIndex =
pAudioDecData->sOutPortExtraDef.nPortIndex = ADEC_OUT_PORT_INDEX_VRENDER;
pAudioDecData->sOutPortDef.bEnabled = TRUE;
pAudioDecData->sOutPortDef.eDomain = COMP_PortDomainAudio;
pAudioDecData->sOutPortDef.eDir = COMP_DirOutput;
pAudioDecData->sOutPortDef.format.audio.cMIMEType = "PCM_RAW";
pAudioDecData->sPortBufSupplier[ADEC_PORT_INDEX_DEMUX].nPortIndex = ADEC_PORT_INDEX_DEMUX;
pAudioDecData->sPortBufSupplier[ADEC_PORT_INDEX_DEMUX].eBufferSupplier = COMP_BufferSupplyInput;
pAudioDecData->sPortBufSupplier[ADEC_OUT_PORT_INDEX_VRENDER].nPortIndex = ADEC_OUT_PORT_INDEX_VRENDER;
pAudioDecData->sPortBufSupplier[ADEC_OUT_PORT_INDEX_VRENDER].eBufferSupplier = COMP_BufferSupplyOutput;
pAudioDecData->sInPortTunnelInfo.nPortIndex = ADEC_PORT_INDEX_DEMUX;
pAudioDecData->sInPortTunnelInfo.eTunnelType = TUNNEL_TYPE_COMMON;
pAudioDecData->sOutPortTunnelInfo.nPortIndex = ADEC_OUT_PORT_INDEX_VRENDER;
pAudioDecData->sOutPortTunnelInfo.eTunnelType = TUNNEL_TYPE_COMMON;
if (message_create(&pAudioDecData->cmd_queue)<0)
{
aloge("create work cmd queue error!");
eError = ERR_ADEC_NOMEM;
goto EXIT;
}
// Create input thread data
AUDIODEC_INPUT_DATA* pInputData = (AUDIODEC_INPUT_DATA*) malloc(sizeof(AUDIODEC_INPUT_DATA));
if (pInputData == NULL)
{
aloge("create input data error!");
eError = ERR_ADEC_NOMEM;
goto EXIT;
}
pAudioDecData->pInputData = pInputData;
// Create the component thread
err = pthread_create(&pAudioDecData->thread_id, NULL, ComponentThread, pAudioDecData);
if (err || !pAudioDecData->thread_id)
{
eError = ERR_ADEC_NOMEM;
goto EXIT;
}
if((eError = AudioDec_InputDataInit(pInputData, pAudioDecData)) != SUCCESS)
{
aloge("fatal error! AudioDec InputData init fail");
goto EXIT;
}
pthread_condattr_destroy(&condAttr);
return eError;
EXIT:
return eError;
}
/*****************************************************************************/
static void* ComponentThread(void* pThreadData)
{
int ret;
int cmddata;
CompInternalMsgType cmd;
message_t cmd_msg;
message_t input_cmd_msg;
// Get component private data
AUDIODECDATATYPE* pAudioDecData = (AUDIODECDATATYPE*)pThreadData;
AUDIODEC_INPUT_DATA* pInputData = pAudioDecData->pInputData;
pAudioDecData->get_audio_info_flag = 1; // control get audio info only once
alogv("AudioDecoder ComponentThread start run...");
sprintf(pAudioDecData->mThreadName, "ADecChn%d", pAudioDecData->mMppChnInfo.mChnId);
prctl(PR_SET_NAME, (unsigned long)pAudioDecData->mThreadName, 0, 0, 0);
while (1)
{
PROCESS_MESSAGE:
if (get_message(&pAudioDecData->cmd_queue, &cmd_msg) == 0)
{// pump message from message queue
cmd = cmd_msg.command;
cmddata = cmd_msg.para0;
//alogv("AudioDec ComponentThread get_message cmd:%d", cmd);
// State transition command
if (cmd == SetState)
{
pthread_mutex_lock(&pAudioDecData->mStateLock);
// If the parameter states a transition to the same state
// raise a same state transition error.
if (pAudioDecData->state == (COMP_STATETYPE) (cmddata))
{
pAudioDecData->pCallbacks->EventHandler(pAudioDecData->hSelf,
pAudioDecData->pAppData,
COMP_EventError,
ERR_ADEC_SAMESTATE,
0,
NULL);
}
else
{
// transitions/callbacks made based on state transition table
// cmddata contains the target state
switch ((COMP_STATETYPE) (cmddata))
{
case COMP_StateInvalid:
{
pAudioDecData->state = COMP_StateInvalid;
pAudioDecData->pCallbacks->EventHandler(pAudioDecData->hSelf,
pAudioDecData->pAppData,
COMP_EventError,
ERR_ADEC_INVALIDSTATE,
0,
NULL);
pAudioDecData->pCallbacks->EventHandler(pAudioDecData->hSelf,
pAudioDecData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pAudioDecData->state,
NULL);
break;
}
case COMP_StateLoaded:
{
if (pAudioDecData->state != COMP_StateIdle)
{
pAudioDecData->pCallbacks->EventHandler(
pAudioDecData->hSelf,
pAudioDecData->pAppData,
COMP_EventError,
ERR_ADEC_INCORRECT_STATE_TRANSITION,
0,
NULL);
}
alogd("ADec_Comp StateLoaded begin");
int cnt;
struct list_head *pList;
alogd("wait ADec idleOutFrameList full");
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
pAudioDecData->mWaitOutFrameFullFlag = TRUE;
//wait all outFrame return.
while(1)
{
cnt = 0;
list_for_each(pList, &pAudioDecData->mIdleOutFrameList)
{
cnt++;
}
if(cnt < pAudioDecData->mFrameNodeNum)
{
alogd("Wait ADec idleOutFrameList [%d]nodes to home[%d]",
pAudioDecData->mFrameNodeNum - cnt, pAudioDecData->mFrameNodeNum);
pthread_cond_wait(&pAudioDecData->mOutFrameFullCondition, &pAudioDecData->mOutFrameListMutex);
}
else
{
break;
}
}
pAudioDecData->mWaitOutFrameFullFlag = FALSE;
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
alogd("Wait ADec idleOutFrameList full done");
// send message to input_thread
message_t InputThreadMsg;
InputThreadMsg.command = SetState;
InputThreadMsg.para0 = COMP_StateLoaded;
put_message(&pInputData->cmd_queue, &InputThreadMsg);
// Sync input thread state
pthread_mutex_lock(&pInputData->mStateLock);
while (pInputData->state != COMP_StateLoaded)
{
pthread_cond_wait(&pInputData->mStateCond, &pInputData->mStateLock);
}
pthread_mutex_unlock(&pInputData->mStateLock);
if (pAudioDecData->pDecoder != NULL)
{
int ret = DestroyAudioDecoder(pAudioDecData->pDecoder);
pAudioDecData->pDecoder = NULL;
if ((FALSE==pAudioDecData->mInputPortTunnelFlag) && (pAudioDecData->mAudioStreamInfo.pCodecSpecificData))
{
free(pAudioDecData->mAudioStreamInfo.pCodecSpecificData);
pAudioDecData->mAudioStreamInfo.pCodecSpecificData = NULL;
}
}
pAudioDecData->state = COMP_StateLoaded;
pAudioDecData->pCallbacks->EventHandler(
pAudioDecData->hSelf, pAudioDecData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pAudioDecData->state,
NULL);
alogd("ADec_Comp StateLoaded ok");
break;
}
case COMP_StateIdle:
{
if(pAudioDecData->state == COMP_StateLoaded)
{
alogv("ADec_Comp: loaded->idle ...");
pAudioDecData->state = COMP_StateIdle;
pAudioDecData->pCallbacks->EventHandler(
pAudioDecData->hSelf,
pAudioDecData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pAudioDecData->state,
NULL);
}
else if(pAudioDecData->state == COMP_StatePause || pAudioDecData->state == COMP_StateExecuting)
{
alogv("ADec_Comp: pause/executing[0x%x]->idle ...", pAudioDecData->state);
pAudioDecData->state = COMP_StateIdle;
#if 0
if (pAudioDecData->pDecoder != NULL)
{
int ret = DestroyAudioDecoder(pAudioDecData->pDecoder);
pAudioDecData->pDecoder = NULL;
if ((FALSE==pAudioDecData->mInputPortTunnelFlag) && (pAudioDecData->mAudioStreamInfo.pCodecSpecificData))
{
free(pAudioDecData->mAudioStreamInfo.pCodecSpecificData);
pAudioDecData->mAudioStreamInfo.pCodecSpecificData = NULL;
}
}
#endif
pAudioDecData->pCallbacks->EventHandler(
pAudioDecData->hSelf,
pAudioDecData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pAudioDecData->state,
NULL);
}
else
{
aloge("Fatal error! current state[0x%x] can't turn to idle!", pAudioDecData->state);
pAudioDecData->pCallbacks->EventHandler(
pAudioDecData->hSelf,
pAudioDecData->pAppData,
COMP_EventError,
ERR_ADEC_INCORRECT_STATE_TRANSITION,
0,
NULL);
}
// send message to input_thread
input_cmd_msg.command = SetState;
input_cmd_msg.para0 = COMP_StateIdle;
put_message(&pInputData->cmd_queue, &input_cmd_msg);
// Sync input thread state
pthread_mutex_lock(&pInputData->mStateLock);
while (pInputData->state != COMP_StateIdle)
{
pthread_cond_wait(&pInputData->mStateCond, &pInputData->mStateLock);
}
pthread_mutex_unlock(&pInputData->mStateLock);
break;
}
case COMP_StateExecuting:
{
if (pAudioDecData->state == COMP_StateIdle || pAudioDecData->state == COMP_StatePause)
{
if (pAudioDecData->state == COMP_StateIdle)
{
if (NULL == pAudioDecData->pDecoder) {
if (AudioDecLibInit(pAudioDecData) != SUCCESS) {
aloge("Fatal error! Why AudioDecLibInit fail again?!!!");
goto EXIT;
}
}
}
pAudioDecData->state = COMP_StateExecuting;
pAudioDecData->pCallbacks->EventHandler(
pAudioDecData->hSelf,
pAudioDecData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pAudioDecData->state,
NULL);
// send message to input_thread
input_cmd_msg.command = SetState;
input_cmd_msg.para0 = COMP_StateExecuting;
put_message(&pInputData->cmd_queue, &input_cmd_msg);
// Sync input thread state
pthread_mutex_lock(&pInputData->mStateLock);
while (pInputData->state != COMP_StateExecuting)
{
pthread_cond_wait(&pInputData->mStateCond, &pInputData->mStateLock);
}
pthread_mutex_unlock(&pInputData->mStateLock);
}
else
{
pAudioDecData->pCallbacks->EventHandler(
pAudioDecData->hSelf,
pAudioDecData->pAppData,
COMP_EventError,
ERR_ADEC_INCORRECT_STATE_TRANSITION,
0,
NULL);
}
break;
}
case COMP_StatePause:
{
// Transition can only happen from idle or executing state
if (pAudioDecData->state == COMP_StateIdle || pAudioDecData->state == COMP_StateExecuting)
{
pAudioDecData->state = COMP_StatePause;
pAudioDecData->pCallbacks->EventHandler(
pAudioDecData->hSelf,
pAudioDecData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pAudioDecData->state,
NULL);
// send message to input_thread
input_cmd_msg.command = SetState;
input_cmd_msg.para0 = COMP_StatePause;
put_message(&pInputData->cmd_queue, &input_cmd_msg);
// Sync input thread state
pthread_mutex_lock(&pInputData->mStateLock);
while (pInputData->state != COMP_StatePause)
{
pthread_cond_wait(&pInputData->mStateCond, &pInputData->mStateLock);
}
pthread_mutex_unlock(&pInputData->mStateLock);
}
else
{
pAudioDecData->pCallbacks->EventHandler(
pAudioDecData->hSelf, pAudioDecData->pAppData,
COMP_EventError,
ERR_ADEC_INCORRECT_STATE_TRANSITION,
0,
NULL);
}
break;
}
default:
{
break;
}
}
}
pthread_mutex_unlock(&pAudioDecData->mStateLock);
}
else if (cmd == StopPort)
{
}
else if (cmd == Flush)
{
}
else if (cmd == Stop)
{
// send message to input_thread
// input_cmd_msg.command = Stop;
// input_cmd_msg.para0 = 0;
// put_message(&pInputData->cmd_queue, &input_cmd_msg);
goto EXIT;
}
else if(cmd == ADecComp_AbsAvailable)
{
alogv("ADec abs available");
}
else if(cmd == ADecComp_PcmBufAvailable)
{
alogv("ADec PcmBuf available");
}
//precede to process message
goto PROCESS_MESSAGE;
}
if (pAudioDecData->state == COMP_StateExecuting)
{
if (pAudioDecData->mbEof)
{
alogd("ADec EOF!");
TMessage_WaitQueueNotEmpty(&pAudioDecData->cmd_queue, 0);
goto PROCESS_MESSAGE;
}
AudioStreamInfo *pAudioStreamInfo = NULL;
if(FALSE==pAudioDecData->mInputPortTunnelFlag)
{
pAudioStreamInfo = &pAudioDecData->mAudioStreamInfo;
}
else
{
pAudioStreamInfo = (AudioStreamInfo *)(pAudioDecData->sInPortExtraDef.pVendorInfo);
}
REREQUEST_OUT_BUFFER:
// Ensure output buffer ready
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
char* pPcmOutBufWrPos = NULL;
int pcmOutSize = 0;
if (DecRequestPcmBuffer(pAudioDecData->pDecoder, &pPcmOutBufWrPos) < 0)
{
//alogv("no pcm buffer, wait.");
pAudioDecData->mWaitPcmBufFlag = TRUE;
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
TMessage_WaitQueueNotEmpty(&pAudioDecData->cmd_queue, 0);
goto PROCESS_MESSAGE;
}
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
// config AudioDecoder before decode.
if ((int)pAudioDecData->audio_channel != pAudioDecData->pDecoder->nAudioChannel)
{
alogw("wow! It is happened! audio_channel[%d]", pAudioDecData->audio_channel);
pAudioDecData->pDecoder->nAudioChannel = pAudioDecData->audio_channel;
}
if (pAudioDecData->volumegain != pAudioDecData->pDecoder->volumegain)
{
alogw("wow! It is happened! volumegain[%d]", pAudioDecData->volumegain);
pAudioDecData->pDecoder->volumegain = pAudioDecData->volumegain;
}
if (pAudioDecData->mute != pAudioDecData->pDecoder->mute)
{
alogw("wow! It is happened! mute[%d]", pAudioDecData->mute);
pAudioDecData->pDecoder->mute = pAudioDecData->mute;
}
if (pAudioDecData->enable_resample != pAudioDecData->pDecoder->nEnableResample)
{
alogw("wow! It is happened! enable_resample[%d]", pAudioDecData->enable_resample);
pAudioDecData->pDecoder->nEnableResample = pAudioDecData->enable_resample;
}
// Decode audio data
ret = DecodeAudioStream(pAudioDecData->pDecoder, pAudioStreamInfo, pPcmOutBufWrPos, &pcmOutSize);
//alogv("Calling decoder, ret = %d", ret);
if (ret == ERR_AUDIO_DEC_NO_BITSTREAM)
{
pAudioDecData->mNoBitstreamCounter++;
}
else
{
pAudioDecData->mNoBitstreamCounter = 0;
}
if (ret == ERR_AUDIO_DEC_NONE)
{
if( pAudioStreamInfo->nSampleRate != pAudioDecData->ad_cedar_info.out_samplerate
|| pAudioStreamInfo->nChannelNum != pAudioDecData->ad_cedar_info.out_channels
)
{
alogd("fatal error! ADecode info channels-sample_rate[%d-%d]!=[%d-%d],bit_width:%d",
pAudioDecData->ad_cedar_info.out_channels, pAudioDecData->ad_cedar_info.out_samplerate,
pAudioStreamInfo->nChannelNum, pAudioStreamInfo->nSampleRate,
pAudioStreamInfo->nBitsPerSample);
pAudioDecData->ad_cedar_info.out_samplerate = pAudioStreamInfo->nSampleRate;
pAudioDecData->ad_cedar_info.out_channels = pAudioStreamInfo->nChannelNum;
}
if (pAudioDecData->get_audio_info_flag)
{// get audio info only once
AudioStreamInfo *as_info = pAudioStreamInfo;
pAudioDecData->get_audio_info_flag = 0;
if(pAudioDecData->ad_cedar_info.bitpersample != 16)
{
alogd("Be careful! why get bitwidth=%d after decode first bs?!", pAudioDecData->ad_cedar_info.bitpersample);
}
if(0 == pAudioDecData->ad_cedar_info.bitpersample)
{
if (as_info->nBitsPerSample == 0)//0 means pcm S16_LE, adecoder should optimize
{
pAudioDecData->ad_cedar_info.bitpersample = 16;
alogd("Be careful! reset bitwidth:0->16!");
}
else
{
pAudioDecData->ad_cedar_info.bitpersample = as_info->nBitsPerSample;
alogd("Be careful! reset bitwidth:0->[%d]", pAudioDecData->ad_cedar_info.bitpersample);
//assert(0);
}
}
if (!as_info->nChannelNum || !as_info->nSampleRate || !as_info->nBitsPerSample)
{
aloge("get audio decoder info fail[%d-%d-%d]!", as_info->nChannelNum, as_info->nSampleRate, as_info->nBitsPerSample);
}
ADEC_CHN_ATTR_S *pADecAttr = &pAudioDecData->mADecChnAttr;
pADecAttr->sampleRate = as_info->nSampleRate;
pADecAttr->channels = as_info->nChannelNum;
pADecAttr->bitsPerSample = pAudioDecData->ad_cedar_info.bitpersample;
alogd("ADecode first BS! channels:%d, sample_rate:%d, bit_width:%d, use this to init AudioRenderHal!",
pADecAttr->channels, pADecAttr->sampleRate, pADecAttr->bitsPerSample);
}
DecUpdatePcmBuffer(pAudioDecData->pDecoder, pcmOutSize);
if (FALSE == pAudioDecData->mInputPortTunnelFlag)
{
pthread_mutex_lock(&pAudioDecData->mAbsInputMutex);
if (pAudioDecData->mWaitEmptyAbsFlag)
{
int bsValidSize = AudioStreamDataSize(pAudioDecData->pDecoder); // inport bs data_size that ready to be decoded
int bsTotalSize = AudioStreamBufferSize(pAudioDecData->pDecoder); // inport bs space total size: 128KB
int bsEmptySize = bsTotalSize - bsValidSize;
int bsValidPercent, bsValidChunkCnt;
BsQueryQuality(pAudioDecData->pDecoder, &bsValidPercent, &bsValidChunkCnt);
int bsTotalChunkCnt = AudioStreamBufferMaxFrameNum();
int bsEmptyChunkCnt = bsTotalChunkCnt - bsValidChunkCnt; // for most time, bsEmptyChunkCnt = 0
if ((bsEmptySize >= pAudioDecData->mRequestAbsLen) && (bsEmptyChunkCnt > 0))
{
//alogv("signal abs empty_buf ready. reqBufLen:%d, emptyBufLen:%d, emptyChunkCnt:%d",
// pAudioDecData->mRequestAbsLen, bsEmptySize, bsEmptyChunkCnt);
pthread_cond_signal(&pAudioDecData->mEmptyAbsCondition);
}
}
pthread_mutex_unlock(&pAudioDecData->mAbsInputMutex);
}
//send pcm data to AudioRender component by tunnel or to APP by non-tunnel
while (1)
{
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
if (list_empty(&pAudioDecData->mIdleOutFrameList))
{
alogw("Low probability! adecComp idle out frame list is empty, malloc more!");
ADecCompOutputFrame *pNode = (ADecCompOutputFrame*)malloc(sizeof(ADecCompOutputFrame));
if (pNode)
{
list_add_tail(&pNode->mList, &pAudioDecData->mIdleOutFrameList);
pAudioDecData->mFrameNodeNum++;
}
else
{
aloge("fatal error! malloc fail[%s]!", strerror(errno));
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
if (TMessage_WaitQueueNotEmpty(&pAudioDecData->cmd_queue, 200) > 0)
{
goto PROCESS_MESSAGE;
}
else
{
continue;
}
}
}
ADecCompOutputFrame *pOutFrame = list_first_entry(&pAudioDecData->mIdleOutFrameList, ADecCompOutputFrame, mList);
pOutFrame->mTimeStamp = PlybkRequestPcmPts(pAudioDecData->pDecoder); //Decode Lib API
int reqRet = PlybkRequestPcmBuffer(pAudioDecData->pDecoder, (unsigned char**)&pOutFrame->mpPcmBuf, &pOutFrame->mSize); //Decode Lib API
if (reqRet == 0)
{
ADEC_CHN_ATTR_S *pPcmAttr = &pAudioDecData->mADecChnAttr;
pOutFrame->mChannelNum = pPcmAttr->channels;
pOutFrame->mBitsPerSample = pPcmAttr->bitsPerSample;
pOutFrame->mSampleRate = pPcmAttr->sampleRate;
pOutFrame->mId = pAudioDecData->mFrameId++;
list_del(&pOutFrame->mList);
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
if (pAudioDecData->mOutputPortTunnelFlag)
{
MM_COMPONENTTYPE *pOutTunnelComp = (MM_COMPONENTTYPE*)(pAudioDecData->sOutPortTunnelInfo.hTunnel);
COMP_BUFFERHEADERTYPE obh;
obh.nOutputPortIndex = pAudioDecData->sOutPortTunnelInfo.nPortIndex;
obh.nInputPortIndex = pAudioDecData->sOutPortTunnelInfo.nTunnelPortIndex;
AUDIO_FRAME_S stAFrame;
config_AUDIO_FRAME_S_by_ADecCompOutputFrame(&stAFrame, pOutFrame);
obh.pOutputPortPrivate = (void*)&stAFrame;
//put frame to usedList first, avoid AO return frame quickly.
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
list_add_tail(&pOutFrame->mList, &pAudioDecData->mUsedOutFrameList);
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
int omxRet = COMP_EmptyThisBuffer(pOutTunnelComp, &obh);
if (SUCCESS == omxRet)
{
}
else
{
if (ERR_AO_SYS_NOTREADY == omxRet)
{
alogd("Be careful! ADec output frame fail[0x%x], maybe next component status is Loaded, return frame!", omxRet);
}
int releaseRet = PlybkUpdatePcmBuffer(pAudioDecData->pDecoder, pOutFrame->mSize);
if (releaseRet != 0)
{
aloge("fatal error! return pcmBuffer fail ret[%d]", ret);
}
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
list_move(&pOutFrame->mList, &pAudioDecData->mIdleOutFrameList);
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
}
}
else
{
pthread_mutex_lock(&pAudioDecData->mOutFrameListMutex);
list_add_tail(&pOutFrame->mList, &pAudioDecData->mReadyOutFrameList);
if (pAudioDecData->mWaitReadyFrameFlag)
{
pthread_cond_signal(&pAudioDecData->mReadyFrameCondition);
}
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
}
}
else
{
pthread_mutex_unlock(&pAudioDecData->mOutFrameListMutex);
break;
}
}
}
else if(ret == ERR_AUDIO_DEC_ABSEND)
{
alogd("adec return abs end!");
pAudioDecData->pCallbacks->EventHandler(pAudioDecData->hSelf, pAudioDecData->pAppData,
COMP_EventBufferFlag, 0, 0, NULL);
//pAudioDecData->state = COMP_StateIdle;
pAudioDecData->mbEof = TRUE;
}
else if(ret == ERR_AUDIO_DEC_NO_BITSTREAM)
{
alogv("adec return no bitstream!");
if (pAudioDecData->priv_flag & CDX_comp_PRIV_FLAGS_STREAMEOF)
{
alogd("audio decoder notify EOF");
CompSendEvent(pAudioDecData, COMP_EventBufferFlag, COMP_CommandStateSet, 0);
//pAudioDecData->state = COMP_StateIdle;
pAudioDecData->mbEof = TRUE;
}
else
{
pthread_mutex_lock(&pAudioDecData->mAbsInputMutex);
int streamSize = AudioStreamDataSize(pAudioDecData->pDecoder);
if (streamSize > 0 && pAudioDecData->mNoBitstreamCounter < 2)
{
alogv("Low probability! AudioDec Component has input abs[%d]", streamSize);
pthread_mutex_unlock(&pAudioDecData->mAbsInputMutex);
}
else
{
pAudioDecData->mWaitAbsInputFlag = TRUE;
pthread_mutex_unlock(&pAudioDecData->mAbsInputMutex);
TMessage_WaitQueueNotEmpty(&pAudioDecData->cmd_queue, 0);
}
goto PROCESS_MESSAGE;
}
}
else if(ret == ERR_AUDIO_DEC_EXIT || ret == ERR_AUDIO_DEC_ENDINGCHKFAIL)
{
if (ret == ERR_AUDIO_DEC_EXIT)
{
aloge("ret == ERR_AUDIO_DEC_EXIT");
}
else
{
aloge("ret == ERR_AUDIO_DEC_ENDINGCHKFAIL");
}
//pAudioDecData->pCallbacks->EventHandler(pAudioDecData->hSelf, pAudioDecData->pAppData,
// OMX_EventBufferFlag, 0, 0, NULL);
//pAudioDecData->state = OMX_StateIdle;
}
else if (ret == ERR_AUDIO_DEC_VIDEOJUMP)
{
alogd("adec jump done[%d]!", pcmOutSize);
}
else
{
aloge("fatal error! impossible ADec decode ret[%d]!", ret);
// show inport buf info.
int bsValidSize = AudioStreamDataSize(pAudioDecData->pDecoder); // inport bs data_size that can be decode but have not be decoded
int bsTotalSize = AudioStreamBufferSize(pAudioDecData->pDecoder); // inport bs space total size: 128KB
int bsEmptySize = bsTotalSize - bsValidSize;
aloge("inport bs buf info: totalSize-%d, validSize-%d, emptySize-%d", bsTotalSize, bsValidSize, bsEmptySize);
// show outport buf info.
int pcmValidPercentage, pcmValidSize;
PcmQueryQuality(pAudioDecData->pDecoder, &pcmValidPercentage, &pcmValidSize);
//int pcmTotalSize = pcmValidSize*100/pcmValidPercentage;
//pcmTotalSize = AudioPCMDataSize(pAudioDecData->pDecoder);
aloge("outport pcm buf info: totalSize-, validPer-%d, validSize-%d", pcmValidPercentage, pcmValidSize);
}
}
else
{
TMessage_WaitQueueNotEmpty(&pAudioDecData->cmd_queue, 0);
}
}
EXIT:
alogv("AudioDecoder ComponentThread stopped");
return (void*) SUCCESS;
}
/*****************************************************************************/
static void* InputThread(void* pThreadData)
{
ERRORTYPE eError = SUCCESS;
COMP_BUFFERHEADERTYPE omx_buffer_header;
EncodedStream dmxOutBuf;
DMXPKT_NODE_T *pEntry, *pTmp;
int cmddata;
CompInternalMsgType cmd;
message_t cmd_msg;
int bsValidSize, bsTotalSize, bsEmptySize;
// Get component private data
AUDIODEC_INPUT_DATA* pInputData = (AUDIODEC_INPUT_DATA*)pThreadData;
AUDIODECDATATYPE* pAudioDecData = pInputData->pAudioDecData;
alogd("AudioDecoder InputThread start run...");
sprintf(pInputData->mThreadName, "ADecInput%d", pAudioDecData->mMppChnInfo.mChnId);
prctl(PR_SET_NAME, (unsigned long)pInputData->mThreadName, 0, 0, 0);
while (1)
{
PROCESS_MESSAGE:
if (get_message(&pInputData->cmd_queue, &cmd_msg) == 0)
{// pump message from message queue
//alogd("input thread got message: cmd=%d cmddata=%d (3-Execute 4-Pause)", cmd, cmddata);
cmd = cmd_msg.command;
cmddata = cmd_msg.para0;
// State transition command
if (cmd == SetState)
{
switch ((COMP_STATETYPE) (cmddata))
{
case COMP_StateLoaded:
{
if(pInputData->state!=COMP_StateIdle)
{
aloge("fatal error! inputThread state[0x%x] != Idle", pInputData->state);
}
pthread_mutex_lock(&pInputData->mAbsListLock);
struct list_head *pList;
pInputData->mbWaitAbsFullFlag = TRUE;
while (1)
{
int cnt = 0;
list_for_each(pList, &pInputData->mIdleAbsList) { cnt++; }
if (cnt < pInputData->mNodeNum)
{
alogd("wait input thread [%d]nodes to idleList!", pInputData->mNodeNum - cnt);
pthread_cond_wait(&pInputData->mAbsFullCond, &pInputData->mAbsListLock);
}
else
{
break;
}
}
pInputData->mbWaitAbsFullFlag = FALSE;
pthread_mutex_unlock(&pInputData->mAbsListLock);
pthread_mutex_lock(&pInputData->mStateLock);
pInputData->state = COMP_StateLoaded;
pthread_cond_signal(&pInputData->mStateCond);
pthread_mutex_unlock(&pInputData->mStateLock);
break;
}
case COMP_StateIdle:
{
pthread_mutex_lock(&pInputData->mStateLock);
pInputData->state = COMP_StateIdle;
pthread_cond_signal(&pInputData->mStateCond);
pthread_mutex_unlock(&pInputData->mStateLock);
break;
}
case COMP_StateExecuting:
{
pthread_mutex_lock(&pInputData->mStateLock);
pInputData->state = COMP_StateExecuting;
pthread_cond_signal(&pInputData->mStateCond);
pthread_mutex_unlock(&pInputData->mStateLock);
break;
}
case COMP_StatePause:
{
pthread_mutex_lock(&pInputData->mStateLock);
pInputData->state = COMP_StatePause;
pthread_cond_signal(&pInputData->mStateCond);
pthread_mutex_unlock(&pInputData->mStateLock);
break;
}
default:
break;
}
}
else if(cmd == ADecComp_AbsAvailable)
{
}
else if (cmd == StopPort)
{
}
else if (cmd == Flush)
{
}
else if (cmd == Stop)
{// Kill thread
goto EXIT;
}
//precede to process message
goto PROCESS_MESSAGE;
}
// wait until executing state
if (pInputData->state != COMP_StateExecuting)
{
TMessage_WaitQueueNotEmpty(&pInputData->cmd_queue, 0);
goto PROCESS_MESSAGE;
}
if (pAudioDecData->mInputPortTunnelFlag == FALSE)
{// inport non-tunnel mode
//Do nothing right now
TMessage_WaitQueueNotEmpty(&pInputData->cmd_queue, 0);
goto PROCESS_MESSAGE;
}
// Get A component
MM_COMPONENTTYPE *pInTunnelComp = (MM_COMPONENTTYPE*)(pAudioDecData->sInPortTunnelInfo.hTunnel);
COMP_PARAM_PORTDEFINITIONTYPE* pPortDef = &pAudioDecData->sInPortDef;
// check whether we should request buffer
pthread_mutex_lock(&pInputData->mAbsListLock);
if (list_empty(&pInputData->mIdleAbsList))
{// no need to request buffer if Idle list is empty
if (pInputData->mWaitAbsValidFlag == TRUE)
{
alogv("waiting message forever again when mWaitAbsValidFlag is set");
}
pInputData->mWaitAbsValidFlag = TRUE;
pthread_mutex_unlock(&pInputData->mAbsListLock);
TMessage_WaitQueueNotEmpty(&pInputData->cmd_queue, 0);
goto PROCESS_MESSAGE;
}
else
{// request buffer to fill node in Idle list
// Get buffer status of Decode Lib
// static int sgLargestSize = 512*1024;
bsValidSize = AudioStreamDataSize(pAudioDecData->pDecoder); // inport bs data_size that can be decode but have not be decoded
bsTotalSize = AudioStreamBufferSize(pAudioDecData->pDecoder); // inport bs space total size: 128KB
bsEmptySize = bsTotalSize - bsValidSize;
//alogd(" bsValidSize[%d] bsTotalSize[%d] bsEmptySize[%d]",bsValidSize, bsTotalSize, bsEmptySize);
// if(sgLargestSize < pInputData->nRequestLen)
// {
// sgLargestSize = pInputData->nRequestLen;
// alogw("Notice This! more big chunkSize:%d", sgLargestSize);
// }
if (bsEmptySize < pInputData->nRequestLen)
{// request bs buffer again after A component return bs buffer
//alogw("low buffer (size = %d) from decode lib", bsEmptySize);
if(bsTotalSize < pInputData->nRequestLen)
{
aloge("fatal error! Adec Bs totalSize[%d]<requestLen[%d]", bsTotalSize, pInputData->nRequestLen);
}
pthread_mutex_unlock(&pInputData->mAbsListLock);
TMessage_WaitQueueNotEmpty(&pInputData->cmd_queue, 200);
goto PROCESS_MESSAGE;
}
else
{
pInputData->nRequestLen = 0;
}
// Request buffer from Decode lib
pEntry = list_first_entry(&pInputData->mIdleAbsList, DMXPKT_NODE_T, mList);
pEntry->stEncodedStream.media_type = CDX_PacketAudio;
pEntry->stEncodedStream.nTobeFillLen = bsEmptySize;
omx_buffer_header.pOutputPortPrivate = (void*)&pEntry->stEncodedStream;
omx_buffer_header.nInputPortIndex = pPortDef->nPortIndex;
pthread_mutex_lock(&pAudioDecData->mAbsInputMutex);
int adecRet = ParserRequestBsBuffer
(pAudioDecData->pDecoder
,pEntry->stEncodedStream.nTobeFillLen
,(unsigned char**)&pEntry->stEncodedStream.pBuffer
,(int*)&pEntry->stEncodedStream.nBufferLen
,(unsigned char**)&pEntry->stEncodedStream.pBufferExtra
,(int*)&pEntry->stEncodedStream.nBufferExtraLen
,(int*)&omx_buffer_header.nOffset
);
pthread_mutex_unlock(&pAudioDecData->mAbsInputMutex);
if (adecRet != 0)
{
// compare to InputThread, WorkThread is slower! which means decoder is slower than parser.
// We need check whether ValidChunkCnt increase to 128(AUDIO_BITSTREAM_BUFFER_MAX_FRAME_NUM)!
int bsValidPercent, bsValidChunkCnt;
BsQueryQuality(pAudioDecData->pDecoder, &bsValidPercent, &bsValidChunkCnt);
int bsRealEmptyBufSize = AudioStreamBufferSize(pAudioDecData->pDecoder)*bsValidPercent/100;
int bsTotalChunkCnt = AudioStreamBufferMaxFrameNum();
int bsEmptyChunkCnt = bsTotalChunkCnt - bsValidChunkCnt; // for most time, bsEmptyChunkCnt = 0
if (bsEmptyChunkCnt > 0)
aloge("RequestBufSz(%d) > RealEmptyBsBufSz(%d)?! ret: %d", bsEmptySize, bsRealEmptyBufSize, adecRet);
pthread_mutex_unlock(&pInputData->mAbsListLock);
TMessage_WaitQueueNotEmpty(&pInputData->cmd_queue, 200);
goto PROCESS_MESSAGE;
}
list_move_tail(&pEntry->mList, &pInputData->mUsingAbsList);
pthread_mutex_unlock(&pInputData->mAbsListLock);
// 调用A component的FillThisBuffer
eError = COMP_FillThisBuffer(pInTunnelComp, &omx_buffer_header);
if(eError != SUCCESS)
{
pthread_mutex_lock(&pInputData->mAbsListLock);
list_move_tail(&pEntry->mList, &pInputData->mIdleAbsList);
pthread_mutex_unlock(&pInputData->mAbsListLock);
}
if (eError == SUCCESS)
{
}
else if ((eError & 0x1FFF) == EN_ERR_NOT_PERM)
{
TMessage_WaitQueueNotEmpty(&pInputData->cmd_queue, 200);
goto PROCESS_MESSAGE;
}
else
{
aloge("fatal error! Low probability! Tunneled inport component FillThisBuffer fail(%d)", eError);
abort();
}
}
}
EXIT:
alogv("AudioDecoder InputThread stopped");
return (void*) SUCCESS;
}