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

481 lines
14 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 <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <sys/poll.h>
#include <time.h>
#include <unistd.h>
#include "sample_comm.h"
static FILE *venc0_file;
static RK_S32 g_s32FrameCnt = -1;
static bool quit = false;
static void sigterm_handler(int sig) {
fprintf(stderr, "signal %d\n", sig);
quit = true;
}
//大小端问题设置的ARGB 但是颜色是BGRA
// for argb8888
#define TEST_ARGB32_PIX_SIZE 4
#define TEST_ARGB32_RED 0xFF0000FF
#define TEST_ARGB32_GREEN 0x00FF00FF
#define TEST_ARGB32_BLUE 0x0000FFFF
#define TEST_ARGB32_TRANS 0x00000000
#define TEST_ARGB32_BLACK 0x000000FF
static void set_argb8888_buffer(RK_U32 *buf, RK_U32 size, RK_U32 color) {
for (RK_U32 i = 0; buf && (i < size); i++)
*(buf + i) = color;
}
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 */
}
static void *GetMediaBuffer0(void *arg) {
(void)arg;
printf("========%s========\n", __func__);
void *pData = RK_NULL;
int loopCount = 0;
int s32Ret;
VENC_STREAM_S stFrame;
stFrame.pstPack = malloc(sizeof(VENC_PACK_S));
while (!quit) {
s32Ret = RK_MPI_VENC_GetStream(0, &stFrame, -1);
if (s32Ret == RK_SUCCESS) {
if (venc0_file) {
pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk);
fwrite(pData, 1, stFrame.pstPack->u32Len, venc0_file);
fflush(venc0_file);
}
RK_U64 nowUs = TEST_COMM_GetNowUs();
RK_LOGD("chn:0, loopCount:%d enc->seq:%d wd:%d pts=%lld delay=%lldus\n",
loopCount, stFrame.u32Seq, stFrame.pstPack->u32Len,
stFrame.pstPack->u64PTS, nowUs - stFrame.pstPack->u64PTS);
s32Ret = RK_MPI_VENC_ReleaseStream(0, &stFrame);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_VENC_ReleaseStream fail %x", s32Ret);
}
loopCount++;
} else {
RK_LOGE("RK_MPI_VI_GetChnFrame fail %x", s32Ret);
}
if ((g_s32FrameCnt >= 0) && (loopCount > g_s32FrameCnt)) {
quit = true;
break;
}
usleep(10 * 1000);
}
if (venc0_file)
fclose(venc0_file);
free(stFrame.pstPack);
return NULL;
}
RK_S32 load_file_osdmem(const RK_CHAR *filename, RK_U8 *pu8Virt, RK_U32 u32Width,
RK_U32 u32Height, RK_U32 pixel_size, RK_U32 shift_value) {
RK_U32 mem_len = u32Width;
RK_U32 read_len = mem_len * pixel_size >> shift_value;
RK_U32 read_height;
FILE *file = NULL;
file = fopen(filename, "rb");
if (file == NULL) {
RK_LOGE("open filename: %s file failed!", filename);
return RK_FAILURE;
}
for (read_height = 0; read_height < u32Height; read_height++) {
fread((pu8Virt + (u32Width * read_height * pixel_size >> shift_value)), 1,
read_len, file);
}
fclose(file);
return RK_SUCCESS;
}
RK_S32 test_rgn_overlay_process() {
printf("========%s========\n", __func__);
RK_S32 s32Ret = RK_SUCCESS;
RGN_HANDLE RgnHandle = 0;
BITMAP_S stBitmap;
RGN_ATTR_S stRgnAttr;
RGN_CHN_ATTR_S stRgnChnAttr;
int u32Width = 128;
int u32Height = 128;
int s32X = 100;
int s32Y = 100;
RK_CHAR *filename = "/data/res/rgn/44";
MPP_CHN_S stMppChn;
stMppChn.enModId = RK_ID_VENC;
stMppChn.s32DevId = 0;
stMppChn.s32ChnId = 0;
/****************************************
step 1: create overlay regions
****************************************/
stRgnAttr.enType = OVERLAY_RGN;
stRgnAttr.unAttr.stOverlay.enPixelFmt = (PIXEL_FORMAT_E)RK_FMT_ARGB8888;
stRgnAttr.unAttr.stOverlay.stSize.u32Width = u32Width;
stRgnAttr.unAttr.stOverlay.stSize.u32Height = u32Height;
stRgnAttr.unAttr.stOverlay.u32ClutNum = 0;
s32Ret = RK_MPI_RGN_Create(RgnHandle, &stRgnAttr);
if (RK_SUCCESS != s32Ret) {
RK_LOGE("RK_MPI_RGN_Create (%d) failed with %#x!", RgnHandle, s32Ret);
RK_MPI_RGN_Destroy(RgnHandle);
return RK_FAILURE;
}
RK_LOGI("The handle: %d, create success!", RgnHandle);
/*********************************************
step 2: display overlay regions to groups
*********************************************/
memset(&stRgnChnAttr, 0, sizeof(stRgnChnAttr));
stRgnChnAttr.bShow = RK_TRUE;
stRgnChnAttr.enType = OVERLAY_RGN;
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.s32X = s32X;
stRgnChnAttr.unChnAttr.stOverlayChn.stPoint.s32Y = s32Y;
stRgnChnAttr.unChnAttr.stOverlayChn.u32BgAlpha = 0;
stRgnChnAttr.unChnAttr.stOverlayChn.u32FgAlpha = 0;
stRgnChnAttr.unChnAttr.stOverlayChn.u32Layer = 0;
stRgnChnAttr.unChnAttr.stOverlayChn.stQpInfo.bEnable = RK_FALSE;
stRgnChnAttr.unChnAttr.stOverlayChn.stQpInfo.bForceIntra = RK_TRUE;
stRgnChnAttr.unChnAttr.stOverlayChn.stQpInfo.bAbsQp = RK_FALSE;
stRgnChnAttr.unChnAttr.stOverlayChn.stQpInfo.s32Qp = RK_FALSE;
stRgnChnAttr.unChnAttr.stOverlayChn.u32ColorLUT[0] = 0x00;
stRgnChnAttr.unChnAttr.stOverlayChn.u32ColorLUT[1] = 0xFFFFFF;
stRgnChnAttr.unChnAttr.stOverlayChn.stInvertColor.bInvColEn = RK_FALSE;
stRgnChnAttr.unChnAttr.stOverlayChn.stInvertColor.stInvColArea.u32Width = 16;
stRgnChnAttr.unChnAttr.stOverlayChn.stInvertColor.stInvColArea.u32Height = 16;
stRgnChnAttr.unChnAttr.stOverlayChn.stInvertColor.enChgMod = LESSTHAN_LUM_THRESH;
stRgnChnAttr.unChnAttr.stOverlayChn.stInvertColor.u32LumThresh = 100;
s32Ret = RK_MPI_RGN_AttachToChn(RgnHandle, &stMppChn, &stRgnChnAttr);
if (RK_SUCCESS != s32Ret) {
RK_LOGE("RK_MPI_RGN_AttachToChn (%d) failed with %#x!", RgnHandle, s32Ret);
return RK_FAILURE;
}
RK_LOGI("Display region to chn success!");
/*********************************************
step 3: show bitmap
*********************************************/
RK_S64 s64ShowBmpStart = TEST_COMM_GetNowUs();
stBitmap.enPixelFormat = (PIXEL_FORMAT_E)RK_FMT_ARGB8888;
stBitmap.u32Width = u32Width;
stBitmap.u32Height = u32Height;
RK_U16 ColorBlockSize = stBitmap.u32Height * stBitmap.u32Width;
stBitmap.pData = malloc(ColorBlockSize * TEST_ARGB32_PIX_SIZE);
RK_U8 *ColorData = (RK_U8 *)stBitmap.pData;
if (filename) {
s32Ret = load_file_osdmem(filename, stBitmap.pData, u32Width, u32Height,
TEST_ARGB32_PIX_SIZE, 0);
if (RK_SUCCESS != s32Ret) {
set_argb8888_buffer((RK_U32 *)ColorData, ColorBlockSize / 4, TEST_ARGB32_RED);
set_argb8888_buffer((RK_U32 *)(ColorData + ColorBlockSize),
ColorBlockSize / 4, TEST_ARGB32_GREEN);
set_argb8888_buffer((RK_U32 *)(ColorData + 2 * ColorBlockSize),
ColorBlockSize / 4, TEST_ARGB32_BLUE);
set_argb8888_buffer((RK_U32 *)(ColorData + 3 * ColorBlockSize),
ColorBlockSize / 4, TEST_ARGB32_BLACK);
}
}
s32Ret = RK_MPI_RGN_SetBitMap(RgnHandle, &stBitmap);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_RGN_SetBitMap failed with %#x!", s32Ret);
return RK_FAILURE;
}
RK_S64 s64ShowBmpEnd = TEST_COMM_GetNowUs();
RK_LOGI("Handle:%d, space time %lld us, load bmp success!", RgnHandle,
s64ShowBmpEnd - s64ShowBmpStart);
//另一种刷osd的方式
#if 0
/*********************************************
step 4: use update canvas interface
*********************************************/
s64ShowBmpStart = TEST_COMM_GetNowUs();
RGN_CANVAS_INFO_S stCanvasInfo;
memset(&stCanvasInfo, 0, sizeof(RGN_CANVAS_INFO_S));
s32Ret = RK_MPI_RGN_GetCanvasInfo(RgnHandle, &stCanvasInfo);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_RGN_GetCanvasInfo failed with %#x!", s32Ret);
return RK_FAILURE;
}
memset(reinterpret_cast<void *>(stCanvasInfo.u64VirAddr), 0xff,
stCanvasInfo.u32VirWidth * stCanvasInfo.u32VirHeight >> 2);
s32Ret = RK_MPI_RGN_UpdateCanvas(RgnHandle);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_RGN_UpdateCanvas failed with %#x!", s32Ret);
return RK_FAILURE;
}
s64ShowBmpEnd = TEST_COMM_GetNowUs();
RK_LOGI("Handle:%d, space time %lld us, update canvas success!", RgnHandle, s64ShowBmpEnd - s64ShowBmpStart);
#endif
return 0;
}
static RK_S32 test_venc_init(int chnId, int width, int height, RK_CODEC_ID_E enType) {
printf("========%s========\n", __func__);
VENC_RECV_PIC_PARAM_S stRecvParam;
VENC_CHN_ATTR_S stAttr;
memset(&stAttr, 0, sizeof(VENC_CHN_ATTR_S));
stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
stAttr.stRcAttr.stH264Cbr.u32BitRate = 10 * 1024;
stAttr.stRcAttr.stH264Cbr.u32Gop = 60;
stAttr.stVencAttr.enType = enType;
stAttr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP;
stAttr.stVencAttr.u32Profile = H264E_PROFILE_HIGH;
stAttr.stVencAttr.u32PicWidth = width;
stAttr.stVencAttr.u32PicHeight = height;
stAttr.stVencAttr.u32VirWidth = width;
stAttr.stVencAttr.u32VirHeight = height;
stAttr.stVencAttr.u32StreamBufCnt = 2;
stAttr.stVencAttr.u32BufSize = width * height * 3 / 2;
stAttr.stVencAttr.enMirror = MIRROR_NONE;
RK_MPI_VENC_CreateChn(chnId, &stAttr);
// stRecvParam.s32RecvPicNum = 100; //recv 100 slice
// RK_MPI_VENC_StartRecvFrame(chnId, &stRecvParam);
memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S));
stRecvParam.s32RecvPicNum = -1;
RK_MPI_VENC_StartRecvFrame(chnId, &stRecvParam);
return 0;
}
// demo板dev默认都是0根据不同的channel 来选择不同的vi节点
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;
}
int vi_chn_init(int channelId, int width, int height) {
int ret;
int buf_cnt = 2;
// VI init
VI_CHN_ATTR_S vi_chn_attr;
memset(&vi_chn_attr, 0, sizeof(vi_chn_attr));
vi_chn_attr.stIspOpt.u32BufCount = buf_cnt;
vi_chn_attr.stIspOpt.enMemoryType =
VI_V4L2_MEMORY_TYPE_DMABUF; // VI_V4L2_MEMORY_TYPE_MMAP;
vi_chn_attr.stSize.u32Width = width;
vi_chn_attr.stSize.u32Height = height;
vi_chn_attr.enPixelFormat = RK_FMT_YUV420SP;
vi_chn_attr.enCompressMode = COMPRESS_MODE_NONE; // COMPRESS_AFBC_16x16;
vi_chn_attr.u32Depth = 2;
ret = RK_MPI_VI_SetChnAttr(0, channelId, &vi_chn_attr);
ret |= RK_MPI_VI_EnableChn(0, channelId);
if (ret) {
printf("ERROR: create VI error! ret=%d\n", ret);
return ret;
}
return ret;
}
static RK_CHAR optstr[] = "?::w:h:c:I:e:o:";
static void print_usage(const RK_CHAR *name) {
printf("usage example:\n");
printf("\t%s -I 0 -w 1920 -h 1080 -o /tmp/venc.h264\n", name);
printf("\t-w | --width: VI width, Default:1920\n");
printf("\t-h | --heght: VI height, Default:1080\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-e | --encode: encode type, Default:h264, Value:h264, h265, mjpeg\n");
printf("\t-o: output path, Default:NULL\n");
}
int main(int argc, char *argv[]) {
RK_S32 s32Ret = RK_FAILURE;
RK_U32 u32Width = 1920;
RK_U32 u32Height = 1080;
RK_CHAR *pOutPath = NULL;
RK_CODEC_ID_E enCodecType = RK_VIDEO_ID_AVC;
RK_CHAR *pCodecName = "H264";
RK_S32 s32chnlId = 0;
int c;
while ((c = getopt(argc, argv, optstr)) != -1) {
switch (c) {
case 'w':
u32Width = atoi(optarg);
break;
case 'h':
u32Height = atoi(optarg);
break;
case 'I':
s32chnlId = atoi(optarg);
break;
case 'c':
g_s32FrameCnt = atoi(optarg);
break;
case 'e':
if (!strcmp(optarg, "h264")) {
enCodecType = RK_VIDEO_ID_AVC;
pCodecName = "H264";
} else if (!strcmp(optarg, "h265")) {
enCodecType = RK_VIDEO_ID_HEVC;
pCodecName = "H265";
} else if (!strcmp(optarg, "mjpeg")) {
enCodecType = RK_VIDEO_ID_MJPEG;
pCodecName = "MJPEG";
} else {
printf("ERROR: Invalid encoder type.\n");
return 0;
}
break;
case 'o':
pOutPath = optarg;
break;
case '?':
default:
print_usage(argv[0]);
return 0;
}
}
printf("#CodecName:%s\n", pCodecName);
printf("#Resolution: %dx%d\n", u32Width, u32Height);
printf("#Output Path: %s\n", pOutPath);
printf("#CameraIdx: %d\n\n", s32chnlId);
printf("#Frame Count to save: %d\n", g_s32FrameCnt);
if (pOutPath) {
venc0_file = fopen(pOutPath, "w");
if (!venc0_file) {
printf("ERROR: open file: %s fail, exit\n", pOutPath);
return 0;
}
}
signal(SIGINT, sigterm_handler);
if (RK_MPI_SYS_Init() != RK_SUCCESS) {
RK_LOGE("rk mpi sys init fail!");
goto __FAILED;
}
vi_dev_init();
vi_chn_init(s32chnlId, u32Width, u32Height);
// venc init
test_venc_init(0, u32Width, u32Height,
enCodecType); // RK_VIDEO_ID_AVC RK_VIDEO_ID_HEVC
MPP_CHN_S stSrcChn, stDestChn;
// bind vi to venc
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32DevId = 0;
stSrcChn.s32ChnId = s32chnlId;
stDestChn.enModId = RK_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = 0;
printf("====RK_MPI_SYS_Bind vi0 to venc0====\n");
s32Ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("bind 0 ch venc failed");
goto __FAILED;
}
test_rgn_overlay_process();
pthread_t main_thread;
pthread_create(&main_thread, NULL, GetMediaBuffer0, NULL);
while (!quit) {
usleep(50000);
}
pthread_join(&main_thread, NULL);
s32Ret = RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_SYS_UnBind fail %x", s32Ret);
}
s32Ret = RK_MPI_VI_DisableChn(0, s32chnlId);
RK_LOGE("RK_MPI_VI_DisableChn %x", s32Ret);
s32Ret = RK_MPI_VENC_StopRecvFrame(0);
if (s32Ret != RK_SUCCESS) {
return s32Ret;
}
s32Ret = RK_MPI_VENC_DestroyChn(0);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_VDEC_DestroyChn fail %x", s32Ret);
}
s32Ret = RK_MPI_VI_DisableDev(0);
RK_LOGE("RK_MPI_VI_DisableDev %x", s32Ret);
__FAILED:
RK_LOGE("test running exit:%d", s32Ret);
RK_MPI_SYS_Exit();
return 0;
}