mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 20:32:04 +09:00
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 <jintao.xu@amlogic.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
return (systime + video_early_threshold) > pts;
|
||||
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");
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user