Files
hisi_SS524V100_SDK/mpp/sample/hdmi/sample_hdmi_video_path.c

1106 lines
35 KiB
C

/*
Copyright (c), 2001-2022, Shenshu Tech. Co., Ltd.
*/
#include "sample_hdmi_video_path.h"
#define VIDIO_STREAM_PATH "."
#define AACLC_SAMPLES_PER_FRAME 1024
#define AUDIO_STREAM_PATH "./source_file/music_8kHz_mono_1min.pcm"
#define AUDIO_CHANNEL_CNT 2
#define ERRNO_SYS_INIT_FAILE (-1)
#define ERRNO_VB_INIT_FAILE (-2)
#define ERRNO_VDEC_START_FAILE (-3)
#define ERRNO_VO_START_FAILE (-5)
#define ERRNO_VPSS_START_FAILE (-4)
#define ERRNO_VDEC_BIND_FAILE (-6)
#define ERRNO_STREAM_SEND_FAILE (-7)
#define hdmi_if_not_success_return_void(express, name) \
do { \
td_s32 re; \
re = express; \
if (re != TD_SUCCESS) { \
printf("\033[0;31mtest case <%s>not pass at line:%d.\033[0;39m\n", __FUNCTION__, __LINE__); \
return; \
} \
} while (0)
/* video info */
static ot_pic_size g_disp_pic_size;
static ot_vo_intf_type g_vo_intf_type = OT_VO_INTF_HDMI;
static ot_size g_disp_size;
static pthread_t g_vdec_thread[NUM_2 * OT_VDEC_MAX_CHN_NUM];
static sample_media_status g_media_status = SAMPLE_MEDIA_RUN;
static ot_hdmi_callback_func g_callback_func;
static hdmi_args g_hdmi_args;
static td_u32 g_vdec_chn_num = 1;
static vdec_thread_param g_vdec_send[OT_VDEC_MAX_CHN_NUM];
static td_u32 g_vpss_grp_num = 1;
static ot_vo_layer g_vo_layer;
static sample_vo_cfg g_vo_config;
static ot_vpss_grp g_vpss_grp;
static td_bool g_vpss_chn_enable[OT_VPSS_MAX_CHN_NUM];
/* audio info */
static ot_payload_type g_payload_type = OT_PT_LPCM;
static sample_adec g_sample_adec[OT_ADEC_MAX_CHN_NUM];
static ot_audio_snd_mode g_audio_snd_mode = OT_AUDIO_SOUND_MODE_MONO;
static ot_audio_sample_rate g_steam_smple_rate = OT_AUDIO_SAMPLE_RATE_BUTT;
static td_bool g_resample_en = TD_FALSE;
static aduio_input g_audio_input;
static td_bool g_audio_input_modified = TD_FALSE;
static const pic_size_param g_pic[] = {
{ OT_VO_OUT_480P60, PIC_480P },
{ OT_VO_OUT_576P50, PIC_576P },
{ OT_VO_OUT_800x600_60, PIC_800X600 },
{ OT_VO_OUT_1024x768_60, PIC_1024X768 },
{ OT_VO_OUT_1366x768_60, PIC_1366X768 },
{ OT_VO_OUT_1280x1024_60, PIC_1280X1024 },
{ OT_VO_OUT_2560x1440_60, PIC_2560X1440 },
{ OT_VO_OUT_1440x900_60, PIC_1440X900 },
{ OT_VO_OUT_1280x800_60, PIC_1280X800 },
{ OT_VO_OUT_1600x1200_60, PIC_1600X1200 },
{ OT_VO_OUT_1680x1050_60, PIC_1680X1050 },
{ OT_VO_OUT_1920x1200_60, PIC_1920X1200 },
{ OT_VO_OUT_640x480_60, PIC_640X480 },
{ OT_VO_OUT_1920x2160_30, PIC_1920X2160 },
{ OT_VO_OUT_2560x1440_30, PIC_2560X1440 },
{ OT_VO_OUT_2560x1600_60, PIC_2560X1600 },
{ OT_VO_OUT_1080P24, PIC_1080P },
{ OT_VO_OUT_1080P25, PIC_1080P },
{ OT_VO_OUT_1080P30, PIC_1080P },
{ OT_VO_OUT_1080P50, PIC_1080P },
{ OT_VO_OUT_1080P60, PIC_1080P },
{ OT_VO_OUT_1080I50, PIC_1080P },
{ OT_VO_OUT_1080I60, PIC_1080P },
{ OT_VO_OUT_720P50, PIC_720P },
{ OT_VO_OUT_720P60, PIC_720P },
{ OT_VO_OUT_3840x2160_24, PIC_3840X2160 },
{ OT_VO_OUT_3840x2160_25, PIC_3840X2160 },
{ OT_VO_OUT_3840x2160_30, PIC_3840X2160 },
{ OT_VO_OUT_3840x2160_50, PIC_3840X2160 },
{ OT_VO_OUT_3840x2160_60, PIC_3840X2160 },
{ OT_VO_OUT_4096x2160_24, PIC_4096X2160 },
{ OT_VO_OUT_4096x2160_25, PIC_4096X2160 },
{ OT_VO_OUT_4096x2160_30, PIC_4096X2160 },
{ OT_VO_OUT_4096x2160_50, PIC_4096X2160 },
{ OT_VO_OUT_4096x2160_60, PIC_4096X2160 },
{ OT_VO_OUT_7680x4320_30, PIC_7680X4320 },
};
static const vo_hdmi_fmt g_vo_hdmi_fmt[] = {
{ OT_VO_OUT_PAL, OT_HDMI_VIDEO_FORMAT_PAL },
{ OT_VO_OUT_NTSC, OT_HDMI_VIDEO_FORMAT_NTSC },
{ OT_VO_OUT_1080P24, OT_HDMI_VIDEO_FORMAT_1080P_24 },
{ OT_VO_OUT_1080P25, OT_HDMI_VIDEO_FORMAT_1080P_25 },
{ OT_VO_OUT_1080P30, OT_HDMI_VIDEO_FORMAT_1080P_30 },
{ OT_VO_OUT_720P50, OT_HDMI_VIDEO_FORMAT_720P_50 },
{ OT_VO_OUT_720P60, OT_HDMI_VIDEO_FORMAT_720P_60 },
{ OT_VO_OUT_1080I50, OT_HDMI_VIDEO_FORMAT_1080i_50 },
{ OT_VO_OUT_1080I60, OT_HDMI_VIDEO_FORMAT_1080i_60 },
{ OT_VO_OUT_1080P50, OT_HDMI_VIDEO_FORMAT_1080P_50 },
{ OT_VO_OUT_1080P60, OT_HDMI_VIDEO_FORMAT_1080P_60 },
{ OT_VO_OUT_576P50, OT_HDMI_VIDEO_FORMAT_576P_50 },
{ OT_VO_OUT_480P60, OT_HDMI_VIDEO_FORMAT_480P_60 },
{ OT_VO_OUT_640x480_60, OT_HDMI_VIDEO_FORMAT_861D_640X480_60 },
{ OT_VO_OUT_800x600_60, OT_HDMI_VIDEO_FORMAT_VESA_800X600_60 },
{ OT_VO_OUT_1024x768_60, OT_HDMI_VIDEO_FORMAT_VESA_1024X768_60 },
{ OT_VO_OUT_1280x1024_60, OT_HDMI_VIDEO_FORMAT_VESA_1280X1024_60 },
{ OT_VO_OUT_1366x768_60, OT_HDMI_VIDEO_FORMAT_VESA_1366X768_60 },
{ OT_VO_OUT_1440x900_60, OT_HDMI_VIDEO_FORMAT_VESA_1440X900_60 },
{ OT_VO_OUT_1280x800_60, OT_HDMI_VIDEO_FORMAT_VESA_1280X800_60 },
{ OT_VO_OUT_1680x1050_60, OT_HDMI_VIDEO_FORMAT_VESA_1680X1050_60 },
{ OT_VO_OUT_1920x2160_30, OT_HDMI_VIDEO_FORMAT_1920x2160_30 },
{ OT_VO_OUT_1600x1200_60, OT_HDMI_VIDEO_FORMAT_VESA_1600X1200_60 },
{ OT_VO_OUT_1920x1200_60, OT_HDMI_VIDEO_FORMAT_VESA_1920X1200_60 },
{ OT_VO_OUT_2560x1440_30, OT_HDMI_VIDEO_FORMAT_2560x1440_30 },
{ OT_VO_OUT_2560x1440_60, OT_HDMI_VIDEO_FORMAT_2560x1440_60 },
{ OT_VO_OUT_2560x1600_60, OT_HDMI_VIDEO_FORMAT_2560x1600_60 },
{ OT_VO_OUT_3840x2160_24, OT_HDMI_VIDEO_FORMAT_3840X2160P_24 },
{ OT_VO_OUT_3840x2160_25, OT_HDMI_VIDEO_FORMAT_3840X2160P_25 },
{ OT_VO_OUT_3840x2160_30, OT_HDMI_VIDEO_FORMAT_3840X2160P_30 },
{ OT_VO_OUT_3840x2160_50, OT_HDMI_VIDEO_FORMAT_3840X2160P_50 },
{ OT_VO_OUT_3840x2160_60, OT_HDMI_VIDEO_FORMAT_3840X2160P_60 }
};
ot_pic_size sample_vdec_get_diplay_cfg(ot_vo_intf_sync intf_sync)
{
td_u32 i;
ot_pic_size pic_size;
for (i = 0; i < (sizeof(g_pic) / sizeof(g_pic[0])); i++) {
if (intf_sync == g_pic[i].vo_sync) {
break;
}
}
if (i < (sizeof(g_pic) / sizeof(g_pic[0]))) {
pic_size = g_pic[i].pic_size;
} else {
pic_size = PIC_3840X2160;
}
return pic_size;
}
static td_s32 step2_init_vb(sample_vdec_attr *sample_vdec, td_u32 size)
{
td_u32 i;
td_s32 ret;
for (i = 0; i < g_vdec_chn_num && i < size; i++) {
sample_vdec[i].type = OT_PT_H265;
sample_vdec[i].width = FMT_3840_2160_WIDTH;
sample_vdec[i].height = FMT_3840_2160_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 = NUM_2;
sample_vdec[i].display_frame_num = NUM_2;
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(g_vdec_chn_num, &sample_vdec[0], OT_VDEC_MAX_CHN_NUM);
if (ret != TD_SUCCESS) {
sample_prt("init mod common vb fail for %#x!\n", ret);
return ERRNO_VB_INIT_FAILE;
}
return TD_SUCCESS;
}
static td_s32 step4_start_vpss(ot_vpss_chn_attr *vpss_chn_attr, td_u32 size)
{
td_u32 i;
td_s32 ret;
ot_vpss_grp_attr vpss_grp_attr = {0};
if (size < NUM_2) {
sample_prt("param err %d!\n", size);
return ERRNO_VPSS_START_FAILE;
}
vpss_grp_attr.max_width = FMT_3840_2160_WIDTH;
vpss_grp_attr.max_height = FMT_3840_2160_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.ie_en = TD_FALSE;
vpss_grp_attr.dci_en = TD_FALSE;
vpss_grp_attr.dei_mode = OT_VPSS_DEI_MODE_OFF;
vpss_grp_attr.buf_share_en = TD_FALSE;
(td_void)memset_s(g_vpss_chn_enable, sizeof(g_vpss_chn_enable), 0, sizeof(g_vpss_chn_enable));
g_vpss_chn_enable[1] = TD_TRUE;
vpss_chn_attr[1].width = g_disp_size.width;
vpss_chn_attr[1].height = g_disp_size.height;
vpss_chn_attr[1].chn_mode = OT_VPSS_CHN_MODE_AUTO;
vpss_chn_attr[1].compress_mode = OT_COMPRESS_MODE_SEG;
vpss_chn_attr[1].pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
vpss_chn_attr[1].frame_rate.src_frame_rate = -1;
vpss_chn_attr[1].frame_rate.dst_frame_rate = -1;
vpss_chn_attr[1].depth = 0;
vpss_chn_attr[1].mirror_en = TD_FALSE;
vpss_chn_attr[1].flip_en = TD_FALSE;
vpss_chn_attr[1].border_en = TD_FALSE;
vpss_chn_attr[1].aspect_ratio.mode = OT_ASPECT_RATIO_NONE;
for (i = 0; i < g_vdec_chn_num; i++) {
g_vpss_grp = i;
ret = sample_common_vpss_start(g_vpss_grp, &g_vpss_chn_enable[0],
&vpss_grp_attr, &vpss_chn_attr[0], OT_VPSS_MAX_CHN_NUM);
if (ret != TD_SUCCESS) {
sample_prt("start VPSS fail for %#x!\n", ret);
return ERRNO_VPSS_START_FAILE;
}
}
return TD_SUCCESS;
}
static td_s32 step5_start_vo(ot_vo_intf_sync intf_sync)
{
td_s32 ret;
g_vo_config.vo_dev = SAMPLE_VO_DEV_UHD;
g_vo_config.vo_intf_type = g_vo_intf_type;
g_vo_config.intf_sync = intf_sync;
g_vo_config.pic_size = g_disp_pic_size;
g_vo_config.bg_color = COLOR_RGB_BLUE;
g_vo_config.dis_buf_len = NUM_3;
g_vo_config.dst_dynamic_range = OT_DYNAMIC_RANGE_SDR8;
g_vo_config.vo_mode = VO_MODE_1MUX;
g_vo_config.pix_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
g_vo_config.disp_rect.x = 0;
g_vo_config.disp_rect.y = 0;
g_vo_config.disp_rect.width = g_disp_size.width;
g_vo_config.disp_rect.height = g_disp_size.height;
g_vo_config.image_size.width = g_disp_size.width;
g_vo_config.image_size.height = g_disp_size.height;
g_vo_config.vo_part_mode = OT_VO_PARTITION_MODE_SINGLE;
ret = sample_comm_vo_start_vo(&g_vo_config);
if (ret != TD_SUCCESS) {
sample_prt("start VO fail for %#x!\n", ret);
return ERRNO_VO_START_FAILE;
}
return TD_SUCCESS;
}
static td_s32 step8_send_stream_to_vdec(sample_vdec_attr *sample_vdec, td_u32 size)
{
td_u32 i;
td_s32 ret;
for (i = 0; i < g_vdec_chn_num && i < size; i++) {
ret = snprintf_s(g_vdec_send[i].c_file_name, FILE_NAME_LEN, FILE_NAME_LEN - 1,
"source_file/3840x2160_8bit.h265");
if (ret < 0) {
sample_prt("snprintf_s err\n");
return ERRNO_STREAM_SEND_FAILE;
}
ret = snprintf_s(g_vdec_send[i].c_file_path, FILE_NAME_LEN, FILE_NAME_LEN - 1, "%s", VIDIO_STREAM_PATH);
if (ret < 0) {
sample_prt("snprintf_s err\n");
return ERRNO_STREAM_SEND_FAILE;
}
g_vdec_send[i].type = sample_vdec[i].type;
g_vdec_send[i].stream_mode = sample_vdec[i].mode;
g_vdec_send[i].chn_id = i;
g_vdec_send[i].interval_time = NUM_1000;
g_vdec_send[i].pts_init = 0;
g_vdec_send[i].pts_increase = 0;
g_vdec_send[i].e_thread_ctrl = THREAD_CTRL_START;
g_vdec_send[i].circle_send = TD_TRUE;
g_vdec_send[i].milli_sec = 0;
g_vdec_send[i].min_buf_size = (sample_vdec[i].width * sample_vdec[i].height * NUM_3) >> 1;
}
sample_comm_vdec_start_send_stream(g_vdec_chn_num, &g_vdec_send[0], &g_vdec_thread[0],
OT_VDEC_MAX_CHN_NUM, NUM_2 * OT_VDEC_MAX_CHN_NUM);
return TD_SUCCESS;
}
static td_void error_handle(td_s32 err)
{
td_u32 i;
td_s32 j, ret;
switch (err) {
case ERRNO_STREAM_SEND_FAILE: {
for (i = 0; i < g_vpss_grp_num; i++) {
ret = sample_comm_vpss_un_bind_vo(i, 1, g_vo_layer, i);
if (ret != TD_SUCCESS) {
sample_prt("vpss unbind vo fail for %#x!\n", ret);
}
}
}; /* fall-through */
case ERRNO_VDEC_BIND_FAILE: {
for (i = 0; i < g_vdec_chn_num; i++) {
ret = sample_comm_vdec_un_bind_vpss(i, i);
if (ret != TD_SUCCESS) {
sample_prt("vdec unbind vpss fail for %#x!\n", ret);
}
}
}; /* fall-through */
case ERRNO_VO_START_FAILE: {
sample_comm_vo_stop_vo(&g_vo_config);
}; /* fall-through */
case ERRNO_VPSS_START_FAILE: {
for (j = g_vpss_grp; j >= 0; j--) {
sample_common_vpss_stop(j, &g_vpss_chn_enable[0], OT_VPSS_MAX_CHN_NUM);
}
}; /* fall-through */
case ERRNO_VDEC_START_FAILE: {
sample_comm_vdec_stop(g_vdec_chn_num);
}; /* fall-through */
case ERRNO_VB_INIT_FAILE: {
sample_comm_vdec_exit_vb_pool();
}; /* fall-through */
case ERRNO_SYS_INIT_FAILE: {
sample_comm_sys_exit();
} break;
default: {
sample_prt("err errno :%d\n", err);
} break;
}
return;
}
static td_s32 step1_init(ot_vo_intf_sync intf_sync)
{
td_s32 ret;
ot_vb_cfg vb_cfg = {0};
ot_pic_buf_attr buf_attr = {0};
g_disp_pic_size = sample_vdec_get_diplay_cfg(intf_sync);
ret = sample_comm_sys_get_pic_size(g_disp_pic_size, &g_disp_size);
if (ret != TD_SUCCESS) {
sample_prt("sys get pic size fail for %#x!\n", ret);
return ERRNO_SYS_INIT_FAILE;
}
buf_attr.align = 0;
buf_attr.bit_width = OT_DATA_BIT_WIDTH_8;
buf_attr.compress_mode = OT_COMPRESS_MODE_SEG;
buf_attr.height = FMT_3840_2160_WIDTH;
buf_attr.width = FMT_3840_2160_HEIGHT;
buf_attr.pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
vb_cfg.max_pool_cnt = 1;
vb_cfg.common_pool[0].blk_cnt = NUM_10 * g_vdec_chn_num;
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_prt("init sys fail for %#x!\n", ret);
return ERRNO_SYS_INIT_FAILE;
}
return TD_SUCCESS;
}
td_s32 sample_hdmi_vdec_vpss_vo_start(ot_vo_intf_sync intf_sync)
{
td_u32 i;
td_s32 ret;
sample_vdec_attr sample_vdec[OT_VDEC_MAX_CHN_NUM] = {0};
ot_vpss_chn_attr vpss_chn_attr[OT_VPSS_MAX_CHN_NUM] = {0};
/* step1: init */
ret = step1_init(intf_sync);
if (ret != TD_SUCCESS) {
goto end;
}
/* step2: init module VB or user VB(for VDEC) */
ret = step2_init_vb(sample_vdec, OT_VDEC_MAX_CHN_NUM);
if (ret != TD_SUCCESS) {
goto end;
}
/* step3: start VDEC */
ret = sample_comm_vdec_start(g_vdec_chn_num, &sample_vdec[0], OT_VDEC_MAX_CHN_NUM);
if (ret != TD_SUCCESS) {
ret = ERRNO_VDEC_START_FAILE;
goto end;
}
/* step4: start VPSS */
ret = step4_start_vpss(vpss_chn_attr, OT_VPSS_MAX_CHN_NUM);
if (ret != TD_SUCCESS) {
goto end;
}
/* step5: start VO */
ret = step5_start_vo(intf_sync);
if (ret != TD_SUCCESS) {
goto end;
}
/* step6: VDEC bind VPSS */
for (i = 0; i < g_vdec_chn_num; i++) {
ret = sample_comm_vdec_bind_vpss(i, i);
if (ret != TD_SUCCESS) {
ret = ERRNO_VDEC_BIND_FAILE;
goto end;
}
}
/* step7: VPSS bind VO */
g_vo_layer = g_vo_config.vo_dev;
for (i = 0; i < g_vpss_grp_num; i++) {
ret = sample_comm_vpss_bind_vo(i, 1, g_vo_layer, i);
if (ret != TD_SUCCESS) {
ret = ERRNO_STREAM_SEND_FAILE;
goto end;
}
}
/* step8: send stream to VDEC */
ret = step8_send_stream_to_vdec(sample_vdec, OT_VDEC_MAX_CHN_NUM);
if (ret != TD_SUCCESS) {
goto end;
}
return TD_SUCCESS;
end:
error_handle(ret);
return TD_FAILURE;
}
td_s32 sample_hdmi_vdec_vpss_vo_stop(td_void)
{
td_u32 i;
td_s32 j;
sample_comm_vdec_stop_send_stream(g_vdec_chn_num, &g_vdec_send[0], &g_vdec_thread[0],
OT_VDEC_MAX_CHN_NUM, NUM_2 * OT_VDEC_MAX_CHN_NUM);
for (i = 0; i < g_vpss_grp_num; i++) {
sample_comm_vpss_un_bind_vo(i, 1, g_vo_layer, i);
}
for (i = 0; i < g_vdec_chn_num; i++) {
sample_comm_vdec_un_bind_vpss(i, i);
}
sample_comm_vo_stop_vo(&g_vo_config);
for (j = g_vpss_grp; j >= 0; j--) {
sample_common_vpss_stop(j, &g_vpss_chn_enable[0], OT_VPSS_MAX_CHN_NUM);
}
sample_comm_vdec_stop(g_vdec_chn_num);
sample_comm_vdec_exit_vb_pool();
sample_comm_sys_exit();
return TD_SUCCESS;
}
td_void sample_hdmi_media_set(td_bool run)
{
if (run == TD_FALSE) {
g_media_status = SAMPLE_MEDIA_STOP;
} else {
g_media_status = SAMPLE_MEDIA_RUN;
}
return;
}
static td_void hdmi_mst_hdmi_convert_sync(ot_vo_intf_sync intf_sync, ot_hdmi_video_format *video_format)
{
td_u32 i;
for (i = 0; i < (sizeof(g_vo_hdmi_fmt) / sizeof(g_vo_hdmi_fmt[0])); i++) {
if (intf_sync == g_vo_hdmi_fmt[i].intf_sync) {
break;
}
}
if (i < (sizeof(g_vo_hdmi_fmt) / sizeof(g_vo_hdmi_fmt[0]))) {
*video_format = g_vo_hdmi_fmt[i].hdmi_fmt;
} else {
*video_format = OT_HDMI_VIDEO_FORMAT_VESA_CUSTOMER_DEFINE;
}
return;
}
static td_void hdmi_hot_plug_proc(td_void *private_data)
{
td_s32 ret;
hdmi_args args = {0};
ot_hdmi_attr attr = {0};
ot_hdmi_sink_capability caps = {0};
printf("\033[32;1mEVENT: HPD\033[0m\n");
if (private_data == TD_NULL) {
printf("\033[31;1m[%s:%d]null pointer!\033[0m\n", __FUNCTION__, __LINE__);
return;
}
ret = memcpy_s(&args, sizeof(args), private_data, sizeof(hdmi_args));
if (ret != EOK) {
sample_prt("return; failed!\n");
return;
}
ret = ss_mpi_hdmi_get_sink_capability(args.hdmi, &caps);
if (ret != TD_SUCCESS) {
sample_prt("get sink caps failed!\n");
} else {
sample_prt("get sink caps success!\n");
}
ret = ss_mpi_hdmi_get_attr(args.hdmi, &attr);
if (ret != TD_SUCCESS) {
sample_prt("get attr failed: 0x%x!\n", ret);
}
ret = ss_mpi_hdmi_set_attr(args.hdmi, &attr);
if (ret != TD_SUCCESS) {
sample_prt("set attr failed: 0x%x!\n", ret);
}
ss_mpi_hdmi_start(args.hdmi);
return;
}
static td_void hdmi_un_plug_proc(td_void *private_data)
{
td_s32 ret;
hdmi_args args = {0};
printf("\033[32;1mEVENT: UN-HPD\033[0m\n");
if (private_data == TD_NULL) {
printf("\033[31;1m[%s:%d]null pointer!\033[0m\n", __FUNCTION__, __LINE__);
return;
}
ret = memcpy_s(&args, sizeof(args), private_data, sizeof(hdmi_args));
if (ret != EOK) {
sample_prt("memcpy_s err. /n");
return;
}
ret = ss_mpi_hdmi_stop(args.hdmi);
if (ret != TD_SUCCESS) {
sample_prt("ret = %d./n", ret);
}
return;
}
static td_void hdmi_event_call_back(ot_hdmi_event_type event, td_void *private_data)
{
switch (event) {
case OT_HDMI_EVENT_HOTPLUG:
hdmi_hot_plug_proc(private_data);
break;
case OT_HDMI_EVENT_NO_PLUG:
hdmi_un_plug_proc(private_data);
break;
default:
break;
}
return;
}
td_void sample_hdmi_start(ot_vo_intf_sync intf_sync)
{
td_s32 ret;
ot_hdmi_attr attr = {0};
ot_vo_hdmi_param hdmi_param = {0};
ot_hdmi_video_format video_format;
ot_hdmi_sink_capability capability = {0};
hdmi_mst_hdmi_convert_sync(intf_sync, &video_format);
g_hdmi_args.hdmi = OT_HDMI_ID_0;
g_callback_func.hdmi_event_callback = hdmi_event_call_back;
g_callback_func.private_data = &g_hdmi_args;
ret = ss_mpi_hdmi_init();
sample_if_failure_return_void(ret);
ret = ss_mpi_hdmi_open(OT_HDMI_ID_0);
sample_if_failure_return_void(ret);
ret = ss_mpi_hdmi_register_callback(OT_HDMI_ID_0, &g_callback_func);
sample_if_failure_return_void(ret);
ret = ss_mpi_hdmi_get_attr(OT_HDMI_ID_0, &attr);
sample_if_failure_return_void(ret);
attr.hdmi_en = TD_TRUE;
attr.video_format = video_format;
attr.deep_color_mode = OT_HDMI_DEEP_COLOR_24BIT;
attr.bit_depth = OT_HDMI_BIT_DEPTH_16;
attr.audio_en = TD_TRUE;
attr.sample_rate = OT_HDMI_SAMPLE_RATE_48K;
ret = ss_mpi_hdmi_set_attr(OT_HDMI_ID_0, &attr);
sample_if_failure_return_void(ret);
ret = ss_mpi_hdmi_get_sink_capability(OT_HDMI_ID_0, &capability);
sample_if_failure_return_void(ret);
if (capability.support_hdmi == TD_FALSE || capability.support_ycbcr == TD_FALSE) {
ret = ss_mpi_vo_get_hdmi_param(SAMPLE_VO_DEV_DHD0, &hdmi_param);
sample_if_failure_return_void(ret);
hdmi_param.csc.csc_matrix = OT_VO_CSC_MATRIX_BT709FULL_TO_RGBFULL;
ret = ss_mpi_vo_set_hdmi_param(SAMPLE_VO_DEV_DHD0, &hdmi_param);
sample_if_failure_return_void(ret);
}
return;
}
static td_s32 sample_stop_vo(sample_vo_cfg *vo_config)
{
td_s32 ret;
ot_vo_dev vo_dev;
ot_vo_layer vo_layer;
sample_vo_mode vo_mode;
if (vo_config == TD_NULL) {
sample_print("error:argument can not be NULL\n");
return TD_FAILURE;
}
vo_dev = vo_config->vo_dev;
vo_layer = vo_config->vo_dev;
vo_mode = vo_config->vo_mode;
ret = sample_comm_vo_stop_chn(vo_layer, vo_mode);
sample_if_failure_return(ret, TD_FAILURE);
ret = sample_comm_vo_stop_layer(vo_layer);
sample_if_failure_return(ret, TD_FAILURE);
ret = sample_comm_vo_stop_dev(vo_dev);
sample_if_failure_return(ret, TD_FAILURE);
return TD_SUCCESS;
}
td_s32 sample_hdmi_fmt_change(ot_vo_intf_sync intf_sync, td_bool rgb_enable)
{
td_s32 ret;
ot_hdmi_attr attr = {0};
td_bool rgb_en = TD_FALSE;
ss_mpi_hdmi_stop(OT_HDMI_ID_0);
ret = sample_stop_vo(&g_vo_config);
if (ret != TD_SUCCESS) {
sample_prt("sys get pic size fail for %#x!\n", ret);
goto err1;
}
g_disp_pic_size = sample_vdec_get_diplay_cfg(intf_sync);
ret = sample_comm_sys_get_pic_size(g_disp_pic_size, &g_disp_size);
if (ret != TD_SUCCESS) {
sample_prt("sys get pic size fail for %#x!\n", ret);
goto err1;
}
ret = ss_mpi_hdmi_get_attr(OT_HDMI_ID_0, &attr);
sample_if_failure_return(ret, TD_FAILURE);
if (attr.hdmi_en == TD_FALSE || rgb_enable == TD_TRUE) {
rgb_en = TD_TRUE;
}
sample_comm_vo_set_hdmi_rgb_mode(rgb_en);
g_vo_config.intf_sync = intf_sync;
g_vo_config.pic_size = g_disp_pic_size;
g_vo_config.disp_rect.width = g_disp_size.width;
g_vo_config.disp_rect.height = g_disp_size.height;
g_vo_config.image_size.width = g_disp_size.width;
g_vo_config.image_size.height = g_disp_size.height;
ret = sample_comm_vo_start_vo(&g_vo_config);
if (ret != TD_SUCCESS) {
sample_prt("start VO fail for %#x!\n", ret);
goto err2;
}
return TD_SUCCESS;
err2:
sample_comm_vo_stop_vo(&g_vo_config);
err1:
return TD_FAILURE;
}
td_s32 sample_hdmi_set_audio_sample_rate(td_u32 sample_rate)
{
td_s32 ret;
if (sample_rate != g_audio_input.sample_rate) {
g_audio_input.sample_rate = sample_rate;
g_audio_input_modified = TD_TRUE;
ret = sample_hdmi_stop_audio();
sample_if_failure_return(ret, TD_FAILURE);
ret = sample_hdmi_start_audio();
sample_if_failure_return(ret, TD_FAILURE);
}
return TD_SUCCESS;
}
td_void hdmi_mst_audio_start_hdmi(ot_aio_attr *attr)
{
ot_hdmi_attr hdmi_attr = {0};
ot_hdmi_id hdmi = OT_HDMI_ID_0;
hdmi_if_not_success_return_void(ss_mpi_hdmi_set_avmute(hdmi, TD_TRUE), "hdmi_set_av_mute");
hdmi_if_not_success_return_void(ss_mpi_hdmi_get_attr(hdmi, &hdmi_attr), "hdmi_get_attr");
hdmi_attr.audio_en = TD_TRUE;
if (attr->sample_rate == OT_AUDIO_SAMPLE_RATE_48000) {
hdmi_attr.sample_rate = OT_HDMI_SAMPLE_RATE_48K;
} else if (attr->sample_rate == OT_AUDIO_SAMPLE_RATE_44100) {
hdmi_attr.sample_rate = OT_HDMI_SAMPLE_RATE_44K;
} else if (attr->sample_rate == OT_AUDIO_SAMPLE_RATE_32000) {
hdmi_attr.sample_rate = OT_HDMI_SAMPLE_RATE_32K;
}
if (attr->bit_width == OT_AUDIO_BIT_WIDTH_16) {
hdmi_attr.bit_depth = OT_HDMI_BIT_DEPTH_16;
} else if (attr->bit_width == OT_AUDIO_BIT_WIDTH_8) {
hdmi_attr.bit_depth = OT_HDMI_BIT_DEPTH_8;
} else if (attr->bit_width == OT_AUDIO_BIT_WIDTH_24) {
hdmi_attr.bit_depth = OT_HDMI_BIT_DEPTH_24;
}
hdmi_if_not_success_return_void(ss_mpi_hdmi_stop(hdmi), "hdmi_stop");
hdmi_if_not_success_return_void(ss_mpi_hdmi_set_attr(hdmi, &hdmi_attr), "hdmi_set_attr");
hdmi_if_not_success_return_void(ss_mpi_hdmi_start(hdmi), "hdmi_start");
hdmi_if_not_success_return_void(ss_mpi_hdmi_set_avmute(hdmi, TD_FALSE), "hdmi_set_av_mute");
return;
}
/*
* function : start adec
*/
td_s32 hdmi_mst_start_adec(ot_adec_chn ad_chn, ot_payload_type type)
{
td_s32 ret;
ot_adec_chn_attr adec_attr = {0};
ot_adec_attr_adpcm adec_adpcm = {0};
ot_adec_attr_lpcm adec_lpcm;
adec_attr.type = type;
adec_attr.buf_size = NUM_20;
adec_attr.mode = OT_ADEC_MODE_STREAM; /* propose use pack mode in your app */
if (adec_attr.type == OT_PT_ADPCMA) {
adec_attr.value = &adec_adpcm;
adec_adpcm.adpcm_type = OT_ADPCM_TYPE_DVI4;
} else {
adec_attr.value = &adec_lpcm;
adec_attr.mode = OT_ADEC_MODE_PACK; /* lpcm must use pack mode */
}
/* create adec chn */
ret = ss_mpi_adec_create_chn(ad_chn, &adec_attr);
if (ret) {
sample_prt("adec_create_chn(%d) failed with %#x!\n", ad_chn, ret);
return ret;
}
return 0;
}
td_s32 hdmi_mst_comm_start_ao(ot_audio_dev ao_dev_id, td_s32 ao_chn_cnt,
ot_aio_attr *attr, ot_audio_sample_rate in_sample_rate, td_bool resample_en)
{
td_s32 i;
td_u32 ret;
if (attr->chn_cnt == 0) {
attr->chn_cnt = 1;
}
ret = ss_mpi_ao_set_pub_attr(ao_dev_id, attr);
if (ret != TD_SUCCESS) {
sample_prt("ao_set_pub_attr(%d) failed with %#x!\n", ao_dev_id, ret);
return TD_FAILURE;
}
ret = ss_mpi_ao_enable(ao_dev_id);
if (ret != TD_SUCCESS) {
sample_prt("ao_enable(%d) failed with %#x!\n", ao_dev_id, ret);
return TD_FAILURE;
}
for (i = 0; i < ao_chn_cnt; i++) {
ret = ss_mpi_ao_enable_chn(ao_dev_id, i);
if (ret != TD_SUCCESS) {
sample_prt("ao_enable_chn(%d) failed with %#x!\n", i, ret);
return TD_FAILURE;
}
if (resample_en == TD_TRUE && attr->snd_mode == OT_AUDIO_SOUND_MODE_MONO) {
ret = ss_mpi_ao_disable_resample(ao_dev_id, i);
ret = ss_mpi_ao_enable_resample(ao_dev_id, i, in_sample_rate);
if (ret != TD_SUCCESS) {
sample_prt("ao_enable_re_smp(%d,%d) failed with %#x!\n", ao_dev_id, i, ret);
return TD_FAILURE;
}
}
}
return TD_SUCCESS;
}
/*
* function : ao bind adec
*/
td_s32 hdmi_mst_comm_ao_bind_adec(ot_audio_dev ao_dev, ot_ao_chn ao_chn, ot_adec_chn ad_chn)
{
ot_mpp_chn src_chn, dest_chn;
src_chn.mod_id = OT_ID_ADEC;
src_chn.dev_id = 0;
src_chn.chn_id = ad_chn;
dest_chn.mod_id = OT_ID_AO;
dest_chn.dev_id = ao_dev;
dest_chn.chn_id = ao_chn;
return ss_mpi_sys_bind(&src_chn, &dest_chn);
}
/*
* function : ao unbind adec
*/
td_s32 hdmi_mst_comm_ao_unbind_adec(ot_audio_dev ao_dev, ot_ao_chn ao_chn, ot_adec_chn ad_chn)
{
ot_mpp_chn src_chn, dest_chn;
src_chn.mod_id = OT_ID_ADEC;
src_chn.chn_id = ad_chn;
src_chn.dev_id = 0;
dest_chn.mod_id = OT_ID_AO;
dest_chn.dev_id = ao_dev;
dest_chn.chn_id = ao_chn;
return ss_mpi_sys_unbind(&src_chn, &dest_chn);
}
/*
* function : get stream from file, and send it to adec
*/
void *hdmi_mst_comm_adec_proc(void *parg)
{
td_s32 ret;
ot_audio_stream aud_stream;
td_u32 len = NUM_1024;
td_u32 read_len;
td_s32 adec_chn;
td_u8 *audio_stream = NULL;
sample_adec *adec_ctl = (sample_adec *)parg;
FILE *pfd = adec_ctl->pfd;
adec_chn = adec_ctl->ad_chn;
audio_stream = (td_u8 *)malloc(sizeof(td_u8) * OT_MAX_AUDIO_STREAM_LEN);
if (audio_stream == NULL) {
sample_prt("malloc failed!\n");
fclose(pfd);
return NULL;
}
(td_void)memset_s(audio_stream, OT_MAX_AUDIO_STREAM_LEN, 0, OT_MAX_AUDIO_STREAM_LEN);
while (adec_ctl->start == TD_TRUE) {
/* read from file */
aud_stream.stream = audio_stream;
read_len = fread(aud_stream.stream, 1, len, pfd);
if (read_len <= 0) {
fseek(pfd, 0, SEEK_SET); /* read file again */
continue;
}
/* here only demo adec streaming sending mode, but pack sending mode is commended */
aud_stream.len = read_len;
ret = ss_mpi_adec_send_stream(adec_chn, &aud_stream, TD_TRUE);
if (ret != TD_SUCCESS) {
sample_prt("%s: ss_mpi_adec_send_stream(%d) failed with %#x!\n",
__FUNCTION__, adec_chn, ret);
break;
}
}
free(audio_stream);
audio_stream = NULL;
fclose(pfd);
adec_ctl->start = TD_FALSE;
return NULL;
}
/*
* function : create the thread to get stream from file and send to adec
*/
td_s32 hdmi_mst_comm_creat_trd_file_adec(ot_adec_chn ad_chn, td_char *src_path)
{
td_char *path = TD_NULL;
sample_adec *adec = NULL;
if (src_path == NULL) {
return TD_FAILURE;
}
if (ad_chn >= OT_ADEC_MAX_CHN_NUM) {
sample_prt("param err!\n");
return TD_FAILURE;
}
adec = &g_sample_adec[ad_chn];
adec->ad_chn = ad_chn;
path = realpath(src_path, TD_NULL);
if (path == TD_NULL) {
sample_prt("\033[31;1m realpath err! \033[0m\n");
return TD_FAILURE;
}
adec->pfd = fopen(path, "rb");
if (adec->pfd == NULL) {
sample_prt("open file %s failed\n", path);
free(path);
return TD_FAILURE;
}
adec->start = TD_TRUE;
pthread_create(&adec->ad_pid, 0, hdmi_mst_comm_adec_proc, adec);
free(path);
return TD_SUCCESS;
}
/*
* function : file -> a_dec -> ao
*/
td_void hdmi_mst_adec_ao(ot_aio_attr *attr, td_char *src_path)
{
td_s32 i;
td_s32 ao_chn_cnt;
g_audio_input.ao_dev = 1;
if (attr == NULL) {
sample_prt("\033[31;1m%s: input point is invalid!\033[0m\n", __FUNCTION__);
return;
}
hdmi_mst_audio_start_hdmi(attr);
ao_chn_cnt = (td_s32)(attr->chn_cnt >> (td_u32)attr->snd_mode);
for (i = 0; i < ao_chn_cnt; i++) {
hdmi_if_not_success_return_void(hdmi_mst_start_adec(i, g_payload_type), "start_adec");
}
hdmi_if_not_success_return_void(hdmi_mst_comm_start_ao(g_audio_input.ao_dev, ao_chn_cnt, attr,
g_steam_smple_rate, g_resample_en), "start_ao");
for (i = 0; i < ao_chn_cnt; i++) {
hdmi_if_not_success_return_void(hdmi_mst_comm_ao_bind_adec(g_audio_input.ao_dev, i, i), "ao_bind_adec");
hdmi_if_not_success_return_void(hdmi_mst_comm_creat_trd_file_adec(i, src_path), "creat_trd_file_adec");
}
return;
}
td_s32 sample_hdmi_start_audio(td_void)
{
td_u32 strm_smprate;
td_u32 strm_point_num;
ot_aio_attr attr = {0};
if (g_audio_input_modified != TD_TRUE) {
g_audio_input.src_path = AUDIO_STREAM_PATH;
g_audio_input.chnl_num = AUDIO_CHANNEL_CNT;
g_audio_input.sample_rate = OT_HDMI_SAMPLE_RATE_48K;
}
g_payload_type = OT_PT_LPCM;
/* init aio. all of cases will use it */
attr.bit_width = OT_AUDIO_BIT_WIDTH_16;
attr.work_mode = OT_AIO_MODE_I2S_MASTER;
attr.snd_mode = OT_AUDIO_SOUND_MODE_MONO;
attr.expand_flag = 0;
attr.frame_num = NUM_30;
attr.chn_cnt = AUDIO_CHANNEL_CNT;
attr.clk_share = 1;
attr.i2s_type = OT_AIO_I2STYPE_INNERHDMI;
attr.point_num_per_frame = AACLC_SAMPLES_PER_FRAME;
if (g_audio_input.sample_rate == OT_HDMI_SAMPLE_RATE_48K) {
attr.sample_rate = OT_AUDIO_SAMPLE_RATE_48000;
} else if (g_audio_input.sample_rate == OT_HDMI_SAMPLE_RATE_44K) {
attr.sample_rate = OT_AUDIO_SAMPLE_RATE_44100;
} else if (g_audio_input.sample_rate == OT_HDMI_SAMPLE_RATE_32K) {
attr.sample_rate = OT_AUDIO_SAMPLE_RATE_32000;
} else {
sample_prt("wrong audio sample rate: %d!\n", g_audio_input.sample_rate);
return TD_FAILURE;
}
strm_smprate = OT_AUDIO_SAMPLE_RATE_8000;
strm_point_num = NUM_320;
attr.point_num_per_frame = strm_point_num * attr.sample_rate / strm_smprate;
if (attr.point_num_per_frame > OT_MAX_AO_POINT_NUM || attr.point_num_per_frame < OT_MIN_AUDIO_POINT_NUM) {
sample_prt("invalid OT_PT_num_per_frm:%d\n", attr.point_num_per_frame);
return TD_FAILURE;
}
g_resample_en = TD_TRUE;
g_steam_smple_rate = strm_smprate;
hdmi_mst_adec_ao(&attr, g_audio_input.src_path);
g_audio_snd_mode = attr.snd_mode;
return TD_SUCCESS;
}
/*
* function : destroy the thread to get stream from file and send to adec
*/
td_s32 hdmi_mst_comm_destory_trd_file_adec(ot_adec_chn ad_chn)
{
sample_adec *adec = NULL;
if (ad_chn >= OT_ADEC_MAX_CHN_NUM) {
printf("err param ad_chn: %d\n", ad_chn);
return TD_FAILURE;
}
adec = &g_sample_adec[ad_chn];
if (adec->start) {
adec->start = TD_FALSE;
pthread_join(adec->ad_pid, 0);
}
return TD_SUCCESS;
}
td_s32 hdmi_mst_comm_stop_ao(ot_audio_dev ao_dev_id, td_s32 ao_chn_cnt, td_bool resample_en)
{
td_s32 i, ret;
for (i = 0; i < ao_chn_cnt; i++) {
if (resample_en == TD_TRUE) {
ret = ss_mpi_ao_disable_resample(ao_dev_id, i);
if (ret != TD_SUCCESS) {
return ret;
}
}
ret = ss_mpi_ao_disable_chn(ao_dev_id, i);
if (ret != TD_SUCCESS) {
return ret;
}
}
ret = ss_mpi_ao_disable(ao_dev_id);
if (ret != TD_SUCCESS) {
return ret;
}
return TD_SUCCESS;
}
/*
* function : stop adec
*/
td_s32 hdmi_mst_comm_stop_adec(ot_adec_chn ad_chn)
{
td_s32 ret;
ret = ss_mpi_adec_destroy_chn(ad_chn);
if (ret != TD_SUCCESS) {
return ret;
}
return TD_SUCCESS;
}
td_s32 sample_hdmi_stop_audio(td_void)
{
td_s32 ret;
td_u32 i;
td_u32 ao_chn_cnt = g_audio_input.chnl_num >> (td_u32)g_audio_snd_mode;
for (i = 0; i < ao_chn_cnt; i++) {
ret = hdmi_mst_comm_destory_trd_file_adec(i);
ret = hdmi_mst_comm_ao_unbind_adec(g_audio_input.ao_dev, i, i);
}
ret = hdmi_mst_comm_stop_ao(g_audio_input.ao_dev, ao_chn_cnt, g_resample_en);
for (i = 0; i < ao_chn_cnt; i++) {
ret = hdmi_mst_comm_stop_adec(i);
}
return ret;
}