videosync: add pattern support [1/1]
authorjintao xu <jintao.xu@amlogic.com>
Wed, 23 Oct 2019 09:33:03 +0000 (17:33 +0800)
committerTao Zeng <tao.zeng@amlogic.com>
Fri, 25 Oct 2019 12:33:07 +0000 (05:33 -0700)
PD#SWPL-15586

Problem:
When hdmi is 59.94 and 30fps and 60fps video pts is not linearly increasing
video display in vd2 video will shake.

Solution:
Videosync add pattern support.

Verify:
U212

Change-Id: I47416681dffb6e5eddef39e9c1dfcd29cfc12b92
Signed-off-by: jintao xu <jintao.xu@amlogic.com>
drivers/amlogic/media/video_processor/videosync/videosync.c
drivers/amlogic/media/video_processor/videosync/videosync.h
drivers/amlogic/media/video_sink/video.c
drivers/amlogic/media/video_sink/video_priv.h

index 050143c..0bd41d8 100644 (file)
@@ -40,7 +40,7 @@ static u32 omx_version = 3;
 static u32 vp_debug_flag;
 static bool no_render;/* default: false */
 static bool async_mode;/* default: false */
-static u32 video_early_threshold = 900; /* default: 900=>10ms */
+/*static u32 video_early_threshold = 900;  default: 900=>10ms */
 
 
 /* video freerun mode */
@@ -52,6 +52,8 @@ static u32 video_early_threshold = 900; /* default: 900=>10ms */
 #define M_PTS_SMOOTH_ADJUST 900
 #define DURATION_GCD 750
 
+static int duration_gcd = DURATION_GCD;
+
 static int omx_pts_interval_upper = 11000;
 static int omx_pts_interval_lower = -5500;
 #define DUR2PTS(x) ((x) - ((x) >> 4))
@@ -59,12 +61,40 @@ static int omx_pts_interval_lower = -5500;
 #define PRINT_ERROR                    0X0
 #define PRINT_QUEUE_STATUS     0X0001
 #define PRINT_TIMESTAMP                0X0002
-#define PRINT_OTHER                    0X0004
+#define PRINT_PATTERN          0X0004
+#define PRINT_OTHER                    0X0008
+
 
 static struct videosync_dev *vp_dev;
 static uint show_first_frame_nosync;
+static uint max_delata_time;
+
 static u32 cur_omx_index;
 
