blob: 41142302c7a95cc8d74acd838105d6d4b887a5b8 [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 */
9
10#include <pthread.h>
11#include <stdbool.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <sys/time.h>
15
16#include "aml_avsync.h"
17#include "queue.h"
18#include "pattern.h"
19#include "tsync.h"
20#include "aml_avsync_log.h"
21
22enum sync_state {
23 AV_SYNC_STAT_INIT = 0,
24 AV_SYNC_STAT_RUNNING = 1,
25 AV_SYNC_STAT_SYNC_SETUP = 2,
26 AV_SYNC_STAT_SYNC_LOST = 3,
27};
28
29struct av_sync_session {
30 /* session id attached */
31 int session_id;
32 /* playback time, will stop increasing during pause */
33 pts90K stream_time;
34 pts90K vpts;
35
36 /* phase adjustment of stream time for rate control */
37 pts90K phase;
38 bool phase_set;
39
40 /* pts of last rendered frame */
41 pts90K last_pts;
42 struct vframe *last_frame;
43
44 bool first_frame_toggled;
45 /* Whether in pause state */
46 bool paused;
47 enum sync_mode mode;
48 enum sync_state state;
49 void *pattern_detector;
50 void *frame_q;
51 /* start threshold */
52 int start_thres;
53
54 /* display property */
55 int delay;
56 pts90K vsync_interval;
57
58 /* state lock */
59 pthread_mutex_t lock;
60 /* pattern */
61 int last_holding_peroid;
62 bool tsync_started;
63
64 float speed;
65
66 /*pip sync, remove after multi instance is supported*/
67 struct timeval base_sys_time;
68 struct timeval pause_start;
69 uint64_t pause_duration;
70 pts90K first_pts;
71
72 /* pause pts */
73 pts90K pause_pts;
74 pause_pts_done pause_pts_cb;
75 void *pause_cb_priv;
76};
77
78#define MAX_FRAME_NUM 32
79#define DEFAULT_START_THRESHOLD 2
80#define TIME_UNIT90K (90000)
81#define AV_DISCONTINUE_THREDHOLD_MIN (TIME_UNIT90K * 3)
82
83static uint64_t time_diff (struct timeval *b, struct timeval *a);
84static bool frame_expire(struct av_sync_session* avsync,
85 uint32_t systime,
86 struct vframe * frame,
87 struct vframe * next_frame,
88 int toggle_cnt);
89static bool frame_expire_pip(struct av_sync_session* avsync,
90 struct vframe * frame);
91static void pattern_detect(struct av_sync_session* avsync,
92 int cur_period,
93 int last_period);
94
95void* av_sync_create(int session_id,
96 enum sync_mode mode,
97 int start_thres,
98 int delay, pts90K vsync_interval)
99{
100 struct av_sync_session *avsync = NULL;
101
102 if (start_thres > 5) {
103 log_error("start_thres too big: %d", start_thres);
104 return NULL;
105 }
106 if (delay != 1 && delay != 2) {
107 log_error("invalid delay: %d\n", delay);
108 return NULL;
109 }
110 if (vsync_interval < 750 || vsync_interval > 3750) {
111 log_error("invalid vsync interval: %d", vsync_interval);
112 return NULL;
113 }
114 if (session_id != 0 && session_id != 1) {
115 log_error("invalid session: %d", session_id);
116 return NULL;
117 }
118
119 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
120 if (!avsync) {
121 log_error("OOM");
122 return NULL;
123 }
124 avsync->pattern_detector = create_pattern_detector();
125 if (!avsync->pattern_detector) {
126 log_error("pd create fail");
127 free(avsync);
128 return NULL;
129 }
130 avsync->state = AV_SYNC_STAT_INIT;
131 avsync->first_frame_toggled = false;
132 avsync->paused = false;
133 avsync->phase_set = false;
134 avsync->session_id = session_id;
135 avsync->mode = mode;
136 avsync->last_frame = NULL;
137 avsync->tsync_started = false;
138 avsync->speed = 1.0f;
139 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
140
141 if (!start_thres)
142 avsync->start_thres = DEFAULT_START_THRESHOLD;
143 else
144 avsync->start_thres = start_thres;
145 avsync->delay = delay;
146 avsync->vsync_interval = vsync_interval;
147
148 avsync->frame_q = create_q(MAX_FRAME_NUM);
149 if (!avsync->frame_q) {
150 log_error("create queue fail");
151 destroy_pattern_detector(avsync->pattern_detector);
152 free(avsync);
153 return NULL;
154 }
155 //TODO: connect kernel session
156
157 if (avsync->session_id != 1) {
158 /* just in case sysnode is wrongly set */
159 tsync_send_video_pause(avsync->session_id, false);
160 } else
161 avsync->first_pts = -1;
162
163 pthread_mutex_init(&avsync->lock, NULL);
164 log_info("mode: %d start_thres: %d delay: %d interval: %d session: %d done\n",
165 mode, start_thres, delay, vsync_interval, session_id);
166 return avsync;
167}
168
169static int internal_stop(struct av_sync_session *avsync)
170{
171 int ret = 0;
172 struct vframe *frame;
173
174 pthread_mutex_lock(&avsync->lock);
175 if (avsync->state == AV_SYNC_STAT_INIT)
176 goto exit;
177
178 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
179 frame->free(frame);
180 }
181
182 avsync->state = AV_SYNC_STAT_INIT;
183exit:
184 pthread_mutex_unlock(&avsync->lock);
185 return ret;
186}
187
188/* destroy and detach from kernel session */
189void av_sync_destroy(void *sync)
190{
191 struct av_sync_session *avsync = (struct av_sync_session *)sync;
192
193 if (!avsync)
194 return;
195
196 log_info("begin");
197 if (avsync->state != AV_SYNC_STAT_INIT)
198 internal_stop(avsync);
199
200 /* all frames are freed */
201 if (avsync->session_id != 1)
202 tsync_set_pts_inc_mode(avsync->session_id, false);
203
204 pthread_mutex_destroy(&avsync->lock);
205 destroy_q(avsync->frame_q);
206 destroy_pattern_detector(avsync->pattern_detector);
207 free(avsync);
208 log_info("done");
209}
210
211int av_sync_pause(void *sync, bool pause)
212{
213 struct av_sync_session *avsync = (struct av_sync_session *)sync;
214
215 if (!avsync)
216 return -1;
217
218 if (avsync->session_id == 1) {
219 if (!avsync->paused && pause) {
220 gettimeofday(&avsync->pause_start, NULL);
221 avsync->paused = true;
222 }
223 if (avsync->paused && !pause) {
224 struct timeval now;
225
226 gettimeofday(&now, NULL);
227 avsync->pause_duration += time_diff(&now, &avsync->pause_start);
228 avsync->paused = false;
229 }
230 return 0;
231 }
232
233 if (avsync->mode == AV_SYNC_MODE_VMASTER) {
234 tsync_send_video_pause(avsync->session_id, pause);
235 }
236 avsync->paused = pause;
237 log_info("paused:%d\n", pause);
238
239 return 0;
240}
241
242int av_sync_push_frame(void *sync , struct vframe *frame)
243{
244 int ret;
245 struct vframe *prev;
246 struct av_sync_session *avsync = (struct av_sync_session *)sync;
247
248 if (!avsync)
249 return -1;
250
251 if (!peek_item(avsync->frame_q, (void **)&prev, 0)) {
252 if (prev->pts == frame->pts) {
253 dqueue_item(avsync->frame_q, (void **)&prev);
254 prev->free(prev);
255 log_info ("drop frame with same pts %u", frame->pts);
256 }
257 }
258
259 frame->hold_period = 0;
260 ret = queue_item(avsync->frame_q, frame);
261 if (avsync->state == AV_SYNC_STAT_INIT &&
262 queue_size(avsync->frame_q) >= avsync->start_thres) {
263 avsync->state = AV_SYNC_STAT_RUNNING;
264 log_info("state: init --> running");
265 }
266
267 if (ret)
268 log_error("%s queue fail:%d", ret);
269 return ret;
270
271}
272
273struct vframe *av_sync_pop_frame(void *sync)
274{
275 struct vframe *frame = NULL;
276 struct av_sync_session *avsync = (struct av_sync_session *)sync;
277 int toggle_cnt = 0;
278 uint32_t systime;
279
280 pthread_mutex_lock(&avsync->lock);
281 if (avsync->state == AV_SYNC_STAT_INIT) {
282 log_trace("in state INIT");
283 goto exit;
284 }
285
286 if (avsync->session_id == 1) {
287 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
288 log_info("empty q");
289 goto exit;
290 }
291
292 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
293 if (frame_expire_pip(avsync, frame)) {
294 toggle_cnt++;
295
296 dqueue_item(avsync->frame_q, (void **)&frame);
297 if (avsync->last_frame) {
298 /* free frame that are not for display */
299 if (toggle_cnt > 1)
300 avsync->last_frame->free(avsync->last_frame);
301 } else {
302 avsync->first_frame_toggled = true;
303 log_info("first frame %u", frame->pts);
304 }
305 avsync->last_frame = frame;
306 } else
307 break;
308 }
309 goto exit;
310 }
311
312 if (!avsync->tsync_started) {
313 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
314 log_info("empty q");
315 goto exit;
316 }
317
318 if (tsync_enable(avsync->session_id, true))
319 log_error("enable tsync fail");
320 if (avsync->mode == AV_SYNC_MODE_VMASTER) {
321 if (tsync_set_mode(avsync->session_id, AV_SYNC_MODE_VMASTER))
322 log_error("set vmaster mode fail");
323 if (tsync_set_pcr(avsync->session_id, frame->pts))
324 log_error("set pcr fail");
325 log_info("update pcr to: %u", frame->pts);
326 if (tsync_set_pts_inc_mode(avsync->session_id, true))
327 log_error("set inc mode fail");
328 } else if (avsync->mode == AV_SYNC_MODE_AMASTER) {
329 if (tsync_set_pts_inc_mode(avsync->session_id, false))
330 log_error("set inc mode fail");
331 if (tsync_set_mode(avsync->session_id, AV_SYNC_MODE_AMASTER))
332 log_error("set amaster mode fail");
333 } else {
334 //PCR master mode should be set alreay, but it won't hurt to set again.
335 if (tsync_set_mode(avsync->session_id, AV_SYNC_MODE_PCR_MASTER))
336 log_error("set pcrmaster mode fail");
337 }
338
339 tsync_set_video_peek_mode(avsync->session_id);
340 tsync_disable_video_stop_event(avsync->session_id, true);
341 /* video start ASAP */
342 tsync_set_video_sync_thres(avsync->session_id, false);
343 /* video start event */
344 if (tsync_send_video_start(avsync->session_id, frame->pts))
345 log_error("send video start fail");
346 else
347 log_info("video start %u", frame->pts);
348 avsync->tsync_started = true;
349 }
350
351 systime = tsync_get_pcr(avsync->session_id);
352 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
353 struct vframe *next_frame = NULL;
354
355 peek_item(avsync->frame_q, (void **)&next_frame, 1);
356 if (next_frame)
357 log_debug("cur_f %u next_f %u", frame->pts, next_frame->pts);
358 if (frame_expire(avsync, systime, frame, next_frame, toggle_cnt)) {
359 log_debug("cur_f %u expire", frame->pts);
360 toggle_cnt++;
361
362 pattern_detect(avsync,
363 (avsync->last_frame?avsync->last_frame->hold_period:0),
364 avsync->last_holding_peroid);
365 if (avsync->last_frame)
366 avsync->last_holding_peroid = avsync->last_frame->hold_period;
367
368 dqueue_item(avsync->frame_q, (void **)&frame);
369 if (avsync->last_frame) {
370 /* free frame that are not for display */
371 if (toggle_cnt > 1)
372 avsync->last_frame->free(avsync->last_frame);
373 } else {
374 avsync->first_frame_toggled = true;
375 log_info("first frame %u", frame->pts);
376 }
377 avsync->last_frame = frame;
378 } else
379 break;
380 }
381
382 /* pause pts */
383 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
384 bool reached;
385
386 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
387 reached = true;
388 else
389 reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
390
391 if (reached) {
392 if (avsync->pause_pts_cb)
393 avsync->pause_pts_cb(avsync->last_frame->pts,
394 avsync->pause_cb_priv);
395
396 /* stay in paused until av_sync_pause(false) */
397 avsync->paused = true;
398 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
399 log_info ("reach pause pts: %u", avsync->last_frame->pts);
400 }
401 }
402
403exit:
404 pthread_mutex_unlock(&avsync->lock);
405 if (avsync->last_frame) {
406 log_debug("pop %u", avsync->last_frame->pts);
407 tsync_set_vpts(avsync->session_id,avsync->last_frame->pts);
408 } else
409 log_debug("pop (nil)");
410 if (avsync->last_frame)
411 avsync->last_frame->hold_period++;
412 return avsync->last_frame;
413}
414
415void av_sync_update_vsync_interval(void *sync, pts90K vsync_interval)
416{
417 struct av_sync_session *avsync = (struct av_sync_session *)sync;
418
419 pthread_mutex_lock(&avsync->lock);
420 avsync->vsync_interval = vsync_interval;
421 if (avsync->state >= AV_SYNC_STAT_RUNNING) {
422 reset_pattern(avsync->pattern_detector);
423 avsync->phase_set = false;
424 }
425 pthread_mutex_unlock(&avsync->lock);
426}
427
428static inline uint32_t abs_diff(uint32_t a, uint32_t b)
429{
430 return a > b ? a - b : b - a;
431}
432
433static uint64_t time_diff (struct timeval *b, struct timeval *a)
434{
435 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_usec - a->tv_usec);
436}
437
438static bool frame_expire_pip(struct av_sync_session* avsync,
439 struct vframe * frame)
440{
441 struct timeval systime;
442 uint64_t passed;
443 pts90K passed_90k;
444
445 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
446 return false;
447
448 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
449 return true;
450
451 gettimeofday(&systime, NULL);
452 if (avsync->first_pts == -1) {
453 avsync->first_pts = frame->pts;
454 avsync->base_sys_time = systime;
455 log_debug("first_pts %u, sys %d/%d", frame->pts,
456 systime.tv_sec, systime.tv_usec);
457 return true;
458 }
459
460 passed = time_diff(&systime, &avsync->base_sys_time);
461 passed -= avsync->pause_duration;
462 passed *= avsync->speed;
463 passed_90k = (pts90K)(passed * 9 / 100);
464
465 if (passed_90k > (frame->pts - avsync->first_pts)) {
466 log_trace("cur_f %u sys: %u/%d stream: %u",
467 frame->pts, systime.tv_sec, systime.tv_usec, passed_90k);
468 return true;
469 }
470
471 return false;
472}
473
474static bool frame_expire(struct av_sync_session* avsync,
475 uint32_t systime,
476 struct vframe * frame,
477 struct vframe * next_frame,
478 int toggle_cnt)
479{
480 uint32_t fpts = frame->pts;
481 bool expire = false;
482 uint32_t pts_correction = avsync->delay * avsync->vsync_interval;
483
484 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
485 return false;
486
487 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
488 return true;
489
490 if (!fpts) {
491 if (avsync->last_frame) {
492 /* try to accumulate duration as PTS */
493 fpts = avsync->vpts + avsync->last_frame->duration;
494 } else {
495 fpts = avsync->vpts;
496 }
497 }
498 systime += pts_correction;
499
500 /* phase adjustment */
501 if (avsync->phase_set)
502 systime += avsync->phase;
503
504 log_trace("systime:%u phase:%u correct:%u", systime,
505 avsync->phase_set?avsync->phase:0, pts_correction);
506 if (abs_diff(systime, fpts) > AV_DISCONTINUE_THREDHOLD_MIN &&
507 avsync->first_frame_toggled) {
508 /* ignore discontinity under pause */
509 if (avsync->paused && avsync->mode != AV_SYNC_MODE_PCR_MASTER)
510 return false;
511
512 log_warn("sync lost systime:%x fpts:%x", systime, fpts);
513 avsync->state = AV_SYNC_STAT_SYNC_LOST;
514 avsync->phase_set = false;
515 if ((int)(systime - fpts) > 0) {
516 if (frame->pts && avsync->mode == AV_SYNC_MODE_VMASTER)
517 tsync_send_video_disc(avsync->session_id, frame->pts);
518 /*catch up PCR */
519 return true;
520 } else if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
521 if (frame->pts)
522 tsync_send_video_disc(avsync->session_id, frame->pts);
523 else {
524 tsync_send_video_disc(avsync->session_id, fpts);
525 return true;
526 }
527 }
528 }
529
530 expire = (int)(systime - fpts) >= 0;
531
532 /* scatter the frame in different vsync whenever possible */
533 if (expire && next_frame && next_frame->pts && toggle_cnt) {
534 /* multi frame expired in current vsync but no frame in next vsync */
535 if (systime + avsync->vsync_interval < next_frame->pts) {
536 expire = false;
537 frame->hold_period++;
538 log_debug("unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
539 systime, avsync->vsync_interval, next_frame->pts, toggle_cnt);
540 }
541 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
542 && avsync->first_frame_toggled) {
543 /* next vsync will have at least 2 frame expired */
544 if (systime + avsync->vsync_interval > next_frame->pts) {
545 expire = true;
546 log_debug("set expire systime:%d inter:%d next_pts:%d",
547 systime, avsync->vsync_interval, next_frame->pts);
548 }
549 }
550
551 correct_pattern(avsync->pattern_detector, frame, next_frame,
552 (avsync->last_frame?avsync->last_frame->hold_period:0),
553 avsync->last_holding_peroid, systime,
554 avsync->vsync_interval, &expire);
555
556 if (expire) {
557 avsync->vpts = fpts;
558 /* phase adjustment */
559 if (!avsync->phase_set) {
560 uint32_t phase_thres = avsync->vsync_interval / 4;
561 //systime = tsync_get_pcr(avsync->session_id);
562 if ( systime > fpts && (systime - fpts) < phase_thres) {
563 /* too aligned to current VSYNC, separate them to 1/4 VSYNC */
564 avsync->phase += phase_thres - (systime - fpts);
565 avsync->phase_set = true;
566 log_info("adjust phase to %d", avsync->phase);
567 }
568 if (!avsync->phase_set && systime > fpts &&
569 systime < (fpts + avsync->vsync_interval) &&
570 (systime - fpts) > avsync->vsync_interval - phase_thres) {
571 /* too aligned to previous VSYNC, separate them to 1/4 VSYNC */
572 avsync->phase += phase_thres + fpts + avsync->vsync_interval - systime;
573 avsync->phase_set = true;
574 log_info("adjust phase to %d", avsync->phase);
575 }
576 }
577
578 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
579 log_info("sync setup");
580 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
581 }
582 return expire;
583}
584
585static void pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
586{
587 log_trace("cur_period: %d last_period: %d", cur_period, last_period);
588 detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period);
589 detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period);
590 detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period);
591}
592
593int av_sync_set_speed(void *sync, float speed)
594{
595 struct av_sync_session *avsync = (struct av_sync_session *)sync;
596
597 if (speed < 0.001f || speed > 100) {
598 log_error("wrong speed %f [0.0001, 100]", speed);
599 return -1;
600 }
601
602 avsync->speed = speed;
603 if (avsync->session_id == 1)
604 return 0;
605
606 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
607 log_info("ignore set speed in mode %d", avsync->mode);
608 return 0;
609 }
610
611 return tsync_set_speed(avsync->session_id, speed);
612}
613
614int av_sync_change_mode(void *sync, enum sync_mode mode)
615{
616 struct av_sync_session *avsync = (struct av_sync_session *)sync;
617
618 if (!avsync)
619 return -1;
620
621 if (avsync->session_id == 1)
622 return 0;
623
624 if (avsync->mode != AV_SYNC_MODE_VMASTER || mode != AV_SYNC_MODE_AMASTER) {
625 log_error("only support V to A mode switch");
626 return -1;
627 }
628
629 if (tsync_set_pts_inc_mode(avsync->session_id, false))
630 log_error("set inc mode fail");
631 if (tsync_set_mode(avsync->session_id, AV_SYNC_MODE_AMASTER))
632 log_error("set amaster mode fail");
633 avsync->mode = mode;
634 log_info("update sync mode to %d", mode);
635 return 0;
636}
637
638int av_sync_set_pause_pts(void *sync, pts90K pts)
639{
640 struct av_sync_session *avsync = (struct av_sync_session *)sync;
641
642 if (!avsync)
643 return -1;
644
645 avsync->pause_pts = pts;
646 return 0;
647}
648
649int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
650{
651 struct av_sync_session *avsync = (struct av_sync_session *)sync;
652
653 if (!avsync)
654 return -1;
655
656 avsync->pause_pts_cb = cb;
657 avsync->pause_cb_priv = priv;
658 return 0;
659}