3516cv610在sample_aiisp上多创一路编码流,方法
首先确保 vpss grp0有视频流
最好保证 已经有一路视频流能推出来
多创一路编码流思路为
将 vpss grp0又绑定给 vpss_chn1
vpss_chn1有绑定给 venc_chn1
这样我们就多创了一路视频流。
这里思路完全正确 可以实现
整个工程代码,在底部链接获取
aiisp需要对 sc500ai寄存器进行操作
// 改变 sc500ai的bayer格式
// 改变为 RGGB的格式
3211, 0x05
3213, 0x05
sdk说明
sdk_010打AOV的补丁
硬件
cv610_20s+sc500ai
下面是 aiisp的例子,多创建一路编码流
// sample_aiisp.c
#include <signal.h>
#include "sample_comm.h"
#include "sample_ipc.h"
#include "sample_aibnr.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <sys/time.h>
#include <sys/select.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <math.h>
#include <unistd.h>
#include <signal.h>
#include <sys/prctl.h>
#include <limits.h>
#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 <index> \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 < pools_id.pool_cnt; ++i) {
if (ss_mpi_vb_pool_share(pools_id.pool[i], pid) != TD_SUCCESS) {
sample_print("vb pool share failed!\n");
return TD_FAILURE;
}
}
#endif
ret = sample_comm_vi_get_isp_run_state(isp_states, OT_VI_MAX_PIPE_NUM);
if (ret != TD_SUCCESS) {
sample_print("get isp states fail\n");
return TD_FAILURE;
}
for (i = 0; i < OT_VI_MAX_PIPE_NUM; i++) {
if (!isp_states[i]) {
continue;
}
ret = ss_mpi_isp_mem_share(i, pid);
if (ret != TD_SUCCESS) {
sample_print("ss_mpi_isp_mem_share vi_pipe %u, pid %d fail\n", i, pid);
}
}
return TD_SUCCESS;
}
static td_void sample_aiisp_msg_proc_vb_pool_unshare(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) {
for (i = 0; i < pools_id.pool_cnt; ++i) {
ret = ss_mpi_vb_pool_unshare(pools_id.pool[i], pid);
if (ret != TD_SUCCESS) {
sample_print("ss_mpi_vb_pool_unshare vi_pipe %u, pid %d fail\n", pools_id.pool[i], pid);
}
}
}
#endif
ret = sample_comm_vi_get_isp_run_state(isp_states, OT_VI_MAX_PIPE_NUM);
if (ret != TD_SUCCESS) {
sample_print("get isp states fail\n");
return;
}
for (i = 0; i < OT_VI_MAX_PIPE_NUM; i++) {
if (!isp_states[i]) {
continue;
}
ret = ss_mpi_isp_mem_unshare(i, pid);
if (ret != TD_SUCCESS) {
sample_print("ss_mpi_isp_mem_unshare vi_pipe %u, pid %d fail\n", i, pid);
}
}
}
static td_s32 sample_aiisp_ipc_msg_proc(const sample_ipc_msg_req_buf *msg_req_buf,
td_bool *is_need_fb, sample_ipc_msg_res_buf *msg_res_buf)
{
td_s32 ret;
if (msg_req_buf == TD_NULL || is_need_fb == TD_NULL) {
return TD_FAILURE;
}
/* need feedback default */
*is_need_fb = TD_TRUE;
switch ((sample_msg_type)msg_req_buf->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, "./") < 0) {
free(stream->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) < 0) {
free(stream->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 < stream->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 < list.num && i < OT_AIISP_MAX_MODEL_NUM; i++) {
printf("id:%d is wdr:%d\n", list.info[i].id, list.info[i].is_wdr_mode);
}
//---------------------aibnr模型0
// sample_get_char("select model 0");
model_attr.op_type = OT_OP_MODE_MANUAL;
model_attr.manual_id = 0;
ss_mpi_aibnr_set_model_attr(0, &model_attr);
//---------------------------aibnr模型1
// sample_get_char("select model 1");
// model_attr.op_type = OT_OP_MODE_MANUAL;
// model_attr.manual_id = 1;
// ss_mpi_aibnr_set_model_attr(0, &model_attr);
//-------------------------模型auto mode
// sample_get_char("set auto mode");
// model_attr.op_type = OT_OP_MODE_AUTO;
// for (td_u32 i = 0; i < OT_AIISP_AUTO_ISO_NUM; i++) {
// model_attr.auto_id[i] = 1;
// if (i < 0x2) {
// model_attr.auto_id[i] = 0;
// }
// }
// ss_mpi_aibnr_set_model_attr(0, &model_attr);
return TD_SUCCESS;
}
static td_s32 sample_aibnr_set_attr(ot_vi_pipe vi_pipe, sample_aibnr_param *aibnr_param)
{
td_s32 ret;
ot_aibnr_attr aibnr_attr;
ret = ss_mpi_aibnr_get_attr(vi_pipe, &aibnr_attr);
if (ret != TD_SUCCESS) {
sample_print("ss_mpi_aibnr_get_attr error\n");
return ret;
}
aibnr_attr.enable = TD_TRUE;
aibnr_attr.bnr_bypass = TD_FALSE;
aibnr_attr.blend = aibnr_param->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 < 0) {
printf("set name failed!\n");
return ret;
}
model_info[0].model.preempted_en = TD_FALSE;
model_info[0].model.image_size.width = in_size.width;
model_info[0].model.image_size.height = in_size.height;
model_info[0].is_wdr_mode = aibnr_param->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 < 0) {
printf("set name failed!\n");
goto unload;
}
model_info[1].model.preempted_en = TD_FALSE;
model_info[1].model.image_size.width = in_size.width;
model_info[1].model.image_size.height = in_size.height;
model_info[1].is_wdr_mode = aibnr_param->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 < model_size; i++) {
if (model_id[i] != -1) {
sample_aibnr_unload_model(&model_info[i], model_id[i]);
}
}
deinit:
ss_mpi_aibnr_exit();
return ret;
}
static td_s32 sample_aibnr_unload(ot_vi_pipe vi_pipe, ot_aibnr_model *model, td_s32 *model_id, td_s32 model_size)
{
td_s32 return_value = TD_SUCCESS;
td_s32 ret;
td_s32 i;
for (i = 0; i < model_size; i++) {
if (model_id[i] != -1) {
ret = sample_aibnr_unload_model(&model[i], model_id[i]);
if (ret != TD_SUCCESS) {
return_value = ret;
}
}
}
return return_value;
}
static td_s32 sample_aibnr_stop(ot_vi_pipe vi_pipe, ot_aibnr_model *model, td_s32 *model_id, td_s32 model_size)
{
td_s32 ret1;
td_s32 ret2;
ret1 = ss_mpi_aibnr_disable(vi_pipe);
if (ret1 != TD_SUCCESS) {
sample_print("ss_mpi_aibnr_disable false error(%#x)\n", ret1);
}
ret2 = sample_aibnr_unload(vi_pipe, model, model_id, model_size);
if (ret2 != TD_SUCCESS) {
sample_print("sample_aibnr_unload_exit false error(%#x)\n", ret2);
}
ss_mpi_aibnr_exit();
if ((ret1 != TD_SUCCESS) || (ret2 != TD_SUCCESS)) {
return TD_FAILURE;
}
return TD_SUCCESS;
}
static td_void sample_aibnr_deinit_aiisp_pool(ot_vi_pipe vi_pipe, const sample_vi_cfg *vi_cfg)
{
if (vi_cfg->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 < enc_param->venc_chn_num && i < CHN_NUM_MAX; i++) {
ret = sample_comm_sys_get_pic_size(pic_size[i], &(enc_param->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 < OT_ISP_WDR_MAX_FRAME_NUM; i++) {
for (j = 0; j < OT_ISP_BAYER_CHN_NUM; j++) {
black_level_attr.user_black_level[i][j] = 1200; /* user_black_level of aibnr default as 1200 */
}
}
ret = ss_mpi_isp_set_black_level_attr(vi_pipe, &black_level_attr);
if (ret != TD_SUCCESS) {
sample_print("ss_mpi_isp_set_black_level_attr failed.\n");
return TD_FAILURE;
}
return TD_SUCCESS;
}
static td_void sample_aibnr_update_cfg(ot_vi_pipe vi_pipe, sample_vi_cfg *vi_cfg, td_bool is_pro)
{
td_u32 dst_fps = (is_pro == TD_TRUE) ? 5 : 12; /* 5\12fps */
vi_cfg->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;
}
// 这里真正开始调 aiisp
td_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 <signal.h>
#include <limits.h>
#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 <= 0) {
sample_print("ftell failed!\n");
goto fail_0;
}
ret = fseek(fp, 0L, SEEK_SET);
if (ret != TD_SUCCESS) {
sample_print("fseek set failed!\n");
goto fail_0;
}
/* malloc model file mem */
ret = ss_mpi_sys_mmz_alloc(&(mem->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_ENABLE
static 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 < pools_id.pool_cnt; ++i) {
ss_mpi_vb_pool_share_all(pools_id.pool[i]);
}
}
#endif
td_s32 sample_aiisp_sys_init(ot_size *in_size, td_u32 vb_cnt)
{
td_s32 ret;
ot_vb_cfg vb_cfg = {0};
td_u32 supplement_config;
ot_vi_vpss_mode_type mode_type = OT_VI_OFFLINE_VPSS_ONLINE;
sample_aiisp_get_default_vb_config(in_size, &vb_cfg, vb_cnt);
supplement_config = OT_VB_SUPPLEMENT_BNR_MOT_MASK;
ret = sample_comm_sys_init_with_vb_supplement(&vb_cfg, supplement_config);
if (ret != TD_SUCCESS) {
return TD_FAILURE;
}
#ifdef SAMPLE_MEM_SHARE_ENABLE
sample_aiisp_init_mem_share();
#endif
ret = sample_comm_vi_set_vi_vpss_mode(mode_type, OT_VI_AIISP_MODE_DEFAULT);
if (ret != TD_SUCCESS) {
return TD_FAILURE;
}
return TD_SUCCESS;
}
td_s32 sample_aiisp_start_vpss(ot_vpss_grp grp, ot_size *in_size)
{
td_s32 ret;
ot_vpss_grp_attr grp_attr = {0};
sample_vpss_chn_attr vpss_chn_attr = {0};
vpss_chn_attr.chn_enable[0] = TD_TRUE;
vpss_chn_attr.chn_array_size = OT_VPSS_MAX_PHYS_CHN_NUM;
sample_comm_vpss_get_default_grp_attr(&grp_attr);
grp_attr.max_width = in_size->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 < (td_s32)chn_num && i < (td_s32)venc_chn_len; i++)
{
ret = sample_comm_venc_start(venc_chn[0], &g_venc_chn_param);
if (ret != TD_SUCCESS) {
goto exit;
}
// 小的 venc_chn分辨率绑定vpss视频源
ret = sample_comm_venc_start(venc_chn[1], &g_venc_chn_param_small_chn);
if (ret != TD_SUCCESS) {
goto exit;
}
}
// 获取视频流
// 改为2,就多创建了一路码流。是创了两个 h264文件,但 index=1是一直没打印的
ret = sample_comm_venc_start_get_stream(venc_chn, 2);
// ret = sample_comm_venc_start_get_stream(venc_chn, chn_num);
if (ret != TD_SUCCESS) {
goto exit;
}
return TD_SUCCESS;
exit:
for (i = i - 1; 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 < grp_num; i++)
{
// 经检验 i等于 0
sample_comm_vpss_bind_venc(vpss_grp[i], vpss_chn, venc_chn[i]);
// 这里需将 vpss_chn1绑定给 venc吗,需要
sample_comm_vpss_bind_venc(vpss_grp[0], vpss_chn_1, venc_chn[1]);
}
return TD_SUCCESS;
start_venc_failed:
return TD_FAILURE;
}
td_void sample_aiisp_stop_vpss(ot_vpss_grp grp)
{
td_bool chn_enable[OT_VPSS_MAX_PHYS_CHN_NUM] = {TD_TRUE, TD_FALSE, TD_FALSE};
sample_common_vpss_stop(grp, chn_enable, OT_VPSS_MAX_PHYS_CHN_NUM);
}
td_void sample_aiisp_stop_venc(ot_venc_chn venc_chn[], td_u32 venc_chn_len, td_u32 chn_num)
{
td_u32 i;
sample_comm_venc_stop_get_stream(chn_num);
for (i = 0; i < chn_num && i < venc_chn_len; i++) {
sample_comm_venc_stop(venc_chn[i]);
}
}
td_void sample_aiisp_stop_venc_and_unbind(ot_vpss_grp vpss_grp[], td_u32 grp_num)
{
td_u32 i;
const ot_vpss_chn vpss_chn = 0;
ot_venc_chn venc_chn[4] = {0, 1, 2, 3}; /* 4: max chn num, 0/1/2/3 chn id */
for (i = 0; i < grp_num; i++) {
sample_comm_vpss_un_bind_venc(vpss_grp[i], vpss_chn, venc_chn[i]);
}
sample_aiisp_stop_venc(venc_chn, sizeof(venc_chn) / sizeof(ot_venc_chn), grp_num);
}
td_s32 sample_aiisp_set_long_frame_mode(ot_vi_pipe vi_pipe, td_bool is_wdr_mode)
{
td_s32 ret;
ot_isp_exposure_attr exp_attr = {0};
ot_isp_wdr_fs_attr fswdr_attr = {0};
if (is_wdr_mode == TD_FALSE) {
return TD_SUCCESS;
}
sample_get_char("set long frame mode");
ret = ss_mpi_isp_get_exposure_attr(vi_pipe, &exp_attr);
if (ret != TD_SUCCESS) {
printf("ss_mpi_isp_get_exposure_attr error[0x%x]\n", ret);
return TD_FAILURE;
}
exp_attr.auto_attr.fswdr_mode = OT_ISP_FSWDR_LONG_FRAME_MODE;
ret = ss_mpi_isp_set_exposure_attr(vi_pipe, &exp_attr);
if (ret != TD_SUCCESS) {
printf("ss_mpi_isp_set_exposure_attr error[0x%x]\n", ret);
return TD_FAILURE;
}
ret = ss_mpi_isp_get_fswdr_attr(vi_pipe, &fswdr_attr);
if (ret != TD_SUCCESS) {
printf("ss_mpi_isp_get_fswdr_attr error[0x%x]\n", ret);
return TD_FAILURE;
}
fswdr_attr.wdr_merge_mode = OT_ISP_MERGE_WDR_MODE;
ret = ss_mpi_isp_set_fswdr_attr(vi_pipe, &fswdr_attr);
if (ret != TD_SUCCESS) {
printf("ss_mpi_isp_set_fswdr_attr error[0x%x]\n", ret);
return TD_FAILURE;
}
return ret;
}
td_void sample_aiisp_get_default_cfg(sample_sns_type sns_type, ot_vi_pipe vi_pipe,
ot_size *size, sample_vi_cfg *vi_cfg)
{
sample_comm_vi_get_size_by_sns_type(sns_type, size);
sample_comm_vi_get_default_vi_cfg(sns_type, vi_cfg);
#ifdef OT_FPGA
vi_cfg->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的分享