From: jintao xu Date: Wed, 23 Oct 2019 09:33:03 +0000 (+0800) Subject: videosync: add pattern support [1/1] X-Git-Tag: hardkernel-4.9.236-104~492 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=609b26fb02bff8f9e7a2d496356714cfb286dbd9;p=platform%2Fkernel%2Flinux-amlogic.git videosync: add pattern support [1/1] 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 --- diff --git a/drivers/amlogic/media/video_processor/videosync/videosync.c b/drivers/amlogic/media/video_processor/videosync/videosync.c index 050143c..0bd41d8 100644 --- a/drivers/amlogic/media/video_processor/videosync/videosync.c +++ b/drivers/amlogic/media/video_processor/videosync/videosync.c @@ -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"); diff --git a/drivers/amlogic/media/video_processor/videosync/videosync.h b/drivers/amlogic/media/video_processor/videosync/videosync.h index 861d955..e212c63 100644 --- a/drivers/amlogic/media/video_processor/videosync/videosync.h +++ b/drivers/amlogic/media/video_processor/videosync/videosync.h @@ -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; }; diff --git a/drivers/amlogic/media/video_sink/video.c b/drivers/amlogic/media/video_sink/video.c index 5fd2a0e..863c48c 100644 --- a/drivers/amlogic/media/video_sink/video.c +++ b/drivers/amlogic/media/video_sink/video.c @@ -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; diff --git a/drivers/amlogic/media/video_sink/video_priv.h b/drivers/amlogic/media/video_sink/video_priv.h index 1486966..4d711f2 100644 --- a/drivers/amlogic/media/video_sink/video_priv.h +++ b/drivers/amlogic/media/video_sink/video_priv.h @@ -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