luckfox-pico-sdk/media/samples/simple_test/simple_vi_bind_venc_osd.c
luckfox-eng29 8f34c2760d project:build.sh: Added fastboot support; custom modifications to U-Boot and kernel implemented using patches.
project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between
the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door
for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more
usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp:
Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for
compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem.
sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device
tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately.
sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick
boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades.
sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for
fastboot.

Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
2024-10-14 09:47:04 +08:00

513 lines
15 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 <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <time.h>
#include <unistd.h>
#include "rk_debug.h"
#include "rk_defines.h"
#include "rk_mpi_adec.h"
#include "rk_mpi_aenc.h"
#include "rk_mpi_ai.h"
#include "rk_mpi_ao.h"
#include "rk_mpi_avs.h"
#include "rk_mpi_cal.h"
#include "rk_mpi_ivs.h"
#include "rk_mpi_mb.h"
#include "rk_mpi_rgn.h"
#include "rk_mpi_sys.h"
#include "rk_mpi_tde.h"
#include "rk_mpi_vdec.h"
#include "rk_mpi_venc.h"
#include "rk_mpi_vi.h"
#include "rk_mpi_vo.h"
#include "rk_mpi_vpss.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));
if (enType == RK_VIDEO_ID_AVC) {
stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
stAttr.stRcAttr.stH264Cbr.u32BitRate = 10 * 1024;
stAttr.stRcAttr.stH264Cbr.u32Gop = 60;
} else if (enType == RK_VIDEO_ID_HEVC) {
stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H265CBR;
stAttr.stRcAttr.stH265Cbr.u32BitRate = 10 * 1024;
stAttr.stRcAttr.stH265Cbr.u32Gop = 60;
} else if (enType == RK_VIDEO_ID_MJPEG) {
stAttr.stRcAttr.enRcMode = VENC_RC_MODE_MJPEGCBR;
stAttr.stRcAttr.stMjpegCbr.u32BitRate = 10 * 1024;
}
stAttr.stVencAttr.enType = enType;
stAttr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP;
if (enType == RK_VIDEO_ID_AVC)
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 = 1;
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 = 0; //0, get fail, 1 - u32BufCount, can get, if bind to other device, must be < u32BufCount
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;
int ret = -1;
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 -1;
}
break;
case 'o':
pOutPath = optarg;
break;
case '?':
default:
print_usage(argv[0]);
return -1;
}
}
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);
ret = 0;
__FAILED:
RK_LOGE("test running exit:%d", s32Ret);
RK_MPI_SYS_Exit();
return ret;
}