avsynclib: support vmaster trickplay with makeup PTS from App [1/1]
PD#TV-52104
Problem:
Support video PTS big gap during trickplay
Solution:
When big video PTS gap is detected, increase the wall clock adjust
threshold
Verify:
TM2 + LLama + Linear channel
Change-Id: I20362c7b5e49eeefd1cc0395a92ac36535906c81
diff --git a/src/avsync.c b/src/avsync.c
index 91a0232..e3fd905 100644
--- a/src/avsync.c
+++ b/src/avsync.c
@@ -164,6 +164,7 @@
#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
+#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
#define OUTLIER_MAX_CNT 8
@@ -326,6 +327,8 @@
if (!attach) {
msync_session_set_mode(avsync->fd, mode);
avsync->mode = mode;
+ if (avsync->mode == AV_SYNC_MODE_VMASTER)
+ msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
} else {
avsync->attached = true;
if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
@@ -595,6 +598,22 @@
}
if (avsync->last_q_pts != -1) {
+ if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
+ /* Sometimes app will fake PTS for trickplay, video PTS gap
+ * is really big depending on the speed. Have to adjust the
+ * threshold dynamically.
+ */
+ int gap = (int)(frame->pts - avsync->last_q_pts);
+ if (gap > avsync->disc_thres_min) {
+ avsync->disc_thres_min = gap * 6;
+ avsync->disc_thres_max = gap * 20;
+ msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
+ msync_session_set_disc_thres(avsync->session_id,
+ avsync->disc_thres_min, avsync->disc_thres_max);
+ log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
+ avsync->disc_thres_min, avsync->disc_thres_max);
+ }
+ }
if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
/* TODO: wrong, should remove from back of queue */
dqueue_item(avsync->frame_q, (void **)&prev);
@@ -839,8 +858,7 @@
if (next_frame)
nfpts = next_frame->pts + avsync->extra_delay;
- if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
- avsync->mode == AV_SYNC_MODE_VMASTER) {
+ if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
/* We need to ensure that the video outputs smoothly,
so output video frame by frame hold_period */
if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
@@ -911,7 +929,7 @@
avsync->phase = 0;
reset_pattern(avsync->pattern_detector);
- if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
+ if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
log_info ("[%d]video disc %u --> %u",
avsync->session_id, systime, fpts);
msync_session_set_video_dis(avsync->fd, fpts);
diff --git a/src/msync_util.c b/src/msync_util.c
index 8a9c5c8..4c77db4 100644
--- a/src/msync_util.c
+++ b/src/msync_util.c
@@ -415,6 +415,16 @@
return rc;
}
+int msync_session_set_wall_adj_thres(int fd, int32_t thres)
+{
+ int rc;
+
+ rc = ioctl(fd, AMSYNCS_IOC_SET_WALL_ADJ_THRES, &thres);
+ if (rc)
+ log_error("session[%d] set wall adj thres errno:%d", fd, errno);
+ return rc;
+}
+
static int get_sysfs_uint32(const char *path, uint32_t *value)
{
int fd;
@@ -425,7 +435,7 @@
if (fd >= 0) {
memset(valstr, 0, 64);
read(fd, valstr, 64 - 1);
- valstr[strlen(valstr)] = '\0';
+ valstr[strnlen(valstr, sizeof(valstr))] = '\0';
close(fd);
} else {
log_error("unable to open file %s\n", path);
@@ -457,3 +467,41 @@
return 0;
}
+
+static int set_sysfs_uint32(const char *path, uint32_t value)
+{
+ int fd, ret = 0;
+ char valstr[64];
+
+ fd = open(path, O_RDWR);
+ snprintf(valstr, sizeof(valstr), "%d", value);
+ if (fd >= 0) {
+ ret = write(fd, valstr, strnlen(valstr, sizeof(valstr)));
+ if (ret >= 0)
+ ret = 0;
+ close(fd);
+ } else {
+ log_error("unable to open file %s\n", path);
+ return -1;
+ }
+ return ret;
+}
+
+int msync_session_set_disc_thres(int session_id, uint32_t min, uint32_t max)
+{
+ char name[64];
+
+ if (snprintf(name, sizeof(name),
+ "/sys/class/avsync_session%d/disc_thres_min", session_id) < 0)
+ return -1;
+ if (set_sysfs_uint32(name, min))
+ return -1;
+
+ if (snprintf(name, sizeof(name),
+ "/sys/class/avsync_session%d/disc_thres_max", session_id) < 0)
+ return -1;
+ if (set_sysfs_uint32(name, max))
+ return -1;
+
+ return 0;
+}
diff --git a/src/msync_util.h b/src/msync_util.h
index c9bf085..1c8544d 100644
--- a/src/msync_util.h
+++ b/src/msync_util.h
@@ -60,5 +60,7 @@
int msync_session_set_audio_switch(int fd, bool start);
int msync_session_get_clock_dev(int fd, int32_t *ppm);
int msync_session_set_clock_dev(int fd, int32_t ppm);
+int msync_session_set_wall_adj_thres(int fd, int32_t thres);
int msync_session_get_disc_thres(int session_id, uint32_t *min, uint32_t *max);
+int msync_session_set_disc_thres(int session_id, uint32_t min, uint32_t max);
#endif