5424 lines
240 KiB
C
Executable File
5424 lines
240 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. --
|
|
-- --
|
|
*******************************************************************************/
|
|
|
|
/**
|
|
abbreviation description
|
|
|
|
avsync_rc_swfv: rc: recRenderSink
|
|
swf: switch file
|
|
v: video duration is enough, prepare to switch file.
|
|
avsync_rc_swfa: audio duration is enough, prepare to switch file
|
|
avsync_ch_v: ch: cache.
|
|
v: video
|
|
avsync_cal: cal: calculate. calculate number of video frames which are written more.
|
|
mVideoPtsWriteMoreSt: St: start.
|
|
avsync_bk1: bk: break.
|
|
*/
|
|
|
|
//#include <CDX_LogNDebug.h>
|
|
//#define LOG_NDEBUG 0
|
|
#define LOG_TAG "RecRender_Component"
|
|
#include <utils/plat_log.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdbool.h>
|
|
#include <math.h>
|
|
#include <sys/prctl.h>
|
|
|
|
#include <tmessage.h>
|
|
#include <tsemaphore.h>
|
|
|
|
//#include <type.h>
|
|
//#include <H264encLibApi.h>
|
|
#include <vencoder.h>
|
|
#include <aenc_sw_lib.h>
|
|
#include <TextEncApi.h>
|
|
#include <mp4_mux_lib.h>
|
|
#include <sa_config.h>
|
|
//#include <cedarv_osal_linux.h>
|
|
//#include <type_camera.h>
|
|
#include <record_writer.h>
|
|
//#include <include_system/cedarx_avs_counter.h>
|
|
//#include <DataQuene.h>
|
|
#include <FsWriter.h>
|
|
//#include "RecRenderSink.h"
|
|
//#include "RecRender_cache.h"
|
|
|
|
#include <SystemBase.h>
|
|
//#include <aenc_sw_lib.h>
|
|
#include <cdx_list.h>
|
|
|
|
#include "RecRender_Component.h"
|
|
#include <EncodedStream.h>
|
|
#include <VencCompStream.h>
|
|
#include <AencCompStream.h>
|
|
#include <media_common.h>
|
|
#include <media_common_vcodec.h>
|
|
#include <media_common_acodec.h>
|
|
//#include <media_debug.h>
|
|
|
|
//#define __SAVE_INPUT_BS__
|
|
#ifdef __SAVE_INPUT_BS__
|
|
static FILE *fp_bs;
|
|
#endif
|
|
|
|
#define RECSINK_MAX_PACKET_NUM (256) //(BITSTREAM_FRAME_SIZE+FIFO_LEVEL)
|
|
#define NOTIFY_NEEDNEXTFD_IN_ADVANCE (10*1000) //ms
|
|
|
|
static void* RecRender_ComponentThread(void* pThreadData);
|
|
//extern ERRORTYPE RecRender_ReleaseBuffer(PARAM_IN RECRENDERDATATYPE *pRecRenderData, PARAM_IN RecSinkPacket* pRSPacket);
|
|
|
|
ERRORTYPE copy_MUX_CHN_ATTR_S(MUX_CHN_ATTR_S *pDst, MUX_CHN_ATTR_S *pSrc)
|
|
{
|
|
memcpy(pDst, pSrc, sizeof(MUX_CHN_ATTR_S));
|
|
return SUCCESS;
|
|
}
|
|
|
|
MEDIA_FILE_FORMAT_E map_MUXERMODES_to_MEDIA_FILE_FORMAT_E(MUXERMODES nMuxerMode)
|
|
{
|
|
MEDIA_FILE_FORMAT_E dstFormat;
|
|
switch(nMuxerMode)
|
|
{
|
|
case MUXER_MODE_MP4:
|
|
dstFormat = MEDIA_FILE_FORMAT_MP4;
|
|
break;
|
|
case MUXER_MODE_MP3:
|
|
dstFormat = MEDIA_FILE_FORMAT_MP3;
|
|
break;
|
|
case MUXER_MODE_AAC:
|
|
dstFormat = MEDIA_FILE_FORMAT_AAC;
|
|
break;
|
|
case MUXER_MODE_WAV:
|
|
dstFormat = MEDIA_FILE_FORMAT_WAV;
|
|
break;
|
|
case MUXER_MODE_RAW:
|
|
dstFormat = MEDIA_FILE_FORMAT_RAW;
|
|
break;
|
|
case MUXER_MODE_TS:
|
|
dstFormat = MEDIA_FILE_FORMAT_TS;
|
|
break;
|
|
default:
|
|
dstFormat = MEDIA_FILE_FORMAT_UNKNOWN;
|
|
break;
|
|
}
|
|
return dstFormat;
|
|
}
|
|
|
|
MUXERMODES map_MEDIA_FILE_FORMAT_E_to_MUXERMODES(MEDIA_FILE_FORMAT_E nMuxFileFormat)
|
|
{
|
|
MUXERMODES dstFormat;
|
|
switch(nMuxFileFormat)
|
|
{
|
|
case MEDIA_FILE_FORMAT_MP4:
|
|
dstFormat = MUXER_MODE_MP4;
|
|
break;
|
|
case MEDIA_FILE_FORMAT_MP3:
|
|
dstFormat = MUXER_MODE_MP3;
|
|
break;
|
|
case MEDIA_FILE_FORMAT_AAC:
|
|
dstFormat = MUXER_MODE_AAC;
|
|
break;
|
|
case MEDIA_FILE_FORMAT_WAV:
|
|
dstFormat = MUXER_MODE_WAV;
|
|
break;
|
|
case MEDIA_FILE_FORMAT_RAW:
|
|
dstFormat = MUXER_MODE_RAW;
|
|
break;
|
|
case MEDIA_FILE_FORMAT_TS:
|
|
dstFormat = MUXER_MODE_TS;
|
|
break;
|
|
default:
|
|
dstFormat = MUXER_MODE_MP4;
|
|
break;
|
|
}
|
|
return dstFormat;
|
|
}
|
|
|
|
static int CDXRecoder_WritePacket_CB(void *parent, CDXRecorderBsInfo *bs_info)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE*)parent;
|
|
return pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventBsframeAvailable,
|
|
0,
|
|
0,
|
|
bs_info);
|
|
}
|
|
|
|
ERRORTYPE setRecSinkPacketByVEncCompOutputBuffer(
|
|
PARAM_IN RECRENDERDATATYPE *pRecRenderData,
|
|
PARAM_OUT RecSinkPacket* pRSPacket,
|
|
PARAM_IN EncodedStream* pEncodedStream,
|
|
PARAM_IN int PortIndex)
|
|
{
|
|
if(pRecRenderData->mnBasePts < 0)
|
|
{
|
|
pRecRenderData->mnBasePts = pEncodedStream->nTimeStamp;
|
|
}
|
|
|
|
int iSize0 = 0;
|
|
int iSize1 = 0;
|
|
if (pEncodedStream->nFilledLen > 0)
|
|
{
|
|
if (pEncodedStream->nFilledLen <= pEncodedStream->nBufferLen)
|
|
{
|
|
iSize0 = pEncodedStream->nFilledLen;
|
|
iSize1 = 0;
|
|
}
|
|
else
|
|
{
|
|
iSize0 = pEncodedStream->nBufferLen;
|
|
iSize1 = pEncodedStream->nFilledLen - pEncodedStream->nBufferLen;
|
|
}
|
|
}
|
|
|
|
pRSPacket->mId = pEncodedStream->nID;
|
|
pRSPacket->mStreamType = CODEC_TYPE_VIDEO;
|
|
pRSPacket->mFlags = 0;
|
|
pRSPacket->mFlags |= (pEncodedStream->nFlags & CEDARV_FLAG_KEYFRAME)? AVPACKET_FLAG_KEYFRAME : 0;
|
|
pRSPacket->mPts = pEncodedStream->nTimeStamp/* - pRecRenderData->mnBasePts*/;
|
|
if(iSize0 > 0)
|
|
{
|
|
pRSPacket->mpData0 = (char*)pEncodedStream->pBuffer;
|
|
}
|
|
else
|
|
{
|
|
pRSPacket->mpData0 = NULL;
|
|
}
|
|
pRSPacket->mSize0 = iSize0;
|
|
if(iSize1 > 0)
|
|
{
|
|
pRSPacket->mpData1 = (char*)pEncodedStream->pBufferExtra;
|
|
}
|
|
else
|
|
{
|
|
pRSPacket->mpData1 = NULL;
|
|
}
|
|
pRSPacket->mSize1 = iSize1;
|
|
pRSPacket->mCurrQp = pEncodedStream->video_frame_info.CurrQp;
|
|
pRSPacket->mavQp = pEncodedStream->video_frame_info.avQp;
|
|
pRSPacket->mnGopIndex = pEncodedStream->video_frame_info.nGopIndex;
|
|
pRSPacket->mnFrameIndex = pEncodedStream->video_frame_info.nFrameIndex;
|
|
pRSPacket->mnTotalIndex = pEncodedStream->video_frame_info.nTotalIndex;
|
|
//pRSPacket->mSourceType = SOURCE_TYPE_COMPONENT;
|
|
pRSPacket->mRefCnt = 0;
|
|
|
|
pRSPacket->mStreamId = PortIndex;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
ERRORTYPE setRecSinkPacketByAEncCompOutputBuffer(PARAM_IN RECRENDERDATATYPE *pRecRenderData, PARAM_OUT RecSinkPacket* pRSPacket, PARAM_IN EncodedStream* pEncodedStream, int PortIndex)
|
|
{
|
|
if(pRecRenderData->mnAudioBasePts < 0)
|
|
{
|
|
pRecRenderData->mnAudioBasePts = pEncodedStream->nTimeStamp;
|
|
}
|
|
pRSPacket->mId = pEncodedStream->nID;
|
|
pRSPacket->mStreamType = CODEC_TYPE_AUDIO;
|
|
pRSPacket->mFlags = 0;
|
|
pRSPacket->mPts = pEncodedStream->nTimeStamp/* - pRecRenderData->mnAudioBasePts*/;
|
|
pRSPacket->mpData0 = (char*)pEncodedStream->pBuffer;
|
|
pRSPacket->mSize0 = pEncodedStream->nFilledLen;
|
|
pRSPacket->mpData1 = (char*)pEncodedStream->pBufferExtra;
|
|
pRSPacket->mSize1 = (int)pEncodedStream->nBufferExtraLen;
|
|
pRSPacket->mCurrQp = 0;
|
|
pRSPacket->mavQp = 0;
|
|
pRSPacket->mnGopIndex = 0;
|
|
pRSPacket->mnFrameIndex = 0;
|
|
pRSPacket->mnTotalIndex = 0;
|
|
//pRSPacket->mSourceType = SOURCE_TYPE_COMPONENT;
|
|
pRSPacket->mRefCnt = 0;
|
|
|
|
pRSPacket->mStreamId = PortIndex;
|
|
return SUCCESS;
|
|
}
|
|
|
|
ERRORTYPE setRecSinkPacketByTEncCompOutputBuffer(PARAM_IN RECRENDERDATATYPE *pRecRenderData, PARAM_OUT RecSinkPacket* pRSPacket, PARAM_IN EncodedStream* pEncodedStream, int PortIndex)
|
|
{
|
|
if(pRecRenderData->mnTextBasePts < 0)
|
|
{
|
|
pRecRenderData->mnTextBasePts = pEncodedStream->nTimeStamp;
|
|
}
|
|
pRSPacket->mId = pEncodedStream->nID;
|
|
pRSPacket->mStreamType = CODEC_TYPE_TEXT;
|
|
pRSPacket->mFlags = 0;
|
|
pRSPacket->mPts = pEncodedStream->nTimeStamp/* - pRecRenderData->mnTextBasePts*/;
|
|
pRSPacket->mpData0 = (char*)pEncodedStream->pBuffer;
|
|
pRSPacket->mSize0 = (int)pEncodedStream->nBufferLen;
|
|
pRSPacket->mpData1 = (char*)pEncodedStream->pBufferExtra;
|
|
pRSPacket->mSize1 = (int)pEncodedStream->nBufferExtraLen;
|
|
pRSPacket->mCurrQp = 0;
|
|
pRSPacket->mavQp = 0;
|
|
pRSPacket->mnGopIndex = 0;
|
|
pRSPacket->mnFrameIndex = 0;
|
|
pRSPacket->mnTotalIndex = 0;
|
|
//pRSPacket->mSourceType = SOURCE_TYPE_COMPONENT;
|
|
pRSPacket->mRefCnt = 0;
|
|
|
|
pRSPacket->mStreamId = PortIndex;
|
|
return SUCCESS;
|
|
}
|
|
|
|
ERRORTYPE RecRender_GetVideoBuffer(
|
|
PARAM_IN RECRENDERDATATYPE *pRecRenderData,
|
|
PARAM_OUT RecSinkPacket* pRSPacket)
|
|
{
|
|
ERRORTYPE eError;
|
|
pthread_mutex_lock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
if (!list_empty(&pRecRenderData->mVideoInputFrameReadyList))
|
|
{
|
|
ENCODER_NODE_T *pEntry = list_first_entry(&pRecRenderData->mVideoInputFrameReadyList, ENCODER_NODE_T, mList);
|
|
setRecSinkPacketByVEncCompOutputBuffer(pRecRenderData, pRSPacket, &pEntry->stEncodedStream, pEntry->mPortIndex);
|
|
pEntry->mUsedRefCnt = 1;
|
|
list_move_tail(&pEntry->mList, &pRecRenderData->mVideoInputFrameUsedList);
|
|
eError = SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
eError = ERR_MUX_NOMEM;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRender_GetAudioBuffer(
|
|
PARAM_IN RECRENDERDATATYPE *pRecRenderData,
|
|
PARAM_INOUT RecSinkPacket* pRSPacket)
|
|
|
|
{
|
|
ERRORTYPE eError;
|
|
pthread_mutex_lock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
if (!list_empty(&pRecRenderData->mAudioInputFrameReadyList))
|
|
{
|
|
ENCODER_NODE_T *pEntry = list_first_entry(&pRecRenderData->mAudioInputFrameReadyList, ENCODER_NODE_T, mList);
|
|
setRecSinkPacketByAEncCompOutputBuffer(pRecRenderData, pRSPacket, &pEntry->stEncodedStream, pEntry->mPortIndex);
|
|
pEntry->mUsedRefCnt = 1;
|
|
list_move_tail(&pEntry->mList, &pRecRenderData->mAudioInputFrameUsedList);
|
|
eError = SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
eError = ERR_MUX_NOMEM;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
return eError;
|
|
}
|
|
ERRORTYPE RecRender_GetTextBuffer(
|
|
PARAM_IN RECRENDERDATATYPE *pRecRenderData,
|
|
PARAM_INOUT RecSinkPacket* pRSPacket)
|
|
{
|
|
ERRORTYPE eError;
|
|
pthread_mutex_lock(&pRecRenderData->mTextInputFrameListMutex);
|
|
if(!list_empty(&pRecRenderData->mTextInputFrameReadyList))
|
|
{
|
|
ENCODER_NODE_T *pEntry = list_first_entry(&pRecRenderData->mTextInputFrameReadyList, ENCODER_NODE_T, mList);
|
|
setRecSinkPacketByTEncCompOutputBuffer(pRecRenderData, pRSPacket, &pEntry->stEncodedStream, pEntry->mPortIndex);
|
|
pEntry->mUsedRefCnt = 1;
|
|
list_move_tail(&pEntry->mList, &pRecRenderData->mTextInputFrameUsedList);
|
|
eError = SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
eError = ERR_MUX_NOMEM;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRender_RefBuffer(
|
|
PARAM_IN RECRENDERDATATYPE *pRecRenderData,
|
|
PARAM_IN RecSinkPacket* pRSPacket)
|
|
{
|
|
ERRORTYPE eError = SUCCESS;
|
|
if(CODEC_TYPE_VIDEO == pRSPacket->mStreamType)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
ENCODER_NODE_T *pEntry;
|
|
BOOL bFindFlag = FALSE;
|
|
list_for_each_entry(pEntry, &pRecRenderData->mVideoInputFrameUsedList, mList)
|
|
{
|
|
if((pEntry->stEncodedStream.nID == pRSPacket->mId) && (pEntry->mPortIndex == pRSPacket->mStreamId))
|
|
{
|
|
bFindFlag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (bFindFlag)
|
|
{
|
|
pEntry->mUsedRefCnt++;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! not find vFrmId[%d-%d-%d] in used list.", pRSPacket->mStreamId, pRSPacket->mId, pRSPacket->mRefCnt);
|
|
eError = ERR_MUX_UNEXIST;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
}
|
|
else if(CODEC_TYPE_AUDIO == pRSPacket->mStreamType)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
ENCODER_NODE_T *pEntry;
|
|
BOOL bFindFlag = FALSE;
|
|
list_for_each_entry(pEntry, &pRecRenderData->mAudioInputFrameUsedList, mList)
|
|
{
|
|
if(pEntry->stEncodedStream.nID == pRSPacket->mId)
|
|
{
|
|
bFindFlag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(bFindFlag)
|
|
{
|
|
pEntry->mUsedRefCnt++;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! not find AFrmId[%d] in used list.", pRSPacket->mId);
|
|
eError = ERR_MUX_UNEXIST;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
}
|
|
else if(CODEC_TYPE_TEXT == pRSPacket->mStreamType)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mTextInputFrameListMutex);
|
|
ENCODER_NODE_T *pEntry;
|
|
BOOL bFindFlag = FALSE;
|
|
list_for_each_entry(pEntry, &pRecRenderData->mTextInputFrameUsedList, mList)
|
|
{
|
|
if(pEntry->stEncodedStream.nID == pRSPacket->mId)
|
|
{
|
|
bFindFlag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(bFindFlag)
|
|
{
|
|
pEntry->mUsedRefCnt++;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! not find TFrmId[%d] in used list.", pRSPacket->mId);
|
|
eError = ERR_MUX_UNEXIST;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! invalid streamType[%d]", pRSPacket->mStreamType);
|
|
eError = ERR_MUX_UNEXIST;
|
|
}
|
|
return eError;
|
|
}
|
|
ERRORTYPE RecRender_ReleaseBuffer(
|
|
PARAM_IN RECRENDERDATATYPE *pRecRenderData,
|
|
PARAM_IN RecSinkPacket* pRSPacket)
|
|
{
|
|
ERRORTYPE eRet = SUCCESS;
|
|
if (CODEC_TYPE_AUDIO == pRSPacket->mStreamType)
|
|
{
|
|
//alogd("pRSPacket->mStreamId: %d", pRSPacket->mStreamId);
|
|
}
|
|
if (CODEC_TYPE_VIDEO == pRSPacket->mStreamType)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
ENCODER_NODE_T *pEntry;
|
|
BOOL bFindFlag = FALSE;
|
|
list_for_each_entry(pEntry, &pRecRenderData->mVideoInputFrameUsedList, mList)
|
|
{
|
|
if((pEntry->stEncodedStream.nID == pRSPacket->mId) && (pEntry->mPortIndex == pRSPacket->mStreamId))
|
|
{
|
|
bFindFlag = TRUE;
|
|
//alogd("pEntry->mPortIndex: %d", pEntry->mPortIndex);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// if((pEntry->stEncodedStream.nID == pRSPacket->mId) && (pEntry->mPortIndex != pRSPacket->mStreamId))
|
|
// {
|
|
// alogd("we catch it! vframeId[%d-%d-%d]!=[%d-%d-%d]",
|
|
// pRSPacket->mStreamId, pRSPacket->mId, pRSPacket->mRefCnt, pEntry->mPortIndex, pEntry->stEncodedStream.nID, pEntry->mUsedRefCnt);
|
|
// }
|
|
}
|
|
}
|
|
if(bFindFlag)
|
|
{
|
|
pEntry->mUsedRefCnt--;
|
|
if (pEntry->mUsedRefCnt == 0)
|
|
{
|
|
list_del(&pEntry->mList);
|
|
//list_move_tail(&pEntry->mList, &pRecRenderData->mVideoInputFrameIdleList);
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
|
|
if(pRecRenderData->mInputPortTunnelFlag[pRSPacket->mStreamId])
|
|
{
|
|
//MM_COMPONENTTYPE *pInPortTunnelComp = (MM_COMPONENTTYPE*)(pRecRenderData->sInPortTunnelInfo[RECR_PORT_INDEX_VIDEO].hTunnel);
|
|
MM_COMPONENTTYPE *pInPortTunnelComp = (MM_COMPONENTTYPE*)(pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].hTunnel);
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
//obh.nOutputPortIndex = pRecRenderData->sInPortTunnelInfo[RECR_PORT_INDEX_VIDEO].nTunnelPortIndex;
|
|
//obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[RECR_PORT_INDEX_VIDEO].nPortIndex;
|
|
|
|
obh.nOutputPortIndex = pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].nTunnelPortIndex;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].nPortIndex;
|
|
obh.pOutputPortPrivate = (void*)&pEntry->stEncodedStream;
|
|
|
|
//alogd("VideoBuff StreamId: %d", pRSPacket->mStreamId);
|
|
eRet = COMP_FillThisBuffer(pInPortTunnelComp, &obh);
|
|
if(eRet != SUCCESS)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] fill this buffer fail[0x%x], video frame id=[%d-%d-%d], check code!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
eRet, pEntry->mPortIndex, pEntry->stEncodedStream.nID, pEntry->mUsedRefCnt);
|
|
pthread_mutex_lock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
list_add_tail(&pEntry->mList, &pRecRenderData->mVideoInputFrameUsedList);
|
|
//list_move_tail(&pEntry->mList, &pRecRenderData->mVideoInputFrameUsedList);
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
}
|
|
else
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
list_add_tail(&pEntry->mList, &pRecRenderData->mVideoInputFrameIdleList);
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].nPortIndex;
|
|
obh.pAppPrivate = (void*)&pEntry->stEncodedStream;
|
|
if(pEntry->mPortIndex != obh.nInputPortIndex)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] video streamId[%d!=%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pEntry->mPortIndex, obh.nInputPortIndex);
|
|
}
|
|
pRecRenderData->pCallbacks->EmptyBufferDone(pRecRenderData->hSelf, pRecRenderData->pAppData, &obh);
|
|
pthread_mutex_lock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
list_add_tail(&pEntry->mList, &pRecRenderData->mVideoInputFrameIdleList);
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(pEntry->mUsedRefCnt < 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] vfrm[%d-%d] usedRefCnt[%d]<0, check code!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pEntry->mPortIndex, pEntry->stEncodedStream.nID, pEntry->mUsedRefCnt);
|
|
eRet = ERR_MUX_NOT_PERM;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] not find VFrmId[%d-%d-%d] in used list.",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRSPacket->mStreamId, pRSPacket->mId, pRSPacket->mRefCnt);
|
|
eRet = ERR_MUX_UNEXIST;
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
}
|
|
}
|
|
else if(CODEC_TYPE_AUDIO == pRSPacket->mStreamType)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
ENCODER_NODE_T *pEntry;
|
|
BOOL bFindFlag = FALSE;
|
|
list_for_each_entry(pEntry, &pRecRenderData->mAudioInputFrameUsedList, mList)
|
|
{
|
|
if(pEntry->stEncodedStream.nID == pRSPacket->mId)
|
|
{
|
|
bFindFlag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(bFindFlag)
|
|
{
|
|
pEntry->mUsedRefCnt--;
|
|
if(pEntry->mUsedRefCnt == 0)
|
|
{
|
|
list_del(&pEntry->mList);
|
|
//list_move_tail(&pEntry->mList, &pRecRenderData->mAudioInputFrameIdleList);
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
if(pRecRenderData->mInputPortTunnelFlag[pRSPacket->mStreamId])
|
|
{
|
|
MM_COMPONENTTYPE *pInPortTunnelComp = (MM_COMPONENTTYPE*)(pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].hTunnel);
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nOutputPortIndex = pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].nTunnelPortIndex;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].nPortIndex;
|
|
obh.pOutputPortPrivate = (void*)&pEntry->stEncodedStream;
|
|
//alogd("Audio Buffer streamId: %d", pRSPacket->mStreamId);
|
|
eRet = COMP_FillThisBuffer(pInPortTunnelComp, &obh);
|
|
if (eRet != SUCCESS)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] fill this buffer fail[0x%x], audio frame id=[%d], check code!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
eRet, pEntry->stEncodedStream.nID);
|
|
pthread_mutex_lock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
list_add_tail(&pEntry->mList, &pRecRenderData->mAudioInputFrameUsedList);
|
|
//list_move_tail(&pEntry->mList, &pRecRenderData->mAudioInputFrameUsedList);
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
}
|
|
else
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
list_add_tail(&pEntry->mList, &pRecRenderData->mAudioInputFrameIdleList);
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].nPortIndex;
|
|
obh.pAppPrivate = (void*)&pEntry->stEncodedStream;
|
|
if(pEntry->mPortIndex != obh.nInputPortIndex)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] audio streamId[%d!=%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pEntry->mPortIndex, obh.nInputPortIndex);
|
|
}
|
|
pRecRenderData->pCallbacks->EmptyBufferDone(pRecRenderData->hSelf, pRecRenderData->pAppData, &obh);
|
|
pthread_mutex_lock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
list_add_tail(&pEntry->mList, &pRecRenderData->mAudioInputFrameIdleList);
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(pEntry->mUsedRefCnt < 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] usedRefCnt[%d]<0, check code!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,pEntry->mUsedRefCnt);
|
|
eRet = ERR_MUX_NOT_PERM;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] not find AFrmId[%d] in used list.",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRSPacket->mId);
|
|
eRet = ERR_MUX_UNEXIST;
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
}
|
|
}
|
|
else if(CODEC_TYPE_TEXT == pRSPacket->mStreamType)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mTextInputFrameListMutex);
|
|
ENCODER_NODE_T *pEntry;
|
|
BOOL bFindFlag = FALSE;
|
|
list_for_each_entry(pEntry, &pRecRenderData->mTextInputFrameUsedList, mList)
|
|
{
|
|
if(pEntry->stEncodedStream.nID == pRSPacket->mId)
|
|
{
|
|
bFindFlag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(bFindFlag)
|
|
{
|
|
pEntry->mUsedRefCnt--;
|
|
if(pEntry->mUsedRefCnt == 0)
|
|
{
|
|
list_del(&pEntry->mList);
|
|
//list_move_tail(&pEntry->mList, &pRecRenderData->mTextInputFrameIdleList);
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
|
|
if(pRecRenderData->mInputPortTunnelFlag[pRSPacket->mStreamId])
|
|
{
|
|
MM_COMPONENTTYPE *pInPortTunnelComp = (MM_COMPONENTTYPE*)(pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].hTunnel);
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nOutputPortIndex = pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].nTunnelPortIndex;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].nPortIndex;
|
|
obh.pOutputPortPrivate = (void*)pEntry;
|
|
eRet = COMP_FillThisBuffer(pInPortTunnelComp, &obh);
|
|
if(eRet != SUCCESS)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] fill this buffer fail[0x%x], text frame id=[%d], check code!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
eRet, pEntry->stEncodedStream.nID);
|
|
pthread_mutex_lock(&pRecRenderData->mTextInputFrameListMutex);
|
|
list_add_tail(&pEntry->mList, &pRecRenderData->mTextInputFrameUsedList);
|
|
//list_move_tail(&pEntry->mList, &pRecRenderData->mTextInputFrameUsedList);
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
}
|
|
else
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mTextInputFrameListMutex);
|
|
list_add_tail(&pEntry->mList, &pRecRenderData->mTextInputFrameIdleList);
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pRSPacket->mStreamId].nPortIndex;
|
|
obh.pAppPrivate = (void*)&pEntry->stEncodedStream;
|
|
if(pEntry->mPortIndex != obh.nInputPortIndex)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] text streamId[%d!=%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pEntry->mPortIndex, obh.nInputPortIndex);
|
|
}
|
|
pRecRenderData->pCallbacks->EmptyBufferDone(pRecRenderData->hSelf, pRecRenderData->pAppData, &obh);
|
|
pthread_mutex_lock(&pRecRenderData->mTextInputFrameListMutex);
|
|
list_add_tail(&pEntry->mList, &pRecRenderData->mTextInputFrameIdleList);
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(pEntry->mUsedRefCnt < 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] usedRefCnt[%d]<0, check code!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pEntry->mUsedRefCnt);
|
|
eRet = ERR_MUX_NOT_PERM;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] not find TFrmId[%d] in used list.",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRSPacket->mId);
|
|
eRet = ERR_MUX_UNEXIST;
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] invalid streamType[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRSPacket->mStreamType);
|
|
eRet = ERR_MUX_NOT_PERM;
|
|
}
|
|
return eRet;
|
|
}
|
|
|
|
ERRORTYPE RecRenderGetPortDefinition(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_INOUT COMP_PARAM_PORTDEFINITIONTYPE *pPortDef)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
unsigned int portIdx = pPortDef->nPortIndex;
|
|
|
|
if (portIdx < pRecRenderData->sPortParam.nPorts)
|
|
{
|
|
memcpy(pPortDef, &pRecRenderData->sInPortDef[portIdx], sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
|
|
}
|
|
else
|
|
eError = ERR_MUX_ILLEGAL_PARAM;
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderSetPortDefinition(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN COMP_PARAM_PORTDEFINITIONTYPE *pPortDef)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
unsigned int portIndex = pPortDef->nPortIndex;
|
|
if (portIndex < pRecRenderData->sPortParam.nPorts)
|
|
{
|
|
memcpy(&pRecRenderData->sInPortDef[portIndex], pPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE));
|
|
}
|
|
else
|
|
eError = ERR_MUX_ILLEGAL_PARAM;
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderGetCompBufferSupplier(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_INOUT COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
//find nPortIndex
|
|
BOOL bFindFlag = FALSE;
|
|
int i;
|
|
for(i=0; i<MAX_REC_RENDER_PORTS; i++)
|
|
{
|
|
if(pRecRenderData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex)
|
|
{
|
|
bFindFlag = TRUE;
|
|
memcpy(pPortBufSupplier, &pRecRenderData->sPortBufSupplier[i], sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE));
|
|
break;
|
|
}
|
|
}
|
|
if(bFindFlag)
|
|
{
|
|
eError = SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
eError = ERR_MUX_ILLEGAL_PARAM;
|
|
}
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderSetCompBufferSupplier(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
//find nPortIndex
|
|
BOOL bFindFlag = FALSE;
|
|
int i;
|
|
for(i=0; i<MAX_REC_RENDER_PORTS; i++)
|
|
{
|
|
if(pRecRenderData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex)
|
|
{
|
|
bFindFlag = TRUE;
|
|
memcpy(&pRecRenderData->sPortBufSupplier[i], pPortBufSupplier, sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE));
|
|
break;
|
|
}
|
|
}
|
|
if(bFindFlag)
|
|
{
|
|
eError = SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
eError = ERR_MUX_ILLEGAL_PARAM;
|
|
}
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderGetPortParam(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_OUT COMP_PORT_PARAM_TYPE *pPortParam)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
memcpy(pPortParam, &pRecRenderData->sPortParam, sizeof(COMP_PORT_PARAM_TYPE));
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderGetMPPChannelInfo(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_OUT MPP_CHN_S *pChn)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
ERRORTYPE eError = SUCCESS;
|
|
copy_MPP_CHN_S(pChn, &pRecRenderData->mMppChnInfo);
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderSetMPPChannelInfo(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN MPP_CHN_S *pChn)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
copy_MPP_CHN_S(&pRecRenderData->mMppChnInfo, pChn);
|
|
return SUCCESS;
|
|
}
|
|
|
|
ERRORTYPE RecRenderGetTunnelInfo(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_INOUT COMP_INTERNAL_TUNNELINFOTYPE *pTunnelInfo)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
ERRORTYPE eError = ERR_MUX_UNEXIST;
|
|
int i;
|
|
for(i=0; i<MAX_REC_RENDER_PORTS; i++)
|
|
{
|
|
if(pRecRenderData->sInPortTunnelInfo[i].nPortIndex == pTunnelInfo->nPortIndex)
|
|
{
|
|
memcpy(pTunnelInfo, &pRecRenderData->sInPortTunnelInfo[i], sizeof(COMP_INTERNAL_TUNNELINFOTYPE));
|
|
eError = SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderGetChnAttr(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_OUT MUX_CHN_ATTR_S *pChnAttr)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
copy_MUX_CHN_ATTR_S(pChnAttr, &pRecRenderData->mChnAttr);
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderSetChnAttr(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN MUX_CHN_ATTR_S *pChnAttr)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
if(COMP_StateLoaded==pRecRenderData->state || COMP_StateIdle==pRecRenderData->state)
|
|
{
|
|
copy_MUX_CHN_ATTR_S(&pRecRenderData->mChnAttr, pChnAttr);
|
|
|
|
//MediaDebugLoadMppMuxParams(pRecRenderData, NULL);
|
|
|
|
pRecRenderData->mRecordMode = RECORDER_MODE_NONE;
|
|
if(pChnAttr->mVideoAttrValidNum > 0)
|
|
{
|
|
pRecRenderData->mRecordMode |= RECORDER_MODE_VIDEO;
|
|
}
|
|
for (int VideoInfoIndex = 0; VideoInfoIndex < pRecRenderData->mChnAttr.mVideoAttrValidNum; VideoInfoIndex++)
|
|
{
|
|
//config media_inf
|
|
if(pRecRenderData->mChnAttr.mVideoAttr[VideoInfoIndex].mVideoEncodeType != PT_MAX)
|
|
{
|
|
pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].nHeight = pRecRenderData->mChnAttr.mVideoAttr[VideoInfoIndex].mHeight;
|
|
pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].nWidth = pRecRenderData->mChnAttr.mVideoAttr[VideoInfoIndex].mWidth;
|
|
pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].uVideoFrmRate = pRecRenderData->mChnAttr.mVideoAttr[VideoInfoIndex].mVideoFrmRate;
|
|
pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].create_time = pRecRenderData->mChnAttr.mVideoAttr[VideoInfoIndex].mCreateTime;
|
|
pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].maxKeyInterval = pRecRenderData->mChnAttr.mVideoAttr[VideoInfoIndex].mMaxKeyInterval;
|
|
pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].mVideoEncodeType = map_PAYLOAD_TYPE_E_to_VENC_CODEC_TYPE(pRecRenderData->mChnAttr.mVideoAttr[VideoInfoIndex].mVideoEncodeType);
|
|
pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].rotate_degree = pRecRenderData->mChnAttr.mVideoAttr[VideoInfoIndex].mRotateDegree;
|
|
}
|
|
}
|
|
pRecRenderData->media_inf.mVideoInfoValidNum = pRecRenderData->mChnAttr.mVideoAttrValidNum;
|
|
|
|
if(pRecRenderData->mChnAttr.mAudioEncodeType != PT_MAX)
|
|
{
|
|
pRecRenderData->mRecordMode |= RECORDER_MODE_AUDIO;
|
|
}
|
|
if(PT_TEXT == pRecRenderData->mChnAttr.mTextEncodeType)
|
|
{
|
|
pRecRenderData->mRecordMode |= RECORDER_MODE_TEXT;
|
|
}
|
|
if(pRecRenderData->mChnAttr.mAudioEncodeType != PT_MAX)
|
|
{
|
|
pRecRenderData->media_inf.channels = pRecRenderData->mChnAttr.mChannels;
|
|
pRecRenderData->media_inf.bits_per_sample = pRecRenderData->mChnAttr.mBitsPerSample;
|
|
pRecRenderData->media_inf.frame_size = pRecRenderData->mChnAttr.mSamplesPerFrame;
|
|
pRecRenderData->media_inf.sample_rate = pRecRenderData->mChnAttr.mSampleRate;
|
|
pRecRenderData->media_inf.audio_encode_type = map_PAYLOAD_TYPE_E_to_AUDIO_ENCODER_TYPE(pRecRenderData->mChnAttr.mAudioEncodeType);
|
|
}
|
|
if(PT_TEXT == pRecRenderData->mChnAttr.mTextEncodeType)
|
|
{
|
|
pRecRenderData->media_inf.text_encode_type = TEXT_ENCODER_GGAD;
|
|
pRecRenderData->media_inf.geo_available = 1;
|
|
}
|
|
pRecRenderData->nCallbackOutFlag = pRecRenderData->mChnAttr.mCallbackOutFlag;
|
|
}
|
|
else if(COMP_StateExecuting==pRecRenderData->state || COMP_StatePause==pRecRenderData->state)
|
|
{
|
|
//only process dynamic changing of some params
|
|
//(1) max file duration, current file takes effect.
|
|
if (pRecRenderData->mChnAttr.mMaxFileDuration != pChnAttr->mMaxFileDuration)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mJudgeSwitchlock);
|
|
if(pRecRenderData->bNeedSw || pRecRenderData->bNeedSwAudio)
|
|
{
|
|
alogd("muxChn[%d-%d] are in switch file process[%d-%d], can't change file duration now",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->bNeedSw, pRecRenderData->bNeedSwAudio);
|
|
eError = ERR_MUX_NOT_PERM;
|
|
}
|
|
else
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mMuxerInitlock);
|
|
alogd("muxChn[%d-%d] change max file duration[%lld->%lld]ms", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mChnAttr.mMaxFileDuration, pChnAttr->mMaxFileDuration);
|
|
//pthread_mutex_lock(&pRecRenderData->mutex_reset_writer_lock);
|
|
pRecRenderData->mChnAttr.mMaxFileDuration = pChnAttr->mMaxFileDuration;
|
|
|
|
if(pRecRenderData->mbMuxerInit)
|
|
{
|
|
if(pRecRenderData->mChnAttr.mMaxFileDuration > pRecRenderData->mCurMaxFileDuration)
|
|
{
|
|
pRecRenderData->mCurFileEndTm += (pRecRenderData->mChnAttr.mMaxFileDuration - pRecRenderData->mCurMaxFileDuration);
|
|
alogd("change file duration long: muxChn[%d-%d] Dur:[%lld->%lld]ms newFileEndTm:%lldms",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mCurMaxFileDuration,
|
|
pRecRenderData->mChnAttr.mMaxFileDuration, pRecRenderData->mCurFileEndTm);
|
|
pRecRenderData->mCurMaxFileDuration = pRecRenderData->mChnAttr.mMaxFileDuration;
|
|
}
|
|
else if(pRecRenderData->mChnAttr.mMaxFileDuration < pRecRenderData->mCurMaxFileDuration)
|
|
{
|
|
pRecRenderData->mCurFileEndTm -= (pRecRenderData->mCurMaxFileDuration - pRecRenderData->mChnAttr.mMaxFileDuration);
|
|
alogd("change file duration short: muxChn[%d] Dur:[%lld->%lld]ms newFileEndTm:%lldms",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mCurMaxFileDuration,
|
|
pRecRenderData->mChnAttr.mMaxFileDuration, pRecRenderData->mCurFileEndTm);
|
|
pRecRenderData->mCurMaxFileDuration = pRecRenderData->mChnAttr.mMaxFileDuration;
|
|
}
|
|
}
|
|
//pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
pthread_mutex_unlock(&pRecRenderData->mMuxerInitlock);
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mJudgeSwitchlock);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] cannot set chnAttr in wrong state[0x%x]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->state);
|
|
eError = ERR_MUX_INCORRECT_STATE_OPERATION;
|
|
}
|
|
return eError;
|
|
}
|
|
|
|
static ERRORTYPE RecRenderSetFd(COMP_HANDLETYPE hComponent, CdxFdT *pCdxFd)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
if(pRecRenderData->nOutputFd >= 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] nOutputFd[%d]>=0", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->nOutputFd);
|
|
close(pRecRenderData->nOutputFd);
|
|
pRecRenderData->nOutputFd = -1;
|
|
}
|
|
if(pCdxFd->mFd >= 0)
|
|
{
|
|
pRecRenderData->nOutputFd = dup(pCdxFd->mFd);
|
|
pRecRenderData->nFallocateLen = pCdxFd->mnFallocateLen;
|
|
//pRecRenderSink->nOutputFd = dup2SeldomUsedFd(pCdxSink->nOutputFd);
|
|
alogd("muxChn[%d-%d] dup fd[%d]->[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pCdxFd->mFd, pRecRenderData->nOutputFd);
|
|
}
|
|
else
|
|
{
|
|
aloge("muxChn[%d-%d] fd[%d] < 0!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pCdxFd->mFd);
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
ERRORTYPE RecRenderSendCommand(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN COMP_COMMANDTYPE Cmd,
|
|
PARAM_IN unsigned int nParam1,
|
|
PARAM_IN void* pCmdData)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
CompInternalMsgType eCmd;
|
|
ERRORTYPE eError = SUCCESS;
|
|
message_t msg;
|
|
void* pMsgData = NULL;
|
|
int nMsgDataSize = 0;
|
|
memset(&msg, 0, sizeof(message_t));
|
|
|
|
alogv("RecRenderSendCommand: %d", Cmd);
|
|
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
|
|
if (pRecRenderData->state == COMP_StateInvalid)
|
|
{
|
|
alogd("stateInvalid deny command[0x%x]", Cmd);
|
|
eError = ERR_MUX_INVALIDSTATE;
|
|
goto OMX_CONF_CMD_BAIL;
|
|
}
|
|
|
|
switch (Cmd)
|
|
{
|
|
case COMP_CommandStateSet:
|
|
eCmd = SetState;
|
|
break;
|
|
|
|
case COMP_CommandFlush:
|
|
eCmd = Flush;
|
|
break;
|
|
|
|
default:
|
|
aloge("fatal error! unknown command[0x%x]", Cmd);
|
|
eCmd = -1;
|
|
break;
|
|
}
|
|
|
|
msg.command = eCmd;
|
|
msg.para0 = nParam1;
|
|
msg.mpData = pMsgData;
|
|
msg.mDataSize = nMsgDataSize;
|
|
putMessageWithData(&pRecRenderData->cmd_queue, &msg);
|
|
OMX_CONF_CMD_BAIL:
|
|
return eError;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
ERRORTYPE RecRenderGetState(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_OUT COMP_STATETYPE* pState) {
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
//pthread_mutex_lock(&pRecRenderData->mStateMutex);
|
|
*pState = pRecRenderData->state;
|
|
//pthread_mutex_unlock(&pRecRenderData->mStateMutex);
|
|
|
|
//OMX_CONF_CMD_BAIL:
|
|
return eError;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
ERRORTYPE RecRenderSetCallbacks(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN COMP_CALLBACKTYPE* pCallbacks,
|
|
PARAM_IN void* pAppData)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
|
|
pRecRenderData->pCallbacks = pCallbacks;
|
|
pRecRenderData->pAppData = pAppData;
|
|
|
|
//OMX_CONF_CMD_BAIL:
|
|
return eError;
|
|
}
|
|
|
|
/**
|
|
set spspps.
|
|
|
|
@return
|
|
SUCCESS
|
|
FAILURE
|
|
ERR_MUX_NOMEM
|
|
*/
|
|
ERRORTYPE RecRenderSetH264SpsPpsInfo(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN VencHeaderDataParam *pVencHeaderDataParam)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
bool bFindFlag = false;
|
|
|
|
if (0 == pVencHeaderDataParam->mH264SpsPpsInfo.nLength || NULL == pVencHeaderDataParam->mH264SpsPpsInfo.pBuffer)
|
|
{
|
|
aloge("fatal error! invalid params! %d, %p", pVencHeaderDataParam->mH264SpsPpsInfo.nLength, pVencHeaderDataParam->mH264SpsPpsInfo.pBuffer);
|
|
return FAILURE;
|
|
}
|
|
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE *) hComponent)->pComponentPrivate);
|
|
|
|
VencHeaderDataNode *pEntry = NULL;
|
|
bFindFlag = false;
|
|
if(!list_empty(&pRecRenderData->mVencHeaderDataList))
|
|
{
|
|
list_for_each_entry(pEntry, &pRecRenderData->mVencHeaderDataList, mList)
|
|
{
|
|
if(pEntry->mVeChn == pVencHeaderDataParam->mVeChn)
|
|
{
|
|
bFindFlag = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(bFindFlag) //update spspps
|
|
{
|
|
alogd("Be careful! muxChn[%d-%d] set streamId[%d] veChn[%d] spspps again, update it.",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pEntry->mStreamId, pEntry->mVeChn);
|
|
if(pEntry->mH264SpsPpsInfo.pBuffer)
|
|
{
|
|
free(pEntry->mH264SpsPpsInfo.pBuffer);
|
|
pEntry->mH264SpsPpsInfo.pBuffer = NULL;
|
|
pEntry->mH264SpsPpsInfo.nLength = 0;
|
|
}
|
|
pEntry->mH264SpsPpsInfo.pBuffer = (unsigned char *)malloc(pVencHeaderDataParam->mH264SpsPpsInfo.nLength);
|
|
if (pEntry->mH264SpsPpsInfo.pBuffer)
|
|
{
|
|
memcpy(pEntry->mH264SpsPpsInfo.pBuffer, pVencHeaderDataParam->mH264SpsPpsInfo.pBuffer, pVencHeaderDataParam->mH264SpsPpsInfo.nLength);
|
|
pEntry->mH264SpsPpsInfo.nLength = pVencHeaderDataParam->mH264SpsPpsInfo.nLength;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! pVencHeaderDataNode->mH264SpsPpsInfo.pBuffer malloc fail!");
|
|
eError = ERR_MUX_NOMEM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VencHeaderDataNode *pVencHeaderDataNode = (VencHeaderDataNode *)malloc(sizeof(VencHeaderDataNode));
|
|
if (NULL == pVencHeaderDataNode)
|
|
{
|
|
aloge("fatal error! malloc pVencHeaderDataNode fail!");
|
|
return FAILURE;
|
|
}
|
|
|
|
memset(pVencHeaderDataNode, 0, sizeof(VencHeaderDataNode));
|
|
pVencHeaderDataNode->mStreamId = -1;
|
|
pVencHeaderDataNode->mVeChn = pVencHeaderDataParam->mVeChn;
|
|
pVencHeaderDataNode->mH264SpsPpsInfo.pBuffer = (unsigned char *)malloc(pVencHeaderDataParam->mH264SpsPpsInfo.nLength);
|
|
if (NULL == pVencHeaderDataNode->mH264SpsPpsInfo.pBuffer)
|
|
{
|
|
aloge("fatal error! pVencHeaderDataNode->mH264SpsPpsInfo.pBuffer malloc fail!");
|
|
free(pVencHeaderDataNode);
|
|
pVencHeaderDataNode = NULL;
|
|
return FAILURE;
|
|
}
|
|
memcpy(pVencHeaderDataNode->mH264SpsPpsInfo.pBuffer, pVencHeaderDataParam->mH264SpsPpsInfo.pBuffer, pVencHeaderDataParam->mH264SpsPpsInfo.nLength);
|
|
pVencHeaderDataNode->mH264SpsPpsInfo.nLength = pVencHeaderDataParam->mH264SpsPpsInfo.nLength;
|
|
|
|
list_add_tail(&pVencHeaderDataNode->mList, &pRecRenderData->mVencHeaderDataList);
|
|
|
|
VeChnBindStreamIdNode *pTmp = NULL;
|
|
bFindFlag = false;
|
|
list_for_each_entry(pTmp, &pRecRenderData->mVeChnBindStreamIdList, mList)
|
|
{
|
|
if (pVencHeaderDataParam->mVeChn == pTmp->mVeChn.mChnId)
|
|
{
|
|
bFindFlag = true;
|
|
break;
|
|
}
|
|
}
|
|
if (bFindFlag)
|
|
{
|
|
pVencHeaderDataNode->mStreamId = pTmp->mStreamId;
|
|
alogd("muxChn[%d-%d] set Venc header data is success! StreamId: %d, veChn: %d, SpsPps info length: %d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pVencHeaderDataNode->mStreamId,
|
|
pVencHeaderDataNode->mVeChn, pVencHeaderDataNode->mH264SpsPpsInfo.nLength);
|
|
}
|
|
else
|
|
{
|
|
alogd("muxChn[%d-%d] set Venc header data! not find VeChn[%d] in streamId binding list, perhaps set SpsPps before binding tunnel!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pVencHeaderDataParam->mVeChn);
|
|
//eError = ERR_MUX_UNEXIST;
|
|
}
|
|
}
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderSetSwitchPolicy(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN RecordFileDurationPolicy *pPolicy
|
|
)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
|
|
pRecRenderData->mFileDurationPolicy = *pPolicy;
|
|
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderGetSwitchPolicy(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN RecordFileDurationPolicy *pPolicy
|
|
)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
|
|
*pPolicy = pRecRenderData->mFileDurationPolicy;
|
|
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderSetShutDownType(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN BOOL bShutDownNowFlag)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
pRecRenderData->mbShutDownNowFlag = bShutDownNowFlag;
|
|
return SUCCESS;
|
|
}
|
|
|
|
ERRORTYPE RecRenderSwitchFileNormal(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN SwitchFileNormalInfo* pInfo)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
|
|
message_t msg;
|
|
InitMessage(&msg);
|
|
msg.command = SwitchFileNormal;
|
|
msg.mpData = pInfo;
|
|
msg.mDataSize = sizeof(SwitchFileNormalInfo);
|
|
msg.pReply = ConstructMessageReply();
|
|
putMessageWithData(&pRecRenderData->cmd_queue, &msg);
|
|
|
|
int ret;
|
|
while(1)
|
|
{
|
|
ret = cdx_sem_down_timedwait(&msg.pReply->ReplySem, 5000);
|
|
if(ret != 0)
|
|
{
|
|
aloge("fatal error! wait switch file normal fail[0x%x]", ret);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
eError = (ERRORTYPE)msg.pReply->ReplyResult;
|
|
alogd("receive switch file normal reply: 0x%x!", eError);
|
|
DestructMessageReply(msg.pReply);
|
|
msg.pReply = NULL;
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderVeChnBindStreamId(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN VeChnBindStreamIdNode* pChn)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
|
|
VeChnBindStreamIdNode *pNode = (VeChnBindStreamIdNode *)malloc(sizeof(VeChnBindStreamIdNode));
|
|
|
|
memset(pNode, 0, sizeof(VeChnBindStreamIdNode));
|
|
pNode->mStreamId = pChn->mStreamId;
|
|
memcpy(&pNode->mVeChn, &pChn->mVeChn, sizeof(MPP_CHN_S));
|
|
|
|
alogd("VeChn mChnId: %d bind StreamId: %d", pChn->mVeChn.mChnId, pChn->mStreamId);
|
|
|
|
//process streamId of pRecRenderData->media_inf.
|
|
for (int VideoInfoIndex = 0; VideoInfoIndex < pRecRenderData->mChnAttr.mVideoAttrValidNum; VideoInfoIndex++)
|
|
{
|
|
if (pRecRenderData->mChnAttr.mVideoAttr[VideoInfoIndex].mVeChn == pNode->mVeChn.mChnId)
|
|
{
|
|
pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].mStreamId = pNode->mStreamId;
|
|
}
|
|
}
|
|
//process streamId of pRecRenderData->mVencHeaderDataList
|
|
if(!list_empty(&pRecRenderData->mVencHeaderDataList))
|
|
{
|
|
int nFindNum = 0;
|
|
VencHeaderDataNode *pEntry = NULL;
|
|
list_for_each_entry(pEntry, &pRecRenderData->mVencHeaderDataList, mList)
|
|
{
|
|
if (pEntry->mVeChn == pNode->mVeChn.mChnId)
|
|
{
|
|
if(pEntry->mStreamId != -1)
|
|
{
|
|
aloge("fatal error! VencHeader data node: veChn[%d], streamId[%d]!=-1", pEntry->mVeChn, pEntry->mStreamId);
|
|
}
|
|
pEntry->mStreamId = pNode->mStreamId;
|
|
nFindNum++;
|
|
}
|
|
}
|
|
if(nFindNum != 1)
|
|
{
|
|
aloge("fatal error! veChn[%d] is found wrong times[%d]", pNode->mVeChn.mChnId, nFindNum);
|
|
}
|
|
}
|
|
|
|
list_add_tail(&pNode->mList, &pRecRenderData->mVeChnBindStreamIdList);
|
|
|
|
return eError;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
ERRORTYPE RecRenderGetConfig(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN COMP_INDEXTYPE nIndex,
|
|
PARAM_INOUT void* pComponentConfigStructure)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
//COMP_INDEXTYPE portIdx;
|
|
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
|
|
switch (nIndex)
|
|
{
|
|
case COMP_IndexParamPortDefinition:
|
|
{
|
|
eError = RecRenderGetPortDefinition(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexParamCompBufferSupplier:
|
|
{
|
|
eError = RecRenderGetCompBufferSupplier(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexParamOtherInit:
|
|
{
|
|
eError = RecRenderGetPortParam(hComponent, (COMP_PORT_PARAM_TYPE*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorGetPortParam:
|
|
{
|
|
eError = RecRenderGetPortParam(hComponent, (COMP_PORT_PARAM_TYPE*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMPPChannelInfo:
|
|
{
|
|
eError = RecRenderGetMPPChannelInfo(hComponent, (MPP_CHN_S*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorTunnelInfo:
|
|
{
|
|
eError = RecRenderGetTunnelInfo(hComponent, (COMP_INTERNAL_TUNNELINFOTYPE*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMuxChnAttr:
|
|
{
|
|
eError = RecRenderGetChnAttr(hComponent, (MUX_CHN_ATTR_S*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMuxGetDuration:
|
|
*(int64_t*)pComponentConfigStructure = pRecRenderData->duration;
|
|
break;
|
|
case COMP_IndexVendorMuxSwitchPolicy:
|
|
{
|
|
eError = RecRenderGetSwitchPolicy(hComponent, (RecordFileDurationPolicy *)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
default:
|
|
aloge("fatal error! unknown index[0x%x]", nIndex);
|
|
break;
|
|
}
|
|
|
|
if (pRecRenderData->state == COMP_StateInvalid)
|
|
eError = ERR_MUX_INCORRECT_STATE_OPERATION;
|
|
|
|
//OMX_CONF_CMD_BAIL:
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderSetConfig(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN COMP_INDEXTYPE nIndex,
|
|
PARAM_IN void* pComponentConfigStructure)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = NULL;
|
|
ERRORTYPE eError = SUCCESS;
|
|
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
|
|
switch (nIndex)
|
|
{
|
|
case COMP_IndexParamPortDefinition:
|
|
{
|
|
eError = RecRenderSetPortDefinition(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexParamCompBufferSupplier:
|
|
{
|
|
eError = RecRenderSetCompBufferSupplier(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMPPChannelInfo:
|
|
{
|
|
eError = RecRenderSetMPPChannelInfo(hComponent, (MPP_CHN_S*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMuxChnAttr:
|
|
{
|
|
eError = RecRenderSetChnAttr(hComponent, (MUX_CHN_ATTR_S*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMuxFD:
|
|
{
|
|
eError = RecRenderSetFd(hComponent, (CdxFdT*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMuxSwitchFd:
|
|
{
|
|
if (pRecRenderData->state != COMP_StateExecuting)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] comp IndexConfigVendorSwitchFd state[%d] is not valid",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->state);
|
|
}
|
|
CdxFdT *pCdxFd = (CdxFdT*)pComponentConfigStructure;
|
|
message_t msg;
|
|
InitMessage(&msg);
|
|
msg.command = RecSink_SwitchFd;
|
|
msg.para0 = pCdxFd->mFd;
|
|
msg.para1 = pCdxFd->mnFallocateLen;
|
|
msg.pReply = ConstructMessageReply();
|
|
putMessageWithData(&pRecRenderData->cmd_queue, &msg);
|
|
|
|
int ret;
|
|
while(1)
|
|
{
|
|
ret = cdx_sem_down_timedwait(&msg.pReply->ReplySem, 5000);
|
|
if(ret != 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] wait switch fd fail[0x%x]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, ret);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
eError = (ERRORTYPE)msg.pReply->ReplyResult;
|
|
alogd("muxChn[%d-%d] receive switch fd reply: 0x%x!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, eError);
|
|
DestructMessageReply(msg.pReply);
|
|
msg.pReply = NULL;
|
|
break;
|
|
}
|
|
case COMP_IndexVendorSdcardState:
|
|
{
|
|
if (pRecRenderData->state != COMP_StateExecuting)
|
|
{
|
|
alogw("COMP IndexVendorSdcardState state[%d] is not valid, sdcardState[%d]", pRecRenderData->state, *(int*)pComponentConfigStructure);
|
|
}
|
|
pRecRenderData->mbSdCardState = (BOOL)*(int*)pComponentConfigStructure;
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMuxStrmIds:
|
|
{
|
|
MuxStreamIdsInfo *pStrmIdsInfo = (MuxStreamIdsInfo*)pComponentConfigStructure;
|
|
pRecRenderData->mValidStreamCount = pStrmIdsInfo->mStrmIdsCnt;
|
|
if(pRecRenderData->mValidStreamCount > MAX_TRACK_COUNT)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] stream count[%d] too many!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mValidStreamCount);
|
|
pRecRenderData->mValidStreamCount = MAX_TRACK_COUNT;
|
|
}
|
|
for(int i=0; i<pRecRenderData->mValidStreamCount; i++)
|
|
{
|
|
pRecRenderData->mValidStreamIds[i] = pStrmIdsInfo->mStrmIds[i];
|
|
}
|
|
break;
|
|
}
|
|
case COMP_IndexVendorExtraData:
|
|
{
|
|
eError = RecRenderSetH264SpsPpsInfo(hComponent, (VencHeaderDataParam *)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
// case OMX_IndexVendorSetRecRenderCallbackInfo:
|
|
// pRecRenderData->callback_writer = (void*)ComponentParameterStructure;
|
|
// break;
|
|
|
|
// case COMP_IndexVendorFsWriteMode:
|
|
// pRecRenderData->mFsWriteMode = *(FSWRITEMODE*)pComponentConfigStructure;
|
|
// break;
|
|
// case COMP_IndexVendorFsSimpleCacheSize:
|
|
// pRecRenderData->mSimpleCacheSize = *(int*)pComponentConfigStructure;
|
|
// break;
|
|
case COMP_IndexVendorMuxSwitchPolicy:
|
|
{
|
|
eError = RecRenderSetSwitchPolicy(hComponent, (RecordFileDurationPolicy *)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMuxShutDownType:
|
|
{
|
|
eError = RecRenderSetShutDownType(hComponent, *(BOOL*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexSwitchFileNormal:
|
|
{
|
|
eError = RecRenderSwitchFileNormal(hComponent, (SwitchFileNormalInfo*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMuxSetThmPic:
|
|
{
|
|
THM_PIC *pThmPic = (THM_PIC*)pComponentConfigStructure;
|
|
pthread_mutex_lock(&pRecRenderData->mThmPicLock);
|
|
if(1 == pRecRenderData->rc_thm_pic_ready)
|
|
{
|
|
alogw("Be careful! thm_pic is in ready, so replace it!");
|
|
pRecRenderData->rc_thm_pic_ready = 0;
|
|
if(pRecRenderData->rc_thm_pic.p_thm_pic_addr)
|
|
{
|
|
free(pRecRenderData->rc_thm_pic.p_thm_pic_addr);
|
|
pRecRenderData->rc_thm_pic.p_thm_pic_addr = NULL;
|
|
pRecRenderData->rc_thm_pic.thm_pic_size = 0;
|
|
}
|
|
}
|
|
if(pThmPic->thm_pic_size > 0)
|
|
{
|
|
pRecRenderData->rc_thm_pic.p_thm_pic_addr = (char*)malloc(pThmPic->thm_pic_size);
|
|
if(pRecRenderData->rc_thm_pic.p_thm_pic_addr)
|
|
{
|
|
memcpy(pRecRenderData->rc_thm_pic.p_thm_pic_addr, pThmPic->p_thm_pic_addr, pThmPic->thm_pic_size);
|
|
pRecRenderData->rc_thm_pic.thm_pic_size = pThmPic->thm_pic_size;
|
|
pRecRenderData->rc_thm_pic_ready = 1;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! malloc fail");
|
|
pRecRenderData->rc_thm_pic_ready = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] rc_set_thm_pic_size[%d] <= 0!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pThmPic->thm_pic_size);
|
|
pRecRenderData->rc_thm_pic_ready = 0;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mThmPicLock);
|
|
break;
|
|
}
|
|
case COMP_IndexVendorMuxVeChnBindStreamId:
|
|
{
|
|
RecRenderVeChnBindStreamId(hComponent, (VeChnBindStreamIdNode*)pComponentConfigStructure);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
aloge("fatal error! unknown nIndex[0x%x] in state[%d]", nIndex, pRecRenderData->state);
|
|
eError = ERR_MUX_ILLEGAL_PARAM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderComponentTunnelRequest(
|
|
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)
|
|
{
|
|
alogd("unsigned int nPort: %d", nPort);
|
|
ERRORTYPE eError = SUCCESS;
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
if (pRecRenderData->state == COMP_StateExecuting)
|
|
{
|
|
alogw("Be careful! tunnel request may be some danger in StateExecuting");
|
|
}
|
|
else if (pRecRenderData->state != COMP_StateIdle)
|
|
{
|
|
aloge("fatal error! tunnel request can't be in state[0x%x]!", pRecRenderData->state);
|
|
eError = ERR_MUX_INCORRECT_STATE_OPERATION;
|
|
goto COMP_CMD_FAIL;
|
|
}
|
|
COMP_PARAM_PORTDEFINITIONTYPE *pPortDef;
|
|
COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo;
|
|
COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier;
|
|
BOOL bFindFlag;
|
|
int i;
|
|
bFindFlag = FALSE;
|
|
for(i=0; i<MAX_REC_RENDER_PORTS; i++)
|
|
{
|
|
if(pRecRenderData->sInPortDef[i].nPortIndex == nPort)
|
|
{
|
|
pPortDef = &pRecRenderData->sInPortDef[i];
|
|
bFindFlag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(FALSE == bFindFlag)
|
|
{
|
|
aloge("fatal error! portIndex[%d] wrong!", nPort);
|
|
eError = ERR_MUX_ILLEGAL_PARAM;
|
|
goto COMP_CMD_FAIL;
|
|
}
|
|
|
|
bFindFlag = FALSE;
|
|
for(i=0; i<MAX_REC_RENDER_PORTS; i++)
|
|
{
|
|
if(pRecRenderData->sInPortTunnelInfo[i].nPortIndex == nPort)
|
|
{
|
|
pPortTunnelInfo = &pRecRenderData->sInPortTunnelInfo[i];
|
|
bFindFlag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(FALSE == bFindFlag)
|
|
{
|
|
aloge("fatal error! portIndex[%d] wrong!", nPort);
|
|
eError = ERR_MUX_ILLEGAL_PARAM;
|
|
goto COMP_CMD_FAIL;
|
|
}
|
|
|
|
bFindFlag = FALSE;
|
|
for(i=0; i<MAX_REC_RENDER_PORTS; i++)
|
|
{
|
|
if(pRecRenderData->sPortBufSupplier[i].nPortIndex == nPort)
|
|
{
|
|
pPortBufSupplier = &pRecRenderData->sPortBufSupplier[i];
|
|
bFindFlag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(FALSE == bFindFlag)
|
|
{
|
|
aloge("fatal error! portIndex[%d] wrong!", nPort);
|
|
eError = ERR_MUX_ILLEGAL_PARAM;
|
|
goto COMP_CMD_FAIL;
|
|
}
|
|
|
|
pPortTunnelInfo->nPortIndex = nPort;
|
|
pPortTunnelInfo->hTunnel = hTunneledComp;
|
|
pPortTunnelInfo->nTunnelPortIndex = nTunneledPort;
|
|
pPortTunnelInfo->eTunnelType = (pPortDef->eDomain == COMP_PortDomainOther) ? TUNNEL_TYPE_CLOCK : TUNNEL_TYPE_COMMON;
|
|
if(NULL==hTunneledComp && 0==nTunneledPort && NULL==pTunnelSetup)
|
|
{
|
|
alogd("omx_core cancel setup tunnel on port[%d]", nPort);
|
|
eError = SUCCESS;
|
|
if(pPortDef->eDir == COMP_DirInput)
|
|
{
|
|
pRecRenderData->mInputPortTunnelFlag[nPort] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! mux has not output port!");
|
|
}
|
|
goto COMP_CMD_FAIL;
|
|
}
|
|
if(pPortDef->eDir == COMP_DirOutput)
|
|
{
|
|
pTunnelSetup->nTunnelFlags = 0;
|
|
pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier;
|
|
}
|
|
else
|
|
{
|
|
//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_MUX_ILLEGAL_PARAM;
|
|
goto COMP_CMD_FAIL;
|
|
}
|
|
pPortDef->format = out_port_def.format;
|
|
|
|
ERRORTYPE eResult = SUCCESS;
|
|
MPP_CHN_S stMppChn;
|
|
eResult = ((MM_COMPONENTTYPE*)hTunneledComp)->GetConfig(hTunneledComp, COMP_IndexVendorMPPChannelInfo, &stMppChn);
|
|
if ((SUCCESS == eResult) && (MOD_ID_VENC == stMppChn.mModId))
|
|
{
|
|
VeChnBindStreamIdNode stVeChnStreamInfo;
|
|
stVeChnStreamInfo.mStreamId = nPort;
|
|
memcpy(&stVeChnStreamInfo.mVeChn, &stMppChn, sizeof(MPP_CHN_S));
|
|
|
|
RecRenderVeChnBindStreamId(hComponent, &stVeChnStreamInfo);
|
|
}
|
|
|
|
//The component B informs component A about the final result of negotiation.
|
|
if(pTunnelSetup->eSupplier != pPortBufSupplier->eBufferSupplier)
|
|
{
|
|
alogw("Low probability! use input portIndex[%d] buffer supplier[%d] as final!", nPort, pPortBufSupplier->eBufferSupplier);
|
|
pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier;
|
|
}
|
|
COMP_PARAM_BUFFERSUPPLIERTYPE oSupplier;
|
|
oSupplier.nPortIndex = nTunneledPort;
|
|
((MM_COMPONENTTYPE*)hTunneledComp)->GetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier);
|
|
oSupplier.eBufferSupplier = pTunnelSetup->eSupplier;
|
|
((MM_COMPONENTTYPE*)hTunneledComp)->SetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier);
|
|
pRecRenderData->mInputPortTunnelFlag[nPort] = TRUE;
|
|
}
|
|
|
|
COMP_CMD_FAIL:
|
|
return eError;
|
|
}
|
|
|
|
//ERRORTYPE AudioRecRequstBuffer(
|
|
// PARAM_IN COMP_HANDLETYPE hComponent,
|
|
// PARAM_IN unsigned int nPortIndex,
|
|
// PARAM_IN COMP_BUFFERHEADERTYPE* pBuffer) {
|
|
//
|
|
// RECRENDERDATATYPE *pRecRenderData = NULL;
|
|
// ERRORTYPE eError = SUCCESS;
|
|
//
|
|
// pRecRenderData
|
|
// = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
//
|
|
// put_data(&pRecRenderData->Audio_buffer_quene, pBuffer);
|
|
//
|
|
//ERROR:
|
|
// return eError;
|
|
//}
|
|
//
|
|
//ERRORTYPE AudioRecReleaseBuffer(
|
|
// PARAM_IN COMP_HANDLETYPE hComponent,
|
|
// PARAM_IN unsigned int nPortIndex,
|
|
// PARAM_IN COMP_BUFFERHEADERTYPE* pBuffer) {
|
|
//
|
|
// RECRENDERDATATYPE *pRecRenderData = NULL;
|
|
// ERRORTYPE eError = SUCCESS;
|
|
//
|
|
// pRecRenderData
|
|
// = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
//
|
|
//ERROR:
|
|
// return eError;
|
|
//
|
|
//}
|
|
#if 0
|
|
/*
|
|
* malloc memory to store data from VENC_STREAM_S.
|
|
*/
|
|
static ERRORTYPE InitEncodedStreamByVENC_STREAM_S(EncodedStream *pDst, VENC_STREAM_S *pSrc, PAYLOAD_TYPE_E eType)
|
|
{
|
|
if (pDst == NULL || pSrc == NULL)
|
|
{
|
|
aloge("fatal error! Empty pointer.");
|
|
return FAILURE;
|
|
}
|
|
memset(pDst, 0, sizeof(EncodedStream));
|
|
pDst->media_type = CDX_PacketVideo;
|
|
pDst->nID = pSrc->mSeq;
|
|
pDst->nFilledLen = pSrc->mpPack[0].mLen0 + pSrc->mpPack[0].mLen1 + pSrc->mpPack[0].mLen2;
|
|
pDst->nTobeFillLen = 0;
|
|
pDst->nTimeStamp = pSrc->mpPack[0].mPTS;
|
|
pDst->nFlags = 0;
|
|
if(PT_H264 == eType)
|
|
{
|
|
if(H264E_NALU_ISLICE == pSrc->mpPack[0].mDataType.enH264EType)
|
|
{
|
|
pDst->nFlags |= CEDARV_FLAG_KEYFRAME;
|
|
}
|
|
}
|
|
else if(PT_H265 == eType)
|
|
{
|
|
if(H265E_NALU_ISLICE == pSrc->mpPack[0].mDataType.enH265EType)
|
|
{
|
|
pDst->nFlags |= CEDARV_FLAG_KEYFRAME;
|
|
}
|
|
}
|
|
|
|
pDst->pBuffer = (unsigned char*)malloc(pDst->nFilledLen);
|
|
if(NULL == pDst->pBuffer)
|
|
{
|
|
aloge("fatal error! malloc [%d]bytes fail!", pDst->nFilledLen);
|
|
return ERR_MUX_NOMEM;
|
|
}
|
|
unsigned char *pBuf = pDst->pBuffer;
|
|
if(pSrc->mpPack[0].mLen0 > 0)
|
|
{
|
|
memcpy(pBuf, pSrc->mpPack[0].mpAddr0, pSrc->mpPack[0].mLen0);
|
|
pBuf += pSrc->mpPack[0].mLen0;
|
|
}
|
|
if(pSrc->mpPack[0].mLen1 > 0)
|
|
{
|
|
memcpy(pBuf, pSrc->mpPack[0].mpAddr1, pSrc->mpPack[0].mLen1);
|
|
pBuf += pSrc->mpPack[0].mLen1;
|
|
}
|
|
if(pSrc->mpPack[0].mLen2 > 0)
|
|
{
|
|
memcpy(pBuf, pSrc->mpPack[0].mpAddr2, pSrc->mpPack[0].mLen2);
|
|
pBuf += pSrc->mpPack[0].mLen2;
|
|
}
|
|
pDst->nBufferLen = pDst->nFilledLen;
|
|
pDst->pBufferExtra = NULL;
|
|
pDst->nBufferExtraLen = 0;
|
|
pDst->pBufferExtra2 = NULL;
|
|
pDst->nBufferExtraLen2 = 0;
|
|
|
|
pDst->infoVersion = -1;
|
|
pDst->pChangedStreamsInfo = NULL;
|
|
pDst->duration = -1;
|
|
return SUCCESS;
|
|
}
|
|
|
|
static ERRORTYPE InitEncodedStreamByAUDIO_STREAM_S(EncodedStream *pDst, AUDIO_STREAM_S *pSrc)
|
|
{
|
|
if (pDst == NULL || pSrc == NULL)
|
|
{
|
|
aloge("fatal error! Empty pointer.");
|
|
return FAILURE;
|
|
}
|
|
pDst->media_type = CDX_PacketAudio;
|
|
memset(pDst, 0, sizeof(EncodedStream));
|
|
pDst->pBuffer = (unsigned char*)malloc(pSrc->mLen);
|
|
if(NULL == pDst->pBuffer)
|
|
{
|
|
aloge("fatal error! malloc [%d]bytes fail!", pSrc->mLen);
|
|
return ERR_MUX_NOMEM;
|
|
}
|
|
memcpy(pDst->pBuffer, pSrc->pStream, pSrc->mLen);
|
|
pDst->nFilledLen = pSrc->mLen;
|
|
pDst->nBufferLen = pSrc->mLen;
|
|
pDst->nTimeStamp = pSrc->mTimeStamp;
|
|
pDst->nID = pSrc->mId;
|
|
return SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
static CDX_PACKETTYPE GetStreamTypeByStreamId(int nStreamId, _media_file_inf_t *pMediaInf)
|
|
{
|
|
CDX_PACKETTYPE eType;
|
|
if(nStreamId < pMediaInf->mVideoInfoValidNum)
|
|
{
|
|
eType = CDX_PacketVideo;
|
|
}
|
|
else if(nStreamId == pMediaInf->mVideoInfoValidNum)
|
|
{
|
|
eType = CDX_PacketAudio;
|
|
}
|
|
else
|
|
{
|
|
eType = CDX_PacketSubtitle;
|
|
}
|
|
return eType;
|
|
}
|
|
|
|
ERRORTYPE RecRenderEmptyThisBuffer(
|
|
PARAM_IN COMP_HANDLETYPE hComponent,
|
|
PARAM_IN COMP_BUFFERHEADERTYPE* pBuffer)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
ERRORTYPE eError = SUCCESS;
|
|
int ret=0;
|
|
|
|
pthread_mutex_lock(&pRecRenderData->mStateMutex);
|
|
|
|
// Check state
|
|
if ((pRecRenderData->state != COMP_StateIdle) && (pRecRenderData->state != COMP_StateExecuting) && (pRecRenderData->state != COMP_StatePause))
|
|
{
|
|
alogd("muxChn[%d-%d] send buffer in invalid state[0x%x]!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->state);
|
|
pthread_mutex_unlock(&pRecRenderData->mStateMutex);
|
|
return ERR_MUX_INCORRECT_STATE_OPERATION;
|
|
}
|
|
BOOL bFindFlag = FALSE;
|
|
int Index;
|
|
for (Index = 0; Index < MAX_REC_RENDER_PORTS; Index++)
|
|
{
|
|
if (pBuffer->nInputPortIndex == pRecRenderData->sInPortDef[Index].nPortIndex)
|
|
{
|
|
bFindFlag = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(FALSE == bFindFlag)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] find port[%d] failure!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pBuffer->nInputPortIndex);
|
|
pthread_mutex_unlock(&pRecRenderData->mStateMutex);
|
|
return ERR_MUX_ILLEGAL_PARAM;
|
|
}
|
|
EncodedStream *pOutFrame = NULL;
|
|
COMP_PORTDOMAINTYPE ePortDomain;
|
|
if(pRecRenderData->mInputPortTunnelFlag[Index])
|
|
{
|
|
ePortDomain = pRecRenderData->sInPortDef[Index].eDomain;
|
|
pOutFrame = (EncodedStream*)pBuffer->pOutputPortPrivate;
|
|
}
|
|
else
|
|
{
|
|
pOutFrame = (EncodedStream*)pBuffer->pAppPrivate;
|
|
switch(pOutFrame->media_type)
|
|
{
|
|
case CDX_PacketVideo:
|
|
{
|
|
ePortDomain = COMP_PortDomainVideo;
|
|
break;
|
|
}
|
|
case CDX_PacketAudio:
|
|
{
|
|
ePortDomain = COMP_PortDomainAudio;
|
|
break;
|
|
}
|
|
case CDX_PacketSubtitle:
|
|
{
|
|
ePortDomain = COMP_PortDomainText;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
aloge("fatal error! unknown streamType[%d]", pOutFrame->media_type);
|
|
ePortDomain = COMP_PortDomainVendorStartUnused;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#ifdef __SAVE_INPUT_BS__
|
|
if (pOutFrame->media_type == CDX_PacketVideo)
|
|
{
|
|
if (ftell(fp_bs) == 0)
|
|
{// Write SPS/PPS info
|
|
alogd("===== Write SPS/PPS Info");
|
|
|
|
int Index;
|
|
for (Index = 0; Index < MAX_REC_RENDER_PORTS; Index++)
|
|
{
|
|
if (pBuffer->nInputPortIndex == pRecRenderData->sInPortDef[Index].nPortIndex)
|
|
{
|
|
if(Index != pRecRenderData->sInPortDef[Index].nPortIndex)
|
|
{
|
|
aloge("fatal error! check port index:%d!=%d", Index, pRecRenderData->sInPortDef[Index].nPortIndex);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
VencHeaderDataNode *pEntry = NULL;
|
|
if (!list_empty(pRecRenderData->mVencHeaderDataList))
|
|
{
|
|
list_for_each_entry(pEntry, &pRecRenderData->mVencHeaderDataList, mList)
|
|
{
|
|
if (pEntry->mStreamId = Index);
|
|
break;
|
|
}
|
|
}
|
|
|
|
fwrite(pEntry->mH264SpsPpsInfo.pBuffer, 1, pEntry.mH264SpsPpsInfo.nLength, fp_bs);
|
|
}
|
|
|
|
fwrite(pOutFrame->pBuffer, 1, pOutFrame->nBufferLen, fp_bs);
|
|
fwrite(pOutFrame->pBufferExtra, 1, pOutFrame->nBufferExtraLen, fp_bs);
|
|
alogv("nBufferLen = %d nBufferExtraLen = %d KeyFrame = %d", pOutFrame->nBufferLen, pOutFrame->nBufferExtraLen, (pOutFrame->nFlags & CEDARV_FLAG_KEYFRAME) != 0);
|
|
}
|
|
#endif
|
|
|
|
//if (pBuffer->nInputPortIndex == pRecRenderData->sInPortDef[RECR_PORT_INDEX_VIDEO].nPortIndex)
|
|
if ((TRUE == bFindFlag) && (COMP_PortDomainVideo == ePortDomain))
|
|
{// VENC input tunnel mode
|
|
if (pOutFrame->nFilledLen == 0)
|
|
{
|
|
//alogw("Video Pkt[ID=%d Pts=%lld] FilledLen[%d] not Match, BufferLen=%d BufferExtraLen=%d",
|
|
// pOutFrame->nID, pOutFrame->nTimeStamp, pOutFrame->nFilledLen, pOutFrame->nBufferLen, pOutFrame->nBufferExtraLen);
|
|
//pOutFrame->nFilledLen = pOutFrame->nBufferLen + pOutFrame->nBufferExtraLen;
|
|
}
|
|
|
|
pthread_mutex_lock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
|
|
if(0 == Index)
|
|
{
|
|
pRecRenderData->video_frm_cnt++;
|
|
}
|
|
|
|
int nVideoStreamId = pRecRenderData->sInPortDef[Index].nPortIndex;
|
|
if(-1 != pRecRenderData->mDebugInputPts[nVideoStreamId])
|
|
{
|
|
if((pOutFrame->nTimeStamp - pRecRenderData->mDebugInputPts[nVideoStreamId])/1000 > 2*1000/30)
|
|
{
|
|
alogw("muxChn[%d-%d] rrn_v_pts_invalid:[%d]-%lld-%lld-%lld-%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
nVideoStreamId, pRecRenderData->mDebugInputPts[nVideoStreamId], pOutFrame->nTimeStamp,
|
|
(pOutFrame->nTimeStamp - pRecRenderData->mDebugInputPts[nVideoStreamId])/1000,
|
|
pRecRenderData->video_frm_cnt, pRecRenderData->audio_frm_cnt);
|
|
}
|
|
}
|
|
pRecRenderData->mDebugInputPts[nVideoStreamId] = pOutFrame->nTimeStamp;
|
|
|
|
// Ensure there is Idle node
|
|
if (list_empty(&pRecRenderData->mVideoInputFrameIdleList))
|
|
{
|
|
alogv("Low probability! RecRender idle frame is empty! Total Num = %d", pRecRenderData->mVideoInputFrameNum);
|
|
ENCODER_NODE_T *pNode = (ENCODER_NODE_T*)malloc(sizeof(ENCODER_NODE_T));
|
|
if (NULL == pNode)
|
|
{
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
pthread_mutex_unlock(&pRecRenderData->mStateMutex);
|
|
aloge("fatal error! malloc fail!");
|
|
eError = ERR_MUX_NOMEM;
|
|
return eError;
|
|
}
|
|
memset(pNode, 0, sizeof(ENCODER_NODE_T));
|
|
list_add_tail(&pNode->mList, &pRecRenderData->mVideoInputFrameIdleList);
|
|
pRecRenderData->mVideoInputFrameNum++;
|
|
if(0 == pRecRenderData->mVideoInputFrameNum%100)
|
|
{
|
|
alogd("Be careful! RecRender input frame total Num increase to %d", pRecRenderData->mVideoInputFrameNum);
|
|
}
|
|
}
|
|
|
|
// Move the node from IdelList to ReadyList
|
|
ENCODER_NODE_T *pFirstNode = list_first_entry(&pRecRenderData->mVideoInputFrameIdleList, ENCODER_NODE_T, mList);
|
|
memcpy(&pFirstNode->stEncodedStream, pOutFrame, sizeof(EncodedStream));
|
|
pFirstNode->mUsedRefCnt = 0; // clear ref count when moving it to ReadyList
|
|
pFirstNode->mPortIndex = pRecRenderData->sInPortDef[Index].nPortIndex;
|
|
list_move_tail(&pFirstNode->mList, &pRecRenderData->mVideoInputFrameReadyList);
|
|
|
|
// Send Input data valid message
|
|
if (pRecRenderData->mNoInputFrameFlag)
|
|
{
|
|
pRecRenderData->mNoInputFrameFlag = 0;
|
|
message_t msg;
|
|
msg.command = RecRenderComp_InputFrameAvailable;
|
|
put_message(&pRecRenderData->cmd_queue, &msg);
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
}
|
|
//else if(pBuffer->nInputPortIndex == pRecRenderData->sInPortDef[RECR_PORT_INDEX_AUDIO].nPortIndex)
|
|
else if ((TRUE == bFindFlag && (COMP_PortDomainAudio == ePortDomain)))
|
|
{// AENC input tunnel mode
|
|
if (pOutFrame->nFilledLen == 0)
|
|
{
|
|
alogw("Audio Pkt[ID=%d Pts=%lld] FilledLen[%d] not Match, BufferLen=%d BufferExtraLen=%d",
|
|
pOutFrame->nID, pOutFrame->nTimeStamp, pOutFrame->nFilledLen, pOutFrame->nBufferLen, pOutFrame->nBufferExtraLen);
|
|
//pOutFrame->nFilledLen = pOutFrame->nBufferLen + pOutFrame->nBufferExtraLen;
|
|
}
|
|
|
|
pthread_mutex_lock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
|
|
pRecRenderData->audio_frm_cnt++;
|
|
|
|
int nAudioStreamId = pRecRenderData->sInPortDef[Index].nPortIndex;
|
|
if(-1 != pRecRenderData->mDebugInputPts[nAudioStreamId])
|
|
{
|
|
if((pOutFrame->nTimeStamp - pRecRenderData->mDebugInputPts[nAudioStreamId])/1000 > 2*1024*1000/pRecRenderData->media_inf.sample_rate)
|
|
{
|
|
aloge("muxChn[%d-%d] rrn_a_pts_invalid:[%d]-%lld-%lld-%lld-%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
nAudioStreamId, pRecRenderData->mDebugInputPts[nAudioStreamId], pOutFrame->nTimeStamp,
|
|
(pOutFrame->nTimeStamp - pRecRenderData->mDebugInputPts[nAudioStreamId])/1000,
|
|
pRecRenderData->video_frm_cnt, pRecRenderData->audio_frm_cnt);
|
|
}
|
|
}
|
|
pRecRenderData->mDebugInputPts[nAudioStreamId] = pOutFrame->nTimeStamp;
|
|
|
|
// Ensure there is Idle node
|
|
if (list_empty(&pRecRenderData->mAudioInputFrameIdleList))
|
|
{
|
|
alogw("Low probability! RecRender idle frame is empty! Total Num = %d", pRecRenderData->mAudioInputFrameNum);
|
|
ENCODER_NODE_T *pNode = (ENCODER_NODE_T*)malloc(sizeof(ENCODER_NODE_T));
|
|
if (NULL == pNode)
|
|
{
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
pthread_mutex_unlock(&pRecRenderData->mStateMutex);
|
|
aloge("fatal error! malloc fail!");
|
|
eError = ERR_MUX_NOMEM;
|
|
return eError;
|
|
}
|
|
memset(pNode, 0, sizeof(ENCODER_NODE_T));
|
|
list_add_tail(&pNode->mList, &pRecRenderData->mAudioInputFrameIdleList);
|
|
pRecRenderData->mAudioInputFrameNum++;
|
|
}
|
|
|
|
// Move the node from IdelList to ReadyList
|
|
ENCODER_NODE_T *pFirstNode = list_first_entry(&pRecRenderData->mAudioInputFrameIdleList, ENCODER_NODE_T, mList);
|
|
memcpy(&pFirstNode->stEncodedStream, pOutFrame, sizeof(EncodedStream));
|
|
pFirstNode->mUsedRefCnt = 0; // clear ref count when moving it to ReadyList
|
|
pFirstNode->mPortIndex = pRecRenderData->sInPortDef[Index].nPortIndex;
|
|
//alogd("pFirstNode->mPortIndex: %d", pFirstNode->mPortIndex);
|
|
list_move_tail(&pFirstNode->mList, &pRecRenderData->mAudioInputFrameReadyList);
|
|
|
|
if (pRecRenderData->mNoInputFrameFlag)
|
|
{
|
|
pRecRenderData->mNoInputFrameFlag = 0;
|
|
message_t msg;
|
|
msg.command = RecRenderComp_InputFrameAvailable;
|
|
put_message(&pRecRenderData->cmd_queue, &msg);
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
}
|
|
//else if(pBuffer->nInputPortIndex == pRecRenderData->sInPortDef[RECR_PORT_INDEX_TEXT].nPortIndex)
|
|
else if ((TRUE == bFindFlag) && (COMP_PortDomainText == ePortDomain))
|
|
{
|
|
if (pOutFrame->nFilledLen == 0)
|
|
{
|
|
alogw("text Pkt[ID=%d Pts=%lld] FilledLen[%d] not Match, BufferLen=%d BufferExtraLen=%d"
|
|
,pOutFrame->nID, pOutFrame->nTimeStamp, pOutFrame->nFilledLen, pOutFrame->nBufferLen, pOutFrame->nBufferExtraLen);
|
|
//pOutFrame->nFilledLen = pOutFrame->nBufferLen + pOutFrame->nBufferExtraLen;
|
|
}
|
|
|
|
pthread_mutex_lock(&pRecRenderData->mTextInputFrameListMutex);
|
|
|
|
if (list_empty(&pRecRenderData->mTextInputFrameIdleList))
|
|
{
|
|
alogw("Low probability! RecRender idle frame is empty! Total Num = %d", pRecRenderData->mAudioInputFrameNum);
|
|
if(FALSE == pRecRenderData->mInputPortTunnelFlag[Index])
|
|
{
|
|
aloge("fatal error! no idle text node in non-tunnel mode.");
|
|
}
|
|
ENCODER_NODE_T *pNode = (ENCODER_NODE_T*)malloc(sizeof(ENCODER_NODE_T));
|
|
if (NULL == pNode)
|
|
{
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
pthread_mutex_unlock(&pRecRenderData->mStateMutex);
|
|
aloge("fatal error! malloc fail!");
|
|
eError = ERR_MUX_NOMEM;
|
|
return eError;
|
|
}
|
|
memset(pNode, 0, sizeof(ENCODER_NODE_T));
|
|
list_add_tail(&pNode->mList, &pRecRenderData->mTextInputFrameIdleList);
|
|
pRecRenderData->mTextInputFrameNum++;
|
|
}
|
|
|
|
// Move the node from IdelList to ReadyList
|
|
ENCODER_NODE_T *pFirstNode = list_first_entry(&pRecRenderData->mTextInputFrameIdleList, ENCODER_NODE_T, mList);
|
|
memcpy(&pFirstNode->stEncodedStream, pOutFrame, sizeof(EncodedStream));
|
|
pFirstNode->mUsedRefCnt = 0; // clear ref count when moving it to ReadyList
|
|
pFirstNode->mPortIndex = pRecRenderData->sInPortDef[Index].nPortIndex;
|
|
list_move_tail(&pFirstNode->mList, &pRecRenderData->mTextInputFrameReadyList);
|
|
if(pRecRenderData->mNoInputFrameFlag)
|
|
{
|
|
pRecRenderData->mNoInputFrameFlag = 0;
|
|
message_t msg;
|
|
msg.command = RecRenderComp_InputFrameAvailable;
|
|
put_message(&pRecRenderData->cmd_queue, &msg);
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! inputPortIndex[%d] match nothing!", pBuffer->nInputPortIndex);
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mStateMutex);
|
|
return eError;
|
|
}
|
|
|
|
ERRORTYPE RecRenderComponentDeInit(PARAM_IN COMP_HANDLETYPE hComponent)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
int err = 0;
|
|
CompInternalMsgType eCmd = Stop;
|
|
message_t msg;
|
|
//int ret;
|
|
int i;
|
|
//ERRORTYPE omx_ret;
|
|
memset(&msg, 0, sizeof(message_t));
|
|
pRecRenderData = (RECRENDERDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate);
|
|
|
|
// should already release all video frame
|
|
int iIdleVideoFrameCnt = 0;
|
|
struct list_head *pList;
|
|
list_for_each(pList, &pRecRenderData->mVideoInputFrameIdleList)
|
|
{
|
|
iIdleVideoFrameCnt++;
|
|
}
|
|
if (iIdleVideoFrameCnt < pRecRenderData->mVideoInputFrameNum)
|
|
{
|
|
aloge("fatal error! inputFrames[%d]<[%d] must return all before!", iIdleVideoFrameCnt, pRecRenderData->mVideoInputFrameNum);
|
|
}
|
|
if (!list_empty(&pRecRenderData->mVideoInputFrameReadyList))
|
|
{
|
|
aloge("fatal error! why readyInputFrame is not empty?");
|
|
}
|
|
if (!list_empty(&pRecRenderData->mVideoInputFrameUsedList))
|
|
{
|
|
aloge("fatal error! why usedInputFrame is not empty?");
|
|
}
|
|
if (!list_empty(&pRecRenderData->mVideoInputFrameIdleList))
|
|
{
|
|
ENCODER_NODE_T *pEntry, *pTmp;
|
|
list_for_each_entry_safe(pEntry, pTmp, &pRecRenderData->mVideoInputFrameIdleList, mList)
|
|
{
|
|
list_del(&pEntry->mList);
|
|
free(pEntry);
|
|
}
|
|
}
|
|
if(pRecRenderData->mVideoInputFrameNum != MUX_FIFO_LEVEL)
|
|
{
|
|
alogw("Low probability! RecRender idle frame Total Num: %d -> %d", MUX_FIFO_LEVEL, pRecRenderData->mVideoInputFrameNum);
|
|
}
|
|
// should already release all audio frame
|
|
int iIdleAudioFrameCnt = 0;
|
|
list_for_each(pList, &pRecRenderData->mAudioInputFrameIdleList)
|
|
{
|
|
iIdleAudioFrameCnt++;
|
|
}
|
|
if (iIdleAudioFrameCnt < pRecRenderData->mAudioInputFrameNum)
|
|
{
|
|
aloge("fatal error! inputFrames[%d]<[%d] must return all before!", iIdleAudioFrameCnt, pRecRenderData->mAudioInputFrameNum);
|
|
}
|
|
if (!list_empty(&pRecRenderData->mAudioInputFrameReadyList))
|
|
{
|
|
aloge("fatal error! why readyInputFrame is not empty?");
|
|
}
|
|
if (!list_empty(&pRecRenderData->mAudioInputFrameUsedList))
|
|
{
|
|
aloge("fatal error! why usedInputFrame is not empty?");
|
|
}
|
|
if (!list_empty(&pRecRenderData->mAudioInputFrameIdleList))
|
|
{
|
|
ENCODER_NODE_T *pEntry, *pTmp;
|
|
list_for_each_entry_safe(pEntry, pTmp, &pRecRenderData->mAudioInputFrameIdleList, mList)
|
|
{
|
|
list_del(&pEntry->mList);
|
|
free(pEntry);
|
|
}
|
|
}
|
|
|
|
// should already release all text frame
|
|
int iIdleTextFrameCnt = 0;
|
|
list_for_each(pList, &pRecRenderData->mTextInputFrameIdleList)
|
|
{
|
|
iIdleTextFrameCnt++;
|
|
}
|
|
if (iIdleTextFrameCnt < pRecRenderData->mTextInputFrameNum)
|
|
{
|
|
aloge("fatal error! inputFrames[%d]<[%d] must return all before!", iIdleTextFrameCnt, pRecRenderData->mTextInputFrameNum);
|
|
}
|
|
if (!list_empty(&pRecRenderData->mTextInputFrameReadyList))
|
|
{
|
|
aloge("fatal error! why readyInputFrame is not empty?");
|
|
}
|
|
if (!list_empty(&pRecRenderData->mTextInputFrameUsedList))
|
|
{
|
|
aloge("fatal error! why usedInputFrame is not empty?");
|
|
}
|
|
if (!list_empty(&pRecRenderData->mTextInputFrameIdleList))
|
|
{
|
|
ENCODER_NODE_T *pEntry, *pTmp;
|
|
list_for_each_entry_safe(pEntry, pTmp, &pRecRenderData->mTextInputFrameIdleList, mList)
|
|
{
|
|
list_del(&pEntry->mList);
|
|
free(pEntry);
|
|
}
|
|
}
|
|
|
|
msg.command = eCmd;
|
|
put_message(&pRecRenderData->cmd_queue, &msg);
|
|
//cdx_sem_up(&pRecRenderData->cdx_sem_wait_message);
|
|
|
|
alogv("wait recorder render component exit!...");
|
|
// Wait for thread to exit so we can get the status into "error"
|
|
pthread_join(pRecRenderData->thread_id, (void*) &eError);
|
|
|
|
//cdx_sem_deinit(&pRecRenderData->cdx_sem_wait_message);
|
|
message_destroy(&pRecRenderData->cmd_queue);
|
|
//data_quene_destroy(&pRecRenderData->Audio_buffer_quene);
|
|
|
|
#ifdef __SAVE_INPUT_BS__
|
|
fclose(fp_bs);
|
|
#endif
|
|
|
|
#if 0
|
|
if(pRecRenderData->venc_extradata_info.pBuffer)
|
|
{
|
|
free(pRecRenderData->venc_extradata_info.pBuffer);
|
|
pRecRenderData->venc_extradata_info.pBuffer = NULL;
|
|
}
|
|
#endif
|
|
|
|
if (!list_empty(&pRecRenderData->mVencHeaderDataList))
|
|
{
|
|
VencHeaderDataNode *pEntry, *pTmp;
|
|
list_for_each_entry_safe(pEntry, pTmp, &pRecRenderData->mVencHeaderDataList, mList)
|
|
{
|
|
list_del(&pEntry->mList);
|
|
free(pEntry->mH264SpsPpsInfo.pBuffer);
|
|
pEntry->mH264SpsPpsInfo.pBuffer = NULL;
|
|
free(pEntry);
|
|
}
|
|
}
|
|
|
|
if (!list_empty(&pRecRenderData->mVeChnBindStreamIdList))
|
|
{
|
|
VeChnBindStreamIdNode *pEntry, *pTmp;
|
|
list_for_each_entry_safe(pEntry, pTmp, &pRecRenderData->mVeChnBindStreamIdList, mList)
|
|
{
|
|
list_del(&pEntry->mList);
|
|
free(pEntry);
|
|
}
|
|
}
|
|
|
|
pthread_mutex_lock(&pRecRenderData->mRSPacketListMutex);
|
|
if(!list_empty(&pRecRenderData->mPrefetchRSPacketList))
|
|
{
|
|
aloge("fatal error! prefetch RSPacket list is not empty! check code!");
|
|
}
|
|
if(!list_empty(&pRecRenderData->mValidRSPacketList))
|
|
{
|
|
aloge("fatal error! valid RSPacket list is not empty! check code!");
|
|
}
|
|
if(!list_empty(&pRecRenderData->mIdleRSPacketList))
|
|
{
|
|
RecSinkPacket *pEntry, *pTmp;
|
|
list_for_each_entry_safe(pEntry, pTmp, &pRecRenderData->mIdleRSPacketList, mList)
|
|
{
|
|
list_del(&pEntry->mList);
|
|
free(pEntry);
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mRSPacketListMutex);
|
|
|
|
pthread_mutex_destroy(&pRecRenderData->mutex_reset_writer_lock);
|
|
pthread_mutex_destroy(&pRecRenderData->mJudgeSwitchlock);
|
|
pthread_mutex_destroy(&pRecRenderData->mMuxerInitlock);
|
|
pthread_mutex_destroy(&pRecRenderData->mVideoInputFrameListMutex);
|
|
pthread_mutex_destroy(&pRecRenderData->mAudioInputFrameListMutex);
|
|
pthread_mutex_destroy(&pRecRenderData->mTextInputFrameListMutex);
|
|
pthread_mutex_destroy(&pRecRenderData->mStateMutex);
|
|
pthread_mutex_destroy(&pRecRenderData->mRSPacketListMutex);
|
|
pthread_mutex_destroy(&pRecRenderData->mThmPicLock);
|
|
|
|
//cdx_sem_deinit(&pRecRenderData->mSemSwitchFileNormalDone);
|
|
if(pRecRenderData)
|
|
{
|
|
free(pRecRenderData);
|
|
pRecRenderData = NULL;
|
|
}
|
|
//alogd("[%s]sync_1", strrchr(__FILE__, '/')+1);
|
|
//sync();
|
|
//alogd("[%s]sync_2", strrchr(__FILE__, '/')+1);
|
|
alogd("recorder render component exited!");
|
|
|
|
return eError;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
ERRORTYPE RecRenderComponentInit(PARAM_IN COMP_HANDLETYPE hComponent)
|
|
{
|
|
MM_COMPONENTTYPE *pComp;
|
|
RECRENDERDATATYPE *pRecRenderData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
int err;
|
|
int i;
|
|
pComp = (MM_COMPONENTTYPE *) hComponent;
|
|
|
|
// Create private data
|
|
pRecRenderData = (RECRENDERDATATYPE *) malloc(sizeof(RECRENDERDATATYPE));
|
|
memset(pRecRenderData, 0x0, sizeof(RECRENDERDATATYPE));
|
|
|
|
pComp->pComponentPrivate = (void*) pRecRenderData;
|
|
pRecRenderData->state = COMP_StateLoaded;
|
|
err = pthread_mutex_init(&pRecRenderData->mStateMutex, NULL);
|
|
if(err!=0)
|
|
{
|
|
aloge("fatal error! pthread mutex init fail!");
|
|
//eError = ERR_MUX_NOMEM;
|
|
//goto EXIT;
|
|
}
|
|
pRecRenderData->hSelf = hComponent;
|
|
// Initialize component data structures to default values
|
|
pRecRenderData->sPortParam.nPorts = 0;
|
|
pRecRenderData->sPortParam.nStartPortNumber = 0x0;
|
|
//port def
|
|
while (pRecRenderData->sPortParam.nPorts < MAX_REC_RENDER_PORTS)
|
|
{
|
|
pRecRenderData->sInPortDef[pRecRenderData->sPortParam.nPorts].nPortIndex = pRecRenderData->sPortParam.nPorts;
|
|
pRecRenderData->sInPortDef[pRecRenderData->sPortParam.nPorts].eDir = COMP_DirInput;
|
|
pRecRenderData->sInPortDef[pRecRenderData->sPortParam.nPorts].bEnabled = FALSE;
|
|
pRecRenderData->sInPortDef[pRecRenderData->sPortParam.nPorts].eDomain = COMP_PortDomainVendorStartUnused;
|
|
pRecRenderData->sPortParam.nPorts++;
|
|
}
|
|
#if 0
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_VIDEO].nPortIndex = pRecRenderData->sPortParam.nPorts;
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_VIDEO].eDir = COMP_DirInput;
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_VIDEO].bEnabled = TRUE;
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_VIDEO].eDomain = COMP_PortDomainVideo;
|
|
pRecRenderData->sPortParam.nPorts++;
|
|
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_AUDIO].nPortIndex = pRecRenderData->sPortParam.nPorts;
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_AUDIO].eDir = COMP_DirInput;
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_AUDIO].bEnabled = TRUE;
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_AUDIO].eDomain = COMP_PortDomainAudio;
|
|
pRecRenderData->sPortParam.nPorts++;
|
|
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_TEXT].nPortIndex = pRecRenderData->sPortParam.nPorts;
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_TEXT].eDir = COMP_DirInput;
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_TEXT].bEnabled = TRUE;
|
|
pRecRenderData->sInPortDef[RECR_PORT_INDEX_TEXT].eDomain = COMP_PortDomainText;
|
|
pRecRenderData->sPortParam.nPorts++;
|
|
#endif
|
|
//port tunnel info
|
|
for (int nPortIndex = 0; nPortIndex < MAX_REC_RENDER_PORTS; nPortIndex++)
|
|
{
|
|
pRecRenderData->sInPortTunnelInfo[nPortIndex].nPortIndex = nPortIndex;
|
|
pRecRenderData->sInPortTunnelInfo[nPortIndex].eTunnelType = TUNNEL_TYPE_COMMON;
|
|
}
|
|
//port buf supplier
|
|
for (int nPortIndex = 0; nPortIndex < MAX_REC_RENDER_PORTS; nPortIndex++)
|
|
{
|
|
pRecRenderData->sPortBufSupplier[nPortIndex].nPortIndex = nPortIndex;
|
|
pRecRenderData->sPortBufSupplier[nPortIndex].eBufferSupplier = COMP_BufferSupplyOutput;
|
|
}
|
|
#if 0
|
|
pRecRenderData->sPortBufSupplier[RECR_PORT_INDEX_VIDEO].nPortIndex = 0x0;
|
|
pRecRenderData->sPortBufSupplier[RECR_PORT_INDEX_VIDEO].eBufferSupplier = COMP_BufferSupplyOutput;
|
|
pRecRenderData->sPortBufSupplier[RECR_PORT_INDEX_AUDIO].nPortIndex = 0x1;
|
|
pRecRenderData->sPortBufSupplier[RECR_PORT_INDEX_AUDIO].eBufferSupplier = COMP_BufferSupplyOutput;
|
|
pRecRenderData->sPortBufSupplier[RECR_PORT_INDEX_TEXT].nPortIndex = 0x2;
|
|
pRecRenderData->sPortBufSupplier[RECR_PORT_INDEX_TEXT].eBufferSupplier = COMP_BufferSupplyOutput;
|
|
|
|
pRecRenderData->sInPortTunnelInfo[RECR_PORT_INDEX_VIDEO].nPortIndex = 0x0;
|
|
pRecRenderData->sInPortTunnelInfo[RECR_PORT_INDEX_VIDEO].eTunnelType = TUNNEL_TYPE_COMMON;
|
|
pRecRenderData->sInPortTunnelInfo[RECR_PORT_INDEX_AUDIO].nPortIndex = 0x1;
|
|
pRecRenderData->sInPortTunnelInfo[RECR_PORT_INDEX_AUDIO].eTunnelType = TUNNEL_TYPE_COMMON;
|
|
pRecRenderData->sInPortTunnelInfo[RECR_PORT_INDEX_TEXT].nPortIndex = 0x2;
|
|
pRecRenderData->sInPortTunnelInfo[RECR_PORT_INDEX_TEXT].eTunnelType = TUNNEL_TYPE_COMMON;
|
|
#endif
|
|
|
|
if(message_create(&pRecRenderData->cmd_queue) < 0)
|
|
{
|
|
aloge("fatal error! create message error!");
|
|
// eError = ERR_MUX_NOMEM;
|
|
// goto EXIT;
|
|
}
|
|
pRecRenderData->mNoInputFrameFlag = 0;
|
|
pRecRenderData->callback_writer.parent = (void*)pRecRenderData;
|
|
pRecRenderData->callback_writer.writer = CDXRecoder_WritePacket_CB;
|
|
pRecRenderData->duration = 0;
|
|
pRecRenderData->duration_audio = 0;
|
|
pRecRenderData->duration_text = 0;
|
|
pRecRenderData->mnBasePts = -1;
|
|
pRecRenderData->mnAudioBasePts = -1;
|
|
pRecRenderData->mnTextBasePts = -1;
|
|
//Init media_inf
|
|
for (int VideoInfoIndex = 0; VideoInfoIndex < MAX_VIDEO_TRACK_COUNT; VideoInfoIndex++)
|
|
{
|
|
pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].mVideoEncodeType = PT_MAX;
|
|
pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].mStreamId = -1;
|
|
}
|
|
//pRecRenderData->mPath = NULL;
|
|
pRecRenderData->nOutputFd = -1;
|
|
pRecRenderData->nFallocateLen = 0;
|
|
pRecRenderData->nCallbackOutFlag = FALSE;
|
|
int j;
|
|
for(j=0;j<MAX_TRACK_COUNT;j++)
|
|
{
|
|
pRecRenderData->mbTrackInit[j] = FALSE;
|
|
pRecRenderData->mPrevPts[j] = -1;
|
|
pRecRenderData->mBasePts[j] = -1;
|
|
pRecRenderData->mInputPrevPts[j] = -1;
|
|
pRecRenderData->mOrigBasePts[j] = -1;
|
|
pRecRenderData->mDebugInputPts[j] = -1;
|
|
}
|
|
pRecRenderData->mRefVideoStreamIndex = 0;
|
|
pRecRenderData->mValidStreamCount = -1;
|
|
pRecRenderData->mBasePtsRefStreamIndex = -1;
|
|
err = pthread_mutex_init(&pRecRenderData->mutex_reset_writer_lock, NULL);
|
|
if(0!=err)
|
|
{
|
|
aloge("fatal error! pthread_mutex init fail");
|
|
//return ERR_MUX_NOMEM;
|
|
}
|
|
err = pthread_mutex_init(&pRecRenderData->mJudgeSwitchlock, NULL);
|
|
if(0!=err)
|
|
{
|
|
aloge("fatal error! pthread_mutex init fail");
|
|
}
|
|
err = pthread_mutex_init(&pRecRenderData->mMuxerInitlock, NULL);
|
|
if(0!=err)
|
|
{
|
|
aloge("fatal error! pthread_mutex init fail");
|
|
}
|
|
pRecRenderData->nSwitchFd = -1;
|
|
pRecRenderData->mCurFileEndTm = 0;
|
|
pRecRenderData->mRecordMode = RECORDER_MODE_NONE;
|
|
pRecRenderData->mFileDurationPolicy = RecordFileDurationPolicy_MinDuration;
|
|
pRecRenderData->mbSdCardState = TRUE;
|
|
pRecRenderData->mVideoPtsWriteMoreSt = -1;
|
|
INIT_LIST_HEAD(&pRecRenderData->mPrefetchRSPacketList);
|
|
INIT_LIST_HEAD(&pRecRenderData->mValidRSPacketList);
|
|
INIT_LIST_HEAD(&pRecRenderData->mIdleRSPacketList);
|
|
RecSinkPacket *pRSPacket;
|
|
for(i=0;i<RECSINK_MAX_PACKET_NUM;i++)
|
|
{
|
|
pRSPacket = (RecSinkPacket*)malloc(sizeof(RecSinkPacket));
|
|
if(NULL == pRSPacket)
|
|
{
|
|
aloge("fatal error! malloc fail");
|
|
//eError = ERR_MUX_NOMEM;
|
|
break;
|
|
}
|
|
list_add_tail(&pRSPacket->mList, &pRecRenderData->mIdleRSPacketList);
|
|
}
|
|
err = pthread_mutex_init(&pRecRenderData->mRSPacketListMutex, NULL);
|
|
if(err!=0)
|
|
{
|
|
aloge("fatal error! pthread mutex init fail!");
|
|
}
|
|
err = pthread_mutex_init(&pRecRenderData->mThmPicLock, NULL);
|
|
if(err!=0)
|
|
{
|
|
aloge("fatal error! pthread mutex init fail!");
|
|
}
|
|
|
|
// Init video output frame buffer
|
|
INIT_LIST_HEAD(&pRecRenderData->mVideoInputFrameIdleList);
|
|
INIT_LIST_HEAD(&pRecRenderData->mVideoInputFrameReadyList);
|
|
INIT_LIST_HEAD(&pRecRenderData->mVideoInputFrameUsedList);
|
|
for (int i = 0; i < MUX_FIFO_LEVEL; i++)
|
|
{
|
|
ENCODER_NODE_T *pNode = (ENCODER_NODE_T*)malloc(sizeof(ENCODER_NODE_T));
|
|
if (NULL == pNode)
|
|
{
|
|
aloge("fatal error! malloc fail!");
|
|
eError = ERR_MUX_NOMEM;
|
|
goto EXIT;
|
|
}
|
|
memset(pNode, 0, sizeof(ENCODER_NODE_T));
|
|
list_add_tail(&pNode->mList, &pRecRenderData->mVideoInputFrameIdleList);
|
|
pRecRenderData->mVideoInputFrameNum++;
|
|
}
|
|
// pthread_condattr_t condAttr;
|
|
// pthread_condattr_init(&condAttr);
|
|
// pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
|
|
// err = pthread_cond_init(&pRecRenderData->mWaitVideoInputFrameCond, &condAttr);
|
|
// if(err!=0)
|
|
// {
|
|
// aloge("fatal error! pthread cond init fail!");
|
|
// }
|
|
err = pthread_mutex_init(&pRecRenderData->mVideoInputFrameListMutex, NULL);
|
|
if (err!=0)
|
|
{
|
|
aloge("pthread mutex init fail!");
|
|
eError = ERR_MUX_NOMEM;
|
|
goto EXIT;
|
|
}
|
|
|
|
// Init audio output frame buffer
|
|
INIT_LIST_HEAD(&pRecRenderData->mAudioInputFrameIdleList);
|
|
INIT_LIST_HEAD(&pRecRenderData->mAudioInputFrameReadyList);
|
|
INIT_LIST_HEAD(&pRecRenderData->mAudioInputFrameUsedList);
|
|
for (int i = 0; i < MUX_FIFO_LEVEL; i++)
|
|
{
|
|
ENCODER_NODE_T *pNode = (ENCODER_NODE_T*)malloc(sizeof(ENCODER_NODE_T));
|
|
if (NULL == pNode)
|
|
{
|
|
aloge("fatal error! malloc fail!");
|
|
eError = ERR_MUX_NOMEM;
|
|
goto EXIT;
|
|
}
|
|
memset(pNode, 0, sizeof(ENCODER_NODE_T));
|
|
list_add_tail(&pNode->mList, &pRecRenderData->mAudioInputFrameIdleList);
|
|
pRecRenderData->mAudioInputFrameNum++;
|
|
}
|
|
err = pthread_mutex_init(&pRecRenderData->mAudioInputFrameListMutex, NULL);
|
|
if(err!=0)
|
|
{
|
|
aloge("pthread mutex init fail!");
|
|
eError = ERR_MUX_NOMEM;
|
|
goto EXIT;
|
|
}
|
|
|
|
// Init text output frame buffer
|
|
INIT_LIST_HEAD(&pRecRenderData->mTextInputFrameIdleList);
|
|
INIT_LIST_HEAD(&pRecRenderData->mTextInputFrameReadyList);
|
|
INIT_LIST_HEAD(&pRecRenderData->mTextInputFrameUsedList);
|
|
for (int i = 0; i < MUX_FIFO_LEVEL; i++)
|
|
{
|
|
ENCODER_NODE_T *pNode = (ENCODER_NODE_T*)malloc(sizeof(ENCODER_NODE_T));
|
|
if (NULL == pNode)
|
|
{
|
|
aloge("fatal error! malloc fail!");
|
|
eError = ERR_MUX_NOMEM;
|
|
goto EXIT;
|
|
}
|
|
memset(pNode, 0, sizeof(ENCODER_NODE_T));
|
|
list_add_tail(&pNode->mList, &pRecRenderData->mTextInputFrameIdleList);
|
|
pRecRenderData->mTextInputFrameNum++;
|
|
}
|
|
|
|
err = pthread_mutex_init(&pRecRenderData->mTextInputFrameListMutex, NULL);
|
|
if(err!=0)
|
|
{
|
|
aloge("pthread mutex init fail!");
|
|
eError = ERR_MUX_NOMEM;
|
|
goto EXIT;
|
|
}
|
|
|
|
INIT_LIST_HEAD(&pRecRenderData->mVencHeaderDataList);
|
|
INIT_LIST_HEAD(&pRecRenderData->mVeChnBindStreamIdList);
|
|
|
|
// Fill in function pointers
|
|
pComp->SetCallbacks = RecRenderSetCallbacks;
|
|
pComp->SendCommand = RecRenderSendCommand;
|
|
pComp->GetConfig = RecRenderGetConfig;
|
|
pComp->SetConfig = RecRenderSetConfig;
|
|
pComp->GetState = RecRenderGetState;
|
|
pComp->ComponentTunnelRequest = RecRenderComponentTunnelRequest;
|
|
pComp->EmptyThisBuffer = RecRenderEmptyThisBuffer;
|
|
pComp->ComponentDeInit = RecRenderComponentDeInit;
|
|
|
|
|
|
#ifdef __SAVE_INPUT_BS__
|
|
fp_bs = fopen("/data/input_video.bin", "wb");
|
|
#endif
|
|
|
|
// Create the component thread
|
|
err = pthread_create(&pRecRenderData->thread_id, NULL, RecRender_ComponentThread, pRecRenderData);
|
|
if (err!=0)
|
|
{
|
|
aloge("fatal error! create thread fail[%d]", err);
|
|
eError = ERR_MUX_NOMEM;
|
|
goto EXIT;
|
|
}
|
|
|
|
EXIT: return eError;
|
|
}
|
|
/*
|
|
void adjustAvsCounter(void* pThreadData)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE*) pThreadData;
|
|
int mediaTimediff;
|
|
OMX_TICKS now_avs_counter;
|
|
|
|
// avs_counter_get_time_us(&now_avs_counter);
|
|
pRecRenderData->avs_counter->get_time(pRecRenderData->avs_counter, &now_avs_counter);
|
|
alogv("now_avs_counter: %lld", now_avs_counter);
|
|
|
|
mediaTimediff = (int)(pRecRenderData->duration - pRecRenderData->duration_audio);
|
|
if(mediaTimediff > 100 || mediaTimediff < -100)
|
|
{
|
|
#if 0
|
|
int adjust_ratio;
|
|
adjust_ratio = mediaTimediff / (AVS_ADJUST_PERIOD_MS/100);
|
|
adjust_ratio = adjust_ratio > 1 ? 1 : adjust_ratio;
|
|
adjust_ratio = adjust_ratio < -1 ? -1 : adjust_ratio;
|
|
|
|
if(adjust_ratio){
|
|
avs_counter_adjust(adjust_ratio);
|
|
}
|
|
#else
|
|
int adjust_ratio;
|
|
adjust_ratio = mediaTimediff / (AVS_ADJUST_PERIOD_MS/100);
|
|
adjust_ratio = adjust_ratio > 2 ? 2 : adjust_ratio;
|
|
adjust_ratio = adjust_ratio < -2 ? -2 : adjust_ratio;
|
|
|
|
// avs_counter_adjust_abs(adjust_ratio);
|
|
pRecRenderData->avs_counter->adjust(pRecRenderData->avs_counter, adjust_ratio);
|
|
#endif
|
|
alogd("----adjust ratio:%d, video:%lld audio:%lld diff:%d diff-percent:%d ----",
|
|
adjust_ratio, pRecRenderData->duration, pRecRenderData->duration_audio,
|
|
mediaTimediff, mediaTimediff / (AVS_ADJUST_PERIOD_MS/100));
|
|
}
|
|
else
|
|
{
|
|
//avs_counter_adjust_abs(0);
|
|
pRecRenderData->avs_counter->adjust(pRecRenderData->avs_counter, 0);
|
|
alogd("----adjust ratio: 0, video: %lld(ms), auido: %lld(ms), diff: %lld(ms)",
|
|
pRecRenderData->duration, pRecRenderData->duration_audio, pRecRenderData->duration - pRecRenderData->duration_audio);
|
|
}
|
|
}
|
|
*/
|
|
/*****************************************************************************/
|
|
|
|
/**
|
|
select stream packet by time stamp.
|
|
The min pts frame will be selected.
|
|
*/
|
|
static enum CodecType SelectStreamToGet(RECRENDERDATATYPE *pRecRenderData)
|
|
{
|
|
enum CodecType eCodecType;
|
|
// int nVideoCnt = 0;
|
|
// int nAudioCnt = 0;
|
|
// int nTextCnt = 0;
|
|
int64_t nVideoPts = -1;
|
|
int64_t nAudioPts = -1;
|
|
int64_t nTextPts = -1;
|
|
pthread_mutex_lock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
pthread_mutex_lock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
pthread_mutex_lock(&pRecRenderData->mTextInputFrameListMutex);
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_VIDEO)
|
|
{
|
|
// struct list_head *pList;
|
|
// list_for_each(pList, &pRecRenderData->mVideoInputFrameReadyList)
|
|
// {
|
|
// nVideoCnt++;
|
|
// }
|
|
if(!list_empty(&pRecRenderData->mVideoInputFrameReadyList))
|
|
{
|
|
ENCODER_NODE_T *pFirstNode = list_first_entry(&pRecRenderData->mVideoInputFrameReadyList, ENCODER_NODE_T, mList);
|
|
nVideoPts = pFirstNode->stEncodedStream.nTimeStamp;
|
|
}
|
|
}
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_AUDIO)
|
|
{
|
|
// struct list_head *pList;
|
|
// list_for_each(pList, &pRecRenderData->mAudioInputFrameReadyList)
|
|
// {
|
|
// nAudioCnt++;
|
|
// }
|
|
if(!list_empty(&pRecRenderData->mAudioInputFrameReadyList))
|
|
{
|
|
ENCODER_NODE_T *pFirstNode = list_first_entry(&pRecRenderData->mAudioInputFrameReadyList, ENCODER_NODE_T, mList);
|
|
nAudioPts = pFirstNode->stEncodedStream.nTimeStamp;
|
|
}
|
|
}
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_TEXT)
|
|
{
|
|
// struct list_head *pList;
|
|
// list_for_each(pList, &pRecRenderData->mTextInputFrameReadyList)
|
|
// {
|
|
// nTextCnt++;
|
|
// }
|
|
if(!list_empty(&pRecRenderData->mTextInputFrameReadyList))
|
|
{
|
|
ENCODER_NODE_T *pFirstNode = list_first_entry(&pRecRenderData->mTextInputFrameReadyList, ENCODER_NODE_T, mList);
|
|
nTextPts = pFirstNode->stEncodedStream.nTimeStamp;
|
|
}
|
|
}
|
|
int64_t nMinPts = -1;
|
|
if(nVideoPts != -1)
|
|
{
|
|
nMinPts = nVideoPts;
|
|
eCodecType = CODEC_TYPE_VIDEO;
|
|
}
|
|
if(nAudioPts != -1)
|
|
{
|
|
if(nAudioPts < nMinPts || -1 == nMinPts)
|
|
{
|
|
nMinPts = nAudioPts;
|
|
eCodecType = CODEC_TYPE_AUDIO;
|
|
}
|
|
}
|
|
if(nTextPts != -1)
|
|
{
|
|
if(nTextPts < nMinPts || -1 == nMinPts)
|
|
{
|
|
nMinPts = nTextPts;
|
|
eCodecType = CODEC_TYPE_TEXT;
|
|
}
|
|
}
|
|
if(-1 == nMinPts)
|
|
{
|
|
eCodecType = CODEC_TYPE_UNKNOWN;
|
|
//set flag to indicate thread needs input frame.
|
|
pRecRenderData->mNoInputFrameFlag = 1;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
return eCodecType;
|
|
}
|
|
|
|
static ERRORTYPE RecSinkIncreaseIdleRSPacketList(RECRENDERDATATYPE *pRecRenderData)
|
|
{
|
|
ERRORTYPE eError = SUCCESS;
|
|
RecSinkPacket *pRSPacket;
|
|
int i;
|
|
for(i=0;i<RECSINK_MAX_PACKET_NUM;i++)
|
|
{
|
|
pRSPacket = (RecSinkPacket*)malloc(sizeof(RecSinkPacket));
|
|
if(NULL == pRSPacket)
|
|
{
|
|
aloge("fatal error! malloc fail");
|
|
eError = ERR_MUX_NOMEM;
|
|
break;
|
|
}
|
|
list_add_tail(&pRSPacket->mList, &pRecRenderData->mIdleRSPacketList);
|
|
}
|
|
return eError;
|
|
}
|
|
|
|
static ERRORTYPE RSSetRecSinkPacket(PARAM_IN RecSinkPacket *pDes, PARAM_IN RecSinkPacket *pSrc)
|
|
{
|
|
pDes->mId = pSrc->mId;
|
|
pDes->mStreamType = pSrc->mStreamType;
|
|
pDes->mFlags = pSrc->mFlags;
|
|
pDes->mPts = pSrc->mPts;
|
|
pDes->mpData0 = pSrc->mpData0;
|
|
pDes->mSize0 = pSrc->mSize0;
|
|
pDes->mpData1 = pSrc->mpData1;
|
|
pDes->mSize1 = pSrc->mSize1;
|
|
pDes->mCurrQp = pSrc->mCurrQp;
|
|
pDes->mavQp = pSrc->mavQp;
|
|
pDes->mnGopIndex = pSrc->mnGopIndex;
|
|
pDes->mnFrameIndex = pSrc->mnFrameIndex;
|
|
pDes->mnTotalIndex = pSrc->mnTotalIndex;
|
|
//pDes->mSourceType = pSrc->mSourceType;
|
|
pDes->mRefCnt = 0;
|
|
|
|
pDes->mStreamId = pSrc->mStreamId;
|
|
return SUCCESS;
|
|
}
|
|
|
|
/**
|
|
set packet content to one idle packet from idle list, and move it to valid list.
|
|
*/
|
|
static ERRORTYPE RecSinkPutRSPacket(RECRENDERDATATYPE *pRecRenderData, RecSinkPacket *pRSPacket)
|
|
{
|
|
ERRORTYPE eError = SUCCESS;
|
|
RecSinkPacket *pEntryPacket;
|
|
pthread_mutex_lock(&pRecRenderData->mRSPacketListMutex);
|
|
if(list_empty(&pRecRenderData->mIdleRSPacketList))
|
|
{
|
|
alogw("muxChn[%d-%d] idleRSPacketList are all used, malloc more!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
if(SUCCESS!=RecSinkIncreaseIdleRSPacketList(pRecRenderData))
|
|
{
|
|
pthread_mutex_unlock(&pRecRenderData->mRSPacketListMutex);
|
|
return ERR_MUX_NOMEM;
|
|
}
|
|
}
|
|
pEntryPacket = list_first_entry(&pRecRenderData->mIdleRSPacketList, RecSinkPacket, mList);
|
|
RSSetRecSinkPacket(pEntryPacket, pRSPacket);
|
|
list_move_tail(&pEntryPacket->mList, &pRecRenderData->mValidRSPacketList);
|
|
pthread_mutex_unlock(&pRecRenderData->mRSPacketListMutex);
|
|
return eError;
|
|
}
|
|
|
|
/**
|
|
move prefetch packets from prefetch list to valid list.
|
|
*/
|
|
static void RecSinkMovePrefetchRSPackets(RECRENDERDATATYPE *pRecRenderData)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mRSPacketListMutex);
|
|
list_splice_init(&pRecRenderData->mPrefetchRSPacketList, &pRecRenderData->mValidRSPacketList);
|
|
pthread_mutex_unlock(&pRecRenderData->mRSPacketListMutex);
|
|
}
|
|
/**
|
|
move valid packet from valid list, delete from valid list to make it independent.
|
|
*/
|
|
static RecSinkPacket* RecSinkGetRSPacket_l(RECRENDERDATATYPE *pRecRenderData)
|
|
{
|
|
RecSinkPacket *pRSPacket = NULL;
|
|
if(!list_empty(&pRecRenderData->mValidRSPacketList))
|
|
{
|
|
pRSPacket = list_first_entry(&pRecRenderData->mValidRSPacketList, RecSinkPacket, mList);
|
|
list_del(&pRSPacket->mList);
|
|
}
|
|
return pRSPacket;
|
|
}
|
|
|
|
static RecSinkPacket* RecSinkGetRSPacket(RECRENDERDATATYPE *pRecRenderData)
|
|
{
|
|
RecSinkPacket *pRSPacket = NULL;
|
|
pthread_mutex_lock(&pRecRenderData->mRSPacketListMutex);
|
|
pRSPacket = RecSinkGetRSPacket_l(pRecRenderData);
|
|
pthread_mutex_unlock(&pRecRenderData->mRSPacketListMutex);
|
|
return pRSPacket;
|
|
}
|
|
|
|
/**
|
|
return independent valid packet, add it to idle list.
|
|
*/
|
|
static ERRORTYPE RecSinkReleaseRSPacket_l(RECRENDERDATATYPE *pRecRenderData, RecSinkPacket *pRSPacket)
|
|
{
|
|
ERRORTYPE ret = RecRender_ReleaseBuffer(pRecRenderData, pRSPacket);
|
|
if(ret != SUCCESS)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] release buffer fail[0x%x]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, ret);
|
|
}
|
|
list_add_tail(&pRSPacket->mList, &pRecRenderData->mIdleRSPacketList);
|
|
return ret;
|
|
}
|
|
static ERRORTYPE RecSinkReleaseRSPacket(RECRENDERDATATYPE *pRecRenderData, RecSinkPacket *pRSPacket)
|
|
{
|
|
ERRORTYPE ret = RecRender_ReleaseBuffer(pRecRenderData, pRSPacket);
|
|
if(ret != SUCCESS)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] release buffer fail[0x%x]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, ret);
|
|
}
|
|
pthread_mutex_lock(&pRecRenderData->mRSPacketListMutex);
|
|
list_add_tail(&pRSPacket->mList, &pRecRenderData->mIdleRSPacketList);
|
|
pthread_mutex_unlock(&pRecRenderData->mRSPacketListMutex);
|
|
return ret;
|
|
}
|
|
/**
|
|
add independent valid packet to prefetch list.
|
|
*/
|
|
static ERRORTYPE RecSinkAddRSPacketToPrefetchList(RECRENDERDATATYPE *pRecRenderData, RecSinkPacket *pRSPacket)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mRSPacketListMutex);
|
|
list_add_tail(&pRSPacket->mList, &pRecRenderData->mPrefetchRSPacketList);
|
|
pthread_mutex_unlock(&pRecRenderData->mRSPacketListMutex);
|
|
return SUCCESS;
|
|
}
|
|
|
|
static void RecSinkUpdateStreamBasePts(RECRENDERDATATYPE *pRecRenderData, RecSinkPacket *pSrcPkt)
|
|
{
|
|
if (!pRecRenderData->mbTrackInit[pSrcPkt->mStreamId])
|
|
{
|
|
pRecRenderData->mbTrackInit[pSrcPkt->mStreamId] = TRUE;
|
|
pRecRenderData->mBasePts[pSrcPkt->mStreamId] = pSrcPkt->mPts;
|
|
if(-1 == pRecRenderData->mBasePtsRefStreamIndex)
|
|
{
|
|
pRecRenderData->mBasePtsRefStreamIndex = pSrcPkt->mStreamId;
|
|
}
|
|
alogd("muxChn[%d-%d] streamIdxBasePts[%d-%lld]us, RefStreamBasePts[%d-%lld], diff:%lld us!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pSrcPkt->mStreamId, pRecRenderData->mBasePts[pSrcPkt->mStreamId],
|
|
pRecRenderData->mBasePtsRefStreamIndex, pRecRenderData->mBasePts[pRecRenderData->mBasePtsRefStreamIndex],
|
|
pRecRenderData->mBasePts[pSrcPkt->mStreamId] - pRecRenderData->mBasePts[pRecRenderData->mBasePtsRefStreamIndex]);
|
|
if(-1 == pRecRenderData->mOrigBasePts[pSrcPkt->mStreamId])
|
|
{
|
|
pRecRenderData->mOrigBasePts[pSrcPkt->mStreamId] = pSrcPkt->mPts;
|
|
alogd("muxChn[%d-%d]streamIdx[%d] OrigBasePts[%lld]us!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pSrcPkt->mStreamId, pSrcPkt->mPts);
|
|
}
|
|
}
|
|
//if(pRecSink->mInputPrevPts[pDesPkt->stream_index] != -1)
|
|
//{
|
|
// pDesPkt->duration = (pSrcPkt->mPts - pRecSink->mInputPrevPts[pDesPkt->stream_index])/1000;
|
|
// if(pDesPkt->duration <= 0)
|
|
// {
|
|
// aloge("fatal error! stream[%d], curPts[%lld]us<=prevPts[%lld]us!", pDesPkt->stream_index, pSrcPkt->mPts, pRecSink->mInputPrevPts[pDesPkt->stream_index]);
|
|
// }
|
|
//}
|
|
//if(pDesPkt->duration < 0)
|
|
//{
|
|
// if(pSrcPkt->mStreamType == CODEC_TYPE_VIDEO)
|
|
// {
|
|
// pDesPkt->duration = 1000*1000 / pRecSink->mpMediaInf->uVideoFrmRate;
|
|
// }
|
|
// else if (pSrcPkt->mStreamType == CODEC_TYPE_AUDIO)
|
|
// {
|
|
// pDesPkt->duration = MAXDECODESAMPLE*1000 / pRecSink->mpMediaInf->sample_rate;
|
|
// }
|
|
// else if (pSrcPkt->mStreamType == CODEC_TYPE_TEXT)
|
|
// {
|
|
// pDesPkt->duration = 1000;
|
|
// }
|
|
// alogd("first packet of stream[%d], duration[%d]ms!", pSrcPkt->mStreamType, pDesPkt->duration);
|
|
//}
|
|
}
|
|
|
|
/**
|
|
Description:
|
|
AVPacket,
|
|
mbTrackInit[]
|
|
mBasePts[]
|
|
mPrevPts[]
|
|
mDuration
|
|
mDurationAudio
|
|
mVideoFrameCounter
|
|
|
|
Parameters:
|
|
|
|
Return:
|
|
|
|
Time: 2014/2/18
|
|
*/
|
|
static ERRORTYPE RecSinkWriteRSPacket(RECRENDERDATATYPE *pRecRenderData, RecSinkPacket *pSrcPkt)
|
|
{
|
|
int ret;
|
|
AVPacket packet;
|
|
AVPacket *pDesPkt = &packet;
|
|
memset(pDesPkt, 0, sizeof(AVPacket));
|
|
pDesPkt->dts = -1;
|
|
pDesPkt->data0 = pSrcPkt->mpData0;
|
|
pDesPkt->size0 = pSrcPkt->mSize0;
|
|
pDesPkt->data1 = pSrcPkt->mpData1;
|
|
pDesPkt->size1 = pSrcPkt->mSize1;
|
|
pDesPkt->stream_index = pSrcPkt->mStreamId;
|
|
pDesPkt->flags = pSrcPkt->mFlags;
|
|
pDesPkt->duration = -1;
|
|
pDesPkt->pos = -1;
|
|
pDesPkt->CurrQp = pSrcPkt->mCurrQp;
|
|
pDesPkt->avQp = pSrcPkt->mavQp;
|
|
pDesPkt->nGopIndex = pSrcPkt->mnGopIndex;
|
|
pDesPkt->nFrameIndex = pSrcPkt->mnFrameIndex;
|
|
pDesPkt->nTotalIndex = pSrcPkt->mnTotalIndex;
|
|
|
|
//find VideoStream mediainfo
|
|
int VideoInfoIndex = 0;
|
|
for (VideoInfoIndex = 0; VideoInfoIndex < pRecRenderData->media_inf.mVideoInfoValidNum; VideoInfoIndex++)
|
|
{
|
|
if (pSrcPkt->mStreamId == pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].mStreamId)
|
|
{
|
|
//alogd("VideoInfoIndex: %d, VideoStreamId: %d", VideoInfoIndex,
|
|
//pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].mStreamId);
|
|
break;
|
|
}
|
|
}
|
|
RecSinkUpdateStreamBasePts(pRecRenderData, pSrcPkt);
|
|
//note: pDesPkt->pts is not equal to pRecSink->mPrevPts[pDesPkt->stream_index], because we think as audio,video stream pts
|
|
//is based on same system time, then new file's a/v stream time can use same basePts to implement avsync.
|
|
pDesPkt->pts = pSrcPkt->mPts - pRecRenderData->mBasePts[pRecRenderData->mBasePtsRefStreamIndex];
|
|
if(pDesPkt->pts < 0)
|
|
{
|
|
alogd("Be careful! muxChn[%d-%d]maybe stream[%d]BasePts[%lld-%lld] < refStream[%d]BasePts[%lld], [%lld-%lld]us",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pDesPkt->stream_index, pRecRenderData->mBasePts[pDesPkt->stream_index], pSrcPkt->mPts,
|
|
pRecRenderData->mBasePtsRefStreamIndex, pRecRenderData->mBasePts[pRecRenderData->mBasePtsRefStreamIndex],
|
|
pRecRenderData->mBasePts[pDesPkt->stream_index] - pRecRenderData->mBasePts[pRecRenderData->mBasePtsRefStreamIndex],
|
|
pDesPkt->pts);
|
|
pDesPkt->pts = 0;
|
|
}
|
|
//if(pRecSink->mPrevPts[pDesPkt->stream_index] >= 0)
|
|
//{
|
|
// pDesPkt->duration = (int)((pDesPkt->pts - pRecSink->mPrevPts[pDesPkt->stream_index])/1000);
|
|
//}
|
|
pRecRenderData->mPrevPts[pDesPkt->stream_index] = pSrcPkt->mPts - pRecRenderData->mBasePts[pDesPkt->stream_index];
|
|
|
|
if(pRecRenderData->mInputPrevPts[pDesPkt->stream_index] != -1)
|
|
{
|
|
//here detect if frame interval is normal, if frame interval is large, perhaps discarding frame happened.
|
|
if (pSrcPkt->mStreamType == CODEC_TYPE_VIDEO)
|
|
{
|
|
if ((pSrcPkt->mPts - pRecRenderData->mInputPrevPts[pDesPkt->stream_index])/1000 >
|
|
1000*1000/pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].uVideoFrmRate * 2)
|
|
{
|
|
aloge("rec_in_pts_v_invalid:muxChn[%d-%d]:%lld-%lld=%lld ms",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pSrcPkt->mPts, pRecRenderData->mInputPrevPts[pDesPkt->stream_index],
|
|
(pSrcPkt->mPts - pRecRenderData->mInputPrevPts[pDesPkt->stream_index])/1000);
|
|
}
|
|
}
|
|
else if (pSrcPkt->mStreamType == CODEC_TYPE_AUDIO)
|
|
{
|
|
//if ((pSrcPkt->mPts - pRecSink->mInputPrevPts[pDesPkt->stream_index])/1000 > MAXDECODESAMPLE*1000 / pRecSink->mpMediaInf->sample_rate *2)
|
|
if ((pSrcPkt->mPts - pRecRenderData->mInputPrevPts[pDesPkt->stream_index])/1000 >
|
|
MAXDECODESAMPLE*1000 / pRecRenderData->media_inf.sample_rate * 2)
|
|
{
|
|
aloge("rec_in_pts_a_invalid:muxChn[%d-%d]:%lld-%lld=%lld ms",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pSrcPkt->mPts, pRecRenderData->mInputPrevPts[pDesPkt->stream_index],
|
|
(pSrcPkt->mPts - pRecRenderData->mInputPrevPts[pDesPkt->stream_index])/1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
pRecRenderData->mInputPrevPts[pDesPkt->stream_index] = pSrcPkt->mPts;
|
|
|
|
if(pSrcPkt->mStreamType == CODEC_TYPE_VIDEO) //if base on videoBasePts, then video duration is accurate.
|
|
{
|
|
//pRecSink->mDuration += pDesPkt->duration;
|
|
//pRecSink->mLoopDuration += pDesPkt->duration;
|
|
//pRecSink->mDuration = lround((double)pDesPkt->pts/1000 + 1000*1000/pRecSink->mpMediaInf->uVideoFrmRate);
|
|
pRecRenderData->mDuration[pDesPkt->stream_index] = lround((double)pRecRenderData->mPrevPts[pDesPkt->stream_index]/1000
|
|
/*+ 1000*1000/pRecSink->mpMediaInf->mMediaVideoInfo[VideoInfoIndex].uVideoFrmRate*/);
|
|
if(pRecRenderData->mDuration[pDesPkt->stream_index] <= 0)
|
|
{
|
|
pDesPkt->duration = lround(1000*1000/pRecRenderData->media_inf.mMediaVideoInfo[VideoInfoIndex].uVideoFrmRate);
|
|
}
|
|
else
|
|
{
|
|
pDesPkt->duration = pRecRenderData->mDuration[pDesPkt->stream_index] - pRecRenderData->mPrevDuration[pDesPkt->stream_index];
|
|
}
|
|
pRecRenderData->mPrevDuration[pDesPkt->stream_index] = pRecRenderData->mDuration[pDesPkt->stream_index];
|
|
if(pRecRenderData->mRefVideoStreamIndex == pSrcPkt->mStreamId)
|
|
{
|
|
//pRecSink->mLoopDuration = llround((double)(pSrcPkt->mPts - pRecSink->mOrigBasePts[pDesPkt->stream_index])/1000 +
|
|
//1000*1000/pRecSink->mpMediaInf->uVideoFrmRate);
|
|
pRecRenderData->mLoopDuration = llround((double)(pSrcPkt->mPts - pRecRenderData->mOrigBasePts[pDesPkt->stream_index])/1000
|
|
/*+ 1000*1000/pRecSink->mpMediaInf->mMediaVideoInfo[VideoInfoIndex].uVideoFrmRate*/);
|
|
pRecRenderData->mVideoFrameCounter++;
|
|
//pRecRenderData->video_frm_cnt++;
|
|
}
|
|
pRecRenderData->mFileSizeBytes += (int64_t)(pDesPkt->size0 + pDesPkt->size1 + 32);
|
|
}
|
|
else if (pSrcPkt->mStreamType == CODEC_TYPE_AUDIO) //if base on videoBasePts, audio duration is not accurate.
|
|
{
|
|
//pRecSink->mDurationAudio += pDesPkt->duration;
|
|
pRecRenderData->mDurationAudio = pRecRenderData->mPrevPts[pDesPkt->stream_index]/1000 /*+ MAXDECODESAMPLE*1000 / pRecSink->mpMediaInf->sample_rate*/;
|
|
if(pRecRenderData->mDurationAudio <= 0)
|
|
{
|
|
pDesPkt->duration = MAXDECODESAMPLE*1000 / pRecRenderData->media_inf.sample_rate;
|
|
}
|
|
else
|
|
{
|
|
pDesPkt->duration = pRecRenderData->mDurationAudio - pRecRenderData->mPrevDurationAudio;
|
|
}
|
|
pRecRenderData->mPrevDurationAudio = pRecRenderData->mDurationAudio;
|
|
pRecRenderData->mFileSizeBytes += (int64_t)(pDesPkt->size0 + pDesPkt->size1);
|
|
pRecRenderData->mLoopDurationAudio = (pSrcPkt->mPts - pRecRenderData->mOrigBasePts[pDesPkt->stream_index])/1000
|
|
/*+ MAXDECODESAMPLE*1000 / pRecSink->mpMediaInf->sample_rate*/;
|
|
//pRecRenderData->audio_frm_cnt++;
|
|
pRecRenderData->mAudioFrmCnt++;
|
|
if(0 == (pRecRenderData->mRecordMode & RECORDER_MODE_VIDEO))
|
|
{
|
|
pRecRenderData->mDuration[0] = pRecRenderData->mDurationAudio;
|
|
pRecRenderData->mPrevDuration[0] = pRecRenderData->mPrevDurationAudio;
|
|
pRecRenderData->mLoopDuration = pRecRenderData->mLoopDurationAudio;
|
|
}
|
|
}
|
|
else if (pSrcPkt->mStreamType == CODEC_TYPE_TEXT)
|
|
{
|
|
//pRecSink->mDurationText += pDesPkt->duration;
|
|
pRecRenderData->mDurationText = pRecRenderData->mPrevPts[pDesPkt->stream_index]/1000 /*+ 1000*/;
|
|
pDesPkt->duration = pRecRenderData->mDurationText - pRecRenderData->mPrevDurationText;
|
|
pRecRenderData->mPrevDurationText = pRecRenderData->mDurationText;
|
|
pRecRenderData->mFileSizeBytes += (int64_t)(pDesPkt->size0 + pDesPkt->size1);
|
|
}
|
|
|
|
if(pRecRenderData->mbSdCardState || pRecRenderData->nCallbackOutFlag)
|
|
{
|
|
if (pRecRenderData->pWriter != NULL)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mThmPicLock);
|
|
if(1 == pRecRenderData->rc_thm_pic_ready) // insert thm pic
|
|
{
|
|
AVPacket thm_packet;
|
|
memset(&thm_packet,0,sizeof(AVPacket));
|
|
|
|
thm_packet.flags |= AVPACKET_FLAG_THUMBNAIL;
|
|
thm_packet.data0 = pRecRenderData->rc_thm_pic.p_thm_pic_addr;
|
|
thm_packet.size0 = pRecRenderData->rc_thm_pic.thm_pic_size;
|
|
|
|
ret = pRecRenderData->pWriter->MuxerWritePacket(pRecRenderData->pMuxerCtx, &thm_packet);
|
|
if(0 != ret)
|
|
{
|
|
aloge("rc_wrt_thm_pic_failed!!");
|
|
}
|
|
if(NULL != pRecRenderData->rc_thm_pic.p_thm_pic_addr)
|
|
{
|
|
free(pRecRenderData->rc_thm_pic.p_thm_pic_addr);
|
|
pRecRenderData->rc_thm_pic.p_thm_pic_addr = NULL;
|
|
}
|
|
pRecRenderData->rc_thm_pic.thm_pic_size = 0;
|
|
pRecRenderData->rc_thm_pic_ready = 0;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mThmPicLock);
|
|
ret = pRecRenderData->pWriter->MuxerWritePacket(pRecRenderData->pMuxerCtx, pDesPkt);
|
|
if (ret != 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] muxerWritePacket FAILED", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alogw("pWriter=NULL, muxChn[%d-%d] not initialize", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alogw("Sdcard is not exist, skip MuxerWritePacket()!");
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
static ERRORTYPE RecSinkStreamCallback(void *hComp, int event)
|
|
{
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE*)hComp;
|
|
alogd("muxChn[%d-%d] WriteDisk fail: muxerFileType[0x%x], fd[%d]",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mChnAttr.mMediaFileFormat, pRecRenderData->nOutputFd);
|
|
pRecRenderData->pCallbacks->EventHandler(pRecRenderData->hSelf, pRecRenderData->pAppData, COMP_EventWriteDiskError,
|
|
pRecRenderData->mChnAttr.mMuxerId, 0, NULL);
|
|
return SUCCESS;
|
|
}
|
|
|
|
ERRORTYPE RecSinkMuxerInit(RECRENDERDATATYPE *pRecRenderData, RecSinkPacket *pRSPacket)
|
|
{
|
|
int result = SUCCESS;
|
|
int ret = 0;
|
|
char *file_path = NULL;
|
|
unsigned int nFallocateLen = pRecRenderData->nFallocateLen;
|
|
|
|
pthread_mutex_lock(&pRecRenderData->mMuxerInitlock);
|
|
alogd("muxChn[%d-%d]: fd[%d], nCallbackOutFlag[%d], fileDurPolicy[%d], fileDur[%lld]ms, first packet:%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->nOutputFd, pRecRenderData->nCallbackOutFlag,
|
|
pRecRenderData->mFileDurationPolicy, pRecRenderData->mChnAttr.mMaxFileDuration, pRSPacket->mStreamId, pRSPacket->mStreamType);
|
|
if(pRecRenderData->rec_file == FILE_NORMAL)
|
|
{
|
|
pRecRenderData->mCurMaxFileDuration = pRecRenderData->mChnAttr.mMaxFileDuration;
|
|
pRecRenderData->mCurFileEndTm += pRecRenderData->mCurMaxFileDuration;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! wrong rec file state[%d]", pRecRenderData->rec_file);
|
|
pRecRenderData->mCurMaxFileDuration = pRecRenderData->mChnAttr.mMaxFileDuration;
|
|
pRecRenderData->mCurFileEndTm += pRecRenderData->mCurMaxFileDuration;
|
|
}
|
|
|
|
alogd("muxChn[%d-%d] muxer_init:%d-%d-%lld-%lld", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->reset_fd_flag, pRecRenderData->nOutputFd, pRecRenderData->mCurMaxFileDuration, pRecRenderData->mCurFileEndTm);
|
|
if(FALSE == pRecRenderData->nCallbackOutFlag)
|
|
{
|
|
if(pRecRenderData->nOutputFd<0)
|
|
{
|
|
alogw("Be careful! nOutputFd<0 when call RecRender MuxerInit, have last chance to get fd!");
|
|
if(pRecRenderData->reset_fd_flag)
|
|
{
|
|
if(pRecRenderData->nSwitchFd >= 0)
|
|
{
|
|
pRecRenderData->nOutputFd = pRecRenderData->nSwitchFd;
|
|
pRecRenderData->nSwitchFd = -1;
|
|
nFallocateLen = pRecRenderData->nSwitchFdFallocateSize;
|
|
pRecRenderData->nSwitchFdFallocateSize = 0;
|
|
pRecRenderData->reset_fd_flag = FALSE;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! pSinkInfo->nSwitchFd[%d] < 0", pRecRenderData->nSwitchFd);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! reset_fd flag != TRUE");
|
|
}
|
|
}
|
|
file_path = generateFilepathFromFd(pRecRenderData->nOutputFd);
|
|
if(NULL != file_path)
|
|
{
|
|
alogd("muxChn[%d-%d] muxer_init2:%d-%s", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->nOutputFd, file_path);
|
|
free(file_path);
|
|
file_path = NULL;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] is not set nOutputFd[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->nOutputFd);
|
|
}
|
|
}
|
|
int i;
|
|
for(i=0;i<MAX_VIDEO_TRACK_COUNT;i++)
|
|
{
|
|
pRecRenderData->mDuration[i] = 0;
|
|
pRecRenderData->mPrevDuration[i] = 0;
|
|
pRecRenderData->mPrefetchFlag[i] = FALSE;
|
|
//pRecRenderData->need_to_force_i_frm[i] = 0;
|
|
pRecRenderData->forced_i_frm[i] = 0;
|
|
pRecRenderData->key_frm_sent[i] = 0;
|
|
pRecRenderData->v_frm_drp_cnt[i] = 0;
|
|
}
|
|
pRecRenderData->mDurationAudio = 0;
|
|
pRecRenderData->mDurationText = 0;
|
|
pRecRenderData->mPrevDurationAudio = 0;
|
|
pRecRenderData->mPrevDurationText = 0;
|
|
pRecRenderData->mPrefetchFlagAudio = FALSE;
|
|
pRecRenderData->mFileSizeBytes = 0;
|
|
for(i=0;i<MAX_TRACK_COUNT;i++)
|
|
{
|
|
pRecRenderData->mbTrackInit[i] = FALSE;
|
|
pRecRenderData->mPrevPts[i] = -1;
|
|
pRecRenderData->mBasePts[i] = -1;
|
|
pRecRenderData->mInputPrevPts[i] = -1;
|
|
}
|
|
pRecRenderData->mBasePtsRefStreamIndex = -1;
|
|
pRecRenderData->mVideoFrameCounter = 0;
|
|
pRecRenderData->mAudioFrmCnt = 0;
|
|
if (pRecRenderData->pWriter == NULL)
|
|
{
|
|
pRecRenderData->pWriter = cedarx_record_writer_create(map_MEDIA_FILE_FORMAT_E_to_MUXERMODES(pRecRenderData->mChnAttr.mMediaFileFormat));
|
|
if (NULL == pRecRenderData->pWriter)
|
|
{
|
|
aloge("fatal error! cedarx_record_writer_create failed");
|
|
result = ERR_MUX_NOMEM;
|
|
goto WRITER_CREATE_ERR;
|
|
}
|
|
pRecRenderData->pMuxerCtx = pRecRenderData->pWriter->MuxerOpen((int*)&ret);
|
|
if (ret != SUCCESS)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] MuxerOpen failed[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
result = ERR_MUX_ILLEGAL_PARAM;
|
|
goto MUXER_OPEN_ERR;
|
|
}
|
|
else
|
|
{
|
|
alogv("MuxerOpen OK");
|
|
}
|
|
//TODO: now, write fd and callback mode are mutex. In the future, we will improve it if necessary.
|
|
if (FALSE == pRecRenderData->nCallbackOutFlag)
|
|
{
|
|
if(pRecRenderData->nOutputFd>=0)
|
|
{
|
|
pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SETFALLOCATELEN, (unsigned int)nFallocateLen, NULL);
|
|
if (pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SETCACHEFD2, (unsigned int)pRecRenderData->nOutputFd, NULL) != 0)
|
|
{
|
|
aloge("fatal error! SETCACHEFD2 failed");
|
|
result = ERR_MUX_ILLEGAL_PARAM;
|
|
goto SETCACHEFD_ERR;
|
|
}
|
|
}
|
|
alogd("muxChn[%d-%d] FileDurationPolicy[0x%x], use fsWriteMode[%d], simpleCacheSize[%ld]KB",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mFileDurationPolicy, pRecRenderData->mChnAttr.mFsWriteMode, pRecRenderData->mChnAttr.mSimpleCacheSize/1024);
|
|
if(FSWRITEMODE_CACHETHREAD == pRecRenderData->mChnAttr.mFsWriteMode)
|
|
{
|
|
aloge("fatal error! not use cacheThread mode now!");
|
|
}
|
|
pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SET_FS_WRITE_MODE, pRecRenderData->mChnAttr.mFsWriteMode, NULL);
|
|
pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SET_FS_SIMPLE_CACHE_SIZE, pRecRenderData->mChnAttr.mSimpleCacheSize, NULL);
|
|
|
|
cdx_write_callback_t callback;
|
|
callback.hComp = pRecRenderData;
|
|
callback.cb = RecSinkStreamCallback;
|
|
pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SET_STREAM_CALLBACK, 0, (void*)&callback);
|
|
}
|
|
else
|
|
{
|
|
//pRecRenderData->writer->MuxerIoctrl(pRecRenderData->p_muxer_ctx, SETOUTURL, (unsigned int)pRecRenderData->url);
|
|
if (pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, REGISTER_WRITE_CALLBACK, 0, (void*)&pRecRenderData->callback_writer) != 0)
|
|
{
|
|
aloge("fatal error! REGISTER_WRITE_CALLBACK failed");
|
|
result = ERR_MUX_ILLEGAL_PARAM;
|
|
goto SETCACHEFD_ERR;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] pWriter[%p] is not NULL!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->pWriter);
|
|
}
|
|
|
|
// mjpeg source form camera
|
|
// if(pRecRenderData->is_compress_source == 1) { /* gushiming compressed source */
|
|
// pSinkInfo->pWriter->MuxerIoctrl(pSinkInfo->pMuxerCtx, SET_VIDEO_CODEC_ID, CODEC_ID_MJPEG);
|
|
// }
|
|
|
|
pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SET_ADD_REPAIR_INFO_FLAG, pRecRenderData->mChnAttr.mAddRepairInfo, NULL);
|
|
pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SET_FILE_REPAIR_INTERVAL, pRecRenderData->mChnAttr.mMaxFrmsTagInterval, NULL);
|
|
int tmp_ret = pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SETAVPARA, 0, (void*)&pRecRenderData->media_inf);
|
|
if(0 != tmp_ret)
|
|
{
|
|
aloge("muxer_set_media_info_failed!!");
|
|
result = ERR_MUX_ILLEGAL_PARAM;
|
|
goto SETCACHEFD_ERR;
|
|
}
|
|
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_VIDEO)
|
|
{
|
|
if (!list_empty(&pRecRenderData->mVencHeaderDataList))
|
|
{
|
|
VencHeaderDataNode *pEntry;
|
|
list_for_each_entry(pEntry, &pRecRenderData->mVencHeaderDataList, mList)
|
|
{
|
|
if (pEntry->mH264SpsPpsInfo.pBuffer && pEntry->mH264SpsPpsInfo.nLength > 0)
|
|
{
|
|
alogd("pEntry->mH264SpsPpsInfo.nLength: %d", pEntry->mH264SpsPpsInfo.nLength);
|
|
pRecRenderData->pWriter->MuxerWriteExtraData(pRecRenderData->pMuxerCtx,
|
|
(unsigned char *)pEntry->mH264SpsPpsInfo.pBuffer, pEntry->mH264SpsPpsInfo.nLength, pEntry->mStreamId);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alogd("VencExtraDataList is empty! May be use MJPEG encode or code error?");
|
|
}
|
|
}
|
|
int nAudioStreamNum = 0;
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_AUDIO)
|
|
{
|
|
nAudioStreamNum = 1;
|
|
__extra_data_t AudioExtraDataForMp4;
|
|
MuxerGenerateAudioExtraData(&AudioExtraDataForMp4, &pRecRenderData->media_inf);
|
|
pRecRenderData->pWriter->MuxerWriteExtraData(pRecRenderData->pMuxerCtx, AudioExtraDataForMp4.extra_data,
|
|
AudioExtraDataForMp4.extra_data_len, pRecRenderData->media_inf.mVideoInfoValidNum);
|
|
}
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_TEXT)
|
|
{ // do nothing
|
|
pRecRenderData->pWriter->MuxerWriteExtraData(pRecRenderData->pMuxerCtx, NULL, 0, pRecRenderData->media_inf.mVideoInfoValidNum+nAudioStreamNum);
|
|
}
|
|
ret = pRecRenderData->pWriter->MuxerWriteHeader(pRecRenderData->pMuxerCtx);
|
|
if (ret != 0)
|
|
{
|
|
aloge("fatal error! write header failed");
|
|
result = ERR_MUX_ILLEGAL_PARAM;
|
|
goto SETCACHEFD_ERR;
|
|
}
|
|
else
|
|
{
|
|
alogv("write header ok");
|
|
}
|
|
// if(FALSE==pSinkInfo->reset_fd_flag)
|
|
// {
|
|
// aloge("fatal error! why reset fd flag = 0?");
|
|
// }
|
|
// pSinkInfo->reset_fd_flag = FALSE;
|
|
pRecRenderData->mbMuxerInit = TRUE;
|
|
pthread_mutex_unlock(&pRecRenderData->mMuxerInitlock);
|
|
return SUCCESS;
|
|
|
|
SETCACHEFD_ERR:
|
|
pRecRenderData->pWriter->MuxerClose(pRecRenderData->pMuxerCtx);
|
|
MUXER_OPEN_ERR:
|
|
cedarx_record_writer_destroy(pRecRenderData->pWriter);
|
|
pRecRenderData->pWriter = NULL;
|
|
WRITER_CREATE_ERR:
|
|
pthread_mutex_unlock(&pRecRenderData->mMuxerInitlock);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
1. now, one muxer can only support one method: fwrite or CallbackOut.
|
|
In future, we will change it if necessary.
|
|
|
|
@param
|
|
|
|
@return
|
|
|
|
@date 2014/7/12
|
|
*/
|
|
static ERRORTYPE RecSinkMuxerClose(RECRENDERDATATYPE *pRecRenderData, int clrFile)
|
|
{
|
|
ERRORTYPE ret = SUCCESS;
|
|
if (pRecRenderData->pWriter != NULL)
|
|
{
|
|
/*
|
|
alogw("avsync_muxer_close:%d-%d-%d-%d--%lld-%lld-%lld-%lld--%d-%d",
|
|
pSinkInfo->mMuxerGrpId,pSinkInfo->mpMediaInf->nWidth,
|
|
pSinkInfo->mDuration,pSinkInfo->mDurationAudio,
|
|
pSinkInfo->mLoopDuration,pSinkInfo->mLoopDurationAudio,
|
|
pSinkInfo->mCurMaxFileDuration,pSinkInfo->mCurFileEndTm,
|
|
pSinkInfo->mVideoFrameCounter,pSinkInfo->mAudioFrmCnt);
|
|
*/
|
|
if(FALSE == pRecRenderData->nCallbackOutFlag)
|
|
{
|
|
if(pRecRenderData->mbSdCardState)
|
|
{
|
|
ret = pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SETTOTALTIME,
|
|
pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex], NULL);
|
|
if(ret != 0)
|
|
{
|
|
aloge("fatal error! writer->Muxer Ioctrl setTOTALTIME FAILED, ret: %d", ret);
|
|
}
|
|
ret = pRecRenderData->pWriter->MuxerWriteTrailer(pRecRenderData->pMuxerCtx);
|
|
if(ret!=0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] muxer WriteTrailer ret:[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, ret);
|
|
}
|
|
ret = pRecRenderData->pWriter->MuxerClose(pRecRenderData->pMuxerCtx);
|
|
if (ret != 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] muxer Close failed, ret = %d", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, ret);
|
|
}
|
|
pRecRenderData->pMuxerCtx = NULL;
|
|
//fflush(pSinkInfo->pOutputFile);
|
|
if (clrFile == 1)
|
|
{
|
|
aloge("fatal error! clrFile[%d]!=0", clrFile);
|
|
// #if (CDXCFG_FILE_SYSTEM==OPTION_FILE_SYSTEM_DIRECT_FATFS)
|
|
// fat_sync((int)pSinkInfo->pOutputFile);
|
|
// fat_lseek((int)pSinkInfo->pOutputFile, 0);
|
|
// fat_truncate((int)pSinkInfo->pOutputFile);
|
|
// #else
|
|
// fflush(pSinkInfo->pOutputFile);
|
|
// ftruncate(fileno(pSinkInfo->pOutputFile), 0);
|
|
// rewind(pSinkInfo->pOutputFile);
|
|
// #endif
|
|
}
|
|
else
|
|
{
|
|
// alogd("before fflush");
|
|
// fflush(pSinkInfo->pOutputFile);
|
|
// alogd("before fsync");
|
|
// fsync(pSinkInfo->nOutputFd);
|
|
// alogd("after fsync");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alogd("muxChn[%d-%d] mbSdCardState[%d], sdcard is pull out", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mbSdCardState);
|
|
pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SETSDCARDSTATE, pRecRenderData->mbSdCardState, NULL);
|
|
pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SETTOTALTIME, pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex], NULL);
|
|
pRecRenderData->pWriter->MuxerClose(pRecRenderData->pMuxerCtx);
|
|
pRecRenderData->pMuxerCtx = NULL;
|
|
alogd("muxChn[%d-%d] mbSdCardState[%d], sdcard is pull out, muxer close done!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mbSdCardState);
|
|
}
|
|
if(pRecRenderData->nOutputFd>=0)
|
|
{
|
|
close(pRecRenderData->nOutputFd);
|
|
pRecRenderData->nOutputFd = -1;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] nOutputFd[%d]<0", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->nOutputFd);
|
|
}
|
|
if(FSWRITEMODE_CACHETHREAD == pRecRenderData->mChnAttr.mFsWriteMode)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] not use cacheThread mode now!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pRecRenderData->pWriter->MuxerIoctrl(pRecRenderData->pMuxerCtx, SETTOTALTIME, pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex], NULL);
|
|
pRecRenderData->pWriter->MuxerWriteTrailer(pRecRenderData->pMuxerCtx);
|
|
pRecRenderData->pWriter->MuxerClose(pRecRenderData->pMuxerCtx);
|
|
pRecRenderData->pMuxerCtx = NULL;
|
|
//pSinkInfo->nCallbackOutFlag = FALSE;
|
|
}
|
|
cedarx_record_writer_destroy(pRecRenderData->pWriter);
|
|
pRecRenderData->pWriter = NULL;
|
|
pthread_mutex_lock(&pRecRenderData->mJudgeSwitchlock);
|
|
pRecRenderData->bNeedSw = FALSE;
|
|
pRecRenderData->bNeedSwAudio = FALSE;
|
|
pRecRenderData->mbMuxerInit = FALSE;
|
|
pthread_mutex_unlock(&pRecRenderData->mJudgeSwitchlock);
|
|
pRecRenderData->pCallbacks->EventHandler(pRecRenderData->hSelf, pRecRenderData->pAppData, COMP_EventRecordDone, pRecRenderData->mChnAttr.mMuxerId, 0, NULL);
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] record writer is null", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
pRecRenderData->mbMuxerInit = FALSE;
|
|
}
|
|
int videoStreamIndex = pRecRenderData->mRefVideoStreamIndex;
|
|
int audioStreamIndex = pRecRenderData->media_inf.mVideoInfoValidNum;
|
|
// alogd("TOTAL duration: %d(ms)", pSinkInfo->mDuration);
|
|
// alogd("TOTAL duration audio: %d(ms)", pSinkInfo->mDurationAudio);
|
|
// alogd("TOTAL duration text: %d(ms)", pSinkInfo->mDurationText);
|
|
alogd("muxChn[%d-%d] LOOP duration:[%lld-%lld]ms, lastPts v[%lld]-a[%lld]=[%lld]ms, duration:[%d-%d-%d]ms,"
|
|
"curInputPts v[%lld]-a[%lld]=[%lld]ms, fileSize:[%lld]bytes, needSwitchFlag:%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mLoopDuration, pRecRenderData->mLoopDurationAudio,
|
|
(pRecRenderData->mPrevPts[videoStreamIndex] + pRecRenderData->mBasePts[videoStreamIndex])/1000,
|
|
(pRecRenderData->mPrevPts[audioStreamIndex] + pRecRenderData->mBasePts[audioStreamIndex])/1000,
|
|
(pRecRenderData->mPrevPts[videoStreamIndex] + pRecRenderData->mBasePts[videoStreamIndex] - (pRecRenderData->mPrevPts[audioStreamIndex] + pRecRenderData->mBasePts[audioStreamIndex]))/1000,
|
|
pRecRenderData->mDuration[videoStreamIndex], pRecRenderData->mDurationAudio, pRecRenderData->mDurationText,
|
|
pRecRenderData->mDebugInputPts[videoStreamIndex]/1000,
|
|
pRecRenderData->mDebugInputPts[audioStreamIndex]/1000,
|
|
(pRecRenderData->mDebugInputPts[videoStreamIndex] - pRecRenderData->mDebugInputPts[audioStreamIndex])/1000,
|
|
pRecRenderData->mFileSizeBytes, pRecRenderData->bNeedSw, pRecRenderData->bNeedSwAudio);
|
|
return SUCCESS;
|
|
}
|
|
|
|
static ERRORTYPE RecSinkDrainAllRSPackets(RECRENDERDATATYPE *pRecRenderData)
|
|
{
|
|
int cnt = 0;
|
|
int sendCnt = 0;
|
|
RecSinkPacket *pEntry, *pTmp;
|
|
RecSinkPacket *pRSPacket;
|
|
pthread_mutex_lock(&pRecRenderData->mRSPacketListMutex);
|
|
alogd("muxerChn[%d-%d] muxerMode[%d] begin to drain packets", pRecRenderData->mMppChnInfo.mChnId,
|
|
pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mChnAttr.mMediaFileFormat);
|
|
while(1)
|
|
{
|
|
if(!pRecRenderData->mbSdCardState || pRecRenderData->mbShutDownNowFlag)
|
|
{
|
|
alogd("sdcard is pull out or shutdown now!");
|
|
break;
|
|
}
|
|
pRSPacket = RecSinkGetRSPacket_l(pRecRenderData);
|
|
if(pRSPacket)
|
|
{
|
|
cnt++;
|
|
if(pRecRenderData->mbMuxerInit == FALSE)
|
|
{
|
|
BOOL bGrant = TRUE;
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_VIDEO)
|
|
{
|
|
if(!(pRSPacket->mFlags & AVPACKET_FLAG_KEYFRAME))
|
|
{
|
|
bGrant = FALSE;
|
|
}
|
|
}
|
|
if(bGrant)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mutex_reset_writer_lock);
|
|
if(pRecRenderData->nCallbackOutFlag==TRUE || (pRecRenderData->nOutputFd>=0) || pRecRenderData->reset_fd_flag==TRUE)
|
|
{
|
|
if(RecSinkMuxerInit(pRecRenderData, pRSPacket) != SUCCESS)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] MuxerInit Error!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
//pRecRenderData->state = COMP_StateInvalid; //OMX_StateIdle;
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
RecSinkReleaseRSPacket_l(pRecRenderData, pRSPacket);
|
|
break;
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
}
|
|
}
|
|
if(pRecRenderData->mbMuxerInit)
|
|
{
|
|
RecSinkWriteRSPacket(pRecRenderData, pRSPacket);
|
|
}
|
|
//release RSPacket
|
|
RecSinkReleaseRSPacket_l(pRecRenderData, pRSPacket);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(!list_empty(&pRecRenderData->mValidRSPacketList))
|
|
{
|
|
list_for_each_entry_safe(pEntry, pTmp, &pRecRenderData->mValidRSPacketList, mList)
|
|
{
|
|
//pRecSink->mpCallbacks->EmptyBufferDone(pRecSink, pRecSink->mpAppData, pEntry);
|
|
RecRender_ReleaseBuffer(pRecRenderData, pEntry);
|
|
list_move_tail(&pEntry->mList, &pRecRenderData->mIdleRSPacketList);
|
|
cnt++;
|
|
sendCnt++;
|
|
}
|
|
alogd("left [%d]packets to send out immediately", sendCnt);
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mRSPacketListMutex);
|
|
alogd("muxChn[%d-%d]muxerMode[%d] drain [%d]packets, ShutDownNow[%d]",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
map_MEDIA_FILE_FORMAT_E_to_MUXERMODES(pRecRenderData->mChnAttr.mMediaFileFormat),
|
|
cnt, pRecRenderData->mbShutDownNowFlag);
|
|
return SUCCESS;
|
|
}
|
|
|
|
static ERRORTYPE RecRenderReleaseAllFrames(RECRENDERDATATYPE *pRecRenderData)
|
|
{
|
|
ERRORTYPE eRet;
|
|
pthread_mutex_lock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
ENCODER_NODE_T *pVEntry, *pVTmp;
|
|
if (!list_empty(&pRecRenderData->mVideoInputFrameUsedList))
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] Used video frame should all released before!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
if (!list_empty(&pRecRenderData->mVideoInputFrameReadyList))
|
|
{
|
|
int nCnt = 0;
|
|
list_for_each_entry_safe(pVEntry, pVTmp, &pRecRenderData->mVideoInputFrameReadyList, mList)
|
|
{
|
|
nCnt++;
|
|
if(pVEntry->mUsedRefCnt != 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] RefCnt[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pVEntry->mUsedRefCnt);
|
|
}
|
|
list_move_tail(&pVEntry->mList, &pRecRenderData->mVideoInputFrameIdleList);
|
|
if(pVEntry->mPortIndex >= MAX_REC_RENDER_PORTS)
|
|
{
|
|
aloge("fatal error! check code! port index:%d", pVEntry->mPortIndex);
|
|
}
|
|
if(pRecRenderData->sInPortDef[pVEntry->mPortIndex].nPortIndex != pVEntry->mPortIndex)
|
|
{
|
|
aloge("fatal error! check port index and suffix:%d!=%d", pRecRenderData->sInPortDef[pVEntry->mPortIndex].nPortIndex, pVEntry->mPortIndex);
|
|
}
|
|
if(pRecRenderData->mInputPortTunnelFlag[pVEntry->mPortIndex])
|
|
{
|
|
if (COMP_PortDomainVideo != pRecRenderData->sInPortDef[pVEntry->mPortIndex].eDomain)
|
|
{
|
|
aloge("fatal error! port[%d] domain[0x%x] is not video!", pVEntry->mPortIndex, pRecRenderData->sInPortDef[pVEntry->mPortIndex].eDomain);
|
|
}
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nOutputPortIndex = pRecRenderData->sInPortTunnelInfo[pVEntry->mPortIndex].nTunnelPortIndex;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pVEntry->mPortIndex].nPortIndex;
|
|
obh.pOutputPortPrivate = (void*)&pVEntry->stEncodedStream;
|
|
eRet = COMP_FillThisBuffer(pRecRenderData->sInPortTunnelInfo[pVEntry->mPortIndex].hTunnel, &obh);
|
|
if(eRet != SUCCESS)
|
|
{
|
|
aloge("fatal error! fill this buffer fail[0x%x], video frame id=[%d], discard it!", eRet, pVEntry->stEncodedStream.nID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pVEntry->mPortIndex].nPortIndex;
|
|
obh.pAppPrivate = (void*)&pVEntry->stEncodedStream;
|
|
if(pVEntry->mPortIndex != obh.nInputPortIndex)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] video streamId[%d!=%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pVEntry->mPortIndex, obh.nInputPortIndex);
|
|
}
|
|
pRecRenderData->pCallbacks->EmptyBufferDone(pRecRenderData->hSelf, pRecRenderData->pAppData, &obh);
|
|
}
|
|
}
|
|
alogd("muxChn[%d-%d] [%d]Ready video frames should all release before!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, nCnt);
|
|
}
|
|
|
|
int iIdleVideoFrameCnt = 0;
|
|
list_for_each_entry(pVEntry, &pRecRenderData->mVideoInputFrameIdleList, mList)
|
|
{
|
|
iIdleVideoFrameCnt++;
|
|
}
|
|
if (iIdleVideoFrameCnt != pRecRenderData->mVideoInputFrameNum)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] video input idle frames [%d]<[%d] must return all before",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, iIdleVideoFrameCnt, pRecRenderData->mVideoInputFrameNum);
|
|
}
|
|
else
|
|
{
|
|
//alogd("Release all video input frame [%d]", pRecRenderData->mVideoInputFrameNum);
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mVideoInputFrameListMutex);
|
|
|
|
pthread_mutex_lock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
ENCODER_NODE_T *pAEntry, *pATmp;
|
|
if (!list_empty(&pRecRenderData->mAudioInputFrameUsedList))
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] used audio frame should all released before!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
if (!list_empty(&pRecRenderData->mAudioInputFrameReadyList))
|
|
{
|
|
int nCnt = 0;
|
|
list_for_each_entry_safe(pAEntry, pATmp, &pRecRenderData->mAudioInputFrameReadyList, mList)
|
|
{
|
|
nCnt++;
|
|
if(pAEntry->mUsedRefCnt != 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] RefCnt[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pAEntry->mUsedRefCnt);
|
|
}
|
|
list_move_tail(&pAEntry->mList, &pRecRenderData->mAudioInputFrameIdleList);
|
|
if(pAEntry->mPortIndex >= MAX_REC_RENDER_PORTS)
|
|
{
|
|
aloge("fatal error! check code! port index:%d", pAEntry->mPortIndex);
|
|
}
|
|
if(pRecRenderData->sInPortDef[pAEntry->mPortIndex].nPortIndex != pAEntry->mPortIndex)
|
|
{
|
|
aloge("fatal error! check port index and suffix:%d!=%d", pRecRenderData->sInPortDef[pAEntry->mPortIndex].nPortIndex, pAEntry->mPortIndex);
|
|
}
|
|
if(pRecRenderData->mInputPortTunnelFlag[pAEntry->mPortIndex])
|
|
{
|
|
if (COMP_PortDomainAudio != pRecRenderData->sInPortDef[pAEntry->mPortIndex].eDomain)
|
|
{
|
|
aloge("fatal error! port[%d] domain[0x%x] is not audio!", pAEntry->mPortIndex, pRecRenderData->sInPortDef[pAEntry->mPortIndex].eDomain);
|
|
}
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nOutputPortIndex = pRecRenderData->sInPortTunnelInfo[pAEntry->mPortIndex].nTunnelPortIndex;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pAEntry->mPortIndex].nPortIndex;
|
|
obh.pOutputPortPrivate = (void*)&pAEntry->stEncodedStream;
|
|
eRet = COMP_FillThisBuffer(pRecRenderData->sInPortTunnelInfo[pAEntry->mPortIndex].hTunnel, &obh);
|
|
if(eRet != SUCCESS)
|
|
{
|
|
aloge("fatal error! fill this buffer fail[0x%x], audio frame id=[%d], discard it!", eRet, pAEntry->stEncodedStream.nID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pAEntry->mPortIndex].nPortIndex;
|
|
obh.pAppPrivate = (void*)&pAEntry->stEncodedStream;
|
|
if(pAEntry->mPortIndex != obh.nInputPortIndex)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] audio streamId[%d!=%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pAEntry->mPortIndex, obh.nInputPortIndex);
|
|
}
|
|
pRecRenderData->pCallbacks->EmptyBufferDone(pRecRenderData->hSelf, pRecRenderData->pAppData, &obh);
|
|
}
|
|
}
|
|
alogd("muxChn[%d-%d] [%d]Ready audio frames should all released before!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, nCnt);
|
|
}
|
|
|
|
int iIdleAudioFrameCnt = 0;
|
|
list_for_each_entry(pAEntry, &pRecRenderData->mAudioInputFrameIdleList, mList)
|
|
{
|
|
iIdleAudioFrameCnt++;
|
|
}
|
|
if (iIdleAudioFrameCnt != pRecRenderData->mAudioInputFrameNum)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] audio input frames [%d]<[%d] must return all before",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, iIdleAudioFrameCnt, pRecRenderData->mAudioInputFrameNum);
|
|
}
|
|
else
|
|
{
|
|
//alogd("Release all audio input frame [%d]", pRecRenderData->mAudioInputFrameNum);
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mAudioInputFrameListMutex);
|
|
|
|
pthread_mutex_lock(&pRecRenderData->mTextInputFrameListMutex);
|
|
ENCODER_NODE_T *pTEntry, *pTTmp;
|
|
if (!list_empty(&pRecRenderData->mTextInputFrameUsedList))
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] used text frame should all released before!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
if (!list_empty(&pRecRenderData->mTextInputFrameReadyList))
|
|
{
|
|
int nCnt = 0;
|
|
list_for_each_entry_safe(pTEntry, pTTmp, &pRecRenderData->mTextInputFrameReadyList, mList)
|
|
{
|
|
nCnt++;
|
|
if(pTEntry->mUsedRefCnt != 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] RefCnt[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pTEntry->mUsedRefCnt);
|
|
}
|
|
list_move_tail(&pTEntry->mList, &pRecRenderData->mTextInputFrameIdleList);
|
|
if(pTEntry->mPortIndex >= MAX_REC_RENDER_PORTS)
|
|
{
|
|
aloge("fatal error! check code! port index:%d", pTEntry->mPortIndex);
|
|
}
|
|
if(pRecRenderData->sInPortDef[pTEntry->mPortIndex].nPortIndex != pTEntry->mPortIndex)
|
|
{
|
|
aloge("fatal error! check port index and suffix:%d!=%d", pRecRenderData->sInPortDef[pTEntry->mPortIndex].nPortIndex, pTEntry->mPortIndex);
|
|
}
|
|
if(pRecRenderData->mInputPortTunnelFlag[pTEntry->mPortIndex])
|
|
{
|
|
if (COMP_PortDomainText != pRecRenderData->sInPortDef[pTEntry->mPortIndex].eDomain)
|
|
{
|
|
aloge("fatal error! port[%d] domain[0x%x] is not text!", pTEntry->mPortIndex, pRecRenderData->sInPortDef[pTEntry->mPortIndex].eDomain);
|
|
}
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nOutputPortIndex = pRecRenderData->sInPortTunnelInfo[pTEntry->mPortIndex].nTunnelPortIndex;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pTEntry->mPortIndex].nPortIndex;
|
|
obh.pOutputPortPrivate = (void*)&pTEntry->stEncodedStream;
|
|
eRet = COMP_FillThisBuffer(pRecRenderData->sInPortTunnelInfo[pTEntry->mPortIndex].hTunnel, &obh);
|
|
if(eRet != SUCCESS)
|
|
{
|
|
aloge("fatal error! fill this buffer fail[0x%x], text frame id=[%d], discard it!", eRet, pTEntry->stEncodedStream.nID);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
COMP_BUFFERHEADERTYPE obh;
|
|
obh.nInputPortIndex = pRecRenderData->sInPortTunnelInfo[pTEntry->mPortIndex].nPortIndex;
|
|
obh.pAppPrivate = (void*)&pTEntry->stEncodedStream;
|
|
if(pTEntry->mPortIndex != obh.nInputPortIndex)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] text streamId[%d!=%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pTEntry->mPortIndex, obh.nInputPortIndex);
|
|
}
|
|
pRecRenderData->pCallbacks->EmptyBufferDone(pRecRenderData->hSelf, pRecRenderData->pAppData, &obh);
|
|
}
|
|
}
|
|
alogd("muxChn[%d-%d] [%d]Ready text frame should all released before!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, nCnt);
|
|
}
|
|
|
|
int iIdleTextFrameCnt = 0;
|
|
list_for_each_entry(pTEntry, &pRecRenderData->mTextInputFrameIdleList, mList)
|
|
{
|
|
iIdleTextFrameCnt++;
|
|
}
|
|
if (iIdleTextFrameCnt != pRecRenderData->mTextInputFrameNum)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] text input frames [%d]<[%d] must return all before",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, iIdleTextFrameCnt, pRecRenderData->mTextInputFrameNum);
|
|
}
|
|
else
|
|
{
|
|
//alogd("Release all text input frame [%d]", pRecRenderData->mTextInputFrameNum);
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mTextInputFrameListMutex);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
static ERRORTYPE RecSinkToForceIFrame(RECRENDERDATATYPE *pRecRenderData, int nStreamId)
|
|
{
|
|
ERRORTYPE eError = SUCCESS;
|
|
if(nStreamId >= MAX_REC_RENDER_PORTS)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] streamId:%d wrong", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, nStreamId);
|
|
}
|
|
if(pRecRenderData->sInPortDef[nStreamId].nPortIndex != nStreamId)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] check portIndex/streamId and suffix:%d!=%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->sInPortDef[nStreamId].nPortIndex, nStreamId);
|
|
}
|
|
if(pRecRenderData->mInputPortTunnelFlag[nStreamId])
|
|
{
|
|
if (COMP_PortDomainVideo != pRecRenderData->sInPortDef[nStreamId].eDomain)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] port[%d] domain[0x%x] is not video!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
nStreamId, pRecRenderData->sInPortDef[nStreamId].eDomain);
|
|
}
|
|
BOOL bRequest = TRUE;
|
|
eError = COMP_SetConfig(pRecRenderData->sInPortTunnelInfo[nStreamId].hTunnel, COMP_IndexVendorVencRequestIDR, (void*)&bRequest);
|
|
if(eError != SUCCESS)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] streamId[%d] forceIFrame fail[0x%x]!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
nStreamId, eError);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
eError = pRecRenderData->pCallbacks->EventHandler(pRecRenderData->hSelf, pRecRenderData->pAppData,
|
|
COMP_EventMuxForceIFrame, nStreamId, 0, NULL);
|
|
}
|
|
return eError;
|
|
}
|
|
|
|
/**
|
|
check if need switch file.
|
|
|
|
@param[out] need_switch_audio
|
|
if audio reach file duration first, set need_switch_audio to true, else set to false.
|
|
|
|
@return
|
|
true: video reach file duration first.
|
|
false: video not reach file duration.
|
|
*/
|
|
static BOOL RecSinkIfNeedSwitchFile(RECRENDERDATATYPE *pRecRenderData, int *need_switch_audio)
|
|
{
|
|
BOOL bNeedSwitch = FALSE;
|
|
pthread_mutex_lock(&pRecRenderData->mJudgeSwitchlock);
|
|
if(TRUE == pRecRenderData->bNeedSw)
|
|
{
|
|
pthread_mutex_unlock(&pRecRenderData->mJudgeSwitchlock);
|
|
return pRecRenderData->bNeedSw;
|
|
}
|
|
else if(TRUE == pRecRenderData->bNeedSwAudio)
|
|
{
|
|
*need_switch_audio = 1;
|
|
pthread_mutex_unlock(&pRecRenderData->mJudgeSwitchlock);
|
|
return FALSE;
|
|
}
|
|
|
|
if(pRecRenderData->mbMuxerInit /* && pRecRenderData->reset_fd_flag == TRUE */ && !pRecRenderData->nCallbackOutFlag) // no network
|
|
{
|
|
if(pRecRenderData->rec_file == FILE_NEED_SWITCH_TO_NORMAL)
|
|
{
|
|
bNeedSwitch = TRUE;
|
|
pRecRenderData->bNeedSw = TRUE;
|
|
}
|
|
else if(pRecRenderData->mCurMaxFileDuration > 0) //user set max duration, then segment file base on duration
|
|
{
|
|
//if(pRecSink->mLoopDuration >= pRecSink->mCurFileEndTm)
|
|
//{
|
|
// bNeedSwitch = TRUE;
|
|
//}
|
|
//int nErrorInterval = 1000*1000/pRecSink->mpMediaInf->uVideoFrmRate/3; //unit:ms
|
|
//int nErrorInterval = 1000*1000/pRecSink->mpMediaInf->mMediaVideoInfo[pRecSink->mRefVideoStreamIndex].uVideoFrmRate/3;
|
|
if((pRecRenderData->mFileDurationPolicy == RecordFileDurationPolicy_MinDuration)
|
|
|| (pRecRenderData->mFileDurationPolicy == RecordFileDurationPolicy_AccurateDuration))
|
|
{
|
|
if(pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex] /*+ nErrorInterval*/ >= pRecRenderData->mCurMaxFileDuration) // to use current actual duration,since current pkt will not be sent out
|
|
{
|
|
bNeedSwitch = TRUE;
|
|
pRecRenderData->bNeedSw = TRUE;
|
|
alogd("muxChn[%d-%d] need_file_switch_v:%d-%d-%lld-%d-%d-%d-%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex],
|
|
pRecRenderData->mDurationAudio,
|
|
pRecRenderData->mCurMaxFileDuration,
|
|
pRecRenderData->mFileDurationPolicy,
|
|
pRecRenderData->video_frm_cnt, pRecRenderData->audio_frm_cnt,
|
|
pRecRenderData->mVideoFrameCounter, pRecRenderData->mAudioFrmCnt);
|
|
}
|
|
}
|
|
else if(pRecRenderData->mFileDurationPolicy == RecordFileDurationPolicy_AverageDuration)
|
|
{
|
|
if(pRecRenderData->mLoopDuration /*+ nErrorInterval*/ >= pRecRenderData->mCurFileEndTm)
|
|
{
|
|
bNeedSwitch = TRUE;
|
|
pRecRenderData->bNeedSw = TRUE;
|
|
alogd("muxChn[%d-%d] need_file_switch_v3:%d-%d-%lld-%d-%lld-%lld-%lld-%d-%d-%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex], pRecRenderData->mDurationAudio,
|
|
pRecRenderData->mCurMaxFileDuration,
|
|
pRecRenderData->mFileDurationPolicy,
|
|
pRecRenderData->mLoopDuration, pRecRenderData->mCurFileEndTm,
|
|
pRecRenderData->mLoopDurationAudio,
|
|
pRecRenderData->video_frm_cnt, pRecRenderData->audio_frm_cnt,
|
|
pRecRenderData->mVideoFrameCounter, pRecRenderData->mAudioFrmCnt);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! unknown FileDurationPolicy[0x%x], check code!", pRecRenderData->mFileDurationPolicy);
|
|
}
|
|
|
|
if(FALSE == bNeedSwitch && (pRecRenderData->mRecordMode & RECORDER_MODE_AUDIO) && (pRecRenderData->mRecordMode & RECORDER_MODE_VIDEO))
|
|
{
|
|
// to check audio status, must has video. when only has audio, pRecRenderData->mDuration[0] and pRecRenderData->mLoopDuration
|
|
// are used to record audio duration and loopDurationAudio.
|
|
//int nErrorInterval = MAXDECODESAMPLE*1000 / pRecSink->mpMediaInf->sample_rate/3; //unit:ms
|
|
*need_switch_audio = 0;
|
|
if(pRecRenderData->mFileDurationPolicy == RecordFileDurationPolicy_MinDuration ||
|
|
pRecRenderData->mFileDurationPolicy == RecordFileDurationPolicy_AccurateDuration)
|
|
{
|
|
if(pRecRenderData->mDurationAudio /*+ nErrorInterval*/ >= pRecRenderData->mCurMaxFileDuration)
|
|
{
|
|
*need_switch_audio = 1;
|
|
pRecRenderData->bNeedSwAudio = TRUE;
|
|
aloge("muxChn[%d-%d] need_file_switch_a:%d-%d-%lld-%d-%lld-%lld-%d-%d-%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mDurationAudio, pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex],
|
|
pRecRenderData->mCurMaxFileDuration, pRecRenderData->mFileDurationPolicy,
|
|
pRecRenderData->mLoopDurationAudio, pRecRenderData->mLoopDuration,
|
|
pRecRenderData->video_frm_cnt, pRecRenderData->audio_frm_cnt,
|
|
pRecRenderData->mVideoFrameCounter, pRecRenderData->mAudioFrmCnt);
|
|
}
|
|
}
|
|
else if(pRecRenderData->mFileDurationPolicy == RecordFileDurationPolicy_AverageDuration)
|
|
{
|
|
if(pRecRenderData->mLoopDurationAudio /*+ nErrorInterval*/ >= pRecRenderData->mCurFileEndTm)
|
|
{
|
|
*need_switch_audio = 1;
|
|
pRecRenderData->bNeedSwAudio = TRUE;
|
|
aloge("muxChn[%d-%d] need_file_switch_a3:%d-%d-%lld-%d-%lld-%lld-%lld-%d-%d-%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mDurationAudio, pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex],
|
|
pRecRenderData->mCurMaxFileDuration, pRecRenderData->mFileDurationPolicy,
|
|
pRecRenderData->mLoopDurationAudio, pRecRenderData->mLoopDuration, pRecRenderData->mCurFileEndTm,
|
|
pRecRenderData->video_frm_cnt, pRecRenderData->audio_frm_cnt,
|
|
pRecRenderData->mVideoFrameCounter, pRecRenderData->mAudioFrmCnt);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! unknown FileDurationPolicy[0x%x], check code!", pRecRenderData->mFileDurationPolicy);
|
|
}
|
|
}
|
|
}
|
|
else if(pRecRenderData->mMaxFileSizeBytes > 0) //user set max file size, then segment file base on fileSize.
|
|
{
|
|
if(pRecRenderData->mFileSizeBytes >= pRecRenderData->mMaxFileSizeBytes)
|
|
{
|
|
double fileSizeMB = (double)pRecRenderData->mFileSizeBytes/(1024*1024);
|
|
alogv("muxChn[%d-%d] fileSize[%lld]Bytes([%7.3lf]MB) >= max[%7.3lf]MB, rec_file[%d], need switch file",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mFileSizeBytes, fileSizeMB, (double)pRecRenderData->mMaxFileSizeBytes/(1024*1024),
|
|
pRecRenderData->rec_file);
|
|
bNeedSwitch = TRUE;
|
|
pRecRenderData->bNeedSw = TRUE;
|
|
}
|
|
}
|
|
else //not switch file
|
|
{
|
|
bNeedSwitch = FALSE;
|
|
pRecRenderData->bNeedSw = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bNeedSwitch = FALSE;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mJudgeSwitchlock);
|
|
return bNeedSwitch;
|
|
}
|
|
|
|
static BOOL RecSink_CheckStreamIdValid(RECRENDERDATATYPE *pRecRenderData, int nStreamId)
|
|
{
|
|
if(pRecRenderData->mValidStreamCount < 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
for(int i=0; i<pRecRenderData->mValidStreamCount; i++)
|
|
{
|
|
if(pRecRenderData->mValidStreamIds[i] == nStreamId)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static BOOL RecSinkGrantSwitchFile(RECRENDERDATATYPE *pRecRenderData, RecSinkPacket *pRSPacket)
|
|
{
|
|
BOOL bGrant = TRUE;
|
|
|
|
if(RecordFileDurationPolicy_AccurateDuration == pRecRenderData->mFileDurationPolicy)
|
|
{
|
|
bGrant = TRUE;
|
|
}
|
|
else if(RecordFileDurationPolicy_MinDuration == pRecRenderData->mFileDurationPolicy
|
|
|| RecordFileDurationPolicy_AverageDuration == pRecRenderData->mFileDurationPolicy)
|
|
{
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_VIDEO)
|
|
{
|
|
if(pRecRenderData->media_inf.mVideoInfoValidNum > MAX_VIDEO_TRACK_COUNT)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] video stream num[%d] too many!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->media_inf.mVideoInfoValidNum);
|
|
}
|
|
//when video meets key frame, we will set prefetch flag, so by prefetch flags, we can decide if all videos meet key frame.
|
|
BOOL bKeyFrameReady = FALSE;
|
|
int i;
|
|
for(i=0; i<pRecRenderData->media_inf.mVideoInfoValidNum; i++)
|
|
{
|
|
if(FALSE == RecSink_CheckStreamIdValid(pRecRenderData, i))
|
|
{
|
|
alogd("muxChn[%d-%d] streamId[%d] is not valid, ignore", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, i);
|
|
continue;
|
|
}
|
|
if(!pRecRenderData->mPrefetchFlag[i])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(i == pRecRenderData->media_inf.mVideoInfoValidNum)
|
|
{
|
|
bKeyFrameReady = TRUE;
|
|
}
|
|
|
|
//use videoStream0 to compare with audioStream
|
|
BOOL bAudioDone = FALSE;
|
|
if(pRecRenderData->mPrefetchFlag[pRecRenderData->mRefVideoStreamIndex])
|
|
{
|
|
int64_t nVideoTotalTm = -1; //unit:ms
|
|
int64_t nAudioTotalTm = -1; //unit:ms
|
|
int VFrameDuration = 1000*1000 / pRecRenderData->media_inf.mMediaVideoInfo[pRecRenderData->mRefVideoStreamIndex].uVideoFrmRate;
|
|
nVideoTotalTm = (pRecRenderData->mPrevPts[pRecRenderData->mRefVideoStreamIndex] + pRecRenderData->mBasePts[pRecRenderData->mRefVideoStreamIndex])/1000+VFrameDuration;
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_AUDIO)
|
|
{
|
|
int AFrameDuration = MAXDECODESAMPLE*1000 / pRecRenderData->media_inf.sample_rate;
|
|
int audioStreamIndex = pRecRenderData->media_inf.mVideoInfoValidNum;
|
|
nAudioTotalTm = (pRecRenderData->mPrevPts[audioStreamIndex]+pRecRenderData->mBasePts[audioStreamIndex])/1000+AFrameDuration;
|
|
if(nAudioTotalTm >= nVideoTotalTm)
|
|
{
|
|
alogd("muxChn[%d-%d] refVideoStream[%d] can switch file. aSrcPts[%lld]ms, vSrcPts[%lld]ms, ATime[%lld]-VTime[%lld]=[%lld]ms, rec_file[%d]",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mRefVideoStreamIndex,
|
|
(pRecRenderData->mPrevPts[audioStreamIndex]+pRecRenderData->mBasePts[audioStreamIndex])/1000,
|
|
(pRecRenderData->mPrevPts[pRecRenderData->mRefVideoStreamIndex]+pRecRenderData->mBasePts[pRecRenderData->mRefVideoStreamIndex])/1000,
|
|
nAudioTotalTm,
|
|
nVideoTotalTm,
|
|
nAudioTotalTm - nVideoTotalTm,
|
|
pRecRenderData->rec_file);
|
|
bAudioDone = TRUE;
|
|
if(!bKeyFrameReady)
|
|
{
|
|
alogw("Be careful! muxChn[%d-%d] refVideoStream[%d]. Not all video streams meet key frame! we still can't switch file, begin to prefetch audio!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mRefVideoStreamIndex);
|
|
//we need cache audio now. wait other videos to meet key frame.
|
|
pRecRenderData->mPrefetchFlagAudio = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(CODEC_TYPE_AUDIO == pRSPacket->mStreamType)
|
|
{
|
|
alogv("muxChn[%d-%d] wait switch file. audio packet. Time a[%lld]ms < v[%lld]ms, rec_file[%d]",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
nAudioTotalTm, nVideoTotalTm, pRecRenderData->rec_file);
|
|
}
|
|
bAudioDone = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bAudioDone = TRUE;
|
|
}
|
|
}
|
|
|
|
if(bKeyFrameReady && bAudioDone)
|
|
{
|
|
int i;
|
|
for(i=0; i<pRecRenderData->media_inf.mVideoInfoValidNum; i++)
|
|
{
|
|
alogd("muxChn[%d-%d] can switch file. VStreamId[%d]Dur:[%d]ms", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, i, pRecRenderData->mDuration[i]);
|
|
}
|
|
alogd("muxChn[%d-%d] can switch file. ADur:[%d]ms", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mDurationAudio);
|
|
bGrant = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bGrant = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bGrant = TRUE;
|
|
}
|
|
}
|
|
return bGrant;
|
|
}
|
|
|
|
/**
|
|
decide if can switch file when audio first meet switch file duration.
|
|
need cache following audio frames to wait video pts to reach audioPts that is at switchFile point. But video need
|
|
switch file at key frame, so when video pts reach that audio pts but witch not key frame, video frames need to be
|
|
written to file contiguously until key frame coming. So cached audio frames need to be written to file again to
|
|
reach video pts, this is done in RecSinkSwitchFile().
|
|
*/
|
|
BOOL RecSinkGrantSwitchFileAudio(RECRENDERDATATYPE *pRecRenderData, RecSinkPacket *pRSPacket)
|
|
{
|
|
BOOL bGrant = TRUE;
|
|
|
|
if(RecordFileDurationPolicy_AccurateDuration == pRecRenderData->mFileDurationPolicy)
|
|
{
|
|
bGrant = TRUE;
|
|
}
|
|
else if(RecordFileDurationPolicy_MinDuration == pRecRenderData->mFileDurationPolicy
|
|
|| RecordFileDurationPolicy_AverageDuration == pRecRenderData->mFileDurationPolicy)
|
|
{
|
|
if(!(pRecRenderData->mRecordMode & RECORDER_MODE_VIDEO) || !(pRecRenderData->mRecordMode & RECORDER_MODE_AUDIO))
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] recordMode[0x%x] wrong!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mRecordMode);
|
|
}
|
|
//(1)video0 duration >= audio duration
|
|
if(!pRecRenderData->bTimeMeetAudio)
|
|
{
|
|
int64_t nVideoTotalTm = -1; //unit:ms
|
|
int64_t nAudioTotalTm = -1; //unit:ms
|
|
int audioStreamIndex = pRecRenderData->media_inf.mVideoInfoValidNum;
|
|
int VFrameDuration = 1000*1000 / pRecRenderData->media_inf.mMediaVideoInfo[pRecRenderData->mRefVideoStreamIndex].uVideoFrmRate;
|
|
int AFrameDuration = MAXDECODESAMPLE*1000 / pRecRenderData->media_inf.sample_rate;
|
|
nVideoTotalTm = (pRecRenderData->mPrevPts[pRecRenderData->mRefVideoStreamIndex]+pRecRenderData->mBasePts[pRecRenderData->mRefVideoStreamIndex])/1000+VFrameDuration;
|
|
nAudioTotalTm = (pRecRenderData->mPrevPts[audioStreamIndex]+pRecRenderData->mBasePts[audioStreamIndex])/1000+AFrameDuration;
|
|
if(nAudioTotalTm <= nVideoTotalTm)
|
|
{
|
|
alogd("muxChn[%d-%d] can switch file audio. VTime[%lld]-ATime[%lld]=[%lld]ms, rec_file[%d]",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
nVideoTotalTm, nAudioTotalTm, nVideoTotalTm-nAudioTotalTm, pRecRenderData->rec_file);
|
|
pRecRenderData->bTimeMeetAudio = TRUE;
|
|
}
|
|
}
|
|
//(2)all videos meet key frame.
|
|
BOOL bKeyFrameReady = FALSE;
|
|
if(pRecRenderData->bTimeMeetAudio)
|
|
{
|
|
if((pRSPacket->mStreamType==CODEC_TYPE_VIDEO) && (pRSPacket->mFlags&AVPACKET_FLAG_KEYFRAME))
|
|
{
|
|
if(pRSPacket->mStreamId >= MAX_VIDEO_TRACK_COUNT)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] wrong streamId[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRSPacket->mStreamId);
|
|
}
|
|
if(!pRecRenderData->mPrefetchFlag[pRSPacket->mStreamId])
|
|
{
|
|
//if current frame is video key frame, we can set prefetchFlag for this video.
|
|
pRecRenderData->mPrefetchFlag[pRSPacket->mStreamId] = TRUE;
|
|
}
|
|
}
|
|
if(pRecRenderData->media_inf.mVideoInfoValidNum > MAX_VIDEO_TRACK_COUNT)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] video stream num[%d] too many!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->media_inf.mVideoInfoValidNum);
|
|
}
|
|
int i;
|
|
for(i=0; i<pRecRenderData->media_inf.mVideoInfoValidNum; i++)
|
|
{
|
|
if(FALSE == RecSink_CheckStreamIdValid(pRecRenderData, i))
|
|
{
|
|
alogd("muxChn[%d-%d] streamId[%d] is not valid, ignore", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, i);
|
|
continue;
|
|
}
|
|
if(!pRecRenderData->mPrefetchFlag[i])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(i == pRecRenderData->media_inf.mVideoInfoValidNum)
|
|
{
|
|
bKeyFrameReady = TRUE;
|
|
}
|
|
}
|
|
if(pRecRenderData->bTimeMeetAudio && bKeyFrameReady)
|
|
{
|
|
int i;
|
|
for(i=0; i<pRecRenderData->media_inf.mVideoInfoValidNum; i++)
|
|
{
|
|
alogd("muxChn[%d-%d] can switch file. VStrm[%d]Dur:[%d]ms", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, i, pRecRenderData->mDuration[i]);
|
|
}
|
|
alogd("muxChn[%d-%d] can switch file. ADur:[%d]ms", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mDurationAudio);
|
|
bGrant = TRUE;
|
|
}
|
|
else
|
|
{
|
|
bGrant = FALSE;
|
|
}
|
|
}
|
|
return bGrant;
|
|
}
|
|
|
|
/**
|
|
switch file. Do following things:
|
|
muxer close,
|
|
clear some variables,
|
|
move prefetch packets to ready list,
|
|
prepare next file fd,
|
|
set rec_file.
|
|
*/
|
|
static void RecSinkSwitchFile(RECRENDERDATATYPE *pRecRenderData, int clrFile)
|
|
{
|
|
if(0 == pRecRenderData->nOutputFd)
|
|
{
|
|
aloge("Be careful, muxChn[%d-%d] fd == 0", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
// alogd("TOTAL duration: %d(ms)", pSinkInfo->mDuration);
|
|
// alogd("TOTAL duration audio: %d(ms)", pSinkInfo->mDurationAudio);
|
|
// alogd("TOTAL file size: %lld(bytes)", pSinkInfo->mFileSizeBytes);
|
|
|
|
//if switchFileAudio, let video duration >= audio duration.
|
|
if(TRUE==pRecRenderData->bTimeMeetAudio && 0<pRecRenderData->mVideoFrmCntWriteMore) // more video frame was sent to file
|
|
{
|
|
if(!(pRecRenderData->mRecordMode & RECORDER_MODE_VIDEO) || !(pRecRenderData->mRecordMode & RECORDER_MODE_AUDIO))
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] recordMode[0x%x] wrong!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->mRecordMode);
|
|
}
|
|
int cnt = 0;
|
|
int nAudCnt = 0;
|
|
RecSinkPacket *pEntry, *pTmp;
|
|
list_for_each_entry(pEntry, &pRecRenderData->mPrefetchRSPacketList, mList)
|
|
{
|
|
if(CODEC_TYPE_AUDIO == pEntry->mStreamType)
|
|
{
|
|
nAudCnt++;
|
|
}
|
|
cnt++;
|
|
}
|
|
alogd("muxChn[%d-%d] avsync_a_list:[%d]-%d-%d-%d-%lld-%lld-%d", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mRefVideoStreamIndex, cnt, nAudCnt, pRecRenderData->mVideoFrmCntWriteMore,
|
|
pRecRenderData->mVideoPtsWriteMoreSt, pRecRenderData->mVideoPtsWriteMoreEnd,
|
|
pRecRenderData->media_inf.mMediaVideoInfo[pRecRenderData->mRefVideoStreamIndex].nWidth);
|
|
|
|
int VFrameDuration = 1000*1000 / pRecRenderData->media_inf.mMediaVideoInfo[pRecRenderData->mRefVideoStreamIndex].uVideoFrmRate;
|
|
int AFrameDuration = MAXDECODESAMPLE*1000 / pRecRenderData->media_inf.sample_rate;
|
|
int nAFrmMore = 0; //the number of audio frames which will be written more to meet video pts.
|
|
BOOL bAllUsedFlag = TRUE; // the audio frames in prefetch list are all used to be written to file
|
|
list_for_each_entry_safe(pEntry, pTmp, &pRecRenderData->mPrefetchRSPacketList, mList)
|
|
{
|
|
//check video time and audio time.
|
|
if(CODEC_TYPE_AUDIO == pEntry->mStreamType)
|
|
{
|
|
int nAudioTotalTm = pEntry->mPts/1000+AFrameDuration;
|
|
int nVideoTotalTm = (pRecRenderData->mPrevPts[pRecRenderData->mRefVideoStreamIndex] + pRecRenderData->mBasePts[pRecRenderData->mRefVideoStreamIndex])/1000+VFrameDuration;
|
|
if(nAudioTotalTm > nVideoTotalTm)
|
|
{
|
|
//this aFrame don't be written to current file. because in switchFileAudio case, audioTime <= videoTime.
|
|
alogd("muxChn[%d-%d] avsync_rc_swfa: [%d]-%d-%d-%d", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mRefVideoStreamIndex, nVideoTotalTm, nAudioTotalTm, nAFrmMore);
|
|
bAllUsedFlag = FALSE;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
list_del(&pEntry->mList);
|
|
RecSinkWriteRSPacket(pRecRenderData, pEntry);
|
|
RecSinkReleaseRSPacket(pRecRenderData, pEntry);
|
|
nAFrmMore++;
|
|
}
|
|
}
|
|
}
|
|
if(bAllUsedFlag)
|
|
{
|
|
alogd("muxChn[%d-%d] avsync_rc_swfa write all afrms: %d-%d-%d", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex], pRecRenderData->mDurationAudio, nAFrmMore);
|
|
}
|
|
}
|
|
if(pRecRenderData->mPrefetchFlagAudio)
|
|
{
|
|
if(pRecRenderData->bNeedSw)
|
|
{
|
|
alogd("muxChn[%d-%d] switchFile cache video, but cache audio too!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
}
|
|
|
|
int64_t tm1, tm2;
|
|
tm1 = CDX_GetSysTimeUsMonotonic();
|
|
RecSinkMuxerClose(pRecRenderData, clrFile);
|
|
tm2 = CDX_GetSysTimeUsMonotonic();
|
|
alogd("muxChn[%d-%d] recRender_MuxerClose itl[%lld]ms", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, (tm2-tm1)/1000);
|
|
|
|
//post process: clear some variables, move prefetch packets to ready list, prepare next file fd, set rec_file.
|
|
int i;
|
|
for (i=0;i<MAX_VIDEO_TRACK_COUNT;i++)
|
|
{
|
|
pRecRenderData->mDuration[i] = 0;
|
|
pRecRenderData->mPrevDuration[i] = 0;
|
|
pRecRenderData->mPrefetchFlag[i] = FALSE;
|
|
//pSinkInfo->need_to_force_i_frm[i] = 0;
|
|
pRecRenderData->forced_i_frm[i] = 0;
|
|
pRecRenderData->key_frm_sent[i] = 0;
|
|
pRecRenderData->v_frm_drp_cnt[i] = 0;
|
|
}
|
|
pRecRenderData->mPrefetchFlagAudio = FALSE;
|
|
pRecRenderData->mDurationAudio = 0;
|
|
pRecRenderData->mDurationText = 0;
|
|
pRecRenderData->mPrevDurationAudio = 0;
|
|
pRecRenderData->mPrevDurationText = 0;
|
|
pRecRenderData->mFileSizeBytes = 0;
|
|
pRecRenderData->bTimeMeetAudio = FALSE;
|
|
pRecRenderData->mVideoFrmCntWriteMore = 0;
|
|
pRecRenderData->mVideoPtsWriteMoreSt = -1;
|
|
pRecRenderData->mVideoPtsWriteMoreEnd = -1;
|
|
for(i=0;i<MAX_TRACK_COUNT;i++)
|
|
{
|
|
pRecRenderData->mbTrackInit[i] = FALSE;
|
|
pRecRenderData->mPrevPts[i] = -1;
|
|
pRecRenderData->mBasePts[i] = -1;
|
|
pRecRenderData->mInputPrevPts[i] = -1;
|
|
}
|
|
pRecRenderData->mBasePtsRefStreamIndex = -1;
|
|
pRecRenderData->mVideoFrameCounter = 0;
|
|
pRecRenderData->mAudioFrmCnt = 0;
|
|
|
|
RecSinkMovePrefetchRSPackets(pRecRenderData);
|
|
|
|
//change fd.
|
|
if(pRecRenderData->nSwitchFd >= 0)
|
|
{
|
|
pRecRenderData->nOutputFd = pRecRenderData->nSwitchFd;
|
|
pRecRenderData->nSwitchFd = -1;
|
|
pRecRenderData->nFallocateLen = pRecRenderData->nSwitchFdFallocateSize;
|
|
pRecRenderData->nSwitchFdFallocateSize = 0;
|
|
pRecRenderData->reset_fd_flag = FALSE;
|
|
}
|
|
else
|
|
{
|
|
alogd("Be careful. muxChn[%d-%d] nSwitchFd<0, reset_fd_flag[%d] should be 0",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->reset_fd_flag);
|
|
}
|
|
|
|
//set rec_file
|
|
if(pRecRenderData->rec_file == FILE_NEED_SWITCH_TO_NORMAL)
|
|
{
|
|
int64_t oldTm = pRecRenderData->mCurFileEndTm;
|
|
pRecRenderData->mCurFileEndTm = pRecRenderData->mLoopDuration;
|
|
alogd("muxChn[%d-%d] switch file normal done. change CurFileEndTm[%lld->%lld]ms",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, oldTm, pRecRenderData->mCurFileEndTm);
|
|
pRecRenderData->rec_file = FILE_NORMAL;
|
|
}
|
|
else
|
|
{
|
|
if(pRecRenderData->rec_file != FILE_NORMAL)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] wrong rec_file[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->rec_file);
|
|
}
|
|
}
|
|
}
|
|
|
|
static BOOL RecSinkIfNeedRequestNextFd(RECRENDERDATATYPE *pRecRenderData)
|
|
{
|
|
if(pRecRenderData->need_set_next_fd == FALSE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
BOOL bNeedRequest = FALSE;
|
|
if(pRecRenderData->mCurMaxFileDuration > 0) //user set max duration, then segment file base on duration
|
|
{
|
|
//if(pRecSink->mLoopDuration + NOTIFY_NEEDNEXTFD_IN_ADVANCE >= pRecSink->mCurFileEndTm)
|
|
//{
|
|
// bNeedRequest = TRUE;
|
|
//}
|
|
if(pRecRenderData->mFileDurationPolicy == RecordFileDurationPolicy_MinDuration
|
|
|| pRecRenderData->mFileDurationPolicy == RecordFileDurationPolicy_AccurateDuration)
|
|
{
|
|
if((pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex] + NOTIFY_NEEDNEXTFD_IN_ADVANCE) >= pRecRenderData->mCurMaxFileDuration)
|
|
{
|
|
bNeedRequest = TRUE;
|
|
}
|
|
}
|
|
else if(pRecRenderData->mFileDurationPolicy == RecordFileDurationPolicy_AverageDuration)
|
|
{
|
|
if((pRecRenderData->mLoopDuration + NOTIFY_NEEDNEXTFD_IN_ADVANCE) >= pRecRenderData->mCurFileEndTm)
|
|
{
|
|
bNeedRequest = TRUE;
|
|
}
|
|
if((pRecRenderData->mLoopDurationAudio + NOTIFY_NEEDNEXTFD_IN_ADVANCE) >= pRecRenderData->mCurFileEndTm)
|
|
{
|
|
bNeedRequest = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! unknown FileDurationPolicy[0x%x], check code!", pRecRenderData->mFileDurationPolicy);
|
|
}
|
|
}
|
|
else if(pRecRenderData->mMaxFileSizeBytes > 0) //user set max file size, then segment file base on fileSize.
|
|
{
|
|
if(pRecRenderData->mFileSizeBytes + pRecRenderData->mMaxFileSizeBytes/10 >= pRecRenderData->mMaxFileSizeBytes)
|
|
{
|
|
double fileSizeMB = (double)pRecRenderData->mFileSizeBytes/(1024*1024);
|
|
alogd("fileSize[%lld]Bytes([%7.3lf]MB) < max[%7.3lf]MB, rec_file[%d], need request next fd",
|
|
pRecRenderData->mFileSizeBytes, fileSizeMB, (double)pRecRenderData->mMaxFileSizeBytes/(1024*1024), pRecRenderData->rec_file);
|
|
bNeedRequest = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bNeedRequest = FALSE;
|
|
}
|
|
return bNeedRequest;
|
|
}
|
|
|
|
/**
|
|
get one input buffer from mVideoInputFrameReadyList, mAudioInputFrameReadyList, or mTextInputFrameReadyList, to
|
|
mValidRSPacketList.
|
|
|
|
@return
|
|
SUCCESS:
|
|
ERR_MUX_NOMEM: no data.
|
|
*/
|
|
static ERRORTYPE RecRender_GetOneBuffer(RECRENDERDATATYPE *pRecRenderData)
|
|
{
|
|
ERRORTYPE ret = SUCCESS;
|
|
ERRORTYPE eRet;
|
|
RecSinkPacket RSPacket;
|
|
memset(&RSPacket, 0, sizeof(RSPacket));
|
|
enum CodecType eSelectType = SelectStreamToGet(pRecRenderData);
|
|
if(CODEC_TYPE_VIDEO == eSelectType)
|
|
{
|
|
eRet = RecRender_GetVideoBuffer(pRecRenderData, &RSPacket);
|
|
if(SUCCESS == eRet)
|
|
{
|
|
RecSinkPutRSPacket(pRecRenderData, &RSPacket);
|
|
pRecRenderData->duration = RSPacket.mPts - pRecRenderData->mnBasePts;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! why get video buffer fail[0x%x]?", eRet);
|
|
ret = ERR_MUX_NOMEM;
|
|
}
|
|
}
|
|
else if(CODEC_TYPE_AUDIO == eSelectType)
|
|
{
|
|
eRet = RecRender_GetAudioBuffer(pRecRenderData, &RSPacket);
|
|
if(SUCCESS == eRet)
|
|
{
|
|
RecSinkPutRSPacket(pRecRenderData, &RSPacket);
|
|
pRecRenderData->duration_audio = RSPacket.mPts - pRecRenderData->mnAudioBasePts;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! why get audio buffer fail[0x%x]?", eRet);
|
|
ret = ERR_MUX_NOMEM;
|
|
}
|
|
}
|
|
else if(CODEC_TYPE_TEXT == eSelectType)
|
|
{
|
|
eRet = RecRender_GetTextBuffer(pRecRenderData, &RSPacket);
|
|
if(SUCCESS == eRet)
|
|
{
|
|
RecSinkPutRSPacket(pRecRenderData, &RSPacket);
|
|
pRecRenderData->duration_text = RSPacket.mPts - pRecRenderData->mnTextBasePts;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! why get text buffer fail[0x%x]?", eRet);
|
|
ret = ERR_MUX_NOMEM;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = ERR_MUX_NOMEM;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
get all input buffers from mVideoInputFrameReadyList, mAudioInputFrameReadyList, or mTextInputFrameReadyList, to
|
|
mValidRSPacketList.
|
|
|
|
@return
|
|
number of input buffers.
|
|
*/
|
|
static int RecRender_GetAllBuffers(RECRENDERDATATYPE *pRecRenderData)
|
|
{
|
|
int nNum = 0;
|
|
ERRORTYPE eRet;
|
|
while(1)
|
|
{
|
|
eRet = RecRender_GetOneBuffer(pRecRenderData);
|
|
if(SUCCESS == eRet)
|
|
{
|
|
nNum++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return nNum;
|
|
}
|
|
|
|
static void* RecRender_ComponentThread(void* pThreadData)
|
|
{
|
|
//int ret = SUCCESS;
|
|
//int track_index = -1;
|
|
//int track_process_num = 0;
|
|
int buffer_fail_flags = 0;
|
|
unsigned int cmddata;
|
|
CompInternalMsgType cmd;
|
|
RECRENDERDATATYPE *pRecRenderData = (RECRENDERDATATYPE*) pThreadData;
|
|
message_t cmd_msg;
|
|
//COMP_BUFFERHEADERTYPE omx_buffer_header;
|
|
//COMP_BUFFERHEADERTYPE * pAudioHeader;
|
|
//VencOutputBuffer data_ctrl;
|
|
//MM_COMPONENTTYPE *pTunnelComp;
|
|
//COMP_INTERNAL_TUNNELINFOTYPE *pTunnelInfo;
|
|
//COMP_BUFFERHEADERTYPE *p_omx_buffer;
|
|
//AVPacket packet;
|
|
//int64_t origin_pts/*, prev_pts[MAX_TRACK_COUNT],base_pts[MAX_TRACK_COUNT]*/; //prev_pts[],base_pts[] are deprecated.
|
|
RecSinkPacket RSPacket;
|
|
RecSinkPacket *pRSPacket = NULL;
|
|
ERRORTYPE eRet;
|
|
alogv("Recorder Render ComponentThread start run...");
|
|
sprintf(pRecRenderData->mThreadName, "muxChn%d", pRecRenderData->mMppChnInfo.mChnId);
|
|
prctl(PR_SET_NAME, (unsigned long)pRecRenderData->mThreadName, 0, 0, 0);
|
|
|
|
while (1)
|
|
{
|
|
PROCESS_MESSAGE:
|
|
if(get_message(&pRecRenderData->cmd_queue, &cmd_msg) == 0)
|
|
{
|
|
cmd = cmd_msg.command;
|
|
cmddata = (unsigned int)cmd_msg.para0;
|
|
|
|
alogv("RecRender ComponentThread get_message cmd:%d", cmd);
|
|
|
|
// State transition command
|
|
if (cmd == SetState)
|
|
{
|
|
pthread_mutex_lock(&pRecRenderData->mStateMutex);
|
|
// If the parameter states a transition to the same state
|
|
// raise a same state transition error.
|
|
if (pRecRenderData->state == (COMP_STATETYPE) (cmddata))
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventError,
|
|
ERR_MUX_SAMESTATE,
|
|
0,
|
|
NULL);
|
|
else
|
|
{
|
|
// transitions/callbacks made based on state transition table
|
|
// cmddata contains the target state
|
|
switch ((COMP_STATETYPE) (cmddata))
|
|
{
|
|
case COMP_StateInvalid:
|
|
{
|
|
pRecRenderData->state = COMP_StateInvalid;
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventError,
|
|
ERR_MUX_INVALIDSTATE,
|
|
0,
|
|
NULL);
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventCmdComplete,
|
|
COMP_CommandStateSet,
|
|
pRecRenderData->state,
|
|
NULL);
|
|
break;
|
|
}
|
|
case COMP_StateLoaded:
|
|
{
|
|
if (pRecRenderData->state != COMP_StateIdle)
|
|
{
|
|
aloge("fatal error! curState[0x%x] is wrong", pRecRenderData->state);
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventError,
|
|
ERR_MUX_INCORRECT_STATE_TRANSITION,
|
|
0,
|
|
NULL);
|
|
}
|
|
alogv("RecRender set state LOADED");
|
|
//release all frames.
|
|
//alogd("release all frames to VEnc, AEnc and TEnc, when state[0x%x]->loaded", pRecRenderData->state);
|
|
RecRenderReleaseAllFrames(pRecRenderData);
|
|
|
|
pRecRenderData->state = COMP_StateLoaded;
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventCmdComplete,
|
|
COMP_CommandStateSet,
|
|
pRecRenderData->state,
|
|
NULL);
|
|
alogv("RecRender set state LOADED ok");
|
|
break;
|
|
}
|
|
case COMP_StateIdle:
|
|
{
|
|
if (COMP_StateExecuting==pRecRenderData->state || COMP_StatePause==pRecRenderData->state)
|
|
{
|
|
alogv("recRender state[%d] to idle", pRecRenderData->state);
|
|
RecSinkMovePrefetchRSPackets(pRecRenderData);
|
|
int nNum = RecRender_GetAllBuffers(pRecRenderData);
|
|
RecSinkDrainAllRSPackets(pRecRenderData);
|
|
if(pRecRenderData->mbMuxerInit)
|
|
{
|
|
int64_t tm1, tm2;
|
|
tm1 = CDX_GetSysTimeUsMonotonic();
|
|
RecSinkMuxerClose(pRecRenderData, 0);
|
|
tm2 = CDX_GetSysTimeUsMonotonic();
|
|
alogd("muxChn[%d-%d] recRender_MuxerClose itl[%lld]ms", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, (tm2-tm1)/1000);
|
|
}
|
|
for(int i=0; i<MAX_VIDEO_TRACK_COUNT; i++)
|
|
{
|
|
pRecRenderData->mPrefetchFlag[i] = FALSE;
|
|
}
|
|
pRecRenderData->mPrefetchFlagAudio = FALSE;
|
|
if(pRecRenderData->nOutputFd >= 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] maybe not muxerInit? nOutputFd[%d]>=0", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->nOutputFd);
|
|
close(pRecRenderData->nOutputFd);
|
|
pRecRenderData->nOutputFd = -1;
|
|
}
|
|
pthread_mutex_lock(&pRecRenderData->mutex_reset_writer_lock);
|
|
if(pRecRenderData->nSwitchFd >= 0)
|
|
{
|
|
close(pRecRenderData->nSwitchFd);
|
|
pRecRenderData->nSwitchFd = -1;
|
|
pRecRenderData->reset_fd_flag = FALSE;
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
|
|
//release all frames.
|
|
alogd("muxChn[%d-%d] release all frames to VEnc, AEnc and TEnc, when state[0x%x]->idle", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->state);
|
|
RecRenderReleaseAllFrames(pRecRenderData);
|
|
|
|
pRecRenderData->mnBasePts = -1;
|
|
pRecRenderData->mnAudioBasePts = -1;
|
|
pRecRenderData->mnTextBasePts = -1;
|
|
pRecRenderData->duration = 0;
|
|
pRecRenderData->duration_audio = 0;
|
|
pRecRenderData->duration_text = 0;
|
|
pRecRenderData->mLoopDuration = 0;
|
|
pRecRenderData->mLoopDurationAudio = 0;
|
|
for(int j=0;j<MAX_TRACK_COUNT;j++)
|
|
{
|
|
pRecRenderData->mOrigBasePts[j] = -1;
|
|
pRecRenderData->mDebugInputPts[j] = -1;
|
|
}
|
|
pRecRenderData->mCurFileEndTm = 0;
|
|
|
|
pRecRenderData->state = COMP_StateIdle;
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventCmdComplete,
|
|
COMP_CommandStateSet,
|
|
pRecRenderData->state,
|
|
NULL);
|
|
}
|
|
else if(COMP_StateLoaded == pRecRenderData->state)
|
|
{
|
|
pRecRenderData->state = COMP_StateIdle;
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventCmdComplete,
|
|
COMP_CommandStateSet,
|
|
pRecRenderData->state,
|
|
NULL);
|
|
}
|
|
else if (COMP_StateInvalid == pRecRenderData->state)
|
|
{
|
|
aloge("fatal error! InvalidState[%d]->[%d]", pRecRenderData->state, COMP_StateIdle);
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventError,
|
|
ERR_MUX_INCORRECT_STATE_OPERATION,
|
|
0,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! recRender state[%d] to idle", pRecRenderData->state);
|
|
pRecRenderData->state = COMP_StateIdle;
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventCmdComplete,
|
|
COMP_CommandStateSet,
|
|
pRecRenderData->state,
|
|
NULL);
|
|
}
|
|
break;
|
|
}
|
|
case COMP_StateExecuting:
|
|
{
|
|
// Transition can only happen from pause or idle state
|
|
if (pRecRenderData->state == COMP_StateIdle || pRecRenderData->state == COMP_StatePause)
|
|
{
|
|
// Return buffers if currently in pause
|
|
if(pRecRenderData->state == COMP_StateIdle)
|
|
{
|
|
for (int index = 0; index < MAX_REC_RENDER_PORTS; index++)
|
|
{
|
|
if(pRecRenderData->mInputPortTunnelFlag[index] && (pRecRenderData->sInPortTunnelInfo[index].hTunnel == NULL))
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] port[%d]domain[0x%x] is tunnel mode, but comp is null",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, index, pRecRenderData->sInPortDef[index].eDomain);
|
|
pRecRenderData->state = COMP_StateInvalid;
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventError,
|
|
ERR_MUX_INVALIDSTATE,
|
|
0,
|
|
NULL);
|
|
//goto EXIT;
|
|
}
|
|
}
|
|
}
|
|
else if (pRecRenderData->state == COMP_StatePause)
|
|
{
|
|
}
|
|
pRecRenderData->state = COMP_StateExecuting;
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventCmdComplete,
|
|
COMP_CommandStateSet,
|
|
pRecRenderData->state,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] InvalidState[%d]->Executing", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->state);
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventError,
|
|
ERR_MUX_INCORRECT_STATE_TRANSITION,
|
|
0,
|
|
NULL);
|
|
}
|
|
break;
|
|
}
|
|
case COMP_StatePause:
|
|
{
|
|
// Transition can only happen from executing state
|
|
if (pRecRenderData->state == COMP_StateExecuting)
|
|
{
|
|
pRecRenderData->state = COMP_StatePause;
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventCmdComplete,
|
|
COMP_CommandStateSet,
|
|
pRecRenderData->state,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] InvalidState[%d]->pause", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->state);
|
|
pRecRenderData->pCallbacks->EventHandler(
|
|
pRecRenderData->hSelf,
|
|
pRecRenderData->pAppData,
|
|
COMP_EventError,
|
|
ERR_MUX_INCORRECT_STATE_TRANSITION,
|
|
0,
|
|
NULL);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
aloge("fatal error! InvalidState[%d]->[%d]", pRecRenderData->state, (COMP_STATETYPE) (cmddata));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mStateMutex);
|
|
}
|
|
else if (cmd == StopPort)
|
|
{
|
|
}
|
|
else if (cmd == Stop)
|
|
{
|
|
// Kill thread
|
|
goto EXIT;
|
|
}
|
|
else if (SwitchFileNormal == cmd)
|
|
{
|
|
SwitchFileNormalInfo *pInfo = (SwitchFileNormalInfo*)cmd_msg.mpData;
|
|
ERRORTYPE eError = SUCCESS;
|
|
alogd("muxChn[%d-%d] Switch file normal", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
if(pRecRenderData->rec_file != FILE_NORMAL)
|
|
{
|
|
aloge("fatal error! Switch file normal, but rec_file_state=%d", pRecRenderData->rec_file);
|
|
goto PROCESS_MESSAGE;
|
|
}
|
|
//------------------set switchFd.---------------
|
|
pthread_mutex_lock(&pRecRenderData->mutex_reset_writer_lock);
|
|
int nFd = pInfo->mFd;
|
|
int nFallocateLen = pInfo->mnFallocateLen;
|
|
if(nFd < 0)
|
|
{
|
|
aloge("Be careful! fd[%d] < 0, app maybe want to bypass frames in this muxChn[%d-%d] next file",
|
|
nFd, pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
//return ERR_MUX_ILLEGAL_PARAM;
|
|
}
|
|
else
|
|
{
|
|
if(pRecRenderData->nSwitchFd >= 0)
|
|
{
|
|
alogd("muxChn[%d-%d] nSwitchFd[%d] already exist, directly close it! maybe switch file happen during new fd is setting.",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->nSwitchFd);
|
|
close(pRecRenderData->nSwitchFd);
|
|
pRecRenderData->nSwitchFd = -1;
|
|
pRecRenderData->nSwitchFdFallocateSize = 0;
|
|
}
|
|
// if(pThiz->mSwitchFilePath)
|
|
// {
|
|
// alogd("switchFilePath[%s] already exist, maybe impact happen during new fd is setting.", pThiz->mSwitchFilePath);
|
|
// free(pThiz->mSwitchFilePath);
|
|
// pThiz->mSwitchFilePath = NULL;
|
|
// pThiz->nSwitchFdFallocateSize = 0;
|
|
// }
|
|
pRecRenderData->nSwitchFd = dup(nFd);
|
|
if(pRecRenderData->nSwitchFd < 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] dup fail:[%d]->[%d],(%s)", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, nFd, pRecRenderData->nSwitchFd, strerror(errno));
|
|
system("lsof");
|
|
}
|
|
//pThiz->nSwitchFd = dup2SeldomUsedFd(nFd);
|
|
pRecRenderData->nSwitchFdFallocateSize = nFallocateLen;
|
|
//pThiz->mSwitchFdImpactFlag = nIsImpact;
|
|
alogd("muxChn[%d-%d] dup setfd[%d] to nSwitchFd[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, nFd, pRecRenderData->nSwitchFd);
|
|
if(TRUE == pRecRenderData->reset_fd_flag)
|
|
{
|
|
alogd("muxChn[%d-%d] reset__fd_flag is already true, maybe switch file happen during new fd is setting", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
pRecRenderData->reset_fd_flag = TRUE;
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
ERRORTYPE switchRet = ERR_MUX_NOT_SUPPORT;
|
|
if(FALSE == pRecRenderData->mbMuxerInit)
|
|
{
|
|
alogd("muxerId[%d-%d] switch file normal begin, but not muxerInit, so close nOutputFd[%d]",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->nOutputFd);
|
|
pRecRenderData->rec_file = FILE_NEED_SWITCH_TO_NORMAL;
|
|
if(pRecRenderData->nOutputFd>=0)
|
|
{
|
|
close(pRecRenderData->nOutputFd);
|
|
pRecRenderData->nOutputFd = -1;
|
|
pRecRenderData->pCallbacks->EventHandler(pRecRenderData->hSelf, pRecRenderData->pAppData, COMP_EventRecordDone, pRecRenderData->mChnAttr.mMuxerId, 0, NULL);
|
|
}
|
|
pthread_mutex_lock(&pRecRenderData->mutex_reset_writer_lock);
|
|
if(pRecRenderData->reset_fd_flag)
|
|
{
|
|
if(pRecRenderData->nSwitchFd < 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] reset__fd_flag is true but switchFd[%d]<0, check code!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->nSwitchFd);
|
|
pRecRenderData->reset_fd_flag = FALSE;
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
}
|
|
else
|
|
{
|
|
alogd("muxChn[%d-%d] switch file normal begin", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
pRecRenderData->rec_file = FILE_NEED_SWITCH_TO_NORMAL;
|
|
}
|
|
switchRet = SUCCESS;
|
|
cmd_msg.pReply->ReplyResult = (int)switchRet;
|
|
cdx_sem_up(&cmd_msg.pReply->ReplySem);
|
|
free(cmd_msg.mpData);
|
|
cmd_msg.mpData = NULL;
|
|
}
|
|
else if(RecSink_SwitchFd == cmd)
|
|
{
|
|
ERRORTYPE eSwitchFdRet = SUCCESS;
|
|
pthread_mutex_lock(&pRecRenderData->mutex_reset_writer_lock);
|
|
/*if (nIsImpact == 1 && (pThiz->rec_file == FILE_IMPACT_RECDRDING || pThiz->rec_file == FILE_NEED_SWITCH_TO_IMPACT))
|
|
{
|
|
alogd("impact file is recording, don't accept new impact Fd[%d].", nFd);
|
|
pthread_mutex_unlock(&pThiz->mutex_reset_writer_lock);
|
|
return SUCCESS;
|
|
}*/
|
|
if(FILE_NEED_SWITCH_TO_NORMAL == pRecRenderData->rec_file)
|
|
{
|
|
alogw("Be careful! muxChn[%d-%d] is in switch_to_normal, refuse to switch fd",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
eSwitchFdRet = ERR_MUX_NOT_PERM;
|
|
goto _switchFdExit;
|
|
}
|
|
int nFd = cmddata;
|
|
int nFallocateLen = cmd_msg.para1;
|
|
if(nFd < 0)
|
|
{
|
|
aloge("Be careful! fd[%d] < 0, app maybe want to bypass frames in this muxChn[%d-%d] next file",
|
|
nFd, pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
//return ERR_MUX_ILLEGAL_PARAM;
|
|
goto _switchFdExit;
|
|
}
|
|
if(pRecRenderData->nSwitchFd >= 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] nSwitchFd[%d] already exist, check code!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRecRenderData->nSwitchFd);
|
|
close(pRecRenderData->nSwitchFd);
|
|
pRecRenderData->nSwitchFd = -1;
|
|
pRecRenderData->nSwitchFdFallocateSize = 0;
|
|
}
|
|
if(nFd >= 0)
|
|
{
|
|
pRecRenderData->nSwitchFd = dup(nFd);
|
|
if(pRecRenderData->nSwitchFd < 0)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] dup fail:[%d]->[%d],(%s)",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
nFd, pRecRenderData->nSwitchFd, strerror(errno));
|
|
system("lsof");
|
|
}
|
|
//pThiz->nSwitchFd = dup2SeldomUsedFd(nFd);
|
|
}
|
|
pRecRenderData->nSwitchFdFallocateSize = nFallocateLen;
|
|
alogd("muxChn[%d-%d] dup setfd[%d] to nSwitchFd[%d]",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
nFd, pRecRenderData->nSwitchFd);
|
|
if(TRUE == pRecRenderData->reset_fd_flag)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] reset__fd_flag is already true, check code!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
pRecRenderData->reset_fd_flag = TRUE;
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
_switchFdExit:
|
|
if(cmd_msg.pReply)
|
|
{
|
|
cmd_msg.pReply->ReplyResult = (int)eSwitchFdRet;
|
|
cdx_sem_up(&cmd_msg.pReply->ReplySem);
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! must need pReply to reply!");
|
|
}
|
|
}
|
|
else if (RecRenderComp_InputFrameAvailable == cmd)
|
|
{
|
|
alogv("inputFrameAvailable");
|
|
//pRecRenderData->mNoInputFrameFlag = 0;
|
|
}
|
|
EndProcessMessage:
|
|
//precede to process message
|
|
goto PROCESS_MESSAGE;
|
|
}
|
|
|
|
if (pRecRenderData->state == COMP_StateExecuting)
|
|
{
|
|
eRet = RecRender_GetOneBuffer(pRecRenderData);
|
|
if(eRet != SUCCESS)
|
|
{
|
|
if(list_empty(&pRecRenderData->mValidRSPacketList))
|
|
{
|
|
int nMsgNum = TMessage_WaitQueueNotEmpty(&pRecRenderData->cmd_queue, 5*1000);
|
|
if(nMsgNum <= 0)
|
|
{
|
|
alogd("Be careful! muxChn[%d-%d] wait InputFrame timeout, msgNum:%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, nMsgNum);
|
|
}
|
|
goto PROCESS_MESSAGE;
|
|
}
|
|
}
|
|
|
|
pthread_mutex_lock(&pRecRenderData->mutex_reset_writer_lock);
|
|
pRSPacket = RecSinkGetRSPacket(pRecRenderData);
|
|
/* if(pRecSink->need_to_force_i_frm == 1)
|
|
{
|
|
aloge("frc_i_frm_p_ck:%d-%d-%d",pRecSink->mMuxerGrpId,pRSPacket->mStreamType,pRSPacket->mFlags);
|
|
} */
|
|
int need_switch_audio = 0; // audio duration meet the maxduration
|
|
BOOL need_switch_video = FALSE;
|
|
need_switch_video = RecSinkIfNeedSwitchFile(pRecRenderData, &need_switch_audio);
|
|
|
|
if(TRUE == need_switch_video) // video time duration reach file duration. meet setting.case1: key frm,with audio;case2:key frm,without audio;case3:not key frm
|
|
{
|
|
if(pRSPacket->mStreamType == CODEC_TYPE_VIDEO)
|
|
{
|
|
if(pRSPacket->mStreamId >= MAX_VIDEO_TRACK_COUNT)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] wrong streamId[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRSPacket->mStreamId);
|
|
}
|
|
if(!(pRSPacket->mFlags&AVPACKET_FLAG_KEYFRAME))
|
|
{ //(1)current packet is not key frame, so notify venc to force I frame, one time is enough.
|
|
if(FALSE == pRecRenderData->mPrefetchFlag[pRSPacket->mStreamId])
|
|
{
|
|
//pRecRenderData->need_to_force_i_frm[pRSPacket->mStreamId] = 1;
|
|
if(0 == pRecRenderData->forced_i_frm[pRSPacket->mStreamId])
|
|
{
|
|
if(pRecRenderData->mRefVideoStreamIndex == pRSPacket->mStreamId)
|
|
{
|
|
int nAudioStreamId = pRecRenderData->media_inf.mVideoInfoValidNum;
|
|
alogd("muxChn[%d-%d] rec_sink_to_force_i_frm_v:[%d]-%d-%d-%d-%lld-%lld-%lld--%lld-%lld-%lld-%lld-%d-%d-%d-%d-%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRSPacket->mStreamId,
|
|
pRecRenderData->media_inf.mMediaVideoInfo[pRSPacket->mStreamId].nWidth,
|
|
pRecRenderData->mDuration[pRSPacket->mStreamId],
|
|
pRecRenderData->mDurationAudio,
|
|
pRecRenderData->mLoopDuration,
|
|
pRecRenderData->mLoopDurationAudio,
|
|
pRecRenderData->mCurFileEndTm,
|
|
pRecRenderData->mBasePts[pRSPacket->mStreamId],
|
|
pRecRenderData->mBasePts[nAudioStreamId],
|
|
pRecRenderData->mOrigBasePts[pRSPacket->mStreamId],
|
|
pRSPacket->mPts, pRSPacket->mStreamType, pRSPacket->mFlags,
|
|
pRecRenderData->mVideoFrameCounter, pRecRenderData->mAudioFrmCnt,
|
|
pRecRenderData->video_frm_cnt, pRecRenderData->audio_frm_cnt);
|
|
}
|
|
else
|
|
{
|
|
alogd("muxChn[%d-%d] rec_sink_to_force_i_frm_v:[%d]-%d-%d--%lld-%lld-%lld-%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRSPacket->mStreamId,
|
|
pRecRenderData->media_inf.mMediaVideoInfo[pRSPacket->mStreamId].nWidth,
|
|
pRecRenderData->mDuration[pRSPacket->mStreamId],
|
|
pRecRenderData->mBasePts[pRSPacket->mStreamId],
|
|
pRecRenderData->mOrigBasePts[pRSPacket->mStreamId],
|
|
pRSPacket->mPts, pRSPacket->mStreamType, pRSPacket->mFlags);
|
|
}
|
|
//if file duration policy is accurate, no need to force I frame, because we will switch
|
|
//file immediately.
|
|
if(pRecRenderData->mFileDurationPolicy != RecordFileDurationPolicy_AccurateDuration)
|
|
{
|
|
RecSinkToForceIFrame(pRecRenderData, pRSPacket->mStreamId);
|
|
}
|
|
pRecRenderData->forced_i_frm[pRSPacket->mStreamId] = 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ //(2)if meet KeyFrame, begin to prefetch.
|
|
if(!pRecRenderData->mPrefetchFlag[pRSPacket->mStreamId])
|
|
{
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_AUDIO)
|
|
{
|
|
int videoStreamIndex = pRSPacket->mStreamId;
|
|
int audioStreamIndex = pRecRenderData->media_inf.mVideoInfoValidNum;
|
|
int64_t nVideoTotalTmUs = pRecRenderData->mPrevPts[videoStreamIndex]+pRecRenderData->mBasePts[videoStreamIndex];
|
|
int64_t nAudioTotalTmUs = pRecRenderData->mPrevPts[audioStreamIndex]+pRecRenderData->mBasePts[audioStreamIndex];
|
|
alogd("muxChn[%d-%d] avsync_ch_v:[%d]-%d-%lld-%lld-%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRSPacket->mStreamId,
|
|
pRecRenderData->media_inf.mMediaVideoInfo[videoStreamIndex].nWidth,
|
|
nAudioTotalTmUs,
|
|
nVideoTotalTmUs,
|
|
pRSPacket->mStreamType, pRSPacket->mFlags);
|
|
}
|
|
pRecRenderData->mPrefetchFlag[pRSPacket->mStreamId] = TRUE; // to cache video pkt in order to push more audio packets to current file
|
|
}
|
|
}
|
|
}
|
|
BOOL bGrant = RecSinkGrantSwitchFile(pRecRenderData, pRSPacket);
|
|
if(bGrant)
|
|
{
|
|
if(pRecRenderData->nOutputFd >= 0)
|
|
{
|
|
int nAudioStreamId = pRecRenderData->media_inf.mVideoInfoValidNum;
|
|
alogd("muxChn[%d-%d] avsync_rc_swfv:[%d]-%d-%d-%d-%lld-%lld--%lld-%lld-%lld-%d-%d-%d-%d-%lld-%d-%d",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mRefVideoStreamIndex,
|
|
pRecRenderData->media_inf.mMediaVideoInfo[pRecRenderData->mRefVideoStreamIndex].nWidth,
|
|
pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex], pRecRenderData->mDurationAudio,
|
|
pRecRenderData->mLoopDuration, pRecRenderData->mCurFileEndTm,
|
|
pRecRenderData->mBasePts[pRecRenderData->mRefVideoStreamIndex],
|
|
pRecRenderData->mBasePts[nAudioStreamId],
|
|
pRecRenderData->mOrigBasePts[pRecRenderData->mRefVideoStreamIndex],
|
|
pRecRenderData->mVideoFrameCounter, pRecRenderData->mAudioFrmCnt,
|
|
pRecRenderData->video_frm_cnt, pRecRenderData->audio_frm_cnt,
|
|
pRSPacket->mPts, pRSPacket->mStreamType, pRSPacket->mStreamId);
|
|
RecSinkAddRSPacketToPrefetchList(pRecRenderData, pRSPacket);
|
|
pRSPacket = NULL;
|
|
RecSinkSwitchFile(pRecRenderData, 0);
|
|
pRSPacket = RecSinkGetRSPacket(pRecRenderData);
|
|
if(pRSPacket != NULL)
|
|
{
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_VIDEO)
|
|
{
|
|
if(pRSPacket->mStreamType==CODEC_TYPE_VIDEO)
|
|
{
|
|
if(!(pRSPacket->mFlags&AVPACKET_FLAG_KEYFRAME))
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] next file streamId[%d] first frame is not key video frame!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRSPacket->mStreamId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] has no packet!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(FALSE == pRecRenderData->nCallbackOutFlag)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] has not fd, but callback mode is false, so don't switch file!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(need_switch_audio) //audio duration reach file duration first.
|
|
{
|
|
if(pRSPacket->mStreamType==CODEC_TYPE_AUDIO)
|
|
{
|
|
if(!pRecRenderData->mPrefetchFlagAudio)
|
|
{
|
|
if(!(pRecRenderData->mRecordMode & RECORDER_MODE_AUDIO))
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] recorder no audio?", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
int audioStreamIndex = pRecRenderData->media_inf.mVideoInfoValidNum;
|
|
int64_t nVideoTotalTmUs = pRecRenderData->mPrevPts[pRecRenderData->mRefVideoStreamIndex]+pRecRenderData->mBasePts[pRecRenderData->mRefVideoStreamIndex];
|
|
int64_t nAudioTotalTmUs = pRecRenderData->mPrevPts[audioStreamIndex]+pRecRenderData->mBasePts[audioStreamIndex];
|
|
alogd("muxChn[%d-%d] avsync_ch_a:[%d]-%d-%lld-%lld-%d-%d", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mRefVideoStreamIndex, pRecRenderData->media_inf.mMediaVideoInfo[pRecRenderData->mRefVideoStreamIndex].nWidth,
|
|
nAudioTotalTmUs, nVideoTotalTmUs, pRSPacket->mStreamType, pRSPacket->mFlags);
|
|
pRecRenderData->mPrefetchFlagAudio = TRUE; // to cache audio pkt in order to push more video packet to current file
|
|
}
|
|
}
|
|
BOOL bGrant = RecSinkGrantSwitchFileAudio(pRecRenderData, pRSPacket);
|
|
if(TRUE == bGrant) // grant to switch file
|
|
{
|
|
if(pRecRenderData->nOutputFd >= 0)
|
|
{
|
|
int nAudioStreamId = pRecRenderData->media_inf.mVideoInfoValidNum;
|
|
alogd("muxChn[%d-%d] avsync_rc_swfa:[%d]-%d-%d-%d-%lld-%lld-%lld--%lld-%lld-%lld-%d-%d-%d-%d-%d-%d-%lld",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mRefVideoStreamIndex, pRecRenderData->media_inf.mMediaVideoInfo[pRecRenderData->mRefVideoStreamIndex].nWidth,
|
|
pRecRenderData->mDuration[pRecRenderData->mRefVideoStreamIndex], pRecRenderData->mDurationAudio,
|
|
pRecRenderData->mLoopDuration, pRecRenderData->mLoopDurationAudio, pRecRenderData->mCurFileEndTm,
|
|
pRecRenderData->mBasePts[pRecRenderData->mRefVideoStreamIndex],
|
|
pRecRenderData->mBasePts[nAudioStreamId],
|
|
pRecRenderData->mOrigBasePts[pRecRenderData->mRefVideoStreamIndex],
|
|
pRecRenderData->mVideoFrameCounter, pRecRenderData->mAudioFrmCnt,
|
|
pRecRenderData->video_frm_cnt, pRecRenderData->audio_frm_cnt,
|
|
pRSPacket->mStreamType, pRSPacket->mFlags, pRSPacket->mPts);
|
|
RecSinkAddRSPacketToPrefetchList(pRecRenderData, pRSPacket);
|
|
pRSPacket = NULL;
|
|
RecSinkSwitchFile(pRecRenderData, 0);
|
|
pRSPacket = RecSinkGetRSPacket(pRecRenderData);
|
|
if(NULL == pRSPacket)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] has no packet!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(FALSE == pRecRenderData->nCallbackOutFlag)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] has not fd, but callback mode is false, so don't switch file!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
}
|
|
}
|
|
}
|
|
else // not grant to switch file now
|
|
{
|
|
if(TRUE == pRecRenderData->bTimeMeetAudio) //time meet,but not all videos meet key frame
|
|
{
|
|
if(pRSPacket->mStreamType==CODEC_TYPE_VIDEO)
|
|
{
|
|
if(pRSPacket->mStreamId >= MAX_VIDEO_TRACK_COUNT)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] wrong streamId[%d]", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRSPacket->mStreamId);
|
|
}
|
|
//(1)if video need force I frame?
|
|
if(!(pRSPacket->mFlags&AVPACKET_FLAG_KEYFRAME))
|
|
{
|
|
if(FALSE == pRecRenderData->mPrefetchFlag[pRSPacket->mStreamId])
|
|
{
|
|
//pRecRenderData->need_to_force_i_frm[pRSPacket->mStreamId] = 1;
|
|
if(0 == pRecRenderData->forced_i_frm[pRSPacket->mStreamId])
|
|
{
|
|
int nAudioStreamId = pRecRenderData->media_inf.mVideoInfoValidNum;
|
|
alogd("muxChn[%d-%d] rec_sink_to_force_i_frm_a:[%d]-%d-%d-%d-%lld-%lld-%lld--%lld-%lld-%lld-%d-%d-%d-%d-%d-%d-%lld",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRSPacket->mStreamId,
|
|
pRecRenderData->media_inf.mMediaVideoInfo[pRSPacket->mStreamId].nWidth,
|
|
pRecRenderData->mDuration[pRSPacket->mStreamId], pRecRenderData->mDurationAudio,
|
|
pRecRenderData->mLoopDuration, pRecRenderData->mLoopDurationAudio, pRecRenderData->mCurFileEndTm,
|
|
pRecRenderData->mBasePts[pRSPacket->mStreamId], pRecRenderData->mBasePts[nAudioStreamId],
|
|
pRecRenderData->mOrigBasePts[pRSPacket->mStreamId],
|
|
pRecRenderData->mVideoFrameCounter, pRecRenderData->mAudioFrmCnt,
|
|
pRecRenderData->video_frm_cnt, pRecRenderData->audio_frm_cnt,
|
|
pRSPacket->mStreamType, pRSPacket->mFlags, pRSPacket->mPts);
|
|
RecSinkToForceIFrame(pRecRenderData, pRSPacket->mStreamId);
|
|
pRecRenderData->forced_i_frm[pRSPacket->mStreamId] = 1;
|
|
}
|
|
}
|
|
}
|
|
//(2)if meet KeyFrame, begin to prefetch.
|
|
else
|
|
{
|
|
if(!pRecRenderData->mPrefetchFlag[pRSPacket->mStreamId])
|
|
{
|
|
pRecRenderData->mPrefetchFlag[pRSPacket->mStreamId] = TRUE; // can cache video pkt
|
|
}
|
|
}
|
|
|
|
//if video0 need continue to write, then calculate video0's write packet number and pts.
|
|
if((pRecRenderData->mRefVideoStreamIndex == pRSPacket->mStreamId) && (FALSE == pRecRenderData->mPrefetchFlag[pRecRenderData->mRefVideoStreamIndex]))
|
|
{
|
|
pRecRenderData->mVideoFrmCntWriteMore++;
|
|
alogd("muxChn[%d-%d] avsync_cal:[%d]-%d-%lld-%lld-%d", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mRefVideoStreamIndex, pRecRenderData->media_inf.mMediaVideoInfo[pRecRenderData->mRefVideoStreamIndex].nWidth,
|
|
pRSPacket->mPts, pRecRenderData->mVideoPtsWriteMoreSt, pRecRenderData->mVideoFrmCntWriteMore);
|
|
if(-1 == pRecRenderData->mVideoPtsWriteMoreSt) // to record the pts of video frame write more
|
|
{
|
|
pRecRenderData->mVideoPtsWriteMoreSt = pRSPacket->mPts;
|
|
pRecRenderData->mVideoPtsWriteMoreEnd = pRSPacket->mPts;
|
|
}
|
|
else
|
|
{
|
|
pRecRenderData->mVideoPtsWriteMoreEnd = pRSPacket->mPts;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(pRecRenderData->mbMuxerInit == FALSE && (pRecRenderData->nCallbackOutFlag==TRUE || pRecRenderData->nOutputFd>=0 || pRecRenderData->reset_fd_flag==TRUE))
|
|
{
|
|
BOOL bGrant = TRUE;
|
|
if(pRecRenderData->mRecordMode & RECORDER_MODE_VIDEO)
|
|
{
|
|
if(pRSPacket->mStreamType==CODEC_TYPE_VIDEO)
|
|
{
|
|
if(pRSPacket->mFlags&AVPACKET_FLAG_KEYFRAME)
|
|
{
|
|
bGrant = TRUE;
|
|
}
|
|
else
|
|
{
|
|
alogd("Be careful! muxChn[%d-%d] video stream[%d] first packet[%d-0x%x] is not key frame! But still grant!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRSPacket->mStreamId, pRSPacket->mStreamType, pRSPacket->mFlags);
|
|
bGrant = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alogd("Be careful! muxChn[%d-%d] stream[%d] first packet[%d-0x%x] is not video stream! But still grant!",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRSPacket->mStreamId, pRSPacket->mStreamType, pRSPacket->mFlags);
|
|
bGrant = TRUE;
|
|
}
|
|
}
|
|
//first packet will be video or not.
|
|
//first video frame may not be key frame, if not key frame, we will not write it to file, we will only
|
|
//record its pts as basePts of this file, then release it.
|
|
// alogd("muxerId[%d]: first packet grant[%d]: stream_type[%d], flags[0x%x], pts[%lld]ms, videoSize[%dx%d]",
|
|
// pRecSink->mMuxerId, bGrant, pRSPacket->mStreamType, pRSPacket->mFlags, pRSPacket->mPts, pRecSink->mpMediaInf->nWidth, pRecSink->mpMediaInf->nHeight);
|
|
if(bGrant)
|
|
{
|
|
if(RecSinkMuxerInit(pRecRenderData, pRSPacket) != SUCCESS)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] ValidMuxerInit Error!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId);
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
RecSinkReleaseRSPacket(pRecRenderData, pRSPacket);
|
|
goto PROCESS_MESSAGE;
|
|
}
|
|
pRecRenderData->mVideoPtsWriteMoreSt = -1;
|
|
if(pRecRenderData->nCallbackOutFlag == FALSE)
|
|
{
|
|
pRecRenderData->need_set_next_fd = TRUE;
|
|
}
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&pRecRenderData->mutex_reset_writer_lock);
|
|
BOOL bReleasePacket = TRUE;
|
|
if(pRecRenderData->mbMuxerInit)
|
|
{
|
|
if(CODEC_TYPE_VIDEO == pRSPacket->mStreamType)
|
|
{
|
|
if(pRSPacket->mStreamId >= MAX_VIDEO_TRACK_COUNT)
|
|
{
|
|
aloge("fatal error! muxChn[%d-%d] streamId[%d] wrong!", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId, pRSPacket->mStreamId);
|
|
}
|
|
if(pRecRenderData->mPrefetchFlag[pRSPacket->mStreamId])
|
|
{
|
|
RecSinkAddRSPacketToPrefetchList(pRecRenderData, pRSPacket);
|
|
bReleasePacket = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if(!pRecRenderData->key_frm_sent[pRSPacket->mStreamId])
|
|
{
|
|
if(pRSPacket->mFlags&AVPACKET_FLAG_KEYFRAME)
|
|
{
|
|
pRecRenderData->key_frm_sent[pRSPacket->mStreamId] = 1;
|
|
RecSinkWriteRSPacket(pRecRenderData, pRSPacket);
|
|
}
|
|
else
|
|
{
|
|
pRecRenderData->v_frm_drp_cnt[pRSPacket->mStreamId]++;
|
|
alogd("muxChn[%d-%d] stream[%d] rc_snk_drp_v_frm:%d", pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRSPacket->mStreamId, pRecRenderData->v_frm_drp_cnt[pRSPacket->mStreamId]);
|
|
//even we drop the front video frames, but first video frame's pts must be set as basePts of
|
|
//current stream, to guarantee av sync.
|
|
RecSinkUpdateStreamBasePts(pRecRenderData, pRSPacket);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RecSinkWriteRSPacket(pRecRenderData, pRSPacket);
|
|
}
|
|
}
|
|
}
|
|
else if(CODEC_TYPE_AUDIO == pRSPacket->mStreamType)
|
|
{
|
|
if(pRecRenderData->mPrefetchFlagAudio)
|
|
{
|
|
RecSinkAddRSPacketToPrefetchList(pRecRenderData, pRSPacket);
|
|
bReleasePacket = FALSE;
|
|
}
|
|
else
|
|
{
|
|
RecSinkWriteRSPacket(pRecRenderData, pRSPacket);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RecSinkWriteRSPacket(pRecRenderData, pRSPacket);
|
|
}
|
|
}
|
|
//release RSPacket
|
|
if(bReleasePacket)
|
|
{
|
|
RecSinkReleaseRSPacket(pRecRenderData, pRSPacket);
|
|
}
|
|
RELEASE:
|
|
if(RecSinkIfNeedRequestNextFd(pRecRenderData))
|
|
{
|
|
alogd("muxChn[%d-%d] Need set next fd: Policy[%d] refvStrm[%d] videosize[%dx%d], vLoopDur[%lld]ms, aLoopDur[%lld]ms, curFileEndTm[%lld]ms",
|
|
pRecRenderData->mMppChnInfo.mChnId, pRecRenderData->mChnAttr.mMuxerId,
|
|
pRecRenderData->mFileDurationPolicy, pRecRenderData->mRefVideoStreamIndex,
|
|
pRecRenderData->media_inf.mMediaVideoInfo[pRecRenderData->mRefVideoStreamIndex].nWidth,
|
|
pRecRenderData->media_inf.mMediaVideoInfo[pRecRenderData->mRefVideoStreamIndex].nHeight,
|
|
pRecRenderData->mLoopDuration, pRecRenderData->mLoopDurationAudio, pRecRenderData->mCurFileEndTm);
|
|
pRecRenderData->need_set_next_fd = FALSE;
|
|
pRecRenderData->pCallbacks->EventHandler(pRecRenderData->hSelf, pRecRenderData->pAppData,
|
|
COMP_EventNeedNextFd, pRecRenderData->mChnAttr.mMuxerId, 0, NULL);
|
|
}
|
|
//no need ReleaseBuffer because we don't RecRender_RefBuffer().
|
|
//RecRender_ReleaseBuffer(pRecRenderData, &RSPacket);
|
|
}
|
|
else
|
|
{
|
|
//cdx_sem_down(&pRecRenderData->cdx_sem_wait_message);
|
|
TMessage_WaitQueueNotEmpty(&pRecRenderData->cmd_queue, 0);
|
|
}
|
|
}
|
|
EXIT:
|
|
alogv("Recorder Render ComponentThread stopped");
|
|
return (void*) SUCCESS;
|
|
}
|
|
|