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

5131 lines
219 KiB
C
Executable File

/*******************************************************************************
-- --
-- CedarX Multimedia Framework --
-- --
-- the Multimedia Framework for Linux/Android System --
-- --
-- This software is confidential and proprietary and may be used --
-- only as expressly authorized by a licensing agreement from --
-- Softwinner Products. --
-- --
-- (C) COPYRIGHT 2011 SOFTWINNER PRODUCTS --
-- ALL RIGHTS RESERVED --
-- --
-- The entire notice above must be reproduced --
-- on all copies and should not be removed. --
-- --
*******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
//#define LOG_NDEBUG 0
#define LOG_TAG "VideoDec_Component"
#include <utils/plat_log.h>
#include <errno.h>
//#include <ion/ion.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/ioctl.h>
#include <mm_component.h>
#include <tmessage.h>
#include <tsemaphore.h>
#include <CDX_MediaFormat.h>
#include <cedarx_demux.h>
#include <memoryAdapter.h>
#include <vdecoder.h>
#include <cdc_config.h>
#include <iniparserapi.h>
//#include <CDX_FormatConvert.h>
#include <EncodedStream.h>
#include <DemuxCompStream.h>
#include <SystemBase.h>
#include <VdecStream.h>
#include "VideoDec_Component.h"
#include "VideoDec_DataType.h"
#include "VideoDec_InputThread.h"
#include <sys_linux_ioctl.h>
#include <mpi_videoformat_conversion.h>
#include <EPIXELFORMAT_g2d_format_convert.h>
#include <media_common_vcodec.h>
#include <ion_memmanager.h>
#include <linux/g2d_driver.h>
//#include <ConfigOption.h>
#include <cdx_list.h>
#define VIDEO_DEC_TIME_DEBUG 0
//#define CDX_COMP_PRIV_FLAGS_ABORT_WAIT_VBV_SEM (1<<16)
#define MAX_YUV_PLANNER_MODE_OUTPUT_WIDTH 1288 //to make 1280x720 pixel by pixel
#define MAX_YUV_PLANNER_MODE_OUTPUT_HEIGHT 728
//#define USE_HARDWARE_FORMAT_CONVERT
#define VDEC_FRAME_COUNT (32)
#define VDEC_COMP_FRAME_COUNT (4)
//#define __WRITEOUT_FRAMEBUFFER
//------------------------------------------------------------------------------------
//extern void* cedar_sys_phymalloc_map(unsigned int size, int align);
//extern void cedar_sys_phyfree_map(void *buf);
//extern unsigned int cedarv_address_phy2vir(void *addr);
//extern unsigned int cedarv_address_vir2phy(void *addr);
//extern void cedarv_set_ve_freq(int freq); //MHz
//extern void cedarx_cache_op(long start, long end, int flag);
static void *ComponentThread(void *pThreadData);
static void *VideoDecCompFrameBufferThread(void *pThreadData);
//ERRORTYPE VideoDecRequstBuffer(COMP_HANDLETYPE hComponent, unsigned int nPortIndex, COMP_BUFFERHEADERTYPE* pBuffer);
//ERRORTYPE VideoDecReleaseBuffer(COMP_HANDLETYPE hComponent, unsigned int nPortIndex, COMP_BUFFERHEADERTYPE* pBuffer);
typedef struct {
void *mpFrameBuf; //memory address, virtual address.
int mIonUserHandle; //ion_user_handle_t
//BOOL mbIonUserHandleValid; //1:ion_user_handle_t is valid, 0:ion_user_handle_t is free.
struct list_head mList;
} VDANWBuffer;
typedef struct {
VideoStreamInfo mStreamInfo;
struct list_head mList;
} VDStreamInfo;
//static void cb_release_frame_buffer_sem(void *cookie)
//{
// VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)cookie;
// cdx_sem_up(&pVideoDecData->sem_frame_buffer);
// return;
//}
//
//static void cb_free_vbs_buffer_sem(void *cookie)
//{
// VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)cookie;
// cdx_sem_signal(&pVideoDecData->sem_vdec_2_dmx); TODO: del it??
// return;
//}
static enum EPIXELFORMAT convertPixelFormatCdx2Vdec(int format)
{
if (format == CDX_PIXEL_FORMAT_AW_MB422) {
return PIXEL_FORMAT_YUV_MB32_422;
} else if (format == CDX_PIXEL_FORMAT_AW_MB420) {
return PIXEL_FORMAT_YUV_MB32_420;
} else if (format == CDX_PIXEL_FORMAT_YV12) {
return PIXEL_FORMAT_YV12;
} else if (format == CDX_PIXEL_FORMAT_YCrCb_420_SP) {
return PIXEL_FORMAT_NV21;
} else if (format == CDX_PIXEL_FORMAT_AW_NV12) {
return PIXEL_FORMAT_NV12;
} else {
alogw("fatal error! format=0x%x", format);
return PIXEL_FORMAT_YUV_MB32_420;
}
}
ROTATE_E map_cedarv_rotation_to_ROTATE_E(int cedarv_rotation)
{
ROTATE_E nRotate;
//clock wise. 0: no rotate, 1: 90 degree (clock wise), 2: 180, 3: 270, 4: horizon flip, 5: vertical flip; implicitly means picture rotate anti-clockwise.
switch (cedarv_rotation) {
case 0:
nRotate = ROTATE_NONE;
break;
case 1:
nRotate = ROTATE_90;
break;
case 2:
nRotate = ROTATE_180;
break;
case 3:
nRotate = ROTATE_270;
break;
default:
aloge("fatal error! not support other rotation[%d]", cedarv_rotation);
nRotate = ROTATE_NONE;
break;
}
return nRotate;
}
int map_ROTATE_E_to_cedarv_rotation(ROTATE_E eRotate)
{
//clock wise. 0: no rotate, 1: 90 degree (clock wise), 2: 180, 3: 270, 4: horizon flip, 5: vertical flip; implicitly means picture rotate anti-clockwise.
int cedarvRotation;
switch (eRotate) {
case ROTATE_NONE:
cedarvRotation = 0;
break;
case ROTATE_90:
cedarvRotation = 1;
break;
case ROTATE_180:
cedarvRotation = 2;
break;
case ROTATE_270:
cedarvRotation = 3;
break;
default:
aloge("fatal error! unknown rotate[%d]", eRotate);
cedarvRotation = 0;
break;
}
return cedarvRotation;
}
ERRORTYPE config_VIDEO_FRAME_INFO_S_by_VideoPicture(VIDEO_FRAME_INFO_S *pFrameInfo, VideoPicture *pVideoPicture,
VIDEODECDATATYPE *pVideoDecData)
{
memset(pFrameInfo, 0, sizeof(VIDEO_FRAME_INFO_S));
pFrameInfo->mId = pVideoPicture->nID;
pFrameInfo->VFrame.mWidth = pVideoPicture->nWidth;
pFrameInfo->VFrame.mHeight = pVideoPicture->nHeight;
if (pVideoPicture->bIsProgressive) {
pFrameInfo->VFrame.mField = VIDEO_FIELD_FRAME;
} else {
pFrameInfo->VFrame.mField = VIDEO_FIELD_INTERLACED;
}
pFrameInfo->VFrame.mPixelFormat = map_EPIXELFORMAT_to_PIXEL_FORMAT_E(pVideoPicture->ePixelFormat);
pFrameInfo->VFrame.mVideoFormat = VIDEO_FORMAT_LINEAR;
pFrameInfo->VFrame.mCompressMode = COMPRESS_MODE_NONE;
// pFrameInfo->VFrame.mPhyAddr[0] = (unsigned int)CdcMemGetPhysicAddressCpu(pVideoDecData->mMemOps, pVideoPicture->pData0);
// pFrameInfo->VFrame.mPhyAddr[1] = (unsigned int)CdcMemGetPhysicAddressCpu(pVideoDecData->mMemOps, pVideoPicture->pData1);
// pFrameInfo->VFrame.mPhyAddr[2] = (unsigned int)CdcMemGetPhysicAddressCpu(pVideoDecData->mMemOps, pVideoPicture->pData2);
pFrameInfo->VFrame.mPhyAddr[0] = (unsigned int)pVideoPicture->phyYBufAddr;
pFrameInfo->VFrame.mPhyAddr[1] = (unsigned int)pVideoPicture->phyCBufAddr;
pFrameInfo->VFrame.mPhyAddr[2] = pVideoPicture->pData2!=NULL?(unsigned int)pVideoPicture->phyCBufAddr+pVideoPicture->nWidth*pVideoPicture->nHeight/4:0;
pFrameInfo->VFrame.mpVirAddr[0] = pVideoPicture->pData0;
pFrameInfo->VFrame.mpVirAddr[1] = pVideoPicture->pData1;
pFrameInfo->VFrame.mpVirAddr[2] = pVideoPicture->pData2;
pFrameInfo->VFrame.mStride[0] = pVideoPicture->nLineStride;
pFrameInfo->VFrame.mStride[1] = pVideoPicture->nLineStride;
pFrameInfo->VFrame.mStride[2] = pVideoPicture->nLineStride;
pFrameInfo->VFrame.mOffsetTop = pVideoPicture->nTopOffset;
pFrameInfo->VFrame.mOffsetBottom = pVideoPicture->nBottomOffset;
pFrameInfo->VFrame.mOffsetLeft = pVideoPicture->nLeftOffset;
pFrameInfo->VFrame.mOffsetRight = pVideoPicture->nRightOffset;
pFrameInfo->VFrame.mpts = pVideoPicture->nPts;
return SUCCESS;
}
/**
* nRotation: vdeclib should static rotate, clock wise. 0: no rotate, 1: 90 degree (clock wise), 2: 180, 3: 270,
* 4: horizon flip, 5: vertical flip; implicitly means picture rotate anti-clockwise.
* we will malloc one buffer contain y,u,v data.
*/
static ERRORTYPE CompFrameInit(VDecCompOutputFrame *pCompFrame, VideoPicture *pPicture, int nRotation)
{
static int sgCompFrameIdCounter = 0;
ERRORTYPE ret = SUCCESS;
if(nRotation < 0 || nRotation > 3)
{
aloge("fatal error! wrong rotation[%d].", nRotation);
return ERR_VDEC_ILLEGAL_PARAM;
}
if(0 == nRotation)
{
alogw("fatal error! rotation is 0");
}
if(pCompFrame->mpPicture)
{
aloge("fatal error! mpPicture[%p] is not NULL.", pCompFrame->mpPicture);
return SUCCESS;
}
pCompFrame->mpPicture = (VideoPicture*)calloc(sizeof(VideoPicture), 1);
if(NULL == pCompFrame->mpPicture)
{
aloge("fatal error! malloc fail!");
return ERR_VDEC_NOMEM;
}
*pCompFrame->mpPicture = *pPicture;
pCompFrame->mpPicture->nID = sgCompFrameIdCounter++;
if(1 == nRotation)
{
pCompFrame->mpPicture->nWidth = pPicture->nHeight;
pCompFrame->mpPicture->nHeight = pPicture->nWidth;
pCompFrame->mpPicture->nLineStride = pPicture->nHeight;
pCompFrame->mpPicture->nTopOffset = pPicture->nLeftOffset;
pCompFrame->mpPicture->nLeftOffset = pPicture->nHeight - pPicture->nBottomOffset;
pCompFrame->mpPicture->nBottomOffset = pPicture->nRightOffset;
pCompFrame->mpPicture->nRightOffset = pPicture->nHeight - pPicture->nTopOffset;
}
else if(2 == nRotation)
{
pCompFrame->mpPicture->nWidth = pPicture->nWidth;
pCompFrame->mpPicture->nHeight = pPicture->nHeight;
pCompFrame->mpPicture->nLineStride = pPicture->nWidth;
pCompFrame->mpPicture->nTopOffset = pPicture->nHeight - pPicture->nBottomOffset;
pCompFrame->mpPicture->nLeftOffset = pPicture->nWidth - pPicture->nRightOffset;
pCompFrame->mpPicture->nBottomOffset = pPicture->nHeight - pPicture->nTopOffset;
pCompFrame->mpPicture->nRightOffset = pPicture->nWidth - pPicture->nLeftOffset;
}
else if(3 == nRotation)
{
pCompFrame->mpPicture->nWidth = pPicture->nHeight;
pCompFrame->mpPicture->nHeight = pPicture->nWidth;
pCompFrame->mpPicture->nLineStride = pPicture->nHeight;
pCompFrame->mpPicture->nTopOffset = pPicture->nWidth - pPicture->nRightOffset;
pCompFrame->mpPicture->nLeftOffset = pPicture->nTopOffset;
pCompFrame->mpPicture->nBottomOffset = pPicture->nWidth - pPicture->nLeftOffset;
pCompFrame->mpPicture->nRightOffset = pPicture->nBottomOffset;
}
else
{
aloge("fatal error! rotation[%d] is not support!", nRotation);
}
int nYSize = 0;
int nUSize = 0;
int nVSize = 0;
if(PIXEL_FORMAT_YV12 == pCompFrame->mpPicture->ePixelFormat)
{
nYSize = pCompFrame->mpPicture->nWidth * pCompFrame->mpPicture->nHeight;
nUSize = pCompFrame->mpPicture->nWidth * pCompFrame->mpPicture->nHeight/4;
nVSize = nUSize;
IonAllocAttr stAttr;
memset(&stAttr, 0, sizeof(IonAllocAttr));
stAttr.mLen = nYSize + nUSize + nVSize;
stAttr.mAlign = 0;
stAttr.mIonHeapType = IonHeapType_IOMMU;
stAttr.mbSupportCache = 0;
char *pVirBuf = (char*)ion_allocMem_extend(&stAttr);
if(NULL == pVirBuf)
{
aloge("fatal error! ion malloc size[%d] fail", nYSize + nUSize + nVSize);
ret = ERR_VDEC_NOMEM;
goto _err0;
}
uintptr_t nPhyBuf = (uintptr_t)ion_getMemPhyAddr(pVirBuf);
pCompFrame->mpPicture->pData0 = pVirBuf;
pCompFrame->mpPicture->pData1 = pVirBuf + nYSize;
pCompFrame->mpPicture->pData2 = pVirBuf + nYSize + nUSize;
pCompFrame->mpPicture->pData3 = NULL;
pCompFrame->mpPicture->phyYBufAddr = nPhyBuf;
pCompFrame->mpPicture->phyCBufAddr = nPhyBuf + nYSize;
}
else if(PIXEL_FORMAT_NV21 == pCompFrame->mpPicture->ePixelFormat
|| PIXEL_FORMAT_NV12 == pCompFrame->mpPicture->ePixelFormat)
{
nYSize = pCompFrame->mpPicture->nWidth * pCompFrame->mpPicture->nHeight;
nUSize = pCompFrame->mpPicture->nWidth * pCompFrame->mpPicture->nHeight/2;
nVSize = 0;
IonAllocAttr stAttr;
stAttr.mLen = nYSize + nUSize + nVSize;
stAttr.mAlign = 0;
stAttr.mIonHeapType = IonHeapType_IOMMU;
stAttr.mbSupportCache = 0;
char *pVirBuf = (char*)ion_allocMem_extend(&stAttr);
if(NULL == pVirBuf)
{
aloge("fatal error! ion malloc size[%d] fail", nYSize + nUSize + nVSize);
ret = ERR_VDEC_NOMEM;
goto _err0;
}
uintptr_t nPhyBuf = (uintptr_t)ion_getMemPhyAddr(pVirBuf);
pCompFrame->mpPicture->pData0 = pVirBuf;
pCompFrame->mpPicture->pData1 = pVirBuf + nYSize;
pCompFrame->mpPicture->pData2 = NULL;
pCompFrame->mpPicture->pData3 = NULL;
pCompFrame->mpPicture->phyYBufAddr = nPhyBuf;
pCompFrame->mpPicture->phyCBufAddr = nPhyBuf + nYSize;
}
else
{
aloge("fatal error! pixelFormat[0x%x] is not support!", pCompFrame->mpPicture->ePixelFormat);
ret = ERR_VDEC_ILLEGAL_PARAM;
goto _err0;
}
alogd("comp frame init, rotation[%d], size[%dx%d, %d,%d,%d,%d]",
nRotation, pCompFrame->mpPicture->nWidth, pCompFrame->mpPicture->nHeight,
pCompFrame->mpPicture->nTopOffset, pCompFrame->mpPicture->nLeftOffset,
pCompFrame->mpPicture->nBottomOffset, pCompFrame->mpPicture->nRightOffset);
return ret;
_err0:
free(pCompFrame->mpPicture);
pCompFrame->mpPicture = NULL;
return ret;
}
static ERRORTYPE CompFrameDestroy(VDecCompOutputFrame *pCompFrame)
{
if(pCompFrame->mpPicture)
{
if(pCompFrame->mpPicture->pData0)
{
ion_freeMem(pCompFrame->mpPicture->pData0);
pCompFrame->mpPicture->pData0 = NULL;
}
if(pCompFrame->mpPicture->pData1)
{
//ion_freeMem(pCompFrame->mpPicture->pData1);
pCompFrame->mpPicture->pData1 = NULL;
}
if(pCompFrame->mpPicture->pData2)
{
//ion_freeMem(pCompFrame->mpPicture->pData2);
pCompFrame->mpPicture->pData2 = NULL;
}
if(pCompFrame->mpPicture->pData3)
{
//ion_freeMem(pCompFrame->mpPicture->pData3);
pCompFrame->mpPicture->pData3 = NULL;
}
free(pCompFrame->mpPicture);
pCompFrame->mpPicture = NULL;
}
return SUCCESS;
}
int decideMaxScaleRatio(int maxRatio, VideoStreamInfo *pStreamInfo)
{
#if (AWCHIP == AW_V5 || AWCHIP == AW_V316 || AWCHIP == AW_V459 || AWCHIP == AW_V853)
switch(pStreamInfo->eCodecFormat)
{
case VIDEO_CODEC_FORMAT_H264:
case VIDEO_CODEC_FORMAT_H265:
{
if (maxRatio > 2)
{
alogd("limit ScaleDownRatio[%d]->[2] of CodecFormat[0x%x]", maxRatio, pStreamInfo->eCodecFormat);
maxRatio = 2;
}
break;
}
case VIDEO_CODEC_FORMAT_MJPEG:
{
if (maxRatio > 3)
{
alogd("limit ScaleDownRatio[%d]->[3] of CodecFormat[0x%x]", maxRatio, pStreamInfo->eCodecFormat);
maxRatio = 3;
}
break;
}
default:
{
aloge("fatal error! unknown CodecFormat[0x%x]", pStreamInfo->eCodecFormat);
if (maxRatio > 2)
{
alogd("limit ScaleDownRatio[%d]->[2] of CodecFormat[0x%x]", maxRatio, pStreamInfo->eCodecFormat);
maxRatio = 2;
}
break;
}
}
#else
aloge("fatal error! unknown chip");
if (maxRatio > 2)
{
alogd("limit ScaleDownRatio[%d]->[2] of CodecFormat[0x%x]", maxRatio, pStreamInfo->eCodecFormat);
maxRatio = 2;
}
#endif
return maxRatio;
}
ERRORTYPE VideoDecDecideCompFrameBufferMode(VIDEODECDATATYPE *pVideoDecData)
{
VideoStreamInfo *pVideoStreamInfo = (VideoStreamInfo *)pVideoDecData->sInPortExtraDef[VDEC_PORT_SUFFIX_DEMUX].pVendorInfo;
if(0 == pVideoDecData->cedarv_rotation)
{
pVideoDecData->mbUseCompFrame = FALSE;
}
else
{
#if 0
if(VIDEO_CODEC_FORMAT_H265 == pVideoStreamInfo->eCodecFormat
||VIDEO_CODEC_FORMAT_MJPEG == pVideoStreamInfo->eCodecFormat
||VIDEO_CODEC_FORMAT_H264 == pVideoStreamInfo->eCodecFormat)
{
pVideoDecData->mbUseCompFrame = TRUE;
}
else
{
pVideoDecData->mbUseCompFrame = FALSE;
}
#else
pVideoDecData->mbUseCompFrame = TRUE;
#endif
}
if(pVideoDecData->mbUseCompFrame)
{
if(pVideoDecData->mG2DHandle < 0)
{
pVideoDecData->mG2DHandle = open("/dev/g2d", O_RDWR, 0);
if (pVideoDecData->mG2DHandle < 0)
{
aloge("fatal error! open /dev/g2d failed");
}
alogv("open /dev/g2d OK");
}
else
{
aloge("fatal error! why g2dDriver[%d] is open?", pVideoDecData->mG2DHandle);
}
if(pVideoDecData->mG2DHandle >= 0)
{
if(0 == pVideoDecData->mCompFrameBufferThreadId)
{
pVideoDecData->mCompFBThreadState = COMP_StateLoaded;
int err = pthread_create(&pVideoDecData->mCompFrameBufferThreadId, NULL, VideoDecCompFrameBufferThread, pVideoDecData);
if (err || !pVideoDecData->mCompFrameBufferThreadId)
{
aloge("fatal error! create thread fail![%d], threadId[%d]", err, (int)pVideoDecData->mCompFrameBufferThreadId);
}
message_t msg;
InitMessage(&msg);
msg.command = SetState;
msg.para0 = COMP_StateIdle;
msg.pReply = ConstructMessageReply();
putMessageWithData(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
int ret;
while(1)
{
ret = cdx_sem_down_timedwait(&msg.pReply->ReplySem, 5000);
if(ret != 0)
{
aloge("fatal error! vdecChn[%d] wait FBThd turn state[%d] timeout[0x%x]", pVideoDecData->mMppChnInfo.mChnId, msg.para0, ret);
}
else
{
break;
}
}
int replyRet = msg.pReply->ReplyResult;
if(replyRet != 0)
{
aloge("fatal error! vdecChn[%d] receive FBThd set state reply: 0x%x!", pVideoDecData->mMppChnInfo.mChnId, replyRet);
}
DestructMessageReply(msg.pReply);
msg.pReply = NULL;
pthread_mutex_lock(&pVideoDecData->mCompFBThreadStateLock);
if(pVideoDecData->mCompFBThreadState != COMP_StateIdle)
{
aloge("fatal error! vdecChn[%d] FBThd state[%d] wrong", pVideoDecData->mMppChnInfo.mChnId, pVideoDecData->mCompFBThreadState);
}
pthread_mutex_unlock(&pVideoDecData->mCompFBThreadStateLock);
}
else
{
aloge("fatal error! comp FBThreadId[%d] is exist!", (int)pVideoDecData->mCompFrameBufferThreadId);
}
}
else
{
pVideoDecData->mbUseCompFrame = FALSE;
}
}
return SUCCESS;
}
int CedarvCodecInit(VIDEODECDATATYPE *pVideoDecData)
{
int ret;
VideoDecoder *pCedarV;
if (pVideoDecData->pCedarV) {
alogd("VideoDecoder already exist!");
return SUCCESS;
}
VideoStreamInfo *pVideoStreamInfo, tmpStreamInfo;
if (pVideoDecData->mInputPortTunnelFlag)
{
pVideoStreamInfo = (VideoStreamInfo *)pVideoDecData->sInPortExtraDef[VDEC_PORT_SUFFIX_DEMUX].pVendorInfo;
if (NULL == pVideoStreamInfo) {
alogd("video stream info is not got, can't init vdeclib now.");
return ERR_VDEC_ILLEGAL_PARAM;
}
}
else
{
alogd("JPEG or H264 decoder init begin!");
pVideoStreamInfo = &tmpStreamInfo;
memset(pVideoStreamInfo, 0, sizeof(VideoStreamInfo));
memcpy(pVideoStreamInfo, &pVideoDecData->stVideoStreamInfo, sizeof(VideoStreamInfo));
pVideoStreamInfo->eCodecFormat = map_PAYLOAD_TYPE_E_to_EVIDEOCODECFORMAT(pVideoDecData->mChnAttr.mType);
pVideoStreamInfo->bIsFramePackage = 1;
}
if(pVideoDecData->mbForceFramePackage)
{
if(0 == pVideoStreamInfo->bIsFramePackage)
{
alogd("parser set bIsFramePackage to 0, but vdec force to 1");
pVideoStreamInfo->bIsFramePackage = 1;
}
}
alogd("video_format: %d", pVideoStreamInfo->eCodecFormat);
if (!(pVideoStreamInfo->eCodecFormat >= VIDEO_CODEC_FORMAT_MIN &&
pVideoStreamInfo->eCodecFormat <= VIDEO_CODEC_FORMAT_MAX)) {
aloge("!!!!can't find cedar codecs!, eCodecFormat(%d)\n", pVideoStreamInfo->eCodecFormat);
return -1;
}
//pCedarV = libcedarv_init(&ret);
pCedarV = CreateVideoDecoder();
if (pCedarV == NULL) {
aloge("libcedarv_init error!");
return -1;
}
if (pVideoDecData->max_resolution)
{
int nMaxCapabilityWidth = pVideoDecData->max_resolution >> 16;
int nMaxCapabilityHeight = pVideoDecData->max_resolution & 0xffff;
if(pVideoDecData->cedarv_max_width > nMaxCapabilityWidth)
{
alogd("Be careful! user setting decode width[%d] > Capability[%d]", pVideoDecData->cedarv_max_width, nMaxCapabilityWidth);
pVideoDecData->cedarv_max_width = nMaxCapabilityWidth;
}
if(pVideoDecData->cedarv_max_height > nMaxCapabilityHeight)
{
alogd("Be careful! user setting decode height[%d] > Capability[%d]", pVideoDecData->cedarv_max_height, nMaxCapabilityHeight);
pVideoDecData->cedarv_max_height = nMaxCapabilityHeight;
}
}
memset(&pVideoDecData->mVConfig, 0, sizeof(VConfig));
//config scale param
if (pVideoDecData->cedarv_max_width != 0 && pVideoDecData->cedarv_max_height != 0 &&
pVideoStreamInfo->nWidth != 0 && pVideoStreamInfo->nHeight != 0)
{
int i;
int nOutput, nActual;
//may be need scale.
if (pVideoStreamInfo->nWidth > pVideoDecData->cedarv_max_width) {
pVideoDecData->mVConfig.bScaleDownEn = 1;
nOutput = pVideoDecData->cedarv_max_width;
nActual = pVideoStreamInfo->nWidth;
for (i = 0; nOutput < nActual; i++) {
nOutput *= 2;
}
pVideoDecData->mVConfig.nHorizonScaleDownRatio = i;
}
if (pVideoStreamInfo->nHeight > pVideoDecData->cedarv_max_height) {
pVideoDecData->mVConfig.bScaleDownEn = 1;
nOutput = pVideoDecData->cedarv_max_height;
nActual = pVideoStreamInfo->nHeight;
for (i = 0; nOutput < nActual; i++) {
nOutput *= 2;
}
pVideoDecData->mVConfig.nVerticalScaleDownRatio = i;
}
int maxRatio = pVideoDecData->mVConfig.nHorizonScaleDownRatio > pVideoDecData->mVConfig.nVerticalScaleDownRatio
? pVideoDecData->mVConfig.nHorizonScaleDownRatio
: pVideoDecData->mVConfig.nVerticalScaleDownRatio;
maxRatio = decideMaxScaleRatio(maxRatio, pVideoStreamInfo);
pVideoDecData->mVConfig.nHorizonScaleDownRatio = pVideoDecData->mVConfig.nVerticalScaleDownRatio = maxRatio;
if (pVideoDecData->mVConfig.bScaleDownEn)
{
alogd("ScaleDownRatio[%dx%d], max_output_resolution[%dx%d], stream_resolution[%dx%d]",
pVideoDecData->mVConfig.nHorizonScaleDownRatio, pVideoDecData->mVConfig.nVerticalScaleDownRatio,
pVideoDecData->cedarv_max_width, pVideoDecData->cedarv_max_height, pVideoStreamInfo->nWidth,
pVideoStreamInfo->nHeight);
if (pVideoDecData->mVConfig.nHorizonScaleDownRatio > pVideoDecData->mVConfig.nVerticalScaleDownRatio)
{
pVideoDecData->mVConfig.nVerticalScaleDownRatio = pVideoDecData->mVConfig.nHorizonScaleDownRatio;
}
else
{
pVideoDecData->mVConfig.nHorizonScaleDownRatio = pVideoDecData->mVConfig.nVerticalScaleDownRatio;
}
alogd("final, ScaleDownRatio[%dx%d]", pVideoDecData->mVConfig.nHorizonScaleDownRatio, pVideoDecData->mVConfig.nVerticalScaleDownRatio);
}
}
if (0 == pVideoDecData->cedarv_rotation)
{
pVideoDecData->mVConfig.bRotationEn = 0;
pVideoDecData->mVConfig.nRotateDegree = 0;
}
else
{
if(VIDEO_CODEC_FORMAT_H265 == pVideoStreamInfo->eCodecFormat
|| VIDEO_CODEC_FORMAT_MJPEG == pVideoStreamInfo->eCodecFormat
|| VIDEO_CODEC_FORMAT_H264 == pVideoStreamInfo->eCodecFormat)
{
alogd("don't use vdeclib to rotate[%d] for vdecFormat[0x%x], we use g2d!", pVideoDecData->cedarv_rotation, pVideoStreamInfo->eCodecFormat);
pVideoDecData->mVConfig.bRotationEn = 0;
pVideoDecData->mVConfig.nRotateDegree = 0;
}
else
{
pVideoDecData->mVConfig.bRotationEn = 1;
pVideoDecData->mVConfig.nRotateDegree = pVideoDecData->cedarv_rotation;
}
}
pVideoDecData->mVConfig.bThumbnailMode = 0;
if (pVideoDecData->cedarv_output_setting == PIXEL_FORMAT_DEFAULT) {
pVideoDecData->mVConfig.eOutputPixelFormat = PIXEL_FORMAT_YV12; //PIXEL_FORMAT_YUV_MB32_420;
alogd("vdec output format default to PIXEL_FORMAT_YV12");
} else {
pVideoDecData->mVConfig.eOutputPixelFormat = pVideoDecData->cedarv_output_setting;
alogd("vdec output format set to [0x%x]", pVideoDecData->mVConfig.eOutputPixelFormat);
}
pVideoDecData->mVConfig.bNoBFrames = 0;
if (pVideoDecData->disable_3d) {
pVideoDecData->mVConfig.bDisable3D = 1;
} else {
pVideoDecData->mVConfig.bDisable3D = 0;
}
pVideoDecData->mVConfig.bSupportMaf = 0;
pVideoDecData->mVConfig.bDispErrorFrame = 0;
if(pVideoDecData->config_vbv_size%1024 != 0)
{
int alignSize = AWALIGN(pVideoDecData->config_vbv_size, 1024);
aloge("fatal error! vbvSize[%d] must 1024 align! we will extend it to [%d]", pVideoDecData->config_vbv_size, alignSize);
pVideoDecData->config_vbv_size = alignSize;
}
pVideoDecData->mVConfig.nVbvBufferSize = pVideoDecData->config_vbv_size;
alogd("config vbvBufferSize[%d]KB", pVideoDecData->mVConfig.nVbvBufferSize / 1024);
pVideoDecData->mVConfig.nAlignStride = 32;
if (0 == pVideoDecData->nDisplayFrameRequestMode) {
pVideoDecData->mVConfig.bGpuBufValid = 0;
} else {
pVideoDecData->mVConfig.bGpuBufValid = 1;
}
pVideoDecData->mVConfig.nDisplayHoldingFrameBufferNum = GetConfigParamterInt("pic_4list_num", NUM_OF_PICTURES_KEEP_IN_LIST) + pVideoDecData->mVdecExtraFrameNum;
pVideoDecData->mVConfig.nDeInterlaceHoldingFrameBufferNum = GetConfigParamterInt("pic_4di_num", 0); //NUM_OF_PICTURES_KEEPPED_BY_DEINTERLACE;
pVideoDecData->mVConfig.nRotateHoldingFrameBufferNum = GetConfigParamterInt("pic_4rotate_num", 0); //NUM_OF_PICTURES_KEEPPED_BY_ROTATE;
pVideoDecData->mVConfig.nDecodeSmoothFrameBufferNum = GetConfigParamterInt("pic_4smooth_num", 0); //NUM_OF_PICTURES_FOR_EXTRA_SMOOTH;
pVideoDecData->mVConfig.nFrameBufferNum = pVideoDecData->mChnAttr.mnFrameBufferNum;
pVideoDecData->mVConfig.memops = pVideoDecData->mMemOps;
// for jpeg decode, reinit VConfig!
if (pVideoDecData->mChnAttr.mType == PT_JPEG)
{
//memset(&pVideoDecData->mVConfig, 0, sizeof(VConfig));
//if(pVideoDecData->config_vbv_size > 0)
//{
// pVideoDecData->mVConfig.nVbvBufferSize = ALIGN(pVideoDecData->config_vbv_size, 1024);
//}
//else
//{
// pVideoDecData->mVConfig.nVbvBufferSize = 4*1024*1024;
//}
pVideoDecData->mVConfig.bThumbnailMode = 0;
alogd("ThumbnailMode=%d", pVideoDecData->mVConfig.bThumbnailMode);
//pVideoDecData->mVConfig.nAlignStride = 32;
//pVideoDecData->mVConfig.eOutputPixelFormat = pVideoDecData->cedarv_output_setting;
}
//open proc to decoder,as defualt
pVideoDecData->mVConfig.bSetProcInfoEnable = 1;
if(0 == pVideoStreamInfo->nFrameRate)
{
pVideoDecData->mVConfig.nSetProcInfoFreq = 25;
}
else
{
pVideoDecData->mVConfig.nSetProcInfoFreq = pVideoStreamInfo->nFrameRate / 1000;
if(0 == pVideoDecData->mVConfig.nSetProcInfoFreq)
{
pVideoDecData->mVConfig.nSetProcInfoFreq = 25;
}
}
pVideoDecData->mVConfig.nChannelNum = pVideoDecData->mMppChnInfo.mChnId;
//init sub output pic output channel
if(pVideoDecData->cedarv_second_output_en)
{
if(PT_MJPEG == pVideoDecData->mChnAttr.mType)
{
pVideoDecData->mVConfig.bSecOutputEn = 1;
pVideoDecData->mVConfig.eSecOutputPixelFormat = pVideoDecData->cedarv_second_output_setting;
pVideoDecData->mVConfig.nSecHorizonScaleDownRatio = pVideoDecData->cedarv_second_horizon_scale_down_ratio;
pVideoDecData->mVConfig.nSecVerticalScaleDownRatio = pVideoDecData->cedarv_second_vertical_scale_down_ratio;
}
else
{
aloge("fatal error, the [%d] decode type do support second output!", pVideoDecData->mChnAttr.mType);
pVideoDecData->mVConfig.bSecOutputEn = 0;
pVideoDecData->cedarv_second_output_en = 0;
}
}
//ret = pCedarV->open(pCedarV);
ret = InitializeVideoDecoder(pCedarV, pVideoStreamInfo, &pVideoDecData->mVConfig);
alogd("video stream info size[%dx%d]", pVideoStreamInfo->nWidth, pVideoStreamInfo->nHeight);
if (ret < 0) {
aloge("CedarV open error! ret=%d", ret);
return -1;
}
pVideoDecData->mbConfigVdecFrameBuffers = FALSE;
//pCedarV->ioctrl(pCedarV, CEDARV_COMMAND_PLAY, 0);
pVideoDecData->pCedarV = pCedarV;
if(pVideoDecData->mVEFreq)
{
alogd("vdec init VE freq to [%d]MHz", pVideoDecData->mVEFreq);
VideoDecoderSetFreq(pVideoDecData->pCedarV, pVideoDecData->mVEFreq);
}
alogv("pVideoDecData->pCedarV:%p", pVideoDecData->pCedarV);
return 0;
}
ERRORTYPE VideoDecTunnel_SendVDecCompOutputFrame(VIDEODECDATATYPE *pVideoDecData, VDecCompOutputFrame *pOutFrame)
{
ERRORTYPE ret;
if(FALSE == pVideoDecData->mbUseCompFrame)
{
ERRORTYPE omxRet;
int releaseRet;
COMP_BUFFERHEADERTYPE obh;
obh.nOutputPortIndex = pVideoDecData->sOutPortTunnelInfo.nPortIndex;
obh.nInputPortIndex = pVideoDecData->sOutPortTunnelInfo.nTunnelPortIndex;
VIDEO_FRAME_INFO_S stFrameInfo;
config_VIDEO_FRAME_INFO_S_by_VideoPicture(&stFrameInfo, pOutFrame->mpPicture, pVideoDecData);
obh.pOutputPortPrivate = (void *)&stFrameInfo;
omxRet = COMP_EmptyThisBuffer(pVideoDecData->sOutPortTunnelInfo.hTunnel, &obh);
if (SUCCESS == omxRet)
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
list_add_tail(&pOutFrame->mList, &pVideoDecData->mUsedOutFrameList);
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
ret = SUCCESS;
}
else
{
int commonErrCode = omxRet&0x1FFF;
if (EN_ERR_INCORRECT_STATE_OPERATION == commonErrCode)
{
alogd("Be careful! VDec output frame fail[0x%x], maybe next component status is Loaded, return frame!", omxRet);
}
else if(EN_ERR_SYS_NOTREADY == commonErrCode)
{
alogv("frame is ignored.");
}
else
{
aloge("fatal error! errCode[0x%x]", omxRet);
}
releaseRet = ReturnPicture(pVideoDecData->pCedarV, (VideoPicture *)pOutFrame->mpPicture);
if (releaseRet != 0)
{
aloge("fatal error! Return Picture() fail ret[%d]", releaseRet);
}
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
list_add(&pOutFrame->mList, &pVideoDecData->mIdleOutFrameList);
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
ret = ERR_VDEC_INCORRECT_STATE_OPERATION;
}
return ret;
}
else
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
list_add_tail(&pOutFrame->mList, &pVideoDecData->mUsedOutFrameList);
if(pVideoDecData->mbCompFBThreadWaitVdecFrameInput)
{
pVideoDecData->mbCompFBThreadWaitVdecFrameInput = FALSE;
message_t msg;
msg.command = VDecComp_CompFrameBufferThread_InputFrameAvailable;
put_message(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
}
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
return SUCCESS;
}
}
ERRORTYPE VideoDecReturnVDecCompOutputFrameToIdleList(VIDEODECDATATYPE *pVideoDecData, int nFrameId)
{
VDecCompOutputFrame *pOutFrame = NULL;
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
VDecCompOutputFrame *pEntry;
BOOL bFindFlag = FALSE;
list_for_each_entry(pEntry, &pVideoDecData->mUsedOutFrameList, mList)
{
if (pEntry->mpPicture->nID == nFrameId)
{
if(!bFindFlag)
{
bFindFlag = TRUE;
pOutFrame = pEntry;
//break;
}
else
{
aloge("fatal error! find frameId[0x%x] again!", pEntry->mpPicture->nID);
}
}
}
if(!bFindFlag)
{
aloge("fatal error! can't find frameId[%d], check code!", nFrameId);
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
return ERR_VDEC_ILLEGAL_PARAM;
}
int ret = ReturnPicture(pVideoDecData->pCedarV, (VideoPicture *)pOutFrame->mpPicture);
if (ret != 0)
{
aloge("fatal error! Return Picture() fail ret[%d]", ret);
}
list_move_tail(&pOutFrame->mList, &pVideoDecData->mIdleOutFrameList);
if (pVideoDecData->mWaitOutFrameFlag)
{
pVideoDecData->mWaitOutFrameFlag = FALSE;
message_t msg;
msg.command = VDecComp_OutFrameAvailable;
put_message(&pVideoDecData->cmd_queue, &msg);
}
if (pVideoDecData->mWaitOutFrameFullFlag)
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoDecData->mIdleOutFrameList)
{
cnt++;
}
if (cnt >= pVideoDecData->mFrameNodeNum)
{
pthread_cond_signal(&pVideoDecData->mOutFrameFullCondition);
}
}
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
return SUCCESS;
}
ERRORTYPE VideoDecTunnel_ReturnVDecCompOutputFrame(VIDEODECDATATYPE *pVideoDecData, int nFrameId)
{
if(FALSE == pVideoDecData->mbUseCompFrame)
{
return VideoDecReturnVDecCompOutputFrameToIdleList(pVideoDecData, nFrameId);
}
else
{
//return it to VideoDec CompFrameBufferThread
VDecCompOutputFrame *pOutFrame = NULL;
pthread_mutex_lock(&pVideoDecData->mCompOutFramesLock);
VDecCompOutputFrame *pEntry;
BOOL bFindFlag = FALSE;
list_for_each_entry(pEntry, &pVideoDecData->mCompUsedOutFrameList, mList)
{
if (pEntry->mpPicture->nID == nFrameId)
{
if(!bFindFlag)
{
bFindFlag = TRUE;
pOutFrame = pEntry;
//break;
}
else
{
aloge("fatal error! find frameId[0x%x] again!", pEntry->mpPicture->nID);
}
}
}
if(!bFindFlag)
{
aloge("fatal error! can't find frameId[%d], check code!", nFrameId);
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
return ERR_VDEC_ILLEGAL_PARAM;
}
list_move_tail(&pOutFrame->mList, &pVideoDecData->mCompIdleOutFrameList);
if (pVideoDecData->mbCompFBThreadWaitOutFrame)
{
pVideoDecData->mbCompFBThreadWaitOutFrame = FALSE;
message_t msg;
msg.command = VDecComp_CompFrameBufferThread_OutFrameAvailable;
put_message(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
}
if (pVideoDecData->mbCompFBThreadWaitOutFrameFull)
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoDecData->mCompIdleOutFrameList)
{
cnt++;
}
if (cnt >= VDEC_COMP_FRAME_COUNT)
{
pthread_cond_signal(&pVideoDecData->mCompFBThreadOutFrameFullCondition);
}
}
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
return SUCCESS;
}
}
ERRORTYPE VideoDecNonTunnel_ReadyVDecCompOutputFrame(VIDEODECDATATYPE *pVideoDecData, VDecCompOutputFrame *pOutFrame)
{
ERRORTYPE ret;
if(FALSE == pVideoDecData->mbUseCompFrame)
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
list_add_tail(&pOutFrame->mList, &pVideoDecData->mReadyOutFrameList);
if (pVideoDecData->mWaitReadyFrameFlag)
{
pthread_cond_signal(&pVideoDecData->mReadyFrameCondition);
}
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
return SUCCESS;
}
else
{
//send to VideoDec CompFrameBufferThread, rotate at there.
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
list_add_tail(&pOutFrame->mList, &pVideoDecData->mUsedOutFrameList);
if(pVideoDecData->mbCompFBThreadWaitVdecFrameInput)
{
pVideoDecData->mbCompFBThreadWaitVdecFrameInput = FALSE;
message_t msg;
msg.command = VDecComp_CompFrameBufferThread_InputFrameAvailable;
put_message(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
}
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
return SUCCESS;
}
}
ERRORTYPE VideoDecNonTunnel_GetVDecCompOutputFrame(
PARAM_IN VIDEODECDATATYPE *pVideoDecData,
PARAM_OUT VIDEO_FRAME_INFO_S *pFrameInfo,
PARAM_OUT VIDEO_FRAME_INFO_S *pSubFrameInfo,
PARAM_IN int nMilliSec)
{
ERRORTYPE eError;
if(FALSE == pVideoDecData->mbUseCompFrame)
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
_TryToGetOutFrame:
if (!list_empty(&pVideoDecData->mReadyOutFrameList))
{
VDecCompOutputFrame *pOutFrame = list_first_entry(&pVideoDecData->mReadyOutFrameList, VDecCompOutputFrame, mList);
config_VIDEO_FRAME_INFO_S_by_VideoPicture(pFrameInfo, pOutFrame->mpPicture, pVideoDecData);
if(pVideoDecData->mVConfig.bSecOutputEn)
{
if(pSubFrameInfo && pOutFrame->mpSubPicture)
{
if(pOutFrame->mpPicture->nID != pOutFrame->mpSubPicture->nID)
{
aloge("fatal error! why frame pair id is not same?[%d]!=[%d]", pOutFrame->mpPicture->nID, pOutFrame->mpSubPicture->nID);
}
config_VIDEO_FRAME_INFO_S_by_VideoPicture(pSubFrameInfo, pOutFrame->mpSubPicture, pVideoDecData);
}
else
{
aloge("fatal error!,if you want get sub portout, why not get stream?");
}
}
list_move_tail(&pOutFrame->mList, &pVideoDecData->mUsedOutFrameList);
eError = SUCCESS;
}
else
{
if (0 == nMilliSec)
{
eError = ERR_VDEC_NOBUF;
}
else if (nMilliSec < 0)
{
pVideoDecData->mWaitReadyFrameFlag = TRUE;
while (list_empty(&pVideoDecData->mReadyOutFrameList))
{
pthread_cond_wait(&pVideoDecData->mReadyFrameCondition, &pVideoDecData->mOutFrameListMutex);
}
pVideoDecData->mWaitReadyFrameFlag = FALSE;
goto _TryToGetOutFrame;
}
else
{
pVideoDecData->mWaitReadyFrameFlag = TRUE;
int ret = pthread_cond_wait_timeout(&pVideoDecData->mReadyFrameCondition, &pVideoDecData->mOutFrameListMutex, nMilliSec);
if (ETIMEDOUT == ret)
{
alogv("wait output frame timeout[%d]ms, ret[%d]", nMilliSec, ret);
eError = ERR_VDEC_NOBUF;
pVideoDecData->mWaitReadyFrameFlag = FALSE;
}
else if (0 == ret)
{
pVideoDecData->mWaitReadyFrameFlag = FALSE;
goto _TryToGetOutFrame;
}
else
{
aloge("fatal error! pthread cond wait timeout ret[%d]", ret);
eError = ERR_VDEC_NOBUF;
pVideoDecData->mWaitReadyFrameFlag = FALSE;
}
}
}
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
return eError;
}
else
{
pthread_mutex_lock(&pVideoDecData->mCompOutFramesLock);
_TryToGetCompOutFrame:
if (!list_empty(&pVideoDecData->mCompReadyOutFrameList))
{
VDecCompOutputFrame *pOutFrame = list_first_entry(&pVideoDecData->mCompReadyOutFrameList, VDecCompOutputFrame, mList);
config_VIDEO_FRAME_INFO_S_by_VideoPicture(pFrameInfo, pOutFrame->mpPicture, pVideoDecData);
if(pVideoDecData->mVConfig.bSecOutputEn)
{
if(pSubFrameInfo && pOutFrame->mpSubPicture)
{
config_VIDEO_FRAME_INFO_S_by_VideoPicture(pSubFrameInfo, pOutFrame->mpSubPicture, pVideoDecData);
}
else
{
aloge("fatal error!,if you want get sub portout, why not get stream?");
}
}
list_move_tail(&pOutFrame->mList, &pVideoDecData->mCompUsedOutFrameList);
eError = SUCCESS;
}
else
{
if (0 == nMilliSec)
{
eError = ERR_VDEC_NOBUF;
}
else if (nMilliSec < 0)
{
pVideoDecData->mbCompWaitReadyFrame = TRUE;
while (list_empty(&pVideoDecData->mCompReadyOutFrameList))
{
pthread_cond_wait(&pVideoDecData->mCompReadyFrameCondition, &pVideoDecData->mCompOutFramesLock);
}
pVideoDecData->mbCompWaitReadyFrame = FALSE;
goto _TryToGetCompOutFrame;
}
else
{
pVideoDecData->mbCompWaitReadyFrame = TRUE;
int ret = pthread_cond_wait_timeout(&pVideoDecData->mCompReadyFrameCondition, &pVideoDecData->mCompOutFramesLock, nMilliSec);
if (ETIMEDOUT == ret)
{
alogv("wait output frame timeout[%d]ms, ret[%d]", nMilliSec, ret);
eError = ERR_VDEC_NOBUF;
pVideoDecData->mbCompWaitReadyFrame = FALSE;
}
else if (0 == ret)
{
pVideoDecData->mbCompWaitReadyFrame = FALSE;
goto _TryToGetCompOutFrame;
}
else
{
aloge("fatal error! pthread cond wait timeout ret[%d]", ret);
eError = ERR_VDEC_NOBUF;
pVideoDecData->mbCompWaitReadyFrame = FALSE;
}
}
}
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
return eError;
}
}
ERRORTYPE VideoDecNonTunnel_ReleaseVDecCompOutputFrame(
PARAM_IN VIDEODECDATATYPE *pVideoDecData,
PARAM_IN VIDEO_FRAME_INFO_S *pFrameInfo,
PARAM_IN VIDEO_FRAME_INFO_S *pSubFrameInfo)
{
ERRORTYPE eError = SUCCESS;
if(FALSE == pVideoDecData->mbUseCompFrame)
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
if (!list_empty(&pVideoDecData->mUsedOutFrameList))
{
int ret; //EVDECODERESULT
int nFindFlag = 0;
VDecCompOutputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoDecData->mUsedOutFrameList, mList)
{
if (pEntry->mpPicture->nID == pFrameInfo->mId)
{
ret = ReturnPicture(pVideoDecData->pCedarV, pEntry->mpPicture);
if (ret != 0)
{
aloge("fatal error! Return Picture() fail ret[%d]", ret);
}
if(pVideoDecData->mVConfig.bSecOutputEn)
{
if(pEntry->mpSubPicture)
{
if(pEntry->mpSubPicture->nID != pSubFrameInfo->mId)
{
aloge("fatal error! why subPicture Id is not match?[%d]!=[%d]", pEntry->mpSubPicture->nID, pSubFrameInfo->mId);
}
ret = ReturnPicture(pVideoDecData->pCedarV, pEntry->mpSubPicture); // must return sub frame to vdecoder, do not check id.
if(ret != 0)
{
aloge("fatal error! Return Picture() fail ret[%d]", ret);
}
}
else
{
aloge("fatal error! if you want get sub portout, why not get stream?");
}
}
list_move_tail(&pEntry->mList, &pVideoDecData->mIdleOutFrameList);
if (pVideoDecData->mWaitOutFrameFlag)
{
pVideoDecData->mWaitOutFrameFlag = FALSE;
message_t msg;
msg.command = VDecComp_OutFrameAvailable;
put_message(&pVideoDecData->cmd_queue, &msg);
}
if (pVideoDecData->mWaitOutFrameFullFlag)
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoDecData->mIdleOutFrameList) { cnt++; }
if (cnt >= pVideoDecData->mFrameNodeNum)
{
pthread_cond_signal(&pVideoDecData->mOutFrameFullCondition);
}
}
nFindFlag = 1;
eError = SUCCESS;
break;
}
}
if (0 == nFindFlag)
{
aloge("fatal error! vdec frameId[0x%x] is not match UsedOutFrameList", pFrameInfo->mId);
eError = ERR_VDEC_ILLEGAL_PARAM;
}
}
else
{
aloge("fatal error! vdec frameId[0x%x] is not find in UsedOutFrameList", pFrameInfo->mId);
eError = ERR_VDEC_ILLEGAL_PARAM;
}
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
return eError;
}
else
{
//return it to VideoDec CompFrameBufferThread
pthread_mutex_lock(&pVideoDecData->mCompOutFramesLock);
if (!list_empty(&pVideoDecData->mCompUsedOutFrameList))
{
int nFindFlag = 0;
VDecCompOutputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoDecData->mCompUsedOutFrameList, mList)
{
if (pEntry->mpPicture->nID == pFrameInfo->mId)
{
list_move_tail(&pEntry->mList, &pVideoDecData->mCompIdleOutFrameList);
if(pVideoDecData->mbCompFBThreadWaitOutFrame)
{
pVideoDecData->mbCompFBThreadWaitOutFrame = FALSE;
message_t msg;
msg.command = VDecComp_CompFrameBufferThread_OutFrameAvailable;
put_message(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
}
if (pVideoDecData->mbCompFBThreadWaitOutFrameFull)
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoDecData->mCompIdleOutFrameList) { cnt++; }
if (cnt >= VDEC_COMP_FRAME_COUNT)
{
pthread_cond_signal(&pVideoDecData->mCompFBThreadOutFrameFullCondition);
}
}
nFindFlag = 1;
eError = SUCCESS;
break;
}
}
if(0 == nFindFlag)
{
aloge("fatal error! comp frameId[0x%x] is not match CompUsedOutFrameList", pFrameInfo->mId);
eError = ERR_VDEC_ILLEGAL_PARAM;
}
}
else
{
aloge("fatal error! comp frameId[0x%x] is not find in CompUsedOutFrameList", pFrameInfo->mId);
eError = ERR_VDEC_ILLEGAL_PARAM;
}
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
return eError;
}
}
VDANWBuffer *searchVDANWBufferListByVideoPicture(struct list_head *pVdAnbList, VideoPicture *pPicture)
{
int num = 0;
VDANWBuffer *pDes = NULL;
VDANWBuffer *pEntry;
list_for_each_entry(pEntry, pVdAnbList, mList)
{
if (pEntry->mIonUserHandle == (int)(uintptr_t)pPicture->pPrivate &&
pEntry->mpFrameBuf == (void *)pPicture->pData0) {
if (0 == num) {
pDes = pEntry;
num++;
} else {
aloge("fatal error! same ion_user_handle_t[%d][%p]?", pEntry->mIonUserHandle, pEntry->mpFrameBuf);
num++;
}
}
}
return pDes;
}
ERRORTYPE VideoDecDestroyVDANWBufferList(VIDEODECDATATYPE *pVideoDecData, struct list_head *pVdAnbList)
{
if (!list_empty(pVdAnbList)) {
alogd("free ANWBuffers ion_user_handle_t!");
VDANWBuffer *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, pVdAnbList, mList)
{
if (pEntry->mIonUserHandle > 0) {
struct ion_handle_data handleData = {
.handle = pEntry->mIonUserHandle,
};
ioctl(pVideoDecData->mIonFd, ION_IOC_FREE, &handleData);
pEntry->mIonUserHandle = 0;
}
list_del(&pEntry->mList);
free(pEntry);
}
}
return SUCCESS;
}
/*****************************************************************************/
/*******************************************************************************
Function name: VideoDecAddChangedStreamInfos
Description:
Parameters:
Return:
return entry which match the first element of pVideoInfo.
Time: 2015/9/21
*******************************************************************************/
VDStreamInfo *VideoDecAddChangedStreamInfos(VIDEODECDATATYPE *pVideoDecData, struct VideoInfo *pVideoinfo)
{
VDStreamInfo *pDesEntry = NULL;
int i;
VDStreamInfo *pVDStreamInfo;
for (i = 0; i < pVideoinfo->videoNum; i++) {
pVDStreamInfo = malloc(sizeof(VDStreamInfo));
if (NULL == pVDStreamInfo) {
aloge("fatal error! malloc video stream info fail!");
break;
}
memset(pVDStreamInfo, 0, sizeof(VDStreamInfo));
memcpy(&pVDStreamInfo->mStreamInfo, &pVideoinfo->video[i], sizeof(VideoStreamInfo));
if (pVideoinfo->video[i].pCodecSpecificData) {
pVDStreamInfo->mStreamInfo.pCodecSpecificData = (char *)malloc(pVideoinfo->video[i].nCodecSpecificDataLen);
if (pVDStreamInfo->mStreamInfo.pCodecSpecificData == NULL) {
aloge("fatal error! malloc video specific data fail!");
free(pVDStreamInfo);
break;
}
memcpy(pVDStreamInfo->mStreamInfo.pCodecSpecificData, pVideoinfo->video[i].pCodecSpecificData,
pVideoinfo->video[i].nCodecSpecificDataLen);
pVDStreamInfo->mStreamInfo.nCodecSpecificDataLen = pVideoinfo->video[i].nCodecSpecificDataLen;
}
list_add_tail(&pVDStreamInfo->mList, &pVideoDecData->mChangedStreamList);
if (NULL == pDesEntry) {
pDesEntry = pVDStreamInfo;
}
}
return pDesEntry;
}
ERRORTYPE VideoDecDeleteChangedStreamInfo(VIDEODECDATATYPE *pVideoDecData, VideoStreamInfo *pVideoStreamInfo)
{
VDStreamInfo *pDesEntry = NULL;
VDStreamInfo *pEntry;
list_for_each_entry(pEntry, &pVideoDecData->mChangedStreamList, mList)
{
if (&pEntry->mStreamInfo == pVideoStreamInfo) {
pDesEntry = pEntry;
}
}
if (pDesEntry) {
list_del(&pDesEntry->mList);
if (pDesEntry->mStreamInfo.pCodecSpecificData) {
free(pDesEntry->mStreamInfo.pCodecSpecificData);
pDesEntry->mStreamInfo.pCodecSpecificData = NULL;
}
free(pDesEntry);
return SUCCESS;
} else {
aloge("fatal error! not find stream[%p] in changedStreamList", pVideoStreamInfo);
return ERR_VDEC_ILLEGAL_PARAM;
}
}
ERRORTYPE VideoDecDestroyChangedStreamInfos(VIDEODECDATATYPE *pVideoDecData)
{
if (!list_empty(&pVideoDecData->mChangedStreamList)) {
VDStreamInfo *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoDecData->mChangedStreamList, mList)
{
if (pEntry->mStreamInfo.pCodecSpecificData) {
free(pEntry->mStreamInfo.pCodecSpecificData);
pEntry->mStreamInfo.pCodecSpecificData = NULL;
}
list_del(&pEntry->mList);
free(pEntry);
}
}
return SUCCESS;
}
ERRORTYPE VideoDecGetMPPChannelInfo(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT MPP_CHN_S *pChn)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
copy_MPP_CHN_S(pChn, &pVideoDecData->mMppChnInfo);
return eError;
}
ERRORTYPE VideoDecGetPortDefinition(PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_INOUT COMP_PARAM_PORTDEFINITIONTYPE *pPortDef)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
if (pPortDef->nPortIndex == pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].nPortIndex)
memcpy(pPortDef, &pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX], sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
else if (pPortDef->nPortIndex == pVideoDecData->sOutPortDef.nPortIndex)
memcpy(pPortDef, &pVideoDecData->sOutPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
else if (pPortDef->nPortIndex == pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_CLOCK].nPortIndex)
memcpy(pPortDef, &pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_CLOCK], sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
else
eError = ERR_VDEC_ILLEGAL_PARAM;
return eError;
}
ERRORTYPE VideoDecGetCompBufferSupplier(PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_INOUT COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
//find nPortIndex
BOOL bFindFlag = FALSE;
int i;
for (i = 0; i < MAX_VDECODER_PORTS; i++) {
if (pVideoDecData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex) {
bFindFlag = TRUE;
memcpy(pPortBufSupplier, &pVideoDecData->sPortBufSupplier[i], sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE));
break;
}
}
if (bFindFlag) {
eError = SUCCESS;
} else {
eError = ERR_VDEC_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE VideoDecGetBufferState(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT COMP_BUFFERSTATE *pBufferState)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
VideoDecoder *pCedarV = pVideoDecData->pCedarV;
int nStreamBufIndex;
if (pBufferState->video_stream_type == VIDEO_TYPE_MINOR) //CDX_VIDEO_STREAM_MINOR
{
nStreamBufIndex = 1;
} else {
nStreamBufIndex = 0;
}
int nVbsBufferSize = VideoStreamBufferSize(pCedarV, nStreamBufIndex);
int nVbsDataSize = VideoStreamDataSize(pCedarV, nStreamBufIndex);
int nVbsFrameNum = VideoStreamFrameNum(pCedarV, nStreamBufIndex);
pBufferState->nElementCounter = nVbsFrameNum;
pBufferState->nValidSizePercent = nVbsDataSize * 100 / nVbsBufferSize;
return SUCCESS;
}
ERRORTYPE VideoDecGetFbmBufInfo(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT FbmBufInfo *pFbmBufInfo)
{
ERRORTYPE eError;
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
FbmBufInfo *pVdeclibFbmBufInfo = GetVideoFbmBufInfo(pVideoDecData->pCedarV);
if (pFbmBufInfo) {
memcpy(pFbmBufInfo, pVdeclibFbmBufInfo, sizeof(FbmBufInfo));
eError = SUCCESS;
} else {
eError = ERR_VDEC_SYS_NOTREADY;
}
return eError;
}
ERRORTYPE VideoDecGetChnAttr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT VDEC_CHN_ATTR_S *pChnAttr)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
memcpy(pChnAttr, &pVideoDecData->mChnAttr, sizeof(VDEC_CHN_ATTR_S));
return SUCCESS;
}
ERRORTYPE VideoDecGetChnState(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT VDEC_CHN_STAT_S *pChnStat)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
VideoStreamInfo videoInfo;
memset(&videoInfo, 0, sizeof(VideoStreamInfo));
GetVideoStreamInfo(pVideoDecData->pCedarV, &videoInfo);
pChnStat->mType = map_EVIDEOCODECFORMAT_to_PAYLOAD_TYPE_E(videoInfo.eCodecFormat);
pChnStat->mLeftStreamBytes = VideoStreamDataSize(pVideoDecData->pCedarV, 0);
pChnStat->mLeftStreamFrames = VideoStreamFrameNum(pVideoDecData->pCedarV, 0);
pChnStat->mLeftPics = ValidPictureNum(pVideoDecData->pCedarV, 0);
if (COMP_StateExecuting == pVideoDecData->state || COMP_StatePause == pVideoDecData->state) {
pChnStat->mbStartRecvStream = TRUE;
} else {
pChnStat->mbStartRecvStream = FALSE;
}
pthread_mutex_lock(&pVideoDecData->mDecodeFramesControlLock);
if(pVideoDecData->mLimitedDecodeFramesFlag)
{
pChnStat->mLeftDecodeStreamFrames = pVideoDecData->mDecodeFramesParam.mDecodeFrameNum - pVideoDecData->mCurDecodeFramesNum;
}
else
{
pChnStat->mLeftDecodeStreamFrames = 0;
}
pthread_mutex_unlock(&pVideoDecData->mDecodeFramesControlLock);
return SUCCESS;
}
ERRORTYPE VideoDecGetParam(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT VDEC_CHN_PARAM_S *pChnParam)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
memcpy(pChnParam, &pVideoDecData->mChnParam, sizeof(VDEC_CHN_PARAM_S));
return SUCCESS;
}
ERRORTYPE VideoDecGetProtocolParam(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT VDEC_PRTCL_PARAM_S *pProtocolParam)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
memcpy(pProtocolParam, &pVideoDecData->mPrtclParam, sizeof(VDEC_PRTCL_PARAM_S));
return SUCCESS;
}
/**
* get frame, used in non-tunnel mode.
*
* @return SUCCESS.
* @param hComponent vdec component.
* @param pFrameInfo store frame info, caller malloc.
* @param nMilliSec 0:return immediately, <0:wait forever, >0:wait some time.
*/
ERRORTYPE VideoDecGetFrame(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT VIDEO_FRAME_INFO_S *pFrameInfo, PARAM_OUT VIDEO_FRAME_INFO_S *pSubFrameInfo, PARAM_IN int nMilliSec)
{
ERRORTYPE eError;
int ret;
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
if (COMP_StateIdle != pVideoDecData->state && COMP_StateExecuting != pVideoDecData->state && COMP_StatePause != pVideoDecData->state)
{
alogw("call getStream in wrong state[0x%x]", pVideoDecData->state);
return ERR_VDEC_NOT_PERM;
}
if (pVideoDecData->mOutputPortTunnelFlag)
{
aloge("fatal error! can't call getStream() in tunnel mode!");
return ERR_VDEC_NOT_PERM;
}
eError = VideoDecNonTunnel_GetVDecCompOutputFrame(pVideoDecData, pFrameInfo, pSubFrameInfo, nMilliSec);
return eError;
}
ERRORTYPE VideoDecGetRotate(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT ROTATE_E *pRotate)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
*pRotate = map_cedarv_rotation_to_ROTATE_E(pVideoDecData->cedarv_rotation);
return SUCCESS;
}
ERRORTYPE VideoDecSetPortDefinition(PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_PARAM_PORTDEFINITIONTYPE *pPortDef)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
if (pPortDef->nPortIndex == pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].nPortIndex)
memcpy(&pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX], pPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
else if (pPortDef->nPortIndex == pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_CLOCK].nPortIndex)
memcpy(&pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_CLOCK], pPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
else if (pPortDef->nPortIndex == pVideoDecData->sOutPortDef.nPortIndex)
memcpy(&pVideoDecData->sOutPortDef, pPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
else
eError = ERR_VDEC_ILLEGAL_PARAM;
return eError;
}
ERRORTYPE VideoDecSetCompBufferSupplier(PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
//find nPortIndex
BOOL bFindFlag = FALSE;
int i;
for (i = 0; i < MAX_VDECODER_PORTS; i++) {
if (pVideoDecData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex) {
bFindFlag = TRUE;
memcpy(&pVideoDecData->sPortBufSupplier[i], pPortBufSupplier, sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE));
break;
}
}
if (bFindFlag) {
eError = SUCCESS;
} else {
eError = ERR_VDEC_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE VideoDecSetIonFd(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN int nIonFd)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
if (pVideoDecData->mIonFd >= 0) {
aloge("fatal error! ionFd[%d] >= 0?", pVideoDecData->mIonFd);
close(pVideoDecData->mIonFd);
pVideoDecData->mIonFd = -1;
}
pVideoDecData->mIonFd = dup(nIonFd);
return SUCCESS;
}
ERRORTYPE VideoDecSeek(PARAM_IN COMP_HANDLETYPE hComponent)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
int cnt = 0;
if(pVideoDecData->pCedarV)
{
if(pVideoDecData->mbUseCompFrame) // to release node cached in
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
if (!list_empty(&pVideoDecData->mUsedOutFrameList))
{
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
VDecCompOutputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoDecData->mUsedOutFrameList, mList)
{
VideoDecReturnVDecCompOutputFrameToIdleList(pVideoDecData, pEntry->mpPicture->nID);
cnt++;
}
}
else
{
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
}
alogd("vdec_out_used_frm_list_node_cnt:%d_when_seek",cnt);
}
ResetVideoDecoder(pVideoDecData->pCedarV);
}
else
{
alogw("the vdecor do not create, it means had seek!!!");
}
pVideoDecData->mbEof = FALSE;
return SUCCESS;
}
ERRORTYPE VideoDecSetStreamEof(PARAM_IN COMP_HANDLETYPE hComponent)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
alogv("vdec end flag is set");
pVideoDecData->priv_flag |= CDX_comp_PRIV_FLAGS_STREAMEOF;
message_t msg;
msg.command = VDecComp_VbsAvailable;
put_message(&pVideoDecData->cmd_queue, &msg);
return SUCCESS;
}
ERRORTYPE VideoDecClearStreamEof(PARAM_IN COMP_HANDLETYPE hComponent)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
alogv("vdec end flag is clear");
pVideoDecData->priv_flag &= ~(CDX_comp_PRIV_FLAGS_STREAMEOF);
return SUCCESS;
}
ERRORTYPE VideoDecSetRotate(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN ROTATE_E eRotate)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
pVideoDecData->cedarv_rotation = map_ROTATE_E_to_cedarv_rotation(eRotate);
return eError;
}
ERRORTYPE VideoDecSetOutputPixelFormat(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN enum EPIXELFORMAT eVdecPixelFormat)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
pVideoDecData->cedarv_output_setting = eVdecPixelFormat;
return eError;
}
ERRORTYPE VideoDecSetDisplayFrameRequestMode(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN int nFrameRequest)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
pVideoDecData->nDisplayFrameRequestMode = nFrameRequest;
return SUCCESS;
}
ERRORTYPE VideoDecSetMPPChannelInfo(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN MPP_CHN_S *pChn)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
copy_MPP_CHN_S(&pVideoDecData->mMppChnInfo, pChn);
return SUCCESS;
}
ERRORTYPE VideoDecSetChnAttr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN VDEC_CHN_ATTR_S *pChnAttr)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
memcpy(&pVideoDecData->mChnAttr, pChnAttr, sizeof(VDEC_CHN_ATTR_S));
pVideoDecData->cedarv_max_width = pVideoDecData->mChnAttr.mPicWidth;
pVideoDecData->cedarv_max_height = pVideoDecData->mChnAttr.mPicHeight;
pVideoDecData->cedarv_output_setting = map_PIXEL_FORMAT_E_to_EPIXELFORMAT(pVideoDecData->mChnAttr.mOutputPixelFormat);
pVideoDecData->cedarv_rotation = map_ROTATE_E_to_cedarv_rotation(pVideoDecData->mChnAttr.mInitRotation);
pVideoDecData->config_vbv_size = pVideoDecData->mChnAttr.mBufSize;
pVideoDecData->mVdecExtraFrameNum = pVideoDecData->mChnAttr.mExtraFrameNum;
pVideoDecData->cedarv_second_output_en = pVideoDecData->mChnAttr.mSubPicEnable;
if(pVideoDecData->cedarv_second_output_en)
{
pVideoDecData->cedarv_second_output_setting = map_PIXEL_FORMAT_E_to_EPIXELFORMAT(pVideoDecData->mChnAttr.mSubOutputPixelFormat);
pVideoDecData->cedarv_second_horizon_scale_down_ratio = pVideoDecData->mChnAttr.mSubPicWidthRatio;
pVideoDecData->cedarv_second_vertical_scale_down_ratio = pVideoDecData->mChnAttr.mSubPicHeightRatio;
if(pVideoDecData->cedarv_second_horizon_scale_down_ratio >= 5
|| pVideoDecData->cedarv_second_horizon_scale_down_ratio < 0
|| pVideoDecData->cedarv_second_vertical_scale_down_ratio >= 5
|| pVideoDecData->cedarv_second_vertical_scale_down_ratio < 0)
{
aloge("fatal error! sub ratio wrong! [%d],[%d]", pVideoDecData->cedarv_second_horizon_scale_down_ratio, pVideoDecData->cedarv_second_vertical_scale_down_ratio);
pVideoDecData->cedarv_second_output_en = 0;
}
}
return eError;
}
ERRORTYPE VideoDecResetChannel(PARAM_IN COMP_HANDLETYPE hComponent)
{
//ERRORTYPE eError;
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
if (pVideoDecData->state != COMP_StateIdle) {
aloge("fatal error! must reset channel in stateIdle!");
return ERR_VDEC_NOT_PERM;
}
int cnt;
struct list_head *pList;
alogd("wait VDec idleOutFrameList full");
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
pVideoDecData->mWaitOutFrameFullFlag = TRUE;
//wait all outFrame return.
while (1) {
cnt = 0;
list_for_each(pList, &pVideoDecData->mIdleOutFrameList) { cnt++; }
if (cnt < pVideoDecData->mFrameNodeNum) {
alogd("wait idleOutFrameList [%d]nodes to home", pVideoDecData->mFrameNodeNum - cnt);
pthread_cond_wait(&pVideoDecData->mOutFrameFullCondition, &pVideoDecData->mOutFrameListMutex);
} else {
break;
}
}
pVideoDecData->mWaitOutFrameFullFlag = FALSE;
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
//free ion_user_handle_t
VideoDecDestroyVDANWBufferList(pVideoDecData, &pVideoDecData->mPreviousANWBuffersList);
VideoDecDestroyVDANWBufferList(pVideoDecData, &pVideoDecData->mANWBuffersList);
pthread_mutex_lock(&pVideoDecData->mDecodeFramesControlLock);
pVideoDecData->mLimitedDecodeFramesFlag = FALSE;
pVideoDecData->mDecodeFramesParam.mDecodeFrameNum = 0;
pVideoDecData->mCurDecodeFramesNum = 0;
pthread_mutex_unlock(&pVideoDecData->mDecodeFramesControlLock);
alogd("wait VDec idleOutFrameList full done");
return SUCCESS;
}
ERRORTYPE VideoDecSetChnParam(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN VDEC_CHN_PARAM_S *pChnParam)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
memcpy(&pVideoDecData->mChnParam, pChnParam, sizeof(VDEC_CHN_PARAM_S));
if (pVideoDecData->mChnParam.mDecMode != 0) {
pVideoDecData->drop_B_frame = 1;
} else {
pVideoDecData->drop_B_frame = 0;
}
return eError;
}
ERRORTYPE VideoDecSetProtocolParam(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN VDEC_PRTCL_PARAM_S *pPrtclParam)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
memcpy(&pVideoDecData->mPrtclParam, pPrtclParam, sizeof(VDEC_PRTCL_PARAM_S));
return eError;
}
/**
* release frame, used in non-tunnel mode.
*
* @return SUCCESS.
* @param hComponent vdec component.
* @param pFrameInfo frame info, caller malloc.
*/
ERRORTYPE VideoDecReleaseFrame(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN VIDEO_FRAME_INFO_S *pFrameInfo, PARAM_IN VIDEO_FRAME_INFO_S *pSubFrameInfo)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
if (COMP_StateIdle != pVideoDecData->state && COMP_StateExecuting != pVideoDecData->state && COMP_StatePause != pVideoDecData->state)
{
alogw("call getStream in wrong state[0x%x]", pVideoDecData->state);
return ERR_VDEC_NOT_PERM;
}
if (pVideoDecData->mOutputPortTunnelFlag)
{
aloge("fatal error! can't call releaseFrame() in tunnel mode!");
return ERR_VDEC_NOT_PERM;
}
eError = VideoDecNonTunnel_ReleaseVDecCompOutputFrame(pVideoDecData, pFrameInfo, pSubFrameInfo);
return eError;
}
ERRORTYPE VideoDecSetFrameBuffersToVdecLib(PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN VDecCompFrameBuffersParam *pParam)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
CdxANWBuffersInfo *pAnwBuffersInfo = pParam->mpANWBuffersInfo;
struct list_head *pOutFrameList = &pParam->mFramesOwnedByANW; //VDecCompOutputFrame
INIT_LIST_HEAD(pOutFrameList);
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
//set gpu buffers to vdeclib.
int i;
VideoPicture tmpVP;
VideoPicture *pVdecPic;
memset(&tmpVP, 0, sizeof(VideoPicture));
for (i = 0; i < pAnwBuffersInfo->mnBufNum; i++) {
// set the buffer address, bufId, ion_user_handle_t, pixelFormat, sizeParam.
tmpVP.pData0 = (char *)pAnwBuffersInfo->mANWBuffers[i].dst;
tmpVP.pData1 = tmpVP.pData0 + (pAnwBuffersInfo->mANWBuffers[i].height * pAnwBuffersInfo->mANWBuffers[i].stride);
tmpVP.pData2 =
tmpVP.pData1 + (pAnwBuffersInfo->mANWBuffers[i].height * pAnwBuffersInfo->mANWBuffers[i].stride) / 4;
tmpVP.phyYBufAddr = (size_addr)pAnwBuffersInfo->mANWBuffers[i].dstPhy;
tmpVP.phyCBufAddr = (size_addr)tmpVP.phyYBufAddr +
(pAnwBuffersInfo->mANWBuffers[i].height * pAnwBuffersInfo->mANWBuffers[i].stride);
tmpVP.nBufId = i;
tmpVP.pPrivate = (void *)(uintptr_t)pAnwBuffersInfo->mANWBuffers[i].mIonUserHandle;
tmpVP.ePixelFormat = convertPixelFormatCdx2Vdec(pAnwBuffersInfo->mANWBuffers[i].format);
tmpVP.nWidth = pAnwBuffersInfo->mANWBuffers[i].stride;
tmpVP.nHeight = pAnwBuffersInfo->mANWBuffers[i].height;
tmpVP.nLineStride = pAnwBuffersInfo->mANWBuffers[i].stride;
if (pAnwBuffersInfo->mANWBuffers[i].mbOccupyFlag) {
if (FALSE == pVideoDecData->mbConfigVdecFrameBuffers) {
SetVideoFbmBufAddress(pVideoDecData->pCedarV, &tmpVP, 0);
} else {
ReturnRelasePicture(pVideoDecData->pCedarV, &tmpVP, 0);
}
} else {
if (FALSE == pVideoDecData->mbConfigVdecFrameBuffers) {
pVdecPic = SetVideoFbmBufAddress(pVideoDecData->pCedarV, &tmpVP, 1);
} else {
pVdecPic = ReturnRelasePicture(pVideoDecData->pCedarV, &tmpVP, 1);
}
if (list_empty(&pVideoDecData->mIdleOutFrameList)) {
aloge("fatal error! idle out frame list can't be empty in state[%d]", pVideoDecData->state);
continue;
}
VDecCompOutputFrame *pOutFrame =
list_first_entry(&pVideoDecData->mIdleOutFrameList, VDecCompOutputFrame, mList);
pOutFrame->mpPicture = pVdecPic;
list_move_tail(&pOutFrame->mList, pOutFrameList);
}
}
pVideoDecData->mbConfigVdecFrameBuffers = TRUE;
//store ANWBuffers in VDANWBuffer list.
if (!list_empty(&pVideoDecData->mANWBuffersList)) {
aloge("fatal error! why ANWBuffers is not empty?");
abort();
}
if (!list_empty(&pVideoDecData->mPreviousANWBuffersList)) {
alogw("Low probability! previousANWBuffersList is not empty");
}
for (i = 0; i < pAnwBuffersInfo->mnBufNum; i++) {
VDANWBuffer *pANWBuf = (VDANWBuffer *)malloc(sizeof(VDANWBuffer));
if (NULL == pANWBuf) {
aloge("fatal error! malloc fail!");
break;
}
memset(pANWBuf, 0, sizeof(VDANWBuffer));
pANWBuf->mpFrameBuf = (void *)pAnwBuffersInfo->mANWBuffers[i].dst;
pANWBuf->mIonUserHandle = pAnwBuffersInfo->mANWBuffers[i].mIonUserHandle;
list_add_tail(&pANWBuf->mList, &pVideoDecData->mANWBuffersList);
}
//print ANativeWindow buffers info
alogd("set gpu buffers num[%d], state[%d]", pAnwBuffersInfo->mnBufNum, pVideoDecData->state);
for (i = 0; i < pAnwBuffersInfo->mnBufNum; i++) {
alogd("buffer[%d]: [%dx%d][%d][0x%x][0x%x][%p][%p][%p],[%d]", i, pAnwBuffersInfo->mANWBuffers[i].width,
pAnwBuffersInfo->mANWBuffers[i].height, pAnwBuffersInfo->mANWBuffers[i].stride,
pAnwBuffersInfo->mANWBuffers[i].format, pAnwBuffersInfo->mANWBuffers[i].usage,
pAnwBuffersInfo->mANWBuffers[i].dst, pAnwBuffersInfo->mANWBuffers[i].dstPhy,
pAnwBuffersInfo->mANWBuffers[i].pObjANativeWindowBuffer, pAnwBuffersInfo->mANWBuffers[i].mbOccupyFlag);
}
//notify vdec thread if necessary
if (pVideoDecData->mWaitOutFrameFlag) {
pVideoDecData->mWaitOutFrameFlag = FALSE;
message_t msg;
msg.command = VDecComp_OutFrameAvailable;
put_message(&pVideoDecData->cmd_queue, &msg);
}
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
return SUCCESS;
}
ERRORTYPE VideoDecReopenVideoEngine(PARAM_IN COMP_HANDLETYPE hComponent)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError;
int ret;
VideoStreamInfo streamInfo;
VideoStreamInfo *pVideoInfo = (VideoStreamInfo *)VideoStreamDataInfoPointer(pVideoDecData->pCedarV, 0);
if (pVideoInfo != NULL) {
memcpy(&streamInfo, pVideoInfo, sizeof(VideoStreamInfo));
} else {
//*if resolustionChange was detected by decoder, we should not send the
//* specific data to decoder. or decoder will appear error.
memset(&streamInfo, 0, sizeof(VideoStreamInfo));
if (pVideoDecData->mInputPortTunnelFlag)
{
VideoStreamInfo *pVideoStreamInfo =
(VideoStreamInfo *)pVideoDecData->sInPortExtraDef[VDEC_PORT_SUFFIX_DEMUX].pVendorInfo;
memcpy(&streamInfo, pVideoStreamInfo, sizeof(VideoStreamInfo));
}
else
{
streamInfo.eCodecFormat = map_PAYLOAD_TYPE_E_to_EVIDEOCODECFORMAT(pVideoDecData->mChnAttr.mType);
}
//streamInfo.pCodecSpecificData = NULL;
//streamInfo.nCodecSpecificDataLen = 0;
}
ret = ReopenVideoEngine(pVideoDecData->pCedarV, &pVideoDecData->mVConfig, &streamInfo);
pVideoDecData->mbConfigVdecFrameBuffers = FALSE;
if (pVideoInfo) {
VideoDecDeleteChangedStreamInfo(pVideoDecData, pVideoInfo);
}
VideoDecDestroyVDANWBufferList(pVideoDecData, &pVideoDecData->mANWBuffersList);
message_t msg;
msg.command = VDecComp_ReopenVideoEngine;
put_message(&pVideoDecData->cmd_queue, &msg);
if (0 == ret) {
eError = SUCCESS;
} else {
eError = ERR_VDEC_SYS_NOTREADY;
}
return eError;
}
static ERRORTYPE VideoDecSetVEFreq(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN int nFreq)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
pVideoDecData->mVEFreq = nFreq;
if(nFreq > 0)
{
if(pVideoDecData->pCedarV)
{
alogd("vdec set VE freq to [%d]MHz", nFreq);
VideoDecoderSetFreq(pVideoDecData->pCedarV, nFreq);
}
}
return SUCCESS;
}
static ERRORTYPE VideoDecSetDecodeFrame(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN VDEC_DECODE_FRAME_PARAM_S *pDecodeParam)
{
ERRORTYPE eError = SUCCESS;
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
pthread_mutex_lock(&pVideoDecData->mDecodeFramesControlLock);
if(pDecodeParam && pDecodeParam->mDecodeFrameNum > 0)
{
pVideoDecData->mLimitedDecodeFramesFlag = TRUE;
pVideoDecData->mDecodeFramesParam = *pDecodeParam;
}
else
{
pVideoDecData->mLimitedDecodeFramesFlag = FALSE;
pVideoDecData->mDecodeFramesParam.mDecodeFrameNum = 0;
}
pVideoDecData->mCurDecodeFramesNum = 0;
pthread_mutex_unlock(&pVideoDecData->mDecodeFramesControlLock);
return eError;
}
static ERRORTYPE VideoDecSetVideoStreamInfo(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN VideoStreamInfo *pVideoStreamInfo)
{
ERRORTYPE eError = SUCCESS;
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
if (NULL == pVideoStreamInfo)
{
aloge("fatal error! Set VideoStreamInfo is NULL!");
return ERR_VDEC_NULL_PTR;
}
memcpy(&pVideoDecData->stVideoStreamInfo, pVideoStreamInfo, sizeof(VideoStreamInfo));
if (pVideoStreamInfo->nCodecSpecificDataLen > 0 && pVideoStreamInfo->pCodecSpecificData)
{
char* tmpBuf = (char*)malloc(pVideoStreamInfo->nCodecSpecificDataLen);
if (NULL == tmpBuf)
{
aloge("fatal error! malloc fail!");
return ERR_VDEC_NOMEM;
}
memcpy(tmpBuf, pVideoStreamInfo->pCodecSpecificData, pVideoStreamInfo->nCodecSpecificDataLen);
pVideoDecData->stVideoStreamInfo.pCodecSpecificData = tmpBuf;
}
return SUCCESS;
}
static ERRORTYPE VideoDecForceFramePackage(PARAM_IN COMP_HANDLETYPE hComponent, BOOL bFlag)
{
ERRORTYPE eError = SUCCESS;
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
pVideoDecData->mbForceFramePackage = bFlag;
return SUCCESS;
}
ERRORTYPE VideoDecSendCommand(COMP_HANDLETYPE hComponent, COMP_COMMANDTYPE Cmd, unsigned int nParam1, void *pCmdData)
{
VIDEODECDATATYPE *pVideoDecData;
CompInternalMsgType eCmd;
ERRORTYPE eError;
message_t msg;
eError = SUCCESS;
pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
if (pVideoDecData->state == COMP_StateInvalid) {
eError = ERR_VDEC_INVALIDSTATE;
goto OMX_CONF_CMD_BAIL;
}
switch (Cmd) {
case COMP_CommandStateSet:
eCmd = SetState;
break;
case COMP_CommandFlush:
eCmd = Flush;
break;
case COMP_CommandPortDisable:
eCmd = StopPort;
break;
case COMP_CommandPortEnable:
eCmd = RestartPort;
break;
case COMP_CommandVendorChangeANativeWindow: {
eCmd = VDecComp_ChangeGraphicBufferProducer;
break;
}
default:
eCmd = -1;
break;
}
msg.command = eCmd;
msg.para0 = nParam1;
put_message(&pVideoDecData->cmd_queue, &msg);
OMX_CONF_CMD_BAIL:
return eError;
}
/*****************************************************************************/
ERRORTYPE VideoDecGetState(COMP_HANDLETYPE hComponent, COMP_STATETYPE *pState)
{
VIDEODECDATATYPE *pVideoDecData;
ERRORTYPE eError;
eError = SUCCESS;
pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
*pState = pVideoDecData->state;
return eError;
}
/*****************************************************************************/
ERRORTYPE VideoDecSetCallbacks(COMP_HANDLETYPE hComponent, COMP_CALLBACKTYPE *pCallbacks, void *pAppData)
{
VIDEODECDATATYPE *pVideoDecData;
ERRORTYPE eError;
eError = SUCCESS;
pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
pVideoDecData->pCallbacks = pCallbacks;
pVideoDecData->pAppData = pAppData;
OMX_CONF_CMD_BAIL:
return eError;
}
ERRORTYPE VideoDecGetConfig(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_INDEXTYPE nIndex,
PARAM_INOUT void *pComponentConfigStructure)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
switch (nIndex) {
case COMP_IndexVendorMPPChannelInfo: {
eError = VideoDecGetMPPChannelInfo(hComponent, (MPP_CHN_S *)pComponentConfigStructure);
break;
}
case COMP_IndexParamPortDefinition: {
eError = VideoDecGetPortDefinition(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE *)pComponentConfigStructure);
break;
}
case COMP_IndexParamCompBufferSupplier: {
eError =
VideoDecGetCompBufferSupplier(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorBufferState: {
eError = VideoDecGetBufferState(hComponent, (COMP_BUFFERSTATE *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorFbmBufInfo: {
eError = VideoDecGetFbmBufInfo(hComponent, (FbmBufInfo *)pComponentConfigStructure);
break;
}
// case COMP_IndexVendorConfigInputBuffer: {
// COMP_BUFFERHEADERTYPE *pBuffer = (COMP_BUFFERHEADERTYPE *)pComponentConfigStructure;
// eError = VideoDecRequstBuffer(hComponent, pBuffer->nInputPortIndex, pBuffer);
// break;
// }
case COMP_IndexVendorVdecChnAttr: {
eError = VideoDecGetChnAttr(hComponent, (VDEC_CHN_ATTR_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecChnState: {
eError = VideoDecGetChnState(hComponent, (VDEC_CHN_STAT_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecParam: {
eError = VideoDecGetParam(hComponent, (VDEC_CHN_PARAM_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecProtocolParam: {
eError = VideoDecGetProtocolParam(hComponent, (VDEC_PRTCL_PARAM_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecGetFrame: {
VdecOutFrame *pFrame = (VdecOutFrame *)pComponentConfigStructure;
eError = VideoDecGetFrame(hComponent, pFrame->pFrameInfo, pFrame->pSubFrameInfo, pFrame->nMilliSec);
break;
}
case COMP_IndexVendorVdecRotate: {
eError = VideoDecGetRotate(hComponent, (ROTATE_E *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecLuma: {
aloge("unsupported temporary");
eError = FAILURE;
break;
}
default: {
aloge("fatal error! unknown nIndex[0x%x] in state[%d]", nIndex, pVideoDecData->state);
eError = ERR_VDEC_NOT_SURPPORT;
break;
}
}
return eError;
}
ERRORTYPE VideoDecSetConfig(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_INDEXTYPE nIndex,
PARAM_IN void *pComponentConfigStructure)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
switch (nIndex) {
case COMP_IndexParamPortDefinition:
eError = VideoDecSetPortDefinition(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE *)pComponentConfigStructure);
break;
case COMP_IndexParamCompBufferSupplier: {
eError =
VideoDecSetCompBufferSupplier(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorIonFd:
eError = VideoDecSetIonFd(hComponent, *(int *)pComponentConfigStructure);
break;
case COMP_IndexVendorSeekToPosition:
eError = VideoDecSeek(hComponent);
break;
case COMP_IndexVendorSetStreamEof: {
eError = VideoDecSetStreamEof(hComponent);
break;
}
case COMP_IndexVendorClearStreamEof:
eError = VideoDecClearStreamEof(hComponent);
break;
case COMP_IndexVendorVdecRotate:
eError = VideoDecSetRotate(hComponent, *(ROTATE_E *)pComponentConfigStructure);
break;
case COMP_IndexVendorCedarvOutputSetting:
eError = VideoDecSetOutputPixelFormat(hComponent, *(enum EPIXELFORMAT *)pComponentConfigStructure);
break;
case COMP_IndexVendorDisplayFrameRequestMode:
eError = VideoDecSetDisplayFrameRequestMode(hComponent, *(int *)pComponentConfigStructure);
break;
case COMP_IndexVendorMPPChannelInfo: {
eError = VideoDecSetMPPChannelInfo(hComponent, (MPP_CHN_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecChnAttr: {
eError = VideoDecSetChnAttr(hComponent, (VDEC_CHN_ATTR_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecResetChannel: {
eError = VideoDecResetChannel(hComponent);
break;
}
case COMP_IndexVendorVdecParam: {
eError = VideoDecSetChnParam(hComponent, (VDEC_CHN_PARAM_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecProtocolParam: {
eError = VideoDecSetProtocolParam(hComponent, (VDEC_PRTCL_PARAM_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecReleaseFrame: {
VdecOutFrame *pFrame = (VdecOutFrame *)pComponentConfigStructure;
eError = VideoDecReleaseFrame(hComponent, pFrame->pFrameInfo, pFrame->pSubFrameInfo);
break;
}
// case COMP_IndexVendorConfigInputBuffer: {
// COMP_BUFFERHEADERTYPE *pBuffer = (COMP_BUFFERHEADERTYPE *)pComponentConfigStructure;
// eError = VideoDecReleaseBuffer(hComponent, pBuffer->nInputPortIndex, pBuffer);
// break;
// }
case COMP_IndexVendorFrameBuffers: {
eError =
VideoDecSetFrameBuffersToVdecLib(hComponent, (VDecCompFrameBuffersParam *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorReopenVideoEngine: {
eError = VideoDecReopenVideoEngine(hComponent);
break;
}
case COMP_IndexVendorVEFreq:
{
eError = VideoDecSetVEFreq(hComponent, *(int*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecDecodeFrameParam:
{
eError = VideoDecSetDecodeFrame(hComponent, (VDEC_DECODE_FRAME_PARAM_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorExtraData:
{
eError = VideoDecSetVideoStreamInfo(hComponent, (VideoStreamInfo *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVdecForceFramePackage:
{
eError = VideoDecForceFramePackage(hComponent, *(BOOL*)pComponentConfigStructure);
break;
}
default: {
aloge("fatal error! unknown nIndex[0x%x] in state[%d]", nIndex, pVideoDecData->state);
eError = ERR_VDEC_ILLEGAL_PARAM;
break;
}
}
return eError;
}
ERRORTYPE VideoDecComponentTunnelRequest(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;
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
if (pVideoDecData->state == COMP_StateExecuting) {
alogw("Be careful! tunnel request may be some danger in StateExecuting");
} else if (pVideoDecData->state != COMP_StateIdle) {
aloge("fatal error! tunnel request can't be in state[0x%x]", pVideoDecData->state);
eError = ERR_VDEC_INCORRECT_STATE_OPERATION;
goto COMP_CMD_FAIL;
}
COMP_PARAM_PORTDEFINITIONTYPE *pPortDef;
COMP_PARAM_PORTEXTRADEFINITIONTYPE *pPortExtraDef = NULL;
COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo;
COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier;
BOOL bFindFlag;
int i;
bFindFlag = FALSE;
for (i = 0; i < MAX_VDECODER_IN_PORTS; i++) {
if (pVideoDecData->sInPortDef[i].nPortIndex == nPort) {
pPortDef = &pVideoDecData->sInPortDef[i];
pPortExtraDef = &pVideoDecData->sInPortExtraDef[i];
bFindFlag = TRUE;
break;
}
}
if (FALSE == bFindFlag) {
if (pVideoDecData->sOutPortDef.nPortIndex == nPort) {
pPortDef = &pVideoDecData->sOutPortDef;
bFindFlag = TRUE;
}
}
if (FALSE == bFindFlag) {
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_VDEC_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
bFindFlag = FALSE;
for (i = 0; i < MAX_VDECODER_IN_PORTS; i++) {
if (pVideoDecData->sInPortTunnelInfo[i].nPortIndex == nPort) {
pPortTunnelInfo = &pVideoDecData->sInPortTunnelInfo[i];
bFindFlag = TRUE;
break;
}
}
if (FALSE == bFindFlag) {
if (pVideoDecData->sOutPortTunnelInfo.nPortIndex == nPort) {
pPortTunnelInfo = &pVideoDecData->sOutPortTunnelInfo;
bFindFlag = TRUE;
}
}
if (FALSE == bFindFlag) {
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_VDEC_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
bFindFlag = FALSE;
for (i = 0; i < MAX_VDECODER_PORTS; i++) {
if (pVideoDecData->sPortBufSupplier[i].nPortIndex == nPort) {
pPortBufSupplier = &pVideoDecData->sPortBufSupplier[i];
bFindFlag = TRUE;
break;
}
}
if (FALSE == bFindFlag) {
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_VDEC_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);
if (pPortDef->eDir == COMP_DirOutput)
{
pVideoDecData->mOutputPortTunnelFlag = FALSE;
}
else
{
pVideoDecData->mInputPortTunnelFlag = FALSE;
}
eError = SUCCESS;
goto COMP_CMD_FAIL;
}
if (pPortDef->eDir == COMP_DirOutput) {
if (pVideoDecData->mOutputPortTunnelFlag) {
aloge("VDec_Comp outport already bind, why bind again?!");
eError = FAILURE;
goto COMP_CMD_FAIL;
}
pTunnelSetup->nTunnelFlags = 0;
pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier;
pVideoDecData->mOutputPortTunnelFlag = TRUE;
} else {
if (pVideoDecData->mInputPortTunnelFlag) {
aloge("VDec_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_VDEC_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! input portIndex[%d] buffer supplier[%d] is not same as output portIndex[%d] buffer supplier[%d], respect output port decision!",
nPort, pPortBufSupplier->eBufferSupplier, nTunneledPort, pTunnelSetup->eSupplier);
pPortBufSupplier->eBufferSupplier = pTunnelSetup->eSupplier;
}
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);
pVideoDecData->mInputPortTunnelFlag = TRUE;
}
COMP_CMD_FAIL:
return eError;
}
#if 0
ERRORTYPE VideoDecRequstBuffer(COMP_HANDLETYPE hComponent, unsigned int nPortIndex, COMP_BUFFERHEADERTYPE *pBuffer)
{
alogw("Be careful! old method, should not use now.");
ERRORTYPE eError = SUCCESS;
// Get component private data
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
EncodedStream *pDmxOutBuf = (EncodedStream *)pBuffer->pOutputPortPrivate;
// Check Video Decoder
if (NULL == pVideoDecData->pCedarV)
{
alogw("vdecLib is not create, can't request buffer.");
return ERR_VDEC_SYS_NOTREADY;
}
//alogd("requestBuf len[%d]", pDmxOutBuf->nTobeFillLen);
if (nPortIndex == pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].nPortIndex)
{// inport tunnel mode
int nStreamBufIndex = (VIDEO_TYPE_MINOR == pDmxOutBuf->video_stream_type) ? 1 : 0;
int ret = RequestVideoStreamBuffer(pVideoDecData->pCedarV, pDmxOutBuf->nTobeFillLen, (char **)&pDmxOutBuf->pBuffer,
(int *)&pDmxOutBuf->nBufferLen, (char **)&pDmxOutBuf->pBufferExtra,
(int *)&pDmxOutBuf->nBufferExtraLen, nStreamBufIndex);
//alogd("requestBuf ret[0x%x], len[%d+%d]", ret, pDmxOutBuf->nBufferLen, pDmxOutBuf->nBufferExtraLen);
if (ret < 0)
{
eError = ERR_VDEC_BUF_FULL;
}
}
else
{// inport non-tunnel mode
aloge("fatal error! wrong portIndex[%d]", nPortIndex);
eError = ERR_VDEC_ILLEGAL_PARAM;
}
return eError;
}
/**
* update vbs data to VdecLib, used in tunnel mode.
*
* @return SUCCESS.
* @param hComponent vdec component.
* @param nPortIndex indicate vbs inputPort index.
* @param pBuffer contain vbs data struct.
*/
ERRORTYPE VideoDecReleaseBuffer(COMP_HANDLETYPE hComponent, unsigned int nPortIndex, COMP_BUFFERHEADERTYPE *pBuffer)
{
alogw("Be careful! old method, should not use now.");
VIDEODECDATATYPE *pVideoDecData;
ERRORTYPE eError = SUCCESS;
int ret;
pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
EncodedStream *pDmxOutBuf = (EncodedStream *)pBuffer->pOutputPortPrivate;
//alogd("releaseBuf len[%d]", pDmxOutBuf->nFilledLen);
if (nPortIndex == pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].nPortIndex)
{// inport tunnel mode
pthread_mutex_lock(&pVideoDecData->mVbsInputMutex);
VideoStreamDataInfo dataInfo;
memset(&dataInfo, 0, sizeof(VideoStreamDataInfo));
//if demux detect stream info change.
if (pDmxOutBuf->infoVersion != pVideoDecData->mVideoInfoVersion)
{
if (pDmxOutBuf->pChangedStreamsInfo)
{
struct VideoInfo *pVideoinfo = (struct VideoInfo *)pDmxOutBuf->pChangedStreamsInfo;
if (pVideoinfo->videoNum != 1)
{
aloge("fatal error! the videoNum is not 1");
abort();
}
VDStreamInfo *pVDStreamInfo = VideoDecAddChangedStreamInfos(pVideoDecData, pVideoinfo);
dataInfo.pVideoInfo = (void *)&pVDStreamInfo->mStreamInfo;
dataInfo.bVideoInfoFlag = 1;
}
pVideoDecData->mVideoInfoVersion = pDmxOutBuf->infoVersion;
}
dataInfo.pData = (char *)pDmxOutBuf->pBuffer;
dataInfo.nLength = pDmxOutBuf->nFilledLen;
if (pDmxOutBuf->nFlags & CEDARV_FLAG_PTS_VALID)
{
dataInfo.nPts = pDmxOutBuf->nTimeStamp;
}
else
{
dataInfo.nPts = -1;
}
dataInfo.nPcr = -1;
if (pDmxOutBuf->nFlags & CEDARV_FLAG_FIRST_PART)
{
dataInfo.bIsFirstPart = 1;
}
if (pDmxOutBuf->nFlags & CEDARV_FLAG_LAST_PART)
{
dataInfo.bIsLastPart = 1;
alogv("last part found!");
}
if (pDmxOutBuf->video_stream_type == VIDEO_TYPE_MINOR) //CDX_VIDEO_STREAM_MINOR
{
dataInfo.nStreamIndex = 1;
}
else
{
dataInfo.nStreamIndex = 0;
}
// Send Vbs data to Decoder Lib
SubmitVideoStreamData(pVideoDecData->pCedarV, &dataInfo, dataInfo.nStreamIndex);
if (pVideoDecData->mWaitVbsInputFlag)
{
pVideoDecData->mWaitVbsInputFlag = FALSE;
message_t msg;
msg.command = VDecComp_VbsAvailable;
put_message(&pVideoDecData->cmd_queue, &msg);
}
pthread_mutex_unlock(&pVideoDecData->mVbsInputMutex);
}
else
{// inport non-tunnel mode
aloge("fatal error! wrong portIndex[%d]", nPortIndex);
eError = ERR_VDEC_ILLEGAL_PARAM;
}
return eError;
}
#endif
ERRORTYPE VideoDecTunnel_EmptyThisBuffer_BufferSupplyInput(COMP_HANDLETYPE hComponent, COMP_BUFFERHEADERTYPE *pBuffer)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
VIDEODEC_INPUT_DATA* pInputData = pVideoDecData->pInputData;
// Get buffer pointer from demux component
EncodedStream* pDmxOutBuf = (EncodedStream*)pBuffer->pOutputPortPrivate;
ERRORTYPE eError = SUCCESS;
DMXPKT_NODE_T* pEntry = NULL;
// Check it is the same buffer in mUsingAbsList
pthread_mutex_lock(&pInputData->mVbsListLock);
if (list_empty(&pInputData->mUsingVbsList))
{
pthread_mutex_unlock(&pInputData->mVbsListLock);
aloge("fatal error! Calling EmptyThisBuffer while mUsingVbsList is empty!");
return FAILURE;
}
pEntry = list_first_entry(&pInputData->mUsingVbsList, DMXPKT_NODE_T, mList);
if ( (pEntry->stEncodedStream.pBuffer != pDmxOutBuf->pBuffer)
|| (pEntry->stEncodedStream.pBufferExtra != pDmxOutBuf->pBufferExtra)
)
{
pthread_mutex_unlock(&pInputData->mVbsListLock);
aloge("fatal error! the buffer in EmptyThisBuffer param is not same as in mUsingVbsList");
return FAILURE;
}
if (-1 == pDmxOutBuf->nFilledLen)
{// buffer is not enough for component A
alogv("vdec 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->mUsingVbsList))
{// moving from mReadyAbsList to mIdleAbsList
pEntry = list_first_entry(&pInputData->mUsingVbsList, DMXPKT_NODE_T, mList);
memset(&pEntry->stEncodedStream, 0, sizeof(EncodedStream));
list_move_tail(&pEntry->mList, &pInputData->mIdleVbsList);
}
// Send Abs Valid message to input thread
if (pInputData->mWaitVbsValidFlag)
{
pInputData->mWaitVbsValidFlag = FALSE;
message_t msg;
msg.command = VDecComp_VbsAvailable;
put_message(&pInputData->cmd_queue, &msg);
}
// signal when all vbs return to idleList
if(pInputData->mbWaitVbsFullFlag)
{
struct list_head *pList;
int cnt = 0;
list_for_each(pList, &pInputData->mIdleVbsList) { cnt++; }
if (cnt >= pInputData->mNodeNum)
{
pInputData->mbWaitVbsFullFlag = FALSE;
pthread_cond_signal(&pInputData->mVbsFullCond);
}
}
pthread_mutex_unlock(&pInputData->mVbsListLock);
return eError;
}
// Prepare datainfo for decode lib
VideoStreamDataInfo dataInfo;
memset(&dataInfo, 0, sizeof(VideoStreamDataInfo));
if(-1 == pVideoDecData->mVideoInfoVersion)
{
pVideoDecData->mVideoInfoVersion = pDmxOutBuf->infoVersion;
alogd("video info init version is [%d]!", pVideoDecData->mVideoInfoVersion);
}
if (pDmxOutBuf->infoVersion != pVideoDecData->mVideoInfoVersion)
{
alogd("Be careful! demux detect video info version change [%d]->[%d]!", pDmxOutBuf->infoVersion, pVideoDecData->mVideoInfoVersion);
if (pDmxOutBuf->pChangedStreamsInfo)
{
struct VideoInfo *pVideoinfo = (struct VideoInfo *)pDmxOutBuf->pChangedStreamsInfo;
if (pVideoinfo->videoNum != 1)
{
aloge("fatal error! the videoNum is not 1");
abort();
}
VDStreamInfo *pVDStreamInfo = VideoDecAddChangedStreamInfos(pVideoDecData, pVideoinfo);
dataInfo.pVideoInfo = (void *)&pVDStreamInfo->mStreamInfo;
dataInfo.bVideoInfoFlag = 1;
}
pVideoDecData->mVideoInfoVersion = pDmxOutBuf->infoVersion;
}
dataInfo.pData = (char*)pDmxOutBuf->pBuffer;
dataInfo.nLength = pDmxOutBuf->nFilledLen;
if (pDmxOutBuf->nFlags & CEDARV_FLAG_PTS_VALID)
{
dataInfo.nPts = pDmxOutBuf->nTimeStamp;
}
else
{
dataInfo.nPts = -1;
}
dataInfo.nPcr = -1;
if (pDmxOutBuf->nFlags & CEDARV_FLAG_FIRST_PART)
{
dataInfo.bIsFirstPart = 1;
}
if (pDmxOutBuf->nFlags & CEDARV_FLAG_LAST_PART)
{
dataInfo.bIsLastPart = 1;
alogv("last part found!");
}
if (pDmxOutBuf->video_stream_type == VIDEO_TYPE_MINOR) //CDX_VIDEO_STREAM_MINOR
{
dataInfo.nStreamIndex = 1;
}
else
{
dataInfo.nStreamIndex = 0;
}
// Send Vbs data to Decoder Lib
pthread_mutex_lock(&pVideoDecData->mVbsInputMutex);
int vdecRet = SubmitVideoStreamData(pVideoDecData->pCedarV, &dataInfo, dataInfo.nStreamIndex);
pthread_mutex_unlock(&pVideoDecData->mVbsInputMutex);
if (0 == vdecRet)
{// Send buf to decode lib success
eError = SUCCESS;
if (!list_empty(&pInputData->mUsingVbsList))
{
// Move node from mUsingVbsList to mIdleVbsList
pEntry = list_first_entry(&pInputData->mUsingVbsList, DMXPKT_NODE_T, mList);
list_move_tail(&pEntry->mList, &pInputData->mIdleVbsList);
// Send Vbs Valid message to input thread
if (pInputData->mWaitVbsValidFlag)
{
pInputData->mWaitVbsValidFlag = FALSE;
message_t msg;
msg.command = VDecComp_VbsAvailable;
put_message(&pInputData->cmd_queue, &msg);
}
// signal when all vbs return to idleList
if(pInputData->mbWaitVbsFullFlag)
{
struct list_head *pList;
int cnt = 0;
list_for_each(pList, &pInputData->mIdleVbsList) { cnt++; }
if (cnt >= pInputData->mNodeNum)
{
pInputData->mbWaitVbsFullFlag = FALSE;
pthread_cond_signal(&pInputData->mVbsFullCond);
}
}
pthread_mutex_unlock(&pInputData->mVbsListLock);
// Send Vbs Valid message to work thread
if (pVideoDecData->mWaitVbsInputFlag)
{
pVideoDecData->mWaitVbsInputFlag = FALSE;
message_t msg;
msg.command = VDecComp_VbsAvailable;
put_message(&pVideoDecData->cmd_queue, &msg);
}
}
else
{
pthread_mutex_unlock(&pInputData->mVbsListLock);
aloge("fatal error! No Using Vbs node while calling EmptyThisBuffer!");
return FAILURE;
}
}
else
{
aloge("fatal error! submit data fail, check code!");
pthread_mutex_unlock(&pInputData->mVbsListLock);
eError = FAILURE;
}
return eError;
}
ERRORTYPE VideoDecTunnel_EmptyThisBuffer_BufferSupplyOutput(COMP_HANDLETYPE hComponent, COMP_BUFFERHEADERTYPE *pBuffer)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
VIDEODEC_INPUT_DATA* pInputData = pVideoDecData->pInputData;
// Get buffer pointer from demux component
EncodedStream* pStream = (EncodedStream*)pBuffer->pOutputPortPrivate;
ERRORTYPE eError = SUCCESS;
DMXPKT_NODE_T* pEntry = NULL;
if(pStream->pBufferExtra!=NULL || pStream->nBufferExtraLen!=0)
{
aloge("fatal error! we only process pBuffer! BufferExtra[%p][%d] will be ignore!", pStream->pBufferExtra, pStream->nBufferExtraLen);
}
// Check it is the same buffer in mUsingAbsList
pthread_mutex_lock(&pInputData->mVbsListLock);
//make sure there is an idle node.
if(list_empty(&pInputData->mIdleVbsList))
{
alogw("Be careful! not enough idle node, malloc more!");
DMXPKT_NODE_T *pNode = (DMXPKT_NODE_T*)malloc(sizeof(DMXPKT_NODE_T));
if(pNode != NULL)
{
memset(pNode, 0, sizeof(DMXPKT_NODE_T));
list_add_tail(&pNode->mList, &pInputData->mIdleVbsList);
pInputData->mNodeNum++;
}
else
{
aloge("fatal error! malloc fail!");
pthread_mutex_unlock(&pInputData->mVbsListLock);
return ERR_VDEC_NOMEM;
}
}
//put to readylist
pEntry = list_first_entry(&pInputData->mIdleVbsList, DMXPKT_NODE_T, mList);
pEntry->stEncodedStream = *pStream;
list_move_tail(&pEntry->mList, &pInputData->mReadyVbsList);
pthread_mutex_lock(&pVideoDecData->mVbsInputMutex);
if (pVideoDecData->mWaitVbsInputFlag)
{
pVideoDecData->mWaitVbsInputFlag = FALSE;
message_t msg;
msg.command = VDecComp_VbsAvailable;
put_message(&pVideoDecData->cmd_queue, &msg);
}
pthread_mutex_unlock(&pVideoDecData->mVbsInputMutex);
pthread_mutex_unlock(&pInputData->mVbsListLock);
return eError;
}
ERRORTYPE VideoDecNonTunnel_EmptyThisBuffer(COMP_HANDLETYPE hComponent, COMP_BUFFERHEADERTYPE *pBuffer)
{
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
/*---------- Non-tunnel mode ----------*/
// Get Vbs Data
VdecInputStream *pInputStream = (VdecInputStream *)pBuffer->pAppPrivate;
VDEC_STREAM_S *pStream = pInputStream->pStream;
int nMilliSec = pInputStream->nMilliSec;
if (0 == pStream->mLen && pStream->mbEndOfStream)
{
alogd("indicate EndOfStream");
VideoDecSetStreamEof(hComponent);
goto ERROR;
}
pthread_mutex_lock(&pVideoDecData->mVbsInputMutex);
//send stream to vdeclib.
EncodedStream DmxOutBuf;
memset(&DmxOutBuf, 0, sizeof(EncodedStream));
_TryToRequestVbs:
DmxOutBuf.nTobeFillLen = pStream->mLen;
int ret = RequestVideoStreamBuffer(pVideoDecData->pCedarV, DmxOutBuf.nTobeFillLen, (char **)&DmxOutBuf.pBuffer,
(int *)&DmxOutBuf.nBufferLen, (char **)&DmxOutBuf.pBufferExtra,
(int *)&DmxOutBuf.nBufferExtraLen, 0);
if (0 == ret)
{// request buffer success
// Copy Vbs data to ringbuffer
if (pStream->mLen > DmxOutBuf.nBufferLen)
{
memcpy(DmxOutBuf.pBuffer, pStream->pAddr, DmxOutBuf.nBufferLen);
memcpy(DmxOutBuf.pBufferExtra, pStream->pAddr + DmxOutBuf.nBufferLen, pStream->mLen - DmxOutBuf.nBufferLen);
}
else
{
memcpy(DmxOutBuf.pBuffer, pStream->pAddr, pStream->mLen);
}
// Prepare Vbs data for video Decoder lib
VideoStreamDataInfo dataInfo;
memset(&dataInfo, 0, sizeof(VideoStreamDataInfo));
dataInfo.pData = (char *)DmxOutBuf.pBuffer;
dataInfo.nLength = pStream->mLen;
dataInfo.nPts = pStream->mPTS;
dataInfo.nPcr = -1;
dataInfo.bIsFirstPart = 1;
if (pStream->mbEndOfFrame)
{
dataInfo.bIsLastPart = 1;
}
else
{
alogw("Be careful! maybe one frame divided to several parts");
dataInfo.bIsLastPart = 0;
}
dataInfo.nStreamIndex = 0;
// Send Vbs data to Decoder lib
SubmitVideoStreamData(pVideoDecData->pCedarV, &dataInfo, dataInfo.nStreamIndex);
if (pVideoDecData->mWaitVbsInputFlag)
{
pVideoDecData->mWaitVbsInputFlag = FALSE;
message_t msg;
msg.command = VDecComp_VbsAvailable;
put_message(&pVideoDecData->cmd_queue, &msg);
}
if (pStream->mbEndOfStream)
{
alogd("indicate EndOfStream");
VideoDecSetStreamEof(hComponent);
}
eError = SUCCESS;
}
else
{// request buffer failed, wait timeout
if (0 == nMilliSec)
{
eError = ERR_VDEC_BUF_FULL;
}
else if (nMilliSec < 0)
{
pVideoDecData->mWaitEmptyVbsFlag = TRUE;
pVideoDecData->mRequestVbsLen = pStream->mLen;
pthread_cond_wait(&pVideoDecData->mEmptyVbsCondition, &pVideoDecData->mVbsInputMutex);
pVideoDecData->mWaitEmptyVbsFlag = FALSE;
goto _TryToRequestVbs;
}
else
{
pVideoDecData->mWaitEmptyVbsFlag = TRUE;
pVideoDecData->mRequestVbsLen = pStream->mLen;
int waitRet = pthread_cond_wait_timeout(&pVideoDecData->mEmptyVbsCondition, &pVideoDecData->mVbsInputMutex, nMilliSec);
if (ETIMEDOUT == waitRet)
{
alogv("wait empty vbs buffer timeout[%d]ms, ret[%d]", nMilliSec, waitRet);
eError = ERR_VDEC_BUF_FULL;
pVideoDecData->mWaitEmptyVbsFlag = FALSE;
}
else if (0 == waitRet)
{
pVideoDecData->mWaitEmptyVbsFlag = FALSE;
goto _TryToRequestVbs;
}
else
{
aloge("fatal error! pthread cond wait timeout ret[%d]", waitRet);
eError = ERR_VDEC_BUF_FULL;
pVideoDecData->mWaitEmptyVbsFlag = FALSE;
}
}
}
pthread_mutex_unlock(&pVideoDecData->mVbsInputMutex);
ERROR:
return eError;
}
/**
* send stream to vdeclib, can used in non-tunnel mode.
*
* @return SUCCESS
* @param hComponent vdecComp handle.
* @param pBuffer stream info.
*/
ERRORTYPE VideoDecEmptyThisBuffer(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_BUFFERHEADERTYPE *pBuffer)
{
ERRORTYPE eError = SUCCESS;
DMXPKT_NODE_T* pEntry = NULL;
// get component private data
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
VIDEODEC_INPUT_DATA* pInputData = pVideoDecData->pInputData;
pthread_mutex_lock(&pVideoDecData->mStateLock);
if (pVideoDecData->state != COMP_StateExecuting && pVideoDecData->state != COMP_StatePause)
{
alogw("send stream when vdec state[0x%x] is not executing/pause", pVideoDecData->state);
}
if(NULL == pVideoDecData->pCedarV)
{
alogw("Be careful! vdeclib is not create! can't send data!");
pthread_mutex_unlock(&pVideoDecData->mStateLock);
return ERR_VDEC_NOT_PERM;
}
if (pVideoDecData->mInputPortTunnelFlag)
{// inport tunnel mode
// check port index
if (pBuffer->nInputPortIndex == pVideoDecData->sInPortTunnelInfo[VDEC_PORT_SUFFIX_DEMUX].nPortIndex)
{
COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufferSupplier = &pVideoDecData->sPortBufSupplier[VDEC_PORT_SUFFIX_DEMUX];
if(COMP_BufferSupplyInput == pPortBufferSupplier->eBufferSupplier)
{
eError = VideoDecTunnel_EmptyThisBuffer_BufferSupplyInput(hComponent, pBuffer);
}
else if(COMP_BufferSupplyOutput == pPortBufferSupplier->eBufferSupplier)
{
eError = VideoDecTunnel_EmptyThisBuffer_BufferSupplyOutput(hComponent, pBuffer);
}
else
{
aloge("fatal error! wrong bufferSupplier[0x%x]!", pPortBufferSupplier->eBufferSupplier);
eError = FAILURE;
}
}
else
{
aloge("fatal error! PortIndex[%u]!=[%u]!", pBuffer->nInputPortIndex, pVideoDecData->sInPortTunnelInfo[VDEC_PORT_SUFFIX_DEMUX].nPortIndex);
eError = FAILURE;
}
}
else
{
eError = VideoDecNonTunnel_EmptyThisBuffer(hComponent, pBuffer);
}
pthread_mutex_unlock(&pVideoDecData->mStateLock);
return eError;
}
/**
* return frame to vdeclib in tunnel mode.
*
* @return SUCCESS
* @param hComponent vdecComp handle.
* @param pBuffer frame buffer info.
*/
ERRORTYPE VideoDecFillThisBuffer(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_BUFFERHEADERTYPE *pBuffer)
{
VIDEODECDATATYPE *pVideoDecData;
ERRORTYPE eError = SUCCESS;
int ret;
pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
if (pBuffer->nOutputPortIndex == pVideoDecData->sOutPortDef.nPortIndex)
{
VIDEO_FRAME_INFO_S *pFrameInfo = (VIDEO_FRAME_INFO_S*)pBuffer->pOutputPortPrivate;
eError = VideoDecTunnel_ReturnVDecCompOutputFrame(pVideoDecData, pFrameInfo->mId);
}
else
{
aloge("fatal error! outPortIndex[%d]!=[%d]", pBuffer->nOutputPortIndex, pVideoDecData->sOutPortDef.nPortIndex);
}
ERROR:
return eError;
}
//ERRORTYPE VideoDecQueryBufferState(COMP_HANDLETYPE hComponent, unsigned int nPortIndex, COMP_BUFFERSTATE* pBufferState)
//{
// VIDEODECDATATYPE* pVideoDecData;
// ERRORTYPE eError;
//
// eError = SUCCESS;
//
// pVideoDecData = (VIDEODECDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
//
// if(nPortIndex == pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].nPortIndex)
// {
// cedarv_quality_t vq;
// VideoDecoder* pCedarV;
//
// pCedarV = pVideoDecData->pCedarV;
// pCedarV->video_stream_type = pBufferState->video_stream_type;
// pCedarV->query_quality(pCedarV,&vq);
// pBufferState->nElementCounter = vq.frame_num_in_vbv;
// pBufferState->nValidSizePercent = vq.vbv_buffer_usage;
//
// int nStreamBufIndex;
// if(pBufferState->video_stream_type == VIDEO_TYPE_MINOR) //CDX_VIDEO_STREAM_MINOR
// {
// nStreamBufIndex = 1;
// }
// else
// {
// nStreamBufIndex = 0;
// }
// int nVbsBufferSize = VideoStreamBufferSize(pCedarV, nStreamBufIndex);
// int nVbsDataSize = VideoStreamDataSize(pCedarV, nStreamBufIndex);
// int nVbsFrameNum = VideoStreamFrameNum(pCedarV, nStreamBufIndex);
// pBufferState->nElementCounter = nVbsFrameNum;
// pBufferState->nValidSizePercent = nVbsDataSize*100/nVbsBufferSize;
// }
//
// return eError;
//}
/*****************************************************************************/
ERRORTYPE VideoDecComponentDeInit(COMP_HANDLETYPE hComponent)
{
VIDEODECDATATYPE *pVideoDecData;
VideoDecoder *pCedarV;
ERRORTYPE eError;
CompInternalMsgType eCmd;
message_t msg;
eError = SUCCESS;
eCmd = Stop;
pVideoDecData = (VIDEODECDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate);
msg.command = eCmd;
put_message(&pVideoDecData->cmd_queue, &msg);
// Wait for thread to exit so we can get the status into "error"
pthread_join(pVideoDecData->thread_id, (void*)&eError);
VideoDec_InputDataDestroy(pVideoDecData->pInputData);
pCedarV = pVideoDecData->pCedarV;
if (pCedarV)
{
DestroyVideoDecoder(pCedarV);
pCedarV = NULL;
}
message_destroy(&pVideoDecData->cmd_queue);
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
if (!list_empty(&pVideoDecData->mUsedOutFrameList)) {
aloge("fatal error! outUsedFrame must be 0!");
}
if (!list_empty(&pVideoDecData->mReadyOutFrameList)) {
aloge("fatal error! outReadyFrame must be 0!");
}
int nodeNum = 0;
if (!list_empty(&pVideoDecData->mIdleOutFrameList)) {
VDecCompOutputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoDecData->mIdleOutFrameList, mList)
{
list_del(&pEntry->mList);
free(pEntry);
nodeNum++;
}
}
if (nodeNum != pVideoDecData->mFrameNodeNum)
{
aloge("fatal error! frame node number is not match[%d][%d]", nodeNum, pVideoDecData->mFrameNodeNum);
}
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
//if VideoDec CompFrameBufferThread exist, stop it
if(pVideoDecData->mCompFrameBufferThreadId != 0)
{
msg.command = Stop;
put_message(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
pthread_join(pVideoDecData->mCompFrameBufferThreadId, (void *)&eError);
pVideoDecData->mCompFrameBufferThreadId = 0;
}
message_destroy(&pVideoDecData->mCompFrameBufferThreadMessageQueue);
if (!list_empty(&pVideoDecData->mCompUsedOutFrameList))
{
aloge("fatal error! CompUsedOutFrame must be 0!");
list_splice_tail_init(&pVideoDecData->mCompUsedOutFrameList, &pVideoDecData->mCompIdleOutFrameList);
}
if (!list_empty(&pVideoDecData->mCompReadyOutFrameList))
{
aloge("fatal error! CompReadyOutFrame must be 0!");
list_splice_tail_init(&pVideoDecData->mCompReadyOutFrameList, &pVideoDecData->mCompIdleOutFrameList);
}
if(!list_empty(&pVideoDecData->mCompIdleOutFrameList))
{
nodeNum = 0;
VDecCompOutputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoDecData->mCompIdleOutFrameList, mList)
{
list_del(&pEntry->mList);
CompFrameDestroy(pEntry);
free(pEntry);
nodeNum++;
}
}
if (nodeNum != VDEC_COMP_FRAME_COUNT)
{
aloge("fatal error! frame node number is not match[%d][%d]", nodeNum, VDEC_COMP_FRAME_COUNT);
}
pthread_cond_destroy(&pVideoDecData->mOutFrameFullCondition);
pthread_cond_destroy(&pVideoDecData->mReadyFrameCondition);
pthread_cond_destroy(&pVideoDecData->mEmptyVbsCondition);
pthread_cond_destroy(&pVideoDecData->mCompFBThreadOutFrameFullCondition);
pthread_cond_destroy(&pVideoDecData->mCompReadyFrameCondition);
pthread_cond_destroy(&pVideoDecData->mCondCompFBThreadState);
pthread_mutex_destroy(&pVideoDecData->mOutFrameListMutex);
pthread_mutex_destroy(&pVideoDecData->mVbsInputMutex);
pthread_mutex_destroy(&pVideoDecData->mCompOutFramesLock);
pthread_mutex_destroy(&pVideoDecData->mCompFBThreadStateLock);
pthread_mutex_destroy(&pVideoDecData->mStateLock);
pthread_mutex_destroy(&pVideoDecData->mDecodeFramesControlLock);
if (!list_empty(&pVideoDecData->mANWBuffersList) || !list_empty(&pVideoDecData->mPreviousANWBuffersList)) {
aloge("fatal error! why ANWBuffers is not empty?");
}
if (pVideoDecData->mIonFd >= 0) {
close(pVideoDecData->mIonFd);
pVideoDecData->mIonFd = -1;
}
if (!list_empty(&pVideoDecData->mChangedStreamList)) {
alogw("Low probability! changedStream is not processed done by vdeclib.");
VideoDecDestroyChangedStreamInfos(pVideoDecData);
}
if(pVideoDecData->mG2DHandle >= 0)
{
close(pVideoDecData->mG2DHandle);
pVideoDecData->mG2DHandle = -1;
}
#if VIDEO_DEC_TIME_DEBUG
//print statistics info
alogd("DecFrameCount[%d], timeDuration[%lld]us, averageDecDuration[%lld]us", pVideoDecData->mDecodeFrameCount, pVideoDecData->mTotalDecodeDuration, pVideoDecData->mTotalDecodeDuration/pVideoDecData->mDecodeFrameCount);
#endif
if (pVideoDecData->pInputData)
{
free(pVideoDecData->pInputData);
}
if (pVideoDecData->stVideoStreamInfo.pCodecSpecificData)
{
free(pVideoDecData->stVideoStreamInfo.pCodecSpecificData);
}
if (pVideoDecData)
{
free(pVideoDecData);
}
alogd("VideoDec component exited!");
return eError;
}
/*****************************************************************************/
ERRORTYPE VideoDecComponentInit(PARAM_IN COMP_HANDLETYPE hComponent)
{
MM_COMPONENTTYPE *pComp;
VIDEODECDATATYPE *pVideoDecData;
ERRORTYPE eError;
unsigned int err;
int i;
eError = SUCCESS;
pComp = (MM_COMPONENTTYPE *)hComponent;
// Create private data
pVideoDecData = (VIDEODECDATATYPE *)malloc(sizeof(VIDEODECDATATYPE));
memset(pVideoDecData, 0x0, sizeof(VIDEODECDATATYPE));
pComp->pComponentPrivate = (void *)pVideoDecData;
pVideoDecData->state = COMP_StateLoaded;
pthread_mutex_init(&pVideoDecData->mStateLock, NULL);
pVideoDecData->hSelf = hComponent;
pVideoDecData->mVideoInfoVersion = -1;
pVideoDecData->mG2DHandle = -1;
INIT_LIST_HEAD(&pVideoDecData->mChangedStreamList);
INIT_LIST_HEAD(&pVideoDecData->mIdleOutFrameList);
INIT_LIST_HEAD(&pVideoDecData->mReadyOutFrameList);
INIT_LIST_HEAD(&pVideoDecData->mUsedOutFrameList);
INIT_LIST_HEAD(&pVideoDecData->mCompIdleOutFrameList);
INIT_LIST_HEAD(&pVideoDecData->mCompReadyOutFrameList);
INIT_LIST_HEAD(&pVideoDecData->mCompUsedOutFrameList);
for (i = 0; i < VDEC_FRAME_COUNT; i++) {
VDecCompOutputFrame *pNode = (VDecCompOutputFrame *)malloc(sizeof(VDecCompOutputFrame));
if (NULL == pNode) {
aloge("fatal error! malloc fail[%s]!", strerror(errno));
break;
}
//memset(pNode, 0, sizeof(VDecCompOutputFrame));
list_add_tail(&pNode->mList, &pVideoDecData->mIdleOutFrameList);
pVideoDecData->mFrameNodeNum++;
}
for (i = 0; i < VDEC_COMP_FRAME_COUNT; i++)
{
VDecCompOutputFrame *pNode = (VDecCompOutputFrame *)malloc(sizeof(VDecCompOutputFrame));
if (NULL == pNode)
{
aloge("fatal error! malloc fail[%s]!", strerror(errno));
break;
}
memset(pNode, 0, sizeof(VDecCompOutputFrame));
list_add_tail(&pNode->mList, &pVideoDecData->mCompIdleOutFrameList);
}
INIT_LIST_HEAD(&pVideoDecData->mANWBuffersList);
INIT_LIST_HEAD(&pVideoDecData->mPreviousANWBuffersList);
pVideoDecData->mIonFd = -1;
err = pthread_mutex_init(&pVideoDecData->mDecodeFramesControlLock, NULL);
if (err != 0)
{
aloge("pthread mutex init fail!");
eError = ERR_VDEC_SYS_NOTREADY;
goto EXIT0;
}
pVideoDecData->mCurDecodeFramesNum = 0;
pVideoDecData->mLimitedDecodeFramesFlag = FALSE;
pVideoDecData->mDecodeFramesParam.mDecodeFrameNum = 0;
err = pthread_mutex_init(&pVideoDecData->mVbsInputMutex, NULL);
if (err != 0) {
aloge("pthread mutex init fail!");
eError = ERR_VDEC_SYS_NOTREADY;
goto EXIT0;
}
err = pthread_mutex_init(&pVideoDecData->mOutFrameListMutex, NULL);
if (err != 0) {
aloge("pthread mutex init fail!");
eError = ERR_VDEC_SYS_NOTREADY;
goto EXIT1;
}
err = pthread_mutex_init(&pVideoDecData->mCompOutFramesLock, NULL);
if (err != 0)
{
aloge("pthread mutex init fail!");
}
err = pthread_mutex_init(&pVideoDecData->mCompFBThreadStateLock, NULL);
if (err != 0)
{
aloge("pthread mutex init fail!");
}
pthread_condattr_t condAttr;
pthread_condattr_init(&condAttr);
pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
err = pthread_cond_init(&pVideoDecData->mOutFrameFullCondition, &condAttr);
if (err != 0) {
aloge("pthread cond init fail!");
eError = ERR_VDEC_SYS_NOTREADY;
goto EXIT2;
}
pthread_cond_init(&pVideoDecData->mReadyFrameCondition, &condAttr);
pthread_cond_init(&pVideoDecData->mEmptyVbsCondition, &condAttr);
pthread_cond_init(&pVideoDecData->mCompFBThreadOutFrameFullCondition, &condAttr);
pthread_cond_init(&pVideoDecData->mCompReadyFrameCondition, &condAttr);
pthread_cond_init(&pVideoDecData->mCondCompFBThreadState, &condAttr);
// Fill in function pointers
pComp->SetCallbacks = VideoDecSetCallbacks;
pComp->SendCommand = VideoDecSendCommand;
pComp->GetConfig = VideoDecGetConfig;
pComp->SetConfig = VideoDecSetConfig;
pComp->GetState = VideoDecGetState;
pComp->ComponentTunnelRequest = VideoDecComponentTunnelRequest;
pComp->ComponentDeInit = VideoDecComponentDeInit;
pComp->EmptyThisBuffer = VideoDecEmptyThisBuffer;
pComp->FillThisBuffer = VideoDecFillThisBuffer;
// Initialize component data structures to default values
pVideoDecData->sPortParam.nPorts = 0x2;
pVideoDecData->sPortParam.nStartPortNumber = 0x0;
// Initialize the video parameters for input port
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].nPortIndex =
pVideoDecData->sInPortExtraDef[VDEC_PORT_SUFFIX_DEMUX].nPortIndex = VDEC_PORT_INDEX_DEMUX;
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].bEnabled = TRUE;
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].eDomain = COMP_PortDomainVideo;
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].format.video.cMIMEType = "MPEG2";
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].format.video.nFrameWidth = 176;
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].format.video.nFrameHeight = 144;
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].eDir = COMP_DirInput;
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX].format.video.eCompressionFormat = PT_MPEG2VIDEO;
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_CLOCK].nPortIndex =
pVideoDecData->sInPortExtraDef[VDEC_PORT_SUFFIX_CLOCK].nPortIndex = VDEC_PORT_INDEX_CLOCK;
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_CLOCK].bEnabled = TRUE;
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_CLOCK].eDomain = COMP_PortDomainOther;
pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_CLOCK].eDir = COMP_DirInput;
// Initialize the video parameters for output port
pVideoDecData->sOutPortDef.nPortIndex = VDEC_OUT_PORT_INDEX_VRENDER;
pVideoDecData->sOutPortDef.bEnabled = TRUE;
pVideoDecData->sOutPortDef.eDomain = COMP_PortDomainVideo;
pVideoDecData->sOutPortDef.format.video.cMIMEType = "YUV420";
pVideoDecData->sOutPortDef.format.video.nFrameWidth = 176;
pVideoDecData->sOutPortDef.format.video.nFrameHeight = 144;
pVideoDecData->sOutPortDef.eDir = COMP_DirOutput;
pVideoDecData->sOutPortDef.format.video.eColorFormat = MM_PIXEL_FORMAT_YVU_PLANAR_420;
pVideoDecData->sPortBufSupplier[VDEC_PORT_SUFFIX_DEMUX].nPortIndex = VDEC_PORT_INDEX_DEMUX;
pVideoDecData->sPortBufSupplier[VDEC_PORT_SUFFIX_DEMUX].eBufferSupplier = COMP_BufferSupplyInput;
pVideoDecData->sPortBufSupplier[VDEC_PORT_SUFFIX_CLOCK].nPortIndex = VDEC_PORT_INDEX_CLOCK;
pVideoDecData->sPortBufSupplier[VDEC_PORT_SUFFIX_CLOCK].eBufferSupplier = COMP_BufferSupplyOutput;
pVideoDecData->sPortBufSupplier[2].nPortIndex = VDEC_OUT_PORT_INDEX_VRENDER;
pVideoDecData->sPortBufSupplier[2].eBufferSupplier = COMP_BufferSupplyOutput;
pVideoDecData->sInPortTunnelInfo[VDEC_PORT_SUFFIX_DEMUX].nPortIndex = VDEC_PORT_INDEX_DEMUX;
pVideoDecData->sInPortTunnelInfo[VDEC_PORT_SUFFIX_DEMUX].eTunnelType = TUNNEL_TYPE_COMMON;
pVideoDecData->sInPortTunnelInfo[VDEC_PORT_SUFFIX_CLOCK].nPortIndex = VDEC_PORT_INDEX_CLOCK;
pVideoDecData->sInPortTunnelInfo[VDEC_PORT_SUFFIX_CLOCK].eTunnelType = TUNNEL_TYPE_CLOCK;
pVideoDecData->sOutPortTunnelInfo.nPortIndex = VDEC_OUT_PORT_INDEX_VRENDER;
pVideoDecData->sOutPortTunnelInfo.eTunnelType = TUNNEL_TYPE_COMMON;
if (message_create(&pVideoDecData->cmd_queue) < 0)
{
aloge("message error!");
eError = ERR_VDEC_NOMEM;
goto EXIT3;
}
if (message_create(&pVideoDecData->mCompFrameBufferThreadMessageQueue) < 0)
{
aloge("fatal error! msg queue init fail!");
}
pVideoDecData->mMemOps = MemAdapterGetOpsS();
// Create input thread data
VIDEODEC_INPUT_DATA* pInputData = (VIDEODEC_INPUT_DATA*) malloc(sizeof(VIDEODEC_INPUT_DATA));
if (pInputData == NULL)
{
aloge("create input data error!");
eError = ERR_VDEC_NOMEM;
goto EXIT4;
}
pVideoDecData->pInputData = pInputData;
// Create the component thread
err = pthread_create(&pVideoDecData->thread_id, NULL, ComponentThread, pVideoDecData);
if (err || !pVideoDecData->thread_id) {
eError = ERR_VDEC_NOMEM;
goto EXIT5;
}
if((eError = VideoDec_InputDataInit(pInputData, pVideoDecData)) != SUCCESS)
{
aloge("fatal error! VideoDec InputData init fail");
goto EXIT5;
}
pthread_condattr_destroy(&condAttr);
return eError;
EXIT5:
free(pInputData);
pVideoDecData->pInputData = NULL;
EXIT4:
message_destroy(&pVideoDecData->cmd_queue);
message_destroy(&pVideoDecData->mCompFrameBufferThreadMessageQueue);
EXIT3:
pthread_cond_destroy(&pVideoDecData->mOutFrameFullCondition);
EXIT2:
pthread_mutex_destroy(&pVideoDecData->mOutFrameListMutex);
EXIT1:
pthread_mutex_destroy(&pVideoDecData->mVbsInputMutex);
EXIT0:
return eError;
}
static ERRORTYPE ReturnAllVideoStreams_Tunnel_BufferSupplyOutput(VIDEODECDATATYPE* pVideoDecData)
{
VIDEODEC_INPUT_DATA* pInputData = pVideoDecData->pInputData;
COMP_PARAM_PORTDEFINITIONTYPE *pPortDef = &pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX];
COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo = &pVideoDecData->sInPortTunnelInfo[VDEC_PORT_SUFFIX_DEMUX];
COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufferSupplier = &pVideoDecData->sPortBufSupplier[VDEC_PORT_SUFFIX_DEMUX];
int num = 0;
pthread_mutex_lock(&pInputData->mVbsListLock);
if(!list_empty(&pInputData->mReadyVbsList))
{
ERRORTYPE eError;
COMP_BUFFERHEADERTYPE obh;
memset(&obh, 0, sizeof(COMP_BUFFERHEADERTYPE));
DMXPKT_NODE_T *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pInputData->mReadyVbsList, mList)
{
obh.pOutputPortPrivate = (void*)&pEntry->stEncodedStream;
obh.nInputPortIndex = pPortDef->nPortIndex;
obh.nOutputPortIndex = pPortTunnelInfo->nTunnelPortIndex;
eError = COMP_FillThisBuffer(pPortTunnelInfo->hTunnel, &obh);
if(SUCCESS == eError)
{
list_move_tail(&pEntry->mList, &pInputData->mIdleVbsList);
num++;
}
else
{
aloge("fatal error! why return encoded stream fail[0x%x]?", eError);
}
}
}
if(num > 0)
{
alogd("VideoDec input thread, Tunnel_BufferSupplyOutput: return [%d]frames when state[%d] turning to idle!", num, pInputData->state);
}
pthread_mutex_unlock(&pInputData->mVbsListLock);
return SUCCESS;
}
static ERRORTYPE SendAllVideoStreamsToVencLib_Tunnel_BufferSupplyOutput(VIDEODECDATATYPE *pVideoDecData)
{
VIDEODEC_INPUT_DATA* pInputData = pVideoDecData->pInputData;
COMP_PARAM_PORTDEFINITIONTYPE *pPortDef = &pVideoDecData->sInPortDef[VDEC_PORT_SUFFIX_DEMUX];
COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo = &pVideoDecData->sInPortTunnelInfo[VDEC_PORT_SUFFIX_DEMUX];
COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufferSupplier = &pVideoDecData->sPortBufSupplier[VDEC_PORT_SUFFIX_DEMUX];
pthread_mutex_lock(&pInputData->mVbsListLock);
if(!list_empty(&pInputData->mReadyVbsList))
{
ERRORTYPE eError;
COMP_BUFFERHEADERTYPE obh;
memset(&obh, 0, sizeof(obh));
DMXPKT_NODE_T *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pInputData->mReadyVbsList, mList)
{
pthread_mutex_lock(&pVideoDecData->mVbsInputMutex);
//send stream to vdeclib.
EncodedStream DmxOutBuf;
memset(&DmxOutBuf, 0, sizeof(EncodedStream));
EncodedStream *pStream = &pEntry->stEncodedStream;
DmxOutBuf.nTobeFillLen = pStream->nFilledLen;
int ret = RequestVideoStreamBuffer(pVideoDecData->pCedarV, DmxOutBuf.nTobeFillLen, (char **)&DmxOutBuf.pBuffer,
(int *)&DmxOutBuf.nBufferLen, (char **)&DmxOutBuf.pBufferExtra,
(int *)&DmxOutBuf.nBufferExtraLen, 0);
if (0 == ret)
{// request buffer success
// Copy Vbs data to ringbuffer
if (pStream->nFilledLen > DmxOutBuf.nBufferLen)
{
memcpy(DmxOutBuf.pBuffer, pStream->pBuffer, DmxOutBuf.nBufferLen);
memcpy(DmxOutBuf.pBufferExtra, pStream->pBuffer + DmxOutBuf.nBufferLen, pStream->nFilledLen - DmxOutBuf.nBufferLen);
}
else
{
memcpy(DmxOutBuf.pBuffer, pStream->pBuffer, pStream->nFilledLen);
}
// Prepare Vbs data for video Decoder lib
VideoStreamDataInfo dataInfo;
memset(&dataInfo, 0, sizeof(VideoStreamDataInfo));
if(-1 == pVideoDecData->mVideoInfoVersion)
{
pVideoDecData->mVideoInfoVersion = pStream->infoVersion;
alogd("video info init version is [%d]!", pVideoDecData->mVideoInfoVersion);
}
if (pStream->infoVersion != pVideoDecData->mVideoInfoVersion)
{
alogd("Be careful! demux detect video info version change [%d]->[%d]!", pStream->infoVersion, pVideoDecData->mVideoInfoVersion);
if (pStream->pChangedStreamsInfo)
{
struct VideoInfo *pVideoinfo = (struct VideoInfo *)pStream->pChangedStreamsInfo;
if (pVideoinfo->videoNum != 1)
{
aloge("fatal error! the videoNum is not 1");
abort();
}
VDStreamInfo *pVDStreamInfo = VideoDecAddChangedStreamInfos(pVideoDecData, pVideoinfo);
dataInfo.pVideoInfo = (void *)&pVDStreamInfo->mStreamInfo;
dataInfo.bVideoInfoFlag = 1;
}
pVideoDecData->mVideoInfoVersion = pStream->infoVersion;
}
dataInfo.pData = (char*)DmxOutBuf.pBuffer;
dataInfo.nLength = pStream->nFilledLen;
if (pStream->nFlags & CEDARV_FLAG_PTS_VALID)
{
dataInfo.nPts = pStream->nTimeStamp;
}
else
{
dataInfo.nPts = -1;
}
//alogd("input encoded frame pts [%lld]us!", dataInfo.nPts);
dataInfo.nPcr = -1;
if (pStream->nFlags & CEDARV_FLAG_FIRST_PART)
{
dataInfo.bIsFirstPart = 1;
}
if (pStream->nFlags & CEDARV_FLAG_LAST_PART)
{
dataInfo.bIsLastPart = 1;
alogv("last part found!");
}
if (pStream->video_stream_type == VIDEO_TYPE_MINOR) //CDX_VIDEO_STREAM_MINOR
{
dataInfo.nStreamIndex = 1;
}
else
{
dataInfo.nStreamIndex = 0;
}
// Send Vbs data to Decoder lib
int submitRet = SubmitVideoStreamData(pVideoDecData->pCedarV, &dataInfo, dataInfo.nStreamIndex);
if(submitRet != 0)
{
aloge("fatal error! check vdeclib, ret[%d]", submitRet);
}
pthread_mutex_unlock(&pVideoDecData->mVbsInputMutex);
//return video stream
obh.pOutputPortPrivate = (void*)&pEntry->stEncodedStream;
obh.nInputPortIndex = pPortDef->nPortIndex;
obh.nOutputPortIndex = pPortTunnelInfo->nTunnelPortIndex;
eError = COMP_FillThisBuffer(pPortTunnelInfo->hTunnel, &obh);
if(eError != SUCCESS)
{
aloge("fatal error! why return video stream fail[0x%x]?", eError);
}
list_move_tail(&pEntry->mList, &pInputData->mIdleVbsList);
}
else
{// request buffer failed, maybe vbv buffer is full.
alogd("VdecChn[%d] request videoStreambuffer failed! maybe vbv is full, stop sending videoStream, start to decode.", pVideoDecData->mMppChnInfo.mChnId);
pthread_mutex_unlock(&pVideoDecData->mVbsInputMutex);
break;
}
}
}
pthread_mutex_unlock(&pInputData->mVbsListLock);
return SUCCESS;
}
/*
* Component Thread
* The ComponentThread function is exeuted in a separate pThread and
* is used to implement the actual component functions.
*/
/*****************************************************************************/
static void *ComponentThread(void *pThreadData)
{
unsigned int cmddata;
CompInternalMsgType cmd;
message_t cmd_msg;
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)pThreadData;
VIDEODEC_INPUT_DATA* pInputData = pVideoDecData->pInputData;
alogv("VideoDecoder ComponentThread start run...");
sprintf(pVideoDecData->mThreadName, "VDecChn%d", pVideoDecData->mMppChnInfo.mChnId);
prctl(PR_SET_NAME, (unsigned long)pVideoDecData->mThreadName, 0, 0, 0);
while (1)
{
PROCESS_MESSAGE:
if (get_message(&pVideoDecData->cmd_queue, &cmd_msg) == 0)
{// pump message from message queue
cmd = cmd_msg.command;
cmddata = (unsigned int)cmd_msg.para0;
// State transition command
if (cmd == SetState)
{
pthread_mutex_lock(&pVideoDecData->mStateLock);
if (pVideoDecData->state == (COMP_STATETYPE)(cmddata))
{// If the parameter states a transition to the same state, raise a same state transition error.
pVideoDecData->pCallbacks->EventHandler
(pVideoDecData->hSelf
,pVideoDecData->pAppData
,COMP_EventError
,ERR_VDEC_SAMESTATE
,pVideoDecData->state
,NULL
);
}
else
{
// transitions/callbacks made based on state transition table
// cmddata contains the target state
switch ((COMP_STATETYPE)(cmddata))
{
case COMP_StateInvalid:
pVideoDecData->state = COMP_StateInvalid;
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData,
COMP_EventError, ERR_VDEC_INVALIDSTATE, 0, NULL);
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData,
COMP_EventCmdComplete, COMP_CommandStateSet,
pVideoDecData->state, NULL);
break;
case COMP_StateLoaded:
{
if (pVideoDecData->state != COMP_StateIdle)
{
aloge("fatal error! VideoDec incorrect state transition [0x%x]->Loaded!", pVideoDecData->state);
pVideoDecData->pCallbacks->EventHandler
(pVideoDecData->hSelf
,pVideoDecData->pAppData
,COMP_EventError
,ERR_VDEC_INCORRECT_STATE_TRANSITION
,0
,NULL
);
}
if (pVideoDecData->mbUseCompFrame)
{
// Send message to FrameBufferThread
message_t msg;
InitMessage(&msg);
msg.command = SetState;
msg.para0 = COMP_StateLoaded;
msg.pReply = ConstructMessageReply();
putMessageWithData(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
int ret;
while(1)
{
ret = cdx_sem_down_timedwait(&msg.pReply->ReplySem, 5000);
if(ret != 0)
{
aloge("fatal error! vdecChn[%d] wait FBThd turn state[%d] timeout[0x%x]", pVideoDecData->mMppChnInfo.mChnId, msg.para0, ret);
}
else
{
break;
}
}
int replyRet = msg.pReply->ReplyResult;
if(replyRet != 0)
{
aloge("fatal error! vdecChn[%d] receive FBThd set state reply: 0x%x!", pVideoDecData->mMppChnInfo.mChnId, replyRet);
}
DestructMessageReply(msg.pReply);
msg.pReply = NULL;
pthread_mutex_lock(&pVideoDecData->mCompFBThreadStateLock);
if(pVideoDecData->mCompFBThreadState != COMP_StateLoaded)
{
aloge("fatal error! vdecChn[%d] FBThd state[%d] wrong", pVideoDecData->mMppChnInfo.mChnId, pVideoDecData->mCompFBThreadState);
}
pthread_mutex_unlock(&pVideoDecData->mCompFBThreadStateLock);
}
// wait all outFrame return.
struct list_head *pList;
alogd("wait VDec idleOutFrameList full");
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
pVideoDecData->mWaitOutFrameFullFlag = TRUE;
while (1)
{
int cnt = 0;
list_for_each(pList, &pVideoDecData->mIdleOutFrameList) { cnt++; }
list_for_each(pList, &pVideoDecData->mReadyOutFrameList) { cnt++; }
if (cnt < pVideoDecData->mFrameNodeNum)
{
alogd("wait idleOutFrameList [%d]nodes to home", pVideoDecData->mFrameNodeNum - cnt);
pthread_cond_wait(&pVideoDecData->mOutFrameFullCondition, &pVideoDecData->mOutFrameListMutex);
}
else
{
break;
}
}
pVideoDecData->mWaitOutFrameFullFlag = FALSE;
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
alogd("wait VDec idleOutFrameList full done");
//free ion_user_handle_t
VideoDecDestroyVDANWBufferList(pVideoDecData, &pVideoDecData->mPreviousANWBuffersList);
VideoDecDestroyVDANWBufferList(pVideoDecData, &pVideoDecData->mANWBuffersList);
//if inputPort is tunnel_BufferSupplyOutput, then return all input Video Stream.
if(pVideoDecData->mInputPortTunnelFlag)
{
if(pVideoDecData->sPortBufSupplier[VDEC_PORT_SUFFIX_DEMUX].eBufferSupplier == COMP_BufferSupplyOutput)
{
ReturnAllVideoStreams_Tunnel_BufferSupplyOutput(pVideoDecData);
}
}
// 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);
pVideoDecData->state = COMP_StateLoaded;
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData,
COMP_EventCmdComplete, COMP_CommandStateSet,
pVideoDecData->state, NULL);
break;
}
case COMP_StateIdle:
{
if (pVideoDecData->state == COMP_StateInvalid)
{
pVideoDecData->pCallbacks->EventHandler
(pVideoDecData->hSelf
,pVideoDecData->pAppData
,COMP_EventError
,ERR_VDEC_INCORRECT_STATE_TRANSITION
,0
,NULL
);
}
else if (pVideoDecData->state == COMP_StateLoaded)
{
pVideoDecData->state = COMP_StateIdle;
pVideoDecData->pCallbacks->EventHandler(
pVideoDecData->hSelf, pVideoDecData->pAppData, COMP_EventCmdComplete,
COMP_CommandStateSet, pVideoDecData->state, NULL);
}
else
{
alogd("VideoDec state[0x%x]->Idle!", pVideoDecData->state);
if (pVideoDecData->mbUseCompFrame)
{
// Send message to FrameBufferThread
message_t msg;
InitMessage(&msg);
msg.command = SetState;
msg.para0 = COMP_StateIdle;
msg.pReply = ConstructMessageReply();
putMessageWithData(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
int ret;
while(1)
{
ret = cdx_sem_down_timedwait(&msg.pReply->ReplySem, 5000);
if(ret != 0)
{
aloge("fatal error! vdecChn[%d] wait FBThd turn state[%d] timeout[0x%x]", pVideoDecData->mMppChnInfo.mChnId, msg.para0, ret);
}
else
{
break;
}
}
int replyRet = msg.pReply->ReplyResult;
if(replyRet != 0)
{
aloge("fatal error! vdecChn[%d] receive FBThd set state reply: 0x%x!", pVideoDecData->mMppChnInfo.mChnId, replyRet);
}
DestructMessageReply(msg.pReply);
msg.pReply = NULL;
//check FrameBufferThread state
pthread_mutex_lock(&pVideoDecData->mCompFBThreadStateLock);
if(pVideoDecData->mCompFBThreadState != COMP_StateIdle)
{
aloge("fatal error! vdecChn[%d] FBThd state[%d] wrong", pVideoDecData->mMppChnInfo.mChnId, pVideoDecData->mCompFBThreadState);
}
pthread_mutex_unlock(&pVideoDecData->mCompFBThreadStateLock);
}
if(pVideoDecData->mInputPortTunnelFlag)
{
if(pVideoDecData->sPortBufSupplier[VDEC_PORT_SUFFIX_DEMUX].eBufferSupplier == COMP_BufferSupplyOutput)
{
ReturnAllVideoStreams_Tunnel_BufferSupplyOutput(pVideoDecData);
}
}
pVideoDecData->state = COMP_StateIdle;
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData,
COMP_EventCmdComplete, COMP_CommandStateSet,
pVideoDecData->state, NULL);
}
// send message to input_thread
message_t InputThreadMsg;
InputThreadMsg.command = SetState;
InputThreadMsg.para0 = COMP_StateIdle;
put_message(&pInputData->cmd_queue, &InputThreadMsg);
// 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:
{
// Transition can only happen from pause or idle state
if (pVideoDecData->state == COMP_StateIdle || pVideoDecData->state == COMP_StatePause)
{
// Do some Init work when trans from Idle to Exec
if (pVideoDecData->state == COMP_StateIdle)
{
// Initial Video Decoder
if (NULL == pVideoDecData->pCedarV)
{
if (CedarvCodecInit(pVideoDecData) == SUCCESS)
{
VideoDecDecideCompFrameBufferMode(pVideoDecData);
}
else
{
aloge("fatal error! check why vdecLib init fail!");
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData,
COMP_EventError,
ERR_VDEC_INCORRECT_STATE_TRANSITION, 0, NULL);
break;
}
}
if (pVideoDecData->mbUseCompFrame)
{
// Send message to FrameBufferThread
message_t msg;
InitMessage(&msg);
msg.command = SetState;
msg.para0 = COMP_StateExecuting;
msg.pReply = ConstructMessageReply();
putMessageWithData(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
int ret;
while(1)
{
ret = cdx_sem_down_timedwait(&msg.pReply->ReplySem, 5000);
if(ret != 0)
{
aloge("fatal error! vdecChn[%d] wait FBThd turn state[%d] timeout[0x%x]", pVideoDecData->mMppChnInfo.mChnId, msg.para0, ret);
}
else
{
break;
}
}
int replyRet = msg.pReply->ReplyResult;
if(replyRet != 0)
{
aloge("fatal error! vdecChn[%d] receive FBThd set state reply: 0x%x!", pVideoDecData->mMppChnInfo.mChnId, replyRet);
}
DestructMessageReply(msg.pReply);
msg.pReply = NULL;
//check FrameBufferThread state
pthread_mutex_lock(&pVideoDecData->mCompFBThreadStateLock);
if(pVideoDecData->mCompFBThreadState != COMP_StateExecuting)
{
aloge("fatal error! vdecChn[%d] FBThd state[%d] wrong", pVideoDecData->mMppChnInfo.mChnId, pVideoDecData->mCompFBThreadState);
}
pthread_mutex_unlock(&pVideoDecData->mCompFBThreadStateLock);
}
}/*Idle to Exec*/
else if(pVideoDecData->state == COMP_StatePause)
{
if (pVideoDecData->mbUseCompFrame)
{
// Send message to FrameBufferThread
message_t msg;
InitMessage(&msg);
msg.command = SetState;
msg.para0 = COMP_StateExecuting;
msg.pReply = ConstructMessageReply();
putMessageWithData(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
int ret;
while(1)
{
ret = cdx_sem_down_timedwait(&msg.pReply->ReplySem, 5000);
if(ret != 0)
{
aloge("fatal error! vdecChn[%d] wait FBThd turn state[%d] timeout[0x%x]", pVideoDecData->mMppChnInfo.mChnId, msg.para0, ret);
}
else
{
break;
}
}
int replyRet = msg.pReply->ReplyResult;
if(replyRet != 0)
{
aloge("fatal error! vdecChn[%d] receive FBThd set state reply: 0x%x!", pVideoDecData->mMppChnInfo.mChnId, replyRet);
}
DestructMessageReply(msg.pReply);
msg.pReply = NULL;
//check FrameBufferThread state
pthread_mutex_lock(&pVideoDecData->mCompFBThreadStateLock);
if(pVideoDecData->mCompFBThreadState != COMP_StateExecuting)
{
aloge("fatal error! vdecChn[%d] FBThd state[%d] wrong", pVideoDecData->mMppChnInfo.mChnId, pVideoDecData->mCompFBThreadState);
}
pthread_mutex_unlock(&pVideoDecData->mCompFBThreadStateLock);
}
}
//hnd_clock_comp = (MM_COMPONENTTYPE *)(pVideoDecData->sInPortTunnelInfo[VDEC_PORT_SUFFIX_CLOCK].hTunnel);
pVideoDecData->state = COMP_StateExecuting;
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData,
COMP_EventCmdComplete, COMP_CommandStateSet,
pVideoDecData->state, NULL);
// send message to input_thread
message_t InputThreadMsg;
InputThreadMsg.command = SetState;
InputThreadMsg.para0 = COMP_StateExecuting;
put_message(&pInputData->cmd_queue, &InputThreadMsg);
// 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
{
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData,
COMP_EventError,
ERR_VDEC_INCORRECT_STATE_TRANSITION, 0, NULL);
}
break;
}
case COMP_StatePause:
{
// Transition can only happen from idle or executing state
if (pVideoDecData->state == COMP_StateIdle || pVideoDecData->state == COMP_StateExecuting)
{
if (pVideoDecData->mbUseCompFrame)
{
// Send message to FrameBufferThread
message_t msg;
InitMessage(&msg);
msg.command = SetState;
msg.para0 = COMP_StatePause;
msg.pReply = ConstructMessageReply();
putMessageWithData(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &msg);
int ret;
while(1)
{
ret = cdx_sem_down_timedwait(&msg.pReply->ReplySem, 5000);
if(ret != 0)
{
aloge("fatal error! vdecChn[%d] wait FBThd turn state[%d] timeout[0x%x]", pVideoDecData->mMppChnInfo.mChnId, msg.para0, ret);
}
else
{
break;
}
}
int replyRet = msg.pReply->ReplyResult;
if(replyRet != 0)
{
aloge("fatal error! vdecChn[%d] receive FBThd set state reply: 0x%x!", pVideoDecData->mMppChnInfo.mChnId, replyRet);
}
DestructMessageReply(msg.pReply);
msg.pReply = NULL;
//check FrameBufferThread state
pthread_mutex_lock(&pVideoDecData->mCompFBThreadStateLock);
if(pVideoDecData->mCompFBThreadState != COMP_StatePause)
{
aloge("fatal error! vdecChn[%d] FBThd state[%d] wrong", pVideoDecData->mMppChnInfo.mChnId, pVideoDecData->mCompFBThreadState);
}
pthread_mutex_unlock(&pVideoDecData->mCompFBThreadStateLock);
}
pVideoDecData->state = COMP_StatePause;
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData,
COMP_EventCmdComplete, COMP_CommandStateSet,
pVideoDecData->state, NULL);
// send message to input_thread
message_t InputThreadMsg;
InputThreadMsg.command = SetState;
InputThreadMsg.para0 = COMP_StatePause;
put_message(&pInputData->cmd_queue, &InputThreadMsg);
// 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
{
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData,
COMP_EventError,
ERR_VDEC_INCORRECT_STATE_TRANSITION, 0, NULL);
}
break;
}
default:
{
break;
}
}
}
pthread_mutex_unlock(&pVideoDecData->mStateLock);
}
else if (cmd == Stop)
{
// send message to input_thread
message_t InputThreadMsg;
InputThreadMsg.command = Stop;
InputThreadMsg.para0 = 0;
put_message(&pInputData->cmd_queue, &InputThreadMsg);
// Kill thread
goto EXIT;
}
else if (cmd == VDecComp_VbsAvailable)
{
alogv("Vdec vbs available");
}
else if (cmd == VDecComp_OutFrameAvailable)
{
alogv("Vdec frame available");
}
else if (cmd == VDecComp_ChangeGraphicBufferProducer)
{
//state is pause here in common
if (pVideoDecData->state != COMP_StatePause)
{
aloge("fatal error! state[%d] is not pause", pVideoDecData->state);
}
alogd("receive message: change GraphicBufferProducer, displayFrameRequestMode[%d]", pVideoDecData->nDisplayFrameRequestMode);
if (pVideoDecData->nDisplayFrameRequestMode)
{
pVideoDecData->mbChangeGraphicBufferProducer = TRUE;
if (!list_empty(&pVideoDecData->mPreviousANWBuffersList))
{
aloge("fatal error! previous GraphicBufferProducer's frames still remain!");
}
list_splice_tail_init(&pVideoDecData->mANWBuffersList, &pVideoDecData->mPreviousANWBuffersList);
//set vdeclib release flag, get release frames as many as possible, and free its ionUserHandle.
SetVideoFbmBufRelease(pVideoDecData->pCedarV);
VideoPicture *pReleasePicture = NULL;
VDANWBuffer *pVdAnb;
int nNeedReleaseBufferNum = 0;
while (1) {
pReleasePicture = RequestReleasePicture(pVideoDecData->pCedarV);
if (NULL == pReleasePicture) {
struct list_head *pList;
list_for_each(pList, &pVideoDecData->mPreviousANWBuffersList) { nNeedReleaseBufferNum++; }
if (nNeedReleaseBufferNum > 0) {
alogw("Low probability, not request all releasePictures, left [%d]frames",
nNeedReleaseBufferNum);
}
break;
}
pVdAnb = searchVDANWBufferListByVideoPicture(&pVideoDecData->mPreviousANWBuffersList, pReleasePicture);
if (NULL == pVdAnb) {
aloge("fatal error! not find release VideoPicture!");
abort();
}
alogd("ion_free: handle_ion[%p]", pReleasePicture->pPrivate);
//ion_free(pVideoDecData->mIonFd, pVdAnb->mIonUserHandle);
struct ion_handle_data handleData = {
.handle = pVdAnb->mIonUserHandle,
};
ioctl(pVideoDecData->mIonFd, ION_IOC_FREE, &handleData);
list_del(&pVdAnb->mList);
free(pVdAnb);
pReleasePicture->pPrivate = NULL;
}
if (nNeedReleaseBufferNum <= 0) {
pVideoDecData->mbChangeGraphicBufferProducer = FALSE;
}
}
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData,
COMP_EventCmdComplete, COMP_CommandVendorChangeANativeWindow, 0,
NULL);
}
else if (cmd == VDecComp_ReopenVideoEngine)
{
alogd("resolution change, reopen VideoEngine done.");
pVideoDecData->mResolutionChangeFlag = FALSE;
}
//precede to process message
goto PROCESS_MESSAGE;
}
if (pVideoDecData->mbEof)
{
alogd("VDec EOF!");
TMessage_WaitQueueNotEmpty(&pVideoDecData->cmd_queue, 0);
}
else if (pVideoDecData->state == COMP_StateExecuting)
{
int ret;
ERRORTYPE omxRet;
int bStreamEOF = 0;
// Get Video Decoder
VideoDecoder *pCedarV = pVideoDecData->pCedarV;
#if VIDEO_DEC_TIME_DEBUG
int64_t start_time = CDX_GetSysTimeUsMonotonic();
int64_t end_time;
#endif
// Check EOF Flag
pthread_mutex_lock(&pVideoDecData->mDecodeFramesControlLock);
if(pVideoDecData->mLimitedDecodeFramesFlag && pVideoDecData->mCurDecodeFramesNum >= pVideoDecData->mDecodeFramesParam.mDecodeFrameNum)
{
alogd("the vdec channel[%d] had decode %d frame, it is enough!",pVideoDecData->mMppChnInfo.mChnId, pVideoDecData->mCurDecodeFramesNum);
pthread_mutex_unlock(&pVideoDecData->mDecodeFramesControlLock);
TMessage_WaitQueueNotEmpty(&pVideoDecData->cmd_queue, 0);
goto PROCESS_MESSAGE;
}
pthread_mutex_unlock(&pVideoDecData->mDecodeFramesControlLock);
if (pVideoDecData->priv_flag & CDX_comp_PRIV_FLAGS_STREAMEOF)
{
bStreamEOF = 1;
}
else
{
bStreamEOF = 0;
}
// Decode one frame
if (!pVideoDecData->mResolutionChangeFlag)
{
// if inputPort is tunnel_BufferSupplyOutput, need send all video streams to vencLib.
if(pVideoDecData->mInputPortTunnelFlag)
{
if(pVideoDecData->sPortBufSupplier[VDEC_PORT_SUFFIX_DEMUX].eBufferSupplier == COMP_BufferSupplyOutput)
{
SendAllVideoStreamsToVencLib_Tunnel_BufferSupplyOutput(pVideoDecData);
}
}
ret = DecodeVideoStream(pCedarV, bStreamEOF /*eof*/, 0 /*key frame only*/, pVideoDecData->drop_B_frame /*drop b frame*/, 0 /*current time*/);
//alogd("decoder ret:0x%x, priv_flag:0x%x", ret, pVideoDecData->priv_flag);
}
else
{
aloge("fatal error! resolution change is not process done, can't decode!");
TMessage_WaitQueueNotEmpty(&pVideoDecData->cmd_queue, 0);
goto PROCESS_MESSAGE;
}
if (ret == VDECODE_RESULT_NO_BITSTREAM)
{
pVideoDecData->mNoBitstreamCounter++;
}
else
{
pVideoDecData->mNoBitstreamCounter = 0;
}
pthread_mutex_lock(&pVideoDecData->mDecodeFramesControlLock);
if(pVideoDecData->mLimitedDecodeFramesFlag && (VDECODE_RESULT_FRAME_DECODED == ret || VDECODE_RESULT_KEYFRAME_DECODED == ret))
{
pVideoDecData->mCurDecodeFramesNum++;
}
pthread_mutex_unlock(&pVideoDecData->mDecodeFramesControlLock);
#if VIDEO_DEC_TIME_DEBUG
end_time = CDX_GetSysTimeUsMonotonic();
if ( ret == VDECODE_RESULT_OK
|| ret == VDECODE_RESULT_CONTINUE
|| ret == VDECODE_RESULT_FRAME_DECODED
|| ret == VDECODE_RESULT_KEYFRAME_DECODED
)
{
if (end_time - start_time > 200 * 1000)
{
alogd("Be careful! vdecChn[%d], decodeType[%d] too long to [%lld]us, ret[0x%x]",
pVideoDecData->mMppChnInfo.mChnId, pVideoDecData->mChnAttr.mType, end_time - start_time, ret);
}
pVideoDecData->mTotalDecodeDuration += end_time - start_time;
if (ret == VDECODE_RESULT_FRAME_DECODED || ret == VDECODE_RESULT_KEYFRAME_DECODED)
{
pVideoDecData->mDecodeFrameCount++;
}
}
#endif
if (pVideoDecData->mbChangeGraphicBufferProducer)
{
alogd("vdeclib ret[%d] when changeGraphicBufferProducer!", ret);
// continue get release frames as many as possible, and free its ionUserHandle.
VDANWBuffer *pVdAnb;
int nNeedReleaseBufferNum = 0;
VideoPicture *pReleasePicture = NULL;
while (1)
{
pReleasePicture = RequestReleasePicture(pVideoDecData->pCedarV);
if (NULL == pReleasePicture)
{
struct list_head *pList;
list_for_each(pList, &pVideoDecData->mPreviousANWBuffersList)
{
nNeedReleaseBufferNum++;
}
if (nNeedReleaseBufferNum > 0)
{
alogw("Low probability, not request all releasePictures, left [%d]frames", nNeedReleaseBufferNum);
}
break;
}
pVdAnb = searchVDANWBufferListByVideoPicture(&pVideoDecData->mPreviousANWBuffersList, pReleasePicture);
if (NULL == pVdAnb)
{
aloge("fatal error! not find release VideoPicture!");
abort();
}
alogd("ion_free: handle_ion[%p]", pReleasePicture->pPrivate);
//ion_free(pVideoDecData->mIonFd, pVdAnb->mIonUserHandle);
struct ion_handle_data handleData = {
.handle = pVdAnb->mIonUserHandle,
};
ioctl(pVideoDecData->mIonFd, ION_IOC_FREE, &handleData);
list_del(&pVdAnb->mList);
free(pVdAnb);
pReleasePicture->pPrivate = NULL;
}
if (nNeedReleaseBufferNum <= 0)
{
pVideoDecData->mbChangeGraphicBufferProducer = FALSE;
}
}
if ((VDECODE_RESULT_KEYFRAME_DECODED == ret || VDECODE_RESULT_FRAME_DECODED == ret || (VDECODE_RESULT_NO_BITSTREAM == ret && ValidPictureNum(pCedarV, 0))))
{// Get one frame
//alogv("cedar dec ret:%d totalframe:%d",ret,pVideoDecData->total_dec_frames++);
//check if need signal emptyVbs ready.
if (FALSE == pVideoDecData->mInputPortTunnelFlag)
{
pthread_mutex_lock(&pVideoDecData->mVbsInputMutex);
if (pVideoDecData->mWaitEmptyVbsFlag)
{
int nEmptyVbsSize = VideoStreamBufferSize(pVideoDecData->pCedarV, 0) - VideoStreamDataSize(pVideoDecData->pCedarV, 0);
if (nEmptyVbsSize >= pVideoDecData->mRequestVbsLen)
{
pthread_cond_signal(&pVideoDecData->mEmptyVbsCondition);
}
}
pthread_mutex_unlock(&pVideoDecData->mVbsInputMutex);
}
//request frame
int releaseRet;
while (1)
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
if (list_empty(&pVideoDecData->mIdleOutFrameList))
{// Output buffer full, malloc new block
aloge("fatal error! idle out frame list is empty, wait");
VDecCompOutputFrame *pNewNode = malloc(sizeof(VDecCompOutputFrame));
if (NULL == pNewNode)
{
aloge("fatal error! malloc fail! turn to stateInvalid!");
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData, COMP_EventError, ERR_VDEC_NOMEM, 0, NULL);
pVideoDecData->state = COMP_StateInvalid;
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
goto PROCESS_MESSAGE;
}
list_add_tail(&pNewNode->mList, &pVideoDecData->mIdleOutFrameList);
}
VDecCompOutputFrame *pOutFrame = list_first_entry(&pVideoDecData->mIdleOutFrameList, VDecCompOutputFrame, mList);
//don't support double stream now. we don't need it.
pOutFrame->mpPicture = RequestPicture(pCedarV, 0 /*the major stream*/);
if (pOutFrame->mpPicture != NULL)
{
if(pVideoDecData->mVConfig.bSecOutputEn)
{
//and now , support double stream ,just for mjpeg no-tunnl...
pOutFrame->mpSubPicture = RequestPicture(pCedarV, 1 /*the sub stream*/);
if(NULL == pOutFrame->mpSubPicture)
{
aloge("fatal error! why the sub output can not get stream?");
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
break;
}
// alogd("main[%d,%d,%dx%d], sub[%d,%d,%dx%d]",
// pOutFrame->mpPicture->nLeftOffset, pOutFrame->mpPicture->nTopOffset,
// pOutFrame->mpPicture->nRightOffset - pOutFrame->mpPicture->nLeftOffset,
// pOutFrame->mpPicture->nBottomOffset - pOutFrame->mpPicture->nTopOffset,
// pOutFrame->mpSubPicture->nLeftOffset, pOutFrame->mpSubPicture->nTopOffset,
// pOutFrame->mpSubPicture->nRightOffset - pOutFrame->mpSubPicture->nLeftOffset,
// pOutFrame->mpSubPicture->nBottomOffset - pOutFrame->mpSubPicture->nTopOffset);
}
list_del(&pOutFrame->mList);
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
#ifdef __WRITEOUT_FRAMEBUFFER
static int pic_id = 0;
if (pic_id % 30 == 0)
{
FILE *fp_yuv = fopen("/mnt/extsd/yuv.dat", "a+");
alogd("pict->nWidth(%d), pict->nHeight(%d)", pOutFrame->mpPicture->nWidth,
pOutFrame->mpPicture->nHeight);
fwrite(pOutFrame->mpPicture->pData0, 1,
pOutFrame->mpPicture->nWidth * pOutFrame->mpPicture->nHeight, fp_yuv);
fwrite(pOutFrame->mpPicture->pData1, 1,
pOutFrame->mpPicture->nWidth * pOutFrame->mpPicture->nHeight / 2, fp_yuv);
fclose(fp_yuv);
}
pic_id++;
#endif
if (pVideoDecData->mOutputPortTunnelFlag)
{// out port tunnel mode
VideoDecTunnel_SendVDecCompOutputFrame(pVideoDecData, pOutFrame);
}
else
{// out port non-tunnel mode
VideoDecNonTunnel_ReadyVDecCompOutputFrame(pVideoDecData, pOutFrame);
}
}
else
{
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
break;
}
}
}
else if (ret == VDECODE_RESULT_OK || ret == VDECODE_RESULT_CONTINUE)
{
}
else if (VDECODE_RESULT_NO_FRAME_BUFFER == ret)
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
int emptyFrameNum = EmptyPictureBufferNum(pCedarV, 0);
if (emptyFrameNum <= 0)
{
pVideoDecData->mWaitOutFrameFlag = TRUE;
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
//if non-tunnel mode and no-rotate, then send cb msg to user, user will return frame,
//now, EyeseeUSBCamera need receive no frame buffer message, then return frame.
if (!pVideoDecData->mOutputPortTunnelFlag && !pVideoDecData->mbUseCompFrame)
{
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData, COMP_EventMoreBuffer, 0, 0, NULL);
}
TMessage_WaitQueueNotEmpty(&pVideoDecData->cmd_queue, 0);
}
else
{
//alogd("Low probability! vdecLib has empty frame[%d] after decode_no_frame!", emptyFrameNum);
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
}
goto PROCESS_MESSAGE;
}
else if (VDECODE_RESULT_NO_BITSTREAM == ret)
{// No Vbs data
if (pVideoDecData->priv_flag & CDX_comp_PRIV_FLAGS_STREAMEOF)
{
usleep(5 * 1000);
if (!pVideoDecData->exit_counter)
{
pVideoDecData->exit_counter++;
continue;
}
alogd("VideoDec notify EOF");
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData, COMP_EventBufferFlag, 0, 0, NULL);
pVideoDecData->mbEof = TRUE;
continue;
}
pthread_mutex_lock(&pVideoDecData->mVbsInputMutex);
int streamSize = VideoStreamDataSize(pCedarV, 0);
if (streamSize > 0 && pVideoDecData->mNoBitstreamCounter < 2)
{
//alogd("Low probability! vdecLib has bitstream[%d]!", streamSize);
pthread_mutex_unlock(&pVideoDecData->mVbsInputMutex);
}
else
{// wait Vbs data come
pVideoDecData->mWaitVbsInputFlag = TRUE;
pthread_mutex_unlock(&pVideoDecData->mVbsInputMutex);
TMessage_WaitQueueNotEmpty(&pVideoDecData->cmd_queue, 0);
}
goto PROCESS_MESSAGE;
}
else if (ret <= VDECODE_RESULT_UNSUPPORTED)
{
//* CXC, unsupported stream, may be stream format not supported or memory allocation for frame buffers fail.
aloge("fatal error! cedarv dec error 0 ret[%d]", ret);
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData, COMP_EventError, ERR_VDEC_INVALIDSTATE, 0, NULL);
pVideoDecData->state = COMP_StateInvalid;
}
else if (ret == VDECODE_RESULT_RESOLUTION_CHANGE)
{
alogd("detect video picture resolution change!");
//request and send all frames to videoRender.
pVideoDecData->mResolutionChangeFlag = TRUE;
int releaseRet;
while (1)
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
if (list_empty(&pVideoDecData->mIdleOutFrameList))
{
aloge("fatal error! idle out frame list is empty, wait");
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
if (TMessage_WaitQueueNotEmpty(&pVideoDecData->cmd_queue, 200) > 0)
{
goto PROCESS_MESSAGE;
}
else
{
continue;
}
}
VDecCompOutputFrame *pOutFrame = list_first_entry(&pVideoDecData->mIdleOutFrameList, VDecCompOutputFrame, mList);
//don't support double stream now. we don't need it.
pOutFrame->mpPicture = RequestPicture(pCedarV, 0 /*the major stream*/);
if (pOutFrame->mpPicture != NULL)
{
list_del(&pOutFrame->mList);
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
if (pVideoDecData->mOutputPortTunnelFlag)
{
COMP_BUFFERHEADERTYPE obh;
obh.nOutputPortIndex = pVideoDecData->sOutPortTunnelInfo.nPortIndex;
obh.nInputPortIndex = pVideoDecData->sOutPortTunnelInfo.nTunnelPortIndex;
VIDEO_FRAME_INFO_S stFrameInfo;
config_VIDEO_FRAME_INFO_S_by_VideoPicture(&stFrameInfo, pOutFrame->mpPicture, pVideoDecData);
obh.pOutputPortPrivate = (void*)&stFrameInfo;
omxRet = COMP_EmptyThisBuffer(pVideoDecData->sOutPortTunnelInfo.hTunnel, &obh);
if (SUCCESS == omxRet)
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
list_add_tail(&pOutFrame->mList, &pVideoDecData->mUsedOutFrameList);
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
}
else
{
if (ERR_VDEC_INCORRECT_STATE_OPERATION == omxRet)
{
alogd(
"Be careful! VDec output frame fail[0x%x], maybe next component status is "
"Loaded, return frame!",
omxRet);
}
releaseRet = ReturnPicture(pCedarV, (VideoPicture *)pOutFrame->mpPicture);
if (releaseRet != 0)
{
aloge("fatal error! Return Picture() fail ret[%d]", ret);
}
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
list_add(&pOutFrame->mList, &pVideoDecData->mIdleOutFrameList);
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
}
}
else
{
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
list_add_tail(&pOutFrame->mList, &pVideoDecData->mReadyOutFrameList);
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
}
}
else
{
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
break;
}
}
//notify videorender resolution change.
if (pVideoDecData->mOutputPortTunnelFlag)
{
COMP_SetConfig(pVideoDecData->sOutPortTunnelInfo.hTunnel, COMP_IndexVendorResolutionChange, NULL);
}
else
{
pVideoDecData->pCallbacks->EventHandler(pVideoDecData->hSelf, pVideoDecData->pAppData, COMP_EventMultiPixelExit, 0, 0, NULL);
}
//wait ReopenVideoEngine().
TMessage_WaitQueueNotEmpty(&pVideoDecData->cmd_queue, 0);
goto PROCESS_MESSAGE;
}
else
{
aloge("fatal error! ret[%d]", ret);
}
}
else
{// not Exec state, wait message
TMessage_WaitQueueNotEmpty(&pVideoDecData->cmd_queue, 0);
}
}
EXIT:
alogv("VideoDecoder ComponentThread stopped");
return (void *)SUCCESS;
}
void setCompVideoPictureInfo(VideoPicture *pDst, VideoPicture *pSrc)
{
// int nID;
pDst->nStreamIndex = pSrc->nStreamIndex;
pDst->ePixelFormat = pSrc->ePixelFormat;
// int nWidth;
// int nHeight;
// int nLineStride;
// int nTopOffset;
// int nLeftOffset;
// int nBottomOffset;
// int nRightOffset;
pDst->nFrameRate = pSrc->nFrameRate;
pDst->nAspectRatio = pSrc->nAspectRatio;
pDst->bIsProgressive = pSrc->bIsProgressive;
pDst->bTopFieldFirst = pSrc->bTopFieldFirst;
pDst->bRepeatTopField = pSrc->bRepeatTopField;
pDst->nPts = pSrc->nPts;
pDst->nPcr = pSrc->nPcr;
// char* pData0;
// char* pData1;
// char* pData2;
// char* pData3;
// int bMafValid;
// char* pMafData;
// int nMafFlagStride;
// int bPreFrmValid;
// int nBufId;
// size_addr phyYBufAddr;
// size_addr phyCBufAddr;
// void* pPrivate;
// int nBufFd;
// int nBufStatus;
// int bTopFieldError;
// int bBottomFieldError;
// int nColorPrimary;
// int bFrameErrorFlag;
//* to save hdr info and afbc header info
// void* pMetaData;
//*display related parameter
// VIDEO_FULL_RANGE_FLAG video_full_range_flag;
// VIDEO_TRANSFER transfer_characteristics;
// VIDEO_MATRIX_COEFFS matrix_coeffs;
// u8 colour_primaries;
//*end of display related parameter defined
//size_addr nLower2BitPhyAddr;
// int nLower2BitBufSize;
// int nLower2BitBufOffset;
// int nLower2BitBufStride;
// int b10BitPicFlag;
// int bEnableAfbcFlag;
//
// int nBufSize;
// int nAfbcSize;
// int nDebugCount;
}
ERRORTYPE VideoDecRotateFrame(const VideoPicture *pSrc, VideoPicture *pDst, VIDEODECDATATYPE *pVideoDecData)
{
int nRotation; //anti-clock wise
switch(pVideoDecData->cedarv_rotation)
{
case 0:
nRotation = 0;
break;
case 1:
nRotation = 90;
break;
case 2:
nRotation = 180;
break;
case 3:
nRotation = 270;
break;
default:
aloge("fatal error! cedarv rotation[%d] is not support!", pVideoDecData->cedarv_rotation);
nRotation = 0;
break;
}
#if 0
g2d_blt blit_para;
int err;
ERRORTYPE ret = SUCCESS;
if (nRotation != 90 && nRotation != 180 && nRotation != 270)
{
aloge("fatal error! rotation[%d] is invalid!", nRotation);
return ERR_VDEC_ILLEGAL_PARAM;
}
if(pVideoDecData->mG2DHandle < 0)
{
aloge("fatal error! g2d driver[%d] is not valid, can't rotate!", pVideoDecData->mG2DHandle);
return ERR_VDEC_SYS_NOTREADY;
}
g2d_data_fmt eSrcFormat, eDstFormat;
g2d_pixel_seq eSrcPixelSeq, eDstPixelSeq;
ERRORTYPE eError;
eError = convert_EPIXELFORMAT_to_G2dFormat((enum EPIXELFORMAT)pSrc->ePixelFormat, &eSrcFormat, &eSrcPixelSeq);
if(eError!=SUCCESS)
{
aloge("fatal error! src pixel format[0x%x] is invalid!", pSrc->ePixelFormat);
return ERR_VDEC_ILLEGAL_PARAM;
}
eError = convert_EPIXELFORMAT_to_G2dFormat((enum EPIXELFORMAT)pDst->ePixelFormat, &eDstFormat, &eDstPixelSeq);
if(eError!=SUCCESS)
{
aloge("fatal error! dst pixel format[0x%x] is invalid!", pDst->ePixelFormat);
return ERR_VDEC_ILLEGAL_PARAM;
}
memset(&blit_para, 0, sizeof(g2d_blt));
blit_para.src_image.addr[0] = pSrc->phyYBufAddr;
blit_para.src_image.addr[1] = pSrc->phyCBufAddr;
blit_para.src_image.w = pSrc->nWidth; /* src buffer width in pixel units */
blit_para.src_image.h = pSrc->nHeight; /* src buffer height in pixel units */
blit_para.src_image.format = eSrcFormat;
blit_para.src_image.pixel_seq = eSrcPixelSeq;//G2D_SEQ_VUVU; /* */
blit_para.src_rect.x = 0; /* src rect->x in pixel */
blit_para.src_rect.y = 0; /* src rect->y in pixel */
blit_para.src_rect.w = pSrc->nWidth; /* src rect->w in pixel */
blit_para.src_rect.h = pSrc->nHeight; /* src rect->h in pixel */
blit_para.dst_image.addr[0] = pDst->phyYBufAddr;
blit_para.dst_image.addr[1] = pDst->phyCBufAddr;
blit_para.dst_image.w = pDst->nWidth; /* dst buffer width in pixel units */
blit_para.dst_image.h = pDst->nHeight; /* dst buffer height in pixel units */
blit_para.dst_image.format = eDstFormat;
blit_para.dst_image.pixel_seq = eDstPixelSeq;
blit_para.dst_x = 0; /* dst rect->x in pixel */
blit_para.dst_y = 0; /* dst rect->y in pixel */
blit_para.color = 0xff; /* fix me*/
blit_para.alpha = 0xff; /* globe alpha */
switch(nRotation)
{
case 90:
blit_para.flag = G2D_BLT_ROTATE90;
break;
case 180:
blit_para.flag = G2D_BLT_ROTATE180;
break;
case 270:
blit_para.flag = G2D_BLT_ROTATE270;
break;
default:
aloge("fatal error! rotation[%d] is invalid!", nRotation);
blit_para.flag = G2D_BLT_NONE;
break;
}
err = ioctl(pVideoDecData->mG2DHandle, G2D_CMD_BITBLT, (unsigned long)&blit_para);
if(err < 0)
{
aloge("fatal error! bit-block(image) transfer failed");
system("cd /sys/class/sunxi_dump;echo 0x14A8000,0x14A8100 > dump;cat dump");
ret = ERR_VDEC_SYS_NOTREADY;
}
return ret;
#else
g2d_blt_h blit;
int err;
ERRORTYPE ret = SUCCESS;
if (nRotation != 90 && nRotation != 180 && nRotation != 270 && nRotation != 360)
{
aloge("fatal error! rotation[%d] is invalid!", nRotation);
return ERR_VDEC_ILLEGAL_PARAM;
}
if(pVideoDecData->mG2DHandle < 0)
{
aloge("fatal error! g2d driver[%d] is not valid, can't rotate!", pVideoDecData->mG2DHandle);
return ERR_VDEC_SYS_NOTREADY;
}
g2d_fmt_enh eSrcFormat, eDstFormat;
ERRORTYPE eError;
eError = convert_EPIXELFORMAT_to_g2d_fmt_enh(pSrc->ePixelFormat, &eSrcFormat);
if(eError!=SUCCESS)
{
aloge("fatal error! src pixel format[0x%x] is invalid!", pSrc->ePixelFormat);
return ERR_VDEC_ILLEGAL_PARAM;
}
eError = convert_EPIXELFORMAT_to_g2d_fmt_enh(pDst->ePixelFormat, &eDstFormat);
if(eError!=SUCCESS)
{
aloge("fatal error! dst pixel format[0x%x] is invalid!", pDst->ePixelFormat);
return ERR_VDEC_ILLEGAL_PARAM;
}
//config blit
memset(&blit, 0, sizeof(g2d_blt_h));
switch(nRotation)
{
case 90:
blit.flag_h = G2D_ROT_90;
break;
case 180:
blit.flag_h = G2D_ROT_180;
break;
case 270:
blit.flag_h = G2D_ROT_270;
break;
default:
aloge("fatal error! rotation[%d] is invalid!", nRotation);
blit.flag_h = G2D_BLT_NONE_H;
break;
}
blit.src_image_h.bbuff = 1;
blit.src_image_h.use_phy_addr = 1;
blit.src_image_h.color = 0xff;
blit.src_image_h.format = eSrcFormat;
blit.src_image_h.laddr[0] = pSrc->phyYBufAddr;
blit.src_image_h.laddr[1] = pSrc->phyCBufAddr;
if(pSrc->ePixelFormat == PIXEL_FORMAT_YUV_PLANER_420)
{
blit.src_image_h.laddr[2] = pSrc->phyCBufAddr+pSrc->nHeight*pSrc->nLineStride/4;
}
else if(pSrc->ePixelFormat == PIXEL_FORMAT_YV12)
{
blit.src_image_h.laddr[1] = pSrc->phyCBufAddr+pSrc->nHeight*pSrc->nLineStride/4;
blit.src_image_h.laddr[2] = pSrc->phyCBufAddr;
}
blit.src_image_h.width = pSrc->nWidth;
blit.src_image_h.height = pSrc->nHeight;
blit.src_image_h.align[0] = 0;
blit.src_image_h.align[1] = 0;
blit.src_image_h.align[2] = 0;
blit.src_image_h.clip_rect.x = 0;
blit.src_image_h.clip_rect.y = 0;
blit.src_image_h.clip_rect.w = pSrc->nWidth;
blit.src_image_h.clip_rect.h = pSrc->nHeight;
blit.src_image_h.gamut = G2D_BT709;
blit.src_image_h.bpremul = 0;
blit.src_image_h.alpha = 0xff;
blit.src_image_h.mode = G2D_GLOBAL_ALPHA;
blit.dst_image_h.bbuff = 1;
blit.dst_image_h.use_phy_addr = 1;
blit.dst_image_h.color = 0xff;
blit.dst_image_h.format = eDstFormat;
blit.dst_image_h.laddr[0] = pDst->phyYBufAddr;
blit.dst_image_h.laddr[1] = pDst->phyCBufAddr;
if(pDst->ePixelFormat == PIXEL_FORMAT_YUV_PLANER_420)
{
blit.dst_image_h.laddr[2] = pDst->phyCBufAddr+pDst->nHeight*pDst->nLineStride/4;
}
else if(pDst->ePixelFormat == PIXEL_FORMAT_YV12)
{
blit.dst_image_h.laddr[1] = pDst->phyCBufAddr+pDst->nHeight*pDst->nLineStride/4;
blit.dst_image_h.laddr[2] = pDst->phyCBufAddr;
}
blit.dst_image_h.width = pDst->nWidth;
blit.dst_image_h.height = pDst->nHeight;
blit.dst_image_h.align[0] = 0;
blit.dst_image_h.align[1] = 0;
blit.dst_image_h.align[2] = 0;
blit.dst_image_h.clip_rect.x = 0;
blit.dst_image_h.clip_rect.y = 0;
blit.dst_image_h.clip_rect.w = pDst->nWidth;
blit.dst_image_h.clip_rect.h = pDst->nHeight;
blit.dst_image_h.gamut = G2D_BT709;
blit.dst_image_h.bpremul = 0;
blit.dst_image_h.alpha = 0xff;
blit.dst_image_h.mode = G2D_GLOBAL_ALPHA;
// blit.color = 0xff;
// blit.alpha = 0xff;
err = ioctl(pVideoDecData->mG2DHandle, G2D_CMD_BITBLT_H, (unsigned long)&blit);
if(err < 0)
{
aloge("fatal error! bit-block(image) transfer failed");
system("cd /sys/class/sunxi_dump;echo 0x14A8000,0x14A8100 > dump;cat dump");
ret = ERR_VDEC_SYS_NOTREADY;
}
//alogd("debug g2d[0x%x]: virAddr[0x%x][0x%x], phyAddr[0x%x][0x%x], size[%dx%d]", pVideoDecData->mG2DHandle,
// pDst->pData0, pDst->pData1, pDst->phyYBufAddr, pDst->phyCBufAddr,
// pDst->nWidth, pDst->nHeight);
//memset(pDes->VFrame.mpVirAddr[0], 0xff, pDes->VFrame.mWidth * pDes->VFrame.mHeight);
//memset(pDes->VFrame.mpVirAddr[1], 0xff, pDes->VFrame.mWidth * pDes->VFrame.mHeight/2);
//memcpy(pDes->VFrame.mpVirAddr[0], pSrc->VFrame.mpVirAddr[0], pDes->VFrame.mWidth * pDes->VFrame.mHeight);
//memcpy(pDes->VFrame.mpVirAddr[1], pSrc->VFrame.mpVirAddr[1], pDes->VFrame.mWidth * pDes->VFrame.mHeight/2);
return ret;
#endif
}
static void *VideoDecCompFrameBufferThread(void *pThreadData)
{
unsigned int cmddata;
CompInternalMsgType cmd;
message_t cmd_msg;
VIDEODECDATATYPE *pVideoDecData = (VIDEODECDATATYPE *)pThreadData;
alogv("VideoDecoder CompFrameBufferThread start run...");
prctl(PR_SET_NAME, (unsigned long)"MPP_VDecCompFrameBuffer", 0, 0, 0);
while (1)
{
PROCESS_MESSAGE:
if (get_message(&pVideoDecData->mCompFrameBufferThreadMessageQueue, &cmd_msg) == 0)
{// pump message from message queue
cmd = cmd_msg.command;
cmddata = (unsigned int)cmd_msg.para0;
if (cmd == SetState)
{// State transition command
int SetStateRet = 0;
if (pVideoDecData->mCompFBThreadState == (COMP_STATETYPE)(cmddata))
{
alogd("comp FBThread same state[0x%x]", pVideoDecData->mCompFBThreadState);
}
else
{
// transitions/callbacks made based on state transition table
// cmddata contains the target state
switch ((COMP_STATETYPE)(cmddata))
{
case COMP_StateLoaded:
{
if (pVideoDecData->mCompFBThreadState != COMP_StateIdle)
{
aloge("fatal error! VDecCompFBThread incorrect state transition [0x%x]->Loaded!", pVideoDecData->mCompFBThreadState);
}
alogd("return all VDec used frames");
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
if (!list_empty(&pVideoDecData->mUsedOutFrameList))
{
int cnt = 0;
VDecCompOutputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoDecData->mUsedOutFrameList, mList)
{
int ret = ReturnPicture(pVideoDecData->pCedarV, (VideoPicture *)pEntry->mpPicture);
if (ret != 0)
{
aloge("fatal error! Return Picture() fail ret[%d]", ret);
}
list_move_tail(&pEntry->mList, &pVideoDecData->mIdleOutFrameList);
if (pVideoDecData->mWaitOutFrameFlag)
{
pVideoDecData->mWaitOutFrameFlag = FALSE;
message_t msg;
msg.command = VDecComp_OutFrameAvailable;
put_message(&pVideoDecData->cmd_queue, &msg);
}
cnt++;
}
alogd("VDec CompFBThread release [%d]used frames!", cnt);
if (pVideoDecData->mWaitOutFrameFullFlag)
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoDecData->mIdleOutFrameList) { cnt++; }
if (cnt >= pVideoDecData->mFrameNodeNum)
{
pthread_cond_signal(&pVideoDecData->mOutFrameFullCondition);
}
}
}
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
alogd("wait VDec CompIdleOutFrameList full");
pthread_mutex_lock(&pVideoDecData->mCompOutFramesLock);
pVideoDecData->mbCompFBThreadWaitOutFrameFull = TRUE;
//wait all outFrame return.
while (1)
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoDecData->mCompIdleOutFrameList) { cnt++; }
list_for_each(pList, &pVideoDecData->mCompReadyOutFrameList) { cnt++; }
if (cnt < VDEC_COMP_FRAME_COUNT)
{
alogd("wait CompIdleOutFrameList [%d]nodes to home", VDEC_COMP_FRAME_COUNT - cnt);
pthread_cond_wait(&pVideoDecData->mCompFBThreadOutFrameFullCondition, &pVideoDecData->mCompOutFramesLock);
}
else
{
break;
}
}
pVideoDecData->mbCompFBThreadWaitOutFrameFull = FALSE;
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
alogd("wait VDec CompIdleOutFrameList full done");
pthread_mutex_lock(&pVideoDecData->mCompFBThreadStateLock);
pVideoDecData->mCompFBThreadState = COMP_StateLoaded;
pthread_cond_signal(&pVideoDecData->mCondCompFBThreadState);
pthread_mutex_unlock(&pVideoDecData->mCompFBThreadStateLock);
SetStateRet = 0;
break;
}
case COMP_StateIdle:
{
alogd("VDec CompFBThread state[0x%x]->Idle!", pVideoDecData->mCompFBThreadState);
pthread_mutex_lock(&pVideoDecData->mCompFBThreadStateLock);
pVideoDecData->mCompFBThreadState = COMP_StateIdle;
pthread_cond_signal(&pVideoDecData->mCondCompFBThreadState);
pthread_mutex_unlock(&pVideoDecData->mCompFBThreadStateLock);
SetStateRet = 0;
break;
}
case COMP_StateExecuting:
{
// Transition can only happen from pause or idle state
if (pVideoDecData->mCompFBThreadState == COMP_StateIdle ||
pVideoDecData->mCompFBThreadState == COMP_StatePause)
{
pthread_mutex_lock(&pVideoDecData->mCompFBThreadStateLock);
pVideoDecData->mCompFBThreadState = COMP_StateExecuting;
pthread_cond_signal(&pVideoDecData->mCondCompFBThreadState);
pthread_mutex_unlock(&pVideoDecData->mCompFBThreadStateLock);
SetStateRet = 0;
}
else
{
aloge("fatal error! wrong state[0x%x]->executing", pVideoDecData->mCompFBThreadState);
SetStateRet = -1;
}
break;
}
case COMP_StatePause:
{
if (pVideoDecData->mCompFBThreadState == COMP_StateIdle ||
pVideoDecData->mCompFBThreadState == COMP_StateExecuting)
{
pthread_mutex_lock(&pVideoDecData->mCompFBThreadStateLock);
pVideoDecData->mCompFBThreadState = COMP_StatePause;
pthread_cond_signal(&pVideoDecData->mCondCompFBThreadState);
pthread_mutex_unlock(&pVideoDecData->mCompFBThreadStateLock);
SetStateRet = 0;
}
else
{
aloge("fatal error! wrong state[0x%x]->executing", pVideoDecData->mCompFBThreadState);
SetStateRet = -1;
}
break;
}
default:
{
aloge("fatal error! wrong dst state[0x%x]", cmddata);
SetStateRet = -1;
break;
}
}
}
if(cmd_msg.pReply)
{
cmd_msg.pReply->ReplyResult = SetStateRet;
cdx_sem_up(&cmd_msg.pReply->ReplySem);
}
}
else if (cmd == Stop)
{
// Kill thread
goto EXIT;
}
else if (cmd == VDecComp_CompFrameBufferThread_InputFrameAvailable)
{
alogv("VDec CompFBThread input frame available");
}
else if (cmd == VDecComp_CompFrameBufferThread_OutFrameAvailable)
{
alogv("VDec CompFBThread out frame available");
}
//precede to process message
goto PROCESS_MESSAGE;
}
if (!pVideoDecData->mbUseCompFrame)
{
aloge("fatal error! useCompFrame is false");
TMessage_WaitQueueNotEmpty(&pVideoDecData->mCompFrameBufferThreadMessageQueue, 0);
goto PROCESS_MESSAGE;
}
if (pVideoDecData->mCompFBThreadState == COMP_StateExecuting)
{
ERRORTYPE ret;
VDecCompOutputFrame *pInputFrame;
VDecCompOutputFrame *pOutputFrame;
//confirm inputFrame exist
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
if (list_empty(&pVideoDecData->mUsedOutFrameList))
{
pVideoDecData->mbCompFBThreadWaitVdecFrameInput = TRUE;
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
TMessage_WaitQueueNotEmpty(&pVideoDecData->mCompFrameBufferThreadMessageQueue, 0);
goto PROCESS_MESSAGE;
}
pInputFrame = list_first_entry(&pVideoDecData->mUsedOutFrameList, VDecCompOutputFrame, mList);
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
//confirm CompIdleOutFrame exist
pthread_mutex_lock(&pVideoDecData->mCompOutFramesLock);
if (list_empty(&pVideoDecData->mCompIdleOutFrameList))
{
pVideoDecData->mbCompFBThreadWaitOutFrame = TRUE;
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
TMessage_WaitQueueNotEmpty(&pVideoDecData->mCompFrameBufferThreadMessageQueue, 0);
goto PROCESS_MESSAGE;
}
pOutputFrame = list_first_entry(&pVideoDecData->mCompIdleOutFrameList, VDecCompOutputFrame, mList);
if (NULL == pOutputFrame->mpPicture)
{
alogd("need init compFrame!");
ret = CompFrameInit(pOutputFrame, pInputFrame->mpPicture, pVideoDecData->cedarv_rotation);
if(ret != SUCCESS)
{
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
goto _SelfFrameErr0;
}
}
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
//rotate to output frame
VideoDecRotateFrame(pInputFrame->mpPicture, pOutputFrame->mpPicture, pVideoDecData);
setCompVideoPictureInfo(pOutputFrame->mpPicture, pInputFrame->mpPicture);
//return input frame to vdeclib
VideoDecReturnVDecCompOutputFrameToIdleList(pVideoDecData, pInputFrame->mpPicture->nID);
//send output frame
if (pVideoDecData->mOutputPortTunnelFlag)
{
pthread_mutex_lock(&pVideoDecData->mCompOutFramesLock);
list_move_tail(&pOutputFrame->mList, &pVideoDecData->mCompUsedOutFrameList);
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
COMP_BUFFERHEADERTYPE obh;
obh.nOutputPortIndex = pVideoDecData->sOutPortTunnelInfo.nPortIndex;
obh.nInputPortIndex = pVideoDecData->sOutPortTunnelInfo.nTunnelPortIndex;
VIDEO_FRAME_INFO_S stFrameInfo;
config_VIDEO_FRAME_INFO_S_by_VideoPicture(&stFrameInfo, pOutputFrame->mpPicture, pVideoDecData);
obh.pOutputPortPrivate = (void*)&stFrameInfo;
ERRORTYPE omxRet = COMP_EmptyThisBuffer(pVideoDecData->sOutPortTunnelInfo.hTunnel, &obh);
if (SUCCESS == omxRet)
{
}
else
{
int commonErrCode = omxRet&0x1FFF;
if (EN_ERR_INCORRECT_STATE_OPERATION == commonErrCode)
{
alogd("Be careful! VDec output frame fail[0x%x], maybe next component status is Loaded, return frame!", omxRet);
}
else if(EN_ERR_SYS_NOTREADY == commonErrCode)
{
alogv("frame is ignored.");
}
else
{
aloge("fatal error! errCode[0x%x]", omxRet);
}
pthread_mutex_lock(&pVideoDecData->mCompOutFramesLock);
list_move(&pOutputFrame->mList, &pVideoDecData->mCompIdleOutFrameList);
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
}
}
else
{
pthread_mutex_lock(&pVideoDecData->mCompOutFramesLock);
list_move_tail(&pOutputFrame->mList, &pVideoDecData->mCompReadyOutFrameList);
if (pVideoDecData->mbCompWaitReadyFrame)
{
pthread_cond_signal(&pVideoDecData->mCompReadyFrameCondition);
}
pthread_mutex_unlock(&pVideoDecData->mCompOutFramesLock);
}
goto PROCESS_MESSAGE;
_SelfFrameErr0:
//return all frames
pthread_mutex_lock(&pVideoDecData->mOutFrameListMutex);
if(!list_empty(&pVideoDecData->mUsedOutFrameList))
{
VDecCompOutputFrame *pEntry;
list_for_each_entry(pEntry, &pVideoDecData->mUsedOutFrameList, mList)
{
int releaseRet = ReturnPicture(pVideoDecData->pCedarV, (VideoPicture *)pEntry->mpPicture);
if (releaseRet != 0)
{
aloge("fatal error! Return Picture() fail ret[%d]", releaseRet);
}
}
list_splice_tail_init(&pVideoDecData->mUsedOutFrameList, &pVideoDecData->mIdleOutFrameList);
}
pthread_mutex_unlock(&pVideoDecData->mOutFrameListMutex);
goto PROCESS_MESSAGE;
}
else
{
TMessage_WaitQueueNotEmpty(&pVideoDecData->mCompFrameBufferThreadMessageQueue, 0);
}
}
EXIT:
alogv("VideoDec CompFrameBufferThread stopped");
return (void *)SUCCESS;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */