media_module: mpeg2 discard dirty data [1/1]
authorPeng Yixin <yixin.peng@amlogic.com>
Thu, 26 Nov 2020 12:41:57 +0000 (20:41 +0800)
committerHui Zhang <hui.zhang@amlogic.com>
Mon, 30 Nov 2020 03:10:22 +0000 (19:10 -0800)
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 <yixin.peng@amlogic.com>
drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c
drivers/frame_provider/decoder/utils/vdec.c
drivers/frame_provider/decoder/utils/vdec.h

index 4113c661ef88103eef01f87e36cae716664fdbd0..e988ec50801ec8a25e52fa6ab5fc54fc0f0fd5cb 100644 (file)
@@ -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);
index 42d7c7fe90250ff5d1c49ff1f58331a7451cbe3d..a096e306953623fe58f4a61354cd32377ebfd5b2 100644 (file)
@@ -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
  */
index b11888ea2642f4138a9d75a35bed802811f011d7..63b786c42180c8b92c0ea47d0407642411096ced 100644 (file)
@@ -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 */