+#define PTS_32_PATTERN_DETECT_RANGE 10
+#define PTS_22_PATTERN_DETECT_RANGE 10
+#define PTS_41_PATTERN_DETECT_RANGE 2
+#define PTS_32_PATTERN_DURATION 3750
+#define PTS_22_PATTERN_DURATION 3000
+
+enum video_refresh_pattern {
+       PTS_32_PATTERN = 0,
+       PTS_22_PATTERN,
+       PTS_41_PATTERN,
+       PTS_MAX_NUM_PATTERNS
+};
+
+static int pts_trace;
+static int pre_pts_trace;
+static bool pts_enforce_pulldown = true;
+static int pts_pattern[3] = {0, 0, 0};
+static int pts_pattern_enter_cnt[3] = {0, 0, 0};
+static int pts_pattern_exit_cnt[3] = {0, 0, 0};
+static int pts_log_enable[3] = {0, 0, 0};
+static int pts_escape_vsync = -1;
+static s32 vsync_pts_align = -DURATION_GCD / 2;
+static int pts_pattern_detected = -1;
+
 static int vp_print(char *name, int debug_flag, const char *fmt, ...)
 {
        if ((vp_debug_flag & debug_flag)
@@ -85,7 +115,7 @@ static int vp_print(char *name, int debug_flag, const char *fmt, ...)
 static u32 ts_pcrscr_get(struct videosync_s *dev_s)
 {
        u32 sys_time = 0;
-       /*unsigned long flags;*/
+
        sys_time = dev_s->system_time;
        return sys_time;
 }
@@ -106,6 +136,166 @@ static u32 ts_pcrscr_enable_state(struct videosync_s *dev_s)
        return dev_s->system_time_up;
 }
 
+static void log_vsync_video_pattern(int pattern)
+{
+       int factor1 = 0, factor2 = 0, pattern_range = 0;
+
+       if (pattern >= PTS_MAX_NUM_PATTERNS)
+               return;
+
+       if (pattern == PTS_32_PATTERN) {
+               factor1 = 3;
+               factor2 = 2;
+               pattern_range =  PTS_32_PATTERN_DETECT_RANGE;
+       } else if (pattern == PTS_22_PATTERN) {
+               factor1 = 2;
+               factor2 = 2;
+               pattern_range =  PTS_22_PATTERN_DETECT_RANGE;
+       } else if (pattern == PTS_41_PATTERN) {
+               pr_info("not support 41 pattern\n");
+               return;
+       }
+
+       /* update 3:2 or 2:2 mode detection */
+       if (((pre_pts_trace == factor1) && (pts_trace == factor2)) ||
+           ((pre_pts_trace == factor2) && (pts_trace == factor1))) {
+               if (pts_pattern[pattern] < pattern_range) {
+                       pts_pattern[pattern]++;
+                       if (pts_pattern[pattern] == pattern_range) {
+                               pts_pattern_enter_cnt[pattern]++;
+                               pts_pattern_detected = pattern;
+                               if (pts_log_enable[pattern])
+                                       pr_info("video %d:%d mode detected\n",
+                                               factor1, factor2);
+                       }
+               }
+       } else if (pts_pattern[pattern] == pattern_range) {
+               pts_pattern[pattern] = 0;
+               pts_pattern_exit_cnt[pattern]++;
+               if (pts_log_enable[pattern])
+                       pr_info("video %d:%d mode broken\n", factor1, factor2);
+       } else {
+               pts_pattern[pattern] = 0;
+       }
+}
+
+static void vsync_video_pattern(void)
+{
+       /*log_vsync_video_pattern(PTS_32_PATTERN);*/
+       log_vsync_video_pattern(PTS_22_PATTERN);
+       /*log_vsync_video_pattern(PTS_41_PATTERN);*/
+}
+
+static inline void vpts_perform_pulldown(
+       struct videosync_s *dev_s,
+       struct vframe_s *next_vf,
+       bool *expired)
+{
+       int pattern_range, expected_curr_interval;
+       int expected_prev_interval;
+       int next_vf_nextpts = 0;
+       int nextPts;
+
+       /* Dont do anything if we have invalid data */
+       if (!next_vf || !next_vf->pts)
+               return;
+       if (next_vf->next_vf_pts_valid)
+               next_vf_nextpts = next_vf->next_vf_pts;
+
+       switch (pts_pattern_detected) {
+       case PTS_32_PATTERN:
+               pattern_range = PTS_32_PATTERN_DETECT_RANGE;
+               switch (pre_pts_trace) {
+               case 3:
+                       expected_prev_interval = 3;
+                       expected_curr_interval = 2;
+                       break;
+               case 2:
+                       expected_prev_interval = 2;
+                       expected_curr_interval = 3;
+                       break;
+               default:
+                       return;
+               }
+               if (!next_vf_nextpts)
+                       next_vf_nextpts = next_vf->pts +
+                               PTS_32_PATTERN_DURATION;
+               break;
+       case PTS_22_PATTERN:
+               if (pre_pts_trace != 2)
+                       return;
+               pattern_range =  PTS_22_PATTERN_DETECT_RANGE;
+               expected_prev_interval = 2;
+               expected_curr_interval = 2;
+               if (!next_vf_nextpts)
+                       next_vf_nextpts = next_vf->pts +
+                               PTS_22_PATTERN_DURATION;
+               break;
+       case PTS_41_PATTERN:
+               /* TODO */
+       default:
+               return;
+       }
+
+       /* We do nothing if  we dont have enough data*/
+       if (pts_pattern[pts_pattern_detected] != pattern_range)
+               return;
+
+       if (*expired) {
+               if (pts_trace < expected_curr_interval) {
+                       /* 2323232323..2233..2323, prev=2, curr=3,*/
+                       /* check if next frame will toggle after 3 vsyncs */
+                       /* 22222...22222 -> 222..2213(2)22...22 */
+                       /* check if next frame will toggle after 3 vsyncs */
+                       nextPts = ts_pcrscr_get(dev_s) + vsync_pts_align;
+
+                       if (((int)(nextPts + (expected_prev_interval + 1) *
+                               vsync_pts_inc - next_vf_nextpts) >= 0)) {
+                               *expired = false;
+                               if (pts_log_enable[PTS_32_PATTERN] ||
+                                   pts_log_enable[PTS_22_PATTERN])
+                                       pr_info("hold frame for pattern: %d",
+                                               pts_pattern_detected);
+                       }
+
+                       /* here need to escape a vsync */
+                       if (ts_pcrscr_get(dev_s) >
+                               (next_vf->pts + vsync_pts_inc)) {
+                               *expired = true;
+                               pts_escape_vsync = 1;
+                               if (pts_log_enable[PTS_32_PATTERN] ||
+                                   pts_log_enable[PTS_22_PATTERN])
+                                       pr_info("escape a vsync pattern: %d",
+                                               pts_pattern_detected);
+                       }
+               }
+       } else {
+               if (pts_trace == expected_curr_interval) {
+                       /* 23232323..233223...2323 curr=2, prev=3 */
+                       /* check if this frame will expire next vsyncs and */
+                       /* next frame will expire after 3 vsyncs */
+                       /* 22222...22222 -> 222..223122...22 */
+                       /* check if this frame will expire next vsyncs and */
+                       /* next frame will expire after 2 vsyncs */
+                       int nextPts = ts_pcrscr_get(dev_s) + vsync_pts_align;
+
+                       if (((int)(nextPts + vsync_pts_inc - next_vf->pts)
+                               >= 0) &&
+                           ((int)(nextPts +
+                           vsync_pts_inc * (expected_prev_interval - 1)
+                           - next_vf_nextpts) < 0) &&
+                           ((int)(nextPts + expected_prev_interval *
+                               vsync_pts_inc - next_vf_nextpts) >= 0)) {
+                               *expired = true;
+                               if (pts_log_enable[PTS_32_PATTERN] ||
+                                   pts_log_enable[PTS_22_PATTERN])
+                                       pr_info("pull frame for pattern: %d",
+                                               pts_pattern_detected);
+                       }
+               }
+       }
+}
+
 void videosync_pcrscr_update(s32 inc, u32 base)
 {
        int i = 0;
@@ -127,9 +317,11 @@ void videosync_pcrscr_update(s32 inc, u32 base)
                                system_time_scale_base = base;
                        }
                        if (dev_s->system_time_up) {
+                               dev_s->time_update = sched_clock();
                                dev_s->system_time +=
                                        div_u64_rem(90000ULL * inc, base, &r)
                                        + system_time_inc_adj;
+                               vsync_pts_inc = 90000 * inc / base;
                                dev_s->system_time_scale_remainder += r;
                                if (dev_s->system_time_scale_remainder
                                        >= system_time_scale_base) {
@@ -157,7 +349,7 @@ void videosync_pcrscr_update(s32 inc, u32 base)
                                        current_omx_pts,
                                        diff);
                                ts_pcrscr_set(dev_s,
-                                       current_omx_pts + DURATION_GCD);
+                                       current_omx_pts + duration_gcd);
                        }
                }
        }
@@ -220,6 +412,7 @@ void vsync_notify_videosync(void)
                }
        }
        if (has_active) {
+               pts_trace++;
                vp_dev->wakeup = 1;
                wake_up_interruptible(&vp_dev->videosync_wait);
        }
@@ -778,9 +971,18 @@ static void clear_ready_queue(struct videosync_s *dev_s)
        }
 }
 
+static u64 func_div(u64 number, u32 divid)
+{
+       u64 tmp = number;
+
+       do_div(tmp, divid);
+       return tmp;
+}
+
 static inline bool omx_vpts_expire(struct vframe_s *cur_vf,
                               struct vframe_s *next_vf,
-                              struct videosync_s *dev_s)
+                              struct videosync_s *dev_s,
+                              int toggled_cnt)
 
 {
        u32 pts = next_vf->pts;
@@ -789,7 +991,10 @@ static inline bool omx_vpts_expire(struct vframe_s *cur_vf,
 #endif
        u32 systime;
        u32 adjust_pts, org_vpts;
+       unsigned long delta = 0;
+       int delta_32 = 0;
        /*u32 dur_pts = 0;*/
+       bool expired;
 
        if (dev_s->freerun_mode == FREERUN_NODUR)
                return true;
@@ -870,8 +1075,45 @@ static inline bool omx_vpts_expire(struct vframe_s *cur_vf,
                        dev_s->video_frame_repeat_count = 0;
                }
        }
+       delta = func_div(sched_clock() - dev_s->time_update, 1000);
+       delta_32 = delta * 90 / 1000;
+       if (delta_32 > max_delata_time)
+               max_delata_time = delta_32;
+
+       expired = (systime + vsync_pts_align) >= pts;
+
+       vp_print(dev_s->vf_receiver_name, PRINT_PATTERN,
+                "expired=%d, valid=%d, next_pts=%d, cnt=%d, systime=%d, inc=%d\n",
+                expired,
+                next_vf->next_vf_pts_valid,
+                next_vf->next_vf_pts,
+                toggled_cnt,
+                systime,
+                vsync_pts_inc);
+
+       if (expired && next_vf && next_vf->next_vf_pts_valid &&
+           pts_enforce_pulldown &&
+           next_vf->next_vf_pts &&
+           (toggled_cnt > 0) &&
+           ((int)(systime + vsync_pts_inc +
+           vsync_pts_align - next_vf->next_vf_pts) < 0)) {
+               expired = false;
+               vp_print(dev_s->vf_receiver_name, PRINT_PATTERN,
+                        "force expired false\n");
+       } else if (!expired && next_vf && next_vf->next_vf_pts_valid &&
+               pts_enforce_pulldown &&
+               next_vf->next_vf_pts &&
+               (toggled_cnt == 0) &&
+               ((int)(systime + vsync_pts_inc +
+               vsync_pts_align - next_vf->next_vf_pts) >= 0)) {
+               expired = true;
+               vp_print(dev_s->vf_receiver_name, PRINT_PATTERN,
+                        "force expired true\n");
+       }
 
-       return (systime + video_early_threshold) > pts;
+       if (pts_enforce_pulldown)
+               vpts_perform_pulldown(dev_s, next_vf, &expired);
+       return expired;
 
 }
 
@@ -879,6 +1121,7 @@ void videosync_sync(struct videosync_s *dev_s)
 {
        int ready_q_size = 0;
        struct vframe_s *vf;
+       int expire_count = 0;
 
        if (smooth_sync_enable) {
                if (dev_s->video_frame_repeat_count)
@@ -888,7 +1131,7 @@ void videosync_sync(struct videosync_s *dev_s)
        vf = vfq_peek(&dev_s->queued_q);
 
        while (vf) {
-               if (omx_vpts_expire(dev_s->cur_dispbuf, vf, dev_s)
+               if (omx_vpts_expire(dev_s->cur_dispbuf, vf, dev_s, expire_count)
                        || show_nosync) {
 
                        vf = vfq_pop(&dev_s->queued_q);
@@ -898,6 +1141,15 @@ void videosync_sync(struct videosync_s *dev_s)
                                                clear_ready_queue(dev_s);
                                }
 
+                               if (pts_escape_vsync == 1) {
+                                       pts_trace++;
+                                       pts_escape_vsync = 0;
+                               }
+                               vsync_video_pattern();
+                               pre_pts_trace = pts_trace;
+                               pts_trace = 0;
+                               expire_count++;
+
                                vfq_push(&dev_s->ready_q, vf);
                                ready_q_size = vfq_level(&dev_s->ready_q);
                                vp_print(dev_s->vf_receiver_name,
@@ -1064,6 +1316,10 @@ static int videosync_receiver_event_fun(int type, void *data,
                complete(&dev->thread_active);
                pr_info("videosync: reg %p, %s\n",
                        dev_s, dev_s->vf_receiver_name);
+               pts_trace = 0;
+               pts_pattern_detected = -1;
+               pre_pts_trace = 0;
+               pts_escape_vsync = 0;
        } else if (type == VFRAME_EVENT_PROVIDER_VFRAME_READY) {
 
        } else if (type == VFRAME_EVENT_PROVIDER_START) {
@@ -1332,11 +1588,20 @@ module_param(no_render, bool, 0664);
 MODULE_PARM_DESC(async_mode, "\n async_mode\n");
 module_param(async_mode, bool, 0664);
 
-MODULE_PARM_DESC(video_early_threshold, "\n video_early_threshold\n");
-module_param(video_early_threshold, uint, 0664);
+MODULE_PARM_DESC(vsync_pts_align, "\n vsync_pts_align\n");
+module_param(vsync_pts_align, int, 0664);
 
 MODULE_PARM_DESC(cur_omx_index, "\n cur_omx_index\n");
 module_param(cur_omx_index, uint, 0664);
 
 MODULE_PARM_DESC(show_first_frame_nosync, "\n show_first_frame_nosync\n");
 module_param(show_first_frame_nosync, uint, 0664);
+
+MODULE_PARM_DESC(max_delata_time, "\n max_delata_time\n");
+module_param(max_delata_time, uint, 0664);
+
+MODULE_PARM_DESC(duration_gcd, "\n duration_gcd\n");
+module_param(duration_gcd, uint, 0664);
+
+module_param(pts_enforce_pulldown, bool, 0644);
+MODULE_PARM_DESC(pts_enforce_pulldown, "enforce video frame pulldown if needed");
index 861d955..e212c63 100644 (file)
@@ -142,6 +142,7 @@ struct videosync_s {
        u32 zorder;
        struct vframe_provider_s video_vf_prov;
        char vf_provider_name[VIDEOSYNC_VF_NAME_SIZE];
+       long long time_update;
 };
 
 
index 5fd2a0e..863c48c 100644 (file)
@@ -104,6 +104,8 @@ int video_vsync = -ENXIO;
 /*global video manage cmd. */
 
 static bool legacy_vpp = true;
+static int get_count;
+static int get_count_pip;
 
 #define DEBUG_TMP 0
 
@@ -1305,6 +1307,7 @@ static inline struct vframe_s *pip_vf_get(void)
        vf = vf_get(RECEIVERPIP_NAME);
 
        if (vf) {
+               get_count_pip++;
                /* video_notify_flag |= VIDEO_NOTIFY_PROVIDER_GET; */
                atomic_set(&vf->use_cnt, 1);
        }
@@ -1372,6 +1375,7 @@ static inline struct vframe_s *video_vf_get(void)
 
        vf = vf_get(RECEIVER_NAME);
        if (vf) {
+               get_count++;
                if (vf->disp_pts && vf->disp_pts_us64) {
                        vf->pts = vf->disp_pts;
                        vf->pts_us64 = vf->disp_pts_us64;
@@ -6770,6 +6774,9 @@ static irqreturn_t vsync_isr_in(int irq, void *dev_id)
        int ret = 0;
        u32 next_afbc_request = atomic_read(&gAfbc_request);
 
+       get_count = 0;
+       get_count_pip = 0;
+
        glayer_info[0].need_no_compress =
                (next_afbc_request & 1) ? true : false;
        glayer_info[1].need_no_compress =
@@ -8863,6 +8870,9 @@ SET_FILTER:
 #endif
        }
 
+       if (debug_flag & DEBUG_FLAG_GET_COUNT)
+               pr_info("count=%d pip=%d\n", get_count, get_count_pip);
+
        switch (READ_VCBUS_REG(VPU_VIU_VENC_MUX_CTRL) & 0x3) {
        case 0:
                enc_line = (READ_VCBUS_REG(ENCL_INFO_READ) >> 16) & 0x1fff;
index 1486966..4d711f2 100644 (file)
@@ -23,6 +23,7 @@
 #define DEBUG_FLAG_BLACKOUT     0x1
 #define DEBUG_FLAG_PRINT_TOGGLE_FRAME 0x2
 #define DEBUG_FLAG_PRINT_RDMA                0x4
+#define DEBUG_FLAG_GET_COUNT                 0x8
 #define DEBUG_FLAG_LOG_RDMA_LINE_MAX         0x100
 #define DEBUG_FLAG_TOGGLE_SKIP_KEEP_CURRENT  0x10000
 #define DEBUG_FLAG_TOGGLE_FRAME_PER_VSYNC    0x20000