blob: dd12513ff4af29a8ac5f8c7677f30e9e1abd6eaf [file] [log] [blame]
Song Zhaoc03ba122020-12-23 21:54:02 -08001/*
2 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
Song Zhaoea5a0412021-01-18 16:40:08 -08009#include <errno.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080010#include <pthread.h>
11#include <stdbool.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <sys/time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080015#include <poll.h>
16#include <fcntl.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/prctl.h>
20#include <sys/ioctl.h>
Song Zhaoa2985cb2021-06-24 12:01:47 -070021#include <time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080022#include <unistd.h>
23//#include <linux/amlogic/msync.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080024#include "aml_avsync.h"
25#include "queue.h"
26#include "pattern.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080027#include "aml_avsync_log.h"
Song Zhaoea5a0412021-01-18 16:40:08 -080028#include "msync_util.h"
29#include "msync.h"
30#include <pthread.h>
wei.dubcc2ed22021-05-19 07:16:10 -040031#include "pcr_monitor.h"
Song Zhao2f6744b2021-11-03 21:23:50 -070032
Song Zhaoc03ba122020-12-23 21:54:02 -080033enum sync_state {
34 AV_SYNC_STAT_INIT = 0,
35 AV_SYNC_STAT_RUNNING = 1,
36 AV_SYNC_STAT_SYNC_SETUP = 2,
37 AV_SYNC_STAT_SYNC_LOST = 3,
38};
39
yongchun.li107a6162021-05-05 02:38:57 -070040enum audio_switch_state_ {
41 AUDIO_SWITCH_STAT_INIT = 0,
42 AUDIO_SWITCH_STAT_RESET = 1,
43 AUDIO_SWITCH_STAT_START = 2,
44 AUDIO_SWITCH_STAT_FINISH = 3,
yongchun.li59e873d2021-07-07 11:42:38 -070045 AUDIO_SWITCH_STAT_AGAIN = 4,
yongchun.li107a6162021-05-05 02:38:57 -070046};
47
Song Zhaoea5a0412021-01-18 16:40:08 -080048#define SESSION_DEV "avsync_s"
49
Song Zhaoc03ba122020-12-23 21:54:02 -080050struct av_sync_session {
51 /* session id attached */
52 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080053 int fd;
54 bool attached;
55 enum sync_mode mode;
56 /* for audio trickplay */
57 enum sync_mode backup_mode;
58 enum sync_type type;
59 uint32_t start_policy;
bo.xiao5821fc72021-07-11 22:47:00 -040060 int timeout;
Song Zhaoc03ba122020-12-23 21:54:02 -080061
Song Zhaoea5a0412021-01-18 16:40:08 -080062 /* playback time, will stop increasing during pause */
63 pts90K vpts;
64 pts90K apts;
65
66 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080067 pts90K phase;
68 bool phase_set;
69
70 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080071 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080072 pts90K last_pts;
73 struct vframe *last_frame;
74
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070075 /* pts of last pushed frame */
76 pts90K last_q_pts;
77
Song Zhaoc03ba122020-12-23 21:54:02 -080078 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080079 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080080 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080081 void *pattern_detector;
82 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080083
Song Zhaoea5a0412021-01-18 16:40:08 -080084 /* start control */
85 int start_thres;
86 audio_start_cb audio_start;
87 void *audio_start_priv;
88
89 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080090 int delay;
91 pts90K vsync_interval;
92
93 /* state lock */
94 pthread_mutex_t lock;
95 /* pattern */
96 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -080097 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -080098
99 float speed;
100
Song Zhaoc03ba122020-12-23 21:54:02 -0800101 /* pause pts */
102 pts90K pause_pts;
103 pause_pts_done pause_pts_cb;
104 void *pause_cb_priv;
Song Zhao5d2b4772021-01-18 16:40:08 -0800105
106 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700107 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800108 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700109 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800110
111 pthread_t poll_thread;
112 /* pcr master, IPTV only */
113 bool quit_poll;
114 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700115 uint32_t disc_thres_min;
116 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700117
118 /* error detection */
119 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700120 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700121 pts90K last_disc_pts;
122
yongchun.li107a6162021-05-05 02:38:57 -0700123 // indicate set audio switch
124 bool in_audio_switch;
125 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400126
127 //pcr monitor handle
128 void *pcr_monitor;
129 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700130 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700131
132 //video FPS detection
133 pts90K last_fpts;
134 int fps_interval;
135 int fps_interval_acc;
136 int fps_cnt;
137
138 //video freerun with rate control
139 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700140 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700141
142 //Audio dropping detection
143 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700144 struct timespec audio_drop_start;
Song Zhao95bd0922021-09-21 14:07:46 -0700145
146 /*system mono time for current vsync interrupt */
147 uint64_t msys;
Song Zhaoc03ba122020-12-23 21:54:02 -0800148};
149
150#define MAX_FRAME_NUM 32
151#define DEFAULT_START_THRESHOLD 2
152#define TIME_UNIT90K (90000)
Song Zhaof46932e2021-05-21 01:51:45 -0700153#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
154#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700155#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
156#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700157#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800158#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhaod62bb392021-04-23 12:25:49 -0700159#define LIVE_MODE(mode) ((mode) == AV_SYNC_MODE_PCR_MASTER || (mode) == AV_SYNC_MODE_IPTV)
160
Song Zhao065800e2021-05-26 15:56:06 -0700161#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700162#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700163#define VALID_TS(x) ((x) != -1)
Song Zhaoc03ba122020-12-23 21:54:02 -0800164
yongchun.li0ee6e372021-08-20 04:26:04 -0700165static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800166static bool frame_expire(struct av_sync_session* avsync,
167 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800168 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800169 struct vframe * frame,
170 struct vframe * next_frame,
171 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700172static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800173 int cur_period,
174 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800175static void * poll_thread(void * arg);
176static void trigger_audio_start_cb(struct av_sync_session *avsync,
177 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700178static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
179static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
Song Zhao2f6744b2021-11-03 21:23:50 -0700180pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800181
Song Zhaoea5a0412021-01-18 16:40:08 -0800182int av_sync_open_session(int *session_id)
183{
Song Zhao2f6744b2021-11-03 21:23:50 -0700184 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800185 int id, rc;
186
Song Zhao2f6744b2021-11-03 21:23:50 -0700187 pthread_mutex_lock(&glock);
188 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800189 if (fd < 0) {
190 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700191 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800192 }
193 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
194 if (rc) {
195 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700196 msync_destory_session(fd);
197 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800198 }
199 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700200 log_debug("new avsession id %d fd %d", id, fd);
201exit:
202 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800203 return fd;
204}
205
206void av_sync_close_session(int session)
207{
Song Zhao2f6744b2021-11-03 21:23:50 -0700208 log_debug("session closed fd %d", session);
209 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800210 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700211 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800212}
213
214static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800215 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800216 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800217 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800218 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800219{
220 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800221 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700222 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800223
Song Zhao95bd0922021-09-21 14:07:46 -0700224 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800225 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
226 if (!avsync) {
227 log_error("OOM");
228 return NULL;
229 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800230
Song Zhao95bd0922021-09-21 14:07:46 -0700231 if (type == AV_SYNC_TYPE_VIDEO &&
232 mode == AV_SYNC_MODE_VIDEO_MONO) {
233 if (session_id < AV_SYNC_SESSION_V_MONO) {
234 log_error("wrong session id %d", session_id);
235 goto err;
236 }
237 avsync->type = type;
238 avsync->mode = mode;
239 avsync->fd = -1;
240 avsync->session_id = session_id;
241 log_info("[%d]init", avsync->session_id);
242 return avsync;
243 }
244
Song Zhaoea5a0412021-01-18 16:40:08 -0800245 if (type == AV_SYNC_TYPE_VIDEO) {
246 avsync->pattern_detector = create_pattern_detector();
247 if (!avsync->pattern_detector) {
248 log_error("pd create fail");
249 goto err;
250 }
251
252 if (!start_thres)
253 avsync->start_thres = DEFAULT_START_THRESHOLD;
254 else {
255 if (start_thres > 5) {
256 log_error("start_thres too big: %d", start_thres);
257 goto err2;
258 }
259 avsync->start_thres = start_thres;
260 }
261 avsync->phase_set = false;
262 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800263 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800264
265 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800266 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800267 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800268 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800269 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800270 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800271 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800272 avsync->speed = 1.0f;
273 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700274 avsync->vsync_interval = -1;
275 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700276 avsync->last_log_syst = -1;
277 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700278 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700279 avsync->last_wall = -1;
280 avsync->fps_interval = -1;
281 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400282 avsync->timeout = -1;
283
Song Zhaof46932e2021-05-21 01:51:45 -0700284 if (msync_session_get_disc_thres(session_id,
285 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
286 log_error("fail to get disc thres", dev_name, errno);
287 avsync->disc_thres_min = AV_DISC_THRES_MIN;
288 avsync->disc_thres_max = AV_DISC_THRES_MAX;
289 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800290
291 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao95bd0922021-09-21 14:07:46 -0700292 log_info("[%d] start_thres %d disc_thres %u/%u",
293 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800294
295 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700296 while (retry) {
297 /* wait for sysfs to update */
298 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
299 if (avsync->fd > 0)
300 break;
301
302 retry--;
303 if (!retry) {
304 log_error("open %s errno %d", dev_name, errno);
305 goto err2;
306 }
307 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800308 }
309
wei.dubcc2ed22021-05-19 07:16:10 -0400310 if (avsync->type == AV_SYNC_TYPE_PCR) {
311 if (pcr_monitor_init(&avsync->pcr_monitor)) {
312 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000313 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400314 }
315 }
316
Song Zhaoea5a0412021-01-18 16:40:08 -0800317 if (!attach) {
318 msync_session_set_mode(avsync->fd, mode);
319 avsync->mode = mode;
320 } else {
321 avsync->attached = true;
322 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
323 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000324 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800325 }
326 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400327 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800328 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000329 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800330 }
yongchun.li107a6162021-05-05 02:38:57 -0700331 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700332 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700333 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000334 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700335 }
336 if (avsync->in_audio_switch) {
337 log_info("audio_switch_state reseted the audio");
338 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
339 }
340
Song Zhaoea5a0412021-01-18 16:40:08 -0800341 log_info("[%d]retrieve sync mode %d policy %d",
342 session_id, avsync->mode, avsync->start_policy);
343 }
344
Song Zhao67c937b2021-10-01 11:21:32 -0700345 /* debug log level */
346 {
347 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
348 if ( env ) {
349 log_set_level(atoi(env));
350 }
351 }
352
Song Zhaoc03ba122020-12-23 21:54:02 -0800353 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000354err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400355 if (avsync->pcr_monitor)
356 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000357err3:
358 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800359err2:
360 destroy_pattern_detector(avsync->pattern_detector);
361err:
362 free(avsync);
363 return NULL;
364}
365
366void* av_sync_create(int session_id,
367 enum sync_mode mode,
368 enum sync_type type,
369 int start_thres)
370{
371 return create_internal(session_id, mode,
372 type, start_thres, false);
373}
374
375void* av_sync_attach(int session_id, enum sync_type type)
376{
Song Zhao95bd0922021-09-21 14:07:46 -0700377 if (type == AV_SYNC_TYPE_VIDEO)
378 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800379 return create_internal(session_id, AV_SYNC_MODE_MAX,
380 type, 0, true);
381}
382
383int av_sync_video_config(void *sync, struct video_config* config)
384{
385 struct av_sync_session *avsync = (struct av_sync_session *)sync;
386
387 if (!avsync || !config)
388 return -1;
389
390 if (config->delay != 1 && config->delay != 2) {
391 log_error("invalid delay: %d\n", config->delay);
392 return -1;
393 }
394
395 avsync->delay = config->delay;
396
397 log_info("[%d] delay: %d",
398 avsync->session_id, config->delay);
399 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800400}
401
402static int internal_stop(struct av_sync_session *avsync)
403{
404 int ret = 0;
405 struct vframe *frame;
406
407 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800408 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
409 frame->free(frame);
410 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800411 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800412 pthread_mutex_unlock(&avsync->lock);
413 return ret;
414}
415
416/* destroy and detach from kernel session */
417void av_sync_destroy(void *sync)
418{
419 struct av_sync_session *avsync = (struct av_sync_session *)sync;
420
421 if (!avsync)
422 return;
423
Song Zhao95bd0922021-09-21 14:07:46 -0700424 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
425 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
426 log_info("[%d]done", avsync->session_id);
427 internal_stop(avsync);
428 destroy_q(avsync->frame_q);
429 free(avsync);
430 return;
431 }
Song Zhaob5458b32021-11-12 15:58:47 -0800432 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhaoea5a0412021-01-18 16:40:08 -0800433 if (avsync->state != AV_SYNC_STAT_INIT) {
434 if (avsync->type == AV_SYNC_TYPE_VIDEO)
435 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800436
Song Zhaoea5a0412021-01-18 16:40:08 -0800437 avsync->quit_poll = true;
438 if (avsync->poll_thread) {
439 pthread_join(avsync->poll_thread, NULL);
440 avsync->poll_thread = 0;
441 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700442 if (avsync->type == AV_SYNC_TYPE_AUDIO)
443 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800444 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800445
Song Zhaoea5a0412021-01-18 16:40:08 -0800446 if (avsync->session_started) {
447 if (avsync->type == AV_SYNC_TYPE_VIDEO)
448 msync_session_set_video_stop(avsync->fd);
449 else
450 msync_session_set_audio_stop(avsync->fd);
451 }
wei.dubcc2ed22021-05-19 07:16:10 -0400452
453 if(avsync->pcr_monitor)
454 pcr_monitor_destroy(avsync->pcr_monitor);
455
Song Zhaoea5a0412021-01-18 16:40:08 -0800456 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800457 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800458 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
459 destroy_q(avsync->frame_q);
460 destroy_pattern_detector(avsync->pattern_detector);
461 }
Song Zhaob5458b32021-11-12 15:58:47 -0800462 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800463 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800464}
465
bo.xiao5821fc72021-07-11 22:47:00 -0400466int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800467{
468 struct av_sync_session *avsync = (struct av_sync_session *)sync;
469
470 if (!avsync || !avsync->fd)
471 return -1;
472
bo.xiao5821fc72021-07-11 22:47:00 -0400473 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
474 avsync->start_policy = st_policy->policy;
475 avsync->timeout = st_policy->timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800476 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400477 if (st_policy->policy != AV_SYNC_START_NONE &&
478 st_policy->policy != AV_SYNC_START_V_PEEK)
479 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800480
481 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800482}
483
484int av_sync_pause(void *sync, bool pause)
485{
486 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700487 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800488 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800489
Song Zhaob5458b32021-11-12 15:58:47 -0800490 if (!avsync) {
491 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800492 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800493 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800494
Song Zhaob5458b32021-11-12 15:58:47 -0800495 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
496 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800497 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800498 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800499
yongchun.li107a6162021-05-05 02:38:57 -0700500 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode,
501 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700502 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700503
yongchun.li5f52fb02021-06-04 18:13:05 -0700504 /* ignore only when video try to pause when audio is acive, on which
505 the control of the STC will be relays.
506 When resume,it can do always as it is possible that video just
507 paused earlier without audio yet,then audio added later before resume.
508 We shall not igore that otherwise it could cause video freeze. */
509 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
510 avsync->type == AV_SYNC_TYPE_VIDEO &&
511 a_active &&
512 !avsync->in_audio_switch) {
513 if (!pause) {
514 log_info("[%d] clear video pause when audio active",
515 avsync->session_id);
516 avsync->paused = pause;
517 } else {
518 log_info("[%d] ignore the pause from video when audio active",
519 avsync->session_id);
520 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800521 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700522 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800523
yongchun.li107a6162021-05-05 02:38:57 -0700524 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
525 log_info("[%d] ignore the pause from audio", avsync->session_id);
526 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
527 return 0;
528 }
529
Song Zhaoea5a0412021-01-18 16:40:08 -0800530 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800531 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800532 log_info("[%d]paused:%d type:%d rc %d",
533 avsync->session_id, pause, avsync->type, rc);
Song Zhaoc03ba122020-12-23 21:54:02 -0800534
Song Zhaoea5a0412021-01-18 16:40:08 -0800535 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800536}
537
538int av_sync_push_frame(void *sync , struct vframe *frame)
539{
540 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700541 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800542 struct av_sync_session *avsync = (struct av_sync_session *)sync;
543
544 if (!avsync)
545 return -1;
546
Song Zhao95bd0922021-09-21 14:07:46 -0700547 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
548 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
549 return video_mono_push_frame(avsync, frame);
550
Song Zhaoea5a0412021-01-18 16:40:08 -0800551 if (!avsync->frame_q) {
552 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400553 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800554 log_error("[%d]get policy", avsync->session_id);
555 return -1;
556 }
557
558 avsync->frame_q = create_q(MAX_FRAME_NUM);
559 if (!avsync->frame_q) {
560 log_error("[%d]create queue fail", avsync->session_id);
yongchun.li0ee6e372021-08-20 04:26:04 -0700561
Song Zhaoea5a0412021-01-18 16:40:08 -0800562 return -1;
563 }
564
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700565 /* for debugging */
566 {
Song Zhaoea5a0412021-01-18 16:40:08 -0800567 int ret;
568
569 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
570 if (ret) {
571 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
572 destroy_q(avsync->frame_q);
573 return -1;
574 }
575 }
576 }
577
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700578 if (avsync->last_q_pts != -1) {
579 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
580 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800581 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700582 if (prev) {
583 prev->free(prev);
584 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
585 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700586 } else if (avsync->fps_cnt < 100) {
587 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700588
589 if (interval > 0 && interval <= 4500) {
590 if (avsync->fps_interval_acc == -1) {
591 avsync->fps_interval_acc = interval;
592 avsync->fps_cnt = 1;
593 } else {
594 avsync->fps_interval_acc += interval;
595 avsync->fps_cnt++;
596 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
597 if (avsync->fps_cnt == 100)
598 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
599 }
600 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800601 }
602 }
603
Song Zhao065800e2021-05-26 15:56:06 -0700604 if (frame->duration == -1)
605 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800606 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700607 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800608 ret = queue_item(avsync->frame_q, frame);
609 if (avsync->state == AV_SYNC_STAT_INIT &&
610 queue_size(avsync->frame_q) >= avsync->start_thres) {
611 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800612 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800613 }
614
615 if (ret)
616 log_error("%s queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400617 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800618 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800619}
620
621struct vframe *av_sync_pop_frame(void *sync)
622{
Song Zhaoea5a0412021-01-18 16:40:08 -0800623 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800624 struct av_sync_session *avsync = (struct av_sync_session *)sync;
625 int toggle_cnt = 0;
626 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800627 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800628 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800629
Song Zhao95bd0922021-09-21 14:07:46 -0700630 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
631 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
632 return video_mono_pop_frame(avsync);
633
Song Zhaoc03ba122020-12-23 21:54:02 -0800634 pthread_mutex_lock(&avsync->lock);
635 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700636 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800637 goto exit;
638 }
639
Song Zhaoea5a0412021-01-18 16:40:08 -0800640 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700641 uint32_t pts;
642
Song Zhaoc03ba122020-12-23 21:54:02 -0800643 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800644 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800645 goto exit;
646 }
Song Zhao35a82df2021-04-15 10:58:49 -0700647 msync_session_get_wall(avsync->fd, &systime, &interval);
648 pts = frame->pts - avsync->delay * interval;
649 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800650 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700651 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800652 }
653
Song Zhaoea5a0412021-01-18 16:40:08 -0800654 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700655 !avsync->first_frame_toggled &&
656 !msync_clock_started(avsync->fd)) {
657 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800658 log_trace("[%d]clock not started", avsync->session_id);
659 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800660 }
661
Song Zhaoea5a0412021-01-18 16:40:08 -0800662 enter_last_frame = avsync->last_frame;
663 msync_session_get_wall(avsync->fd, &systime, &interval);
664
665 /* handle refresh rate change */
666 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
667 avsync->vsync_interval != interval) {
668 log_info("[%d]vsync interval update %d --> %u",
669 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700670 if (avsync->fps_interval == -1)
671 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800672 avsync->vsync_interval = interval;
673 avsync->phase_set = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700674 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800675 reset_pattern(avsync->pattern_detector);
676 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800677 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
678 struct vframe *next_frame = NULL;
679
680 peek_item(avsync->frame_q, (void **)&next_frame, 1);
681 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700682 log_debug("[%d]cur_f %u next_f %u size %d",
683 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800684 if (frame_expire(avsync, systime, interval,
685 frame, next_frame, toggle_cnt)) {
686 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800687 toggle_cnt++;
688
Song Zhao35a82df2021-04-15 10:58:49 -0700689 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800690 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700691 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700692 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700693 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
694 if (next_frame)
695 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
696 }
Song Zhao35a82df2021-04-15 10:58:49 -0700697
Song Zhaoc03ba122020-12-23 21:54:02 -0800698 if (avsync->last_frame)
699 avsync->last_holding_peroid = avsync->last_frame->hold_period;
700
701 dqueue_item(avsync->frame_q, (void **)&frame);
702 if (avsync->last_frame) {
703 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800704 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700705 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
706 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800707 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800708 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800709 } else {
710 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800711 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800712 }
713 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800714 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800715 } else
716 break;
717 }
718
719 /* pause pts */
720 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800721 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800722 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800723 else
Song Zhao468fd652021-01-15 22:13:04 -0800724 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
725 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
726 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
727 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
728 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800729
Song Zhao468fd652021-01-15 22:13:04 -0800730 if (pause_pts_reached) {
731 if (avsync->pause_pts_cb)
732 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800733 avsync->pause_cb_priv);
734
Song Zhao468fd652021-01-15 22:13:04 -0800735 /* stay in paused until av_sync_pause(false) */
736 avsync->paused = true;
737 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800738 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800739 avsync->session_id, avsync->pause_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800740 }
741
742exit:
743 pthread_mutex_unlock(&avsync->lock);
744 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800745 if (enter_last_frame != avsync->last_frame)
746 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400747 log_trace("[%d]pop=%u, stc=%u, QNum=%d", avsync->session_id, avsync->last_frame->pts, systime, queue_size(avsync->frame_q));
Song Zhao065800e2021-05-26 15:56:06 -0700748 /* don't update vpts for out_lier */
749 if (avsync->last_frame->duration != -1)
750 msync_session_update_vpts(avsync->fd, systime,
751 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800752 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800753 if (enter_last_frame != avsync->last_frame)
754 log_debug("[%d]pop (nil)", avsync->session_id);
755
Song Zhao35a82df2021-04-15 10:58:49 -0700756 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800757 if (avsync->last_frame)
758 avsync->last_frame->hold_period++;
759 return avsync->last_frame;
760}
761
Song Zhaoc03ba122020-12-23 21:54:02 -0800762static inline uint32_t abs_diff(uint32_t a, uint32_t b)
763{
Song Zhaoea5a0412021-01-18 16:40:08 -0800764 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800765}
766
yongchun.li0ee6e372021-08-20 04:26:04 -0700767static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800768{
yongchun.li0ee6e372021-08-20 04:26:04 -0700769 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_nsec/1000 - a->tv_nsec/1000);
Song Zhaoc03ba122020-12-23 21:54:02 -0800770}
771
Song Zhaoc03ba122020-12-23 21:54:02 -0800772static bool frame_expire(struct av_sync_session* avsync,
773 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800774 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800775 struct vframe * frame,
776 struct vframe * next_frame,
777 int toggle_cnt)
778{
779 uint32_t fpts = frame->pts;
780 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800781 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800782
783 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
784 return false;
785
786 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
787 return true;
788
fei.deng63e43e12021-09-23 19:44:01 +0800789 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
790 avsync->mode == AV_SYNC_MODE_VMASTER) {
791 /* We need to ensure that the video outputs smoothly,
792 so output video frame by frame hold_period */
793 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
794 avsync->last_frame &&
795 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
796 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
797 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700798 return true;
799 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700800 }
801
Song Zhaoc03ba122020-12-23 21:54:02 -0800802 if (!fpts) {
803 if (avsync->last_frame) {
804 /* try to accumulate duration as PTS */
805 fpts = avsync->vpts + avsync->last_frame->duration;
806 } else {
807 fpts = avsync->vpts;
808 }
809 }
810 systime += pts_correction;
811
812 /* phase adjustment */
813 if (avsync->phase_set)
814 systime += avsync->phase;
815
yongchun.lia50b1e92021-08-07 01:11:54 +0000816 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800817 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000818 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700819 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800820 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800821 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800822 return false;
823
Song Zhaoa2985cb2021-06-24 12:01:47 -0700824 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
825 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700826 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800827
yongchun.li0ee6e372021-08-20 04:26:04 -0700828 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700829 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800830 avsync->last_pts = fpts;
831 if (time_diff(&now, &avsync->sync_lost_print_time) >=
832 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700833 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800834 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800835 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700836 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800837 } else
838 avsync->sync_lost_cnt++;
839 }
Song Zhaod62bb392021-04-23 12:25:49 -0700840
841 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
842 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700843 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700844 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700845 /* outlier by stream error */
846 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700847 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700848 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
849 log_info("render outlier %u", fpts);
850 return true;
851 }
852 }
853
854 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800855 avsync->state = AV_SYNC_STAT_SYNC_LOST;
856 avsync->phase_set = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700857 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800858 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700859
860 if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700861 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700862 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700863 msync_session_set_video_dis(avsync->fd, fpts);
864 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700865 }
866
867 if ((int)(systime - fpts) > 0) {
868 if ((int)(systime - fpts) < avsync->disc_thres_max) {
869 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700870 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700871 } else {
872 /* render according to FPS */
873 if (!VALID_TS(avsync->last_r_syst) ||
874 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
875 avsync->last_r_syst = systime;
876 return true;
877 }
878 return false;
879 }
880 } else if (LIVE_MODE(avsync->mode)) {
881 /* hold if the gap is small */
882 if ((int)(fpts - systime) < avsync->disc_thres_max) {
883 return false;
884 } else {
885 /* render according to FPS */
886 if (!VALID_TS(avsync->last_r_syst) ||
887 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
888 avsync->last_r_syst = systime;
889 return true;
890 }
891 return false;
892 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800893 }
894 }
895
Song Zhao52f55192021-05-06 10:52:21 -0700896 /* In some cases, keeping pattern will enlarge the gap */
897 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
898 avsync->first_frame_toggled) {
899 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700900 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700901 systime, fpts);
902 }
903
Song Zhaoc03ba122020-12-23 21:54:02 -0800904 expire = (int)(systime - fpts) >= 0;
905
906 /* scatter the frame in different vsync whenever possible */
907 if (expire && next_frame && next_frame->pts && toggle_cnt) {
908 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800909 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800910 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800911 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
912 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800913 }
914 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
915 && avsync->first_frame_toggled) {
916 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700917 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800918 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800919 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
920 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800921 }
922 }
923
Song Zhaoa58c3e92021-03-09 18:52:55 -0800924 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
925 correct_pattern(avsync->pattern_detector, frame, next_frame,
926 (avsync->last_frame?avsync->last_frame->hold_period:0),
927 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800928 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800929
930 if (expire) {
931 avsync->vpts = fpts;
932 /* phase adjustment */
933 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +0000934 //always adjust to the half v-sync to give most pts tolerace and unify behavior
935 if ((int)(systime - fpts) >= 0 && (int)(fpts + interval - systime) > 0) {
936 avsync->phase = interval/2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800937 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +0000938 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800939 }
940 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800941 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800942 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800943 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800944 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800945 }
946 return expire;
947}
948
Song Zhao35a82df2021-04-15 10:58:49 -0700949static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800950{
Song Zhao35a82df2021-04-15 10:58:49 -0700951 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800952 log_trace("[%d]cur_period: %d last_period: %d",
953 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700954 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
955 ret = true;
956 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
957 ret = true;
958 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
959 ret = true;
960 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
961 ret = true;
962
963 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800964}
965
966int av_sync_set_speed(void *sync, float speed)
967{
968 struct av_sync_session *avsync = (struct av_sync_session *)sync;
969
970 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800971 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800972 return -1;
973 }
974
Song Zhaoea5a0412021-01-18 16:40:08 -0800975 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
976 avsync->mode == AV_SYNC_MODE_IPTV) {
977 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800978 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800979 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800980
Song Zhaoea5a0412021-01-18 16:40:08 -0800981 avsync->speed = speed;
982
983 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
984 if (speed == 1.0) {
985 avsync->mode = avsync->backup_mode;
986 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
987 } else {
988 avsync->backup_mode = avsync->mode;
989 avsync->mode = AV_SYNC_MODE_FREE_RUN;
990 log_info("[%d]audio to freerun mode", avsync->session_id);
991 }
992 }
993#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800994 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
995 log_info("ignore set speed in mode %d", avsync->mode);
996 return 0;
997 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800998#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800999
Song Zhaoea5a0412021-01-18 16:40:08 -08001000 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1001 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001002}
1003
1004int av_sync_change_mode(void *sync, enum sync_mode mode)
1005{
1006 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1007
1008 if (!avsync)
1009 return -1;
1010
Song Zhaoea5a0412021-01-18 16:40:08 -08001011 if (msync_session_set_mode(avsync->fd, mode)) {
1012 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001013 return -1;
1014 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001015 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001016 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001017 return 0;
1018}
1019
Song Zhao01031bb2021-05-13 21:23:20 -07001020int av_sync_get_mode(void *sync, enum sync_mode *mode)
1021{
1022 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1023
1024 if (!avsync || !mode)
1025 return -1;
1026
1027 *mode = avsync->mode;
1028 return 0;
1029}
1030
Song Zhaoc03ba122020-12-23 21:54:02 -08001031int av_sync_set_pause_pts(void *sync, pts90K pts)
1032{
1033 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1034
1035 if (!avsync)
1036 return -1;
1037
1038 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001039 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001040 return 0;
1041}
1042
1043int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1044{
1045 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1046
1047 if (!avsync)
1048 return -1;
1049
1050 avsync->pause_pts_cb = cb;
1051 avsync->pause_cb_priv = priv;
1052 return 0;
1053}
Song Zhaoea5a0412021-01-18 16:40:08 -08001054
1055static void trigger_audio_start_cb(struct av_sync_session *avsync,
1056 avs_ascb_reason reason)
1057{
1058 if (avsync) {
1059 pthread_mutex_lock(&avsync->lock);
1060 if (avsync->audio_start) {
1061 avsync->audio_start(avsync->audio_start_priv, reason);
1062 avsync->session_started = true;
1063 avsync->audio_start = NULL;
1064 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1065 }
1066 pthread_mutex_unlock(&avsync->lock);
1067 }
1068}
1069
1070avs_start_ret av_sync_audio_start(
1071 void *sync,
1072 pts90K pts,
1073 pts90K delay,
1074 audio_start_cb cb,
1075 void *priv)
1076{
1077 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1078 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001079 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001080 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1081 bool create_poll_t = false;
1082
1083 if (!avsync)
1084 return ret;
1085
yongchun.li59e873d2021-07-07 11:42:38 -07001086 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1087 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001088
yongchun.li59e873d2021-07-07 11:42:38 -07001089 if (avsync->in_audio_switch &&
1090 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1091 {
1092 start_mode = AVS_START_SYNC;
1093 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1094 } else {
1095 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1096 log_error("[%d]fail to set audio start", avsync->session_id);
1097 }
1098 if (avsync->in_audio_switch &&
1099 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1100 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1101 msync_session_get_wall(avsync->fd, &systime, NULL);
1102 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1103 start_mode == AVS_START_SYNC) {
1104 log_info("%d audio_switch audio need drop first.ahead %d ms",
1105 avsync->session_id, (int)(systime - pts)/90);
1106 ret = AV_SYNC_ASTART_AGAIN;
1107 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1108 goto exit;
1109 }
1110 else {
1111 int diff = (int)(pts - systime);
1112 log_info("%d audio_switch_state to start mode %d diff %d ms",
1113 avsync->session_id, start_mode, diff/90);
1114 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1115 if (diff < A_ADJ_THREDHOLD_LB) {
1116 log_info("%d orig mode %d already close enough direct start",
1117 avsync->session_id, start_mode);
1118 start_mode = AVS_START_SYNC;
1119 }
1120 }
yongchun.li107a6162021-05-05 02:38:57 -07001121 }
1122
Song Zhaoea5a0412021-01-18 16:40:08 -08001123 if (start_mode == AVS_START_SYNC) {
1124 ret = AV_SYNC_ASTART_SYNC;
1125 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001126 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001127 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001128 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001129 avsync->state = AV_SYNC_STAT_RUNNING;
1130 } else if (start_mode == AVS_START_AGAIN) {
1131 ret = AV_SYNC_ASTART_AGAIN;
1132 }
1133
1134 if (ret == AV_SYNC_ASTART_AGAIN)
1135 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001136
yongchun.li107a6162021-05-05 02:38:57 -07001137 if (avsync->mode == AV_SYNC_MODE_AMASTER || avsync->in_audio_switch) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001138 create_poll_t = true;
1139 if (start_mode == AVS_START_ASYNC) {
1140 if (!cb) {
1141 log_error("[%d]invalid cb", avsync->session_id);
1142 return AV_SYNC_ASTART_ERR;
1143 }
1144 avsync->audio_start = cb;
1145 avsync->audio_start_priv = priv;
1146 }
Song Zhaod62bb392021-04-23 12:25:49 -07001147 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001148 create_poll_t = true;
1149
Song Zhaod62bb392021-04-23 12:25:49 -07001150 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001151 int ret;
1152
1153 log_info("[%d]start poll thread", avsync->session_id);
1154 avsync->quit_poll = false;
1155 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1156 if (ret) {
1157 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1158 return AV_SYNC_ASTART_ERR;
1159 }
1160 }
Song Zhaod62bb392021-04-23 12:25:49 -07001161 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001162 msync_session_get_wall(avsync->fd, &systime, NULL);
1163 log_info("[%d]return %u w %u pts %u d %u",
1164 avsync->session_id, ret, systime, pts, delay);
1165 }
1166exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001167 log_info("[%d]return %u", avsync->session_id, ret);
1168 return ret;
1169}
1170
1171int av_sync_audio_render(
1172 void *sync,
1173 pts90K pts,
1174 struct audio_policy *policy)
1175{
1176 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001177 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001178 uint32_t systime;
1179 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1180 avs_audio_action action = AA_SYNC_AA_MAX;
1181
1182 if (!avsync || !policy)
1183 return -1;
1184
yongchun.li107a6162021-05-05 02:38:57 -07001185 msync_session_get_wall(avsync->fd, &systime, NULL);
1186
1187 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1188 pts, systime, avsync->mode, (int)(pts-systime)/90);
1189
1190 if (avsync->in_audio_switch
1191 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1192 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1193 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1194 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1195 action = AV_SYNC_AA_RENDER;
1196 } else if ((int)(systime - pts) > 0) {
1197 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1198 (int)(systime - pts)/90, systime, pts);
1199 action = AV_SYNC_AA_DROP;
1200 } else {
1201 action = AV_SYNC_AA_INSERT;
1202 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1203 (int)(pts - systime)/90, systime, pts);
1204 }
1205 goto done;
1206 }
1207
Song Zhaoea5a0412021-01-18 16:40:08 -08001208 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1209 avsync->mode == AV_SYNC_MODE_AMASTER) {
1210 action = AV_SYNC_AA_RENDER;
1211 goto done;
1212 }
1213
Song Zhaod62bb392021-04-23 12:25:49 -07001214 /* stopping procedure, unblock audio rendering */
1215 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1216 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1217 action = AV_SYNC_AA_DROP;
1218 goto done;
1219 }
1220
Song Zhao7daf3a12021-05-10 22:22:25 -07001221 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1222 avsync->mode == AV_SYNC_MODE_AMASTER) {
1223 action = AV_SYNC_AA_RENDER;
1224 goto done;
1225 }
1226
Song Zhaod62bb392021-04-23 12:25:49 -07001227 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1228 LIVE_MODE(avsync->mode) &&
1229 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1230 /* outlier by stream error */
1231 avsync->outlier_cnt++;
1232 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1233 /* treat as disc, just drop current frame */
1234 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1235 avsync->outlier_cnt = 0;
1236 action = AV_SYNC_AA_DROP;
1237 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001238 goto done;
1239 }
1240 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1241 pts = systime;
1242 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001243 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001244 goto done;
1245 }
1246
1247 avsync->outlier_cnt = 0;
1248 /* low bound from sync_lost to sync_setup */
1249 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1250 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1251 action = AV_SYNC_AA_RENDER;
1252 goto done;
1253 }
1254
1255 /* high bound of sync_setup */
1256 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1257 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1258 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001259 action = AV_SYNC_AA_RENDER;
1260 goto done;
1261 }
1262
1263 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001264 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001265 action = AV_SYNC_AA_DROP;
1266 goto done;
1267 }
1268
1269 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001270 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001271 action = AV_SYNC_AA_INSERT;
1272 goto done;
1273 }
1274
1275done:
1276 policy->action = action;
1277 policy->delta = (int)(systime - pts);
1278 if (action == AV_SYNC_AA_RENDER) {
1279 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001280 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001281 if (!out_lier)
1282 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001283 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001284 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001285 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1286 msync_session_update_apts(avsync->fd, systime, pts, 0);
1287 log_info("[%d] audio switch done sys %u pts %u",
1288 avsync->session_id, systime, pts);
1289 msync_session_set_audio_switch(avsync->fd, false);
1290 avsync->in_audio_switch = false;
1291 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1292 } else {
1293 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1294 avsync->session_id, action, systime, pts, systime - pts);
1295 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001296 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001297 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001298 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001299 avsync->last_disc_pts != pts &&
1300 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001301 log_info ("[%d]audio disc %u --> %u",
1302 avsync->session_id, systime, pts);
1303 msync_session_set_audio_dis(avsync->fd, pts);
1304 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001305 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001306 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001307
1308 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001309 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001310 if (!avsync->audio_drop_cnt)
1311 avsync->audio_drop_start = now;
1312 avsync->audio_drop_cnt++;
1313 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1314 log_info ("[%d]audio keep dropping sys %u vs a %u",
1315 avsync->session_id, systime, pts);
1316 msync_session_set_audio_dis(avsync->fd, pts);
1317 }
Song Zhao409739b2021-05-12 22:21:40 -07001318 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001319 if (action != AV_SYNC_AA_DROP)
1320 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001321 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001322 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001323 }
1324
1325 return ret;
1326}
1327
1328int av_sync_get_clock(void *sync, pts90K *pts)
1329{
1330 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1331
1332 if (!avsync || !pts)
1333 return -1;
1334 return msync_session_get_wall(avsync->fd, pts, NULL);
1335}
1336
1337static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001338 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001339{
bo.xiao1f94b352021-08-02 03:53:47 -04001340 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d", avsync->session_id,
Song Zhaoe208d692021-04-19 15:38:52 -07001341 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001342 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1343 float speed;
1344 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001345 a_active && avsync->audio_start) {
yongchun.li107a6162021-05-05 02:38:57 -07001346 if (v_active || v_timeout || avsync->in_audio_switch) {
Song Zhaoe208d692021-04-19 15:38:52 -07001347 log_info("audio start cb");
1348 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
yongchun.li107a6162021-05-05 02:38:57 -07001349 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001350 }
1351
1352 if (!msync_session_get_rate(avsync->fd, &speed)) {
1353 /* speed change is triggered by asink,
1354 * attached audio HAL will handle it
1355 */
1356 if (speed != avsync->speed)
1357 log_info("[%d]new rate %f", avsync->session_id, speed);
1358 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001359 if (avsync->mode != avsync->backup_mode) {
1360 avsync->mode = avsync->backup_mode;
1361 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1362 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001363 } else {
1364 avsync->backup_mode = avsync->mode;
1365 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1366 log_info("[%d]audio to freerun mode", avsync->session_id);
1367 }
1368 avsync->speed = speed;
1369 }
Song Zhaod62bb392021-04-23 12:25:49 -07001370 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1371 struct session_debug debug;
1372 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001373 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001374 avsync->backup_mode = avsync->mode;
1375 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001376 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001377 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001378 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001379 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001380 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001381 log_warn("[%d]audio back to mode %d",
1382 avsync->session_id, avsync->mode);
1383 }
1384 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001385 }
1386}
1387
1388static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001389 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001390{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001391 struct session_debug debug;
1392
bo.xiao1f94b352021-08-02 03:53:47 -04001393 log_info("[%d]av_sync amode mode %d %d v/a %d/%d", avsync->session_id,
Song Zhaoea5a0412021-01-18 16:40:08 -08001394 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001395 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1396 if (debug.debug_freerun && !avsync->debug_freerun) {
1397 avsync->backup_mode = avsync->mode;
1398 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1399 avsync->debug_freerun = true;
1400 log_warn("[%d]video to freerun mode", avsync->session_id);
1401 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1402 avsync->mode = avsync->backup_mode;
1403 avsync->debug_freerun = false;
1404 log_warn("[%d]video back to mode %d",
1405 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001406 }
1407 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001408}
1409
1410static void * poll_thread(void * arg)
1411{
1412 int ret = 0;
1413 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1414 const int fd = avsync->fd;
1415 struct pollfd pfd = {
1416 /* default blocking capture */
1417 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1418 .fd = avsync->fd,
1419 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001420 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001421
1422 prctl (PR_SET_NAME, "avs_poll");
1423 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001424
1425 if (avsync->type == AV_SYNC_TYPE_AUDIO)
1426 sflag = SRC_A;
1427 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
1428 sflag = SRC_V;
1429
Song Zhaoea5a0412021-01-18 16:40:08 -08001430 while (!avsync->quit_poll) {
1431 for (;;) {
1432 ret = poll(&pfd, 1, 10);
1433 if (ret > 0)
1434 break;
1435 if (avsync->quit_poll)
1436 goto exit;
1437 if (errno == EINTR)
1438 continue;
1439 }
1440
1441 /* error handling */
1442 if (pfd.revents & POLLERR)
1443 log_error("[%d]POLLERR received", avsync->session_id);
1444
Song Zhaod62bb392021-04-23 12:25:49 -07001445 /* mode change. Non-exclusive wait so all the processes
1446 * shall be woken up
1447 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001448 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001449 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001450
1451 msync_session_get_stat(fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001452 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001453
1454 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001455 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001456 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001457 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001458 usleep(10000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001459 }
1460 }
1461exit:
1462 log_info("[%d]quit", avsync->session_id);
1463 return NULL;
1464}
1465
Song Zhao623e2f12021-09-03 15:54:04 -07001466#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1467/* return ppm between demod and PCR clock */
1468int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1469{
1470 int fd = -1, ppm = 0, nread;
1471 char buf[128];
1472 uint32_t reg_v, lock;
1473 float val;
1474
1475 fd = open(DEMOD_NODE, O_RDWR);
1476 if (fd < 0) {
1477 log_warn("node not found %s", DEMOD_NODE);
1478 /* do not retry */
1479 avsync->ppm_adjusted = true;
1480 return 0;
1481 }
1482 snprintf(buf, sizeof(buf), "%d", 5);
1483 write(fd, buf, 2);
1484
1485 lseek(fd, 0, SEEK_SET);
1486
1487 nread = read(fd, buf, sizeof(buf));
1488 if (nread <= 0) {
1489 log_error("read error");
1490 goto err;
1491 }
1492 buf[nread] = 0;
1493 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1494 log_error("wrong format %s", buf);
1495 goto err;
1496 }
1497 if (lock != 0x1f) {
1498 log_info("demod not locked");
1499 goto err;
1500 }
1501 if (reg_v > ((2 << 20) - 1))
1502 reg_v -= (2 << 21);
1503 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1504 ppm = val;
1505 log_info("ppm from SFO %d", ppm);
1506 avsync->ppm_adjusted = true;
1507
1508err:
1509 if (fd >= 0)
1510 close(fd);
1511 return ppm;
1512}
1513
Song Zhaod62bb392021-04-23 12:25:49 -07001514int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001515{
1516 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001517 struct pcr_info pcr;
1518 enum pcr_monitor_status status;
1519 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001520 if (!avsync)
1521 return -1;
1522
1523 if (avsync->type != AV_SYNC_TYPE_PCR)
1524 return -2;
1525
Song Zhao623e2f12021-09-03 15:54:04 -07001526 /* initial estimation from Demod SFO HW */
1527 if (!avsync->ppm_adjusted) {
1528 ppm = dmod_get_sfo_dev(avsync);
1529 if (ppm != 0) {
1530 /* ppm > 0 means board clock is faster */
1531 msync_session_set_clock_dev(avsync->fd, -ppm);
1532 }
1533 }
wei.dubcc2ed22021-05-19 07:16:10 -04001534 pcr.monoclk = mono_clock / 1000;
1535 pcr.pts = (long long) pts * 1000 / 90;
1536 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1537
1538 status = pcr_monitor_get_status(avsync->pcr_monitor);
1539
1540 if (status >= DEVIATION_READY) {
1541 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1542 if (avsync->ppm != ppm) {
1543 avsync->ppm = ppm;
1544 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1545 if (msync_session_set_clock_dev(avsync->fd, ppm))
1546 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001547 else
1548 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001549 }
1550 }
1551
Song Zhaod62bb392021-04-23 12:25:49 -07001552 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001553}
1554
Song Zhaod62bb392021-04-23 12:25:49 -07001555int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001556{
1557 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1558
1559 if (!avsync)
1560 return -1;
1561
Song Zhaod62bb392021-04-23 12:25:49 -07001562 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001563}
1564
1565int av_sync_set_session_name(void *sync, const char *name)
1566{
1567 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1568
1569 if (!avsync)
1570 return -1;
1571
1572 return msync_session_set_name(avsync->fd, name);
1573}
yongchun.li107a6162021-05-05 02:38:57 -07001574
1575int av_sync_set_audio_switch(void *sync, bool start)
1576{
1577 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1578 bool v_active, a_active, v_timeout;
1579
1580 if (!avsync)
1581 return -1;
1582 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1583 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001584 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001585 log_error("[%d] can not get session state",
1586 avsync->session_id);
1587 return -1;
1588 }
1589 if (!v_active || !a_active) {
1590 log_error("[%d] no apply if not AV both active v %d a %d",
1591 avsync->session_id, v_active, a_active);
1592 return -1;
1593 }
1594 if (msync_session_set_audio_switch(avsync->fd, start)) {
1595 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1596 return -1;
1597 }
1598 avsync->in_audio_switch = start;
1599 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1600 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1601 return 0;
1602}
1603
1604int av_sync_get_audio_switch(void *sync, bool *start)
1605{
1606 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1607
1608 if (!avsync)
1609 return -1;
1610 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001611 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001612 log_error("[%d] can not audio seamless switch state",
1613 avsync->session_id);
1614 return -1;
1615 }
1616 if (start) *start = avsync->in_audio_switch;
1617 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001618}
Song Zhao8039f562021-05-18 18:11:25 -07001619
Song Zhao623e2f12021-09-03 15:54:04 -07001620enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001621{
1622 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1623
wei.dubcc2ed22021-05-19 07:16:10 -04001624 if (!avsync || !ppm)
1625 return CLK_RECOVERY_ERR;
1626 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001627 return CLK_RECOVERY_NOT_RUNNING;
1628
wei.dubcc2ed22021-05-19 07:16:10 -04001629 if (msync_session_get_clock_dev(avsync->fd, ppm))
1630 return CLK_RECOVERY_ERR;
1631
1632 if (*ppm == 0)
1633 return CLK_RECOVERY_ONGOING;
1634 else
1635 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001636}
Song Zhao95bd0922021-09-21 14:07:46 -07001637
1638static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1639{
1640 int ret;
1641
1642 if (!avsync->frame_q) {
1643 avsync->frame_q = create_q(MAX_FRAME_NUM);
1644 if (!avsync->frame_q) {
1645 log_error("[%d]create queue fail", avsync->session_id);
1646
1647 return -1;
1648 }
1649 }
1650
1651 ret = queue_item(avsync->frame_q, frame);
1652 if (ret)
1653 log_error("%s queue fail:%d", ret);
1654 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1655 return ret;
1656}
1657
1658int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1659{
1660 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1661
1662 if (!avsync)
1663 return -1;
1664 avsync->msys = msys;
1665 return 0;
1666}
1667
1668static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1669{
1670 struct vframe *frame = NULL, *enter_last_frame = NULL;
1671 uint64_t systime;
1672 int toggle_cnt = 0;
1673
1674 enter_last_frame = avsync->last_frame;
1675 systime = avsync->msys;
1676 log_debug("[%d]sys %llu", avsync->session_id, systime);
1677 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1678 if (systime >= frame->mts) {
1679 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1680 toggle_cnt++;
1681
1682 if (avsync->last_frame)
1683 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1684
1685 dqueue_item(avsync->frame_q, (void **)&frame);
1686 if (avsync->last_frame) {
1687 /* free frame that are not for display */
1688 if (toggle_cnt > 1) {
1689 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1690 avsync->last_frame->mts, frame->mts, systime);
1691 avsync->last_frame->free(avsync->last_frame);
1692 }
1693 } else {
1694 avsync->first_frame_toggled = true;
1695 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1696 }
1697 avsync->last_frame = frame;
1698 } else
1699 break;
1700 }
1701
1702 if (avsync->last_frame) {
1703 if (enter_last_frame != avsync->last_frame)
1704 log_debug("[%d]pop %llu", avsync->session_id, avsync->last_frame->pts);
1705 log_trace("[%d]pop=%llu, system=%llu, diff %d(ms), QNum=%d", avsync->session_id,
1706 avsync->last_frame->mts,
1707 systime, (systime - avsync->last_frame->mts) / 1000000,
1708 queue_size(avsync->frame_q));
1709 } else
1710 if (enter_last_frame != avsync->last_frame)
1711 log_debug("[%d]pop (nil)", avsync->session_id);
1712
1713 if (avsync->last_frame)
1714 avsync->last_frame->hold_period++;
1715 return avsync->last_frame;
1716}