luckfox-pico-sdk/media/samples/simple_test/simple_vi_get_frame_rkaiq.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

427 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 <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/poll.h>
#include <time.h>
#include <unistd.h>
#ifdef RV1126_RV1109
#include <rk_aiq_user_api_camgroup.h>
#include <rk_aiq_user_api_imgproc.h>
#include <rk_aiq_user_api_sysctl.h>
#else
#include <rk_aiq_user_api2_camgroup.h>
#include <rk_aiq_user_api2_imgproc.h>
#include <rk_aiq_user_api2_sysctl.h>
#endif
#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 RK_S32 g_s32FrameCnt = -1;
static bool quit = false;
#define MAX_AIQ_CTX 8
static rk_aiq_sys_ctx_t *g_aiq_ctx[MAX_AIQ_CTX];
rk_aiq_working_mode_t g_WDRMode[MAX_AIQ_CTX];
#include <stdatomic.h>
static atomic_int g_sof_cnt = 0;
static atomic_bool g_should_quit = false;
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 */
}
static void *GetMediaBuffer0(void *arg) {
printf("========%s========\n", __func__);
int loopCount = 0;
int s32Ret;
RK_S32 waitTime = 1000;
int pipeId = 0;
int channelId = 0;
channelId = *(int *)arg;
VIDEO_FRAME_INFO_S stViFrame;
VI_CHN_STATUS_S stChnStatus;
while (!quit) {
s32Ret = RK_MPI_VI_GetChnFrame(pipeId, channelId, &stViFrame, waitTime);
if (s32Ret == RK_SUCCESS) {
RK_U64 nowUs = TEST_COMM_GetNowUs();
void *data = RK_MPI_MB_Handle2VirAddr(stViFrame.stVFrame.pMbBlk);
RK_LOGD(
"RK_MPI_VI_GetChnFrame ok:data %p loop:%d seq:%d pts:%lld ms len=%llu",
data, loopCount, stViFrame.stVFrame.u32TimeRef,
stViFrame.stVFrame.u64PTS / 1000, stViFrame.stVFrame.u64PrivateData);
// 6.get the channel status
s32Ret = RK_MPI_VI_QueryChnStatus(pipeId, channelId, &stChnStatus);
RK_LOGD("RK_MPI_VI_QueryChnStatus ret %x, w:%d,h:%d,enable:%d,"
"current frame id:%d,input lost:%d,output lost:%d,"
"framerate:%d,vbfail:%d delay=%lldus",
s32Ret, stChnStatus.stSize.u32Width, stChnStatus.stSize.u32Height,
stChnStatus.bEnable, stChnStatus.u32CurFrameID,
stChnStatus.u32InputLostFrame, stChnStatus.u32OutputLostFrame,
stChnStatus.u32FrameRate, stChnStatus.u32VbFail,
nowUs - stViFrame.stVFrame.u64PTS);
// 7.release the frame
s32Ret = RK_MPI_VI_ReleaseChnFrame(pipeId, channelId, &stViFrame);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_VI_ReleaseChnFrame fail %x", s32Ret);
}
loopCount++;
} else {
RK_LOGE("RK_MPI_VI_GetChnFrame timeout %x", s32Ret);
}
if ((g_s32FrameCnt >= 0) && (loopCount > g_s32FrameCnt)) {
quit = true;
break;
}
}
return NULL;
}
// 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 = 2; //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 XCamReturn SIMPLE_COMM_ISP_SofCb(rk_aiq_metas_t *meta) {
g_sof_cnt++;
if (g_sof_cnt <= 2)
printf("=== %u ===\n", meta->frame_id);
return XCAM_RETURN_NO_ERROR;
}
static XCamReturn SIMPLE_COMM_ISP_ErrCb(rk_aiq_err_msg_t *msg) {
if (msg->err_code == XCAM_RETURN_BYPASS)
g_should_quit = true;
return XCAM_RETURN_NO_ERROR;
}
RK_S32 SIMPLE_COMM_ISP_Init(RK_S32 CamId, rk_aiq_working_mode_t WDRMode, RK_BOOL MultiCam,
const char *iq_file_dir) {
if (CamId >= MAX_AIQ_CTX) {
printf("%s : CamId is over 3\n", __FUNCTION__);
return -1;
}
// char *iq_file_dir = "iqfiles/";
setlinebuf(stdout);
if (iq_file_dir == NULL) {
printf("SIMPLE_COMM_ISP_Init : not start.\n");
g_aiq_ctx[CamId] = NULL;
return 0;
}
// must set HDR_MODE, before init
g_WDRMode[CamId] = WDRMode;
char hdr_str[16];
snprintf(hdr_str, sizeof(hdr_str), "%d", (int)WDRMode);
setenv("HDR_MODE", hdr_str, 1);
rk_aiq_sys_ctx_t *aiq_ctx;
rk_aiq_static_info_t aiq_static_info;
#ifdef RV1126_RV1109
rk_aiq_uapi_sysctl_enumStaticMetas(CamId, &aiq_static_info);
printf("ID: %d, sensor_name is %s, iqfiles is %s\n", CamId,
aiq_static_info.sensor_info.sensor_name, iq_file_dir);
aiq_ctx =
rk_aiq_uapi_sysctl_init(aiq_static_info.sensor_info.sensor_name, iq_file_dir,
SIMPLE_COMM_ISP_ErrCb, SIMPLE_COMM_ISP_SofCb);
if (MultiCam)
rk_aiq_uapi_sysctl_setMulCamConc(aiq_ctx, true);
#else
rk_aiq_uapi2_sysctl_enumStaticMetas(CamId, &aiq_static_info);
printf("ID: %d, sensor_name is %s, iqfiles is %s\n", CamId,
aiq_static_info.sensor_info.sensor_name, iq_file_dir);
aiq_ctx =
rk_aiq_uapi2_sysctl_init(aiq_static_info.sensor_info.sensor_name, iq_file_dir,
SIMPLE_COMM_ISP_ErrCb, SIMPLE_COMM_ISP_SofCb);
if (MultiCam)
rk_aiq_uapi2_sysctl_setMulCamConc(aiq_ctx, true);
#endif
g_aiq_ctx[CamId] = aiq_ctx;
return 0;
}
RK_S32 SIMPLE_COMM_ISP_Run(RK_S32 CamId) {
if (CamId >= MAX_AIQ_CTX || !g_aiq_ctx[CamId]) {
printf("%s : CamId is over 3 or not init\n", __FUNCTION__);
return -1;
}
#ifdef RV1126_RV1109
if (rk_aiq_uapi_sysctl_prepare(g_aiq_ctx[CamId], 0, 0, g_WDRMode[CamId])) {
printf("rkaiq engine prepare failed !\n");
g_aiq_ctx[CamId] = NULL;
return -1;
}
printf("rk_aiq_uapi_sysctl_init/prepare succeed\n");
if (rk_aiq_uapi_sysctl_start(g_aiq_ctx[CamId])) {
printf("rk_aiq_uapi_sysctl_start failed\n");
return -1;
}
printf("rk_aiq_uapi_sysctl_start succeed\n");
#else
if (rk_aiq_uapi2_sysctl_prepare(g_aiq_ctx[CamId], 0, 0, g_WDRMode[CamId])) {
printf("rkaiq engine prepare failed !\n");
g_aiq_ctx[CamId] = NULL;
return -1;
}
printf("rk_aiq_uapi2_sysctl_init/prepare succeed\n");
if (rk_aiq_uapi2_sysctl_start(g_aiq_ctx[CamId])) {
printf("rk_aiq_uapi2_sysctl_start failed\n");
return -1;
}
printf("rk_aiq_uapi2_sysctl_start succeed\n");
#endif
return 0;
}
RK_S32 SIMPLE_COMM_ISP_Stop(RK_S32 CamId) {
if (CamId >= MAX_AIQ_CTX || !g_aiq_ctx[CamId]) {
printf("%s : CamId is over 3 or not init g_aiq_ctx[%d] = %p\n", __FUNCTION__,
CamId, g_aiq_ctx[CamId]);
return -1;
}
#ifdef RV1126_RV1109
printf("rk_aiq_uapi_sysctl_stop enter\n");
rk_aiq_uapi_sysctl_stop(g_aiq_ctx[CamId], false);
printf("rk_aiq_uapi_sysctl_deinit enter\n");
rk_aiq_uapi_sysctl_deinit(g_aiq_ctx[CamId]);
printf("rk_aiq_uapi_sysctl_deinit exit\n");
#else
printf("rk_aiq_uapi2_sysctl_stop enter\n");
rk_aiq_uapi2_sysctl_stop(g_aiq_ctx[CamId], false);
printf("rk_aiq_uapi2_sysctl_deinit enter\n");
rk_aiq_uapi2_sysctl_deinit(g_aiq_ctx[CamId]);
printf("rk_aiq_uapi2_sysctl_deinit exit\n");
#endif
g_aiq_ctx[CamId] = NULL;
return 0;
}
static RK_CHAR optstr[] = "?::a::w:h:c:I:o:m:d:";
static void print_usage(const RK_CHAR *name) {
printf("usage example:\n");
printf("\t%s -I 0 -w 1920 -h 1080 -o 1\n", name);
printf("\t-a | --aiq: iq file path, Default:/etc/iqfiles\n");
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-d | --hdr_mode: Default:0, 0:normal,1:hdr2\n");
printf("\t-m | --multiple sensor: Default:0 \n");
printf("\t-o: output path, Default:0 0 or 1 /data/test_0.yuv\n");
}
int main(int argc, char *argv[]) {
RK_S32 s32Ret = RK_FAILURE;
RK_U32 u32Width = 1920;
RK_U32 u32Height = 1080;
int savefile = 0;
RK_S32 s32chnlId = 0;
int c;
int ret = -1;
char *iq_dir = NULL;
VI_SAVE_FILE_INFO_S stDebugFile;
#ifdef RKAIQ
int hdr = 0;
int multi_sensor = RK_FALSE;
#endif
while ((c = getopt(argc, argv, optstr)) != -1) {
switch (c) {
case 'a':
if (optarg)
iq_dir = optarg;
else
iq_dir = "/etc/iqfiles";
break;
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 'o':
savefile = atoi(optarg);
break;
#ifdef RKAIQ
case 'd':
hdr = atoi(optarg);
break;
case 'm':
multi_sensor = atoi(optarg);
break;
#endif
case '?':
default:
print_usage(argv[0]);
return -1;
}
}
if (iq_dir) {
#ifdef RKAIQ
printf("#####Aiq xml dirpath: %s\n\n", iq_dir);
rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
if (hdr == 1)
hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR2;
SIMPLE_COMM_ISP_Init(0, hdr_mode, multi_sensor, iq_dir);
SIMPLE_COMM_ISP_Run(0);
#endif
}
printf("#Resolution: %dx%d\n", u32Width, u32Height);
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) {
RK_LOGE("rk mpi sys init fail!");
goto __FAILED;
}
vi_dev_init();
vi_chn_init(s32chnlId, u32Width, u32Height);
stDebugFile.bCfg = (RK_BOOL)savefile;
// memcpy(stDebugFile.aFilePath, "/userdata/", strlen("/data"));
strcpy(stDebugFile.aFilePath, "/userdata/");
snprintf(stDebugFile.aFileName, sizeof(stDebugFile.aFileName), "test_%d.yuv",
s32chnlId);
RK_MPI_VI_ChnSaveFile(0, s32chnlId, &stDebugFile);
pthread_t main_thread;
pthread_create(&main_thread, NULL, GetMediaBuffer0, &s32chnlId);
while (!quit) {
usleep(50000);
}
pthread_join(main_thread, NULL);
s32Ret = RK_MPI_VI_DisableChn(0, s32chnlId);
RK_LOGE("RK_MPI_VI_DisableChn %x", s32Ret);
s32Ret = RK_MPI_VI_DisableDev(0);
RK_LOGE("RK_MPI_VI_DisableDev %x", s32Ret);
#ifdef RKAIQ
SIMPLE_COMM_ISP_Stop(0);
#endif
ret = 0;
__FAILED:
RK_LOGE("test running exit:%d", s32Ret);
RK_MPI_SYS_Exit();
return ret;
}