luckfox-pico-sdk/media/samples/simple_test/simple_vi_venc_wrap.c
2023-08-08 20:36:47 +08:00

414 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <sys/poll.h>
#include <time.h>
#include <unistd.h>
#include "sample_comm.h"
#define RK_MAX(a, b) ((a) > (b) ? (a) : (b))
#define RK_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
typedef struct _rkTestVencCfg {
RK_BOOL bOutDebugCfg;
VENC_CHN_ATTR_S stAttr;
RK_CHAR dstFilePath[128];
RK_CHAR dstFileName[128];
RK_S32 s32ChnId;
FILE *fp;
RK_S32 selectFd;
} TEST_VENC_CFG;
static RK_S32 g_s32FrameCnt = -1;
static bool quit = false;
static RK_U32 g_u32MaxWidth;
static RK_U32 g_u32MaxHeight;
static RK_BOOL g_u8SaveCfg;
static VI_CHN_ATTR_S g_vi_chn_attr;
static RK_BOOL g_bWrapEn;
static RK_U32 g_u32WrapLine;
static VI_CHN_BUF_WRAP_S g_stViWrap;
static RK_U32 g_u32DstCodec;
static RK_U32 g_u32DeBreath;
static TEST_VENC_CFG g_venc_cfgs[2];
static VENC_STREAM_S g_venc_stFrame[2];
static void sigterm_handler(int sig) {
fprintf(stderr, "signal %d\n", sig);
quit = true;
}
RK_U64 TEST_COMM_GetNowUs() {
struct timespec time = {0, 0};
clock_gettime(CLOCK_MONOTONIC, &time);
return (RK_U64)time.tv_sec * 1000000 + (RK_U64)time.tv_nsec / 1000; /* microseconds */
}
// demo板dev默认都是0根据不同的channel 来选择不同的vi节点
static int vi_dev_init() {
printf("%s\n", __func__);
int ret = 0;
int devId = 0;
int pipeId = devId;
VI_DEV_ATTR_S stDevAttr;
VI_DEV_BIND_PIPE_S stBindPipe;
memset(&stDevAttr, 0, sizeof(stDevAttr));
memset(&stBindPipe, 0, sizeof(stBindPipe));
// 0. get dev config status
ret = RK_MPI_VI_GetDevAttr(devId, &stDevAttr);
if (ret == RK_ERR_VI_NOT_CONFIG) {
// 0-1.config dev
ret = RK_MPI_VI_SetDevAttr(devId, &stDevAttr);
if (ret != RK_SUCCESS) {
printf("RK_MPI_VI_SetDevAttr %x\n", ret);
return -1;
}
} else {
printf("RK_MPI_VI_SetDevAttr already\n");
}
// 1.get dev enable status
ret = RK_MPI_VI_GetDevIsEnable(devId);
if (ret != RK_SUCCESS) {
// 1-2.enable dev
ret = RK_MPI_VI_EnableDev(devId);
if (ret != RK_SUCCESS) {
printf("RK_MPI_VI_EnableDev %x\n", ret);
return -1;
}
// 1-3.bind dev/pipe
stBindPipe.u32Num = pipeId;
stBindPipe.PipeId[0] = pipeId;
ret = RK_MPI_VI_SetDevBindPipe(devId, &stBindPipe);
if (ret != RK_SUCCESS) {
printf("RK_MPI_VI_SetDevBindPipe %x\n", ret);
return -1;
}
} else {
printf("RK_MPI_VI_EnableDev already\n");
}
return 0;
}
static int vi_chn_init(int channelId, int width, int height, int maxWidth,
int maxHeight) {
int ret;
int buf_cnt = 3;
// VI init
memset(&g_vi_chn_attr, 0, sizeof(g_vi_chn_attr));
g_vi_chn_attr.stIspOpt.u32BufCount = buf_cnt;
g_vi_chn_attr.stIspOpt.enMemoryType =
VI_V4L2_MEMORY_TYPE_DMABUF; // VI_V4L2_MEMORY_TYPE_MMAP;
g_vi_chn_attr.stSize.u32Width = width;
g_vi_chn_attr.stSize.u32Height = height;
g_vi_chn_attr.enPixelFormat = RK_FMT_YUV420SP;
g_vi_chn_attr.stIspOpt.stMaxSize.u32Width = RK_MAX(maxWidth, width);
g_vi_chn_attr.stIspOpt.stMaxSize.u32Height = RK_MAX(maxHeight, height);
g_vi_chn_attr.u32Depth = 1;
ret = RK_MPI_VI_SetChnAttr(0, channelId, &g_vi_chn_attr);
if (ret) {
printf("ERROR: VI set channel attribute fail, ret=%d\n", ret);
return ret;
}
// set wrap mode attr
memset(&g_stViWrap, 0, sizeof(VI_CHN_BUF_WRAP_S));
if (g_bWrapEn) {
if (g_u32WrapLine < 128 || g_u32WrapLine > height) {
printf("wrap mode buffer line must between [128, H]");
return -1;
}
g_stViWrap.bEnable = RK_TRUE;
g_stViWrap.u32BufLine = g_u32WrapLine;
g_stViWrap.u32WrapBufferSize =
g_stViWrap.u32BufLine * width * 3 / 2; // nv12 (w * wrapLine *3 / 2)
printf("set channel wrap line: %d, wrapBuffSize = %d", g_u32WrapLine,
g_stViWrap.u32WrapBufferSize);
RK_MPI_VI_SetChnWrapBufAttr(0, channelId, &g_stViWrap);
}
ret |= RK_MPI_VI_EnableChn(0, channelId);
if (ret) {
printf("ERROR: create VI error! ret=%d\n", ret);
return ret;
}
return ret;
}
static void init_venc_cfg(RK_U32 u32Ch, RK_CODEC_ID_E enType) {
RK_BOOL bSvc = RK_FALSE;
RK_S32 vencChId = 0;
RK_U32 u32GopSize = 60;
RK_U32 u32BitRateKb = 10 * 1024;
g_venc_cfgs[u32Ch].stAttr.stVencAttr.enType = enType;
g_venc_cfgs[u32Ch].s32ChnId = vencChId + u32Ch;
g_venc_cfgs[u32Ch].stAttr.stVencAttr.enPixelFormat = g_vi_chn_attr.enPixelFormat;
g_venc_cfgs[u32Ch].stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
g_venc_cfgs[u32Ch].stAttr.stRcAttr.stH264Cbr.u32BitRate = u32BitRateKb;
g_venc_cfgs[u32Ch].stAttr.stRcAttr.stH264Cbr.u32Gop = u32GopSize;
g_venc_cfgs[u32Ch].stAttr.stVencAttr.u32MaxPicWidth = g_u32MaxWidth;
g_venc_cfgs[u32Ch].stAttr.stVencAttr.u32MaxPicHeight = g_u32MaxHeight;
g_venc_cfgs[u32Ch].stAttr.stVencAttr.u32PicWidth = g_vi_chn_attr.stSize.u32Width;
g_venc_cfgs[u32Ch].stAttr.stVencAttr.u32PicHeight = g_vi_chn_attr.stSize.u32Height;
g_venc_cfgs[u32Ch].stAttr.stVencAttr.u32VirWidth = g_vi_chn_attr.stSize.u32Width;
g_venc_cfgs[u32Ch].stAttr.stVencAttr.u32VirHeight = g_vi_chn_attr.stSize.u32Height;
g_venc_cfgs[u32Ch].stAttr.stVencAttr.u32StreamBufCnt = 5;
g_venc_cfgs[u32Ch].stAttr.stVencAttr.u32BufSize =
g_u32MaxWidth * g_u32MaxHeight * 3 / 2;
g_venc_cfgs[u32Ch].stAttr.stGopAttr.u32MaxLtrCount = 1;
}
static RK_S32 create_venc(RK_U32 u32Ch) {
RK_BOOL bRefBufShare = RK_FALSE;
VENC_RECV_PIC_PARAM_S stRecvParam;
VENC_CHN_BUF_WRAP_S stVencChnBufWrap;
VENC_CHN_REF_BUF_SHARE_S stVencChnRefBufShare;
memset(&stVencChnBufWrap, 0, sizeof(stVencChnBufWrap));
stVencChnBufWrap.bEnable = g_stViWrap.bEnable;
memset(&stVencChnRefBufShare, 0, sizeof(VENC_CHN_REF_BUF_SHARE_S));
stVencChnRefBufShare.bEnable = bRefBufShare;
stRecvParam.s32RecvPicNum = g_s32FrameCnt;
RK_MPI_VENC_CreateChn(g_venc_cfgs[u32Ch].s32ChnId, &g_venc_cfgs[u32Ch].stAttr);
RK_MPI_VENC_SetChnBufWrapAttr(g_venc_cfgs[u32Ch].s32ChnId, &stVencChnBufWrap);
RK_MPI_VENC_SetChnRefBufShareAttr(g_venc_cfgs[u32Ch].s32ChnId, &stVencChnRefBufShare);
if (g_u32DeBreath > 0) {
VENC_DEBREATHEFFECT_S stDeBreathEffect;
memset(&stDeBreathEffect, 0, sizeof(stDeBreathEffect));
stDeBreathEffect.bEnable = RK_TRUE;
stDeBreathEffect.s32Strength1 = g_u32DeBreath;
RK_MPI_VENC_SetDeBreathEffect(u32Ch, &stDeBreathEffect);
}
RK_MPI_VENC_StartRecvFrame(g_venc_cfgs[u32Ch].s32ChnId, &stRecvParam);
return RK_SUCCESS;
}
static void *vi_venc_wrap(void *arg) {
RK_S32 s32Ret;
RK_S32 loopCount = 0;
void *pData = RK_NULL;
(void)arg;
VI_CHN_STATUS_S stChnStatus;
printf("========%s========\n", __func__);
while (!quit) {
s32Ret = RK_MPI_VENC_GetStream(g_venc_cfgs[0].s32ChnId, &g_venc_stFrame[0], -1);
if (s32Ret == RK_SUCCESS) {
if (g_venc_cfgs[0].bOutDebugCfg) {
pData = RK_MPI_MB_Handle2VirAddr(g_venc_stFrame[0].pstPack->pMbBlk);
fwrite(pData, 1, g_venc_stFrame[0].pstPack->u32Len, g_venc_cfgs[0].fp);
fflush(g_venc_cfgs[0].fp);
}
RK_U64 nowUs = TEST_COMM_GetNowUs();
printf("chn:0, loopCount:%d enc->seq:%d wd:%d pts=%lld delay=%lldus\n",
loopCount, g_venc_stFrame[0].u32Seq, g_venc_stFrame[0].pstPack->u32Len,
g_venc_stFrame[0].pstPack->u64PTS,
nowUs - g_venc_stFrame[0].pstPack->u64PTS);
s32Ret =
RK_MPI_VENC_ReleaseStream(g_venc_cfgs[0].s32ChnId, &g_venc_stFrame[0]);
if (s32Ret != RK_SUCCESS) {
printf("RK_MPI_VENC_ReleaseStream fail %x", s32Ret);
}
loopCount++;
} else {
printf("RK_MPI_VI_GetChnFrame fail %x", s32Ret);
}
if ((g_s32FrameCnt >= 0) && (loopCount > g_s32FrameCnt)) {
quit = true;
break;
}
usleep(1 * 1000);
}
}
static RK_CHAR optstr[] = "?::d:n:w:h:W:H:c:I:o:";
static void print_usage(const RK_CHAR *name) {
printf("usage example:\n");
printf("\t%s -I 0 -w 1920 -h 1080 -W 2560 -H 1440 -o 1\n", name);
printf("\t-w | --width: VI width, Default:2560\n");
printf("\t-h | --height: VI height, Default:1440\n");
printf("\t-W | --maxWidth: sensor output resolution max width, Default:2560\n");
printf("\t-H | --maxHeight: sensor output resolution max height, Default:1440\n");
printf("\t-c | --frame_cnt: frame number of output, Default:-1\n");
printf("\t-I | --camid: camera ctx id, Default 0. "
"0:rkisp_mainpath,1:rkisp_selfpath,2:rkisp_bypasspath\n");
printf("\t-o: output path, Default:0 0 or 1 /data/test_0.yuv\n");
}
static const struct option long_options[] = {
{"aiq", optional_argument, NULL, 'a'},
{"pixel_format", optional_argument, NULL, 'f'},
{"device_name", required_argument, NULL, 'd'},
{"camera_num", required_argument, NULL, 'n'},
{"width", required_argument, NULL, 'w'},
{"height", required_argument, NULL, 'h'},
{"maxWidth", required_argument, NULL, 'W'},
{"maxHeight", required_argument, NULL, 'H'},
{"wrap", required_argument, NULL, 'r'},
{"wrap_line", required_argument, NULL, 'L'},
{"codec", required_argument, NULL, 'C'},
{"de_breath", required_argument, NULL, 'D'}, // debreath[0, 35] default(0)
{"loop_count", required_argument, NULL, 'l'},
{"output_path", required_argument, NULL, 'o'},
{"camid", required_argument, NULL, 'I'},
{"help", optional_argument, NULL, '?'},
{NULL, 0, NULL, 0},
};
int main(int argc, char *argv[]) {
RK_S32 s32Ret = RK_FAILURE;
RK_U32 u32Width = 1920;
RK_U32 u32Height = 1080;
RK_U32 u32MaxWidth = 2560;
RK_U32 u32MaxHeight = 1440;
int savefile = 0;
RK_S32 s32DevId = 0;
RK_S32 s32chnlId = 0;
RK_U32 u32DeBreath = 0;
int c;
VI_SAVE_FILE_INFO_S stDebugFile;
RK_U32 u32DstCodec = RK_VIDEO_ID_HEVC;
g_bWrapEn = RK_TRUE;
while ((c = getopt_long(argc, argv, optstr, long_options, NULL)) != -1) {
switch (c) {
case 'w':
u32Width = atoi(optarg);
break;
case 'h':
u32Height = atoi(optarg);
break;
case 'W':
u32MaxWidth = atoi(optarg);
break;
case 'H':
u32MaxHeight = atoi(optarg);
break;
case 'I':
s32chnlId = atoi(optarg);
break;
case 'C': // codec
u32DstCodec = atoi(optarg);
break;
case 'D': // de_breath
u32DeBreath = atoi(optarg);
break;
case 'l':
g_s32FrameCnt = atoi(optarg);
break;
case 'o':
savefile = atoi(optarg);
break;
case 'r': // wrap
g_bWrapEn = (RK_BOOL)atoi(optarg);
break;
case 'L': // wrap line
g_u32WrapLine = atoi(optarg);
break;
case '?':
default:
print_usage(argv[0]);
return 0;
}
}
printf("#Resolution: %dx%d\n", u32Width, u32Height);
printf("#Sensor Max Resolution: %dx%d\n", g_u32MaxWidth, g_u32MaxHeight);
printf("#Output Path: %d\n", savefile);
printf("#CameraIdx: %d\n\n", s32chnlId);
printf("#Frame Count to save: %d\n", g_s32FrameCnt);
signal(SIGINT, sigterm_handler);
if (RK_MPI_SYS_Init() != RK_SUCCESS) {
printf("rk mpi sys init fail!");
goto __FAILED;
}
g_u32MaxWidth = u32MaxWidth;
g_u32MaxHeight = u32MaxHeight;
g_u32DstCodec = u32DstCodec;
g_u32DeBreath = u32DeBreath;
vi_dev_init();
vi_chn_init(s32chnlId, u32Width, u32Height, u32MaxWidth, u32MaxHeight);
stDebugFile.bCfg = (RK_BOOL)savefile;
g_u8SaveCfg = stDebugFile.bCfg;
g_venc_cfgs[0].bOutDebugCfg = g_u8SaveCfg;
// memcpy(stDebugFile.aFilePath, "/userdata/", strlen("/data"));
strcpy(stDebugFile.aFilePath, "/userdata/");
snprintf(stDebugFile.aFileName, sizeof(stDebugFile.aFileName), "venc_wrap_%d.bin",
s32chnlId);
RK_MPI_VI_ChnSaveFile(0, 0, &stDebugFile);
MPP_CHN_S stSrcChn;
MPP_CHN_S stDestChn[2];
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32DevId = s32DevId;
stSrcChn.s32ChnId = s32chnlId;
// venc init and create
init_venc_cfg(0, (RK_CODEC_ID_E)u32DstCodec);
s32Ret = create_venc(0);
if (s32Ret != RK_SUCCESS) {
printf("create %d ch venc failed", g_venc_cfgs[0].s32ChnId);
return s32Ret;
}
// bind vi to venc
stDestChn[0].enModId = RK_ID_VENC;
stDestChn[0].s32DevId = 0;
stDestChn[0].s32ChnId = g_venc_cfgs[0].s32ChnId;
s32Ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn[0]);
if (s32Ret != RK_SUCCESS) {
printf("bind %d ch venc failed", g_venc_cfgs[0].s32ChnId);
goto __FAILED;
}
g_venc_stFrame[0].pstPack = (VENC_PACK_S *)(malloc(sizeof(VENC_PACK_S)));
pthread_t main_thread;
pthread_create(&main_thread, NULL, vi_venc_wrap, NULL);
while (!quit) {
usleep(50000);
}
pthread_join(&main_thread, NULL);
s32Ret = RK_MPI_VI_DisableChn(0, 0);
printf("RK_MPI_VI_DisableChn %x", s32Ret);
s32Ret = RK_MPI_VI_DisableDev(0);
printf("RK_MPI_VI_DisableDev %x", s32Ret);
__FAILED:
printf("test running exit:%d", s32Ret);
RK_MPI_SYS_Exit();
return 0;
}