/* * Copyright 2023 Rockchip Electronics Co. LTD * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #ifdef __cplusplus #if __cplusplus extern "C" { #endif #endif /* End of #ifdef __cplusplus */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sample_comm.h" #include "sample_comm_aov.h" #define VI_CHN_MAX 2 #define VENC_CHN_MAX 2 #define MAIN_CAM_INDEX 0 #define SUB_CAM_INDEX 1 #define VENC_MAIN_CHN 0 #define VENC_SUB_CHN 1 #define TRACE_BEGIN() RK_LOGW("Enter\n") #define TRACE_END() RK_LOGW("Exit\n") typedef struct _rkCmdArgs { RK_U32 u32Main0Width; RK_U32 u32Main0Height; RK_U32 u32Main1Width; RK_U32 u32Main1Height; RK_U32 u32ViBuffCnt; RK_U32 u32Gop; RK_U32 u32ViFps; RK_CHAR *pOutPathVenc; RK_CHAR *pIqFileDir; RK_BOOL bMultictx; CODEC_TYPE_E enCodecType; VENC_RC_MODE_E enRcMode; RK_CHAR *pCodecName; RK_S32 s32CamId; RK_BOOL bEnableSaveToSdcard; RK_BOOL bEnableMultiMode; RK_S32 s32BitRate; RK_U32 u32VencFps; rk_aiq_working_mode_t eHdrMode; RK_S32 s32AeMode; RK_S32 s32AovLoopCount; RK_S32 s32SuspendTime; RK_U32 u32BootFrame; RK_U32 u32QuickStart; } RkCmdArgs; typedef struct _rkMpiCtx { SAMPLE_VI_CTX_S vi[VI_CHN_MAX]; SAMPLE_VENC_CTX_S venc[VENC_CHN_MAX]; } SAMPLE_MPI_CTX_S; typedef struct _rkThreadStatus { RK_BOOL bIfMainThreadQuit; RK_BOOL bIfVencThreadQuit; pthread_t s32VencThreadId; } ThreadStatus; static RkCmdArgs *g_cmd_args = RK_NULL; static SAMPLE_MPI_CTX_S *g_mpi_ctx = RK_NULL; static RK_S32 g_exit_result = RK_SUCCESS; static ThreadStatus *g_thread_status = RK_NULL; static void program_handle_error(const char *func, RK_U32 line) { RK_LOGE("func: <%s> line: <%d> error exit!", func, line); g_exit_result = RK_FAILURE; g_thread_status->bIfMainThreadQuit = RK_TRUE; } static void program_normal_exit(const char *func, RK_U32 line) { RK_LOGE("func: <%s> line: <%d> normal exit!", func, line); g_thread_status->bIfMainThreadQuit = RK_TRUE; } static void sigterm_handler(int sig) { fprintf(stderr, "signal %d\n", sig); program_normal_exit(__func__, __LINE__); } static void drop_all_venc_chn_frame() { VENC_STREAM_S stFrame_tmp; RK_S32 s32ChnId; RK_S32 s32LoopCount = 0; stFrame_tmp.pstPack = (VENC_PACK_S *)(malloc(sizeof(VENC_PACK_S))); for (s32ChnId = 0; s32ChnId != VENC_CHN_MAX; ++s32ChnId) { s32LoopCount = 0; while (RK_MPI_VENC_GetStream(s32ChnId, &stFrame_tmp, 1000) == RK_SUCCESS) { RK_MPI_VENC_ReleaseStream(s32ChnId, &stFrame_tmp); RK_LOGD("drop frame now, chn:%d, len:%u, pts:%llu, seq:%u", s32ChnId, stFrame_tmp.pstPack->u32Len, stFrame_tmp.pstPack->u64PTS, stFrame_tmp.u32Seq); ++s32LoopCount; if (s32LoopCount > 30) RK_LOGW("venc %d drop too much frame!!!", s32ChnId); } } free(stFrame_tmp.pstPack); } static RK_S32 venc_get_frame_and_save2sdcard(SAMPLE_VENC_CTX_S *ctx, char *const buffer, RK_U32 *psize, RK_S32 frame_num) { VENC_STREAM_S frame; RK_S32 s32Ret; void *data = RK_NULL; memset(&frame, 0, sizeof(frame)); frame.pstPack = (VENC_PACK_S *)(malloc(sizeof(VENC_PACK_S))); if (frame.pstPack == NULL) { RK_LOGE("malloc failed!"); program_handle_error(__func__, __LINE__); return RK_FAILURE; } s32Ret = RK_MPI_VENC_GetStream(ctx->s32ChnId, &frame, 2000); if (s32Ret != RK_SUCCESS) { RK_LOGE("RK_MPI_VENC_GetStream failed %#X", s32Ret); free(frame.pstPack); return s32Ret; } if (g_cmd_args->bEnableSaveToSdcard) { if (buffer == NULL || *psize > AOV_STREAM_SIZE_WRITE_TO_SDCARD) { RK_LOGE("Error buffer ptr %p, size %d!", buffer, *psize); program_handle_error(__func__, __LINE__); free(frame.pstPack); return RK_FAILURE; } data = RK_MPI_MB_Handle2VirAddr(frame.pstPack->pMbBlk); if ((*psize + frame.pstPack->u32Len) <= AOV_STREAM_SIZE_WRITE_TO_SDCARD) { if (*psize == 0 && frame.pstPack->DataType.enH265EType == H265E_NALU_PSLICE) { // force idr frame RK_LOGD("work round force idr, skip...\n"); } else { memcpy(buffer + *psize, data, frame.pstPack->u32Len); *psize += frame.pstPack->u32Len; RK_LOGD("cache stream in buffer\n"); } } else { RK_LOGD("save stream to sdcard\n"); RK_MPI_VENC_RequestIDR(ctx->s32ChnId, RK_FALSE); SAMPLE_COMM_AOV_CopyStreamToSdcard(ctx->s32ChnId, buffer, *psize, data, frame.pstPack->u32Len); *psize = 0; } } RK_LOGD("chn:%d, frame %d, len:%u, pts:%llu, seq:%u", ctx->s32ChnId, frame_num, frame.pstPack->u32Len, frame.pstPack->u64PTS, frame.u32Seq); RK_MPI_VENC_ReleaseStream(ctx->s32ChnId, &frame); free(frame.pstPack); return RK_SUCCESS; } /****************************************************************************** * function : venc thread ******************************************************************************/ static void *venc_get_stream(void *pArgs) { SAMPLE_VENC_CTX_S *main_ctx = &g_mpi_ctx->venc[0]; SAMPLE_VENC_CTX_S *sub_ctx = &g_mpi_ctx->venc[1]; RK_S32 s32Ret = RK_FAILURE; char name[256] = {0}; RK_S32 loop_count = 0; char *main_buffer = NULL; char *sub_buffer = NULL; RK_U32 main_buffer_size = 0; RK_U32 sub_buffer_size = 0; RK_U32 venc_drop_frame_count = 0; TRACE_BEGIN(); if (g_cmd_args->bEnableSaveToSdcard) { // Allocate buffer to cache venc stream. main_buffer = (char *)malloc(AOV_STREAM_SIZE_WRITE_TO_SDCARD); // 10M form 200 frame if (main_buffer == NULL) { RK_LOGE("malloc failed!"); program_handle_error(__func__, __LINE__); return NULL; } main_buffer_size = 0; sub_buffer = (char *)malloc(AOV_STREAM_SIZE_WRITE_TO_SDCARD); // 10M form 200 frame if (sub_buffer == NULL) { RK_LOGE("malloc failed!"); program_handle_error(__func__, __LINE__); return NULL; } sub_buffer_size = 0; } for (int i = 0; i < g_cmd_args->u32BootFrame; i++) { venc_get_frame_and_save2sdcard(main_ctx, main_buffer, &main_buffer_size, i); venc_get_frame_and_save2sdcard(sub_ctx, sub_buffer, &sub_buffer_size, i); } if (g_cmd_args->bEnableSaveToSdcard) { if (main_buffer_size) { SAMPLE_COMM_AOV_CopyStreamToSdcard(VENC_MAIN_CHN, main_buffer, main_buffer_size, NULL, 0); main_buffer_size = 0; } if (sub_buffer_size) { SAMPLE_COMM_AOV_CopyStreamToSdcard(VENC_SUB_CHN, sub_buffer, sub_buffer_size, NULL, 0); sub_buffer_size = 0; } } // Enter single frame mode SAMPLE_COMM_ISP_SingleFrame(MAIN_CAM_INDEX); SAMPLE_COMM_ISP_SingleFrame(SUB_CAM_INDEX); // drop frame drop_all_venc_chn_frame(); // request idr RK_MPI_VENC_RequestIDR(VENC_MAIN_CHN, RK_FALSE); RK_MPI_VENC_RequestIDR(VENC_SUB_CHN, RK_FALSE); SAMPLE_COMM_AOV_EnterSleep(); while (!g_thread_status->bIfVencThreadQuit) { s32Ret = venc_get_frame_and_save2sdcard(main_ctx, main_buffer, &main_buffer_size, loop_count); s32Ret |= venc_get_frame_and_save2sdcard(sub_ctx, sub_buffer, &sub_buffer_size, loop_count); ++loop_count; if (s32Ret == RK_SUCCESS) { if (g_cmd_args->s32AovLoopCount != 0) { if (g_cmd_args->s32AovLoopCount > 0) --g_cmd_args->s32AovLoopCount; SAMPLE_COMM_AOV_EnterSleep(); } else { program_normal_exit(__func__, __LINE__); RK_LOGI("Exit AOV!"); break; } venc_drop_frame_count = 0; } else { ++venc_drop_frame_count; RK_LOGE("venc drop frame, force to Sleep, venc_drop_frame_count = %d\n", venc_drop_frame_count); venc_drop_frame_count++; if (venc_drop_frame_count < 10) SAMPLE_COMM_AOV_EnterSleep(); else RK_LOGE("venc drop too much frame!!!"); } } if (g_cmd_args->bEnableSaveToSdcard) { if (main_buffer_size) { SAMPLE_COMM_AOV_CopyStreamToSdcard(VENC_MAIN_CHN, main_buffer, main_buffer_size, NULL, 0); main_buffer_size = 0; } if (sub_buffer_size) { SAMPLE_COMM_AOV_CopyStreamToSdcard(VENC_SUB_CHN, sub_buffer, sub_buffer_size, NULL, 0); sub_buffer_size = 0; } } if (main_buffer) free(main_buffer); if (sub_buffer) free(sub_buffer); SAMPLE_COMM_ISP_MultiFrame(MAIN_CAM_INDEX); SAMPLE_COMM_ISP_MultiFrame(SUB_CAM_INDEX); TRACE_END(); return RK_NULL; } static RK_S32 global_param_init(void) { TRACE_BEGIN(); g_thread_status = (ThreadStatus *)malloc(sizeof(ThreadStatus)); if (!g_thread_status) { RK_LOGI("malloc for g_thread_status failure\n"); goto __global_init_fail; } memset(g_thread_status, 0, sizeof(ThreadStatus)); // Allocate global ctx. g_mpi_ctx = (SAMPLE_MPI_CTX_S *)(malloc(sizeof(SAMPLE_MPI_CTX_S))); if (!g_mpi_ctx) { printf("ctx is null, malloc failure\n"); goto __global_init_fail; } memset(g_mpi_ctx, 0, sizeof(SAMPLE_MPI_CTX_S)); g_cmd_args = malloc(sizeof(RkCmdArgs)); if (!g_cmd_args) { printf("g_cmd_args is null, malloc failure\n"); goto __global_init_fail; } memset(g_cmd_args, 0, sizeof(RkCmdArgs)); TRACE_END(); return RK_SUCCESS; __global_init_fail: if (g_thread_status) { free(g_thread_status); g_thread_status = RK_NULL; } if (g_mpi_ctx) { free(g_mpi_ctx); g_mpi_ctx = NULL; } if (g_cmd_args) { free(g_cmd_args); g_cmd_args = NULL; } TRACE_END(); return RK_FAILURE; } static RK_S32 global_param_deinit(void) { TRACE_BEGIN(); if (g_thread_status) { free(g_thread_status); g_thread_status = RK_NULL; } if (g_mpi_ctx) { free(g_mpi_ctx); g_mpi_ctx = NULL; } if (g_cmd_args) { free(g_cmd_args); g_cmd_args = NULL; } TRACE_END(); return RK_SUCCESS; } static RK_S32 isp_init(SAMPLE_MPI_CTX_S *ctx, RkCmdArgs *pArgs) { RK_S32 s32Ret = RK_SUCCESS; if (g_cmd_args->pIqFileDir) { s32Ret = SAMPLE_COMM_ISP_Init(MAIN_CAM_INDEX, g_cmd_args->eHdrMode, g_cmd_args->bMultictx, g_cmd_args->pIqFileDir); s32Ret |= SAMPLE_COMM_ISP_Run(MAIN_CAM_INDEX); if (s32Ret != RK_SUCCESS) { printf("#ISP cam %d init failed!\n", MAIN_CAM_INDEX); return s32Ret; } s32Ret = SAMPLE_COMM_ISP_Init(SUB_CAM_INDEX, g_cmd_args->eHdrMode, g_cmd_args->bMultictx, g_cmd_args->pIqFileDir); s32Ret |= SAMPLE_COMM_ISP_Run(SUB_CAM_INDEX); if (s32Ret != RK_SUCCESS) { printf("#ISP cam %d init failed!\n", SUB_CAM_INDEX); return s32Ret; } } return s32Ret; } static RK_S32 isp_deinit(SAMPLE_MPI_CTX_S *ctx, RkCmdArgs *pArgs) { RK_S32 s32Ret = RK_SUCCESS; if (g_cmd_args->pIqFileDir) { SAMPLE_COMM_ISP_Stop(MAIN_CAM_INDEX); SAMPLE_COMM_ISP_Stop(SUB_CAM_INDEX); } return s32Ret; } static RK_S32 vi_chn_init(SAMPLE_MPI_CTX_S *ctx, RkCmdArgs *pArgs) { RK_S32 s32Ret = RK_SUCCESS; TRACE_BEGIN(); /* Init VI[0] */ ctx->vi[0].bIfQuickStart = pArgs->u32QuickStart; ctx->vi[0].u32Width = pArgs->u32Main0Width; ctx->vi[0].u32Height = pArgs->u32Main0Height; ctx->vi[0].s32DevId = MAIN_CAM_INDEX; ctx->vi[0].u32PipeId = MAIN_CAM_INDEX; ctx->vi[0].s32ChnId = 0; ctx->vi[0].stChnAttr.stIspOpt.stMaxSize.u32Width = pArgs->u32Main0Width; ctx->vi[0].stChnAttr.stIspOpt.stMaxSize.u32Height = pArgs->u32Main0Height; ctx->vi[0].stChnAttr.stIspOpt.u32BufCount = pArgs->u32ViBuffCnt; ctx->vi[0].stChnAttr.stIspOpt.enMemoryType = VI_V4L2_MEMORY_TYPE_DMABUF; ctx->vi[0].stChnAttr.enPixelFormat = RK_FMT_YUV420SP; ctx->vi[0].stChnAttr.enCompressMode = COMPRESS_MODE_NONE; ctx->vi[0].stChnAttr.stFrameRate.s32SrcFrameRate = -1; ctx->vi[0].stChnAttr.stFrameRate.s32DstFrameRate = -1; s32Ret = SAMPLE_COMM_VI_CreateChn(&(ctx->vi[0])); if (s32Ret != RK_SUCCESS) RK_LOGE("SAMPLE_COMM_VI_CreateChn 0 failure:%d", s32Ret); /* Init VI[1] */ ctx->vi[1].bIfQuickStart = pArgs->u32QuickStart; ctx->vi[1].u32Width = pArgs->u32Main1Width; ctx->vi[1].u32Height = pArgs->u32Main1Height; ctx->vi[1].s32DevId = SUB_CAM_INDEX; ctx->vi[1].u32PipeId = SUB_CAM_INDEX; ctx->vi[1].s32ChnId = 0; ctx->vi[1].stChnAttr.stIspOpt.stMaxSize.u32Width = pArgs->u32Main1Width; ctx->vi[1].stChnAttr.stIspOpt.stMaxSize.u32Height = pArgs->u32Main1Height; ctx->vi[1].stChnAttr.stIspOpt.u32BufCount = pArgs->u32ViBuffCnt; ctx->vi[1].stChnAttr.stIspOpt.enMemoryType = VI_V4L2_MEMORY_TYPE_DMABUF; ctx->vi[1].stChnAttr.enPixelFormat = RK_FMT_YUV420SP; ctx->vi[1].stChnAttr.enCompressMode = COMPRESS_MODE_NONE; ctx->vi[1].stChnAttr.stFrameRate.s32SrcFrameRate = -1; ctx->vi[1].stChnAttr.stFrameRate.s32DstFrameRate = -1; s32Ret = SAMPLE_COMM_VI_CreateChn(&(ctx->vi[1])); if (s32Ret != RK_SUCCESS) RK_LOGE("SAMPLE_COMM_VI_CreateChn 1 failure:%d", s32Ret); TRACE_END(); return s32Ret; } static RK_S32 vi_chn_deinit(SAMPLE_MPI_CTX_S *ctx, RkCmdArgs *pArgs) { RK_S32 s32Ret = RK_SUCCESS; TRACE_BEGIN(); s32Ret = SAMPLE_COMM_VI_DestroyChn(&(ctx->vi[1])); if (s32Ret != RK_SUCCESS) RK_LOGE("SAMPLE_COMM_VI_DestroyChn failure:%d", s32Ret); s32Ret = SAMPLE_COMM_VI_DestroyChn(&(ctx->vi[0])); if (s32Ret != RK_SUCCESS) RK_LOGE("SAMPLE_COMM_VI_DestroyChn failure:%d", s32Ret); TRACE_END(); return s32Ret; } static RK_S32 venc_chn_init(SAMPLE_MPI_CTX_S *ctx, RkCmdArgs *pArgs) { RK_S32 s32Ret = RK_SUCCESS; TRACE_BEGIN(); // Init VENC[0] ctx->venc[0].s32ChnId = VENC_MAIN_CHN; ctx->venc[0].u32Width = pArgs->u32Main0Width; ctx->venc[0].u32Height = pArgs->u32Main0Height; ctx->venc[0].u32Fps = pArgs->u32VencFps; ctx->venc[0].u32Gop = pArgs->u32Gop; ctx->venc[0].u32BitRate = pArgs->s32BitRate; ctx->venc[0].enCodecType = pArgs->enCodecType; ctx->venc[0].enRcMode = pArgs->enRcMode; ctx->venc[0].getStreamCbFunc = NULL; ctx->venc[0].dstFilePath = pArgs->pOutPathVenc; ctx->venc[0].u32BuffSize = pArgs->u32Main0Width * pArgs->u32Main0Height / 2; ctx->venc[0].enable_buf_share = RK_TRUE; // H264 66:Baseline 77:Main Profile 100:High Profile // H265 0:Main Profile 1:Main 10 Profile // MJPEG 0:Baseline ctx->venc[0].stChnAttr.stGopAttr.enGopMode = VENC_GOPMODE_NORMALP; // VENC_GOPMODE_SMARTP if (RK_CODEC_TYPE_H264 != pArgs->enCodecType) { ctx->venc[0].stChnAttr.stVencAttr.u32Profile = 0; } else { ctx->venc[0].stChnAttr.stVencAttr.u32Profile = 100; } s32Ret = SAMPLE_COMM_VENC_CreateChn(&ctx->venc[0]); if (s32Ret != RK_SUCCESS) RK_LOGE("SAMPLE_COMM_VENC_CreateChn venc0 failed %#X\n", s32Ret); // Init VENC[1] ctx->venc[1].s32ChnId = VENC_SUB_CHN; ctx->venc[1].u32Width = pArgs->u32Main1Width; ctx->venc[1].u32Height = pArgs->u32Main1Height; ctx->venc[1].u32Fps = pArgs->u32VencFps; ctx->venc[1].u32Gop = pArgs->u32Gop; ctx->venc[1].u32BitRate = pArgs->s32BitRate; ctx->venc[1].enCodecType = pArgs->enCodecType; ctx->venc[1].enRcMode = pArgs->enRcMode; ctx->venc[1].getStreamCbFunc = NULL; ctx->venc[1].dstFilePath = pArgs->pOutPathVenc; ctx->venc[1].u32BuffSize = pArgs->u32Main1Width * pArgs->u32Main1Height / 2; ctx->venc[1].enable_buf_share = RK_TRUE; // H264 66:Baseline 77:Main Profile 100:High Profile // H265 0:Main Profile 1:Main 10 Profile // MJPEG 0:Baseline ctx->venc[1].stChnAttr.stGopAttr.enGopMode = VENC_GOPMODE_NORMALP; // VENC_GOPMODE_SMARTP if (RK_CODEC_TYPE_H264 != pArgs->enCodecType) { ctx->venc[1].stChnAttr.stVencAttr.u32Profile = 0; } else { ctx->venc[1].stChnAttr.stVencAttr.u32Profile = 100; } s32Ret = SAMPLE_COMM_VENC_CreateChn(&ctx->venc[1]); if (s32Ret != RK_SUCCESS) RK_LOGE("SAMPLE_COMM_VENC_CreateChn venc1 failed %#X\n", s32Ret); TRACE_END(); return s32Ret; } static RK_S32 venc_chn_deinit(SAMPLE_MPI_CTX_S *ctx, RkCmdArgs *pArgs) { RK_S32 s32Ret = RK_SUCCESS; TRACE_BEGIN(); s32Ret = SAMPLE_COMM_VENC_DestroyChn(&ctx->venc[1]); if (s32Ret != RK_SUCCESS) RK_LOGE("SAMPLE_COMM_VENC_CreateChn venc1 failed %#X\n", s32Ret); s32Ret = SAMPLE_COMM_VENC_DestroyChn(&ctx->venc[0]); if (s32Ret != RK_SUCCESS) RK_LOGE("SAMPLE_COMM_VENC_CreateChn venc0 failed %#X\n", s32Ret); TRACE_END(); return s32Ret; } static RK_S32 bind_init(SAMPLE_MPI_CTX_S *ctx, RkCmdArgs *pArgs) { RK_S32 s32Ret = RK_SUCCESS; MPP_CHN_S stSrcChn, stDestChn; TRACE_BEGIN(); // Bind VI[0] and VENC[0] stSrcChn.enModId = RK_ID_VI; stSrcChn.s32DevId = ctx->vi[MAIN_CAM_INDEX].s32DevId; stSrcChn.s32ChnId = ctx->vi[MAIN_CAM_INDEX].s32ChnId; stDestChn.enModId = RK_ID_VENC; stDestChn.s32DevId = 0; stDestChn.s32ChnId = VENC_MAIN_CHN; s32Ret = SAMPLE_COMM_Bind(&stSrcChn, &stDestChn); if (s32Ret != RK_SUCCESS) RK_LOGE("bind vi0 to vpss0 failed"); // Bind VI[1] and VENC[1] stSrcChn.enModId = RK_ID_VI; stSrcChn.s32DevId = ctx->vi[SUB_CAM_INDEX].s32DevId; stSrcChn.s32ChnId = ctx->vi[SUB_CAM_INDEX].s32ChnId; stDestChn.enModId = RK_ID_VENC; stDestChn.s32DevId = 0; stDestChn.s32ChnId = VENC_SUB_CHN; s32Ret = SAMPLE_COMM_Bind(&stSrcChn, &stDestChn); if (s32Ret != RK_SUCCESS) RK_LOGE("bind vi1 to vpss1 failed"); TRACE_END(); return s32Ret; } static RK_S32 bind_deinit(SAMPLE_MPI_CTX_S *ctx, RkCmdArgs *pArgs) { RK_S32 s32Ret = RK_SUCCESS; MPP_CHN_S stSrcChn, stDestChn; TRACE_BEGIN(); // UnBind VI[1] and VENC[1] stSrcChn.enModId = RK_ID_VI; stSrcChn.s32DevId = ctx->vi[SUB_CAM_INDEX].s32DevId; stSrcChn.s32ChnId = ctx->vi[SUB_CAM_INDEX].s32ChnId; stDestChn.enModId = RK_ID_VENC; stDestChn.s32DevId = 0; stDestChn.s32ChnId = VENC_SUB_CHN; SAMPLE_COMM_UnBind(&stSrcChn, &stDestChn); // UnBind VI[0] and VENC[0] stSrcChn.enModId = RK_ID_VI; stSrcChn.s32DevId = ctx->vi[MAIN_CAM_INDEX].s32DevId; stSrcChn.s32ChnId = ctx->vi[MAIN_CAM_INDEX].s32ChnId; stDestChn.enModId = RK_ID_VENC; stDestChn.s32DevId = 0; stDestChn.s32ChnId = VENC_MAIN_CHN; SAMPLE_COMM_UnBind(&stSrcChn, &stDestChn); TRACE_END(); return s32Ret; } static RK_S32 sub_threads_init(SAMPLE_MPI_CTX_S *ctx, RkCmdArgs *pArgs) { TRACE_BEGIN(); pthread_create(&g_thread_status->s32VencThreadId, NULL, venc_get_stream, NULL); TRACE_END(); return RK_SUCCESS; } static RK_S32 sub_threads_deinit(SAMPLE_MPI_CTX_S *ctx, RkCmdArgs *pArgs) { TRACE_BEGIN(); g_thread_status->bIfVencThreadQuit = true; pthread_join(g_thread_status->s32VencThreadId, NULL); TRACE_END(); return RK_SUCCESS; } static RK_CHAR optstr[] = "?::a::w:h:o:l:b:f:r:g:v:e:i:s:I:"; static const struct option long_options[] = { {"aiq", optional_argument, RK_NULL, 'a'}, {"sensor", required_argument, RK_NULL, 's'}, {"width", required_argument, RK_NULL, 'w'}, {"height", required_argument, RK_NULL, 'h'}, {"encode", required_argument, RK_NULL, 'e'}, {"output_path", required_argument, RK_NULL, 'o'}, {"bitrate", required_argument, NULL, 'b'}, {"fps", required_argument, RK_NULL, 'f'}, {"vi_buff_cnt", required_argument, RK_NULL, 'v'}, {"gop", required_argument, RK_NULL, 'g'}, {"enable_multi_frame", required_argument, RK_NULL, 'e' + 'm' + 'f'}, {"enable_save_sdcard", required_argument, RK_NULL, 'e' + 'm' + 'h'}, {"suspend_time", required_argument, NULL, 's' + 't'}, {"aov_loop_count", required_argument, NULL, 'a' + 'm' + 'c'}, {"help", optional_argument, RK_NULL, '?'}, {"boot_frame", required_argument, NULL, 'b' + 'f'}, {"quick_start", required_argument, NULL, 'q' + 'k' + 's'}, {RK_NULL, 0, RK_NULL, 0}, }; /****************************************************************************** * function : show usage ******************************************************************************/ static void print_usage(const RK_CHAR *name) { printf("\t%s -s 0 -w 2048 -h 1536 -s 1 -w 1920 -h 1080 --aov_loop_count 10\n", name); printf("\t-a | --aiq : enable aiq with dirpath provided, eg:-a " "/etc/iqfiles/, \n" "\t set dirpath empty to using path by default, without " "this option aiq \n" "\t should run in other application\n"); printf("\t-w | --width : mainStream width, must is sensor width\n"); printf("\t-h | --height : mainStream height, must is sensor height\n"); printf("\t-s | --sensor : 0 means main camera, 1 means sub camera\n"); printf("\t-e | --encode: encode type, Default:h264cbr, Value:h264cbr, " "h264vbr, h264avbr " "h265cbr, h265vbr, h265avbr, mjpegcbr, mjpegvbr\n"); printf("\t-b | --bitrate: encode bitrate, Default 4096\n"); printf("\t-o | --output_path : encode output file path, Default: RK_NULL\n"); printf("\t-v | --vi_buff_cnt : main stream vi buffer num, Default: 2\n"); printf("\t--vi_chnid : vi channel id, default: 0\n"); printf("\t-f | --fps : set fps, default: 10\n"); printf("\t--aov_loop_count: When the value of aov_loop_count is greater \n" "\t\t than 0, " "this value represents the number of AOV cycles. A \n" "\t\t negative value indicates an infinite loop, Default: " "-1(unlimit)\n"); printf("\t--suspend_time: set aov suspend time, Default: 1000ms\n"); printf("\t--boot_frame: How long will it take to enter AOV mode after boot" ", Default: 60 frames\n"); printf("\t--quick_start: quick start stream, Default: 0\n"); } /****************************************************************************** * function : parse_cmd_args() * Description : Parse command line arguments. ******************************************************************************/ static RK_S32 parse_cmd_args(int argc, char **argv, RkCmdArgs *pArgs) { pArgs->u32Main0Width = 1920; pArgs->u32Main0Height = 1080; pArgs->u32Main1Width = 1920; pArgs->u32Main1Height = 1080; pArgs->u32ViBuffCnt = 2; pArgs->u32Gop = 20; pArgs->u32ViFps = 10; pArgs->pOutPathVenc = NULL; pArgs->pIqFileDir = "/oem/usr/share/iqfiles"; pArgs->bMultictx = RK_TRUE; pArgs->enCodecType = RK_CODEC_TYPE_H264; pArgs->enRcMode = VENC_RC_MODE_H264CBR; pArgs->pCodecName = "H264"; pArgs->s32CamId = 0; pArgs->s32BitRate = 4 * 1024; pArgs->u32VencFps = 10; pArgs->eHdrMode = RK_AIQ_WORKING_MODE_NORMAL; pArgs->s32AeMode = 0; pArgs->s32AovLoopCount = -1; pArgs->s32SuspendTime = 1000; pArgs->bEnableSaveToSdcard = RK_TRUE; pArgs->bEnableMultiMode = RK_TRUE; pArgs->u32BootFrame = 60; pArgs->u32QuickStart = 0; int sensor_index = 0; RK_S32 c = 0; while ((c = getopt_long(argc, argv, optstr, long_options, RK_NULL)) != -1) { const char *tmp_optarg = optarg; switch (c) { case 'a': if (!optarg && RK_NULL != argv[optind] && '-' != argv[optind][0]) { tmp_optarg = argv[optind++]; } if (tmp_optarg) { pArgs->pIqFileDir = (char *)tmp_optarg; } else { pArgs->pIqFileDir = RK_NULL; } break; case 's': sensor_index = atoi(optarg); case 'w': if (sensor_index == 0) pArgs->u32Main0Width = atoi(optarg); else if (sensor_index == 1) pArgs->u32Main1Width = atoi(optarg); else printf("# Error sensor index %d!\n", sensor_index); break; case 'h': if (sensor_index == 0) pArgs->u32Main0Height = atoi(optarg); else if (sensor_index == 1) pArgs->u32Main1Height = atoi(optarg); else printf("# Error sensor index %d!\n", sensor_index); break; case 'b': pArgs->s32BitRate = atoi(optarg); break; case 'e': if (!strcmp(optarg, "h264cbr")) { pArgs->enCodecType = RK_CODEC_TYPE_H264; pArgs->enRcMode = VENC_RC_MODE_H264CBR; } else if (!strcmp(optarg, "h264vbr")) { pArgs->enCodecType = RK_CODEC_TYPE_H264; pArgs->enRcMode = VENC_RC_MODE_H264VBR; } else if (!strcmp(optarg, "h264avbr")) { pArgs->enCodecType = RK_CODEC_TYPE_H264; pArgs->enRcMode = VENC_RC_MODE_H264AVBR; } else if (!strcmp(optarg, "h265cbr")) { pArgs->enCodecType = RK_CODEC_TYPE_H265; pArgs->enRcMode = VENC_RC_MODE_H265CBR; } else if (!strcmp(optarg, "h265vbr")) { pArgs->enCodecType = RK_CODEC_TYPE_H265; pArgs->enRcMode = VENC_RC_MODE_H265VBR; } else if (!strcmp(optarg, "h265avbr")) { pArgs->enCodecType = RK_CODEC_TYPE_H265; pArgs->enRcMode = VENC_RC_MODE_H265AVBR; } else { RK_LOGE("Invalid encoder type!"); return RK_FAILURE; } break; case 'o': pArgs->pOutPathVenc = optarg; break; case 'f': pArgs->u32VencFps = atoi(optarg); break; case 'v': pArgs->u32ViBuffCnt = atoi(optarg); break; case 'g': pArgs->u32Gop = atoi(optarg); break; case 'e' + 'm' + 'f': pArgs->bEnableMultiMode = atoi(optarg); break; case 'e' + 'm' + 'h': pArgs->bEnableSaveToSdcard = atoi(optarg); break; case 'a' + 'm' + 'c': pArgs->s32AovLoopCount = atoi(optarg); break; case 's' + 't': pArgs->s32SuspendTime = atoi(optarg); break; case 'b' + 'f': pArgs->u32BootFrame = atoi(optarg); break; case 'q' + 'k' + 's': pArgs->u32QuickStart = atoi(optarg); break; case '?': print_usage(argv[0]); default: return RK_FAILURE; } } return RK_SUCCESS; } /****************************************************************************** * function : main() * Description : main ******************************************************************************/ int main(int argc, char *argv[]) { RK_S32 s32Ret = RK_SUCCESS; if (argc < 2) { print_usage(argv[0]); printf("bad arguments!\n"); return RK_FAILURE; } if (global_param_init() != RK_SUCCESS) { printf("global_param_init failure!\n"); return RK_FAILURE; } // Parse command line. if (parse_cmd_args(argc, argv, g_cmd_args) != RK_SUCCESS) { printf("parse_cmd_args failure\n"); goto __ISP_INIT_FAILED; } signal(SIGINT, sigterm_handler); signal(SIGTERM, sigterm_handler); SAMPLE_COMM_AOV_Init(NULL); printf("#CameraIdx: %d\n", g_cmd_args->s32CamId); printf("#CodecName:%s\n", g_cmd_args->pCodecName); printf("#Output Path: %s\n", g_cmd_args->pOutPathVenc); printf("#bMultictx: %d\n\n", g_cmd_args->bMultictx); if (isp_init(g_mpi_ctx, g_cmd_args) != RK_SUCCESS) { printf("isp_init failure!\n"); g_exit_result = RK_FAILURE; goto __ISP_INIT_FAILED; } if (RK_MPI_SYS_Init() != RK_SUCCESS) { printf("RK_MPI_SYS_Init failure"); g_exit_result = RK_FAILURE; goto __MPI_INIT_FAILED; } vi_chn_init(g_mpi_ctx, g_cmd_args); venc_chn_init(g_mpi_ctx, g_cmd_args); bind_init(g_mpi_ctx, g_cmd_args); if (!g_cmd_args->u32QuickStart) { RK_MPI_VI_StartPipe(MAIN_CAM_INDEX); RK_MPI_VI_StartPipe(SUB_CAM_INDEX); } sub_threads_init(g_mpi_ctx, g_cmd_args); SAMPLE_COMM_AOV_SetSuspendTime(g_cmd_args->s32SuspendTime); // Keep running ... while (!g_thread_status->bIfMainThreadQuit) { sleep(1); } sub_threads_deinit(g_mpi_ctx, g_cmd_args); bind_deinit(g_mpi_ctx, g_cmd_args); venc_chn_deinit(g_mpi_ctx, g_cmd_args); vi_chn_deinit(g_mpi_ctx, g_cmd_args); RK_MPI_SYS_Exit(); __MPI_INIT_FAILED: isp_deinit(g_mpi_ctx, g_cmd_args); SAMPLE_COMM_AOV_Deinit(); __ISP_INIT_FAILED: global_param_deinit(); return g_exit_result; } #ifdef __cplusplus #if __cplusplus } #endif #endif /* End of #ifdef __cplusplus */