/* * Copyright (C) 2020-2022 Artinchip Technology Co. Ltd * * author: * Desc: h264 register config * */ #include #include #include "h264_decoder.h" #include "h264_hal.h" #include "ve_top_register.h" #include "ve.h" #include "mpp_log.h" #define MAX(a,b) ((a) > (b) ? (a) : (b)) static void write_reg(unsigned long reg_addr, u32 val, FILE* fp) { write_reg_u32(reg_addr, val); if(fp) { fprintf(fp, "write_reg %08x %08x\n", (u32)reg_addr, val); } } static u32 read_reg(unsigned long reg_addr) { return read_reg_u32(reg_addr); } static void ve_config_ve_top_reg(struct h264_dec_ctx *s) { write_reg(s->regs_base + VE_CLK_REG, 1, s->fp_reg); write_reg(s->regs_base + VE_RST_REG, RST_AVC_PIC_MODULE, s->fp_reg); while(1) { u32 tmp = 0; tmp = read_reg(s->regs_base + VE_RST_REG); if ((tmp>>16) == 0) break; } write_reg(s->regs_base + VE_INIT_REG, 1, s->fp_reg); write_reg(s->regs_base + VE_IRQ_REG, 1, s->fp_reg); write_reg(s->regs_base + VE_AVC_EN_REG, 1, s->fp_reg); } static void ve_reset_pic_info_reg(struct h264_dec_ctx *s) { write_reg(s->regs_base + VE_RST_REG, RST_PIC_MODULE, s->fp_reg); while (1) { u32 tmp = 0; tmp = read_reg(s->regs_base + VE_RST_REG); if ((tmp>>16) == 0) break; } write_reg(s->regs_base + VE_IRQ_REG, 1, s->fp_reg); write_reg(s->regs_base + VE_AVC_EN_REG, 1, s->fp_reg); } // enable irq here, because it will disable irq in irq_handle function (aic_ve driver) static void enable_irq(struct h264_dec_ctx *s) { write_reg(s->regs_base + VE_IRQ_REG, 1, s->fp_reg); } static void config_sps(struct h264_dec_ctx *s) { if(s->fp_reg) fprintf(s->fp_reg, "// config sequence parameter set\n"); struct h264_sps_info* cur_sps = s->sps_buffers[s->active_sps_id]; struct reg_avc_sps avc_sps; u32* pdwTemp; memset(&avc_sps, 0, sizeof(struct reg_avc_sps)); pdwTemp = (u32*)&avc_sps; avc_sps.direct_8x8_inference_flag = cur_sps->direct_8x8_inference_flag; avc_sps.mb_adaptive_frame_filed_flag = cur_sps->mbaff; avc_sps.frame_mbs_only_flag = cur_sps->frame_mbs_only_flag; avc_sps.pic_height_in_map_units_minus1 = cur_sps->pic_mb_height - 1; avc_sps.pic_width_in_mbs_minus1 = cur_sps->pic_mb_width - 1; avc_sps.chroma_format_idc = cur_sps->chroma_format_idc; avc_sps.uv_interleave = (s->pix_format == MPP_FMT_NV12 || s->pix_format == MPP_FMT_NV21); avc_sps.uv_alter = s->pix_format == MPP_FMT_NV21; avc_sps.pic_init = (s->sh.first_mb_in_slice == 0); write_reg(s->regs_base + AVC_SPS_REG, *pdwTemp, s->fp_reg); } static void config_avc_pps_register(struct h264_dec_ctx *s) { struct h264_pps_info* cur_pps = s->pps_buffers[s->active_pps_id]; struct reg_avc_pps avc_pps; u32* pdwTemp; if(s->fp_reg) fprintf(s->fp_reg, "// config picture parameter set\n"); memset(&avc_pps, 0, sizeof(struct reg_avc_pps)); pdwTemp = (u32*)(&avc_pps); avc_pps.constrained_intra_pred_flag = cur_pps->constrained_intra_pred_flag; avc_pps.entropy_coding_mode_flag = cur_pps->entropy_coding_flag; avc_pps.num_ref_idx_l0_active_minus1_pic = cur_pps->num_ref_idx[0] - 1; avc_pps.num_ref_idx_l1_active_minus1_pic = cur_pps->num_ref_idx[1] - 1; avc_pps.transform_8x8_mode_flag = cur_pps->transform_8x8_mode_flag; avc_pps.weighted_bipred_idc = cur_pps->weighted_bipred_flag; avc_pps.weighted_pred_flag = cur_pps->weighted_pred_flag; write_reg(s->regs_base + AVC_PPS_REG, *pdwTemp, s->fp_reg); } static void config_avc_sh_register(struct h264_dec_ctx *s) { struct h264_slice_header* sh = &s->sh; struct h264_sps_info* cur_sps = s->sps_buffers[s->active_sps_id]; struct h264_pps_info* cur_pps = s->pps_buffers[s->active_pps_id]; struct reg_avc_sh1 avc_sh1; struct reg_avc_sh2 avc_sh2; struct reg_avc_shs_wp avc_wp; struct reg_avc_shs_qp avc_qp; int mb_x = sh->first_mb_in_slice % cur_sps->pic_mb_width; int mb_y = (sh->first_mb_in_slice / cur_sps->pic_mb_width) << cur_sps->mbaff; if(s->fp_reg) fprintf(s->fp_reg, "// config slice header\n"); memset(&avc_sh1, 0, 4); memset(&avc_sh2, 0, 4); memset(&avc_wp, 0, 4); memset(&avc_qp, 0, 4); u32* pdwTemp; pdwTemp = (u32*)(&avc_sh1); avc_sh1.slice_type = sh->slice_type; avc_sh1.cabac_init_idc = sh->cabac_init_idc; avc_sh1.nal_ref_flag = (s->nal_ref_idc != 0); avc_sh1.direct_spatial_mv_pred_flag = sh->direct_spatial_mv_pred; avc_sh1.bottom_field_flag = sh->bottom_field_flag; avc_sh1.field_pic_flag = sh->field_pic_flag; avc_sh1.first_slice_in_pic = (sh->first_mb_in_slice == 0); avc_sh1.first_mb_x = mb_x; avc_sh1.first_mb_y = mb_y; write_reg(s->regs_base + AVC_SHS1_REG, *pdwTemp, s->fp_reg); pdwTemp = (u32*)(&avc_sh2); avc_sh2.slice_beta_offset_div2 = sh->slice_beta_offset_div2; avc_sh2.slice_alpha_offset_div2 = sh->slice_alpha_c0_offset_div2; avc_sh2.disable_deblocking_filter_idc = sh->deblocking_filter; avc_sh2.num_ref_idx_active_override_flag = sh->num_ref_idx_active_override; avc_sh2.num_ref_idx_l0_active_minus1 = sh->num_ref_idx[0] - 1; avc_sh2.num_ref_idx_l1_active_minus1 = sh->num_ref_idx[1] - 1; write_reg(s->regs_base + AVC_SHS2_REG, *pdwTemp, s->fp_reg); pdwTemp = (u32*)(&avc_wp); avc_wp.chroma_log2_weight_denom = sh->pwt.chroma_log2_weight_denom; avc_wp.luma_log2_weight_denom = sh->pwt.luma_log2_weight_denom; write_reg(s->regs_base + AVC_SHS_WP_REG, *pdwTemp, s->fp_reg); pdwTemp = (u32*)(&avc_qp); avc_qp.chroma_qp_idx_offset = cur_pps->chroma_qp_index_offset[0]; avc_qp.second_chroma_qp_idx_offset = cur_pps->chroma_qp_index_offset[1]; avc_qp.slice_qpy = sh->qp_y; write_reg(s->regs_base + AVC_SHS_QP_REG, *pdwTemp, s->fp_reg); } static void init_decode_mb_number(struct h264_dec_ctx *s) { if(s->sh.first_mb_in_slice == 0) write_reg(s->regs_base + CORRECT_DECODE_MB_NUMBER_REG, s->sh.first_mb_in_slice, s->fp_reg); } static void config_weight_pred_para(struct h264_dec_ctx *s) { int i; int comp; struct h264_slice_header* sh = &s->sh; struct reg_avc_weight_pred avc_wp; u32* pdwTemp; if(s->fp_reg) fprintf(s->fp_reg, "// config weighted pred\n"); memset(&avc_wp, 0, 4); pdwTemp = (u32*)&avc_wp; // list0 for(comp = 0; comp < 3; comp++) { for (i = 0; i < 32; i++) { avc_wp.weight_pred_addr = 32*comp + i; if (i < sh->num_ref_idx[0]) { avc_wp.weight = sh->pwt.wp_weight[0][i][comp]; avc_wp.offset = sh->pwt.wp_offset[0][i][comp]; } else { avc_wp.weight = 1; avc_wp.offset = 0; } write_reg(s->regs_base + AVC_WEIGHT_PRED_REGISTER, *pdwTemp, s->fp_reg); } } // list1 for(comp = 0; comp < 3; comp++) { for (i = 0; i < 32; i++) { avc_wp.weight_pred_addr = 96 + 32*comp + i; if (i < sh->num_ref_idx[1]) { avc_wp.weight = sh->pwt.wp_weight[1][i][comp]; avc_wp.offset = sh->pwt.wp_offset[1][i][comp]; } else { avc_wp.weight = 1; avc_wp.offset = 0; } write_reg(s->regs_base + AVC_WEIGHT_PRED_REGISTER, *pdwTemp, s->fp_reg); } } } static void config_quant_matrix(struct h264_dec_ctx *s) { struct h264_pps_info* cur_pps = s->pps_buffers[s->active_pps_id]; struct reg_avc_scaling_matrix avc_scale_matrix; u32* pdwTemp; int i, j; if(s->fp_reg) fprintf(s->fp_reg, "// config quant matrix\n"); memset(&avc_scale_matrix, 0, 4); pdwTemp = (u32*)&avc_scale_matrix; avc_scale_matrix.matrix_access = 1; avc_scale_matrix.write_enable = 1; //4x4 for (i = 0; i<6; i++) { avc_scale_matrix.matrix_addr = i; for (j = 0; j<16; j++) { avc_scale_matrix.matrix_addr = i * 16 + j; avc_scale_matrix.scaling_matrix_data = cur_pps->scaling_matrix4[i][j]; write_reg(s->regs_base + AVC_SCALING_MATRIX_REGISTER, *pdwTemp, s->fp_reg); } } //8x8 for (i = 0; i<2; i++) { avc_scale_matrix.matrix_addr = i + 6; for (j = 0; j<64; j++) { avc_scale_matrix.matrix_addr = 96 + i * 64 + j; avc_scale_matrix.scaling_matrix_data = cur_pps->scaling_matrix8[i][j]; write_reg(s->regs_base + AVC_SCALING_MATRIX_REGISTER, *pdwTemp, s->fp_reg); } } write_reg(s->regs_base + AVC_SCALING_MATRIX_REGISTER, 0, s->fp_reg); } static void config_reflist(struct h264_dec_ctx *s) { struct h264_slice_header* sh = &s->sh; struct reg_avc_ref_list avc_ref_list; struct h264_picture* pic = NULL; u32* pdwTemp; int i; if(s->fp_reg) fprintf(s->fp_reg, "// config reflist\n"); memset(&avc_ref_list, 0, 4); pdwTemp = (u32*)&avc_ref_list; avc_ref_list.ref_idx_rw = 1; for (i = 0; i < MAX(sh->num_ref_idx[0], sh->num_ref_idx[1]); i++) { avc_ref_list.ref_idx = i; if (i < sh->num_ref_idx[0] && (sh->slice_type == H264_SLICE_P || sh->slice_type == H264_SLICE_B)) { pic = s->frame_info.ref_list[0][i].parent; if (pic) { avc_ref_list.buf_idx_list0 = pic->buf_idx; } else { logw("ref idx maybe error"); avc_ref_list.buf_idx_list0 = 0; } avc_ref_list.field_sel_list0 = (s->frame_info.ref_list[0][i].refrence == PICT_BOTTOM_FIELD); } if(inum_ref_idx[1] && sh->slice_type == H264_SLICE_B) { pic = s->frame_info.ref_list[1][i].parent; if (pic) { avc_ref_list.buf_idx_list1 = pic->buf_idx; } else { logw("ref idx maybe error"); avc_ref_list.buf_idx_list1 = 0; } avc_ref_list.field_sel_list1 = (s->frame_info.ref_list[1][i].refrence == PICT_BOTTOM_FIELD); } write_reg(s->regs_base + AVC_REF_LIST_REGISTER, *pdwTemp, s->fp_reg); } write_reg(s->regs_base + AVC_REF_LIST_REGISTER, 0, s->fp_reg); } static void config_frame_info(struct h264_dec_ctx *s, struct h264_picture* pic) { struct frame_struct_ref_info frm_info; struct reg_avc_buf_info avc_buf_info; int cur_frame_idx = s->frame_info.cur_pic_ptr->buf_idx; memset(&frm_info, 0, 4); memset(&avc_buf_info, 0, 4); u32* buf_info = (u32*)&avc_buf_info; u32* ptr_tmp; logd("s->picture_structure: %d", s->picture_structure); if(s->picture_structure == PICT_FRAME) { // top poc ( select 0 ) avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = pic->buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 0; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, pic->field_poc[0], s->fp_reg); // bot poc (select 1) avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = pic->buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 1; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, pic->field_poc[1], s->fp_reg); // frame_info (select 2) avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = pic->buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 2; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); frm_info.frm_struct = s->sh.mbaff_frame ? 2 : 0; frm_info.top_ref_type = frm_info.bot_ref_type = s->nal_ref_idc ? 0: 2; ptr_tmp = (u32*)&frm_info; write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, *ptr_tmp, s->fp_reg); } else if(s->picture_structure == PICT_TOP_FIELD) { // top poc avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = pic->buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 0; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, pic->field_poc[0], s->fp_reg); // frame_info avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = pic->buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 2; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); frm_info.top_ref_type = s->nal_ref_idc ? 0: 2; frm_info.frm_struct = 1; ptr_tmp = (u32*)&frm_info; write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, *ptr_tmp, s->fp_reg); } else if(s->picture_structure == PICT_BOTTOM_FIELD) { // bot poc avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = pic->buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 1; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, pic->field_poc[1], s->fp_reg); // frame_info avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = pic->buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 2; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); frm_info.bot_ref_type = s->nal_ref_idc ? 0: 2; frm_info.frm_struct = 1; ptr_tmp = (u32*)&frm_info; write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, *ptr_tmp, s->fp_reg); } // top co-located info addr (select 5) avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = pic->buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 5; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, pic->top_field_col_addr, s->fp_reg); // bot co-located info addr (select 6) avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = pic->buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 6; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, pic->bot_field_col_addr, s->fp_reg); } struct frame_info { int used; int buf_idx; int field_poc[2]; int frame_stucture; //0:frame; 1:field; 2: mbaff int top_ref_type; // 0: short-term; 1: long-term; 2: non-ref int bot_ref_type; // 0: short-term; 1: long-term; 2: non-ref }; static int get_ref_type(struct h264_picture* pic, int is_bottom_field) { if(pic->nal_ref_idc[is_bottom_field] == 0) return 2; return pic->long_ref ? 1: 0; } /* if the refrence frame is field, for example top field, we should find the bottom field of this frame, then config the frame(including top and bottom field) info to register */ static void config_refrence_frame_info(struct h264_dec_ctx *s) { int i=0; int j=0; int list = 0; struct frame_info frame_info[32]; int valid_frame[32] = {0}; int valid_frame_num = 0; struct h264_picture* pic = NULL; struct frame_struct_ref_info frm_info; struct reg_avc_buf_info avc_buf_info; memset(&avc_buf_info, 0, 4); u32* buf_info = (u32*)&avc_buf_info; u32* ptr_tmp; int cur_frame_idx = s->frame_info.cur_pic_ptr->buf_idx; memset(frame_info, 0, 32*sizeof(struct frame_info)); //* 1. find the corresponding top/bottom field, //* then save the info to frame_info logd("list_count: %d, num_ref: %d", s->sh.list_count, s->sh.num_ref_idx[0]); for(list=0; listsh.list_count; list++) { for(i=0; ish.num_ref_idx[list]; i++) { int buf_idx = 0; pic = s->frame_info.ref_list[list][i].parent; if (pic) { buf_idx = pic->buf_idx; frame_info[buf_idx].buf_idx = buf_idx; if(pic->refrence == PICT_FRAME) { //* current picture is used for refrence frame_info[buf_idx].field_poc[0] = pic->field_poc[0]; frame_info[buf_idx].field_poc[1] = pic->field_poc[1]; frame_info[buf_idx].frame_stucture = 1; if(pic->picture_structure == PICT_FRAME) { frame_info[buf_idx].frame_stucture = pic->mbaff_frame ? 2: 0; } // maybe error, long-term/short-term? frame_info[buf_idx].top_ref_type = get_ref_type(pic, 0); frame_info[buf_idx].bot_ref_type = get_ref_type(pic, 1); } else if(pic->refrence == PICT_TOP_FIELD) { // top field of current picture is used for refrence frame_info[buf_idx].field_poc[0] = pic->field_poc[0]; frame_info[buf_idx].frame_stucture = 1; frame_info[buf_idx].top_ref_type = get_ref_type(pic, 0); } else if(pic->refrence == PICT_BOTTOM_FIELD) { frame_info[buf_idx].field_poc[1] = pic->field_poc[1]; frame_info[buf_idx].frame_stucture = 1; frame_info[buf_idx].top_ref_type = get_ref_type(pic, 1); } } else { logw("ref list maybe error"); frame_info[0].field_poc[0] = 0; frame_info[0].field_poc[1] = 0; frame_info[0].frame_stucture = 0; frame_info[0].top_ref_type = 0; frame_info[0].bot_ref_type = 0; } valid_frame[valid_frame_num] = buf_idx; if(frame_info[buf_idx].used == 0) valid_frame_num ++; frame_info[buf_idx].used = 1; } } logd("valid_frame_num: %d", valid_frame_num); //* config reference frame info register for(i=0; iregs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, frame_info[j].field_poc[0], s->fp_reg); // bot poc (select 1) avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = frame_info[j].buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 1; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, frame_info[j].field_poc[1], s->fp_reg); // frame_info (select 2) frm_info.frm_struct = frame_info[j].frame_stucture; frm_info.top_ref_type = frame_info[j].top_ref_type; frm_info.bot_ref_type = frame_info[j].bot_ref_type; avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = frame_info[j].buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 2; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); ptr_tmp = (u32*)&frm_info; write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, *ptr_tmp, s->fp_reg); pic = &s->frame_info.picture[frame_info[j].buf_idx]; // top co-located info addr (select 5) avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = frame_info[j].buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 5; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, pic->top_field_col_addr, s->fp_reg); // bot co-located info addr (select 6) avc_buf_info.curr_frame_idx = cur_frame_idx; avc_buf_info.buf_idx = frame_info[j].buf_idx; avc_buf_info.buf_info_rw = 1; avc_buf_info.content_select = 6; write_reg(s->regs_base + AVC_BUF_INFO_REGISTER, *buf_info, s->fp_reg); write_reg(s->regs_base + AVC_BUF_INFO_CONTENT_REGISTER, pic->bot_field_col_addr, s->fp_reg); } } /* ************** framebuffer data struct ******** |-------------------------------------------------| | top field poc/ frame poc (32bit) | |-------------------------------------------------| | bottom field poc (32 bit) | |-------------------------------------------------| | frame_struct_ref_info (32bit) | |-------------------------------------------------| | top filed/frame motion vector collocated info | |-------------------------------------------------| | bottom field motion vector collocated info | |-------------------------------------------------| */ static void config_framebuffer_info(struct h264_dec_ctx *s) { if(s->fp_reg) fprintf(s->fp_reg, "// config framebuffer info\n"); //* config currrent frame info config_frame_info(s, s->frame_info.cur_pic_ptr); //* config reference frame info config_refrence_frame_info(s); } static void config_picture_info(struct h264_dec_ctx *s) { int i; u32* ptr_tmp = NULL; u32 phy_addr_offset[3] = {0}; struct h264_picture* pic = NULL; struct h264_picture* cur_pic = s->frame_info.cur_pic_ptr; struct frame_format_reg frm_format; memset(&frm_format, 0, sizeof(u32)); struct frame_size_reg frm_size; memset(&frm_size, 0, sizeof(u32)); frm_size.pic_xsize = s->width; frm_size.pic_ysize = s->height; if(s->fp_reg) fprintf(s->fp_reg, "// config picture info\n"); if(s->pix_format == MPP_FMT_YUV420P || s->pix_format == MPP_FMT_NV12 || s->pix_format == MPP_FMT_NV21) frm_format.color_mode = 0; else frm_format.color_mode = 4; // yuv400 frm_format.stride = cur_pic->frame->mpp_frame.buf.stride[0]; frm_format.cbcr_interleaved = (s->pix_format == MPP_FMT_NV12) || (s->pix_format == MPP_FMT_NV21); phy_addr_offset[0] = s->decoder.output_y * cur_pic->frame->mpp_frame.buf.stride[0] + s->decoder.output_x; if ((s->pix_format == MPP_FMT_NV12) || (s->pix_format == MPP_FMT_NV21)) { phy_addr_offset[1] = s->decoder.output_y * cur_pic->frame->mpp_frame.buf.stride[1] /2 + s->decoder.output_x ; } else { phy_addr_offset[1] = s->decoder.output_y * cur_pic->frame->mpp_frame.buf.stride[1] /2 + s->decoder.output_x / 2; phy_addr_offset[2] = s->decoder.output_y * cur_pic->frame->mpp_frame.buf.stride[2] /2 + s->decoder.output_x / 2; } for(i=0; iframe_info.max_valid_frame_num; i++) { pic = &s->frame_info.picture[i]; if(pic->frame) { ptr_tmp = (u32*)&frm_format; write_reg(s->regs_base + FRAME_FORMAT_REG(i), *ptr_tmp, s->fp_reg); ptr_tmp = (u32*)&frm_size; write_reg(s->regs_base + FRAME_SIZE_REG(i), *ptr_tmp, s->fp_reg); write_reg(s->regs_base + FRAME_YADDR_REG(i), pic->frame->phy_addr[0] + phy_addr_offset[0], s->fp_reg); write_reg(s->regs_base + FRAME_CBADDR_REG(i), pic->frame->phy_addr[1] + phy_addr_offset[1], s->fp_reg); write_reg(s->regs_base + FRAME_CRADDR_REG(i), pic->frame->phy_addr[2] + phy_addr_offset[2], s->fp_reg); } } } static void config_mc_register(struct h264_dec_ctx *s) { int logwd_y, logwd_c; struct h264_pps_info* cur_pps = s->pps_buffers[s->active_pps_id]; if(s->fp_reg) fprintf(s->fp_reg, "// config mc reg\n"); write_reg(s->regs_base + MC_DMA_MODE_REG, 0, s->fp_reg); int implicited_en = (s->sh.slice_type == H264_SLICE_B) && (cur_pps->weighted_bipred_flag == 2); int weighted_pred_en = (s->sh.slice_type == H264_SLICE_P && cur_pps->weighted_pred_flag) || ((s->sh.slice_type == H264_SLICE_B) && cur_pps->weighted_bipred_flag); write_reg(s->regs_base + MC_WP_EN_REG, weighted_pred_en<<1 | implicited_en, s->fp_reg); if((s->sh.slice_type == H264_SLICE_B) && (cur_pps->weighted_bipred_flag == 2)) { logwd_c = logwd_y = 5; } else { logwd_c = s->sh.pwt.chroma_log2_weight_denom; logwd_y = s->sh.pwt.luma_log2_weight_denom; } write_reg(s->regs_base + MC_WP_LOGWD_REG, logwd_c<<3 | logwd_y, s->fp_reg); } static void config_dblk_register(struct h264_dec_ctx *s) { struct h264_sps_info* cur_sps = s->sps_buffers[s->active_sps_id]; struct h264_picture* cur_pic = s->frame_info.cur_pic_ptr; u32 *ptr_tmp = NULL; if(s->fp_reg) fprintf(s->fp_reg, "// config dblk reg\n"); int tmp = (s->sh.mbaff_frame << 2) | (s->sh.field_pic_flag << 1) | s->sh.bottom_field_flag; write_reg(s->regs_base + DBLK_PIC_TYPE_REG, tmp, s->fp_reg); write_reg(s->regs_base + DBLK_PIC_SIZE_REG, (s->width<<16) | s->height, s->fp_reg); write_reg(s->regs_base + DBLK_EN_REG, 1, s->fp_reg); write_reg(s->regs_base + DBLK_BUF_Y_REG, s->frame_info.dblk_y_buf->phy_addr, s->fp_reg); write_reg(s->regs_base + DBLK_BUF_C_REG, s->frame_info.dblk_c_buf->phy_addr, s->fp_reg); struct reg_dec_config dec_config; memset(&dec_config, 0, sizeof(u32)); dec_config.dec_chroma_idc = !cur_sps->chroma_format_idc; dec_config.dec_luma_only = cur_sps->chroma_format_idc == 0; dec_config.dec_wr_en = 1; dec_config.uv_interleave = (s->pix_format == MPP_FMT_NV12) || (s->pix_format == MPP_FMT_NV21); dec_config.uv_alternative = s->pix_format == MPP_FMT_NV21; ptr_tmp = (u32*)&dec_config; write_reg(s->regs_base + DEC_CONFIG_REG, *ptr_tmp, s->fp_reg); write_reg(s->regs_base + DEC_FRAME_IDX_REG, cur_pic->buf_idx, s->fp_reg); } static void avc_reset(struct h264_dec_ctx *s) { if(s->fp_reg) fprintf(s->fp_reg, "// reset avc\n"); write_reg(s->regs_base + AVC_RESET_REG, 1, s->fp_reg); // wait until reset finish while(read_reg(s->regs_base + AVC_RESET_REG)) { }; } static void config_bitstream(struct h264_dec_ctx *s) { u32 end_addr = s->curr_packet->phy_base + s->curr_packet->phy_size - 1; u32 bit_offset = s->curr_packet->phy_offset*8 + s->bit_offset; u32 bit_length = s->curr_packet->size*8 - s->bit_offset; //logi("packet phy_offset: %d, size: %d", s->curr_packet->phy_offset, s->curr_packet->size); if (s->fp_reg) fprintf(s->fp_reg, "// config bitstream\n"); write_reg(s->regs_base + BIT_BUFFER_START_ADDR_REG, s->curr_packet->phy_base, s->fp_reg); write_reg(s->regs_base + BIT_BUFFER_END_ADDR_REG, end_addr, s->fp_reg); write_reg(s->regs_base + BIT_BUFFER_BIT_OFFSET_REG, bit_offset, s->fp_reg); write_reg(s->regs_base + BIT_BUFFER_BIT_LEN_REG, bit_length, s->fp_reg); write_reg(s->regs_base + BIT_BUFFER_DATA_VALID_REG, 0x80000003, s->fp_reg); } static void clear_interrupt_register(struct h264_dec_ctx *s) { write_reg(s->regs_base + VE_STATUS_REG, 7 << 16, s->fp_reg); } static void config_internal_memory(struct h264_dec_ctx *s) { if (s->fp_reg) fprintf(s->fp_reg, "// config internal memory\n"); write_reg(s->regs_base + MB_COL_BUF_ADDR_REG, s->frame_info.mb_col_info_buf->phy_addr, s->fp_reg); write_reg(s->regs_base + MBINFO_BUF_ADDR_REG, s->frame_info.mb_info_buf->phy_addr, s->fp_reg); write_reg(s->regs_base + MB_INTRAP_ADDR_REG, s->frame_info.intrap_buf->phy_addr, s->fp_reg); } static void config_avc_ctrl(struct h264_dec_ctx *s) { struct reg_avc_ctrl avc_ctrl; memset(&avc_ctrl, 0, 4); if (s->fp_reg) fprintf(s->fp_reg, "// slice start\n"); avc_ctrl.stcd_detect_en = 1; avc_ctrl.eptb_detection = 1; avc_ctrl.bit_request_int_enable = 1; avc_ctrl.dec_error_int_enable = 1; avc_ctrl.dec_finish_int_enable = 1; avc_ctrl.slice_start = 1; u32 *pval = (u32*)(&avc_ctrl); write_reg(s->regs_base + AVC_CTRL_REG, *pval, s->fp_reg); } int decode_slice(struct h264_dec_ctx *s) { int ret = 0; u32 status = 0; struct h264_picture* cur_pic = s->frame_info.cur_pic_ptr; struct h264_pps_info* cur_pps = s->pps_buffers[s->active_pps_id]; ve_get_client(); if(s->avc_start) { ve_config_ve_top_reg(s); avc_reset(s); s->avc_start = 0; } else { // only reset picture module ve_reset_pic_info_reg(s); } logi("s->cur_slice_num: %d", s->cur_slice_num); init_decode_mb_number(s); enable_irq(s); clear_interrupt_register(s); config_sps(s); config_avc_pps_register(s); config_avc_sh_register(s); if((s->sh.slice_type == H264_SLICE_P && cur_pps->weighted_pred_flag) || (s->sh.slice_type == H264_SLICE_B && cur_pps->weighted_bipred_flag)) config_weight_pred_para(s); config_quant_matrix(s); config_reflist(s); config_framebuffer_info(s); config_picture_info(s); config_dblk_register(s); config_mc_register(s); config_internal_memory(s); config_avc_ctrl(s); config_bitstream(s); if (ve_wait(&status) < 0) { loge("ve timeout, avc status: %x", read_reg(s->regs_base + 0x128)); logi("correct number: %d", read_reg(s->regs_base + CORRECT_DECODE_MB_NUMBER_REG)); ret = -1; goto error; } if(s->sh.slice_type == H264_SLICE_P){ logi("%p, %s slice, cycle: %d", s,"P", read_reg(s->regs_base + CYCLES_REG)); }else if(s->sh.slice_type == H264_SLICE_B){ logi("%p, %s slice, cycle: %d", s,"B", read_reg(s->regs_base + CYCLES_REG)); }else if(s->sh.slice_type == H264_SLICE_I){ logi("%p, %s slice, cycle: %d", s,"I", read_reg(s->regs_base + CYCLES_REG)); } s->decode_mb_num = read_reg(s->regs_base + CORRECT_DECODE_MB_NUMBER_REG); if (status & AVC_ERROR) { loge("decode error, status: %x", status); ret = -1; goto error; } else if (status & AVC_BIT_REQ) { logw("bit request"); ret = -1; goto error; } else if (status & AVC_FINISH) { if (status & (~AVC_FINISH)) { // the status will be 0x10100 in multi-slice case. // it is not error, so we cannot reset avc module here. // if the data is not enough to decode the whole picture, // we can justice frame error from first_mb in next slice header. } logd("finish, cur pic top poc: %d, bot poc: %d, buf_idx: %d, nal_ref_idc: %d", cur_pic->field_poc[0], cur_pic->field_poc[1], cur_pic->buf_idx, s->nal_ref_idc); ve_put_client(); return 0; } logw("unkown error"); error: cur_pic->frame->mpp_frame.flags |= FRAME_FLAG_ERROR; ve_put_client(); s->avc_start = 1; return ret; }