基于sample_aiisp例子,创建3路编码流,记录

基于sample_aiisp例子,创建3路编码流,记录

基于 aiisp已有两路编码流

首先vpss grp0有视频流

已经有两路视频流能推出来

创第3路编码流思路为

将 vpss grp0又绑定给 vpss_chn2

vpss_chn1又绑定给 venc_chn2

这样我们就创建了第3路视频流。

这里思路完全正确 可以实现

整个工程代码,在底部链接获取

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==0){//发送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;


    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);  // 适用弱光环境
            // ret = snprintf_s(model_file, max_len, max_len - 1, "./aibnr_model/aibnr_model_%dx%d_pro.bin", in_size.width, in_size.height);       // 适用于 2688x1520@5fps
            
            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_JPEG,
    // .type                 = OT_PT_MJPEG,
    .type                 = OT_PT_H264,
    .rc_mode              = SAMPLE_RC_CBR,
};

static sample_comm_venc_chn_param g_venc_chn_param_small_chn_2 = {
    .frame_rate           = 30, /* 30 is a number */
    .stats_time           = 2,  /* 2 is a number */
    .gop                  = 60, /* 60 is a number */
    .venc_size            = {320, 240},
    .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_JPEG,
    // .type                 = OT_PT_MJPEG,
    // .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]);
    vpss_chn_attr.chn_attr[1].width  = 720;
    vpss_chn_attr.chn_attr[1].height = 480;


    // 将 vpss grp0绑定到 vpss_chn2上
    // 这里增加一组 将vi数据源绑定给 vpss
    vpss_chn_attr.chn_enable[2] = TD_TRUE;
    vpss_chn_attr.chn_array_size = OT_VPSS_MAX_PHYS_CHN_NUM;
    vpss_chn_attr.chn_attr[2].width  = 320;
    vpss_chn_attr.chn_attr[2].height = 240;
    vpss_chn_attr.chn_attr[2].pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
    sample_comm_vpss_get_default_grp_attr(&grp_attr);
    sample_comm_vpss_get_default_chn_attr(&vpss_chn_attr.chn_attr[2]);
    vpss_chn_attr.chn_attr[2].width  = 320;
    vpss_chn_attr.chn_attr[2].height = 240;



    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通道没有流


    // venc_chn2
    g_venc_chn_param_small_chn_2.venc_size.width        = 320;
    g_venc_chn_param_small_chn_2.venc_size.height       = 240;
    // 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;
        }

        // venc_chn_2分辨率绑定vpss视频源
        ret = sample_comm_venc_start(venc_chn[2], &g_venc_chn_param_small_chn_2);
        if (ret != TD_SUCCESS) {
            goto exit;
        }
    }

    // 获取视频流
    // 改为3,就创建了3路码流。
    ret = sample_comm_venc_start_get_stream(venc_chn, 3);

    // // 改为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
    const ot_vpss_chn vpss_chn_2 = 1;   // 添加一个 vpss_chn2

    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]);


        sample_comm_vpss_bind_venc(vpss_grp[0], vpss_chn_2, venc_chn[2]);
    }

    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_chn2的通道流

工程代码

通过网盘分享的文件:aiisp_three_video_chn.zip

链接: https://pan.baidu.com/s/1sfxKs6fcMN4in7l_kI4SNg 提取码: kanv

--来自百度网盘超级会员v5的分享

相关推荐
小白跃升坊3 小时前
基于1Panel的AI运维
linux·运维·人工智能·ai大模型·教学·ai agent
跃渊Yuey3 小时前
【Linux】线程同步与互斥
linux·笔记
舰长1153 小时前
linux 实现文件共享的实现方式比较
linux·服务器·网络
zmjjdank1ng4 小时前
Linux 输出重定向
linux·运维
路由侠内网穿透.4 小时前
本地部署智能家居集成解决方案 ESPHome 并实现外部访问( Linux 版本)
linux·运维·服务器·网络协议·智能家居
VekiSon4 小时前
Linux内核驱动——基础概念与开发环境搭建
linux·运维·服务器·c语言·arm开发
zl_dfq4 小时前
Linux 之 【进程信号】(signal、kill、raise、abort、alarm、Core Dump核心转储机制)
linux
Ankie Wan5 小时前
cgroup(Control Group)是 Linux 内核提供的一种机制,用来“控制、限制、隔离、统计”进程对系统资源的使用。
linux·容器·cgroup·lxc
skywalk81635 小时前
尝试在openi启智社区的dcu环境安装ollama最新版0.15.2(失败)
linux·运维·服务器·ollama
zhengfei6116 小时前
AutoPentestX – Linux 自动化渗透测试和漏洞报告工具
linux·运维·自动化