/* Copyright (c), 2001-2022, Shenshu Tech. Co., Ltd. */ #include #include #include #include #include #include #include "sample_comm.h" #include "loadbmp.h" #define VDA_WIDTH_ALIGN 16 #define VDA_HEIGHT_ALIGN 16 #define VDA_THREAD_ARRAY_LEN (2 * OT_VDEC_MAX_CHN_NUM) #define VDA_SAMPLE_MAX_WIDTH 3840 #define VDA_SAMPLE_MAX_HEIGHT 2160 #define VDA_VPSS_CHN OT_VPSS_CHN0 pthread_t g_vdec_thread[VDA_THREAD_ARRAY_LEN]; td_bool g_exit = TD_FALSE; static int g_sample_vda_exit = 0; #define SAMPLE_VDA_STREAM_NAME "D1chn25.h264" #define SAMPLE_VDA_STREAM_PATH "./" /* Description : to process abnormal case */ void sample_vda_handle_sig(td_s32 signo) { if (signo == SIGINT || signo == SIGTERM) { g_sample_vda_exit = 1; } } static int sample_vda_getchar(td_void) { int c; if (g_sample_vda_exit == 1) { sample_common_vda_handle_sig(); sample_comm_sys_exit(); printf("\033[0;31mprogram exit abnormally!\033[0;39m\n"); exit(-1); } c = getchar(); if (g_sample_vda_exit == 1) { sample_common_vda_handle_sig(); sample_comm_sys_exit(); printf("\033[0;31mprogram exit abnormally!\033[0;39m\n"); exit(-1); } return c; } /* Description : show usage */ td_void sample_vda_usage(td_void) { printf("\n\n/************************************/\n"); printf("please choose the case which you want to run:\n"); printf("\t0: MD\n"); printf("\t1: OD\n"); printf("sample command:"); return; } static td_s32 sample_vda_init(ot_pic_size disp_pic_size, ot_size *disp_size, td_u32 vdec_chn_num) { td_s32 ret; ot_pic_buf_attr buf_attr = { 0 }; ot_vb_cfg vb_cfg; /* init SYS, init common VB */ ret = sample_comm_sys_get_pic_size(disp_pic_size, disp_size); if (ret != TD_SUCCESS) { sample_print("sys get pic size fail for %#x!\n", ret); return ret; } buf_attr.align = 0; buf_attr.bit_width = OT_DATA_BIT_WIDTH_8; buf_attr.compress_mode = OT_COMPRESS_MODE_NONE; buf_attr.height = disp_size->height; buf_attr.width = disp_size->width; buf_attr.pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420; (td_void)memset_s(&vb_cfg, sizeof(ot_vb_cfg), 0, sizeof(ot_vb_cfg)); vb_cfg.max_pool_cnt = 1; vb_cfg.common_pool[0].blk_cnt = 10 * vdec_chn_num; /* 10 : 10 vb per chn */ vb_cfg.common_pool[0].blk_size = ot_common_get_pic_buf_size(&buf_attr); ret = sample_comm_sys_init(&vb_cfg); if (ret != TD_SUCCESS) { sample_print("init sys fail for %#x!\n", ret); return ret; } return TD_SUCCESS; } td_void sample_vda_deinit(td_void) { sample_comm_vdec_exit_vb_pool(); sample_comm_sys_exit(); } static td_s32 sample_vda_init_vdec(sample_vdec_attr *sample_vdec, td_s32 max_vdec_chn, td_u32 vdec_chn_num) { td_s32 ret; td_u32 i; /* step1: init module VB or user VB(for VDEC) */ for (i = 0; (i < vdec_chn_num) && (i < max_vdec_chn); i++) { sample_vdec[i].type = OT_PT_H264; sample_vdec[i].width = VDA_SAMPLE_MAX_WIDTH; sample_vdec[i].height = VDA_SAMPLE_MAX_HEIGHT; sample_vdec[i].mode = OT_VDEC_SEND_MODE_FRAME; sample_vdec[i].sample_vdec_video.dec_mode = OT_VIDEO_DEC_MODE_IP; sample_vdec[i].sample_vdec_video.bit_width = OT_DATA_BIT_WIDTH_8; sample_vdec[i].sample_vdec_video.ref_frame_num = 2; /* 2 : reference frame number */ sample_vdec[i].display_frame_num = 2; /* display_frame number */ sample_vdec[i].frame_buf_cnt = sample_vdec[i].sample_vdec_video.ref_frame_num + sample_vdec[i].display_frame_num + 1; } ret = sample_comm_vdec_init_vb_pool(vdec_chn_num, &sample_vdec[0], OT_VDEC_MAX_CHN_NUM); if (ret != TD_SUCCESS) { sample_print("init mod common vb fail for %#x!\n", ret); return ret; } /* step2: start VDEC */ ret = sample_comm_vdec_start(vdec_chn_num, &sample_vdec[0], OT_VDEC_MAX_CHN_NUM); if (ret != TD_SUCCESS) { sample_print("start VDEC fail for %#x!\n", ret); goto vdec_stop; } return TD_SUCCESS; vdec_stop: sample_comm_vdec_exit_vb_pool(); return TD_FAILURE; } td_void sample_vda_deinit_vdec(td_u32 vdec_chn_num) { td_s32 ret; ret = sample_comm_vdec_stop(vdec_chn_num); if (ret != TD_SUCCESS) { sample_print("vdec stop fail for %#x!\n", ret); } } static td_s32 sample_vda_init_vpss(td_s32 vpss_grp_num, const ot_size *disp_size, td_bool chn_enable[], td_s32 vpss_chn_num) { td_s32 ret; td_s32 i; ot_vpss_chn_attr vpss_chn_attr[OT_VPSS_MAX_CHN_NUM] = { 0 }; ot_vpss_grp_attr vpss_grp_attr = { 0 }; /* start VPSS */ vpss_grp_attr.max_width = VDA_SAMPLE_MAX_WIDTH; vpss_grp_attr.max_height = VDA_SAMPLE_MAX_HEIGHT; vpss_grp_attr.frame_rate.src_frame_rate = -1; vpss_grp_attr.frame_rate.dst_frame_rate = -1; vpss_grp_attr.pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420; vpss_grp_attr.nr_en = TD_FALSE; vpss_grp_attr.dci_en = TD_FALSE; if (memset_s(chn_enable, vpss_chn_num * sizeof(td_bool), 0, vpss_chn_num * sizeof(td_bool)) != EOK) { return TD_FAILURE; } chn_enable[VDA_VPSS_CHN] = TD_TRUE; vpss_chn_attr[VDA_VPSS_CHN].width = disp_size->width; vpss_chn_attr[VDA_VPSS_CHN].height = disp_size->height; vpss_chn_attr[VDA_VPSS_CHN].chn_mode = OT_VPSS_CHN_MODE_USER; vpss_chn_attr[VDA_VPSS_CHN].compress_mode = OT_COMPRESS_MODE_NONE; vpss_chn_attr[VDA_VPSS_CHN].pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420; vpss_chn_attr[VDA_VPSS_CHN].frame_rate.src_frame_rate = -1; vpss_chn_attr[VDA_VPSS_CHN].frame_rate.dst_frame_rate = -1; vpss_chn_attr[VDA_VPSS_CHN].depth = 0; vpss_chn_attr[VDA_VPSS_CHN].mirror_en = TD_FALSE; vpss_chn_attr[VDA_VPSS_CHN].flip_en = TD_FALSE; vpss_chn_attr[VDA_VPSS_CHN].aspect_ratio.mode = OT_ASPECT_RATIO_NONE; for (i = 0; i < vpss_grp_num; i++) { ot_vpss_grp vpss_grp = i; ret = sample_common_vpss_start(vpss_grp, chn_enable, &vpss_grp_attr, vpss_chn_attr, OT_VPSS_MAX_CHN_NUM); if (ret != TD_SUCCESS) { sample_print("start VPSS fail for %#x!\n", ret); return TD_FAILURE; } } return TD_SUCCESS; } td_void sample_vda_deinit_vpss(const td_bool chn_enable[], td_u32 chn_array_size) { td_s32 ret; const ot_vpss_grp vpss_grp = 0; ret = sample_common_vpss_stop(vpss_grp, chn_enable, chn_array_size); if (ret != TD_SUCCESS) { sample_print("vpss grp %d stop fail for %#x!\n", vpss_grp, ret); } } static td_s32 sample_vda_init_vo(ot_pic_size disp_pic_size, const ot_size *disp_size, sample_vo_cfg *vo_config) { td_s32 ret; ot_vo_intf_sync intf_sync = OT_VO_OUT_1080P60; ot_vo_intf_type vo_intf_type = OT_VO_INTF_HDMI | OT_VO_INTF_VGA; vo_config->vo_dev = SAMPLE_VO_DEV_UHD; vo_config->vo_intf_type = vo_intf_type; vo_config->intf_sync = intf_sync; vo_config->pic_size = disp_pic_size; vo_config->bg_color = COLOR_RGB_BLUE; vo_config->dis_buf_len = 3; /* 3 : display buffer length */ vo_config->dst_dynamic_range = OT_DYNAMIC_RANGE_SDR8; vo_config->vo_mode = VO_MODE_1MUX; vo_config->pix_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420; vo_config->disp_rect.x = 0; vo_config->disp_rect.y = 0; vo_config->disp_rect.width = disp_size->width; vo_config->disp_rect.height = disp_size->height; vo_config->image_size.width = disp_size->width; vo_config->image_size.height = disp_size->height; vo_config->vo_part_mode = OT_VO_PARTITION_MODE_SINGLE; vo_config->compress_mode = OT_COMPRESS_MODE_NONE; ret = sample_comm_vo_start_vo(vo_config); if (ret != TD_SUCCESS) { sample_print("start VO fail for %#x!\n", ret); return ret; } return TD_SUCCESS; } td_void sample_vda_deinit_vo(const sample_vo_cfg *vo_config) { td_s32 ret; ret = sample_comm_vo_stop_vo(vo_config); if (ret != TD_SUCCESS) { sample_print("vo stop fail for %#x!\n", ret); } } td_s32 sample_vda_bind_init(td_u32 vdec_chn_num, td_u32 vpss_grp_num, ot_vo_layer vo_layer) { td_s32 i, j, k; td_s32 ret; td_s32 vdec_chn_num_tmp = (td_s32)vdec_chn_num; for (i = 0; i < vdec_chn_num_tmp; i++) { ret = sample_comm_vdec_bind_vpss(i, i); if (ret != TD_SUCCESS) { sample_print("vdec bind vpss fail for %#x!\n", ret); goto vdec_unbind_vpss; } } for (j = 0; j < (td_s32)vpss_grp_num; j++) { ret = sample_comm_vpss_bind_vo(j, VDA_VPSS_CHN, vo_layer, j); if (ret != TD_SUCCESS) { sample_print("vpss bind vo fail for %#x!\n", ret); goto vpss_unbind_vo; } } return TD_SUCCESS; vpss_unbind_vo: for (k = j - 1; k >= 0; k--) { ret = sample_comm_vpss_un_bind_vo(k, VDA_VPSS_CHN, vo_layer, k); if (ret != TD_SUCCESS) { sample_print("vpss unbind vo fail for %#x!\n", ret); } } vdec_unbind_vpss: for (k = i - 1; k >= 0; k--) { ret = sample_comm_vdec_un_bind_vpss(k, k); if (ret != TD_SUCCESS) { sample_print("vdec unbind vpss fail for %#x!\n", ret); } } return TD_FAILURE; } td_void sample_vda_bind_deinit(td_u32 vdec_chn_num, td_u32 vpss_grp_num, ot_vo_layer vo_layer) { td_u32 i; td_s32 ret; for (i = 0; i < vpss_grp_num; i++) { ret = sample_comm_vpss_un_bind_vo(i, VDA_VPSS_CHN, vo_layer, i); if (ret != TD_SUCCESS) { sample_print("vpss unbind vo fail for %#x!\n", ret); } } for (i = 0; i < vdec_chn_num; i++) { ret = sample_comm_vdec_un_bind_vpss(i, i); if (ret != TD_SUCCESS) { sample_print("vdec unbind vpss fail for %#x!\n", ret); } } } static td_s32 sample_vda_send_vdec_stream(vdec_thread_param vdec_send[], td_u32 vdec_max_thread, const sample_vdec_attr sample_vdec[], td_u32 vdec_max_chn, td_u32 vdec_chn_num) { td_s32 ret; td_u32 i; for (i = 0; ((i < vdec_chn_num) && (i < vdec_max_chn) && (i < vdec_max_thread)); i++) { ret = snprintf_s(vdec_send[i].c_file_name, sizeof(vdec_send[i].c_file_name), strlen(SAMPLE_VDA_STREAM_NAME), SAMPLE_VDA_STREAM_NAME); if (ret == -1) { sample_print("set stream name fail!\n"); return TD_FAILURE; } ret = snprintf_s(vdec_send[i].c_file_path, sizeof(vdec_send[i].c_file_path), strlen(SAMPLE_VDA_STREAM_PATH), "%s", SAMPLE_VDA_STREAM_PATH); if (ret == -1) { sample_print("set stream path fail!\n"); return TD_FAILURE; } vdec_send[i].type = sample_vdec[i].type; vdec_send[i].stream_mode = sample_vdec[i].mode; vdec_send[i].chn_id = i; vdec_send[i].interval_time = 1000; /* 1000 : send interval time */ vdec_send[i].pts_init = 0; vdec_send[i].pts_increase = 0; vdec_send[i].e_thread_ctrl = THREAD_CTRL_START; vdec_send[i].circle_send = TD_TRUE; vdec_send[i].milli_sec = 0; vdec_send[i].min_buf_size = (sample_vdec[i].width * sample_vdec[i].height * 3) >> 1; /* 3/2 : sp420 size cal */ } sample_comm_vdec_start_send_stream(vdec_chn_num, &vdec_send[0], &g_vdec_thread[0], OT_VDEC_MAX_CHN_NUM, VDA_THREAD_ARRAY_LEN); return TD_SUCCESS; } td_s32 sample_vda_process(ot_vda_work_mode work_mode) { td_s32 ret; ot_pic_size vda_pic_size = PIC_CIF; ot_size vda_size; const ot_vda_chn vda_chn = 0; /* start VDA MD process */ ret = sample_comm_sys_get_pic_size(vda_pic_size, &vda_size); if (ret != TD_SUCCESS) { sample_print("sys get pic size fail for %#x!\n", ret); return TD_FAILURE; } if (vda_size.width % 2) { /* 2 : odd-even */ vda_size.width = (vda_size.width / VDA_WIDTH_ALIGN + 1) * VDA_WIDTH_ALIGN; } if (vda_size.height % 2) { /* 2 : odd-even */ vda_size.height = (vda_size.height / VDA_HEIGHT_ALIGN + 1) * VDA_HEIGHT_ALIGN; } if (work_mode == OT_VDA_WORK_MODE_MD) { ret = sample_common_vda_md_start(vda_chn, VDA_VPSS_CHN, &vda_size); } else if (work_mode == OT_VDA_WORK_MODE_OD) { ret = sample_common_vda_od_start(vda_chn, VDA_VPSS_CHN, &vda_size); } else { sample_print("work_mode(%d) invalid!\n", work_mode); return TD_FAILURE; } if (ret != TD_SUCCESS) { sample_print("vda md start fail for %#x!\n", ret); return TD_FAILURE; } printf("\nPress any key to stop!"); sample_vda_getchar(); if (work_mode == OT_VDA_WORK_MODE_MD) { sample_common_vda_md_stop(vda_chn, VDA_VPSS_CHN); } else if (work_mode == OT_VDA_WORK_MODE_OD) { sample_common_vda_od_stop(vda_chn, VDA_VPSS_CHN); } else { sample_print("work_mode(%d) invalid!\n", work_mode); return TD_FAILURE; } return TD_SUCCESS; } td_s32 sample_vda(ot_vda_work_mode work_mode) { static vdec_thread_param vdec_send[OT_VDEC_MAX_CHN_NUM] = { 0 }; ot_size disp_size; ot_pic_size disp_pic_size = PIC_D1_PAL; sample_vdec_attr sample_vdec[OT_VDEC_MAX_CHN_NUM] = { 0 }; sample_vo_cfg vo_config; td_bool chn_enable[OT_VPSS_MAX_CHN_NUM] = { 0 }; const td_u32 vdec_chn_num = 1; td_u32 vpss_grp_num = vdec_chn_num; if (sample_vda_init(disp_pic_size, &disp_size, vdec_chn_num) != TD_SUCCESS) { return TD_FAILURE; } if (sample_vda_init_vdec(sample_vdec, OT_VDEC_MAX_CHN_NUM, vdec_chn_num) != TD_SUCCESS) { goto vdec_init_fail; } if (sample_vda_init_vpss(vpss_grp_num, &disp_size, chn_enable, OT_VPSS_MAX_CHN_NUM) != TD_SUCCESS) { goto vpss_init_fail; } if (sample_vda_init_vo(disp_pic_size, &disp_size, &vo_config) != TD_SUCCESS) { goto vo_init_fail; } if (sample_vda_bind_init(vdec_chn_num, vpss_grp_num, vo_config.vo_dev) != TD_SUCCESS) { goto bind_init_fail; } if (sample_vda_send_vdec_stream(vdec_send, OT_VDEC_MAX_CHN_NUM, sample_vdec, OT_VDEC_MAX_CHN_NUM, vdec_chn_num) != TD_SUCCESS) { goto send_stream_fail; } if (sample_vda_process(work_mode) != TD_SUCCESS) { printf("vda_process fail!\n"); } sample_comm_vdec_stop_send_stream(vdec_chn_num, &vdec_send[0], &g_vdec_thread[0], OT_VDEC_MAX_CHN_NUM, VDA_THREAD_ARRAY_LEN); send_stream_fail: sample_vda_bind_deinit(vdec_chn_num, vpss_grp_num, vo_config.vo_dev); bind_init_fail: sample_vda_deinit_vo(&vo_config); vo_init_fail: sample_vda_deinit_vpss(chn_enable, OT_VPSS_MAX_CHN_NUM); vpss_init_fail: sample_vda_deinit_vdec(vdec_chn_num); vdec_init_fail: sample_vda_deinit(); return TD_SUCCESS; } td_s32 main(int argc, char *argv[]) { td_s32 ret; char index; if (argc != 2) { /* 2: 2 arg num */ sample_vda_usage(); return TD_FAILURE; } if (!strncmp(argv[1], "-h", 2)) { /* 2: 2 chars */ sample_vda_usage(); return TD_SUCCESS; } sample_sys_signal(&sample_vda_handle_sig); if (strlen(argv[1]) > 1) { sample_vda_usage(); return TD_FAILURE; } index = *argv[1]; switch (index) { case '0': { ret = sample_vda(OT_VDA_WORK_MODE_MD); break; } case '1': { ret = sample_vda(OT_VDA_WORK_MODE_OD); break; } default: { sample_print("the index is invalid!\n"); sample_vda_usage(); return TD_FAILURE; } } if (ret == TD_SUCCESS) { sample_print("sample_vda exit success!\n"); } else { sample_print("sample_vda exit abnormally!\n"); } return ret; }