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

2641 lines
116 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. --
-- --
*******************************************************************************/
//#define LOG_NDEBUG 0
#define LOG_TAG "VideoRender_Component"
#include <utils/plat_log.h>
//#include <threads.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/prctl.h>
#include <mm_component.h>
//#include <CDX_FormatConvert.h>
#include <SystemBase.h>
#include <VIDEO_FRAME_INFO_S.h>
#include <tmessage.h>
#include <tsemaphore.h>
#include <video_render.h>
//#include <cdx_math.h>
#include <vdecoder.h>
#include <vencoder.h>
#include <CDX_ErrorType.h>
#include <cutils/properties.h>
#include <VdecCompStream.h>
#include "VideoRender_Component.h"
#include <mpi_videoformat_conversion.h>
#include <plat_systrace.h>
#include <cdx_list.h>
//#include <ConfigOption.h>
//----------------------------------------------------------------------------
#define MAX_VDRENDER_PORTS 2
typedef enum VIDEORENDER_PORT_SUFFIX_DEFINITION{
VDR_PORT_SUFFIX_CLOCK = 0,
VDR_PORT_SUFFIX_VIDEO = 1,
}VIDEORENDER_PORT_SUFFIX_DEFINITION;
#define VIDEO_RENDER_FIRST_FRAME_FLAG 1
static void* VideoRender_ComponentThread(void* pThreadData);
typedef struct
{
ANativeWindowBufferCedarXWrapper mANWBuffer;
struct list_head mList;
} VRANWBuffer;
typedef struct VOCompInputFrame
{
VIDEO_FRAME_INFO_S mFrameInfo;
struct list_head mList;
}VOCompInputFrame;
typedef struct VIDEORENDERDATATYPE {
COMP_STATETYPE state;
pthread_mutex_t mStateMutex;
COMP_CALLBACKTYPE *pCallbacks;
void* pAppData;
COMP_HANDLETYPE hSelf;
char mThreadName[32];
COMP_PORT_PARAM_TYPE sPortParam;
COMP_PARAM_PORTDEFINITIONTYPE sInPortDef[MAX_VDRENDER_PORTS];
COMP_INTERNAL_TUNNELINFOTYPE sInPortTunnelInfo[MAX_VDRENDER_PORTS];
COMP_PARAM_BUFFERSUPPLIERTYPE sPortBufSupplier[MAX_VDRENDER_PORTS];
BOOL mInputPortTunnelFlags[MAX_VDRENDER_PORTS];
BOOL mOutputPortTunnelFlag; //TRUE: tunnel mode; FALSE: non-tunnel mode.
MPP_CHN_S mMppChnInfo;
VO_CHN_ATTR_S mChnAttr;
pthread_t thread_id;
CompInternalMsgType eTCmd;
message_queue_t cmd_queue;
BOOL start_to_play;
int wait_time_out;
BOOL is_ref_clock;
int video_rend_flag; //VIDEO_RENDER_FIRST_FRAME_FLAG
BOOL mbRenderingStart;
volatile int priv_flag;
char av_sync;
int64_t last_pts; //last render frame pts, unit:us
CDX_VideoRenderHAL *hnd_cdx_video_render;
int hnd_cdx_video_render_init_flag;
BOOL mbShowPicFlag; //should show picture.
ANativeWindowBufferCedarXWrapper mANativeWindowBuffer;
BOOL mResolutionChangeFlag;
int render_seeking_flag;
VideoRenderMode VRenderMode; //cedarv_output_setting=CEDARX_OUTPUT_SETTING_MODE_PLANNER
struct list_head mVideoInputFrameIdleList; // VOCompInputFrame
struct list_head mVideoInputFrameReadyList;
struct list_head mVideoInputFrameUsedList;
BOOL mWaitInputFrameFlag; //1: no input frame, wait!
pthread_mutex_t mVideoInputFrameListMutex;
unsigned int mDispBufNum; //cache display frameBuf number. scope:[0],[2,15]
int mVideoDisplayTopX; //record vdec frame displayTopX and displayTopY
int mVideoDisplayTopY;
int mVideoDisplayWidth; //record vdec frame display_width and display_height
int mVideoDisplayHeight;
BOOL bUserFlag;
RECT_S mUserRegion;
pthread_mutex_t mUserRegionMutex;
BOOL mbNeedNotifyDisplaySize;
int mDispFrameRate; //0:not limit.
int64_t mPlayFrameInterval; //indicate two frame's interval which be used to display. unit:us
int64_t mLastRenderFramePts; //last inFrame's pts, unit:us
int mStoreFrameCnt;
struct list_head mANWBuffersList; //VRANWBuffer, for VideoRender_GUI mode
//int subDelay; //unit:ms
}VIDEORENDERDATATYPE;
static int convertColorPrimary2ColorSpace(int nColorPrimary)
{
int cdxColorSpace;
int nVideoFullRange = (nColorPrimary >> 8) & 0xFF;
switch(nVideoFullRange)
{
case 0x0:
cdxColorSpace = VENC_BT601;
break;
case 0x1:
cdxColorSpace = VENC_YCC;
break;
default:
aloge("fatal error! unknown video full range[%d]", nVideoFullRange);
cdxColorSpace = VENC_YCC;
break;
}
return cdxColorSpace;
}
ERRORTYPE PropertyGet_PlayFrameInterval(int64_t *pInterval)
{
alogv("play frame interval use 40fps as default");
*pInterval = 1000000/40;
//return ERR_VO_NOT_SUPPORT;
return SUCCESS;
/*
char prop_value[PROPERTY_VALUE_MAX];
int len = property_get(PROP_KEY_PLAY_FRAME_INTERVAL, prop_value, NULL);
if(len <= 0)
{
alogd("key[%s] is not find", PROP_KEY_PLAY_FRAME_INTERVAL);
return ERR_VO_NOT_SUPPORT;
}
alogd("key[%s] value[%s]ms", PROP_KEY_PLAY_FRAME_INTERVAL, prop_value);
*pInterval = (int64_t)atoi(prop_value)*1000;
return SUCCESS;
*/
}
ERRORTYPE VideoRenderAddFrame_l(
PARAM_IN VIDEORENDERDATATYPE *pVideoRenderData,
PARAM_IN VIDEO_FRAME_INFO_S* pInFrame)
{
VOCompInputFrame *pNode;
if(list_empty(&pVideoRenderData->mVideoInputFrameIdleList))
{
alogw("input frame list is empty, increase one");
// return error if there is no more memory
pNode = (VOCompInputFrame*)malloc(sizeof(VOCompInputFrame));
if(NULL == pNode)
{
aloge("fatal error! malloc fail!");
return ERR_VO_NO_MEM;
}
memset(pNode, 0, sizeof(VOCompInputFrame));
list_add_tail(&pNode->mList, &pVideoRenderData->mVideoInputFrameIdleList);
}
pNode = list_first_entry(&pVideoRenderData->mVideoInputFrameIdleList, VOCompInputFrame, mList);
memcpy(&pNode->mFrameInfo, pInFrame, sizeof(VIDEO_FRAME_INFO_S));
list_move_tail(&pNode->mList, &pVideoRenderData->mVideoInputFrameReadyList);
return SUCCESS;
}
ERRORTYPE VideoRenderReleaseFrame_l(
PARAM_IN VIDEORENDERDATATYPE *pVideoRenderData,
PARAM_IN VOCompInputFrame* pFrame)
{
ERRORTYPE omxRet = SUCCESS;
VOCompInputFrame *pEntry;
BOOL bFindFlag = FALSE;
list_for_each_entry(pEntry, &pVideoRenderData->mVideoInputFrameUsedList, mList)
{
if(pEntry == pFrame)
{
bFindFlag = TRUE;
break;
}
}
if(FALSE == bFindFlag)
{
list_for_each_entry(pEntry, &pVideoRenderData->mVideoInputFrameReadyList, mList)
{
if(pEntry == pFrame)
{
bFindFlag = TRUE;
break;
}
}
}
if(bFindFlag)
{
if(pVideoRenderData->mInputPortTunnelFlags[VDR_PORT_SUFFIX_VIDEO])
{
COMP_BUFFERHEADERTYPE obh;
obh.nOutputPortIndex = pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_VIDEO].nTunnelPortIndex;
obh.nInputPortIndex = pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_VIDEO].nPortIndex;
obh.pOutputPortPrivate = (void*)&pEntry->mFrameInfo;
omxRet = COMP_FillThisBuffer(pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_VIDEO].hTunnel, &obh);
if(omxRet != SUCCESS)
{
aloge("fatal error! fill this buffer fail[0x%x], nId=[%d], check code!", omxRet, pFrame->mFrameInfo.mId);
}
else
{
list_move_tail(&pEntry->mList, &pVideoRenderData->mVideoInputFrameIdleList);
}
}
else
{
COMP_BUFFERHEADERTYPE obh;
obh.pAppPrivate = (void*)&pEntry->mFrameInfo;
pVideoRenderData->pCallbacks->EmptyBufferDone(
pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
&obh);
list_move_tail(&pEntry->mList, &pVideoRenderData->mVideoInputFrameIdleList);
}
}
else
{
aloge("fatal error! not find pFrame[%p], pictureId[%d] in used list.", pFrame, pFrame->mFrameInfo.mId);
omxRet = ERR_VO_ILLEGAL_PARAM;
}
return omxRet;
}
ERRORTYPE VideoRenderReleaseFrame(
PARAM_IN VIDEORENDERDATATYPE *pVideoRenderData,
PARAM_IN VOCompInputFrame* pFrame)
{
ERRORTYPE eError;
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
eError = VideoRenderReleaseFrame_l(pVideoRenderData, pFrame);
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
return eError;
}
/*******************************************************************************
Function name: VideoRenderANWBufferComeBack
Description:
find in pVideoRenderData->mANWBuffersList, and config it, mbOccupyFlag=1,
Parameters:
Return:
Time: 2015/9/12
*******************************************************************************/
ANativeWindowBufferCedarXWrapper* VideoRenderANWBufferComeBack(VIDEORENDERDATATYPE *pVideoRenderData, ANativeWindowBufferCedarXWrapper *pANWB)
{
if(list_empty(&pVideoRenderData->mANWBuffersList))
{
aloge("fatal error! ANWBuffersList is empty!");
return NULL;
}
int num = 0;
VRANWBuffer *pEntry;
ANativeWindowBufferCedarXWrapper *pANWBuf = NULL;
list_for_each_entry(pEntry, &pVideoRenderData->mANWBuffersList, mList)
{
if(pEntry->mANWBuffer.dst == pANWB->dst)
{
if(pEntry->mANWBuffer.width == pANWB->width
&& pEntry->mANWBuffer.height == pANWB->height
&& pEntry->mANWBuffer.stride == pANWB->stride
&& pEntry->mANWBuffer.format == pANWB->format
&& pEntry->mANWBuffer.usage == pANWB->usage
//&& pEntry->mANWBuffer.dstPhy == pANWB->dstPhy
&& pEntry->mANWBuffer.pObjANativeWindowBuffer == pANWB->pObjANativeWindowBuffer
//&& pEntry->mANWBuffer.mIonUserHandle == pANWB->mIonUserHandle
)
{
}
else
{
aloge("fatal error! ANativeWindowBufferCedarXWrapper not match:\n"
"[%dx%d][%d][0x%x][0x%x][%p][%p][%p][%d]\n"
"[%dx%d][%d][0x%x][0x%x][%p][%p][%p][%d]\n",
pEntry->mANWBuffer.width, pEntry->mANWBuffer.height, pEntry->mANWBuffer.stride,
pEntry->mANWBuffer.format, pEntry->mANWBuffer.usage,
pEntry->mANWBuffer.dst, pEntry->mANWBuffer.dstPhy,
pEntry->mANWBuffer.pObjANativeWindowBuffer, pEntry->mANWBuffer.mIonUserHandle,
pANWB->width, pANWB->height, pANWB->stride,
pANWB->format, pANWB->usage,
pANWB->dst, pANWB->dstPhy,
pANWB->pObjANativeWindowBuffer, pANWB->mIonUserHandle);
if(pEntry->mANWBuffer.pObjANativeWindowBuffer != pANWB->pObjANativeWindowBuffer)
{
pEntry->mANWBuffer.pObjANativeWindowBuffer = pANWB->pObjANativeWindowBuffer;
}
}
if(0 == pEntry->mANWBuffer.mbOccupyFlag)
{
pEntry->mANWBuffer.mbOccupyFlag = 1;
}
else
{
aloge("fatal error! why this ANWB dst[%p] is not goto GUI?", pEntry->mANWBuffer.dst);
}
if(0 == num)
{
pANWBuf = &pEntry->mANWBuffer;
num++;
}
else
{
aloge("fatal error! more AndroidNativeWindowBuffer has buffer[%p]!", pEntry->mANWBuffer.dst);
num++;
}
}
}
return pANWBuf;
}
VOCompInputFrame* VideoRenderFindUsedFrameByANWBuffer(VIDEORENDERDATATYPE *pVideoRenderData, ANativeWindowBufferCedarXWrapper *pANWB)
{
ERRORTYPE omxRet = SUCCESS;
VOCompInputFrame *pEntry;
BOOL bFindFlag = FALSE;
list_for_each_entry(pEntry, &pVideoRenderData->mVideoInputFrameUsedList, mList)
{
if(pEntry->mFrameInfo.VFrame.mpVirAddr[0] == pANWB->dst)
{
bFindFlag = TRUE;
break;
}
}
if(bFindFlag)
{
return pEntry;
}
else
{
aloge("fatal error! not find frame[%p] in used list.", pANWB->dst);
return NULL;
}
}
static ANativeWindowBufferCedarXWrapper* VideoRenderFindANWBufferByFrame(VIDEORENDERDATATYPE* pVideoRenderData, VOCompInputFrame *pFrame)
{
if(list_empty(&pVideoRenderData->mANWBuffersList))
{
aloge("fatal error! ANWBuffersList is empty!");
return NULL;
}
int num = 0;
VRANWBuffer *pEntry;
ANativeWindowBufferCedarXWrapper *pANWBuf = NULL;
list_for_each_entry(pEntry, &pVideoRenderData->mANWBuffersList, mList)
{
if(pEntry->mANWBuffer.dst == (void*)pFrame->mFrameInfo.VFrame.mpVirAddr[0])
{
if(0 == num)
{
pANWBuf = &pEntry->mANWBuffer;
num++;
}
else
{
aloge("fatal error! more AndroidNativeWindowBuffer has buffer[%p]!", pEntry->mANWBuffer.dst);
num++;
}
}
}
return pANWBuf;
}
static ERRORTYPE VideoRenderDestroyANWBuffersInfo(VIDEORENDERDATATYPE *pVideoRenderData)
{
if(list_empty(&pVideoRenderData->mANWBuffersList))
{
return SUCCESS;
}
int ret;
//cancel frame to gpu
VRANWBuffer *pEntry, *pTmp;
ANativeWindowBufferCedarXWrapper *pANWBuf = NULL;
list_for_each_entry(pEntry, &pVideoRenderData->mANWBuffersList, mList)
{
if(pEntry->mANWBuffer.mbOccupyFlag)
{
ret = pVideoRenderData->hnd_cdx_video_render->cancel_frame(pVideoRenderData->hnd_cdx_video_render, &pEntry->mANWBuffer);
if(SUCCESS == ret)
{
pEntry->mANWBuffer.mbOccupyFlag = 0;
}
else
{
alogw("fatal error! CancelFrame fail[%d]", ret);
}
}
}
//free list
list_for_each_entry_safe(pEntry, pTmp, &pVideoRenderData->mANWBuffersList, mList)
{
list_del(&pEntry->mList);
free(pEntry);
}
return SUCCESS;
}
static ERRORTYPE VideoRenderCreateANWBuffersInfo(VIDEORENDERDATATYPE *pVideoRenderData, CdxANWBuffersInfo *pANWBuffersInfo)
{
int i;
VRANWBuffer *pBuf;
if(!list_empty(&pVideoRenderData->mANWBuffersList))
{
aloge("fatal error! why ANWBuffersList is not empty!");
}
for(i=0; i<pANWBuffersInfo->mnBufNum; i++)
{
pBuf = (VRANWBuffer*)malloc(sizeof(VRANWBuffer));
if(NULL == pBuf)
{
aloge("fatal error! malloc fail!");
return ERR_VO_NO_MEM;
}
memset(pBuf, 0, sizeof(VRANWBuffer));
memcpy(&pBuf->mANWBuffer, &pANWBuffersInfo->mANWBuffers[i], sizeof(ANativeWindowBufferCedarXWrapper));
list_add_tail(&pBuf->mList, &pVideoRenderData->mANWBuffersList);
}
return SUCCESS;
}
ERRORTYPE VideoRenderGetMPPChannelInfo(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT MPP_CHN_S *pChn)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
copy_MPP_CHN_S(pChn, &pVideoRenderData->mMppChnInfo);
return eError;
}
ERRORTYPE VideoRenderSetMPPChannelInfo(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN MPP_CHN_S *pChn)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
copy_MPP_CHN_S(&pVideoRenderData->mMppChnInfo, pChn);
return SUCCESS;
}
ERRORTYPE VideoRenderSetChnAttr(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN VO_CHN_ATTR_S *pChnAttr)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
memcpy(&pVideoRenderData->mChnAttr, pChnAttr, sizeof(VO_CHN_ATTR_S));
return eError;
}
ERRORTYPE VideoRenderGetChnAttr(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT VO_CHN_ATTR_S* pChnAttr)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
memcpy(pChnAttr, &pVideoRenderData->mChnAttr, sizeof(VO_CHN_ATTR_S));
return SUCCESS;
}
ERRORTYPE VideoRenderSetDisplayRegion(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN RECT_S *pRectAttr)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
pthread_mutex_lock(&pVideoRenderData->mUserRegionMutex);
pVideoRenderData->mUserRegion.X = pRectAttr->X;
pVideoRenderData->mUserRegion.Y = pRectAttr->Y;
pVideoRenderData->mUserRegion.Width = pRectAttr->Width;
pVideoRenderData->mUserRegion.Height = pRectAttr->Height;
pthread_mutex_unlock(&pVideoRenderData->mUserRegionMutex);
return SUCCESS;
}
ERRORTYPE VideoRenderGetDisplayRegion(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT RECT_S *pRectAttr)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
pRectAttr->X = pVideoRenderData->mUserRegion.X;
pRectAttr->Y = pVideoRenderData->mUserRegion.Y;
pRectAttr->Width = pVideoRenderData->mUserRegion.Width;
pRectAttr->Height = pVideoRenderData->mUserRegion.Height;
return SUCCESS;
}
ERRORTYPE VideoRenderGetDisplaySize(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT SIZE_S *pDisplaySize)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
pDisplaySize->Width = pVideoRenderData->mVideoDisplayWidth;
pDisplaySize->Height = pVideoRenderData->mVideoDisplayHeight;
return eError;
}
ERRORTYPE VideoRenderSetDispBufNum(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT unsigned int nDispBufNum)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
pVideoRenderData->mDispBufNum = nDispBufNum;
return eError;
}
ERRORTYPE VideoRenderSetDispFrameRate(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN int nDispFrameRate)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
pVideoRenderData->mDispFrameRate = nDispFrameRate;
pVideoRenderData->mPlayFrameInterval = (int64_t)1000000/pVideoRenderData->mDispFrameRate;
return SUCCESS;
}
ERRORTYPE VideoRenderGetDispFrameRate(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN int *pDispFrameRate)
{
ERRORTYPE eError = SUCCESS;
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if(pDispFrameRate)
{
*pDispFrameRate = pVideoRenderData->mDispFrameRate;
}
else
{
eError = ERR_VO_NULL_PTR;
}
return eError;
}
ERRORTYPE VideoRenderGetDispBufNum(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT unsigned int *pDispBufNum)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
*pDispBufNum = pVideoRenderData->mDispBufNum;
return eError;
}
ERRORTYPE VideoRenderStoreFrame(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN uint64_t framePts)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
message_t msg;
memset(&msg, 0, sizeof(message_t));
msg.command = VRenderComp_StoreFrame;
msg.mpData = (void*)&framePts;
msg.mDataSize = sizeof(framePts);
putMessageWithData(&pVideoRenderData->cmd_queue, &msg);
return eError;
}
ERRORTYPE VideoRenderGetPortDefinition(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_INOUT COMP_PARAM_PORTDEFINITIONTYPE *pPortDef)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
int i;
ERRORTYPE eError = SUCCESS;
for(i=0; i<pVideoRenderData->sPortParam.nPorts; i++)
{
if(pPortDef->nPortIndex == pVideoRenderData->sInPortDef[i].nPortIndex)
{
memcpy(pPortDef, &pVideoRenderData->sInPortDef[i], sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
}
}
if(i == pVideoRenderData->sPortParam.nPorts)
{
eError = ERR_VO_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE VideoRenderGetCompBufferSupplier(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_INOUT COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
//find nPortIndex
BOOL bFindFlag = FALSE;
int i;
for(i=0; i<MAX_VDRENDER_PORTS; i++)
{
if(pVideoRenderData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex)
{
bFindFlag = TRUE;
memcpy(pPortBufSupplier, &pVideoRenderData->sPortBufSupplier[i], sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE));
break;
}
}
if(bFindFlag)
{
eError = SUCCESS;
}
else
{
eError = ERR_VO_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE VideoRenderGetPortParam(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT COMP_PORT_PARAM_TYPE *pPortParam)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
memcpy(pPortParam, &pVideoRenderData->sPortParam, sizeof(COMP_PORT_PARAM_TYPE));
return SUCCESS;
}
ERRORTYPE VideoRenderGetTimeCurrentMediaTime(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT COMP_TIME_CONFIG_TIMESTAMPTYPE *pComponentConfigStructure)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
COMP_TIME_CONFIG_TIMESTAMPTYPE *timestamp = (COMP_TIME_CONFIG_TIMESTAMPTYPE*)pComponentConfigStructure;
timestamp->nTimestamp = pVideoRenderData->last_pts;
return SUCCESS;
}
ERRORTYPE VideoRenderSetPortDefinition(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_PARAM_PORTDEFINITIONTYPE *pPortDef)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
int i;
ERRORTYPE eError = SUCCESS;
for(i=0; i<pVideoRenderData->sPortParam.nPorts; i++)
{
if(pPortDef->nPortIndex == pVideoRenderData->sInPortDef[i].nPortIndex)
{
memcpy(&pVideoRenderData->sInPortDef[i], pPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
break;
}
}
if(i == pVideoRenderData->sPortParam.nPorts)
{
eError = ERR_VO_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE VideoRenderSetCompBufferSupplier(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError;
//find nPortIndex
BOOL bFindFlag = FALSE;
int i;
for(i=0; i<MAX_VDRENDER_PORTS; i++)
{
if(pVideoRenderData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex)
{
bFindFlag = TRUE;
memcpy(&pVideoRenderData->sPortBufSupplier[i], pPortBufSupplier, sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE));
break;
}
}
if(bFindFlag)
{
eError = SUCCESS;
}
else
{
eError = ERR_VO_ILLEGAL_PARAM;
}
return eError;
}
ERRORTYPE VideoRenderSetTimeActiveRefClock(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_TIME_CONFIG_ACTIVEREFCLOCKTYPE *pRefClock)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
if(pRefClock->eClock == COMP_TIME_RefClockVideo)
{
pVideoRenderData->is_ref_clock = TRUE;
}
else
{
aloge("fatal error! check RefClock[0x%x]", pRefClock->eClock);
pVideoRenderData->is_ref_clock = FALSE;
}
return eError;
}
ERRORTYPE VideoRenderSeek(PARAM_IN COMP_HANDLETYPE hComponent)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
pVideoRenderData->render_seeking_flag = 1;
//keep used frames, return other frames. vdeclib permit return frame out-of-order.
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoRenderData->mVideoInputFrameUsedList)
{
cnt++;
}
if(cnt > 2)
{
aloge("fatal error! why VR_HW used frame[%d]>2? check code!", cnt);
}
VOCompInputFrame *pEntry, *pTmp;
COMP_BUFFERHEADERTYPE obh;
ERRORTYPE omxRet;
cnt = 0;
list_for_each_entry_safe(pEntry, pTmp, &pVideoRenderData->mVideoInputFrameReadyList, mList)
{
VideoRenderReleaseFrame_l(pVideoRenderData, pEntry);
cnt++;
}
alogd("VR seek, release [%d]input video Frame!", cnt);
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
return eError;
}
ERRORTYPE VideoRenderSwitchAudio(PARAM_IN COMP_HANDLETYPE hComponent)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
alogd("need start to play again after switch audio!");
pVideoRenderData->render_seeking_flag = 1;
return eError;
}
ERRORTYPE VideoRenderSetStreamEof(PARAM_IN COMP_HANDLETYPE hComponent)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
alogv("videoRender end flag is set");
pVideoRenderData->priv_flag |= CDX_comp_PRIV_FLAGS_STREAMEOF;
message_t msg;
msg.command = VRenderComp_InputFrameAvailable;
put_message(&pVideoRenderData->cmd_queue, &msg);
return eError;
}
ERRORTYPE VideoRenderClearStreamEof(PARAM_IN COMP_HANDLETYPE hComponent)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
pVideoRenderData->priv_flag &= ~CDX_comp_PRIV_FLAGS_STREAMEOF;
return eError;
}
ERRORTYPE VideoRenderShow(PARAM_IN COMP_HANDLETYPE hComponent, BOOL bShowFlag)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
if(pVideoRenderData->mbShowPicFlag == bShowFlag)
{
alogd("vo already [%s]", bShowFlag?"show":"hide");
return eError;
}
pVideoRenderData->mbShowPicFlag = bShowFlag;
if(pVideoRenderData->hnd_cdx_video_render_init_flag)
{
pVideoRenderData->hnd_cdx_video_render->set_showflag(pVideoRenderData->hnd_cdx_video_render, bShowFlag);
}
return eError;
}
ERRORTYPE VideoRenderInitVideoRenderHAL(PARAM_IN COMP_HANDLETYPE hComponent, void *callback_info)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
pVideoRenderData->hnd_cdx_video_render = cedarx_video_render_create(callback_info);
return eError;
}
ERRORTYPE VideoRenderSetAVSync(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN char avSyncFlag)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
pVideoRenderData->av_sync = avSyncFlag;
return eError;
}
ERRORTYPE VideoRenderSetVRenderMode(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN VideoRenderMode mode)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
pVideoRenderData->VRenderMode = mode;
alogd("CDX use VideoRenderMode = %d", pVideoRenderData->VRenderMode);
return eError;
}
ERRORTYPE VideoRenderNotifyStartToRun(PARAM_IN COMP_HANDLETYPE hComponent)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
pVideoRenderData->start_to_play = TRUE;
return eError;
}
ERRORTYPE VideoRenderResolutionChange(PARAM_IN COMP_HANDLETYPE hComponent)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
message_t msg;
msg.command = VRenderComp_ResolutionChange;
put_message(&pVideoRenderData->cmd_queue, &msg);
return eError;
}
ERRORTYPE VideoRenderSendCommand(PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_COMMANDTYPE Cmd, PARAM_IN unsigned int nParam1,
PARAM_IN void* pCmdData) {
VIDEORENDERDATATYPE *pVideoRenderData;
CompInternalMsgType eCmd;
ERRORTYPE eError = SUCCESS;
message_t msg;
pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if (pVideoRenderData->state == COMP_StateInvalid)
{
eError = ERR_VO_CHN_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_CommandMarkBuffer:
eCmd = MarkBuf;
if (nParam1 > 0)
{
eError = ERR_VO_ILLEGAL_PARAM;
goto OMX_CONF_CMD_BAIL;
}
break;
case COMP_CommandVendorChangeANativeWindow:
eCmd = VRenderComp_ChangeANativeWindow;
break;
default:
eCmd = -1;
break;
}
msg.command = eCmd;
msg.para0 = nParam1;
put_message(&pVideoRenderData->cmd_queue, &msg);
OMX_CONF_CMD_BAIL: return eError;
}
/*****************************************************************************/
ERRORTYPE VideoRenderGetState(PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_OUT COMP_STATETYPE* pState) {
VIDEORENDERDATATYPE *pVideoRenderData;
ERRORTYPE eError = SUCCESS;
pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
*pState = pVideoRenderData->state;
OMX_CONF_CMD_BAIL: return eError;
}
/*****************************************************************************/
ERRORTYPE VideoRenderSetCallbacks(PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_CALLBACKTYPE* pCallbacks, PARAM_IN void* pAppData) {
VIDEORENDERDATATYPE *pVideoRenderData;
ERRORTYPE eError = SUCCESS;
pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
pVideoRenderData->pCallbacks = pCallbacks;
pVideoRenderData->pAppData = pAppData;
OMX_CONF_CMD_BAIL: return eError;
}
ERRORTYPE VideoRenderGetConfig(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_INDEXTYPE nIndex,
PARAM_INOUT void* pComponentConfigStructure)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
if (pVideoRenderData->state == COMP_StateInvalid)
{
eError = ERR_VO_CHN_INCORRECT_STATE_OPERATION;
goto OMX_CONF_CMD_BAIL;
}
switch (nIndex)
{
case COMP_IndexParamPortDefinition:
{
eError = VideoRenderGetPortDefinition(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexParamCompBufferSupplier:
{
eError = VideoRenderGetCompBufferSupplier(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorGetPortParam:
{
eError = VideoRenderGetPortParam(hComponent, (COMP_PORT_PARAM_TYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexConfigTimeCurrentMediaTime:
{
eError = VideoRenderGetTimeCurrentMediaTime(hComponent, (COMP_TIME_CONFIG_TIMESTAMPTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorMPPChannelInfo:
{
eError = VideoRenderGetMPPChannelInfo(hComponent, (MPP_CHN_S*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVOChnAttr:
{
eError = VideoRenderGetChnAttr(hComponent, (VO_CHN_ATTR_S*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorDisplayRegion:
{
eError = VideoRenderGetDisplayRegion(hComponent, (RECT_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVOChnDisplaySize:
{
eError = VideoRenderGetDisplaySize(hComponent, (SIZE_S*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVODispBufNum:
{
eError = VideoRenderGetDispBufNum(hComponent, (unsigned int*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVOChnFrameRate:
{
eError = VideoRenderGetDispFrameRate(hComponent, (int*)pComponentConfigStructure);
break;
}
default:
aloge("fatal error! unknown index[0x%x]", nIndex);
eError = ERR_VO_ILLEGAL_PARAM;
break;
}
OMX_CONF_CMD_BAIL:
return eError;
}
ERRORTYPE VideoRenderSetConfig(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_INDEXTYPE nIndex,
PARAM_IN void* pComponentConfigStructure)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE*)((MM_COMPONENTTYPE*)hComponent)->pComponentPrivate;
ERRORTYPE eError = SUCCESS;
switch (nIndex)
{
case COMP_IndexParamPortDefinition:
{
eError = VideoRenderSetPortDefinition(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexParamCompBufferSupplier:
{
eError = VideoRenderSetCompBufferSupplier(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexConfigTimeActiveRefClock:
{
eError = VideoRenderSetTimeActiveRefClock(hComponent, (COMP_TIME_CONFIG_ACTIVEREFCLOCKTYPE*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorSeekToPosition:
{
eError = VideoRenderSeek(hComponent);
break;
}
case COMP_IndexVendorSwitchAudio:
{
eError = VideoRenderSwitchAudio(hComponent);
break;
}
case COMP_IndexVendorSetStreamEof:
{
eError = VideoRenderSetStreamEof(hComponent);
break;
}
case COMP_IndexVendorClearStreamEof:
{
eError = VideoRenderClearStreamEof(hComponent);
break;
}
case COMP_IndexVendorInitInstance:
{
eError = VideoRenderInitVideoRenderHAL(hComponent, pComponentConfigStructure);
break;
}
case COMP_IndexVendorSetAVSync:
{
eError = VideoRenderSetAVSync(hComponent, *(char*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVRenderMode:
{
eError = VideoRenderSetVRenderMode(hComponent, *(VideoRenderMode*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorNotifyStartToRun:
{
eError = VideoRenderNotifyStartToRun(hComponent);
break;
}
case COMP_IndexVendorResolutionChange:
{
eError = VideoRenderResolutionChange(hComponent);
break;
}
case COMP_IndexVendorMPPChannelInfo:
{
eError = VideoRenderSetMPPChannelInfo(hComponent, (MPP_CHN_S*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVOChnAttr:
{
eError = VideoRenderSetChnAttr(hComponent, (VO_CHN_ATTR_S*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorDisplayRegion:
{
eError = VideoRenderSetDisplayRegion(hComponent, (RECT_S *)pComponentConfigStructure);
break;
}
case COMP_IndexVendorShow:
{
eError = VideoRenderShow(hComponent, *(BOOL*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVODispBufNum:
{
eError = VideoRenderSetDispBufNum(hComponent, *(unsigned int*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorVOChnFrameRate:
{
eError = VideoRenderSetDispFrameRate(hComponent, *(int*)pComponentConfigStructure);
break;
}
case COMP_IndexVendorStoreFrame:
{
eError = VideoRenderStoreFrame(hComponent, *(uint64_t*)pComponentConfigStructure);
break;
}
default:
{
aloge("fatal error! unknown nIndex[0x%x] in state[%d]", nIndex, pVideoRenderData->state);
eError = ERR_VO_ILLEGAL_PARAM;
break;
}
}
return eError;
}
ERRORTYPE VideoRenderComponentTunnelRequest(
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;
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
if (pVideoRenderData->state == COMP_StateExecuting)
{
alogw("Be careful! tunnel request may be some danger in StateExecuting");
}
else if(pVideoRenderData->state != COMP_StateIdle)
{
aloge("fatal error! tunnel request can't be in state[0x%x]", pVideoRenderData->state);
eError = ERR_VO_CHN_INCORRECT_STATE_OPERATION;
goto COMP_CMD_FAIL;
}
COMP_PARAM_PORTDEFINITIONTYPE *pPortDef;
COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo;
COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier;
int nInPortSuffix = -1;
BOOL bFindFlag;
int i;
bFindFlag = FALSE;
for(i=0; i<MAX_VDRENDER_PORTS; i++)
{
if(pVideoRenderData->sInPortDef[i].nPortIndex == nPort)
{
pPortDef = &pVideoRenderData->sInPortDef[i];
bFindFlag = TRUE;
nInPortSuffix =i;
break;
}
}
if(FALSE == bFindFlag)
{
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_VO_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
bFindFlag = FALSE;
for(i=0; i<MAX_VDRENDER_PORTS; i++)
{
if(pVideoRenderData->sInPortTunnelInfo[i].nPortIndex == nPort)
{
pPortTunnelInfo = &pVideoRenderData->sInPortTunnelInfo[i];
bFindFlag = TRUE;
break;
}
}
if(FALSE == bFindFlag)
{
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_VO_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
bFindFlag = FALSE;
for(i=0; i<MAX_VDRENDER_PORTS; i++)
{
if(pVideoRenderData->sPortBufSupplier[i].nPortIndex == nPort)
{
pPortBufSupplier = &pVideoRenderData->sPortBufSupplier[i];
bFindFlag = TRUE;
break;
}
}
if(FALSE == bFindFlag)
{
aloge("fatal error! portIndex[%d] wrong!", nPort);
eError = ERR_VO_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
pPortTunnelInfo->nPortIndex = nPort;
pPortTunnelInfo->hTunnel = hTunneledComp;
pPortTunnelInfo->nTunnelPortIndex = nTunneledPort;
pPortTunnelInfo->eTunnelType = (pPortDef->eDomain == COMP_PortDomainOther) ? TUNNEL_TYPE_CLOCK : TUNNEL_TYPE_COMMON;
if(NULL==hTunneledComp && 0==nTunneledPort && NULL==pTunnelSetup)
{
alogd("omx_core cancel setup tunnel on port[%d]", nPort);
eError = SUCCESS;
goto COMP_CMD_FAIL;
}
if (pPortTunnelInfo->eTunnelType == TUNNEL_TYPE_CLOCK)
{
CDX_NotifyStartToRunTYPE NotifyStartToRunInfo;
NotifyStartToRunInfo.nPortIndex = pPortTunnelInfo->nTunnelPortIndex;
NotifyStartToRunInfo.mbNotify = TRUE;
COMP_SetConfig(
pPortTunnelInfo->hTunnel,
COMP_IndexVendorNotifyStartToRunInfo,
(void*)&NotifyStartToRunInfo);
}
if(pPortDef->eDir == COMP_DirOutput)
{
if (pVideoRenderData->mOutputPortTunnelFlag) {
aloge("VO_Comp outport already bind, why bind again?!");
eError = FAILURE;
goto COMP_CMD_FAIL;
}
pTunnelSetup->nTunnelFlags = 0;
pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier;
pVideoRenderData->mOutputPortTunnelFlag = TRUE;
}
else
{
if (pVideoRenderData->mInputPortTunnelFlags[VDR_PORT_SUFFIX_CLOCK] && pVideoRenderData->mInputPortTunnelFlags[VDR_PORT_SUFFIX_VIDEO]) {
aloge("VO_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;
COMP_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_VO_ILLEGAL_PARAM;
goto COMP_CMD_FAIL;
}
pPortDef->format = out_port_def.format;
//The component B informs component A about the final result of negotiation.
if(pTunnelSetup->eSupplier != pPortBufSupplier->eBufferSupplier)
{
alogw("Low probability! use input portIndex[%d] buffer supplier[%d] as final!", nPort, pPortBufSupplier->eBufferSupplier);
pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier;
}
COMP_PARAM_BUFFERSUPPLIERTYPE oSupplier;
oSupplier.nPortIndex = nTunneledPort;
COMP_GetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier);
oSupplier.eBufferSupplier = pTunnelSetup->eSupplier;
COMP_SetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier);
pVideoRenderData->mInputPortTunnelFlags[nInPortSuffix] = TRUE;
}
COMP_CMD_FAIL:
return eError;
}
ERRORTYPE VideoRenderEmptyThisBuffer(
PARAM_IN COMP_HANDLETYPE hComponent,
PARAM_IN COMP_BUFFERHEADERTYPE* pBuffer)
{
VIDEORENDERDATATYPE *pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
ERRORTYPE eError = SUCCESS;
VIDEO_FRAME_INFO_S *pInFrame;
pthread_mutex_lock(&pVideoRenderData->mStateMutex);
if(pVideoRenderData->state!=COMP_StateIdle && pVideoRenderData->state!=COMP_StateExecuting && pVideoRenderData->state!=COMP_StatePause)
{
alogd("call function in invalid state[0x%x]!", pVideoRenderData->state);
pthread_mutex_unlock(&pVideoRenderData->mStateMutex);
return ERR_VO_CHN_INCORRECT_STATE_OPERATION;
}
if(pVideoRenderData->mInputPortTunnelFlags[VDR_PORT_SUFFIX_VIDEO])
{
pInFrame = (VIDEO_FRAME_INFO_S*)pBuffer->pOutputPortPrivate;
}
else
{
pInFrame = (VIDEO_FRAME_INFO_S*)pBuffer->pAppPrivate;
}
/*
alogd("inPts[%lld]ms", (int64_t)pInFrame->VFrame.mpts/1000);
if((int64_t)pInFrame->VFrame.mpts - pVideoRenderData->mLastRenderFramePts > 60*1000)
{
alogw("Be careful! pts jump[%lld]ms, [%lld]ms-[%lldms]", ((int64_t)pInFrame->VFrame.mpts - pVideoRenderData->mLastRenderFramePts)/1000, (int64_t)pInFrame->VFrame.mpts/1000, pVideoRenderData->mLastRenderFramePts/1000);
}
*/
if(pVideoRenderData->mLastRenderFramePts >=0)
{
if ((int64_t)pInFrame->VFrame.mpts < pVideoRenderData->mLastRenderFramePts)
{
pVideoRenderData->mLastRenderFramePts = pInFrame->VFrame.mpts;
}
if ((int64_t)pInFrame->VFrame.mpts - pVideoRenderData->mLastRenderFramePts < pVideoRenderData->mPlayFrameInterval)
{
pthread_mutex_unlock(&pVideoRenderData->mStateMutex);
return ERR_VO_SYS_NOTREADY;
}
}
pVideoRenderData->mLastRenderFramePts = pInFrame->VFrame.mpts;
if(pVideoRenderData->mInputPortTunnelFlags[VDR_PORT_SUFFIX_VIDEO])
{
if(pBuffer->nInputPortIndex == pVideoRenderData->sInPortDef[VDR_PORT_SUFFIX_VIDEO].nPortIndex)
{
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
eError = VideoRenderAddFrame_l(pVideoRenderData, pInFrame);
if (eError != SUCCESS)
{
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
goto ADD_FRM_ERR;
}
if(pVideoRenderData->mWaitInputFrameFlag)
{
pVideoRenderData->mWaitInputFrameFlag = FALSE;
message_t msg;
msg.command = VRenderComp_InputFrameAvailable;
put_message(&pVideoRenderData->cmd_queue, &msg);
}
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
}
else
{
aloge("fatal error! inputPortIndex[%u] match nothing!", pBuffer->nInputPortIndex);
eError = ERR_VO_ILLEGAL_PARAM;
}
}
else
{
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
eError = VideoRenderAddFrame_l(pVideoRenderData, pInFrame);
if (eError != SUCCESS)
{
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
goto ADD_FRM_ERR;
}
if(pVideoRenderData->mWaitInputFrameFlag)
{
pVideoRenderData->mWaitInputFrameFlag = FALSE;
message_t msg;
msg.command = VRenderComp_InputFrameAvailable;
put_message(&pVideoRenderData->cmd_queue, &msg);
}
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
}
ADD_FRM_ERR:
pthread_mutex_unlock(&pVideoRenderData->mStateMutex);
return eError;
}
ERRORTYPE VideoRenderComponentDeInit(PARAM_IN COMP_HANDLETYPE hComponent) {
VIDEORENDERDATATYPE *pVideoRenderData;
ERRORTYPE eError = SUCCESS;
CompInternalMsgType eCmd = Stop;
message_t msg;
pVideoRenderData = (VIDEORENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
msg.command = eCmd;
put_message(&pVideoRenderData->cmd_queue, &msg);
alogv("wait video render component exit!...");
// Wait for thread to exit so we can get the status into "error"
pthread_join(pVideoRenderData->thread_id, (void*) &eError);
alogv("video render component exited 0!");
message_destroy(&pVideoRenderData->cmd_queue);
if(pVideoRenderData->hnd_cdx_video_render != NULL)
{
pVideoRenderData->hnd_cdx_video_render->exit(pVideoRenderData->hnd_cdx_video_render);
cedarx_video_render_destroy(pVideoRenderData->hnd_cdx_video_render);
}
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
if (!list_empty(&pVideoRenderData->mVideoInputFrameUsedList))
{
aloge("fatal error! inputUsedFrame must be 0!");
}
if (!list_empty(&pVideoRenderData->mVideoInputFrameReadyList))
{
aloge("fatal error! inputReadyFrame must be 0!");
}
if (!list_empty(&pVideoRenderData->mVideoInputFrameIdleList))
{
VOCompInputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoRenderData->mVideoInputFrameIdleList, mList)
{
list_del(&pEntry->mList);
free(pEntry);
}
}
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
pthread_mutex_destroy(&pVideoRenderData->mStateMutex);
pthread_mutex_destroy(&pVideoRenderData->mVideoInputFrameListMutex);
pthread_mutex_destroy(&pVideoRenderData->mUserRegionMutex);
if(pVideoRenderData)
{
free(pVideoRenderData);
pVideoRenderData = NULL;
}
alogv("video render component exited 1!");
return eError;
}
/*****************************************************************************/
ERRORTYPE VideoRenderComponentInit(PARAM_IN COMP_HANDLETYPE hComponent)
{
MM_COMPONENTTYPE *pComp;
VIDEORENDERDATATYPE *pVideoRenderData;
ERRORTYPE eError = SUCCESS;
unsigned int err;
int i;
pComp = (MM_COMPONENTTYPE *) hComponent;
// Create private data
pVideoRenderData = (VIDEORENDERDATATYPE *) malloc(sizeof(VIDEORENDERDATATYPE));
memset(pVideoRenderData, 0x0, sizeof(VIDEORENDERDATATYPE));
alogv("hComponent %p, pVideoRenderData %p", hComponent, pVideoRenderData);
pComp->pComponentPrivate = (void*) pVideoRenderData;
pVideoRenderData->state = COMP_StateLoaded;
pVideoRenderData->hSelf = hComponent;
pVideoRenderData->mVideoDisplayWidth = -1;
pVideoRenderData->mVideoDisplayHeight = -1;
pVideoRenderData->mbShowPicFlag = TRUE;
pVideoRenderData->mLastRenderFramePts = -1;
//PropertyGet_PlayFrameInterval(&pVideoRenderData->mPlayFrameInterval);
err = pthread_mutex_init(&pVideoRenderData->mStateMutex, NULL);
if(err!=0)
{
aloge("fatal error! pthread mutex init fail!");
eError = ERR_VO_SYS_NOTREADY;
goto EXIT0;
}
INIT_LIST_HEAD(&pVideoRenderData->mVideoInputFrameIdleList);
INIT_LIST_HEAD(&pVideoRenderData->mVideoInputFrameReadyList);
INIT_LIST_HEAD(&pVideoRenderData->mVideoInputFrameUsedList);
for (i = 0; i < 16; i++)
{
VOCompInputFrame *pNode = (VOCompInputFrame*)malloc(sizeof(VOCompInputFrame));
if (NULL == pNode)
{
aloge("fatal error! malloc fail[%s]!", strerror(errno));
break;
}
memset(pNode, 0, sizeof(VOCompInputFrame));
list_add_tail(&pNode->mList, &pVideoRenderData->mVideoInputFrameIdleList);
}
INIT_LIST_HEAD(&pVideoRenderData->mANWBuffersList);
err = pthread_mutex_init(&pVideoRenderData->mUserRegionMutex, NULL);
if(err!=0)
{
aloge("fatal error! pthread mutex init fail!");
eError = ERR_VO_NO_MEM;
goto EXIT1;
}
err = pthread_mutex_init(&pVideoRenderData->mVideoInputFrameListMutex, NULL);
if(err!=0)
{
aloge("fatal error! pthread mutex init fail!");
eError = ERR_VO_NO_MEM;
goto EXIT2;
}
// Fill in function pointers
pComp->SetCallbacks = VideoRenderSetCallbacks;
pComp->SendCommand = VideoRenderSendCommand;
pComp->GetConfig = VideoRenderGetConfig;
pComp->SetConfig = VideoRenderSetConfig;
pComp->GetState = VideoRenderGetState;
pComp->ComponentTunnelRequest = VideoRenderComponentTunnelRequest;
pComp->EmptyThisBuffer = VideoRenderEmptyThisBuffer;
pComp->ComponentDeInit = VideoRenderComponentDeInit;
// Initialize component data structures to default values
pVideoRenderData->sPortParam.nPorts = 0;
pVideoRenderData->sPortParam.nStartPortNumber = 0x0;
pVideoRenderData->sPortBufSupplier[VDR_PORT_SUFFIX_CLOCK].nPortIndex = 0x0;
pVideoRenderData->sPortBufSupplier[VDR_PORT_SUFFIX_CLOCK].eBufferSupplier = COMP_BufferSupplyOutput;
pVideoRenderData->sPortBufSupplier[VDR_PORT_SUFFIX_VIDEO].nPortIndex = 0x1;
pVideoRenderData->sPortBufSupplier[VDR_PORT_SUFFIX_VIDEO].eBufferSupplier = COMP_BufferSupplyOutput;
pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_CLOCK].nPortIndex = 0x0;
pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_CLOCK].eTunnelType = TUNNEL_TYPE_CLOCK;
pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_VIDEO].nPortIndex = 0x1;
pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_VIDEO].eTunnelType = TUNNEL_TYPE_COMMON;
pVideoRenderData->sInPortDef[VDR_PORT_SUFFIX_CLOCK].nPortIndex = pVideoRenderData->sPortParam.nPorts;
pVideoRenderData->sInPortDef[VDR_PORT_SUFFIX_CLOCK].bEnabled = TRUE;
pVideoRenderData->sInPortDef[VDR_PORT_SUFFIX_CLOCK].eDomain = COMP_PortDomainOther;
pVideoRenderData->sInPortDef[VDR_PORT_SUFFIX_CLOCK].eDir = COMP_DirInput;
pVideoRenderData->sPortParam.nPorts++;
pVideoRenderData->sInPortDef[VDR_PORT_SUFFIX_VIDEO].nPortIndex = pVideoRenderData->sPortParam.nPorts;
pVideoRenderData->sInPortDef[VDR_PORT_SUFFIX_VIDEO].bEnabled = TRUE;
pVideoRenderData->sInPortDef[VDR_PORT_SUFFIX_VIDEO].eDomain = COMP_PortDomainVideo;
pVideoRenderData->sInPortDef[VDR_PORT_SUFFIX_VIDEO].eDir = COMP_DirInput;
pVideoRenderData->sPortParam.nPorts++;
if(message_create(&pVideoRenderData->cmd_queue) < 0)
{
aloge("message error!\n");
eError = ERR_VO_SYS_NOTREADY;
goto EXIT3;
}
// Create the component thread
err = pthread_create(&pVideoRenderData->thread_id, NULL, VideoRender_ComponentThread, pVideoRenderData);
if (err || !pVideoRenderData->thread_id)
{
eError = ERR_VO_SYS_NOTREADY;
goto EXIT4;
}
return eError;
EXIT4:
// free(pVideoRenderData->pANativeWindowBuffer);
// pVideoRenderData->pANativeWindowBuffer = NULL;
EXIT3:
pthread_mutex_destroy(&pVideoRenderData->mVideoInputFrameListMutex);
EXIT2:
pthread_mutex_destroy(&pVideoRenderData->mUserRegionMutex);
EXIT1:
pthread_mutex_destroy(&pVideoRenderData->mStateMutex);
EXIT0:
return eError;
}
ERRORTYPE VideoRenderGetFrame_l(
PARAM_IN VIDEORENDERDATATYPE *pVideoRenderData,
PARAM_OUT VOCompInputFrame** ppFrame)
{
ERRORTYPE eError;
if(!list_empty(&pVideoRenderData->mVideoInputFrameReadyList))
{
VOCompInputFrame *pOutFrame = list_first_entry(&pVideoRenderData->mVideoInputFrameReadyList, VOCompInputFrame, mList);
list_move_tail(&pOutFrame->mList, &pVideoRenderData->mVideoInputFrameUsedList);
*ppFrame = pOutFrame;
eError = SUCCESS;
}
else
{
eError = ERR_VO_NO_MEM;
}
return eError;
}
ERRORTYPE VideoRenderGetFrame(
PARAM_IN VIDEORENDERDATATYPE *pVideoRenderData,
PARAM_OUT VOCompInputFrame** ppFrame)
{
ERRORTYPE eError;
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
eError = VideoRenderGetFrame_l(pVideoRenderData, ppFrame);
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
return eError;
}
/*****************************************************************************/
static void* VideoRender_ComponentThread(void* pThreadData)
{
unsigned int cmddata;
CompInternalMsgType cmd;
VIDEORENDERDATATYPE* pVideoRenderData = (VIDEORENDERDATATYPE*) pThreadData;
COMP_BUFFERHEADERTYPE omx_buffer_header;
message_t cmd_msg;
int i;
COMP_HANDLETYPE hnd_vdec_comp;
COMP_HANDLETYPE hnd_clock_comp;
MM_COMPONENTTYPE* hnd_sub_comp;
COMP_INTERNAL_TUNNELINFOTYPE* p_vdec_tunnel;
COMP_INTERNAL_TUNNELINFOTYPE* p_clock_tunnel;
COMP_BUFFERHEADERTYPE omx_sub_header;
sprintf(pVideoRenderData->mThreadName, "VOChn[%d-%d]", pVideoRenderData->mMppChnInfo.mDevId, pVideoRenderData->mMppChnInfo.mChnId);
prctl(PR_SET_NAME, (unsigned long)pVideoRenderData->mThreadName, 0, 0, 0);
int64_t total_interval = 0;
int64_t dec_cnt = 0;
hnd_vdec_comp = NULL;
hnd_clock_comp = NULL;
hnd_sub_comp = NULL;
p_vdec_tunnel = NULL;
p_clock_tunnel = NULL;
pVideoRenderData->video_rend_flag = VIDEO_RENDER_FIRST_FRAME_FLAG;
//omx_buffer_header.pBuffer = pVideoRenderData->p_frame_info;
while (1)
{
PROCESS_MESSAGE:
if(get_message(&pVideoRenderData->cmd_queue, &cmd_msg) == 0)
{
cmd = cmd_msg.command;
cmddata = (unsigned int)cmd_msg.para0;
// State transition command
if (cmd == SetState)
{
pthread_mutex_lock(&pVideoRenderData->mStateMutex);
if (pVideoRenderData->state == (COMP_STATETYPE) (cmddata))
{
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventError,
ERR_VO_CHN_SAMESTATE,
pVideoRenderData->state,
NULL);
}
else
{
switch ((COMP_STATETYPE) (cmddata))
{
case COMP_StateInvalid:
pVideoRenderData->state = COMP_StateInvalid;
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventError,
ERR_VO_CHN_INVALIDSTATE,
0,
NULL);
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pVideoRenderData->state,
NULL);
break;
case COMP_StateLoaded:
{
if (pVideoRenderData->state != COMP_StateIdle)
{
aloge("fatal error! VideoRender incorrect state transition [0x%x]->Loaded!", pVideoRenderData->state);
pVideoRenderData->pCallbacks->EventHandler(
pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventError,
ERR_VO_CHN_INCORRECT_STATE_TRANSITION,
0,
NULL);
}
ERRORTYPE omxRet;
//release all frames.
alogv("release all frames to VDec, when state[0x%x]->[0x%x]", pVideoRenderData->state, COMP_StateLoaded);
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
if(!list_empty(&pVideoRenderData->mVideoInputFrameUsedList))
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoRenderData->mVideoInputFrameUsedList)
{
cnt++;
}
alogd("release [%d]used inputFrame! state[%d->loaded]", cnt, pVideoRenderData->state);
VOCompInputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoRenderData->mVideoInputFrameUsedList, mList)
{
VideoRenderReleaseFrame_l(pVideoRenderData, pEntry);
}
}
if(!list_empty(&pVideoRenderData->mVideoInputFrameReadyList))
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoRenderData->mVideoInputFrameReadyList)
{
cnt++;
}
alogd("release [%d]unused inputFrame! state[%d->loaded]", cnt, pVideoRenderData->state);
VOCompInputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoRenderData->mVideoInputFrameReadyList, mList)
{
VideoRenderReleaseFrame_l(pVideoRenderData, pEntry);
}
}
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
VideoRenderDestroyANWBuffersInfo(pVideoRenderData);
pVideoRenderData->state = COMP_StateLoaded;
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pVideoRenderData->state,
NULL);
break;
}
case COMP_StateIdle:
if (pVideoRenderData->state == COMP_StateInvalid)
{
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventError,
ERR_VO_CHN_INCORRECT_STATE_OPERATION,
0,
NULL);
}
else
{
alogv("VideoRender state[0x%x]->Idle!", pVideoRenderData->state);
if ((pVideoRenderData->state == COMP_StateExecuting) || (pVideoRenderData->state == COMP_StatePause))
{
//release all frames. //for vi comp will wait for all frame buffer release when stop chn(vi state to idle)
ERRORTYPE omxRet;
alogv("release all frames");
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
if(!list_empty(&pVideoRenderData->mVideoInputFrameUsedList))
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoRenderData->mVideoInputFrameUsedList)
{
cnt++;
}
alogd("VideoLayer[%d]: release [%d]used inputFrame!", pVideoRenderData->mMppChnInfo.mDevId, cnt);
VOCompInputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoRenderData->mVideoInputFrameUsedList, mList)
{
VideoRenderReleaseFrame_l(pVideoRenderData, pEntry);
}
}
if(!list_empty(&pVideoRenderData->mVideoInputFrameReadyList))
{
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoRenderData->mVideoInputFrameReadyList)
{
cnt++;
}
alogd("VideoLayer[%d]: release [%d]unused inputFrame!", pVideoRenderData->mMppChnInfo.mDevId, cnt);
VOCompInputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoRenderData->mVideoInputFrameReadyList, mList)
{
VideoRenderReleaseFrame_l(pVideoRenderData, pEntry);
}
}
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
VideoRenderDestroyANWBuffersInfo(pVideoRenderData);
}
pVideoRenderData->state = COMP_StateIdle;
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pVideoRenderData->state,
NULL);
}
break;
case COMP_StateExecuting:
// Transition can only happen from pause or idle state
if (pVideoRenderData->state == COMP_StateIdle || pVideoRenderData->state == COMP_StatePause)
{
hnd_vdec_comp = (pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_VIDEO].hTunnel);
p_vdec_tunnel = &pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_VIDEO];
hnd_clock_comp = (pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_CLOCK].hTunnel);
p_clock_tunnel = &pVideoRenderData->sInPortTunnelInfo[VDR_PORT_SUFFIX_CLOCK];
#if 1
if(pVideoRenderData->state == COMP_StateIdle)
{
pVideoRenderData->video_rend_flag |= VIDEO_RENDER_FIRST_FRAME_FLAG;
if(!pVideoRenderData->av_sync)
pVideoRenderData->start_to_play = TRUE;
else
pVideoRenderData->start_to_play = FALSE;
pVideoRenderData->wait_time_out = 0;
if(pVideoRenderData->render_seeking_flag)
{
alogd("seek in idle state?");
pVideoRenderData->render_seeking_flag = 0;
}
}
else if(pVideoRenderData->state == COMP_StatePause)
{
//if current Pause is caused by jump, we need set first frame flag. Because we need reset start_time to clock_component.
if(pVideoRenderData->render_seeking_flag)
{
pVideoRenderData->video_rend_flag |= VIDEO_RENDER_FIRST_FRAME_FLAG;
if(!pVideoRenderData->av_sync)
pVideoRenderData->start_to_play = TRUE;
else
pVideoRenderData->start_to_play = FALSE;
pVideoRenderData->wait_time_out = 0;
pVideoRenderData->render_seeking_flag = 0;
}
}
#else
pVideoRenderData->video_rend_flag |= VIDEO_RENDER_FIRST_FRAME_FLAG;
if(!pVideoRenderData->av_sync)
pVideoRenderData->start_to_play = TRUE;
else
pVideoRenderData->start_to_play = FALSE;
pVideoRenderData->wait_time_out = 0;
#endif
pVideoRenderData->state = COMP_StateExecuting;
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pVideoRenderData->state,
NULL);
}
else
{
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventError,
ERR_VO_CHN_INCORRECT_STATE_OPERATION,
0,
NULL);
}
break;
case COMP_StatePause:
// Transition can only happen from idle or executing state
if (pVideoRenderData->state == COMP_StateIdle || pVideoRenderData->state == COMP_StateExecuting)
{
pVideoRenderData->state = COMP_StatePause;
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventCmdComplete,
COMP_CommandStateSet,
pVideoRenderData->state,
NULL);
}
else
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventError,
ERR_VO_CHN_INCORRECT_STATE_TRANSITION,
0,
NULL);
break;
default:
break;
}
}
pthread_mutex_unlock(&pVideoRenderData->mStateMutex);
}
else if (cmd == Stop)
{
// Kill thread
goto EXIT;
}
else if (cmd == VRenderComp_InputFrameAvailable)
{
alogv("inputFrameAvailable");
}
else if (cmd == VRenderComp_ChangeANativeWindow)
{
if(pVideoRenderData->state!=COMP_StatePause)
{
aloge("fatal error! state[%d] is not pause when change window", pVideoRenderData->state);
}
alogd("change Android Native Window");
if(pVideoRenderData->hnd_cdx_video_render_init_flag)
{
if(VideoRender_GUI == pVideoRenderData->VRenderMode)
{
ERRORTYPE omxRet;
//return gui occupied frames to vdec. mVideoInputFrameUsedList
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
if(!list_empty(&pVideoRenderData->mVideoInputFrameUsedList))
{
alogd("release used video frame!");
VOCompInputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoRenderData->mVideoInputFrameUsedList, mList)
{
VideoRenderReleaseFrame_l(pVideoRenderData, pEntry);
}
}
//return frames to VDecComponent.
//cancel frames to ANativeWindow
int nCancelFrameRet;
if(!list_empty(&pVideoRenderData->mVideoInputFrameReadyList))
{
alogd("release all inputVideoFrame!");
VOCompInputFrame *pEntry, *pTmp;
list_for_each_entry_safe(pEntry, pTmp, &pVideoRenderData->mVideoInputFrameReadyList, mList)
{
VideoRenderReleaseFrame_l(pVideoRenderData, pEntry);
ANativeWindowBufferCedarXWrapper *pANWBuffer = VideoRenderFindANWBufferByFrame(pVideoRenderData, pEntry);
if(NULL == pANWBuffer)
{
alogw("fatal error! not find ANWBuffer for VideoPicture!");
//pVideoRenderData->state = COMP_StateInvalid;
//goto PROCESS_MESSAGE;
continue;
}
nCancelFrameRet = pVideoRenderData->hnd_cdx_video_render->cancel_frame(pVideoRenderData->hnd_cdx_video_render, pANWBuffer);
if(SUCCESS == nCancelFrameRet)
{
pANWBuffer->mbOccupyFlag = 0;
}
else
{
aloge("fatal error! CancelFrame fail[%d]", nCancelFrameRet);
}
}
}
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
//clear all ANWBuffers
VideoRenderDestroyANWBuffersInfo(pVideoRenderData);
}
pVideoRenderData->hnd_cdx_video_render->exit(pVideoRenderData->hnd_cdx_video_render);
pVideoRenderData->hnd_cdx_video_render_init_flag = 0;
}
else
{
alogd("Be careful! not init video render when change Android Native Window in state[%d]", pVideoRenderData->state);
}
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventCmdComplete,
COMP_CommandVendorChangeANativeWindow,
pVideoRenderData->state,
NULL);
}
else if (cmd == VRenderComp_ResolutionChange)
{
alogd("Resolution Change");
pVideoRenderData->mResolutionChangeFlag = TRUE;
}
else if(cmd == VRenderComp_StoreFrame)
{
uint64_t framePts = *(uint64_t*)cmd_msg.mpData;
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
if(!list_empty(&pVideoRenderData->mVideoInputFrameUsedList) || !list_empty(&pVideoRenderData->mVideoInputFrameReadyList))
{
//find nearest frame to store
int64_t minInterval = -1;
int64_t minAbsInterval = -1;
int64_t nInterval;
int64_t nAbsInterval;
VOCompInputFrame *pEntry = NULL;
VOCompInputFrame *pDstEntry = NULL;
list_for_each_entry(pEntry, &pVideoRenderData->mVideoInputFrameUsedList, mList)
{
if(pEntry->mFrameInfo.VFrame.mpts >= framePts)
{
nAbsInterval = (int64_t)(pEntry->mFrameInfo.VFrame.mpts - framePts);
nInterval = nAbsInterval;
}
else
{
nAbsInterval = (int64_t)(framePts - pEntry->mFrameInfo.VFrame.mpts);
nInterval = -nAbsInterval;
}
if(-1 == minAbsInterval || minAbsInterval > nAbsInterval)
{
minAbsInterval = nAbsInterval;
minInterval = nInterval;
pDstEntry = pEntry;
}
}
list_for_each_entry(pEntry, &pVideoRenderData->mVideoInputFrameReadyList, mList)
{
if(pEntry->mFrameInfo.VFrame.mpts >= framePts)
{
nAbsInterval = (int64_t)(pEntry->mFrameInfo.VFrame.mpts - framePts);
nInterval = nAbsInterval;
}
else
{
nAbsInterval = (int64_t)(framePts - pEntry->mFrameInfo.VFrame.mpts);
nInterval = -nAbsInterval;
}
if(-1 == minAbsInterval || minAbsInterval > nAbsInterval)
{
minAbsInterval = nAbsInterval;
minInterval = nInterval;
pDstEntry = pEntry;
}
}
alogd("match voPts[%lld]-dstPts[%lld]=[%lld]us", pDstEntry->mFrameInfo.VFrame.mpts, framePts, minInterval);
if(MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420 == pDstEntry->mFrameInfo.VFrame.mPixelFormat)
{
char DbgStoreFilePath[256];
snprintf(DbgStoreFilePath, 256, "/tmp/pic[%d][%lldus].nv21", pVideoRenderData->mStoreFrameCnt++, pDstEntry->mFrameInfo.VFrame.mpts);
alogw("prepare store frame in file[%s]", DbgStoreFilePath);
FILE *dbgFp = fopen(DbgStoreFilePath, "wb");
if(dbgFp != NULL)
{
VideoFrameBufferSizeInfo FrameSizeInfo;
getVideoFrameBufferSizeInfo(&pDstEntry->mFrameInfo, &FrameSizeInfo);
int yuvSize[3] = {FrameSizeInfo.mYSize, FrameSizeInfo.mUSize, FrameSizeInfo.mVSize};
for(int i=0; i<3; i++)
{
if(pDstEntry->mFrameInfo.VFrame.mpVirAddr[i] != NULL)
{
fwrite(pDstEntry->mFrameInfo.VFrame.mpVirAddr[i], 1, yuvSize[i], dbgFp);
alogd("virAddr[%d]=[%p], length=[%d]", i, pDstEntry->mFrameInfo.VFrame.mpVirAddr[i], yuvSize[i]);
}
}
fclose(dbgFp);
alogd("store frame in file[%s]", DbgStoreFilePath);
}
}
else
{
aloge("other pixel format[0x%x], need support!", pDstEntry->mFrameInfo.VFrame.mPixelFormat);
}
}
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
/* mpData is malloced in TMessageDeepCopyMessage() */
free(cmd_msg.mpData);
cmd_msg.mpData = NULL;
cmd_msg.mDataSize = 0;
}
//precede to process message
goto PROCESS_MESSAGE;
}
if (pVideoRenderData->state == COMP_StateExecuting)
{
ERRORTYPE ret;
COMP_TIME_CONFIG_TIMESTAMPTYPE time_stamp;
int64_t lltime_stamp2;
int64_t lltime_stamp3;
int64_t media_clock_time; //unit:us
int64_t media_video_time; //unit:us
VIDEO_FRAME_INFO_S *pic=NULL; //VideoPicture
int nRenderRet;
int nQueueFrameRet;
int nDequeueFrameRet;
RECT_S stRegion;
pthread_mutex_lock(&pVideoRenderData->mUserRegionMutex);
stRegion = pVideoRenderData->mUserRegion;
if(stRegion.Width == 0 && stRegion.Height == 0)
{
pVideoRenderData->bUserFlag = FALSE;
}
else if(stRegion.Width != 0 && stRegion.Height != 0)
{
pVideoRenderData->bUserFlag = TRUE;
}
pthread_mutex_unlock(&pVideoRenderData->mUserRegionMutex);
if(VideoRender_GUI == pVideoRenderData->VRenderMode)
{
if(0==pVideoRenderData->hnd_cdx_video_render_init_flag)
{
//try to get vdec fbm para.
CdxVRANWInitPara nativeWindowInitPara;
FbmBufInfo vdecFbmBufInfo;
while(1)
{
if(SUCCESS == COMP_GetConfig(hnd_vdec_comp, COMP_IndexVendorFbmBufInfo, (void*)&vdecFbmBufInfo))
{
memset(&nativeWindowInitPara, 0, sizeof(CdxVRANWInitPara));
nativeWindowInitPara.mnBufNum = vdecFbmBufInfo.nBufNum;
nativeWindowInitPara.mnBufWidth = vdecFbmBufInfo.nBufWidth;
nativeWindowInitPara.mnBufHeight = vdecFbmBufInfo.nBufHeight;
nativeWindowInitPara.mePixelFormat = vdecFbmBufInfo.ePixelFormat;
nativeWindowInitPara.mnAlignValue = vdecFbmBufInfo.nAlignValue;
nativeWindowInitPara.mbProgressiveFlag = vdecFbmBufInfo.bProgressiveFlag;
break;
}
else
{
alogd("get vdec FbmBufInfo fail, wait 50ms!");
if(TMessage_WaitQueueNotEmpty(&pVideoRenderData->cmd_queue, 50) > 0)
{
goto PROCESS_MESSAGE;
}
}
}
//init video render, get gpu buffers, set back to vdec.
CdxANWBuffersInfo anwBuffersInfo;
memset(&anwBuffersInfo, 0, sizeof(CdxANWBuffersInfo));
if(SUCCESS != pVideoRenderData->hnd_cdx_video_render->init(pVideoRenderData->hnd_cdx_video_render,
pVideoRenderData->VRenderMode, (void*)&nativeWindowInitPara, (void*)&anwBuffersInfo))
{
alogw("fatal error! init ANativeWindow fail! state to OMX StateInvalid");
pVideoRenderData->state = COMP_StateInvalid;
goto PROCESS_MESSAGE;
}
VideoRenderCreateANWBuffersInfo(pVideoRenderData, &anwBuffersInfo);
VDecCompFrameBuffersParam setFrameBuffersParam;
setFrameBuffersParam.mpANWBuffersInfo = &anwBuffersInfo;
INIT_LIST_HEAD(&setFrameBuffersParam.mFramesOwnedByANW);
if(SUCCESS != COMP_SetConfig(hnd_vdec_comp, COMP_IndexVendorFrameBuffers, (void*)&setFrameBuffersParam))
{
alogw("fatal error! set gpu buffers to vdec fail! state to OMX StateInvalid");
pVideoRenderData->state = COMP_StateInvalid;
goto PROCESS_MESSAGE;
}
//put frames owned by ANW to videoInputFrameUsedList
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoRenderData->mVideoInputFrameUsedList)
{
cnt++;
}
if(cnt > 0)
{
aloge("fatal error! check videoInputFrameUsedList, it has [%d] used frames.", cnt);
}
list_splice_tail(&setFrameBuffersParam.mFramesOwnedByANW, &pVideoRenderData->mVideoInputFrameUsedList);
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
pVideoRenderData->hnd_cdx_video_render_init_flag = 1;
}
}
//pict = (VideoPicture*)omx_buffer_header.pBuffer;
VOCompInputFrame *pFrame = NULL;
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
ret = VideoRenderGetFrame_l(pVideoRenderData, &pFrame);
if(ret != SUCCESS)
{
if(pVideoRenderData->mResolutionChangeFlag)
{
alogd("Resolution Change, vrender display all old frames, vdec can ReopenVideoEngine() and continue to decode!");
//return usedInputframes because we will ReopenVideoEngine().
if(!list_empty(&pVideoRenderData->mVideoInputFrameUsedList))
{
alogd("release used video frame!");
VOCompInputFrame *pEntry, *pTmp;
ERRORTYPE omxRet;
list_for_each_entry_safe(pEntry, pTmp, &pVideoRenderData->mVideoInputFrameUsedList, mList)
{
VideoRenderReleaseFrame_l(pVideoRenderData, pEntry);
}
}
VideoRenderDestroyANWBuffersInfo(pVideoRenderData);
COMP_SetConfig(hnd_vdec_comp, COMP_IndexVendorReopenVideoEngine, NULL);
if(pVideoRenderData->hnd_cdx_video_render_init_flag)
{
pVideoRenderData->hnd_cdx_video_render->exit(pVideoRenderData->hnd_cdx_video_render);
pVideoRenderData->hnd_cdx_video_render_init_flag = 0;
}
else
{
alogd("Be careful! not init video render when resolution change in state[%d]", pVideoRenderData->state);
}
pVideoRenderData->mVideoDisplayWidth = -1;
pVideoRenderData->mVideoDisplayHeight = -1;
pVideoRenderData->mResolutionChangeFlag = FALSE;
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
goto PROCESS_MESSAGE;
}
pVideoRenderData->mWaitInputFrameFlag = TRUE;
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
if(pVideoRenderData->priv_flag & CDX_comp_PRIV_FLAGS_STREAMEOF)
{
alogd("videoRender notify EOF!");
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf, pVideoRenderData->pAppData, COMP_EventBufferFlag, 0, 0, NULL);
pVideoRenderData->state = COMP_StateIdle;
goto PROCESS_MESSAGE;
}
TMessage_WaitQueueNotEmpty(&pVideoRenderData->cmd_queue, 0);
if(pVideoRenderData->priv_flag & CDX_comp_PRIV_FLAGS_STREAMEOF)
{
alogd("videoRender notify EOF!");
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf, pVideoRenderData->pAppData, COMP_EventBufferFlag, 0, 0, NULL);
pVideoRenderData->state = COMP_StateIdle;
}
goto PROCESS_MESSAGE;
}
else
{
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
}
{
pic = &pFrame->mFrameInfo;
if(pVideoRenderData->bUserFlag != TRUE)//if user set the Display Region
{
if(-1 == pVideoRenderData->mVideoDisplayWidth && -1 == pVideoRenderData->mVideoDisplayHeight)
{
pVideoRenderData->mVideoDisplayTopX = pic->VFrame.mOffsetLeft;
pVideoRenderData->mVideoDisplayTopY = pic->VFrame.mOffsetTop;
pVideoRenderData->mVideoDisplayWidth = pic->VFrame.mOffsetRight - pic->VFrame.mOffsetLeft;
pVideoRenderData->mVideoDisplayHeight = pic->VFrame.mOffsetBottom - pic->VFrame.mOffsetTop;
pVideoRenderData->mbNeedNotifyDisplaySize = TRUE;
}
if(pVideoRenderData->mVideoDisplayWidth != pic->VFrame.mOffsetRight - pic->VFrame.mOffsetLeft
|| pVideoRenderData->mVideoDisplayHeight != pic->VFrame.mOffsetBottom - pic->VFrame.mOffsetTop
|| pVideoRenderData->mVideoDisplayTopX != pic->VFrame.mOffsetLeft
|| pVideoRenderData->mVideoDisplayTopY != pic->VFrame.mOffsetTop)
{
alogw("Be careful! resolution has changed! oldSize[%d,%d][%dx%d],newSize[%d,%d][%dx%d]",
pVideoRenderData->mVideoDisplayTopX, pVideoRenderData->mVideoDisplayTopY, pVideoRenderData->mVideoDisplayWidth, pVideoRenderData->mVideoDisplayHeight,
pic->VFrame.mOffsetLeft, pic->VFrame.mOffsetTop, pic->VFrame.mOffsetRight-pic->VFrame.mOffsetLeft, pic->VFrame.mOffsetBottom-pic->VFrame.mOffsetTop);
pVideoRenderData->mVideoDisplayTopX = pic->VFrame.mOffsetLeft;
pVideoRenderData->mVideoDisplayTopY = pic->VFrame.mOffsetTop;
pVideoRenderData->mVideoDisplayWidth = pic->VFrame.mOffsetRight-pic->VFrame.mOffsetLeft;
pVideoRenderData->mVideoDisplayHeight = pic->VFrame.mOffsetBottom-pic->VFrame.mOffsetTop;
pVideoRenderData->mbNeedNotifyDisplaySize = TRUE;
}
}
else
{
//if user set the width:0 height:0,then the data will be set up by default value
if(pVideoRenderData->mVideoDisplayTopX != stRegion.X
|| pVideoRenderData->mVideoDisplayTopY != stRegion.Y
|| pVideoRenderData->mVideoDisplayWidth != stRegion.Width
|| pVideoRenderData->mVideoDisplayHeight != stRegion.Height)
{
pVideoRenderData->mVideoDisplayTopX = stRegion.X;
pVideoRenderData->mVideoDisplayTopY = stRegion.Y;
pVideoRenderData->mVideoDisplayWidth = stRegion.Width;
pVideoRenderData->mVideoDisplayHeight = stRegion.Height;
pVideoRenderData->mbNeedNotifyDisplaySize = TRUE;
}
}
if(0==pVideoRenderData->hnd_cdx_video_render_init_flag)
{
//init video render
alogv("request first frame, init video_render, param: display_width[%d], display_height[%d], colorFormat[0x%x]",
pic->VFrame.mOffsetRight-pic->VFrame.mOffsetLeft, pic->VFrame.mOffsetBottom-pic->VFrame.mOffsetTop, pic->VFrame.mPixelFormat);
/*{
char DbgStoreFilePath[256];
snprintf(DbgStoreFilePath, 256, "/mnt/extsd/pic.nv21");
alogw("prepare store frame in file[%s]", DbgStoreFilePath);
FILE *dbgFp = fopen(DbgStoreFilePath, "wb");
if(dbgFp != NULL)
{
VideoFrameBufferSizeInfo FrameSizeInfo;
getVideoFrameBufferSizeInfo(pic, &FrameSizeInfo);
int yuvSize[3] = {FrameSizeInfo.mYSize, FrameSizeInfo.mUSize, FrameSizeInfo.mVSize};
for(int i=0; i<3; i++)
{
if(pic->VFrame.mpVirAddr[i] != NULL)
{
fwrite(pic->VFrame.mpVirAddr[i], 1, yuvSize[i], dbgFp);
alogd("virAddr[%d]=[%p], length=[%d]", i, pic->VFrame.mpVirAddr[i], yuvSize[i]);
}
}
fclose(dbgFp);
alogd("store frame in file[%s]", DbgStoreFilePath);
}
}*/
if(VideoRender_HW == pVideoRenderData->VRenderMode)
{
CdxVRHwcLayerInitPara hwcInitPara;
memset(&hwcInitPara, 0, sizeof(CdxVRHwcLayerInitPara));
hwcInitPara.mnBufWidth = pic->VFrame.mWidth;
hwcInitPara.mnBufHeight = pic->VFrame.mHeight;
/*
hwcInitPara.mnDisplayTopX = pic->VFrame.mOffsetLeft;
hwcInitPara.mnDisplayTopY = pic->VFrame.mOffsetTop;
hwcInitPara.mnDisplayWidth = pic->VFrame.mOffsetRight - pic->VFrame.mOffsetLeft;
hwcInitPara.mnDisplayHeight = pic->VFrame.mOffsetBottom - pic->VFrame.mOffsetTop;
*/
hwcInitPara.mnDisplayTopX = pVideoRenderData->mVideoDisplayTopX;
hwcInitPara.mnDisplayTopY = pVideoRenderData->mVideoDisplayTopY;
hwcInitPara.mnDisplayWidth = pVideoRenderData->mVideoDisplayWidth;
hwcInitPara.mnDisplayHeight = pVideoRenderData->mVideoDisplayHeight;
hwcInitPara.mePixelFormat = map_PIXEL_FORMAT_E_to_EPIXELFORMAT(pic->VFrame.mPixelFormat);
hwcInitPara.mColorSpace = VENC_BT601; //convertColorPrimary2ColorSpace(pic->nColorPrimary);
hwcInitPara.mVoLayer = pVideoRenderData->mMppChnInfo.mDevId;
pVideoRenderData->hnd_cdx_video_render->init(pVideoRenderData->hnd_cdx_video_render,
pVideoRenderData->VRenderMode, &hwcInitPara, NULL);
pVideoRenderData->hnd_cdx_video_render->set_showflag(pVideoRenderData->hnd_cdx_video_render,
(int)pVideoRenderData->mbShowPicFlag);
//notify vdec display width and height
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventVideoDisplaySize,
pic->VFrame.mOffsetRight - pic->VFrame.mOffsetLeft,
pic->VFrame.mOffsetBottom - pic->VFrame.mOffsetTop,
NULL);
pVideoRenderData->hnd_cdx_video_render_init_flag = 1;
pVideoRenderData->mbNeedNotifyDisplaySize = FALSE;
alogd("init video_render, param: displayRect[%d,%d][%dx%d], bufSize[%dx%d], vdecColorFormat[0x%x]",
hwcInitPara.mnDisplayTopX, hwcInitPara.mnDisplayTopY,
hwcInitPara.mnDisplayWidth, hwcInitPara.mnDisplayHeight,
hwcInitPara.mnBufWidth, hwcInitPara.mnBufHeight,
hwcInitPara.mePixelFormat);
/*{
alogd("store first frame,len[%d]", pic->VFrame.mStride[0]);
FILE* pFp = fopen("/mnt/extsd/pic[0].raw", "wb");
fwrite(pic->VFrame.mpVirAddr[0], 1, pic->VFrame.mStride[0], pFp);
fclose(pFp);
}*/
}
else if(VideoRender_SW == pVideoRenderData->VRenderMode)
{
CdxVRSWANWInitPara swANWInitPara;
memset(&swANWInitPara, 0, sizeof(CdxVRSWANWInitPara));
swANWInitPara.mnBufWidth = pic->VFrame.mWidth;
swANWInitPara.mnBufHeight = pic->VFrame.mHeight;
swANWInitPara.mnDisplayWidth = pic->VFrame.mOffsetRight - pic->VFrame.mOffsetLeft;
swANWInitPara.mnDisplayHeight = pic->VFrame.mOffsetBottom - pic->VFrame.mOffsetTop;
swANWInitPara.mePixelFormat = PIXEL_FORMAT_YV12;
pVideoRenderData->hnd_cdx_video_render->init(pVideoRenderData->hnd_cdx_video_render,
pVideoRenderData->VRenderMode, &swANWInitPara, NULL);
pVideoRenderData->hnd_cdx_video_render_init_flag = 1;
pVideoRenderData->mbNeedNotifyDisplaySize = FALSE;
}
else
{
alogw("fatal error! videoRender GUI must init video render at begin!");
pVideoRenderData->state = COMP_StateInvalid;
goto PROCESS_MESSAGE;
}
}
}
if(VideoRender_SW == pVideoRenderData->VRenderMode)
{
//begin dequeue frame, convert.
nRenderRet = pVideoRenderData->hnd_cdx_video_render->dequeue_frame(pVideoRenderData->hnd_cdx_video_render, &pVideoRenderData->mANativeWindowBuffer);
if(CDX_OK == nRenderRet)
{
//lltime_stamp2 = CDX_GetNowUs();
alogw("vdec output pixel_format[0x%x], not support!", pic->VFrame.mPixelFormat);
//need copy to gpu frame.
// lltime_stamp3 = CDX_GetNowUs();
// total_interval += (lltime_stamp3 - lltime_stamp2);
// dec_cnt++;
// alogd("lltime_stamp2[%lld], lltime_stamp3[%lld], interval[%lld]", lltime_stamp2, lltime_stamp3, lltime_stamp3-lltime_stamp2);
// alogd("average_interval=[%lld], [%lld]/[%lld]", total_interval/dec_cnt, total_interval, dec_cnt);
}
else if(CDX_NO_NATIVE_WINDOW == nRenderRet)
{
// mNativeWindow == NULL, we process as dequeue frame success!
alogd("ret[%d], pts[%lld]us, NativeWindow=NULL, consider dequeue frame success!", nRenderRet, pic->VFrame.mpts);
}
else
{
alogw("fatal error! ret[%d], pts[%lld]us, why dequeue frame fail?", nRenderRet, pic->VFrame.mpts);
//if dequeue frame from gui fail, we ReleaseBuffer immediately, consider as display successful.
VideoRenderReleaseFrame(pVideoRenderData, pFrame);
goto PROCESS_MESSAGE;
}
}
media_video_time = pic->VFrame.mpts;
//alogd("newPicture.rotate_angle=%d", newPicture.rotate_angle);
if(pVideoRenderData->render_seeking_flag || (pVideoRenderData->video_rend_flag & VIDEO_RENDER_FIRST_FRAME_FLAG))
{
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf, pVideoRenderData->pAppData, COMP_EventKeyFrameDecoded, 0, 0, (void *)&media_video_time);
pVideoRenderData->render_seeking_flag = 0;
}
if (!(pVideoRenderData->video_rend_flag & VIDEO_RENDER_FIRST_FRAME_FLAG))
{
//****************************************************************************************************//
//* if it is not for wifi display, we need to wait some time for synchronization.
//****************************************************************************************************//
//alogv("av_sync %d, stream_source_type %d", pVideoRenderData->av_sync, pVideoRenderData->stream_source_type);
if(pVideoRenderData->av_sync && hnd_clock_comp)
{
int vpsspeed = 0;
COMP_GetConfig(hnd_clock_comp, COMP_IndexConfigTimeCurrentMediaTime, &time_stamp);
media_clock_time = time_stamp.nTimestamp;
COMP_GetConfig(hnd_clock_comp, COMP_IndexVendorVps, &vpsspeed);
vpsspeed = -vpsspeed;
if (media_video_time > media_clock_time && media_clock_time > 0)
{
int sleep_time = (int)(media_video_time - media_clock_time);
if(sleep_time > 200*1000)
{
alogw("videorender sleep too long[%d]us, media_video_time:%lld media_clock_time:%lld", sleep_time, media_video_time, media_clock_time);
int delayTime = (sleep_time *100/(100+vpsspeed))/1000;
if(delayTime > 3*1000)
{
delayTime = 3*1000;
}
//at least delay 200ms.
if(delayTime>200)
{
usleep(200*1000);
delayTime-=200;
}
TMessage_WaitQueueNotEmpty(&pVideoRenderData->cmd_queue, (unsigned int)delayTime);
}
else if(sleep_time > 0)
{
usleep(sleep_time *100/(100+vpsspeed));
}
else
{
alogw("sleep none!!");
}
}
else if(media_video_time + 100000< media_clock_time && media_clock_time > 0)
{
//decide whether give up this frame. Commonly, we don't want to give up frame. But in vps play,
//when vps > 0, we must give up some frames to guarantee av sync.
if(vpsspeed > 0)
{
alogd("vps[%d], V:[%lld]ms S:[%lld]ms DIFF:[%lld]ms, give up frame!",
vpsspeed, media_video_time/1000, time_stamp.nTimestamp/1000, media_video_time/1000-time_stamp.nTimestamp/1000);
}
}
}
}
//****************************************************************************************************//
//* send the new frame to display.
//****************************************************************************************************//
// hnd_clock_comp->GetConfig(hnd_clock_comp,OMX_IndexConfigTimeCurrentMediaTime, &time_stamp);
// alogv(" V:%lld S:%lld DIFF:%lld", media_video_time/1000, time_stamp.nTimestamp/1000, media_video_time/1000-time_stamp.nTimestamp/1000);
if(VideoRender_HW == pVideoRenderData->VRenderMode)
{
if(pVideoRenderData->mbNeedNotifyDisplaySize)
{
CdxVRFrameInfo frameInfo;
memset(&frameInfo, 0, sizeof(CdxVRFrameInfo));
frameInfo.mnDisplayTopX = pVideoRenderData->mVideoDisplayTopX;
frameInfo.mnDisplayTopY = pVideoRenderData->mVideoDisplayTopY;
frameInfo.mnDisplayWidth = pVideoRenderData->mVideoDisplayWidth;
frameInfo.mnDisplayHeight = pVideoRenderData->mVideoDisplayHeight;
frameInfo.mnBufWidth = pic->VFrame.mWidth;
frameInfo.mnBufHeight = pic->VFrame.mHeight;
pVideoRenderData->hnd_cdx_video_render->update_display_size(pVideoRenderData->hnd_cdx_video_render, &frameInfo);
//notify vdec display width and height
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventVideoDisplaySize,
pVideoRenderData->mVideoDisplayWidth,
pVideoRenderData->mVideoDisplayHeight,
NULL);
pVideoRenderData->mbNeedNotifyDisplaySize = FALSE;
}
MPP_AtraceBegin(ATRACE_TAG_MPP_VO, "ATRACE_TAG_MPP_VO");
pVideoRenderData->hnd_cdx_video_render->render(pVideoRenderData->hnd_cdx_video_render, (void*)pic, pic->mId);
MPP_AtraceEnd(ATRACE_TAG_MPP_VO);
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
int cnt = 0;
struct list_head *pList;
list_for_each(pList, &pVideoRenderData->mVideoInputFrameUsedList)
{
cnt++;
}
if(cnt > pVideoRenderData->mDispBufNum + 1)
{
aloge("fatal error! why VR_HW used frame[%d]>[%d]? check code!", cnt, pVideoRenderData->mDispBufNum + 1);
}
VOCompInputFrame *pEntry;
while(cnt>pVideoRenderData->mDispBufNum)
{
pEntry = list_first_entry(&pVideoRenderData->mVideoInputFrameUsedList, VOCompInputFrame, mList);
VideoRenderReleaseFrame_l(pVideoRenderData, pEntry);
cnt--;
}
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
}
else if(VideoRender_SW == pVideoRenderData->VRenderMode)
{
nRenderRet = pVideoRenderData->hnd_cdx_video_render->enqueue_frame(pVideoRenderData->hnd_cdx_video_render, &pVideoRenderData->mANativeWindowBuffer);
if(nRenderRet != SUCCESS)
{
aloge("fatal error! videoRender_SW queue frame fail!");
}
VideoRenderReleaseFrame(pVideoRenderData, pFrame);
}
else if(VideoRender_GUI == pVideoRenderData->VRenderMode)
{
//need set pFrame to pANativeWindowBuffer;
ANativeWindowBufferCedarXWrapper *pANWBuffer = VideoRenderFindANWBufferByFrame(pVideoRenderData, pFrame);
if(NULL == pANWBuffer)
{
alogw("fatal error! not find ANWBuffer for VideoPicture!");
pVideoRenderData->state = COMP_StateInvalid;
goto PROCESS_MESSAGE;
}
if(pVideoRenderData->mbNeedNotifyDisplaySize)
{
CdxVRFrameInfo frameInfo;
memset(&frameInfo, 0, sizeof(CdxVRFrameInfo));
frameInfo.mnDisplayTopX = pVideoRenderData->mVideoDisplayTopX;
frameInfo.mnDisplayTopY = pVideoRenderData->mVideoDisplayTopY;
frameInfo.mnDisplayWidth = pVideoRenderData->mVideoDisplayWidth;
frameInfo.mnDisplayHeight = pVideoRenderData->mVideoDisplayHeight;
frameInfo.mnBufWidth = pic->VFrame.mWidth;
frameInfo.mnBufHeight = pic->VFrame.mHeight;
pVideoRenderData->hnd_cdx_video_render->update_display_size(pVideoRenderData->hnd_cdx_video_render, &frameInfo);
//notify vdec display width and height
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventVideoDisplaySize,
pVideoRenderData->mVideoDisplayWidth,
pVideoRenderData->mVideoDisplayHeight,
NULL);
pVideoRenderData->mbNeedNotifyDisplaySize = FALSE;
}
nQueueFrameRet = pVideoRenderData->hnd_cdx_video_render->enqueue_frame(pVideoRenderData->hnd_cdx_video_render, pANWBuffer);
if(CDX_OK == nQueueFrameRet)
{
pANWBuffer->mbOccupyFlag = 0;
}
else
{
alogw("fatal error! QueueFrame fail[%d]", nQueueFrameRet);
}
nDequeueFrameRet = pVideoRenderData->hnd_cdx_video_render->dequeue_frame(pVideoRenderData->hnd_cdx_video_render, &pVideoRenderData->mANativeWindowBuffer);
if(SUCCESS == nDequeueFrameRet)
{
ANativeWindowBufferCedarXWrapper *pDequeueANWB = VideoRenderANWBufferComeBack(pVideoRenderData, &pVideoRenderData->mANativeWindowBuffer);
pthread_mutex_lock(&pVideoRenderData->mVideoInputFrameListMutex);
//find VDecCompOutputFrame in mVideoInputFrameUsedList accord to ANativeWindowBufferCedarXWrapper.
VOCompInputFrame *pReturnFrame = VideoRenderFindUsedFrameByANWBuffer(pVideoRenderData, pDequeueANWB);
//return VDecCompOutputFrame to VdecComponent.
VideoRenderReleaseFrame_l(pVideoRenderData, pReturnFrame);
pthread_mutex_unlock(&pVideoRenderData->mVideoInputFrameListMutex);
}
else if(CDX_NO_NATIVE_WINDOW == nDequeueFrameRet)
{
// mNativeWindow == NULL, we process as dequeue frame success!
alogd("NativeWindow=NULL, ret[%d], pts[%lld]us, consider dequeue frame success!", nDequeueFrameRet, pic->VFrame.mpts);
}
else
{
aloge("fatal error! ret[%d], pts[%lld], why dequeue frame fail?", nDequeueFrameRet, pic->VFrame.mpts);
//if dequeue frame from gui fail, we ReleaseBuffer immediately, consider as display successful.
}
}
else
{
alogw("fatal error! pVideoRenderData->VRenderMode[%d]", pVideoRenderData->VRenderMode);
}
if(!pVideoRenderData->mbRenderingStart)
{
//notify rendering start
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf,
pVideoRenderData->pAppData,
COMP_EventRenderingStart,
0,
0,
NULL);
pVideoRenderData->mbRenderingStart = TRUE;
}
pVideoRenderData->last_pts = pic->VFrame.mpts;
//****************************************************************************************************//
//* wait some time for audio start, clear the first frame flag.
//****************************************************************************************************//
if (pVideoRenderData->video_rend_flag & VIDEO_RENDER_FIRST_FRAME_FLAG)
{
if(media_video_time >= 0) //* only if the pts is valid.
{
if(hnd_clock_comp)
{
int time_out = 0;
time_stamp.nPortIndex = p_clock_tunnel->nTunnelPortIndex;
time_stamp.nTimestamp = media_video_time;
alogd("video set config start time to [%lld]us", time_stamp.nTimestamp);
COMP_SetConfig(hnd_clock_comp, COMP_IndexConfigTimeClientStartTime, &time_stamp);
while(pVideoRenderData->start_to_play != TRUE)
{
usleep(20*1000);
if(pVideoRenderData->wait_time_out > 150)
{
alogd(" video wait too long, force clock component to start.");
COMP_SetConfig(hnd_clock_comp, COMP_IndexVendorConfigTimeClientForceStart, &time_stamp);
pVideoRenderData->wait_time_out = 0;
}
pVideoRenderData->wait_time_out++;
if(get_message_count(&pVideoRenderData->cmd_queue) > 0)
{
alogd("video wait to start, meet a message come!");
goto PROCESS_MESSAGE;
}
if(pVideoRenderData->priv_flag & CDX_comp_PRIV_FLAGS_STREAMEOF)
{
alogd("videoRender notify EOF!");
pVideoRenderData->pCallbacks->EventHandler(pVideoRenderData->hSelf, pVideoRenderData->pAppData, COMP_EventBufferFlag, 0, 0, NULL);
pVideoRenderData->state = COMP_StateIdle;
break;
}
}
}
else
{
pVideoRenderData->start_to_play = TRUE;
}
pVideoRenderData->video_rend_flag &= ~VIDEO_RENDER_FIRST_FRAME_FLAG;
}
else
{
alogw("fatal error! frame Pts[%lld]us is invalid!", media_video_time);
}
}
}
else
{
TMessage_WaitQueueNotEmpty(&pVideoRenderData->cmd_queue, 0);
}
}
EXIT:
alogv("Video Render ComponentThread stopped");
return (void*) SUCCESS;
}