/* * Copyright (C) 2020 Rockchip Electronics Co., Ltd. * author: Zhihua Wang, hogan.wang@rock-chips.com * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL), available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "uvc_control.h" #include "uvc_video.h" #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" struct camera_param { int width; int height; int fcc; int fps; }; static struct camera_param g_param; static pthread_t g_th; static bool g_run; 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节点 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 depth) { int ret; int buf_cnt = 4; // 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 = depth; //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_S32 test_venc_init(int chnId, int width, int height, RK_CODEC_ID_E enType) { VENC_RECV_PIC_PARAM_S stRecvParam; VENC_CHN_ATTR_S stAttr; memset(&stAttr, 0, sizeof(VENC_CHN_ATTR_S)); stAttr.stVencAttr.enType = enType; stAttr.stVencAttr.enPixelFormat = RK_FMT_YUV420SP; stAttr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR; stAttr.stRcAttr.stH264Cbr.u32BitRate = 10 * 1024; stAttr.stRcAttr.stH264Cbr.u32Gop = 60; 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; RK_MPI_VENC_CreateChn(chnId, &stAttr); memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S)); stRecvParam.s32RecvPicNum = -1; RK_MPI_VENC_StartRecvFrame(chnId, &stRecvParam); return 0; } static RK_S32 test_venc_exit(int chnId) { RK_S32 s32Ret; s32Ret = RK_MPI_VENC_StopRecvFrame(chnId); if (s32Ret != RK_SUCCESS) { RK_LOGE("RK_MPI_VENC_StopRecvFrame fail %x", s32Ret); return s32Ret; } s32Ret = RK_MPI_VENC_DestroyChn(chnId); if (s32Ret != RK_SUCCESS) { RK_LOGE("RK_MPI_VDEC_DestroyChn fail %x", s32Ret); return s32Ret; } return s32Ret; } int rockit_uvc(int width, int height, int fcc, int fps) { int s32Ret; int pipeId = 0; int channelId = 0; if (!g_run) return -1; printf("%s enter\n", __func__); vi_dev_init(); vi_chn_init(channelId, width, height, fcc == V4L2_PIX_FMT_YUYV ? 2 : 0); if (fcc == V4L2_PIX_FMT_YUYV) { VIDEO_FRAME_INFO_S stViFrame; RK_S32 waitTime = 1000; do { s32Ret = RK_MPI_VI_GetChnFrame(pipeId, channelId, &stViFrame, waitTime); if (s32Ret == RK_SUCCESS) { void *data = RK_MPI_MB_Handle2VirAddr(stViFrame.stVFrame.pMbBlk); int s32Fd = RK_MPI_MB_Handle2Fd(stViFrame.stVFrame.pMbBlk); RK_MPI_SYS_MmzFlushCache(stViFrame.stVFrame.pMbBlk, RK_TRUE); uvc_read_camera_buffer(data, s32Fd, width * height * 3 / 2, NULL, 0); s32Ret = RK_MPI_VI_ReleaseChnFrame(pipeId, channelId, &stViFrame); if (s32Ret != RK_SUCCESS) { RK_LOGE("RK_MPI_VI_ReleaseChnFrame fail %x", s32Ret); } } else { RK_LOGE("RK_MPI_VI_GetChnFrame timeout %x", s32Ret); } } while (g_run); } else if (fcc == V4L2_PIX_FMT_MJPEG || fcc == V4L2_PIX_FMT_H264) { RK_CODEC_ID_E enType; if (fcc == V4L2_PIX_FMT_MJPEG) enType = RK_VIDEO_ID_JPEG; else if (fcc == V4L2_PIX_FMT_H264) enType = RK_VIDEO_ID_AVC; test_venc_init(0, width, height, enType); MPP_CHN_S stSrcChn, stDestChn; // bind vi to venc stSrcChn.enModId = RK_ID_VI; stSrcChn.s32DevId = 0; stSrcChn.s32ChnId = channelId; 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; } VENC_STREAM_S stFrame; stFrame.pstPack = malloc(sizeof(VENC_PACK_S)); int loopCount = 0; while (g_run) { s32Ret = RK_MPI_VENC_GetStream(0, &stFrame, -1); if (s32Ret == RK_SUCCESS) { void *pData = RK_MPI_MB_Handle2VirAddr(stFrame.pstPack->pMbBlk); RK_S32 fd = RK_MPI_MB_Handle2Fd(stFrame.pstPack->pMbBlk); 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); uvc_read_camera_buffer(pData, fd, stFrame.pstPack->u32Len, NULL, 0); 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_VENC_GetStream fail %x", s32Ret); } } free(stFrame.pstPack); s32Ret = RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn); if (s32Ret != RK_SUCCESS) { RK_LOGE("RK_MPI_SYS_UnBind fail %x", s32Ret); } test_venc_exit(0); } else { printf("fcc %d is not support by rockit.\n", fcc); } __FAILED: printf("%s exit\n", __func__); s32Ret = RK_MPI_VI_DisableChn(0, channelId); RK_LOGE("RK_MPI_VI_DisableChn %x", s32Ret); s32Ret = RK_MPI_VI_DisableDev(0); RK_LOGE("RK_MPI_VI_DisableDev %x", s32Ret); return 0; } void *rockit_uvc_thread(void *arg) { struct camera_param *param = (struct camera_param *)arg; while (!rockit_uvc(param->width, param->height, param->fcc, param->fps)) usleep(100000); pthread_exit(NULL); } int open_rockit_uvc(int width, int height, int fcc, int fps) { g_run = true; g_param.width = width; g_param.height = height; g_param.fcc = fcc; g_param.fps = fps; return pthread_create(&g_th, NULL, rockit_uvc_thread, &g_param); } void close_rockit_uvc(void) { g_run = false; pthread_join(g_th, NULL); } int main(int argc, char* argv[]) { uint32_t flags = 0; register_uvc_open_camera(open_rockit_uvc); register_uvc_close_camera(close_rockit_uvc); if (RK_MPI_SYS_Init() != RK_SUCCESS) { RK_LOGE("rk mpi sys init fail!"); exit(0); } flags = UVC_CONTROL_LOOP_ONCE; uvc_control_run(flags); while (1) sleep(5); RK_MPI_SYS_Exit(); uvc_control_join(flags); return 0; }