3516cv610在sample_aiisp上多创一路编码流,方法
首先确保 vpss grp0有视频流
最好保证 已经有一路视频流能推出来
多创一路编码流思路为
将 vpss grp0又绑定给 vpss_chn1
vpss_chn1有绑定给 venc_chn1
这样我们就多创了一路视频流。
这里思路完全正确 可以实现
整个工程代码,在底部链接获取
aiisp需要对 sc500ai寄存器进行操作
// 改变 sc500ai的bayer格式// 改变为 RGGB的格式3211, 0x053213, 0x05
sdk说明
sdk_010打AOV的补丁
硬件
cv610_20s+sc500ai
下面是 aiisp的例子,多创建一路编码流
// sample_aiisp.c #include #include "sample_comm.h"#include "sample_ipc.h"#include "sample_aibnr.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rtsp_demo.h" rtsp_demo_handle g_rtsplive = NULL;rtsp_session_handle session= NULL; static td_void sample_aiisp_usage(const char *prg_name){ printf("usage : %s \n", prg_name); printf("index:\n"); printf(" (0) aibnr line mode : base mode, has reference frame\n"); printf(" (1) aibnr line pro mode\n");} static td_void sample_register_sig_handler(td_void (*sig_handle)(td_s32)){ struct sigaction sa; (td_void)memset_s(&sa, sizeof(struct sigaction), 0, sizeof(struct sigaction)); sa.sa_handler = sig_handle; sa.sa_flags = 0; sigaction(SIGINT, &sa, TD_NULL); sigaction(SIGTERM, &sa, TD_NULL);} static td_s32 sample_aiisp_msg_proc_vb_pool_share(td_s32 pid){ td_s32 ret; td_u32 i; td_bool isp_states[OT_VI_MAX_PIPE_NUM];#ifndef SAMPLE_MEM_SHARE_ENABLE ot_vb_common_pools_id pools_id = {0}; if (ss_mpi_vb_get_common_pool_id(&pools_id) != TD_SUCCESS) { sample_print("get common pool_id failed!\n"); return TD_FAILURE; } for (i = 0; i msg_type) { case SAMPLE_MSG_TYPE_VB_POOL_SHARE_REQ: { if (msg_res_buf == TD_NULL) { return TD_FAILURE; } ret = sample_aiisp_msg_proc_vb_pool_share(msg_req_buf->msg_data.pid); msg_res_buf->msg_type = SAMPLE_MSG_TYPE_VB_POOL_SHARE_RES; msg_res_buf->msg_data.is_req_success = (ret == TD_SUCCESS) ? TD_TRUE : TD_FALSE; break; } case SAMPLE_MSG_TYPE_VB_POOL_UNSHARE_REQ: { if (msg_res_buf == TD_NULL) { return TD_FAILURE; } sample_aiisp_msg_proc_vb_pool_unshare(msg_req_buf->msg_data.pid); msg_res_buf->msg_type = SAMPLE_MSG_TYPE_VB_POOL_UNSHARE_RES; msg_res_buf->msg_data.is_req_success = TD_TRUE; break; } default: { printf("unsupported msg type(%ld)!\n", msg_req_buf->msg_type); return TD_FAILURE; } } return TD_SUCCESS;} td_s32 sample_comm_save_frame_to_file(td_s32 index, sample_comm_venc_stream_proc_info *stream_proc_info, ot_venc_stream *stream, ot_venc_stream_buf_info *stream_buf_info, ot_payload_type *payload_type){// printf("\n\nfunction: %s line: %d\n\n", __FUNCTION__, __LINE__); td_s32 ret, fd; if (payload_type[index] == OT_PT_JPEG) { if (snprintf_s(stream_proc_info->file_name[index], FILE_NAME_LEN, FILE_NAME_LEN - 1, "./") pack); return SAMPLE_RETURN_NULL; } if (realpath(stream_proc_info->file_name[index], stream_proc_info->real_file_name[index]) == TD_NULL) { free(stream->pack); sample_print("chn[%d] stream file path error\n", stream_proc_info->venc_chn); return SAMPLE_RETURN_NULL; } if (snprintf_s(stream_proc_info->real_file_name[index], FILE_NAME_LEN, FILE_NAME_LEN - 1, "stream_chn%d_%u%s", index, stream_proc_info->picture_cnt[index], stream_proc_info->file_postfix) pack); return SAMPLE_RETURN_NULL; } stream_proc_info->file[index] = fopen(stream_proc_info->real_file_name[index], "wb"); if (!stream_proc_info->file[index]) { free(stream->pack); sample_print("open file err!\n"); return SAMPLE_RETURN_NULL; } fd = fileno(stream_proc_info->file[index]); fchmod(fd, S_IRUSR | S_IWUSR); } #ifndef __LITEOS__ ot_unused(stream_buf_info); ret = sample_comm_venc_save_stream(stream_proc_info->file[index], stream); // printf("\nindex is %d\n", index); //rtsp发送 td_u8 * pStremData = NULL;int nSize = 0;td_u32 j=0; if(index==1){//发送venc通道1 for (j = 0; j pack_cnt; j++) { //(td_void)fwrite(stream->pack[j].addr + stream->pack[j].offset, stream->pack[j].len - stream->pack[j].offset, 1, fd); if(stream->pack[j].data_type.h264_type == OT_VENC_H264_NALU_SEI) continue;//暂时去掉SEI帧 pStremData = stream->pack[j].addr + stream->pack[j].offset; nSize = stream->pack[j].len - stream->pack[j].offset; if(g_rtsplive) { rtsp_sever_tx_video(g_rtsplive,session,pStremData,nSize,stream->pack[j].pts); } } } ret = TD_SUCCESS; #else ret = sample_comm_venc_save_stream_phys_addr(stream_proc_info->file[index], &stream_buf_info[index], stream);#endif if (ret != TD_SUCCESS) { free(stream->pack); stream->pack = TD_NULL; sample_print("save stream failed!\n"); return SAMPLE_RETURN_BREAK; } return TD_SUCCESS;} td_s32 main(td_s32 argc, td_char *argv[]){ g_rtsplive = create_rtsp_demo(554);//554端口创建rtspserver session= create_rtsp_session(g_rtsplive,"/test.264");//创建rtsp会话 rtsp://[IP]/test.264 td_s32 ret = TD_FAILURE; td_u32 index; td_char *para_stop; sample_aiisp_usage(argv[0]); sample_register_sig_handler(sample_aiisp_handle_sig); if (sample_ipc_server_init(sample_aiisp_ipc_msg_proc) != TD_SUCCESS) { printf("sample_ipc_server_init failed!!!\n"); } sample_aibnr_param aibnr_param = {0}; aibnr_param.is_wdr_mode = TD_FALSE; aibnr_param.ref_mode = OT_AIBNR_REF_MODE_NORM; aibnr_param.is_blend = TD_FALSE; aibnr_param.is_pro = TD_FALSE; ret = sample_aibnr(&aibnr_param); if ((ret == TD_SUCCESS) && (sample_aiisp_get_sig() == 0)) { sample_print("\033[0;32mprogram exit normally!\033[0;39m\n"); } else { sample_print("\033[0;31mprogram exit abnormally!\033[0;39m\n"); } server_deinit: sample_ipc_server_deinit(); exit:#ifdef __LITEOS__ return ret;#else exit(ret);#endif}
主要在 sample_aibnr.c、sample_aiisp_common.c增加编码通道
// sample_aibnr.c #include "sample_aibnr.h"#include "sample_aiisp_common.h"#include "ss_mpi_aibnr.h" #define VB_AIBNR_LINE_CNT 4#define VB_AIBNR_TNR_CNT 4#define VB_AIBNR_COMMON_VB_CNT 3// #define VB_AIBNR_COMMON_VB_CNT 1 //----------------------------add a chnnel stream 开始#define CHN_NUM_MAX 2 typedef struct { td_s32 venc_chn_num; ot_size enc_size[CHN_NUM_MAX]; td_s32 vpss_chn_depth;} sample_venc_param;//----------------------------add a chnnel stream 结束 static td_u16 g_r_calib_lut[OT_AIBNR_NLC_LUT_NUM] = { 1043, 1043, 1029, 1024, 1021, 1020, 1019, 1018, 1017, 1017, 1016, 1015, 1014, 1014, 1013, 1013, 1012, 1012, 1012, 1011, 1011, 1011, 1010, 1010, 1010, 1010, 1009, 1009, 1008, 1008, 1008, 1000}; static td_u16 g_b_calib_lut[OT_AIBNR_NLC_LUT_NUM] = { 1024, 1024, 1027, 1028, 1029, 1029, 1029, 1029, 1027, 1024, 1021, 1019, 1018, 1016, 1015, 1013, 1011, 1009, 1008, 1006, 1005, 1004, 1004, 1004, 1003, 1003, 1003, 1002, 1002, 1002, 1002, 1000}; static td_s32 sample_aibnr_set_nlc(ot_aibnr_nlc *nlc){ td_s32 ret; nlc->enable = TD_FALSE; nlc->step_bit = 0x3; ret = memcpy_s(nlc->r_fact, sizeof(nlc->r_fact), g_r_calib_lut, sizeof(g_r_calib_lut)); if (ret != EOK) { printf("memcpy_s failed!\n"); return TD_FAILURE; } ret = memcpy_s(nlc->b_fact, sizeof(nlc->b_fact), g_b_calib_lut, sizeof(g_b_calib_lut)); if (ret != EOK) { printf("memcpy_s failed!\n"); return TD_FAILURE; } return TD_SUCCESS;} static td_s32 sample_aibnr_set_model_attr(td_void){ td_s32 ret; ot_aibnr_model_list list = {0}; ot_aibnr_model_attr model_attr = {0}; ret = ss_mpi_aibnr_query_model_list(&list); if (ret != TD_SUCCESS) { sample_print("ss_mpi_aibnr_query_model_list error\n"); return ret; } printf("model list info:\n"); printf("num:%d\n", list.num); for (td_u32 i = 0; i is_blend; aibnr_attr.op_type = OT_OP_MODE_MANUAL; aibnr_attr.manual_attr.sfs = 31; /* sfs: 31 */ ret = sample_aibnr_set_nlc(&aibnr_attr.manual_attr.nlc); if (ret != TD_SUCCESS) { printf("call sample_aibnr_set_nlc failed!\n"); return TD_FAILURE; } ret = ss_mpi_aibnr_set_attr(vi_pipe, &aibnr_attr); if (ret != TD_SUCCESS) { sample_print("ss_mpi_aibnr_set_attr error\n"); return ret; } if (aibnr_param->is_pro == TD_FALSE) { sample_aibnr_set_model_attr(); } return TD_SUCCESS;} // 有调用static td_s32 sample_aibnr_load_model(ot_aibnr_model *model_info, td_s32 *model_id, td_char *model_file){ td_s32 ret; ot_aiisp_model *model = &model_info->model; // printf("\n\nfunction: %s line: %d\n\n", __FUNCTION__, __LINE__); if (model->mem_info.virt_addr == TD_NULL) { ret = sample_aiisp_load_mem((ot_aiisp_mem_info *)&(model->mem_info), model_file); if (ret != TD_SUCCESS) { sample_print("sample_aiisp_load_mem error\n"); return ret; } } ret = ss_mpi_aibnr_load_model(model_info, model_id); if (ret != TD_SUCCESS) { sample_print("ss_mpi_aibnr_load_model error(%#x)\n", ret); goto unload_mem; } return ret; unload_mem: sample_aiisp_unload_mem((ot_aiisp_mem_info *)&(model->mem_info)); return ret;} static td_s32 sample_aibnr_unload_model(ot_aibnr_model *model, td_s32 model_id){ td_s32 ret; ret = ss_mpi_aibnr_unload_model(model_id); if (ret != TD_SUCCESS) { sample_print("ss_mpi_aibnr_unload_cfg error(%#x)\n", ret); } sample_aiisp_unload_mem((ot_aiisp_mem_info *)&(model->model.mem_info)); return ret;} // 有调用static td_s32 sample_aibnr_load(ot_size in_size, ot_aibnr_model *model_info, td_s32 *model_id, sample_aibnr_param *aibnr_param){// printf("\n\nfunction: %s line: %d\n\n", __FUNCTION__, __LINE__);printf("\n\nwidth is %d height is %d\n\n", in_size.width, in_size.height); td_s32 ret; td_u32 max_len = 256; td_char model_file[max_len]; if (aibnr_param->is_pro == TD_FALSE) {printf("\n\naiisp normal bin\n\n"); ret = snprintf_s(model_file, max_len, max_len - 1, "./aibnr_model/aibnr_model_%dx%d.bin", in_size.width, in_size.height); } else {printf("\n\naiisp pro bin\n\n"); ret = snprintf_s(model_file, max_len, max_len - 1, "./aibnr_model/aibnr_model_%dx%d_pro.bin", in_size.width, in_size.height); } if (ret is_wdr_mode; model_info[0].ref_mode = aibnr_param->ref_mode; model_info[0].nlc_en = TD_FALSE; model_info[0].is_wdr_mode = TD_FALSE; ret = (&model_info[0], &model_id[0], model_file); // 这里报错,确实是这里报错 // if (ret != TD_SUCCESS) // { // return ret; // } // 这里这个分支也会进 if (aibnr_param->is_pro == TD_FALSE) {// 进入这个分支// printf("\n\nfunction: %s line: %d\n\n", __FUNCTION__, __LINE__); // ret = snprintf_s(model_file, max_len, max_len - 1, "./aibnr_model/aibnr_model_%dx%d.bin", in_size.width, in_size.height); ret = snprintf_s(model_file, max_len, max_len - 1, "./aibnr_model/aibnr_model_%dx%d_high_iso.bin", in_size.width, in_size.height); if (ret is_wdr_mode; model_info[1].ref_mode = aibnr_param->ref_mode; model_info[1].nlc_en = TD_FALSE; model_info[1].is_wdr_mode = TD_FALSE; ret = sample_aibnr_load_model(&model_info[1], &model_id[1], model_file); // if (ret != TD_SUCCESS) // { // goto unload; // } } return TD_SUCCESS; unload: sample_aibnr_unload_model(&model_info[0], model_id[0]); return TD_FAILURE;} static td_s32 sample_aibnr_start(ot_vi_pipe vi_pipe, ot_size in_size, ot_aibnr_model *model_info, td_s32 *model_id, td_s32 model_size, sample_aibnr_param *aibnr_param){ td_s32 ret = ss_mpi_aibnr_init(); ot_aibnr_cfg cfg; td_s32 i; if (ret != TD_SUCCESS) { sample_print("ss_mpi_aibnr_init error(%#x)\n", ret); return ret; } // 加载 aibnr模型文件 ret = sample_aibnr_load(in_size, model_info, model_id, aibnr_param); if (ret != TD_SUCCESS) { sample_print("sample_aibnr_load error(%#x)\n", ret); goto deinit; } cfg.ref_mode = aibnr_param->ref_mode; /* ref mode NORM: need reference frame; NONE: no reference frame */ ret = ss_mpi_aibnr_set_cfg(vi_pipe, &cfg); if (ret != TD_SUCCESS) { sample_print("ss_mpi_aibnr_set_alg_cfg error(%#x)\n", ret); goto unload_model; } usleep(100000); // int c; // printf("请输入一个字符:"); // c = getchar(); // 读取用户输入的第一个字符 // printf("你输入的字符是:%c\n", (char)c); // sample_get_char("enable"); // 只是获取输入的符号 ret = ss_mpi_aibnr_enable(vi_pipe); // 底层接口 if (ret != TD_SUCCESS) { sample_print("ss_mpi_aibnr_enable error(%#x)\n", ret); goto unload_model; } ret = sample_aibnr_set_attr(vi_pipe, aibnr_param); if (ret != TD_SUCCESS) { sample_print("sample_aibnr_set_attr error(%#x)\n", ret); goto aibnr_disable; } return ret; aibnr_disable: ss_mpi_aibnr_disable(vi_pipe);unload_model: for (i = 0;i pipe_info[vi_pipe].attach_pool != OT_VB_INVALID_POOL_ID) { ss_mpi_vb_destroy_pool(vi_cfg->pipe_info[vi_pipe].attach_pool); }} static td_void sample_aibnr_stop_vi(ot_vi_pipe vi_pipe, const sample_vi_cfg *vi_cfg){ sample_comm_vi_stop_vi(vi_cfg); sample_aibnr_deinit_aiisp_pool(vi_pipe, vi_cfg); sample_comm_sys_exit();} static td_s32 sample_aibnr_init_aiisp_pool(ot_size *in_size, td_u32 vb_cnt){ td_s32 blk_size; ot_vb_pool vb_pool; ot_vb_pool_cfg vb_pool_cfg = {0}; blk_size = ot_aibnr_get_pic_buf_size(in_size->width, in_size->height); vb_pool_cfg.blk_size = blk_size; vb_pool_cfg.blk_cnt = vb_cnt; vb_pool_cfg.remap_mode = OT_VB_REMAP_MODE_NONE; vb_pool = ss_mpi_vb_create_pool(&vb_pool_cfg); if (vb_pool == OT_VB_INVALID_POOL_ID) { sample_print("aibnr create user pool failed!\n"); return OT_VB_INVALID_POOL_ID; } #ifdef SAMPLE_MEM_SHARE_ENABLE ss_mpi_vb_pool_share_all(vb_pool);#endif return vb_pool;} static td_void sample_aibnr_set_vpss_crop(ot_vpss_grp grp, ot_size *in_size){ td_s32 ret; ot_vpss_crop_info crop_info = {0}; td_u32 crop_pixel = 8; crop_info.enable = TD_TRUE; crop_info.crop_mode = OT_COORD_ABS; crop_info.crop_rect.x = crop_pixel; crop_info.crop_rect.y = crop_pixel; crop_info.crop_rect.width = in_size->width - crop_pixel; crop_info.crop_rect.height = in_size->height - crop_pixel; ret = ss_mpi_vpss_set_grp_crop(grp, &crop_info); if (ret != TD_SUCCESS) { sample_print("ss_mpi_vpss_set_grp_crop failed!\n"); }} static td_s32 sample_venc_get_enc_size(ot_pic_size *pic_size, sample_venc_param *enc_param){ td_s32 i; td_s32 ret; for (i = 0; i venc_chn_num && i enc_size[i])); if (ret != TD_SUCCESS) { sample_print("sample_comm_sys_get_pic_size failed!\n"); return ret; } } return TD_SUCCESS;} static td_s32 sample_aibnr_start_vi(ot_vi_pipe vi_pipe, sample_vi_cfg *vi_cfg, ot_size *in_size, td_u32 vb_cnt){ td_s32 ret; sample_vi_pipe_info *pipe_info = &vi_cfg->pipe_info[vi_pipe]; if (sample_aiisp_sys_init(in_size, VB_AIBNR_COMMON_VB_CNT) != TD_SUCCESS) { sample_print("sample_aiisp_sys_init failed.\n"); return TD_FAILURE; } /* aiisp route use attach pool */ pipe_info->attach_pool = sample_aibnr_init_aiisp_pool(&pipe_info->pipe_attr.size, vb_cnt); if (pipe_info->attach_pool == OT_VB_INVALID_POOL_ID) { goto sys_exit; } ret = sample_comm_vi_start_vi(vi_cfg); if (ret != TD_SUCCESS) { sample_print("start vi failed.\n"); goto denit_vb_pool; } return TD_SUCCESS; denit_vb_pool: ss_mpi_vb_destroy_pool(pipe_info->attach_pool);sys_exit: sample_comm_sys_exit(); return TD_FAILURE;} static td_s32 sample_aibnr_set_blc(ot_vi_pipe vi_pipe, sample_sns_type sns_type){ td_s32 i, j, ret; ot_isp_black_level_attr black_level_attr; ret = ss_mpi_isp_get_black_level_attr(vi_pipe, &black_level_attr); if (ret != TD_SUCCESS) { sample_print("ss_mpi_isp_get_black_level_attr failed.\n"); return TD_FAILURE; } black_level_attr.user_black_level_en = TD_TRUE; for (i = 0; i pipe_info[vi_pipe].set_early_end_mode = TD_TRUE; vi_cfg->pipe_info[vi_pipe].pipe_attr.compress_mode = OT_COMPRESS_MODE_NONE; vi_cfg->pipe_info[vi_pipe].pipe_attr.pixel_format = OT_PIXEL_FORMAT_RGB_BAYER_12BPP; /* 12fps */ vi_cfg->pipe_info[vi_pipe].isp_info.isp_pub_attr.frame_rate = dst_fps;} static td_s32 sample_aibnr_check_support(ot_vi_pipe vi_pipe, sample_aibnr_param *aibnr_param){ if (aibnr_param->is_wdr_mode == TD_TRUE) { if (aibnr_param->is_blend != TD_FALSE) { sample_print("normal_blend must be false in wdr mode\n"); return TD_FAILURE; } if (vi_pipe >= OT_VI_MAX_PHYS_PIPE_NUM) { sample_print("vi_pipe must be phy pipe in wdr mode\n"); return TD_FAILURE; } } /* bnr_bypass must be false when attr->enable is false */ /* blend must be false when bnr_bypass is true */ /* vi must be offline */ return TD_SUCCESS;} // 这里真正开始调 aiisptd_s32 sample_aibnr(sample_aibnr_param *aibnr_param){ td_s32 ret = TD_FAILURE; sample_vi_cfg vi_cfg = {0}; sample_sns_type sns_type = SC500AI_MIPI_5M_30FPS_10BIT; // sample_sns_type sns_type = SENSOR0_TYPE; const td_u32 vb_cnt = (aibnr_param->is_pro == TD_TRUE) ? VB_AIBNR_TNR_CNT : VB_AIBNR_LINE_CNT; const ot_vi_pipe vi_pipe = aibnr_param->is_wdr_mode ? 1 : 0; ot_vi_pipe master_pipe = 0; const ot_vi_chn vi_chn = 0; ot_vpss_grp vpss_grp[1] = {0}; ot_size in_size = {0}; ot_aibnr_model model_info[2] = {0}; td_s32 model_id[2] = {-1, -1}; td_s32 model_size = (td_s32)(sizeof(model_id) / sizeof(td_s32)); // ot_vpss_grp vpss_grp = 0; if (sample_aibnr_check_support(vi_pipe, aibnr_param) != TD_SUCCESS) { return TD_FAILURE; } sample_aiisp_get_default_cfg(sns_type, vi_pipe, &in_size, &vi_cfg); sample_aibnr_update_cfg(vi_pipe, &vi_cfg, aibnr_param->is_pro); // 开始 vi if (sample_aibnr_start_vi(vi_pipe, &vi_cfg, &in_size, vb_cnt) != TD_SUCCESS) { return TD_FAILURE; } // sample_comm_vi_bind_vpss(master_pipe, 0, vpss_grp, 0); // sample_venc是这样写的,这样写会有报错 log sample_comm_vi_bind_vpss(master_pipe, vi_chn, vpss_grp[0], 0); if (sample_aiisp_start_vpss(vpss_grp[0], &in_size) != TD_SUCCESS) // 这样使用不会报错。这里将 vi的流绑定给 vpss_grp[0]。确实只需将 vpss grp0的流绑定给 vpss_chn就好 { goto stop_vi; } // sample_aibnr_set_vpss_crop(vpss_grp, &in_size); sample_aibnr_set_vpss_crop(vpss_grp[0], &in_size); // 只对 vpss_grp[0]做裁剪 printf("\n\nsizeof(vpss_grp) / sizeof(vpss_grp) is %d\n\n", sizeof(vpss_grp) / sizeof(vpss_grp)); if (sample_aiisp_start_venc_bind(vpss_grp, sizeof(vpss_grp) / sizeof(vpss_grp), &in_size) != TD_SUCCESS) // // if (sample_aiisp_start_venc_bind(vpss_grp, 2, &in_size) != TD_SUCCESS) // 这里涉及到创建 venc_chn // if (sample_aiisp_start_venc_bind(vpss_grp, sizeof(vpss_grp) / sizeof(vpss_grp[0]), &in_size) != TD_SUCCESS) // { goto stop_vpss; } // 通过 VI、VPSS模块获取原始视频帧; // 在 VENC中创建两个编码通道,绑定统一 VI、VPSS输入源 // 分别配置两路通道的编码参数 if (sample_aibnr_set_blc(master_pipe, sns_type) != TD_SUCCESS) { goto stop_venc_and_vo; } if (sample_aibnr_start(vi_pipe, in_size, model_info, model_id, model_size, aibnr_param) != TD_SUCCESS) { goto stop_venc_and_vo; } if (sample_aiisp_set_long_frame_mode(master_pipe, aibnr_param->is_wdr_mode) != TD_SUCCESS) { goto stop_aibnr; } sample_get_char("disable"); ret = TD_SUCCESS; stop_aibnr: sample_aibnr_stop(vi_pipe, model_info, model_id, model_size); // sample_get_char("exit"); usleep(100000); stop_venc_and_vo: // sample_aiisp_stop_venc_and_unbind(vpss_grp, sizeof(vpss_grp) / sizeof(vpss_grp)); sample_aiisp_stop_venc_and_unbind(vpss_grp, sizeof(vpss_grp) / sizeof(vpss_grp[0]));stop_vpss: // sample_aiisp_stop_vpss(vpss_grp); sample_aiisp_stop_vpss(vpss_grp[0]);stop_vi: // sample_comm_vi_un_bind_vpss(master_pipe, vi_chn, vpss_grp, 0); sample_comm_vi_un_bind_vpss(master_pipe, vi_chn, vpss_grp[0], 0); sample_aibnr_stop_vi(vi_pipe, &vi_cfg); return ret;}
sample_aiisp_common.c文件
// sample_aiisp_common.c #include #include #include "sample_aiisp_common.h" #define VENC_WIDTH 3840#define VENC_HEIGTH 2160 static sample_comm_venc_chn_param g_venc_chn_param = { .frame_rate = 30, /* 30 is a number */ .stats_time = 2, /* 2 is a number */ .gop = 60, /* 60 is a number */ .venc_size = {VENC_WIDTH, VENC_HEIGTH}, .size = -1, .profile = 0, .is_rcn_ref_share_buf = TD_FALSE, .gop_attr = { .gop_mode = OT_VENC_GOP_MODE_NORMAL_P, .normal_p = {2}, }, // .type = OT_PT_H265, .type = OT_PT_H264, .rc_mode = SAMPLE_RC_CBR,}; static sample_comm_venc_chn_param g_venc_chn_param_small_chn = { .frame_rate = 30, /* 30 is a number */ .stats_time = 2, /* 2 is a number */ .gop = 60, /* 60 is a number */ .venc_size = {720, 480}, .size = -1, .profile = 0, .is_rcn_ref_share_buf = TD_FALSE, .gop_attr = { .gop_mode = OT_VENC_GOP_MODE_NORMAL_P, .normal_p = {2}, }, // .type = OT_PT_H265, .type = OT_PT_H264, .rc_mode = SAMPLE_RC_CBR,}; volatile sig_atomic_t g_sig_flag = 0; td_void sample_aiisp_handle_sig(td_s32 signo){ if (signo == SIGINT || signo == SIGTERM) { g_sig_flag = 1; }} td_void sample_get_char(td_char *s){ if (g_sig_flag == 1) { return; } printf("---------------press any key to %s!---------------\n", s); (td_void)getchar();} sig_atomic_t sample_aiisp_get_sig(td_void){ return g_sig_flag;} static td_s32 sample_aiisp_check_fp(FILE *fp, td_char *model_file){ if (fp == TD_NULL) { sample_print("open file err!\n"); return TD_FAILURE; } printf("open %s success\n", model_file); return TD_SUCCESS;} td_s32 sample_aiisp_load_mem(ot_aiisp_mem_info *mem, td_char *model_file){ td_s32 ret; FILE *fp = TD_NULL; td_char path[PATH_MAX + 1] = {0}; /* Get model file size */ sample_aiisp_check_exps_return((strlen(model_file) > PATH_MAX) || realpath(model_file, path) == TD_NULL); fp = fopen(path, "rb"); if (sample_aiisp_check_fp(fp, model_file) != TD_SUCCESS) { return TD_FAILURE; } ret = fseek(fp, 0L, SEEK_END); if (ret != TD_SUCCESS) { sample_print("fseek end failed!\n"); goto fail_0; } mem->size = ftell(fp); if (mem->size phys_addr), &(mem->virt_addr), "./aibnr_model", TD_NULL, mem->size); if (ret != TD_SUCCESS) { sample_print("malloc mmz failed!\n"); goto fail_0; } ret = fread(mem->virt_addr, mem->size, 1, fp); if (ret != 1) { sample_print("read model file failed!\n"); goto fail_1; } ret = fclose(fp); if (ret != 0) { sample_print("close file error\n"); } return TD_SUCCESS; fail_1: ss_mpi_sys_mmz_free(mem->phys_addr, mem->virt_addr); mem->phys_addr = 0; mem->virt_addr = TD_NULL;fail_0: (td_void)fclose(fp); return TD_FAILURE;} td_void sample_aiisp_unload_mem(ot_aiisp_mem_info *param_mem){ if ((param_mem->phys_addr != 0) && (param_mem->virt_addr != TD_NULL)) { (td_void)ss_mpi_sys_mmz_free(param_mem->phys_addr, param_mem->virt_addr); }} static td_void sample_aiisp_get_default_vb_config(const ot_size *size, ot_vb_cfg *vb_cfg, td_u32 vb_cnt){ ot_vb_calc_cfg calc_cfg = {0}; ot_pic_buf_attr buf_attr = {0}; (td_void)memset_s(vb_cfg, sizeof(ot_vb_cfg), 0, sizeof(ot_vb_cfg)); vb_cfg->max_pool_cnt = 128; /* 128 blks */ buf_attr.width = size->width; buf_attr.height = size->height; buf_attr.align = OT_DEFAULT_ALIGN; buf_attr.bit_width = OT_DATA_BIT_WIDTH_8; buf_attr.pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420; buf_attr.compress_mode = OT_COMPRESS_MODE_NONE; buf_attr.video_format = OT_VIDEO_FORMAT_LINEAR; ot_common_get_pic_buf_cfg(&buf_attr, &calc_cfg); vb_cfg->common_pool[0].blk_size = calc_cfg.vb_size; vb_cfg->common_pool[0].blk_cnt = vb_cnt;} #ifdef SAMPLE_MEM_SHARE_ENABLEstatic td_void sample_aiisp_init_mem_share(td_void){ td_u32 i; ot_vb_common_pools_id pools_id = {0}; if (ss_mpi_vb_get_common_pool_id(&pools_id) != TD_SUCCESS) { sample_print("get common pool_id failed!\n"); return; } for (i = 0; i width; grp_attr.max_height = in_size->height; sample_comm_vpss_get_default_chn_attr(&vpss_chn_attr.chn_attr[0]); vpss_chn_attr.chn_attr[0].width = in_size->width; vpss_chn_attr.chn_attr[0].height = in_size->height; // 将 vpss grp0绑定到 vpss_chn1上 // 这里增加一组 将vi数据源绑定给 vpss vpss_chn_attr.chn_enable[1] = TD_TRUE; vpss_chn_attr.chn_array_size = OT_VPSS_MAX_PHYS_CHN_NUM; vpss_chn_attr.chn_attr[1].width = 720; vpss_chn_attr.chn_attr[1].height = 480; vpss_chn_attr.chn_attr[1].pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420; sample_comm_vpss_get_default_grp_attr(&grp_attr); grp_attr.max_width = 720; grp_attr.max_height = 480; // 这里这样使用,没问题 vpss_chn_attr.chn_attr[1].mirror_en = TD_FALSE; vpss_chn_attr.chn_attr[1].flip_en = TD_FALSE; vpss_chn_attr.chn_attr[1].border_en = TD_FALSE; vpss_chn_attr.chn_attr[1].width = 720; vpss_chn_attr.chn_attr[1].height = 480; vpss_chn_attr.chn_attr[1].depth = 0; vpss_chn_attr.chn_attr[1].chn_mode = OT_VPSS_CHN_MODE_USER; vpss_chn_attr.chn_attr[1].video_format = OT_VIDEO_FORMAT_LINEAR; vpss_chn_attr.chn_attr[1].dynamic_range = OT_DYNAMIC_RANGE_SDR8; vpss_chn_attr.chn_attr[1].pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420; vpss_chn_attr.chn_attr[1].compress_mode = OT_COMPRESS_MODE_NONE; vpss_chn_attr.chn_attr[1].aspect_ratio.mode = OT_ASPECT_RATIO_NONE; vpss_chn_attr.chn_attr[1].frame_rate.src_frame_rate = -1; vpss_chn_attr.chn_attr[1].frame_rate.dst_frame_rate = -1; // 这样使用,同样没问题 // sample_comm_vpss_get_default_chn_attr(&vpss_chn_attr.chn_attr[1]); ret = sample_common_vpss_start(grp, &grp_attr, &vpss_chn_attr); if (ret != TD_SUCCESS) { return ret; } return TD_SUCCESS;} td_s32 sample_aiisp_start_venc(ot_venc_chn venc_chn[], td_u32 venc_chn_len, td_u32 chn_num, ot_size *size){ td_s32 i; td_s32 ret; g_venc_chn_param.venc_size.width = size->width; g_venc_chn_param.venc_size.height = size->height; g_venc_chn_param.size = sample_comm_sys_get_pic_enum(size); g_venc_chn_param_small_chn.venc_size.width = 720; g_venc_chn_param_small_chn.venc_size.height = 480; // g_venc_chn_param_small_chn.size = sample_comm_sys_get_pic_enum(size); // 这个函数不能调用,调用后 venc_chn1通道没有流 for (i = 0; i = 0; i--) { sample_comm_venc_stop(venc_chn[i]); sample_comm_venc_stop(venc_chn[1]); } return TD_FAILURE;} // 这里就是重点了td_s32 sample_aiisp_start_venc_bind(ot_vpss_grp vpss_grp[], td_u32 grp_num, ot_size *in_size){ // grp_num应该等于1 td_u32 i; td_s32 ret; const ot_vpss_chn vpss_chn = 0; const ot_vpss_chn vpss_chn_1 = 1; // 添加一个 vpss_chn ot_venc_chn venc_chn[4] = {0, 1, 2, 3}; /* 4: max chn num, 0/1/2/3 chn id */ // 函数作用是设置 venc_chn的属性。将 vpss的流绑定给 venc ret = sample_aiisp_start_venc(venc_chn, 1, grp_num, in_size); // ret = sample_aiisp_start_venc(venc_chn, sizeof(venc_chn) / sizeof(ot_venc_chn), grp_num, in_size); if (ret != TD_SUCCESS) { goto start_venc_failed; } for (i = 0; i pipe_info[vi_pipe].pipe_attr.frame_rate_ctrl.src_frame_rate = 30; /* 30fps */ vi_cfg->pipe_info[vi_pipe].pipe_attr.frame_rate_ctrl.dst_frame_rate = 5; /* 5fps */#endif}
上述操作,可以多一路 venc_chn1的通道流
工程代码
通过网盘分享的文件:aiisp_easy_rtsp.zip
链接: https://pan.baidu.com/s/1ZNkiUpKQgV1cgB0bfrclSA 提取码: h4ib
--来自百度网盘超级会员v5的分享