#include #include #include #include #include #include #include #include #include #include #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(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; }