401 lines
14 KiB
C
401 lines
14 KiB
C
|
/******************************************************************************
|
||
|
Copyright (C), 2001-2023, Allwinner Tech. Co., Ltd.
|
||
|
******************************************************************************
|
||
|
File Name : FillVencSeiData.c
|
||
|
Version : Initial Draft
|
||
|
Author : Allwinner
|
||
|
Created : 2023/04/10
|
||
|
Last Modified :
|
||
|
Description : fill vencoder SEI data function
|
||
|
Function List :
|
||
|
History :
|
||
|
******************************************************************************/
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include <utils/plat_log.h>
|
||
|
#include "FillVencSeiData.h"
|
||
|
|
||
|
#define VENC_SEI_DATA_INFO_READ_LINE_LEN_MAX (512)
|
||
|
|
||
|
#define VENC_SEI_CONFIG_LEVEL_MASK_FOR_ISP (0x1)
|
||
|
#define VENC_SEI_CONFIG_LEVEL_MASK_FOR_VIPP (0x2)
|
||
|
#define VENC_SEI_CONFIG_LEVEL_MASK_FOR_VE_BASE (0x4)
|
||
|
#define VENC_SEI_CONFIG_LEVEL_MASK_FOR_VE_ADVANCE (0x8)
|
||
|
|
||
|
#define VENC_SEI_UPDATE_INTERVAL_MS_DEFAULT (1000)
|
||
|
|
||
|
#define VENC_SEI_DATA_BUF_SIZE_FOR_ISP (1024)
|
||
|
#define VENC_SEI_DATA_BUF_SIZE_FOR_VIPP (3*1024)
|
||
|
#define VENC_SEI_DATA_BUF_SIZE_FOR_VE_BASE (1024)
|
||
|
#define VENC_SEI_DATA_BUF_SIZE_FOR_VE_ADVANCE (1024)
|
||
|
|
||
|
#define DEBUGFS_PATH_FOR_ISP "/sys/kernel/debug/mpp/isp"
|
||
|
#define DEBUGFS_PATH_FOR_VIPP "/sys/kernel/debug/mpp/vi"
|
||
|
#define DEBUGFS_PATH_FOR_VE_BASE "/sys/kernel/debug/mpp/ve_base"
|
||
|
#define DEBUGFS_PATH_FOR_VE_ADVANCE "/sys/kernel/debug/mpp/ve_advance"
|
||
|
|
||
|
#define VENC_SEI_INFO_EXE_CMD_FOR_ISP "cat /sys/kernel/debug/mpp/isp"
|
||
|
#define VENC_SEI_INFO_EXE_CMD_FOR_VIPP "cat /sys/kernel/debug/mpp/vi"
|
||
|
#define VENC_SEI_INFO_EXE_CMD_FOR_VE_BASE "cat /sys/kernel/debug/mpp/ve_base"
|
||
|
#define VENC_SEI_INFO_EXE_CMD_FOR_VE_ADVANCE "cat /sys/kernel/debug/mpp/ve_advance"
|
||
|
|
||
|
typedef enum VENC_SEI_DATA_SOURCE
|
||
|
{
|
||
|
VENC_SEI_DATA_ISP_INFO,
|
||
|
VENC_SEI_DATA_VIPP_INFO,
|
||
|
VENC_SEI_DATA_VE_BASE_INFO,
|
||
|
VENC_SEI_DATA_VE_ADVANCE_INFO,
|
||
|
VENC_SEI_DATA_INFO_LAST,
|
||
|
} VENC_SEI_DATA_SOURCE;
|
||
|
|
||
|
static void GetExecuteCmdResult(const char *cmd, unsigned char *result, unsigned int size, unsigned int *reallen)
|
||
|
{
|
||
|
int total_len = 0;
|
||
|
char line[VENC_SEI_DATA_INFO_READ_LINE_LEN_MAX];
|
||
|
*reallen = 0;
|
||
|
|
||
|
FILE *fp = popen(cmd, "r");
|
||
|
if (NULL != fp)
|
||
|
{
|
||
|
// The number of characters in a line should not exceed 512 bytes,
|
||
|
// otherwise it cannot be obtained.
|
||
|
while(fgets(line, VENC_SEI_DATA_INFO_READ_LINE_LEN_MAX, fp) != NULL)
|
||
|
{
|
||
|
total_len += strlen(line);
|
||
|
if (total_len > (size - 1))
|
||
|
{
|
||
|
alogv("total len: %d is more than buf size %d, discard remain info.", total_len, size);
|
||
|
break;
|
||
|
}
|
||
|
strncat((char*)result, line, size);
|
||
|
*reallen += strlen(line);
|
||
|
}
|
||
|
pclose(fp);
|
||
|
fp = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
aloge("fatal error, popen %s error!", cmd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int GetSeiDataInfo(VIDEOENCDATATYPE* pVideoEncData, unsigned int nSeiNum, unsigned int nBufLen, enum VENC_SEI_DATA_SOURCE eSeiDataSource)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
if (VENC_SEI_DATA_NUM_MAX <= nSeiNum)
|
||
|
{
|
||
|
aloge("fatal error, VencChn[%d] invalid SeiNum %d >= %d", pVideoEncData->mMppChnInfo.mChnId, nSeiNum, VENC_SEI_DATA_NUM_MAX);
|
||
|
return -1;
|
||
|
}
|
||
|
VencSeiData *pSeiData = &pVideoEncData->mSeiData[nSeiNum];
|
||
|
|
||
|
if (NULL == pSeiData->pBuffer || 0 == pSeiData->nBufLen || nBufLen != pSeiData->nBufLen)
|
||
|
{
|
||
|
if (pSeiData->pBuffer)
|
||
|
{
|
||
|
alogd("VencChn[%d] SeiData[%d] source %d maybe buf size change %d -> %d, free old buf.", pVideoEncData->mMppChnInfo.mChnId, nSeiNum, eSeiDataSource, pSeiData->nBufLen, nBufLen);
|
||
|
free(pSeiData->pBuffer);
|
||
|
pSeiData->pBuffer = NULL;
|
||
|
pSeiData->nBufLen = 0;
|
||
|
pSeiData->nDataLen = 0;
|
||
|
pSeiData->nType = 0;
|
||
|
}
|
||
|
// all SeiData buffer will be free in VideoEncComponentDeInit()
|
||
|
pSeiData->pBuffer = malloc(nBufLen);
|
||
|
if (NULL == pSeiData->pBuffer)
|
||
|
{
|
||
|
aloge("fatal error, VencChn[%d] malloc SeiData buffer failed! size=%d", pVideoEncData->mMppChnInfo.mChnId, nBufLen);
|
||
|
return ERR_VENC_NOMEM;
|
||
|
}
|
||
|
alogd("VencChn[%d] SeiData[%d] source %d malloc buffer %p, size %d", pVideoEncData->mMppChnInfo.mChnId, nSeiNum, eSeiDataSource, pSeiData->pBuffer, nBufLen);
|
||
|
}
|
||
|
memset(pSeiData->pBuffer, 0, nBufLen);
|
||
|
pSeiData->nBufLen = nBufLen;
|
||
|
pSeiData->nType = 5;
|
||
|
|
||
|
unsigned int nDataLen = 0;
|
||
|
|
||
|
switch (eSeiDataSource)
|
||
|
{
|
||
|
case VENC_SEI_DATA_ISP_INFO:
|
||
|
{
|
||
|
if (access(DEBUGFS_PATH_FOR_ISP, F_OK | W_OK) == 0)
|
||
|
{
|
||
|
GetExecuteCmdResult(VENC_SEI_INFO_EXE_CMD_FOR_ISP, pSeiData->pBuffer, nBufLen, &nDataLen);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
aloge("fatal error, VencChn[%d] %s is not found!", pVideoEncData->mMppChnInfo.mChnId, DEBUGFS_PATH_FOR_ISP);
|
||
|
ret = -1;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case VENC_SEI_DATA_VIPP_INFO:
|
||
|
{
|
||
|
if (access(DEBUGFS_PATH_FOR_VIPP, F_OK | W_OK) == 0)
|
||
|
{
|
||
|
GetExecuteCmdResult(VENC_SEI_INFO_EXE_CMD_FOR_VIPP, pSeiData->pBuffer, nBufLen, &nDataLen);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
aloge("fatal error, VencChn[%d] %s is not found!", pVideoEncData->mMppChnInfo.mChnId, DEBUGFS_PATH_FOR_VIPP);
|
||
|
ret = -1;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case VENC_SEI_DATA_VE_BASE_INFO:
|
||
|
{
|
||
|
if (access(DEBUGFS_PATH_FOR_VE_BASE, F_OK | W_OK) == 0)
|
||
|
{
|
||
|
GetExecuteCmdResult(VENC_SEI_INFO_EXE_CMD_FOR_VE_BASE, pSeiData->pBuffer, nBufLen, &nDataLen);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
aloge("fatal error, VencChn[%d] %s is not found!", pVideoEncData->mMppChnInfo.mChnId, DEBUGFS_PATH_FOR_VE_BASE);
|
||
|
ret = -1;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case VENC_SEI_DATA_VE_ADVANCE_INFO:
|
||
|
{
|
||
|
if (access(DEBUGFS_PATH_FOR_VE_ADVANCE, F_OK | W_OK) == 0)
|
||
|
{
|
||
|
GetExecuteCmdResult(VENC_SEI_INFO_EXE_CMD_FOR_VE_ADVANCE, pSeiData->pBuffer, nBufLen, &nDataLen);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
aloge("fatal error, VencChn[%d] %s is not found!", pVideoEncData->mMppChnInfo.mChnId, DEBUGFS_PATH_FOR_VE_ADVANCE);
|
||
|
ret = -1;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
aloge("fatal error, VencChn[%d] unknown SeiDataSource %d !", pVideoEncData->mMppChnInfo.mChnId, eSeiDataSource);
|
||
|
ret = -1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (nBufLen < nDataLen)
|
||
|
{
|
||
|
aloge("fatal error, data len %d is more than buf size %d\n", nDataLen, nBufLen);
|
||
|
nDataLen = nBufLen;
|
||
|
}
|
||
|
pSeiData->nDataLen = nDataLen;
|
||
|
alogv("VencChn[%d] SeiData[%d] source %d buffer %p buflen %d datalen %d type %d", pVideoEncData->mMppChnInfo.mChnId, nSeiNum, eSeiDataSource, pSeiData->pBuffer, pSeiData->nBufLen, pSeiData->nDataLen, pSeiData->nType);
|
||
|
|
||
|
alogv("VencChn[%d] SeiData[%d] source %d buffer data:\n%s\n", pVideoEncData->mMppChnInfo.mChnId, nSeiNum, eSeiDataSource, pSeiData->pBuffer);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void FreeSeiDataBuffer(VIDEOENCDATATYPE* pVideoEncData)
|
||
|
{
|
||
|
for (int i = 0; i < VENC_SEI_DATA_NUM_MAX; i++)
|
||
|
{
|
||
|
if (pVideoEncData->mSeiData[i].pBuffer)
|
||
|
{
|
||
|
alogd("VencChn[%d] free SeiData[%d] buffer %p", pVideoEncData->mMppChnInfo.mChnId, i, pVideoEncData->mSeiData[i].pBuffer);
|
||
|
free(pVideoEncData->mSeiData[i].pBuffer);
|
||
|
pVideoEncData->mSeiData[i].pBuffer = NULL;
|
||
|
pVideoEncData->mSeiData[i].nBufLen = 0;
|
||
|
pVideoEncData->mSeiData[i].nDataLen = 0;
|
||
|
pVideoEncData->mSeiData[i].nType = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
extern int MPP_GLOBAL_VENC_SEI_CONFIG_LEVEL;
|
||
|
extern int MPP_GLOBAL_VENC_SEI_UPDATE_INTERVAL;
|
||
|
extern int MPP_GLOBAL_VENC_SEI_DATA_BUFFER_SIZE;
|
||
|
|
||
|
/**
|
||
|
environment variable:
|
||
|
/tmp/mpp_venc_sei_config_param
|
||
|
param format: level,update_interval,sei_data_buf_size
|
||
|
[level]
|
||
|
range is [0,15]
|
||
|
Independent SEI
|
||
|
0 :disable all
|
||
|
1 :isp
|
||
|
2 :vipp
|
||
|
4 :ve_base
|
||
|
8 :ve_advance
|
||
|
Combination SEI:
|
||
|
3 :isp + vipp
|
||
|
5 :isp + ve_base
|
||
|
6 :vipp + ve_base
|
||
|
7 :isp + vipp + ve_base
|
||
|
9 :isp + ve_advance
|
||
|
10:vipp + ve_advance
|
||
|
11:isp + vipp + ve_advance
|
||
|
12:ve_base + ve_advance
|
||
|
13:isp + ve_base + ve_advance
|
||
|
14:vipp + ve_base + ve_advance
|
||
|
15:isp + vipp + ve_base + ve_advance
|
||
|
[update_interval]
|
||
|
unit is ms, default is 1000ms.
|
||
|
[sei_data_buf_size]
|
||
|
range is [0,1048576], default is for every sei define.
|
||
|
*/
|
||
|
int FillSeiDataToVencLib(VIDEOENCDATATYPE* pVideoEncData)
|
||
|
{
|
||
|
unsigned char isp_flag = 0;
|
||
|
unsigned char vipp_flag = 0;
|
||
|
unsigned char ve_base_flag = 0;
|
||
|
unsigned char ve_advance_flag = 0;
|
||
|
VencSeiData *pSeiData = NULL;
|
||
|
enum VENC_SEI_DATA_SOURCE eSeiDataSource = VENC_SEI_DATA_INFO_LAST;
|
||
|
int usr_sei_config_level = MPP_GLOBAL_VENC_SEI_CONFIG_LEVEL;
|
||
|
int usr_sei_update_interval = MPP_GLOBAL_VENC_SEI_UPDATE_INTERVAL;
|
||
|
int usr_sei_data_buf_size = MPP_GLOBAL_VENC_SEI_DATA_BUFFER_SIZE;
|
||
|
unsigned int SeiUpdateInterval = 0;
|
||
|
unsigned int SeiDataBufferSize = 0;
|
||
|
unsigned int SeiNum = 0;
|
||
|
uint64_t mCurTimeMs = 0;
|
||
|
int ret = 0;
|
||
|
|
||
|
if (0 == usr_sei_config_level)
|
||
|
{
|
||
|
FreeSeiDataBuffer(pVideoEncData);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if ((NULL == pVideoEncData->pCedarV) || (0 == pVideoEncData->mbCedarvVideoEncInitFlag))
|
||
|
{
|
||
|
alogd("fatal error, VE is not ready! %p, %d", pVideoEncData->pCedarV, pVideoEncData->mbCedarvVideoEncInitFlag);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (0 == pVideoEncData->mOutputStreamCnt)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (usr_sei_config_level != pVideoEncData->mLastSeiDataConfigLevel)
|
||
|
{
|
||
|
FreeSeiDataBuffer(pVideoEncData);
|
||
|
pVideoEncData->mLastSeiDataConfigLevel = usr_sei_config_level;
|
||
|
}
|
||
|
|
||
|
if (0 < usr_sei_update_interval)
|
||
|
{
|
||
|
SeiUpdateInterval = usr_sei_update_interval;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SeiUpdateInterval = VENC_SEI_UPDATE_INTERVAL_MS_DEFAULT;
|
||
|
}
|
||
|
|
||
|
mCurTimeMs = GetSysTimeByUsec() / 1000;
|
||
|
if (0 == pVideoEncData->mLastSetSeiDataTimeMs)
|
||
|
{
|
||
|
pVideoEncData->mLastSetSeiDataTimeMs = mCurTimeMs;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pVideoEncData->mLastSetSeiDataTimeMs + SeiUpdateInterval > mCurTimeMs)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
alogv("VencChn[%d] set sei data time(ms) last %llu cur %llu", pVideoEncData->mMppChnInfo.mChnId, pVideoEncData->mLastSetSeiDataTimeMs, mCurTimeMs);
|
||
|
pVideoEncData->mLastSetSeiDataTimeMs = mCurTimeMs;
|
||
|
|
||
|
if (PT_H264 == pVideoEncData->mEncChnAttr.VeAttr.Type || PT_H265 == pVideoEncData->mEncChnAttr.VeAttr.Type)
|
||
|
{
|
||
|
alogv("VencChn[%d] usr config level: 0x%x, %d(ms), %d", pVideoEncData->mMppChnInfo.mChnId, usr_sei_config_level, usr_sei_update_interval, usr_sei_data_buf_size);
|
||
|
isp_flag = usr_sei_config_level & VENC_SEI_CONFIG_LEVEL_MASK_FOR_ISP;
|
||
|
vipp_flag = usr_sei_config_level & VENC_SEI_CONFIG_LEVEL_MASK_FOR_VIPP;
|
||
|
ve_base_flag = usr_sei_config_level & VENC_SEI_CONFIG_LEVEL_MASK_FOR_VE_BASE;
|
||
|
ve_advance_flag = usr_sei_config_level & VENC_SEI_CONFIG_LEVEL_MASK_FOR_VE_ADVANCE;
|
||
|
|
||
|
if (isp_flag)
|
||
|
{
|
||
|
SeiDataBufferSize = VENC_SEI_DATA_BUF_SIZE_FOR_ISP;
|
||
|
if (0 < usr_sei_data_buf_size)
|
||
|
{
|
||
|
SeiDataBufferSize = usr_sei_data_buf_size;
|
||
|
}
|
||
|
ret = GetSeiDataInfo(pVideoEncData, SeiNum, SeiDataBufferSize, VENC_SEI_DATA_ISP_INFO);
|
||
|
if (ret != 0)
|
||
|
{
|
||
|
aloge("fatal error! VencChn[%d] get SeiData[%d] failed! ret=%d", pVideoEncData->mMppChnInfo.mChnId, SeiNum, ret);
|
||
|
goto exit;
|
||
|
}
|
||
|
SeiNum += 1;
|
||
|
}
|
||
|
if (vipp_flag)
|
||
|
{
|
||
|
SeiDataBufferSize = VENC_SEI_DATA_BUF_SIZE_FOR_VIPP;
|
||
|
if (0 < usr_sei_data_buf_size)
|
||
|
{
|
||
|
SeiDataBufferSize = usr_sei_data_buf_size;
|
||
|
}
|
||
|
ret = GetSeiDataInfo(pVideoEncData, SeiNum, SeiDataBufferSize, VENC_SEI_DATA_VIPP_INFO);
|
||
|
if (ret != 0)
|
||
|
{
|
||
|
aloge("fatal error! VencChn[%d] get SeiData[%d] failed! ret=%d", pVideoEncData->mMppChnInfo.mChnId, SeiNum, ret);
|
||
|
goto exit;
|
||
|
}
|
||
|
SeiNum += 1;
|
||
|
}
|
||
|
if (ve_base_flag)
|
||
|
{
|
||
|
SeiDataBufferSize = VENC_SEI_DATA_BUF_SIZE_FOR_VE_BASE;
|
||
|
if (0 < usr_sei_data_buf_size)
|
||
|
{
|
||
|
SeiDataBufferSize = usr_sei_data_buf_size;
|
||
|
}
|
||
|
ret = GetSeiDataInfo(pVideoEncData, SeiNum, SeiDataBufferSize, VENC_SEI_DATA_VE_BASE_INFO);
|
||
|
if (ret != 0)
|
||
|
{
|
||
|
aloge("fatal error! VencChn[%d] get SeiData[%d] failed! ret=%d", pVideoEncData->mMppChnInfo.mChnId, SeiNum, ret);
|
||
|
goto exit;
|
||
|
}
|
||
|
SeiNum += 1;
|
||
|
}
|
||
|
if (ve_advance_flag)
|
||
|
{
|
||
|
SeiDataBufferSize = VENC_SEI_DATA_BUF_SIZE_FOR_VE_ADVANCE;
|
||
|
if (0 < usr_sei_data_buf_size)
|
||
|
{
|
||
|
SeiDataBufferSize = usr_sei_data_buf_size;
|
||
|
}
|
||
|
ret = GetSeiDataInfo(pVideoEncData, SeiNum, SeiDataBufferSize, VENC_SEI_DATA_VE_ADVANCE_INFO);
|
||
|
if (ret != 0)
|
||
|
{
|
||
|
aloge("fatal error! VencChn[%d] get SeiData[%d] failed! ret=%d", pVideoEncData->mMppChnInfo.mChnId, SeiNum, ret);
|
||
|
goto exit;
|
||
|
}
|
||
|
SeiNum += 1;
|
||
|
}
|
||
|
|
||
|
VencSeiParam stSeiParam;
|
||
|
memset(&stSeiParam, 0, sizeof(VencSeiParam));
|
||
|
stSeiParam.nSeiNum = SeiNum;
|
||
|
stSeiParam.pSeiData = &pVideoEncData->mSeiData[0];
|
||
|
alogv("VencChn[%d] set SeiNum:%d, SeiData:%p", pVideoEncData->mMppChnInfo.mChnId, stSeiParam.nSeiNum, stSeiParam.pSeiData);
|
||
|
ret = VencSetParameter(pVideoEncData->pCedarV, VENC_IndexParamSeiParam, (void*)&stSeiParam);
|
||
|
if (ret != 0)
|
||
|
{
|
||
|
aloge("fatal error! VencChn[%d] set sei param failed! ret=%d", pVideoEncData->mMppChnInfo.mChnId, ret);
|
||
|
goto exit;
|
||
|
}
|
||
|
alogv("VencChn[%d] set SeiParam success", pVideoEncData->mMppChnInfo.mChnId);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
alogw("fatal error! VencChn[%d] VeType %d does not support this api, only H264/H265 supports it.", pVideoEncData->mMppChnInfo.mChnId, pVideoEncData->mEncChnAttr.VeAttr.Type);
|
||
|
return ERR_VENC_ILLEGAL_PARAM;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
exit:
|
||
|
FreeSeiDataBuffer(pVideoEncData);
|
||
|
return -1;
|
||
|
}
|