From 6bdc30f9cf62c039d3f15be4c4c13df18ca5d37f Mon Sep 17 00:00:00 2001 From: Peng Yixin Date: Thu, 26 Nov 2020 20:41:57 +0800 Subject: [PATCH] media_module: mpeg2 discard dirty data [1/1] PD#SWPL-37142 Problem: Due to a lot of dirty data sent by demux, the decoder could not decode and the data was overflowed, cause out of sync. Solution: Adding code to discard dirty data solves this problem Verify: SC2 Change-Id: I53c53441afe5768c74239ae8ef0fc7df7f343db0 Signed-off-by: Peng Yixin --- .../decoder/mpeg12/vmpeg12_multi.c | 61 +++++++++++++++-- drivers/frame_provider/decoder/utils/vdec.c | 68 +++++++++++++++++++ drivers/frame_provider/decoder/utils/vdec.h | 4 ++ 3 files changed, 129 insertions(+), 4 deletions(-) diff --git a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c index 4113c66..e988ec5 100644 --- a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c +++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c @@ -334,6 +334,7 @@ struct vdec_mpeg12_hw_s { int sidebind_channel_id; u32 profile_idc; u32 level_idc; + int dec_again_cnt; }; static void vmpeg12_local_init(struct vdec_mpeg12_hw_s *hw); static int vmpeg12_hw_ctx_restore(struct vdec_mpeg12_hw_s *hw); @@ -356,7 +357,8 @@ unsigned int mpeg12_debug_mask = 0xff; /*static int counter_max = 5;*/ static u32 run_ready_min_buf_num = 2; - +static int dirty_again_threshold = 100; +static int error_proc_policy = 0x1; #define PRINT_FLAG_ERROR 0x0 #define PRINT_FLAG_RUN_FLOW 0X0001 @@ -1306,8 +1308,7 @@ static void vmmpeg2_reset_userdata_fifo(struct vdec_s *vdec, int bInit) if (hw) { mutex_lock(&hw->userdata_mutex); - pr_info("%s: bInit: %d, ri: %d, wi: %d\n", - __func__, + pr_info("mpeg2_reset_userdata_fifo: bInit: %d, ri: %d, wi: %d\n", bInit, hw->userdata_info.read_index, hw->userdata_info.write_index); @@ -2224,8 +2225,9 @@ static void vmpeg12_work_implement(struct vdec_mpeg12_hw_s *hw, debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, "%s, result=%d, status=%d\n", __func__, hw->dec_result, vdec->next_status); - if (hw->dec_result == DEC_RESULT_DONE) { + if (vdec->input.swap_valid) + hw->dec_again_cnt = 0; vdec_vframe_dirty(vdec, hw->chunk); hw->chunk = NULL; } else if (hw->dec_result == DEC_RESULT_AGAIN && @@ -2242,6 +2244,7 @@ static void vmpeg12_work_implement(struct vdec_mpeg12_hw_s *hw, #ifdef AGAIN_HAS_THRESHOLD hw->next_again_flag = 1; #endif + //hw->dec_again_cnt++; } else if (hw->dec_result == DEC_RESULT_GET_DATA && vdec->next_status != VDEC_STATUS_DISCONNECTED) { if (!vdec_has_more_input(vdec)) { @@ -3016,6 +3019,7 @@ static void vmpeg12_local_init(struct vdec_mpeg12_hw_s *hw) hw->buffer_not_ready = 0; hw->start_process_time = 0; hw->init_flag = 0; + hw->dec_again_cnt = 0; hw->error_frame_skip_level = error_frame_skip_level; if (dec_control) @@ -3182,6 +3186,37 @@ static unsigned char get_data_check_sum return sum; } +static int check_dirty_data(struct vdec_s *vdec) +{ + struct vdec_mpeg12_hw_s *hw = + (struct vdec_mpeg12_hw_s *)(vdec->private); + u32 wp, rp, level; + + rp = STBUF_READ(&vdec->vbuf, get_rp); + wp = STBUF_READ(&vdec->vbuf, get_wp); + + if (wp > rp) + level = wp - rp; + else + level = wp + vdec->input.size - rp ; + + if (hw->next_again_flag && + hw->pre_parser_wr_ptr != + STBUF_READ(&vdec->vbuf, get_wp)) + hw->dec_again_cnt++; + if ((level > (vdec->input.size * 2 / 3) ) && + (hw->dec_again_cnt > dirty_again_threshold)) { + debug_print(DECODE_ID(hw), 0, "mpeg12 data skipped %x, level %x\n", ((level / 2) >> 20) << 20, level); + if (vdec->input.swap_valid) { + vdec_stream_skip_data(vdec, ((level / 2) >> 20) << 20); + hw->dec_again_cnt = 0; + } + return 1; + } + return 0; +} + + static void run(struct vdec_s *vdec, unsigned long mask, void (*callback)(struct vdec_s *, void *), void *arg) @@ -3200,6 +3235,19 @@ void (*callback)(struct vdec_s *, void *), hw->vdec_cb_arg = arg; hw->vdec_cb = callback; + if ((vdec_stream_based(vdec)) && + (error_proc_policy & 0x1) && + check_dirty_data(vdec)) { + hw->dec_result = DEC_RESULT_AGAIN; + if (!vdec->input.swap_valid) { + debug_print(DECODE_ID(hw), 0, "mpeg12 start dirty data skipped\n"); + vdec_prepare_input(vdec, &hw->chunk); + hw->dec_result = DEC_RESULT_DONE; + } + vdec_schedule_work(&hw->work); + return; + } + #ifdef AGAIN_HAS_THRESHOLD if (vdec_stream_based(vdec)) { hw->pre_parser_wr_ptr = @@ -3665,6 +3713,9 @@ module_param_array(max_process_time, uint, &max_decode_instance_num, 0664); module_param(udebug_flag, uint, 0664); MODULE_PARM_DESC(udebug_flag, "\n ammvdec_mpeg12 udebug_flag\n"); +module_param(dirty_again_threshold, int, 0664); +MODULE_PARM_DESC(dirty_again_threshold, "\n ammvdec_mpeg12 dirty_again_threshold\n"); + #ifdef AGAIN_HAS_THRESHOLD module_param(again_threshold, uint, 0664); @@ -3674,6 +3725,8 @@ MODULE_PARM_DESC(again_threshold, "\n again_threshold\n"); module_param(without_display_mode, uint, 0664); MODULE_PARM_DESC(without_display_mode, "\n ammvdec_mpeg12 without_display_mode\n"); +module_param(error_proc_policy, uint, 0664); +MODULE_PARM_DESC(error_proc_policy, "\n ammvdec_mpeg12 error_proc_policy\n"); module_init(ammvdec_mpeg12_driver_init_module); module_exit(ammvdec_mpeg12_driver_remove_module); diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c index 42d7c7f..a096e30 100644 --- a/drivers/frame_provider/decoder/utils/vdec.c +++ b/drivers/frame_provider/decoder/utils/vdec.c @@ -1355,6 +1355,74 @@ static void vdec_sync_input_write(struct vdec_s *vdec) } } +void vdec_stream_skip_data(struct vdec_s *vdec, int skip_size) +{ + u32 rp_set; + struct vdec_input_s *input = &vdec->input; + u32 rp = 0, wp = 0, level; + + rp = STBUF_READ(&vdec->vbuf, get_rp); + wp = STBUF_READ(&vdec->vbuf, get_wp); + pr_err("aaaa wp %x, rp %x\n", wp, rp); + pr_err("1VLD_MEM_VIFIFO_RP %x\n", rp); + + if (wp > rp) + level = wp - rp; + else + level = wp + vdec->input.size - rp ; + + if (level <= skip_size) { + pr_err("skip size is error, buffer level = 0x%x, skip size = 0x%x\n", level, skip_size); + return; + } + + if (wp >= rp) { + pr_err("case 1\n"); + rp_set = rp + skip_size; + } + else if ((rp + skip_size) < (input->start + input->size)) { + pr_err("case 2\n"); + rp_set = rp + skip_size; + } else { + pr_err("case 3\n"); + rp_set = rp + skip_size - input->size; + input->stream_cookie++; + } + + if (vdec->format == VFORMAT_H264) + SET_VREG_MASK(POWER_CTL_VLD, + (1 << 9)); + + WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0); + + /* restore read side */ + WRITE_VREG(VLD_MEM_SWAP_ADDR, + input->swap_page_phys); + WRITE_VREG(VLD_MEM_SWAP_CTL, 1); + + while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7)) + ; + WRITE_VREG(VLD_MEM_SWAP_CTL, 0); + + WRITE_VREG(VLD_MEM_VIFIFO_CURR_PTR, + rp_set); + WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 1); + WRITE_VREG(VLD_MEM_VIFIFO_CONTROL, 0); + STBUF_WRITE(&vdec->vbuf, set_rp, + rp_set); + WRITE_VREG(VLD_MEM_SWAP_ADDR, + input->swap_page_phys); + WRITE_VREG(VLD_MEM_SWAP_CTL, 3); + while (READ_VREG(VLD_MEM_SWAP_CTL) & (1<<7)) + ; + WRITE_VREG(VLD_MEM_SWAP_CTL, 0); + pr_err("2VLD_MEM_VIFIFO_RP %x\n", READ_VREG(VLD_MEM_VIFIFO_RP)); + +} +EXPORT_SYMBOL(vdec_stream_skip_data); + + + /* *get next frame from input chain */ diff --git a/drivers/frame_provider/decoder/utils/vdec.h b/drivers/frame_provider/decoder/utils/vdec.h index b11888e..63b786c 100644 --- a/drivers/frame_provider/decoder/utils/vdec.h +++ b/drivers/frame_provider/decoder/utils/vdec.h @@ -484,5 +484,9 @@ extern u32 timestamp_avsync_counter_get(void); int vdec_resource_checking(struct vdec_s *vdec); + void vdec_set_profile_level(struct vdec_s *vdec, u32 profile_idc, u32 level_idc); + +extern void vdec_stream_skip_data(struct vdec_s *vdec, int skip_size); + #endif /* VDEC_H */ -- 2.20.1