1947 lines
77 KiB
C
Executable File
1947 lines
77 KiB
C
Executable File
/******************************************************************************
|
|
Copyright (C), 2001-2016, Allwinner Tech. Co., Ltd.
|
|
******************************************************************************
|
|
File Name :
|
|
Version : Initial Draft
|
|
Author : Allwinner BU3-PD2 Team
|
|
Created : 2016/11/4
|
|
Last Modified :
|
|
Description :
|
|
Function List :
|
|
History :
|
|
******************************************************************************/
|
|
|
|
#define LOG_NDEBUG 0
|
|
#define LOG_TAG "SampleVirVi2Venc2Muxer"
|
|
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <time.h>
|
|
#include "plat_log.h"
|
|
#include <mm_common.h>
|
|
#include <mpi_videoformat_conversion.h>
|
|
#include <mpi_region.h>
|
|
#include "sample_vi2venc2muxer.h"
|
|
#include "sample_vi2venc2muxer_conf.h"
|
|
|
|
#define DEFAULT_SIMPLE_CACHE_SIZE_VFS (64*1024)
|
|
//#define DOUBLE_ENCODER_FILE_OUT
|
|
#define ISP_RUN (1)
|
|
|
|
static SAMPLE_VI2VENC2MUXER_S *gpVi2Venc2MuxerData;
|
|
|
|
static void handle_exit(int signo)
|
|
{
|
|
alogd("user want to exit!");
|
|
if(NULL != gpVi2Venc2MuxerData)
|
|
{
|
|
cdx_sem_up(&gpVi2Venc2MuxerData->mSemExit);
|
|
}
|
|
}
|
|
|
|
static int setOutputFileSync(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData, char* path, int64_t fallocateLength, int muxerId);
|
|
|
|
|
|
static ERRORTYPE InitVi2Venc2MuxerData(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData)
|
|
{
|
|
if (pVi2Venc2MuxerData == NULL)
|
|
{
|
|
aloge("malloc struct fail");
|
|
return FAILURE;
|
|
}
|
|
memset(pVi2Venc2MuxerData, 0, sizeof(SAMPLE_VI2VENC2MUXER_S));
|
|
pVi2Venc2MuxerData->mMuxGrp = MM_INVALID_CHN;
|
|
pVi2Venc2MuxerData->mVeChn = MM_INVALID_CHN;
|
|
pVi2Venc2MuxerData->mViChn = MM_INVALID_CHN;
|
|
pVi2Venc2MuxerData->mViDev = MM_INVALID_DEV;
|
|
|
|
int i=0;
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
INIT_LIST_HEAD(&pVi2Venc2MuxerData->mMuxerFileListArray[i]);
|
|
}
|
|
alogd("&pVi2Venc2MuxerData->mMuxerFileListArray[0][%p], &pVi2Venc2MuxerData->mMuxerFileListArray[1][%p]",
|
|
&pVi2Venc2MuxerData->mMuxerFileListArray[0], &pVi2Venc2MuxerData->mMuxerFileListArray[1]);
|
|
|
|
pVi2Venc2MuxerData->mCurrentState = REC_NOT_PREPARED;
|
|
|
|
if (message_create(&pVi2Venc2MuxerData->mMsgQueue) < 0)
|
|
{
|
|
aloge("message create fail!");
|
|
return FAILURE;
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
static ERRORTYPE parseCmdLine(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData, int argc, char** argv)
|
|
{
|
|
ERRORTYPE ret = FAILURE;
|
|
|
|
if(argc <= 1)
|
|
{
|
|
alogd("use default config.");
|
|
return SUCCESS;
|
|
}
|
|
while (*argv)
|
|
{
|
|
if (!strcmp(*argv, "-path"))
|
|
{
|
|
argv++;
|
|
if (*argv)
|
|
{
|
|
ret = SUCCESS;
|
|
if (strlen(*argv) >= MAX_FILE_PATH_LEN)
|
|
{
|
|
aloge("fatal error! file path[%s] too long:!", *argv);
|
|
}
|
|
|
|
strncpy(pVi2Venc2MuxerData->mCmdLinePara.mConfigFilePath, *argv, MAX_FILE_PATH_LEN-1);
|
|
pVi2Venc2MuxerData->mCmdLinePara.mConfigFilePath[MAX_FILE_PATH_LEN-1] = '\0';
|
|
}
|
|
}
|
|
else if(!strcmp(*argv, "-h"))
|
|
{
|
|
printf("CmdLine param:\n"
|
|
"\t-path /home/sample_vi2venc2muxer.conf\n");
|
|
break;
|
|
}
|
|
else if (*argv)
|
|
{
|
|
argv++;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ERRORTYPE loadConfigPara(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData, const char *conf_path)
|
|
{
|
|
int ret;
|
|
char *ptr;
|
|
pVi2Venc2MuxerData->mConfigPara.mDstFileMaxCnt = 3;
|
|
pVi2Venc2MuxerData->mConfigPara.srcWidth = 1920;
|
|
pVi2Venc2MuxerData->mConfigPara.srcHeight = 1080;
|
|
pVi2Venc2MuxerData->mConfigPara.dstWidth = 1920;
|
|
pVi2Venc2MuxerData->mConfigPara.dstHeight = 1080;
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mViBufferNum = 4;
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mMaxFileDuration = 0;
|
|
pVi2Venc2MuxerData->mConfigPara.mTestDuration = 30; // unit:s
|
|
pVi2Venc2MuxerData->mConfigPara.mVideoFrameRate = 20; // unit:fps
|
|
pVi2Venc2MuxerData->mConfigPara.mVideoBitRate = 15728640; // 1.5M
|
|
pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YUV_AW_LBC_2_0X;
|
|
pVi2Venc2MuxerData->mConfigPara.mColorSpace = V4L2_COLORSPACE_REC709_PART_RANGE;
|
|
pVi2Venc2MuxerData->mConfigPara.mVideoEncoderFmt = PT_H264;
|
|
pVi2Venc2MuxerData->mConfigPara.mField = VIDEO_FIELD_FRAME;
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mHorizonFlipFlag = FALSE;
|
|
pVi2Venc2MuxerData->mConfigPara.mColor2Grey = FALSE;
|
|
pVi2Venc2MuxerData->mConfigPara.m3DNR = 0;
|
|
strcpy(pVi2Venc2MuxerData->mConfigPara.dstVideoFile, "/mnt/extsd/1080p.mp4");
|
|
pVi2Venc2MuxerData->mConfigPara.mProductMode = (int)VENC_PRODUCT_IPC_MODE;
|
|
pVi2Venc2MuxerData->mConfigPara.mSensorType = (int)VENC_ST_EN_WDR;
|
|
pVi2Venc2MuxerData->mConfigPara.mKeyFrameInterval = 0;
|
|
pVi2Venc2MuxerData->mConfigPara.mRcMode = 0;
|
|
pVi2Venc2MuxerData->mConfigPara.mQp0 = 10;
|
|
pVi2Venc2MuxerData->mConfigPara.mQp1 = 40;
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mViDropFrameNum = 0;
|
|
pVi2Venc2MuxerData->mConfigPara.mVencDropFrameNum = 0;
|
|
pVi2Venc2MuxerData->mConfigPara.wdr_en = 0;
|
|
pVi2Venc2MuxerData->mConfigPara.mEnMbQpLimit = 0;
|
|
pVi2Venc2MuxerData->mConfigPara.mEnableGdc = 0;
|
|
|
|
if(conf_path != NULL)
|
|
{
|
|
CONFPARSER_S mConf;
|
|
|
|
ret = createConfParser(conf_path, &mConf);
|
|
if (ret < 0)
|
|
{
|
|
aloge("load conf fail");
|
|
return FAILURE;
|
|
}
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mVippDev = GetConfParaInt(&mConf, CFG_VIPP_DEV_ID, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mVeChn = GetConfParaInt(&mConf, CFG_VENC_CH_ID, 0);
|
|
alogd("vippDev: %d, veChn: %d", pVi2Venc2MuxerData->mConfigPara.mVippDev, pVi2Venc2MuxerData->mConfigPara.mVeChn);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.srcWidth = GetConfParaInt(&mConf, CFG_SRC_WIDTH, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.srcHeight = GetConfParaInt(&mConf, CFG_SRC_HEIGHT, 0);
|
|
alogd("srcWidth: %d, srcHeight: %d", pVi2Venc2MuxerData->mConfigPara.srcWidth, pVi2Venc2MuxerData->mConfigPara.srcHeight);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.dstWidth = GetConfParaInt(&mConf, CFG_DST_VIDEO_WIDTH, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.dstHeight = GetConfParaInt(&mConf, CFG_DST_VIDEO_HEIGHT, 0);
|
|
alogd("dstWidth: %d, dstHeight: %d", pVi2Venc2MuxerData->mConfigPara.dstWidth, pVi2Venc2MuxerData->mConfigPara.dstHeight);
|
|
|
|
ptr = (char *)GetConfParaString(&mConf, CFG_SRC_PIXFMT, NULL);
|
|
if (ptr != NULL)
|
|
{
|
|
if (!strcmp(ptr, "nv21"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
|
|
}
|
|
else if (!strcmp(ptr, "yv12"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YVU_PLANAR_420;
|
|
}
|
|
else if (!strcmp(ptr, "nv12"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420;
|
|
}
|
|
else if (!strcmp(ptr, "yu12"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YUV_PLANAR_420;
|
|
}
|
|
/* aw compression format */
|
|
else if (!strcmp(ptr, "aw_afbc"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YUV_AW_AFBC;
|
|
}
|
|
else if (!strcmp(ptr, "aw_lbc_2_0x"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YUV_AW_LBC_2_0X;
|
|
}
|
|
else if (!strcmp(ptr, "aw_lbc_2_5x"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YUV_AW_LBC_2_5X;
|
|
}
|
|
else if (!strcmp(ptr, "aw_lbc_1_5x"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YUV_AW_LBC_1_5X;
|
|
}
|
|
else if (!strcmp(ptr, "aw_lbc_1_0x"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YUV_AW_LBC_1_0X;
|
|
}
|
|
/* aw_package_422 NOT support */
|
|
// else if (!strcmp(ptr, "aw_package_422"))
|
|
// {
|
|
// pVi2Venc2MuxerData->mConfigPara.srcPixFmt = MM_PIXEL_FORMAT_YVYU_AW_PACKAGE_422;
|
|
// }
|
|
else
|
|
{
|
|
aloge("fatal error! wrong src pixfmt:%s", ptr);
|
|
alogw("use the default pixfmt %d", pVi2Venc2MuxerData->mConfigPara.srcPixFmt);
|
|
}
|
|
}
|
|
|
|
ptr = (char *)GetConfParaString(&mConf, CFG_COLOR_SPACE, NULL);
|
|
if (!strcmp(ptr, "jpeg"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.mColorSpace = V4L2_COLORSPACE_JPEG;
|
|
}
|
|
else if (!strcmp(ptr, "rec709"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.mColorSpace = V4L2_COLORSPACE_REC709;
|
|
}
|
|
else if (!strcmp(ptr, "rec709_part_range"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.mColorSpace = V4L2_COLORSPACE_REC709_PART_RANGE;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! wrong color space:%s", ptr);
|
|
pVi2Venc2MuxerData->mConfigPara.mColorSpace = V4L2_COLORSPACE_JPEG;
|
|
}
|
|
|
|
alogd("srcPixFmt=%d, ColorSpace=%d", pVi2Venc2MuxerData->mConfigPara.srcPixFmt, pVi2Venc2MuxerData->mConfigPara.mColorSpace);
|
|
|
|
ptr = (char *)GetConfParaString(&mConf, CFG_DST_VIDEO_FILE_STR, NULL);
|
|
strcpy(pVi2Venc2MuxerData->mConfigPara.dstVideoFile, ptr);
|
|
pVi2Venc2MuxerData->mConfigPara.mbAddRepairInfo = GetConfParaInt(&mConf, CFG_ADD_REPAIR_INFO, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mMaxFrmsTagInterval = GetConfParaInt(&mConf, CFG_FRMSTAG_BACKUP_INTERVAL, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mDstFileMaxCnt = GetConfParaInt(&mConf, CFG_DST_FILE_MAX_CNT, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mVideoFrameRate = GetConfParaInt(&mConf, CFG_DST_VIDEO_FRAMERATE, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mViBufferNum = GetConfParaInt(&mConf, CFG_DST_VI_BUFFER_NUM, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mVideoBitRate = GetConfParaInt(&mConf, CFG_DST_VIDEO_BITRATE, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mMaxFileDuration = GetConfParaInt(&mConf, CFG_DST_VIDEO_DURATION, 0);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mProductMode = GetConfParaInt(&mConf, CFG_PRODUCT_MODE, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mSensorType = GetConfParaInt(&mConf, CFG_SENSOR_TYPE, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mKeyFrameInterval = GetConfParaInt(&mConf, CFG_KEY_FRAME_INTERVAL, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mRcMode = GetConfParaInt(&mConf, CFG_RC_MODE, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mQp0 = GetConfParaInt(&mConf, CFG_RC_QP0, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mQp1 = GetConfParaInt(&mConf, CFG_RC_QP1, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mGopMode = GetConfParaInt(&mConf, CFG_GOP_MODE, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mGopSize = GetConfParaInt(&mConf, CFG_GOP_SIZE, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mAdvancedRef_Base = GetConfParaInt(&mConf, CFG_AdvancedRef_Base, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mAdvancedRef_Enhance = GetConfParaInt(&mConf, CFG_AdvancedRef_Enhance, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mAdvancedRef_RefBaseEn = GetConfParaInt(&mConf, CFG_AdvancedRef_RefBaseEn, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mEnableFastEnc = GetConfParaInt(&mConf, CFG_FAST_ENC, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mbEnableSmart = GetConfParaBoolean(&mConf, CFG_ENABLE_SMART, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mSVCLayer = GetConfParaInt(&mConf, CFG_SVC_LAYER, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mEncodeRotate = GetConfParaInt(&mConf, CFG_ENCODE_ROTATE, 0);
|
|
|
|
ptr = (char *)GetConfParaString(&mConf, CFG_DST_VIDEO_ENCODER, NULL);
|
|
if (!strcmp(ptr, "H.264"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.mVideoEncoderFmt = PT_H264;
|
|
alogd("H.264");
|
|
}
|
|
else if (!strcmp(ptr, "H.265"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.mVideoEncoderFmt = PT_H265;
|
|
alogd("H.265");
|
|
}
|
|
else if (!strcmp(ptr, "MJPEG"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.mVideoEncoderFmt = PT_MJPEG;
|
|
alogd("MJPEG");
|
|
}
|
|
else
|
|
{
|
|
aloge("error conf encoder type");
|
|
}
|
|
pVi2Venc2MuxerData->mConfigPara.mTestDuration = GetConfParaInt(&mConf, CFG_TEST_DURATION, 0);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mEncUseProfile = GetConfParaInt(&mConf, CFG_DST_ENCODE_PROFILE, 0);
|
|
|
|
alogd("vipp:%d, frame rate:%d, bitrate:%d, video_duration=%d, test_time=%d, profile=%d", pVi2Venc2MuxerData->mConfigPara.mVippDev,\
|
|
pVi2Venc2MuxerData->mConfigPara.mVideoFrameRate, pVi2Venc2MuxerData->mConfigPara.mVideoBitRate,\
|
|
pVi2Venc2MuxerData->mConfigPara.mMaxFileDuration, pVi2Venc2MuxerData->mConfigPara.mTestDuration,\
|
|
pVi2Venc2MuxerData->mConfigPara.mEncUseProfile);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mHorizonFlipFlag = GetConfParaInt(&mConf, CFG_MIRROR, 0);
|
|
|
|
ptr = (char *)GetConfParaString(&mConf, CFG_COLOR2GREY, NULL);
|
|
if(!strcmp(ptr, "yes"))
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.mColor2Grey = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pVi2Venc2MuxerData->mConfigPara.mColor2Grey = FALSE;
|
|
}
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.m3DNR = GetConfParaInt(&mConf, CFG_3DNR, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mRoiNum = GetConfParaInt(&mConf, CFG_ROI_NUM, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mRoiQp = GetConfParaInt(&mConf, CFG_ROI_QP, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mRoiBgFrameRateEnable = GetConfParaBoolean(&mConf, CFG_ROI_BgFrameRateEnable, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mRoiBgFrameRateAttenuation = GetConfParaInt(&mConf, CFG_ROI_BgFrameRateAttenuation, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mIntraRefreshBlockNum = GetConfParaInt(&mConf, CFG_IntraRefresh_BlockNum, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mOrlNum = GetConfParaInt(&mConf, CFG_ORL_NUM, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mVbvBufferSize = GetConfParaInt(&mConf, CFG_vbvBufferSize, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mVbvThreshSize = GetConfParaInt(&mConf, CFG_vbvThreshSize, 0);
|
|
|
|
alogd("mirror:%d, Color2Grey:%d, 3DNR:%d, RoiNum:%d, RoiQp:%d, RoiBgFrameRate Enable:%d Attenuation:%d, IntraRefreshBlockNum:%d, OrlNum:%d"
|
|
"VbvBufferSize:%d, VbvThreshSize:%d",
|
|
pVi2Venc2MuxerData->mConfigPara.mHorizonFlipFlag, pVi2Venc2MuxerData->mConfigPara.mColor2Grey,
|
|
pVi2Venc2MuxerData->mConfigPara.m3DNR, pVi2Venc2MuxerData->mConfigPara.mRoiNum, pVi2Venc2MuxerData->mConfigPara.mRoiQp,
|
|
pVi2Venc2MuxerData->mConfigPara.mRoiBgFrameRateEnable, pVi2Venc2MuxerData->mConfigPara.mRoiBgFrameRateAttenuation,
|
|
pVi2Venc2MuxerData->mConfigPara.mIntraRefreshBlockNum,
|
|
pVi2Venc2MuxerData->mConfigPara.mOrlNum, pVi2Venc2MuxerData->mConfigPara.mVbvBufferSize,
|
|
pVi2Venc2MuxerData->mConfigPara.mVbvThreshSize);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mCropEnable = GetConfParaInt(&mConf, CFG_CROP_ENABLE, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mCropRectX = GetConfParaInt(&mConf, CFG_CROP_RECT_X, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mCropRectY = GetConfParaInt(&mConf, CFG_CROP_RECT_Y, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mCropRectWidth = GetConfParaInt(&mConf, CFG_CROP_RECT_WIDTH, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mCropRectHeight = GetConfParaInt(&mConf, CFG_CROP_RECT_HEIGHT, 0);
|
|
|
|
alogd("venc crop enable:%d, X:%d, Y:%d, Width:%d, Height:%d",
|
|
pVi2Venc2MuxerData->mConfigPara.mCropEnable, pVi2Venc2MuxerData->mConfigPara.mCropRectX,
|
|
pVi2Venc2MuxerData->mConfigPara.mCropRectY, pVi2Venc2MuxerData->mConfigPara.mCropRectWidth,
|
|
pVi2Venc2MuxerData->mConfigPara.mCropRectHeight);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mVuiTimingInfoPresentFlag = GetConfParaInt(&mConf, CFG_vui_timing_info_present_flag, 0);
|
|
alogd("VuiTimingInfoPresentFlag:%d", pVi2Venc2MuxerData->mConfigPara.mVuiTimingInfoPresentFlag);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mVeFreq = GetConfParaInt(&mConf, CFG_Ve_Freq, 0);
|
|
alogd("mVeFreq:%d MHz", pVi2Venc2MuxerData->mConfigPara.mVeFreq);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mOnlineEnable = GetConfParaInt(&mConf, CFG_online_en, 0);
|
|
pVi2Venc2MuxerData->mConfigPara.mOnlineShareBufNum = GetConfParaInt(&mConf, CFG_online_share_buf_num, 0);
|
|
alogd("OnlineEnable: %d, OnlineShareBufNum: %d", pVi2Venc2MuxerData->mConfigPara.mOnlineEnable,
|
|
pVi2Venc2MuxerData->mConfigPara.mOnlineShareBufNum);
|
|
|
|
if (0 == pVi2Venc2MuxerData->mConfigPara.mOnlineEnable)
|
|
{
|
|
// venc drop frame only support offline.
|
|
pVi2Venc2MuxerData->mConfigPara.mViDropFrameNum = GetConfParaInt(&mConf, CFG_DROP_FRAME_NUM, 0);
|
|
alogd("ViDropFrameNum: %d", pVi2Venc2MuxerData->mConfigPara.mViDropFrameNum);
|
|
}
|
|
else
|
|
{
|
|
// venc drop frame support online and offline.
|
|
pVi2Venc2MuxerData->mConfigPara.mVencDropFrameNum = GetConfParaInt(&mConf, CFG_DROP_FRAME_NUM, 0);
|
|
alogd("VencDropFrameNum: %d", pVi2Venc2MuxerData->mConfigPara.mVencDropFrameNum);
|
|
}
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.wdr_en = GetConfParaInt(&mConf, CFG_WDR_EN, 0);
|
|
alogd("wdr_en: %d", pVi2Venc2MuxerData->mConfigPara.wdr_en);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mEnMbQpLimit = GetConfParaInt(&mConf, CFG_EnMbQpLimit, 0);
|
|
alogd("EnMbQpLimit: %d", pVi2Venc2MuxerData->mConfigPara.mEnMbQpLimit);
|
|
|
|
pVi2Venc2MuxerData->mConfigPara.mEnableGdc = GetConfParaInt(&mConf, CFG_EnableGdc, 0);
|
|
alogd("EnableGdc: %d", pVi2Venc2MuxerData->mConfigPara.mEnableGdc);
|
|
|
|
destroyConfParser(&mConf);
|
|
}
|
|
|
|
//parse dst directory form dst file path.
|
|
char *pLastSlash = strrchr(pVi2Venc2MuxerData->mConfigPara.dstVideoFile, '/');
|
|
if(pLastSlash != NULL)
|
|
{
|
|
int dirLen = pLastSlash-pVi2Venc2MuxerData->mConfigPara.dstVideoFile;
|
|
strncpy(pVi2Venc2MuxerData->mDstDir, pVi2Venc2MuxerData->mConfigPara.dstVideoFile, dirLen);
|
|
pVi2Venc2MuxerData->mDstDir[dirLen] = '\0';
|
|
|
|
char *pFileName = pLastSlash+1;
|
|
strcpy(pVi2Venc2MuxerData->mFirstFileName, pFileName);
|
|
}
|
|
else
|
|
{
|
|
strcpy(pVi2Venc2MuxerData->mDstDir, "");
|
|
strcpy(pVi2Venc2MuxerData->mFirstFileName, pVi2Venc2MuxerData->mConfigPara.dstVideoFile);
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
static unsigned long long GetNowTimeUs(void)
|
|
{
|
|
struct timeval now;
|
|
gettimeofday(&now, NULL);
|
|
return now.tv_sec * 1000000 + now.tv_usec;
|
|
}
|
|
|
|
static int getFileNameByCurTime(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData, char *pNameBuf)
|
|
{
|
|
#if 0
|
|
sprintf(pNameBuf, "%s", "/mnt/extsd/sample_mux/");
|
|
sprintf(pNameBuf, "%s%llud.mp4", pNameBuf, GetNowTimeUs());
|
|
#else
|
|
static int file_cnt = 0;
|
|
char strStemPath[MAX_FILE_PATH_LEN] = {0};
|
|
int len = strlen(pVi2Venc2MuxerData->mConfigPara.dstVideoFile);
|
|
char *ptr = pVi2Venc2MuxerData->mConfigPara.dstVideoFile;
|
|
while (*(ptr+len-1) != '.')
|
|
{
|
|
len--;
|
|
}
|
|
|
|
++file_cnt;
|
|
strncpy(strStemPath, pVi2Venc2MuxerData->mConfigPara.dstVideoFile, len-1);
|
|
sprintf(pNameBuf, "%s_%d.mp4", strStemPath, file_cnt);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static ERRORTYPE MPPCallbackWrapper(void *cookie, MPP_CHN_S *pChn, MPP_EVENT_TYPE event, void *pEventData)
|
|
{
|
|
SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData = (SAMPLE_VI2VENC2MUXER_S *)cookie;
|
|
|
|
if(MOD_ID_VENC == pChn->mModId)
|
|
{
|
|
switch(event)
|
|
{
|
|
case MPP_EVENT_RELEASE_VIDEO_BUFFER:
|
|
{
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if(MOD_ID_MUX == pChn->mModId)
|
|
{
|
|
switch(event)
|
|
{
|
|
case MPP_EVENT_RECORD_DONE:
|
|
{
|
|
message_t stCmdMsg;
|
|
Vi2Venc2Muxer_MessageData stMsgData;
|
|
|
|
alogd("MuxerId[%d] record file done.", *(int*)pEventData);
|
|
stMsgData.pVi2Venc2MuxerData = (SAMPLE_VI2VENC2MUXER_S*)cookie;
|
|
stCmdMsg.command = Rec_FileDone;
|
|
stCmdMsg.para0 = *(int*)pEventData;
|
|
stCmdMsg.mDataSize = sizeof(Vi2Venc2Muxer_MessageData);
|
|
stCmdMsg.mpData = &stMsgData;
|
|
|
|
putMessageWithData(&gpVi2Venc2MuxerData->mMsgQueue, &stCmdMsg);
|
|
/*
|
|
int ret;
|
|
int muxerId = *(int*)pEventData;
|
|
alogd("file done, mux_id=%d", muxerId);
|
|
int idx=-1;
|
|
if (muxerId == pVi2Venc2MuxerData->mMuxId[0])
|
|
{
|
|
idx = 0;
|
|
}
|
|
#ifdef DOUBLE_ENCODER_FILE_OUT
|
|
else if(muxerId == pVi2Venc2MuxerData->mMuxId[1])
|
|
{
|
|
idx = 1;
|
|
}
|
|
#endif
|
|
if (idx >= 0)
|
|
{
|
|
int cnt = 0;
|
|
struct list_head *pList = NULL;
|
|
list_for_each(pList, &pVi2Venc2MuxerData->mMuxerFileListArray[idx]){cnt++;}
|
|
FilePathNode *pNode = NULL;
|
|
while(cnt > pVi2Venc2MuxerData->mConfigPara.mDstFileMaxCnt)
|
|
{
|
|
pNode = list_first_entry(&pVi2Venc2MuxerData->mMuxerFileListArray[idx], FilePathNode, mList);
|
|
if ((ret = remove(pNode->strFilePath)) != 0)
|
|
{
|
|
aloge("fatal error! delete file[%s] failed:%s", pNode->strFilePath, strerror(errno));
|
|
}
|
|
else
|
|
{
|
|
alogd("delete file[%s] success", pNode->strFilePath);
|
|
}
|
|
cnt--;
|
|
list_del(&pNode->mList);
|
|
free(pNode);
|
|
}
|
|
}
|
|
*/
|
|
break;
|
|
}
|
|
case MPP_EVENT_NEED_NEXT_FD:
|
|
{
|
|
message_t stCmdMsg;
|
|
Vi2Venc2Muxer_MessageData stMsgData;
|
|
|
|
alogd("MuxerId[%d] need next fd.", *(int*)pEventData);
|
|
stMsgData.pVi2Venc2MuxerData = (SAMPLE_VI2VENC2MUXER_S*)cookie;
|
|
stCmdMsg.command = Rec_NeedSetNextFd;
|
|
stCmdMsg.para0 = *(int*)pEventData;
|
|
stCmdMsg.mDataSize = sizeof(Vi2Venc2Muxer_MessageData);
|
|
stCmdMsg.mpData = &stMsgData;
|
|
|
|
putMessageWithData(&gpVi2Venc2MuxerData->mMsgQueue, &stCmdMsg);
|
|
/*
|
|
int muxerId = *(int*)pEventData;
|
|
SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData = (SAMPLE_VI2VENC2MUXER_S *)cookie;
|
|
char fileName[MAX_FILE_PATH_LEN] = {0};
|
|
|
|
if (muxerId == pVi2Venc2MuxerData->mMuxId[0])
|
|
{
|
|
getFileNameByCurTime(pVi2Venc2MuxerData, fileName);
|
|
FilePathNode *pFilePathNode = (FilePathNode*)malloc(sizeof(FilePathNode));
|
|
memset(pFilePathNode, 0, sizeof(FilePathNode));
|
|
strncpy(pFilePathNode->strFilePath, fileName, MAX_FILE_PATH_LEN-1);
|
|
list_add_tail(&pFilePathNode->mList, &pVi2Venc2MuxerData->mMuxerFileListArray[0]);
|
|
}
|
|
#ifdef DOUBLE_ENCODER_FILE_OUT
|
|
else if(muxerId == pVi2Venc2MuxerData->mMuxId[1])
|
|
{
|
|
//strcpy(fileName, "/mnt/extsd/sample_vi2venc2muxer/");
|
|
static int cnt = 0;
|
|
cnt++;
|
|
sprintf(fileName, "/mnt/extsd/sample_vi2venc2muxer/%d.ts", cnt);
|
|
FilePathNode *pFilePathNode = (FilePathNode*)malloc(sizeof(FilePathNode));
|
|
memset(pFilePathNode, 0, sizeof(FilePathNode));
|
|
strncpy(pFilePathNode->strFilePath, fileName, MAX_FILE_PATH_LEN-1);
|
|
list_add_tail(&pFilePathNode->mList, &pVi2Venc2MuxerData->mMuxerFileListArray[1]);
|
|
}
|
|
#endif
|
|
alogd("muxId[%d] set next fd, filepath=%s", muxerId, fileName);
|
|
setOutputFileSync(pVi2Venc2MuxerData, fileName, 0, muxerId);
|
|
*/
|
|
break;
|
|
}
|
|
case MPP_EVENT_BSFRAME_AVAILABLE:
|
|
{
|
|
alogd("mux bs frame available");
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
static ERRORTYPE configMuxGrpAttr(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData)
|
|
{
|
|
memset(&pVi2Venc2MuxerData->mMuxGrpAttr, 0, sizeof(MUX_GRP_ATTR_S));
|
|
|
|
pVi2Venc2MuxerData->mMuxGrpAttr.mVideoAttrValidNum = 1;
|
|
pVi2Venc2MuxerData->mMuxGrpAttr.mVideoAttr[0].mVideoEncodeType = pVi2Venc2MuxerData->mConfigPara.mVideoEncoderFmt;
|
|
pVi2Venc2MuxerData->mMuxGrpAttr.mVideoAttr[0].mWidth = pVi2Venc2MuxerData->mConfigPara.dstWidth;
|
|
pVi2Venc2MuxerData->mMuxGrpAttr.mVideoAttr[0].mHeight = pVi2Venc2MuxerData->mConfigPara.dstHeight;
|
|
pVi2Venc2MuxerData->mMuxGrpAttr.mVideoAttr[0].mVideoFrmRate = pVi2Venc2MuxerData->mConfigPara.mVideoFrameRate*1000;
|
|
//pVi2Venc2MuxerData->mMuxGrpAttr.mMaxKeyInterval =
|
|
pVi2Venc2MuxerData->mMuxGrpAttr.mVideoAttr[0].mVeChn = pVi2Venc2MuxerData->mVeChn;
|
|
pVi2Venc2MuxerData->mMuxGrpAttr.mAudioEncodeType = PT_MAX;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
static ERRORTYPE createMuxGrp(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData)
|
|
{
|
|
ERRORTYPE ret;
|
|
BOOL nSuccessFlag = FALSE;
|
|
|
|
configMuxGrpAttr(pVi2Venc2MuxerData);
|
|
pVi2Venc2MuxerData->mMuxGrp = 0;
|
|
while (pVi2Venc2MuxerData->mMuxGrp < MUX_MAX_GRP_NUM)
|
|
{
|
|
ret = AW_MPI_MUX_CreateGrp(pVi2Venc2MuxerData->mMuxGrp, &pVi2Venc2MuxerData->mMuxGrpAttr);
|
|
if (SUCCESS == ret)
|
|
{
|
|
nSuccessFlag = TRUE;
|
|
alogd("create mux group[%d] success!", pVi2Venc2MuxerData->mMuxGrp);
|
|
break;
|
|
}
|
|
else if (ERR_MUX_EXIST == ret)
|
|
{
|
|
alogd("mux group[%d] is exist, find next!", pVi2Venc2MuxerData->mMuxGrp);
|
|
pVi2Venc2MuxerData->mMuxGrp++;
|
|
}
|
|
else
|
|
{
|
|
alogd("create mux group[%d] ret[0x%x], find next!", pVi2Venc2MuxerData->mMuxGrp, ret);
|
|
pVi2Venc2MuxerData->mMuxGrp++;
|
|
}
|
|
}
|
|
|
|
if (FALSE == nSuccessFlag)
|
|
{
|
|
pVi2Venc2MuxerData->mMuxGrp = MM_INVALID_CHN;
|
|
aloge("fatal error! create mux group fail!");
|
|
return FAILURE;
|
|
}
|
|
else
|
|
{
|
|
MPPCallbackInfo cbInfo;
|
|
cbInfo.cookie = (void*)pVi2Venc2MuxerData;
|
|
cbInfo.callback = (MPPCallbackFuncType)&MPPCallbackWrapper;
|
|
AW_MPI_MUX_RegisterCallback(pVi2Venc2MuxerData->mMuxGrp, &cbInfo);
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
|
|
static int addOutputFormatAndOutputSink_l(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData, OUTSINKINFO_S *pSinkInfo)
|
|
{
|
|
int retMuxerId = -1;
|
|
MUX_CHN_INFO_S *pEntry, *pTmp;
|
|
|
|
alogd("fmt:0x%x, fd:%d, FallocateLen:%d, callback_out_flag:%d", pSinkInfo->mOutputFormat, pSinkInfo->mOutputFd, pSinkInfo->mFallocateLen, pSinkInfo->mCallbackOutFlag);
|
|
if(pSinkInfo->mOutputFd >= 0 && TRUE == pSinkInfo->mCallbackOutFlag)
|
|
{
|
|
aloge("fatal error! one muxer cannot support two sink methods!");
|
|
return -1;
|
|
}
|
|
|
|
//find if the same output_format sinkInfo exist or callback out stream is exist.
|
|
pthread_mutex_lock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
if (!list_empty(&pVi2Venc2MuxerData->mMuxChnList))
|
|
{
|
|
list_for_each_entry_safe(pEntry, pTmp, &pVi2Venc2MuxerData->mMuxChnList, mList)
|
|
{
|
|
if (pEntry->mSinkInfo.mOutputFormat == pSinkInfo->mOutputFormat)
|
|
{
|
|
alogd("Be careful! same outputForamt[0x%x] exist in array", pSinkInfo->mOutputFormat);
|
|
}
|
|
// if (pEntry->mSinkInfo.mCallbackOutFlag == pSinkInfo->mCallbackOutFlag)
|
|
// {
|
|
// aloge("fatal error! only support one callback out stream");
|
|
// }
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
|
|
MUX_CHN_INFO_S *p_node = (MUX_CHN_INFO_S *)malloc(sizeof(MUX_CHN_INFO_S));
|
|
if (p_node == NULL)
|
|
{
|
|
aloge("alloc mux chn info node fail");
|
|
return -1;
|
|
}
|
|
|
|
memset(p_node, 0, sizeof(MUX_CHN_INFO_S));
|
|
p_node->mSinkInfo.mMuxerId = pVi2Venc2MuxerData->mMuxerIdCounter;
|
|
p_node->mSinkInfo.mOutputFormat = pSinkInfo->mOutputFormat;
|
|
if (pSinkInfo->mOutputFd > 0)
|
|
{
|
|
p_node->mSinkInfo.mOutputFd = dup(pSinkInfo->mOutputFd);
|
|
}
|
|
else
|
|
{
|
|
p_node->mSinkInfo.mOutputFd = -1;
|
|
}
|
|
p_node->mSinkInfo.mFallocateLen = pSinkInfo->mFallocateLen;
|
|
p_node->mSinkInfo.mCallbackOutFlag = pSinkInfo->mCallbackOutFlag;
|
|
|
|
p_node->mMuxChnAttr.mMuxerId = p_node->mSinkInfo.mMuxerId;
|
|
p_node->mMuxChnAttr.mMediaFileFormat = p_node->mSinkInfo.mOutputFormat;
|
|
p_node->mMuxChnAttr.mMaxFileDuration = pVi2Venc2MuxerData->mConfigPara.mMaxFileDuration *1000;
|
|
p_node->mMuxChnAttr.mFallocateLen = p_node->mSinkInfo.mFallocateLen;
|
|
p_node->mMuxChnAttr.mCallbackOutFlag = p_node->mSinkInfo.mCallbackOutFlag;
|
|
p_node->mMuxChnAttr.mFsWriteMode = FSWRITEMODE_SIMPLECACHE;
|
|
p_node->mMuxChnAttr.mSimpleCacheSize = DEFAULT_SIMPLE_CACHE_SIZE_VFS;
|
|
p_node->mMuxChnAttr.mAddRepairInfo = pVi2Venc2MuxerData->mConfigPara.mbAddRepairInfo;
|
|
p_node->mMuxChnAttr.mMaxFrmsTagInterval = pVi2Venc2MuxerData->mConfigPara.mMaxFrmsTagInterval;
|
|
|
|
p_node->mMuxChn = MM_INVALID_CHN;
|
|
|
|
if ((pVi2Venc2MuxerData->mCurrentState == REC_PREPARED) || (pVi2Venc2MuxerData->mCurrentState == REC_RECORDING))
|
|
{
|
|
ERRORTYPE ret;
|
|
BOOL nSuccessFlag = FALSE;
|
|
MUX_CHN nMuxChn = 0;
|
|
while (nMuxChn < MUX_MAX_CHN_NUM)
|
|
{
|
|
ret = AW_MPI_MUX_CreateChn(pVi2Venc2MuxerData->mMuxGrp, nMuxChn, &p_node->mMuxChnAttr, p_node->mSinkInfo.mOutputFd);
|
|
if (SUCCESS == ret)
|
|
{
|
|
nSuccessFlag = TRUE;
|
|
alogd("create mux group[%d] channel[%d] success, muxerId[%d]!", pVi2Venc2MuxerData->mMuxGrp, nMuxChn, p_node->mMuxChnAttr.mMuxerId);
|
|
break;
|
|
}
|
|
else if (ERR_MUX_EXIST == ret)
|
|
{
|
|
alogd("mux group[%d] channel[%d] is exist, find next!", pVi2Venc2MuxerData->mMuxGrp, nMuxChn);
|
|
nMuxChn++;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! create mux group[%d] channel[%d] fail ret[0x%x], find next!", pVi2Venc2MuxerData->mMuxGrp, nMuxChn, ret);
|
|
nMuxChn++;
|
|
}
|
|
}
|
|
|
|
if (nSuccessFlag)
|
|
{
|
|
retMuxerId = p_node->mSinkInfo.mMuxerId;
|
|
p_node->mMuxChn = nMuxChn;
|
|
pVi2Venc2MuxerData->mMuxerIdCounter++;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! create mux group[%d] channel fail!", pVi2Venc2MuxerData->mMuxGrp);
|
|
if (p_node->mSinkInfo.mOutputFd >= 0)
|
|
{
|
|
close(p_node->mSinkInfo.mOutputFd);
|
|
p_node->mSinkInfo.mOutputFd = -1;
|
|
}
|
|
|
|
retMuxerId = -1;
|
|
}
|
|
|
|
pthread_mutex_lock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
list_add_tail(&p_node->mList, &pVi2Venc2MuxerData->mMuxChnList);
|
|
pthread_mutex_unlock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
}
|
|
else
|
|
{
|
|
retMuxerId = p_node->mSinkInfo.mMuxerId;
|
|
pVi2Venc2MuxerData->mMuxerIdCounter++;
|
|
pthread_mutex_lock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
list_add_tail(&p_node->mList, &pVi2Venc2MuxerData->mMuxChnList);
|
|
pthread_mutex_unlock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
}
|
|
|
|
return retMuxerId;
|
|
}
|
|
|
|
static int addOutputFormatAndOutputSink(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData, char* path, MEDIA_FILE_FORMAT_E format)
|
|
{
|
|
int muxerId = -1;
|
|
OUTSINKINFO_S sinkInfo = {0};
|
|
|
|
if (path != NULL)
|
|
{
|
|
sinkInfo.mFallocateLen = 0;
|
|
sinkInfo.mCallbackOutFlag = FALSE;
|
|
sinkInfo.mOutputFormat = format;
|
|
sinkInfo.mOutputFd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
|
if (sinkInfo.mOutputFd < 0)
|
|
{
|
|
aloge("Failed to open %s", path);
|
|
return -1;
|
|
}
|
|
|
|
muxerId = addOutputFormatAndOutputSink_l(pVi2Venc2MuxerData, &sinkInfo);
|
|
close(sinkInfo.mOutputFd);
|
|
}
|
|
|
|
return muxerId;
|
|
}
|
|
|
|
static int setOutputFileSync_l(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData, int fd, int64_t fallocateLength, int muxerId)
|
|
{
|
|
MUX_CHN_INFO_S *pEntry, *pTmp;
|
|
|
|
if (pVi2Venc2MuxerData->mCurrentState != REC_RECORDING)
|
|
{
|
|
aloge("must be in recording state");
|
|
return -1;
|
|
}
|
|
|
|
alogv("setOutputFileSync fd=%d", fd);
|
|
if (fd < 0)
|
|
{
|
|
aloge("Invalid parameter");
|
|
return -1;
|
|
}
|
|
|
|
MUX_CHN muxChn = MM_INVALID_CHN;
|
|
pthread_mutex_lock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
if (!list_empty(&pVi2Venc2MuxerData->mMuxChnList))
|
|
{
|
|
list_for_each_entry_safe(pEntry, pTmp, &pVi2Venc2MuxerData->mMuxChnList, mList)
|
|
{
|
|
if (pEntry->mMuxChnAttr.mMuxerId == muxerId)
|
|
{
|
|
muxChn = pEntry->mMuxChn;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
|
|
if (muxChn != MM_INVALID_CHN)
|
|
{
|
|
alogd("switch fd");
|
|
AW_MPI_MUX_SwitchFd(pVi2Venc2MuxerData->mMuxGrp, muxChn, fd, fallocateLength);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! can't find muxChn which muxerId[%d]", muxerId);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static int setOutputFileSync(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData, char* path, int64_t fallocateLength, int muxerId)
|
|
{
|
|
int ret;
|
|
|
|
if (pVi2Venc2MuxerData->mCurrentState != REC_RECORDING)
|
|
{
|
|
aloge("not in recording state");
|
|
return -1;
|
|
}
|
|
|
|
if(path != NULL)
|
|
{
|
|
int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
|
if (fd < 0)
|
|
{
|
|
aloge("fail to open %s", path);
|
|
return -1;
|
|
}
|
|
ret = setOutputFileSync_l(pVi2Venc2MuxerData, fd, fallocateLength, muxerId);
|
|
close(fd);
|
|
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
static inline unsigned int map_H264_UserSet2Profile(int val)
|
|
{
|
|
unsigned int profile = (unsigned int)H264_PROFILE_HIGH;
|
|
switch (val)
|
|
{
|
|
case 0:
|
|
profile = (unsigned int)H264_PROFILE_BASE;
|
|
break;
|
|
|
|
case 1:
|
|
profile = (unsigned int)H264_PROFILE_MAIN;
|
|
break;
|
|
|
|
case 2:
|
|
profile = (unsigned int)H264_PROFILE_HIGH;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return profile;
|
|
}
|
|
|
|
static inline unsigned int map_H265_UserSet2Profile(int val)
|
|
{
|
|
unsigned int profile = H265_PROFILE_MAIN;
|
|
switch (val)
|
|
{
|
|
case 0:
|
|
profile = (unsigned int)H265_PROFILE_MAIN;
|
|
break;
|
|
|
|
case 1:
|
|
profile = (unsigned int)H265_PROFILE_MAIN10;
|
|
break;
|
|
|
|
case 2:
|
|
profile = (unsigned int)H265_PROFILE_STI11;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return profile;
|
|
}
|
|
|
|
static void initGdcParam(sGdcParam *pGdcParam)
|
|
{
|
|
pGdcParam->bGDC_en = 1;
|
|
pGdcParam->eWarpMode = Gdc_Warp_LDC;
|
|
pGdcParam->eMountMode = Gdc_Mount_Wall;
|
|
pGdcParam->bMirror = 0;
|
|
|
|
pGdcParam->fx = 2417.19;
|
|
pGdcParam->fy = 2408.43;
|
|
pGdcParam->cx = 1631.50;
|
|
pGdcParam->cy = 1223.50;
|
|
pGdcParam->fx_scale = 2161.82;
|
|
pGdcParam->fy_scale = 2153.99;
|
|
pGdcParam->cx_scale = 1631.50;
|
|
pGdcParam->cy_scale = 1223.50;
|
|
|
|
pGdcParam->eLensDistModel = Gdc_DistModel_FishEye;
|
|
|
|
pGdcParam->distCoef_wide_ra[0] = -0.3849;
|
|
pGdcParam->distCoef_wide_ra[1] = 0.1567;
|
|
pGdcParam->distCoef_wide_ra[2] = -0.0030;
|
|
pGdcParam->distCoef_wide_ta[0] = -0.00005;
|
|
pGdcParam->distCoef_wide_ta[1] = 0.0016;
|
|
|
|
pGdcParam->distCoef_fish_k[0] = -0.0024;
|
|
pGdcParam->distCoef_fish_k[1] = 0.141;
|
|
pGdcParam->distCoef_fish_k[2] = -0.3;
|
|
pGdcParam->distCoef_fish_k[3] = 0.2328;
|
|
|
|
pGdcParam->centerOffsetX = -255; //[-255,0]
|
|
pGdcParam->centerOffsetY = 0; //[-255,0]
|
|
pGdcParam->rotateAngle = 0; //[0,360]
|
|
pGdcParam->radialDistortCoef = 0; //[-255,255]
|
|
pGdcParam->trapezoidDistortCoef = 0; //[-255,255]
|
|
pGdcParam->fanDistortCoef = 0; //[-255,255]
|
|
pGdcParam->pan = 0; //pano360:[0,360]; others:[-90,90]
|
|
pGdcParam->tilt = 0; //[-90,90]
|
|
pGdcParam->zoomH = 100; //[0,100]
|
|
pGdcParam->zoomV = 100; //[0,100]
|
|
pGdcParam->scale = 100; //[0,100]
|
|
pGdcParam->innerRadius = 0; //[0,width/2]
|
|
pGdcParam->roll = 0; //[-90,90]
|
|
pGdcParam->pitch = 0; //[-90,90]
|
|
pGdcParam->yaw = 0; //[-90,90]
|
|
|
|
pGdcParam->perspFunc = Gdc_Persp_Only;
|
|
pGdcParam->perspectiveProjMat[0] = 1.0;
|
|
pGdcParam->perspectiveProjMat[1] = 0.0;
|
|
pGdcParam->perspectiveProjMat[2] = 0.0;
|
|
pGdcParam->perspectiveProjMat[3] = 0.0;
|
|
pGdcParam->perspectiveProjMat[4] = 1.0;
|
|
pGdcParam->perspectiveProjMat[5] = 0.0;
|
|
pGdcParam->perspectiveProjMat[6] = 0.0;
|
|
pGdcParam->perspectiveProjMat[7] = 0.0;
|
|
pGdcParam->perspectiveProjMat[8] = 1.0;
|
|
|
|
pGdcParam->mountHeight = 0.85; //meters
|
|
pGdcParam->roiDist_ahead = 4.5; //meters
|
|
pGdcParam->roiDist_left = -1.5; //meters
|
|
pGdcParam->roiDist_right = 1.5; //meters
|
|
pGdcParam->roiDist_bottom = 0.65; //meters
|
|
|
|
pGdcParam->peaking_en = 1; //0/1
|
|
pGdcParam->peaking_clamp = 1; //0/1
|
|
pGdcParam->peak_m = 16; //[0,63]
|
|
pGdcParam->th_strong_edge = 6; //[0,15]
|
|
pGdcParam->peak_weights_strength = 2; //[0,15]
|
|
|
|
if (pGdcParam->eWarpMode == Gdc_Warp_LDC)
|
|
{
|
|
pGdcParam->birdsImg_width = 768;
|
|
pGdcParam->birdsImg_height = 1080;
|
|
}
|
|
}
|
|
|
|
static ERRORTYPE configVencChnAttr(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData)
|
|
{
|
|
memset(&pVi2Venc2MuxerData->mVencChnAttr, 0, sizeof(VENC_CHN_ATTR_S));
|
|
if (pVi2Venc2MuxerData->mConfigPara.mOnlineEnable)
|
|
{
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.mOnlineEnable = 1;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.mOnlineShareBufNum = pVi2Venc2MuxerData->mConfigPara.mOnlineShareBufNum;
|
|
}
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Type = pVi2Venc2MuxerData->mConfigPara.mVideoEncoderFmt;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.MaxKeyInterval = pVi2Venc2MuxerData->mConfigPara.mKeyFrameInterval;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.SrcPicWidth = pVi2Venc2MuxerData->mConfigPara.srcWidth;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.SrcPicHeight = pVi2Venc2MuxerData->mConfigPara.srcHeight;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Field = pVi2Venc2MuxerData->mConfigPara.mField;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.PixelFormat = pVi2Venc2MuxerData->mConfigPara.srcPixFmt;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.mColorSpace = pVi2Venc2MuxerData->mConfigPara.mColorSpace;
|
|
alogd("pixfmt:0x%x, colorSpace:0x%x", pVi2Venc2MuxerData->mVencChnAttr.VeAttr.PixelFormat, pVi2Venc2MuxerData->mVencChnAttr.VeAttr.mColorSpace);
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.mDropFrameNum = pVi2Venc2MuxerData->mConfigPara.mVencDropFrameNum;
|
|
alogd("DropFrameNum:%d", pVi2Venc2MuxerData->mVencChnAttr.VeAttr.mDropFrameNum);
|
|
switch(pVi2Venc2MuxerData->mConfigPara.mEncodeRotate)
|
|
{
|
|
case 90:
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Rotate = ROTATE_90;
|
|
break;
|
|
case 180:
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Rotate = ROTATE_180;
|
|
break;
|
|
case 270:
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Rotate = ROTATE_270;
|
|
break;
|
|
default:
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Rotate = ROTATE_NONE;
|
|
break;
|
|
}
|
|
|
|
pVi2Venc2MuxerData->mVencRcParam.product_mode = pVi2Venc2MuxerData->mConfigPara.mProductMode;
|
|
pVi2Venc2MuxerData->mVencRcParam.sensor_type = pVi2Venc2MuxerData->mConfigPara.mSensorType;
|
|
if (PT_H264 == pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Type)
|
|
{
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH264e.BufSize = pVi2Venc2MuxerData->mConfigPara.mVbvBufferSize;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH264e.mThreshSize = pVi2Venc2MuxerData->mConfigPara.mVbvThreshSize;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH264e.bByFrame = TRUE;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH264e.Profile = map_H264_UserSet2Profile(pVi2Venc2MuxerData->mConfigPara.mEncUseProfile);
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH264e.mLevel = H264_LEVEL_51; //H264_LEVEL_32
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH264e.PicWidth = pVi2Venc2MuxerData->mConfigPara.dstWidth;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH264e.PicHeight = pVi2Venc2MuxerData->mConfigPara.dstHeight;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH264e.mbPIntraEnable = TRUE;
|
|
switch (pVi2Venc2MuxerData->mConfigPara.mRcMode)
|
|
{
|
|
case 1:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_H264VBR;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Vbr.mMinQp = pVi2Venc2MuxerData->mConfigPara.mQp0;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Vbr.mMaxQp = pVi2Venc2MuxerData->mConfigPara.mQp1;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH264Vbr.mMaxBitRate = pVi2Venc2MuxerData->mConfigPara.mVideoBitRate;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Vbr.mMaxPqp = 50;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Vbr.mMinPqp = 10;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Vbr.mQpInit = 30;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Vbr.mbEnMbQpLimit = pVi2Venc2MuxerData->mConfigPara.mEnMbQpLimit;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Vbr.mMovingTh = 20;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Vbr.mQuality = 8;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Vbr.mIFrmBitsCoef = 15;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Vbr.mPFrmBitsCoef = 10;
|
|
break;
|
|
case 2:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_H264FIXQP;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH264FixQp.mIQp = pVi2Venc2MuxerData->mConfigPara.mQp0;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH264FixQp.mPQp = pVi2Venc2MuxerData->mConfigPara.mQp1;
|
|
break;
|
|
case 3:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_H264ABR;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH264Abr.mMaxBitRate = pVi2Venc2MuxerData->mConfigPara.mVideoBitRate;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH264Abr.mRatioChangeQp = 85;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH264Abr.mQuality = 8;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH264Abr.mMinIQp = 20;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH264Abr.mMinQp = pVi2Venc2MuxerData->mConfigPara.mQp0;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH264Abr.mMaxQp = pVi2Venc2MuxerData->mConfigPara.mQp1;
|
|
break;
|
|
case 0:
|
|
default:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_H264CBR;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH264Cbr.mBitRate = pVi2Venc2MuxerData->mConfigPara.mVideoBitRate;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Cbr.mMaxQp = pVi2Venc2MuxerData->mConfigPara.mQp1;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Cbr.mMinQp = pVi2Venc2MuxerData->mConfigPara.mQp0;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Cbr.mMaxPqp = 50;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Cbr.mMinPqp = 10;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Cbr.mQpInit = 30;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH264Cbr.mbEnMbQpLimit = pVi2Venc2MuxerData->mConfigPara.mEnMbQpLimit;
|
|
break;
|
|
}
|
|
if (pVi2Venc2MuxerData->mConfigPara.mEnableFastEnc)
|
|
{
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH264e.FastEncFlag = TRUE;
|
|
}
|
|
}
|
|
else if (PT_H265 == pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Type)
|
|
{
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH265e.mBufSize = pVi2Venc2MuxerData->mConfigPara.mVbvBufferSize;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH265e.mThreshSize = pVi2Venc2MuxerData->mConfigPara.mVbvThreshSize;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH265e.mbByFrame = TRUE;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH265e.mProfile = map_H265_UserSet2Profile(pVi2Venc2MuxerData->mConfigPara.mEncUseProfile);
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH265e.mLevel = H265_LEVEL_62;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH265e.mPicWidth = pVi2Venc2MuxerData->mConfigPara.dstWidth;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH265e.mPicHeight = pVi2Venc2MuxerData->mConfigPara.dstHeight;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH265e.mbPIntraEnable = TRUE;
|
|
switch (pVi2Venc2MuxerData->mConfigPara.mRcMode)
|
|
{
|
|
case 1:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_H265VBR;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Vbr.mMinQp = pVi2Venc2MuxerData->mConfigPara.mQp0;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Vbr.mMaxQp = pVi2Venc2MuxerData->mConfigPara.mQp1;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH265Vbr.mMaxBitRate = pVi2Venc2MuxerData->mConfigPara.mVideoBitRate;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Vbr.mMaxPqp = 50;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Vbr.mMinPqp = 10;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Vbr.mQpInit = 30;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Vbr.mbEnMbQpLimit = pVi2Venc2MuxerData->mConfigPara.mEnMbQpLimit;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Vbr.mMovingTh = 20;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Vbr.mQuality = 5;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Vbr.mIFrmBitsCoef = 15;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Vbr.mPFrmBitsCoef = 10;
|
|
break;
|
|
case 2:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_H265FIXQP;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH265FixQp.mIQp = pVi2Venc2MuxerData->mConfigPara.mQp0;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH265FixQp.mPQp = pVi2Venc2MuxerData->mConfigPara.mQp1;
|
|
break;
|
|
case 3:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_H265ABR;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH265Abr.mMaxBitRate = pVi2Venc2MuxerData->mConfigPara.mVideoBitRate;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH265Abr.mRatioChangeQp = 85;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH265Abr.mQuality = 8;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH265Abr.mMinIQp = 20;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH265Abr.mMinQp = pVi2Venc2MuxerData->mConfigPara.mQp0;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH265Abr.mMaxQp = pVi2Venc2MuxerData->mConfigPara.mQp1;
|
|
break;
|
|
case 0:
|
|
default:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_H265CBR;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrH265Cbr.mBitRate = pVi2Venc2MuxerData->mConfigPara.mVideoBitRate;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Cbr.mMaxQp = pVi2Venc2MuxerData->mConfigPara.mQp1;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Cbr.mMinQp = pVi2Venc2MuxerData->mConfigPara.mQp0;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Cbr.mMaxPqp = 50;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Cbr.mMinPqp = 10;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Cbr.mQpInit = 30;
|
|
pVi2Venc2MuxerData->mVencRcParam.ParamH265Cbr.mbEnMbQpLimit = pVi2Venc2MuxerData->mConfigPara.mEnMbQpLimit;
|
|
break;
|
|
}
|
|
if (pVi2Venc2MuxerData->mConfigPara.mEnableFastEnc)
|
|
{
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrH265e.mFastEncFlag = TRUE;
|
|
}
|
|
}
|
|
else if (PT_MJPEG == pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Type)
|
|
{
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrMjpeg.mBufSize = pVi2Venc2MuxerData->mConfigPara.mVbvBufferSize;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrMjpeg.mbByFrame = TRUE;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrMjpeg.mPicWidth = pVi2Venc2MuxerData->mConfigPara.dstWidth;
|
|
pVi2Venc2MuxerData->mVencChnAttr.VeAttr.AttrMjpeg.mPicHeight = pVi2Venc2MuxerData->mConfigPara.dstHeight;
|
|
switch (pVi2Venc2MuxerData->mConfigPara.mRcMode)
|
|
{
|
|
case 0:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_MJPEGCBR;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrMjpegeCbr.mBitRate = pVi2Venc2MuxerData->mConfigPara.mVideoBitRate;
|
|
break;
|
|
case 1:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_MJPEGFIXQP;
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrMjpegeFixQp.mQfactor = 40;
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
aloge("not support! use default cbr mode");
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_MJPEGCBR;
|
|
break;
|
|
default:
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode = VENC_RC_MODE_MJPEGCBR;
|
|
break;
|
|
}
|
|
pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mAttrMjpegeCbr.mBitRate = pVi2Venc2MuxerData->mConfigPara.mVideoBitRate;
|
|
}
|
|
|
|
alogd("venc set Rcmode=%d", pVi2Venc2MuxerData->mVencChnAttr.RcAttr.mRcMode);
|
|
|
|
if(0 == pVi2Venc2MuxerData->mConfigPara.mGopMode)
|
|
{
|
|
pVi2Venc2MuxerData->mVencChnAttr.GopAttr.enGopMode = VENC_GOPMODE_NORMALP;
|
|
}
|
|
else if(1 == pVi2Venc2MuxerData->mConfigPara.mGopMode)
|
|
{
|
|
pVi2Venc2MuxerData->mVencChnAttr.GopAttr.enGopMode = VENC_GOPMODE_DUALP;
|
|
}
|
|
else if(2 == pVi2Venc2MuxerData->mConfigPara.mGopMode)
|
|
{
|
|
pVi2Venc2MuxerData->mVencChnAttr.GopAttr.enGopMode = VENC_GOPMODE_SMARTP;
|
|
pVi2Venc2MuxerData->mVencChnAttr.GopAttr.stSmartP.mVirtualIFrameInterval = 15;
|
|
}
|
|
pVi2Venc2MuxerData->mVencChnAttr.GopAttr.mGopSize = pVi2Venc2MuxerData->mConfigPara.mGopSize;
|
|
|
|
if (pVi2Venc2MuxerData->mConfigPara.mEnableGdc)
|
|
{
|
|
alogd("enable GDC and init GDC params");
|
|
initGdcParam(&pVi2Venc2MuxerData->mVencChnAttr.GdcAttr);
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
static ERRORTYPE createVencChn(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData)
|
|
{
|
|
ERRORTYPE ret;
|
|
BOOL nSuccessFlag = FALSE;
|
|
|
|
configVencChnAttr(pVi2Venc2MuxerData);
|
|
if (pVi2Venc2MuxerData->mConfigPara.mOnlineEnable)
|
|
{
|
|
pVi2Venc2MuxerData->mVeChn = 0;
|
|
alogd("online: only vipp0 & Vechn0 support online.");
|
|
}
|
|
else
|
|
{
|
|
pVi2Venc2MuxerData->mVeChn = pVi2Venc2MuxerData->mConfigPara.mVeChn;
|
|
}
|
|
|
|
while (pVi2Venc2MuxerData->mVeChn < VENC_MAX_CHN_NUM)
|
|
{
|
|
ret = AW_MPI_VENC_CreateChn(pVi2Venc2MuxerData->mVeChn, &pVi2Venc2MuxerData->mVencChnAttr);
|
|
if (SUCCESS == ret)
|
|
{
|
|
nSuccessFlag = TRUE;
|
|
alogd("create venc channel[%d] success!", pVi2Venc2MuxerData->mVeChn);
|
|
break;
|
|
}
|
|
else if (ERR_VENC_EXIST == ret)
|
|
{
|
|
alogd("venc channel[%d] is exist, find next!", pVi2Venc2MuxerData->mVeChn);
|
|
pVi2Venc2MuxerData->mVeChn++;
|
|
}
|
|
else
|
|
{
|
|
alogd("create venc channel[%d] ret[0x%x], find next!", pVi2Venc2MuxerData->mVeChn, ret);
|
|
pVi2Venc2MuxerData->mVeChn++;
|
|
}
|
|
}
|
|
|
|
if (nSuccessFlag == FALSE)
|
|
{
|
|
pVi2Venc2MuxerData->mVeChn = MM_INVALID_CHN;
|
|
aloge("fatal error! create venc channel fail!");
|
|
return FAILURE;
|
|
}
|
|
else
|
|
{
|
|
int nFreq = pVi2Venc2MuxerData->mConfigPara.mVeFreq;
|
|
if (0 != nFreq)
|
|
{
|
|
alogd("set VE freq %d MHz", nFreq);
|
|
AW_MPI_VENC_SetVEFreq(pVi2Venc2MuxerData->mVeChn, nFreq);
|
|
}
|
|
AW_MPI_VENC_SetRcParam(pVi2Venc2MuxerData->mVeChn, &pVi2Venc2MuxerData->mVencRcParam);
|
|
VENC_FRAME_RATE_S stFrameRate;
|
|
stFrameRate.SrcFrmRate = stFrameRate.DstFrmRate = pVi2Venc2MuxerData->mConfigPara.mVideoFrameRate;
|
|
alogd("set venc framerate:%d", stFrameRate.DstFrmRate);
|
|
AW_MPI_VENC_SetFrameRate(pVi2Venc2MuxerData->mVeChn, &stFrameRate);
|
|
|
|
VENC_PARAM_REF_S stRefParam;
|
|
memset(&stRefParam, 0, sizeof(VENC_PARAM_REF_S));
|
|
stRefParam.Base = pVi2Venc2MuxerData->mConfigPara.mAdvancedRef_Base;
|
|
stRefParam.Enhance = pVi2Venc2MuxerData->mConfigPara.mAdvancedRef_Enhance;
|
|
stRefParam.bEnablePred = pVi2Venc2MuxerData->mConfigPara.mAdvancedRef_RefBaseEn;
|
|
AW_MPI_VENC_SetRefParam(pVi2Venc2MuxerData->mVeChn, &stRefParam);
|
|
|
|
AW_MPI_VENC_Set3DNR(pVi2Venc2MuxerData->mVeChn, pVi2Venc2MuxerData->mConfigPara.m3DNR);
|
|
alogd("set 3DNR %d", pVi2Venc2MuxerData->mConfigPara.m3DNR);
|
|
|
|
VENC_COLOR2GREY_S bColor2Grey;
|
|
memset(&bColor2Grey, 0, sizeof(VENC_COLOR2GREY_S));
|
|
bColor2Grey.bColor2Grey = pVi2Venc2MuxerData->mConfigPara.mColor2Grey;
|
|
AW_MPI_VENC_SetColor2Grey(pVi2Venc2MuxerData->mVeChn, &bColor2Grey);
|
|
alogd("set Color2Grey %d", pVi2Venc2MuxerData->mConfigPara.mColor2Grey);
|
|
|
|
AW_MPI_VENC_SetHorizonFlip(pVi2Venc2MuxerData->mVeChn, pVi2Venc2MuxerData->mConfigPara.mHorizonFlipFlag);
|
|
alogd("set HorizonFlip %d", pVi2Venc2MuxerData->mConfigPara.mHorizonFlipFlag);
|
|
|
|
VENC_CROP_CFG_S stCropCfg;
|
|
memset(&stCropCfg, 0, sizeof(VENC_CROP_CFG_S));
|
|
stCropCfg.bEnable = pVi2Venc2MuxerData->mConfigPara.mCropEnable;
|
|
stCropCfg.Rect.X = pVi2Venc2MuxerData->mConfigPara.mCropRectX;
|
|
stCropCfg.Rect.Y = pVi2Venc2MuxerData->mConfigPara.mCropRectY;
|
|
stCropCfg.Rect.Width = pVi2Venc2MuxerData->mConfigPara.mCropRectWidth;
|
|
stCropCfg.Rect.Height = pVi2Venc2MuxerData->mConfigPara.mCropRectHeight;
|
|
AW_MPI_VENC_SetCrop(pVi2Venc2MuxerData->mVeChn, &stCropCfg);
|
|
alogd("set Crop %d, [%d][%d][%d][%d]", stCropCfg.bEnable, stCropCfg.Rect.X, stCropCfg.Rect.Y, stCropCfg.Rect.Width, stCropCfg.Rect.Height);
|
|
|
|
//test PIntraRefresh
|
|
if(pVi2Venc2MuxerData->mConfigPara.mIntraRefreshBlockNum > 0)
|
|
{
|
|
VENC_PARAM_INTRA_REFRESH_S stIntraRefresh;
|
|
memset(&stIntraRefresh, 0, sizeof(VENC_PARAM_INTRA_REFRESH_S));
|
|
stIntraRefresh.bRefreshEnable = TRUE;
|
|
stIntraRefresh.RefreshLineNum = pVi2Venc2MuxerData->mConfigPara.mIntraRefreshBlockNum;
|
|
ret = AW_MPI_VENC_SetIntraRefresh(pVi2Venc2MuxerData->mVeChn, &stIntraRefresh);
|
|
if(ret != SUCCESS)
|
|
{
|
|
aloge("fatal error! set roiBgFrameRate fail[0x%x]!", ret);
|
|
}
|
|
else
|
|
{
|
|
alogd("set intra refresh:%d", stIntraRefresh.RefreshLineNum);
|
|
}
|
|
}
|
|
|
|
if(pVi2Venc2MuxerData->mConfigPara.mbEnableSmart)
|
|
{
|
|
VencSmartFun smartParam;
|
|
memset(&smartParam, 0, sizeof(VencSmartFun));
|
|
smartParam.smart_fun_en = 1;
|
|
smartParam.img_bin_en = 1;
|
|
smartParam.img_bin_th = 0;
|
|
smartParam.shift_bits = 2;
|
|
AW_MPI_VENC_SetSmartP(pVi2Venc2MuxerData->mVeChn, &smartParam);
|
|
}
|
|
|
|
if(pVi2Venc2MuxerData->mConfigPara.mSVCLayer > 0)
|
|
{
|
|
VencH264SVCSkip stSVCSkip;
|
|
memset(&stSVCSkip, 0, sizeof(VencH264SVCSkip));
|
|
stSVCSkip.nTemporalSVC = pVi2Venc2MuxerData->mConfigPara.mSVCLayer;
|
|
AW_MPI_VENC_SetH264SVCSkip(pVi2Venc2MuxerData->mVeChn, &stSVCSkip);
|
|
}
|
|
|
|
if (pVi2Venc2MuxerData->mConfigPara.mVuiTimingInfoPresentFlag)
|
|
{
|
|
/** must be call it before AW_MPI_VENC_GetH264SpsPpsInfo(unbind) and AW_MPI_VENC_StartRecvPic. */
|
|
if(PT_H264 == pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Type)
|
|
{
|
|
VENC_PARAM_H264_VUI_S H264Vui;
|
|
memset(&H264Vui, 0, sizeof(VENC_PARAM_H264_VUI_S));
|
|
AW_MPI_VENC_GetH264Vui(pVi2Venc2MuxerData->mVeChn, &H264Vui);
|
|
H264Vui.VuiTimeInfo.timing_info_present_flag = 1;
|
|
H264Vui.VuiTimeInfo.fixed_frame_rate_flag = 0;
|
|
H264Vui.VuiTimeInfo.num_units_in_tick = 1000;
|
|
H264Vui.VuiTimeInfo.time_scale = H264Vui.VuiTimeInfo.num_units_in_tick * pVi2Venc2MuxerData->mConfigPara.mVideoFrameRate * 2;
|
|
AW_MPI_VENC_SetH264Vui(pVi2Venc2MuxerData->mVeChn, &H264Vui);
|
|
}
|
|
else if(PT_H265 == pVi2Venc2MuxerData->mVencChnAttr.VeAttr.Type)
|
|
{
|
|
VENC_PARAM_H265_VUI_S H265Vui;
|
|
memset(&H265Vui, 0, sizeof(VENC_PARAM_H265_VUI_S));
|
|
AW_MPI_VENC_GetH265Vui(pVi2Venc2MuxerData->mVeChn, &H265Vui);
|
|
H265Vui.VuiTimeInfo.timing_info_present_flag = 1;
|
|
H265Vui.VuiTimeInfo.num_units_in_tick = 1000;
|
|
/* Notices: the protocol syntax states that h265 does not need to be multiplied by 2. */
|
|
H265Vui.VuiTimeInfo.time_scale = H265Vui.VuiTimeInfo.num_units_in_tick * pVi2Venc2MuxerData->mConfigPara.mVideoFrameRate;
|
|
H265Vui.VuiTimeInfo.num_ticks_poc_diff_one_minus1 = H265Vui.VuiTimeInfo.num_units_in_tick;
|
|
AW_MPI_VENC_SetH265Vui(pVi2Venc2MuxerData->mVeChn, &H265Vui);
|
|
}
|
|
}
|
|
|
|
MPPCallbackInfo cbInfo;
|
|
cbInfo.cookie = (void*)pVi2Venc2MuxerData;
|
|
cbInfo.callback = (MPPCallbackFuncType)&MPPCallbackWrapper;
|
|
AW_MPI_VENC_RegisterCallback(pVi2Venc2MuxerData->mVeChn, &cbInfo);
|
|
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
|
|
static ERRORTYPE createViChn(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData)
|
|
{
|
|
ERRORTYPE ret;
|
|
|
|
//create vi channel
|
|
if (pVi2Venc2MuxerData->mConfigPara.mOnlineEnable)
|
|
{
|
|
pVi2Venc2MuxerData->mViDev = 0;
|
|
alogd("online: only vipp0 & Vechn0 support online.");
|
|
}
|
|
else
|
|
{
|
|
pVi2Venc2MuxerData->mViDev = pVi2Venc2MuxerData->mConfigPara.mVippDev;
|
|
}
|
|
pVi2Venc2MuxerData->mIspDev = 0;
|
|
pVi2Venc2MuxerData->mViChn = 0;
|
|
|
|
ret = AW_MPI_VI_CreateVipp(pVi2Venc2MuxerData->mViDev);
|
|
if (ret != SUCCESS)
|
|
{
|
|
aloge("fatal error! AW_MPI_VI CreateVipp failed");
|
|
}
|
|
|
|
memset(&pVi2Venc2MuxerData->mViAttr, 0, sizeof(VI_ATTR_S));
|
|
if (pVi2Venc2MuxerData->mConfigPara.mOnlineEnable)
|
|
{
|
|
pVi2Venc2MuxerData->mViAttr.mOnlineEnable = 1;
|
|
pVi2Venc2MuxerData->mViAttr.mOnlineShareBufNum = pVi2Venc2MuxerData->mConfigPara.mOnlineShareBufNum;
|
|
}
|
|
pVi2Venc2MuxerData->mViAttr.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
|
pVi2Venc2MuxerData->mViAttr.memtype = V4L2_MEMORY_MMAP;
|
|
pVi2Venc2MuxerData->mViAttr.format.pixelformat = map_PIXEL_FORMAT_E_to_V4L2_PIX_FMT(pVi2Venc2MuxerData->mConfigPara.srcPixFmt);
|
|
pVi2Venc2MuxerData->mViAttr.format.field = V4L2_FIELD_NONE;
|
|
pVi2Venc2MuxerData->mViAttr.format.colorspace = pVi2Venc2MuxerData->mConfigPara.mColorSpace;
|
|
pVi2Venc2MuxerData->mViAttr.format.width = pVi2Venc2MuxerData->mConfigPara.srcWidth;
|
|
pVi2Venc2MuxerData->mViAttr.format.height = pVi2Venc2MuxerData->mConfigPara.srcHeight;
|
|
pVi2Venc2MuxerData->mViAttr.nbufs = pVi2Venc2MuxerData->mConfigPara.mViBufferNum;
|
|
alogd("vipp use %d v4l2 buffers, colorspace: 0x%x", pVi2Venc2MuxerData->mViAttr.nbufs, pVi2Venc2MuxerData->mViAttr.format.colorspace);
|
|
pVi2Venc2MuxerData->mViAttr.nplanes = 2;
|
|
pVi2Venc2MuxerData->mViAttr.wdr_mode = pVi2Venc2MuxerData->mConfigPara.wdr_en;
|
|
alogd("wdr_mode %d", pVi2Venc2MuxerData->mViAttr.wdr_mode);
|
|
pVi2Venc2MuxerData->mViAttr.fps = pVi2Venc2MuxerData->mConfigPara.mVideoFrameRate;
|
|
pVi2Venc2MuxerData->mViAttr.drop_frame_num = pVi2Venc2MuxerData->mConfigPara.mViDropFrameNum;
|
|
|
|
ret = AW_MPI_VI_SetVippAttr(pVi2Venc2MuxerData->mViDev, &pVi2Venc2MuxerData->mViAttr);
|
|
if (ret != SUCCESS)
|
|
{
|
|
aloge("fatal error! AW_MPI_VI SetVippAttr failed");
|
|
}
|
|
#if ISP_RUN
|
|
AW_MPI_ISP_Run(pVi2Venc2MuxerData->mIspDev);
|
|
#endif
|
|
ViVirChnAttrS stVirChnAttr;
|
|
memset(&stVirChnAttr, 0, sizeof(ViVirChnAttrS));
|
|
stVirChnAttr.mbRecvInIdleState = TRUE;
|
|
ret = AW_MPI_VI_CreateVirChn(pVi2Venc2MuxerData->mViDev, pVi2Venc2MuxerData->mViChn, &stVirChnAttr);
|
|
if (ret != SUCCESS)
|
|
{
|
|
aloge("fatal error! createVirChn[%d] fail!", pVi2Venc2MuxerData->mViChn);
|
|
}
|
|
ret = AW_MPI_VI_EnableVipp(pVi2Venc2MuxerData->mViDev);
|
|
if (ret != SUCCESS)
|
|
{
|
|
aloge("fatal error! enableVipp fail!");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static ERRORTYPE prepare(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData)
|
|
{
|
|
BOOL nSuccessFlag;
|
|
MUX_CHN nMuxChn;
|
|
MUX_CHN_INFO_S *pEntry, *pTmp;
|
|
ERRORTYPE ret;
|
|
ERRORTYPE result = FAILURE;
|
|
|
|
if (createViChn(pVi2Venc2MuxerData) != SUCCESS)
|
|
{
|
|
aloge("create vi chn fail");
|
|
return result;
|
|
}
|
|
|
|
if (createVencChn(pVi2Venc2MuxerData) != SUCCESS)
|
|
{
|
|
aloge("create venc chn fail");
|
|
return result;
|
|
}
|
|
|
|
if (createMuxGrp(pVi2Venc2MuxerData) != SUCCESS)
|
|
{
|
|
aloge("create mux group fail");
|
|
return result;
|
|
}
|
|
|
|
//set spspps
|
|
if (pVi2Venc2MuxerData->mConfigPara.mVideoEncoderFmt == PT_H264)
|
|
{
|
|
VencHeaderData H264SpsPpsInfo;
|
|
memset(&H264SpsPpsInfo, 0, sizeof(VencHeaderData));
|
|
ret = AW_MPI_VENC_GetH264SpsPpsInfo(pVi2Venc2MuxerData->mVeChn, &H264SpsPpsInfo);
|
|
if (SUCCESS != ret)
|
|
{
|
|
aloge("fatal error, venc GetH264SpsPpsInfo failed! ret=%d", ret);
|
|
return result;
|
|
}
|
|
AW_MPI_MUX_SetH264SpsPpsInfo(pVi2Venc2MuxerData->mMuxGrp, pVi2Venc2MuxerData->mVeChn, &H264SpsPpsInfo);
|
|
}
|
|
else if(pVi2Venc2MuxerData->mConfigPara.mVideoEncoderFmt == PT_H265)
|
|
{
|
|
VencHeaderData H265SpsPpsInfo;
|
|
memset(&H265SpsPpsInfo, 0, sizeof(VencHeaderData));
|
|
ret = AW_MPI_VENC_GetH265SpsPpsInfo(pVi2Venc2MuxerData->mVeChn, &H265SpsPpsInfo);
|
|
if (SUCCESS != ret)
|
|
{
|
|
aloge("fatal error, venc GetH265SpsPpsInfo failed! ret=%d", ret);
|
|
return result;
|
|
}
|
|
AW_MPI_MUX_SetH265SpsPpsInfo(pVi2Venc2MuxerData->mMuxGrp, pVi2Venc2MuxerData->mVeChn, &H265SpsPpsInfo);
|
|
}
|
|
|
|
pthread_mutex_lock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
if (!list_empty(&pVi2Venc2MuxerData->mMuxChnList))
|
|
{
|
|
list_for_each_entry_safe(pEntry, pTmp, &pVi2Venc2MuxerData->mMuxChnList, mList)
|
|
{
|
|
nMuxChn = 0;
|
|
nSuccessFlag = FALSE;
|
|
while (pEntry->mMuxChn < MUX_MAX_CHN_NUM)
|
|
{
|
|
ret = AW_MPI_MUX_CreateChn(pVi2Venc2MuxerData->mMuxGrp, nMuxChn, &pEntry->mMuxChnAttr, pEntry->mSinkInfo.mOutputFd);
|
|
if (SUCCESS == ret)
|
|
{
|
|
nSuccessFlag = TRUE;
|
|
alogd("create mux group[%d] channel[%d] success, muxerId[%d]!", pVi2Venc2MuxerData->mMuxGrp, \
|
|
nMuxChn, pEntry->mMuxChnAttr.mMuxerId);
|
|
break;
|
|
}
|
|
else if(ERR_MUX_EXIST == ret)
|
|
{
|
|
nMuxChn++;
|
|
//break;
|
|
}
|
|
else
|
|
{
|
|
nMuxChn++;
|
|
}
|
|
}
|
|
|
|
if (FALSE == nSuccessFlag)
|
|
{
|
|
pEntry->mMuxChn = MM_INVALID_CHN;
|
|
aloge("fatal error! create mux group[%d] channel fail!", pVi2Venc2MuxerData->mMuxGrp);
|
|
}
|
|
else
|
|
{
|
|
result = SUCCESS;
|
|
pEntry->mMuxChn = nMuxChn;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aloge("maybe something wrong,mux chn list is empty");
|
|
}
|
|
pthread_mutex_unlock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
|
|
if ((pVi2Venc2MuxerData->mViDev >= 0 && pVi2Venc2MuxerData->mViChn >= 0) && pVi2Venc2MuxerData->mVeChn >= 0)
|
|
{
|
|
MPP_CHN_S ViChn = {MOD_ID_VIU, pVi2Venc2MuxerData->mViDev, pVi2Venc2MuxerData->mViChn};
|
|
MPP_CHN_S VeChn = {MOD_ID_VENC, 0, pVi2Venc2MuxerData->mVeChn};
|
|
|
|
AW_MPI_SYS_Bind(&ViChn, &VeChn);
|
|
}
|
|
|
|
if (pVi2Venc2MuxerData->mVeChn >= 0 && pVi2Venc2MuxerData->mMuxGrp >= 0)
|
|
{
|
|
MPP_CHN_S MuxGrp = {MOD_ID_MUX, 0, pVi2Venc2MuxerData->mMuxGrp};
|
|
MPP_CHN_S VeChn = {MOD_ID_VENC, 0, pVi2Venc2MuxerData->mVeChn};
|
|
|
|
AW_MPI_SYS_Bind(&VeChn, &MuxGrp);
|
|
pVi2Venc2MuxerData->mCurrentState = REC_PREPARED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static ERRORTYPE start(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData)
|
|
{
|
|
ERRORTYPE ret = SUCCESS;
|
|
|
|
alogd("start");
|
|
|
|
ret = AW_MPI_VI_EnableVirChn(pVi2Venc2MuxerData->mViDev, pVi2Venc2MuxerData->mViChn);
|
|
if (ret != SUCCESS)
|
|
{
|
|
alogd("VI enable error!");
|
|
return FAILURE;
|
|
}
|
|
|
|
if (pVi2Venc2MuxerData->mVeChn >= 0)
|
|
{
|
|
AW_MPI_VENC_StartRecvPic(pVi2Venc2MuxerData->mVeChn);
|
|
}
|
|
|
|
if (pVi2Venc2MuxerData->mMuxGrp >= 0)
|
|
{
|
|
AW_MPI_MUX_StartGrp(pVi2Venc2MuxerData->mMuxGrp);
|
|
}
|
|
|
|
pVi2Venc2MuxerData->mCurrentState = REC_RECORDING;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static ERRORTYPE stop(SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData)
|
|
{
|
|
MUX_CHN_INFO_S *pEntry, *pTmp;
|
|
ERRORTYPE ret = SUCCESS;
|
|
|
|
alogd("stop");
|
|
|
|
if (pVi2Venc2MuxerData->mViChn >= 0)
|
|
{
|
|
AW_MPI_VI_DisableVirChn(pVi2Venc2MuxerData->mViDev, pVi2Venc2MuxerData->mViChn);
|
|
}
|
|
|
|
if (pVi2Venc2MuxerData->mVeChn >= 0)
|
|
{
|
|
alogd("stop venc");
|
|
AW_MPI_VENC_StopRecvPic(pVi2Venc2MuxerData->mVeChn);
|
|
}
|
|
|
|
if (pVi2Venc2MuxerData->mMuxGrp >= 0)
|
|
{
|
|
alogd("stop mux grp");
|
|
AW_MPI_MUX_StopGrp(pVi2Venc2MuxerData->mMuxGrp);
|
|
}
|
|
if (pVi2Venc2MuxerData->mMuxGrp >= 0)
|
|
{
|
|
alogd("destory mux grp");
|
|
AW_MPI_MUX_DestroyGrp(pVi2Venc2MuxerData->mMuxGrp);
|
|
pVi2Venc2MuxerData->mMuxGrp = MM_INVALID_CHN;
|
|
}
|
|
if (pVi2Venc2MuxerData->mVeChn >= 0)
|
|
{
|
|
alogd("destory venc");
|
|
//AW_MPI_VENC_ResetChn(pVi2Venc2MuxerData->mVeChn);
|
|
AW_MPI_VENC_DestroyChn(pVi2Venc2MuxerData->mVeChn);
|
|
pVi2Venc2MuxerData->mVeChn = MM_INVALID_CHN;
|
|
}
|
|
if (pVi2Venc2MuxerData->mViChn >= 0)
|
|
{
|
|
AW_MPI_VI_DestroyVirChn(pVi2Venc2MuxerData->mViDev, pVi2Venc2MuxerData->mViChn);
|
|
AW_MPI_VI_DisableVipp(pVi2Venc2MuxerData->mViDev);
|
|
#if ISP_RUN
|
|
AW_MPI_ISP_Stop(pVi2Venc2MuxerData->mIspDev);
|
|
#endif
|
|
AW_MPI_VI_DestroyVipp(pVi2Venc2MuxerData->mViDev);
|
|
}
|
|
|
|
pthread_mutex_lock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
if (!list_empty(&pVi2Venc2MuxerData->mMuxChnList))
|
|
{
|
|
alogd("free chn list node");
|
|
list_for_each_entry_safe(pEntry, pTmp, &pVi2Venc2MuxerData->mMuxChnList, mList)
|
|
{
|
|
if (pEntry->mSinkInfo.mOutputFd > 0)
|
|
{
|
|
alogd("close file");
|
|
close(pEntry->mSinkInfo.mOutputFd);
|
|
pEntry->mSinkInfo.mOutputFd = -1;
|
|
}
|
|
|
|
list_del(&pEntry->mList);
|
|
free(pEntry);
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
ERRORTYPE SampleVI2Venc2Muxer_CreateFolder(const char* pStrFolderPath)
|
|
{
|
|
if(NULL == pStrFolderPath || 0 == strlen(pStrFolderPath))
|
|
{
|
|
aloge("folder path is wrong!");
|
|
return FAILURE;
|
|
}
|
|
//check folder existence
|
|
struct stat sb;
|
|
if (stat(pStrFolderPath, &sb) == 0)
|
|
{
|
|
if(S_ISDIR(sb.st_mode))
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! [%s] is exist, but mode[0x%x] is not directory!", pStrFolderPath, (int)sb.st_mode);
|
|
return FAILURE;
|
|
}
|
|
}
|
|
//create folder if necessary
|
|
int ret = mkdir(pStrFolderPath, S_IRWXU | S_IRWXG | S_IRWXO);
|
|
if(!ret)
|
|
{
|
|
alogd("create folder[%s] success", pStrFolderPath);
|
|
return SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
aloge("fatal error! create folder[%s] failed!", pStrFolderPath);
|
|
return FAILURE;
|
|
}
|
|
}
|
|
|
|
void *MsgQueueThread(void *pThreadData)
|
|
{
|
|
SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData = (SAMPLE_VI2VENC2MUXER_S*)pThreadData;
|
|
message_t stCmdMsg;
|
|
Vi2Venc2MuxerMsgType cmd;
|
|
int nCmdPara;
|
|
|
|
alogd("msg queue thread start run!");
|
|
while (1)
|
|
{
|
|
if (0 == get_message(&pVi2Venc2MuxerData->mMsgQueue, &stCmdMsg))
|
|
{
|
|
cmd = stCmdMsg.command;
|
|
nCmdPara = stCmdMsg.para0;
|
|
|
|
switch (cmd)
|
|
{
|
|
case Rec_NeedSetNextFd:
|
|
{
|
|
int muxerId = nCmdPara;
|
|
char fileName[MAX_FILE_PATH_LEN] = {0};
|
|
Vi2Venc2Muxer_MessageData *pMsgData = (Vi2Venc2Muxer_MessageData*)stCmdMsg.mpData;
|
|
|
|
if (muxerId == pMsgData->pVi2Venc2MuxerData->mMuxId[0])
|
|
{
|
|
getFileNameByCurTime(pMsgData->pVi2Venc2MuxerData, fileName);
|
|
FilePathNode *pFilePathNode = (FilePathNode*)malloc(sizeof(FilePathNode));
|
|
memset(pFilePathNode, 0, sizeof(FilePathNode));
|
|
strncpy(pFilePathNode->strFilePath, fileName, MAX_FILE_PATH_LEN-1);
|
|
list_add_tail(&pFilePathNode->mList, &pMsgData->pVi2Venc2MuxerData->mMuxerFileListArray[0]);
|
|
}
|
|
#ifdef DOUBLE_ENCODER_FILE_OUT
|
|
static int cnt = 0;
|
|
cnt++;
|
|
sprintf(fileName, "/mnt/extsd/sample_vi2venc2muxer/%d.ts", cnt);
|
|
FilePathNode *pFilePathNode = (FilePathNode*)malloc(sizeof(FilePathNode));
|
|
memset(pFilePathNode->strFilePath, fileName, MAX_FILE_PATH_LEN-1);
|
|
list_add_tail(&pFilePathNode->mList, &pVi2Venc2MuxerData->mMuxerFileListArray[1]);
|
|
#endif
|
|
alogd("muxId[%d] set next fd, filepath=%s", muxerId, fileName);
|
|
setOutputFileSync(pVi2Venc2MuxerData, fileName, 0, muxerId);
|
|
//free msg mpdata
|
|
free(stCmdMsg.mpData);
|
|
stCmdMsg.mpData = NULL;
|
|
break;
|
|
}
|
|
case Rec_FileDone:
|
|
{
|
|
int ret;
|
|
int muxerId = nCmdPara;
|
|
Vi2Venc2Muxer_MessageData *pMsgData = (Vi2Venc2Muxer_MessageData*)stCmdMsg.mpData;
|
|
int idx = -1;
|
|
|
|
if (muxerId == pMsgData->pVi2Venc2MuxerData->mMuxId[0])
|
|
{
|
|
idx = 0;
|
|
}
|
|
#ifdef DOUBLE_ENCODER_FILE_OUT
|
|
else if
|
|
{
|
|
idx = 1;
|
|
}
|
|
#endif
|
|
if (idx >= 0)
|
|
{
|
|
int cnt = 0;
|
|
struct list_head *pList;
|
|
list_for_each(pList, &pMsgData->pVi2Venc2MuxerData->mMuxerFileListArray[idx]){cnt++;}
|
|
FilePathNode *pNode = NULL;
|
|
while (cnt > pMsgData->pVi2Venc2MuxerData->mConfigPara.mDstFileMaxCnt)
|
|
{
|
|
pNode = list_first_entry(&pMsgData->pVi2Venc2MuxerData->mMuxerFileListArray[idx], FilePathNode, mList);
|
|
if ((ret = remove(pNode->strFilePath)) != 0)
|
|
{
|
|
aloge("fatal error! delete file[%s] failed:%s", pNode->strFilePath, strerror(errno));
|
|
}
|
|
else
|
|
{
|
|
alogd("delete file[%s] success", pNode->strFilePath);
|
|
}
|
|
cnt--;
|
|
list_del(&pNode->mList);
|
|
free(pNode);
|
|
}
|
|
}
|
|
//free msg mpdata
|
|
free(stCmdMsg.mpData);
|
|
stCmdMsg.mpData = NULL;
|
|
break;
|
|
}
|
|
case MsgQueue_Stop:
|
|
{
|
|
goto _Exit;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TMessage_WaitQueueNotEmpty(&pVi2Venc2MuxerData->mMsgQueue, 0);
|
|
}
|
|
}
|
|
_Exit:
|
|
alogd("msg queue thread exit!");
|
|
return NULL;
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
int result = -1;
|
|
MUX_CHN_INFO_S *pEntry, *pTmp;
|
|
GLogConfig stGLogConfig =
|
|
{
|
|
.FLAGS_logtostderr = 1,
|
|
.FLAGS_colorlogtostderr = 1,
|
|
.FLAGS_stderrthreshold = _GLOG_INFO,
|
|
.FLAGS_minloglevel = _GLOG_INFO,
|
|
.FLAGS_logbuflevel = -1,
|
|
.FLAGS_logbufsecs = 0,
|
|
.FLAGS_max_log_size = 1,
|
|
.FLAGS_stop_logging_if_full_disk = 1,
|
|
};
|
|
strcpy(stGLogConfig.LogDir, "/tmp/log");
|
|
strcpy(stGLogConfig.InfoLogFileNameBase, "LOG-");
|
|
strcpy(stGLogConfig.LogFileNameExtension, "IPC-");
|
|
log_init(argv[0], &stGLogConfig);
|
|
|
|
printf("sample_virvi2venc2muxer running!\n");
|
|
SAMPLE_VI2VENC2MUXER_S *pVi2Venc2MuxerData = (SAMPLE_VI2VENC2MUXER_S* )malloc(sizeof(SAMPLE_VI2VENC2MUXER_S));
|
|
|
|
if (pVi2Venc2MuxerData == NULL)
|
|
{
|
|
aloge("malloc struct fail");
|
|
result = FAILURE;
|
|
goto _err0;
|
|
}
|
|
if (InitVi2Venc2MuxerData(pVi2Venc2MuxerData) != SUCCESS)
|
|
{
|
|
return -1;
|
|
}
|
|
gpVi2Venc2MuxerData = pVi2Venc2MuxerData;
|
|
cdx_sem_init(&pVi2Venc2MuxerData->mSemExit, 0);
|
|
|
|
/* register process function for SIGINT, to exit program. */
|
|
if (signal(SIGINT, handle_exit) == SIG_ERR)
|
|
{
|
|
aloge("can't catch SIGSEGV");
|
|
}
|
|
|
|
if (parseCmdLine(pVi2Venc2MuxerData, argc, argv) != SUCCESS)
|
|
{
|
|
aloge("parse cmdline fail");
|
|
result = FAILURE;
|
|
goto err_out_0;
|
|
}
|
|
char *pConfPath = NULL;
|
|
if(argc > 1)
|
|
{
|
|
pConfPath = pVi2Venc2MuxerData->mCmdLinePara.mConfigFilePath;
|
|
}
|
|
|
|
if (loadConfigPara(pVi2Venc2MuxerData, pConfPath) != SUCCESS)
|
|
{
|
|
aloge("load config file fail");
|
|
result = FAILURE;
|
|
goto err_out_0;
|
|
}
|
|
alogd("ViDropFrameNum=%d", pVi2Venc2MuxerData->mConfigPara.mViDropFrameNum);
|
|
result = SampleVI2Venc2Muxer_CreateFolder(pVi2Venc2MuxerData->mDstDir);
|
|
if (result)
|
|
{
|
|
goto err_out_0;
|
|
}
|
|
|
|
INIT_LIST_HEAD(&pVi2Venc2MuxerData->mMuxChnList);
|
|
pthread_mutex_init(&pVi2Venc2MuxerData->mMuxChnListLock, NULL);
|
|
|
|
pVi2Venc2MuxerData->mSysConf.nAlignWidth = 32;
|
|
AW_MPI_SYS_SetConf(&pVi2Venc2MuxerData->mSysConf);
|
|
result = AW_MPI_SYS_Init();
|
|
if (SUCCESS != result)
|
|
{
|
|
goto err_out_0;
|
|
}
|
|
|
|
pVi2Venc2MuxerData->mMuxId[0] = addOutputFormatAndOutputSink(pVi2Venc2MuxerData, pVi2Venc2MuxerData->mConfigPara.dstVideoFile, MEDIA_FILE_FORMAT_MP4);
|
|
if (pVi2Venc2MuxerData->mMuxId[0] < 0)
|
|
{
|
|
result = -1;
|
|
aloge("add first out file fail");
|
|
goto err_out_1;
|
|
}
|
|
FilePathNode *pFilePathNode = (FilePathNode*)malloc(sizeof(FilePathNode));
|
|
memset(pFilePathNode, 0, sizeof(FilePathNode));
|
|
strncpy(pFilePathNode->strFilePath, pVi2Venc2MuxerData->mConfigPara.dstVideoFile, MAX_FILE_PATH_LEN-1);
|
|
list_add_tail(&pFilePathNode->mList, &pVi2Venc2MuxerData->mMuxerFileListArray[0]);
|
|
|
|
#ifdef DOUBLE_ENCODER_FILE_OUT
|
|
char mov_path[MAX_FILE_PATH_LEN];
|
|
strcpy(mov_path, "/mnt/extsd/sample_vi2venc2muxer/0.ts");
|
|
pVi2Venc2MuxerData->mMuxId[1] = addOutputFormatAndOutputSink(pVi2Venc2MuxerData, mov_path, MEDIA_FILE_FORMAT_TS);
|
|
if (pVi2Venc2MuxerData->mMuxId[1] < 0)
|
|
{
|
|
alogd("add mMuxId[1] ts file sink fail");
|
|
}
|
|
else
|
|
{
|
|
FilePathNode *pFilePathNode = (FilePathNode*)malloc(sizeof(FilePathNode));
|
|
memset(pFilePathNode, 0, sizeof(FilePathNode));
|
|
strncpy(pFilePathNode->strFilePath, mov_path, MAX_FILE_PATH_LEN-1);
|
|
list_add_tail(&pFilePathNode->mList, &pVi2Venc2MuxerData->mMuxerFileListArray[1]);
|
|
}
|
|
#endif
|
|
|
|
if (prepare(pVi2Venc2MuxerData) != SUCCESS)
|
|
{
|
|
result = -1;
|
|
aloge("prepare fail!");
|
|
goto err_out_2;
|
|
}
|
|
|
|
//create msg queue thread
|
|
result = pthread_create(&pVi2Venc2MuxerData->mMsgQueueThreadId, NULL, MsgQueueThread, pVi2Venc2MuxerData);
|
|
if (result != 0)
|
|
{
|
|
result = -1;
|
|
aloge("fatal error! create Msg Queue Thread fail[%d]", result);
|
|
goto err_out_3;
|
|
}
|
|
else
|
|
{
|
|
alogd("create Msg Queue Thread success! threadId[0x%x]", &pVi2Venc2MuxerData->mMsgQueueThreadId);
|
|
}
|
|
|
|
start(pVi2Venc2MuxerData);
|
|
|
|
if (pVi2Venc2MuxerData->mConfigPara.mTestDuration > 0)
|
|
{
|
|
cdx_sem_down_timedwait(&pVi2Venc2MuxerData->mSemExit, pVi2Venc2MuxerData->mConfigPara.mTestDuration*1000);
|
|
}
|
|
else
|
|
{
|
|
cdx_sem_down(&pVi2Venc2MuxerData->mSemExit);
|
|
}
|
|
|
|
//stop msg queue thread
|
|
message_t stMsgCmd;
|
|
stMsgCmd.command = MsgQueue_Stop;
|
|
put_message(&pVi2Venc2MuxerData->mMsgQueue, &stMsgCmd);
|
|
pthread_join(pVi2Venc2MuxerData->mMsgQueueThreadId, NULL);
|
|
alogd("start to free res");
|
|
err_out_3:
|
|
stop(pVi2Venc2MuxerData);
|
|
result = 0;
|
|
err_out_2:
|
|
pthread_mutex_lock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
if (!list_empty(&pVi2Venc2MuxerData->mMuxChnList))
|
|
{
|
|
alogd("chn list not empty");
|
|
list_for_each_entry_safe(pEntry, pTmp, &pVi2Venc2MuxerData->mMuxChnList, mList)
|
|
{
|
|
if (pEntry->mSinkInfo.mOutputFd > 0)
|
|
{
|
|
close(pEntry->mSinkInfo.mOutputFd);
|
|
pEntry->mSinkInfo.mOutputFd = -1;
|
|
}
|
|
}
|
|
|
|
list_del(&pEntry->mList);
|
|
free(pEntry);
|
|
}
|
|
pthread_mutex_unlock(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
err_out_1:
|
|
AW_MPI_SYS_Exit();
|
|
|
|
pthread_mutex_destroy(&pVi2Venc2MuxerData->mMuxChnListLock);
|
|
err_out_0:
|
|
cdx_sem_deinit(&pVi2Venc2MuxerData->mSemExit);
|
|
message_destroy(&pVi2Venc2MuxerData->mMsgQueue);
|
|
free(pVi2Venc2MuxerData);
|
|
gpVi2Venc2MuxerData = pVi2Venc2MuxerData = NULL;
|
|
_err0:
|
|
log_quit();
|
|
|
|
int disp_fd = open("/dev/fb0", O_RDWR);
|
|
if (disp_fd < 0)
|
|
{
|
|
alogd("[%s] open fb0 fail!", LOG_TAG);
|
|
}
|
|
|
|
printf("%s", ((0 == result) ? "PASS" : "FAIL"));
|
|
return result;
|
|
}
|