blob: 38c62146bf5062788712c973a3f385b31171b2f8 [file] [log] [blame]
Song Zhao6859d412020-06-15 17:16:04 -07001/*
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
15#include "aml_avsync.h"
16#include "queue.h"
17#include "pattern.h"
18#include "tsync.h"
19#include "aml_avsync_log.h"
20
21enum sync_mode {
22 AV_SYNC_MODE_AMASTER = 0,
23 AV_SYNC_MODE_VMASTER = 1,
24 AV_SYNC_MODE_PCR_MASTER = 2,
25};
26
27enum sync_state {
28 AV_SYNC_STAT_INIT = 0,
29 AV_SYNC_STAT_RUNNING = 1,
30 AV_SYNC_STAT_SYNC_SETUP = 2,
31 AV_SYNC_STAT_SYNC_LOST = 3,
32};
33
34struct av_sync_session {
35 /* session id attached */
36 int session_id;
37 /* playback time, will stop increasing during pause */
38 pts90K stream_time;
39 pts90K vpts;
40
41 /* phase adjustment of stream time for rate control */
42 pts90K phase;
43 bool phase_set;
44
45 /* pts of last rendered frame */
46 pts90K last_pts;
47 struct vframe *last_frame;
48
49 /* monotonic system time, keep increasing during pause */
50 struct timespec system_time;
51 bool first_frame_toggled;
52 /* Whether in pause state */
53 bool paused;
54 enum sync_mode mode;
55 enum sync_state state;
56 void *pattern_detector;
57 void *frame_q;
58 /* start threshold */
59 int start_thres;
60
61 /* display property */
62 int delay;
63 pts90K vsync_interval;
64
65 /* state lock */
66 pthread_mutex_t lock;
67 /* pattern */
68 int last_holding_peroid;
69 bool tsync_started;
70};
71
72#define MAX_FRAME_NUM 32
73#define DEFAULT_START_THRESHOLD 2
74#define TIME_UNIT90K (90000)
75#define AV_DISCONTINUE_THREDHOLD_MIN (TIME_UNIT90K * 3)
76
77static bool frame_expire(struct av_sync_session* avsync,
78 uint32_t systime,
79 struct vframe * frame,
80 struct vframe * next_frame,
81 int toggle_cnt);
82static void pattern_detect(struct av_sync_session* avsync,
83 int cur_period,
84 int last_period);
85
86void* av_sync_create(int session_id, int start_thres,
87 int delay, pts90K vsync_interval)
88{
89 struct av_sync_session *avsync = NULL;
90
91 if (start_thres > 5) {
92 log_error("start_thres too big: %d", start_thres);
93 return NULL;
94 }
95 if (delay != 1 && delay != 2) {
96 log_error("invalid delay: %d\n", delay);
97 return NULL;
98 }
99 if (vsync_interval < 750 || vsync_interval >= 3750) {
100 log_error("invalid vsync interval: %d", vsync_interval);
101 return NULL;
102 }
103
104 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
105 if (!avsync) {
106 log_error("OOM");
107 return NULL;
108 }
109 avsync->pattern_detector = create_pattern_detector();
110 if (!avsync->pattern_detector) {
111 log_error("pd create fail");
112 free(avsync);
113 return NULL;
114 }
115 avsync->state = AV_SYNC_STAT_INIT;
116 avsync->first_frame_toggled = false;
117 avsync->paused = false;
118 avsync->phase_set = false;
119 avsync->session_id = session_id;
120 avsync->mode = AV_SYNC_MODE_AMASTER;
121 avsync->last_frame = NULL;
122 avsync->tsync_started = false;
123 if (!start_thres)
124 avsync->start_thres = DEFAULT_START_THRESHOLD;
125 else
126 avsync->start_thres = start_thres;
127 avsync->delay = delay;
128 avsync->vsync_interval = vsync_interval;
129
130 avsync->frame_q = create_q(MAX_FRAME_NUM);
131 if (!avsync->frame_q) {
132 log_error("create queue fail");
133 destroy_pattern_detector(avsync->pattern_detector);
134 free(avsync);
135 return NULL;
136 }
137 //TODO: connect kernel session
138
139 pthread_mutex_init(&avsync->lock, NULL);
140 log_info("start_thres: %d delay: %d interval: %d done\n",
141 start_thres, delay, vsync_interval);
142 return avsync;
143}
144
145static int internal_stop(struct av_sync_session *avsync)
146{
147 int ret = 0;
148 struct vframe *frame;
149
150 pthread_mutex_lock(&avsync->lock);
151 if (avsync->state == AV_SYNC_STAT_INIT)
152 goto exit;
153
154 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
155 frame->free(frame);
156 }
157
158 avsync->state = AV_SYNC_STAT_INIT;
159exit:
160 pthread_mutex_unlock(&avsync->lock);
161 return ret;
162}
163
164/* destroy and detach from kernel session */
165void av_sync_destroy(void *sync)
166{
167 struct av_sync_session *avsync = (struct av_sync_session *)sync;
168
169 if (!avsync)
170 return;
171
172 log_info("begin");
173 if (avsync->state != AV_SYNC_STAT_INIT)
174 internal_stop(avsync);
175
176 /* all frames are freed */
177 //TODO: disconnect kernel session
178 tsync_enable(avsync->session_id, false);
179 pthread_mutex_destroy(&avsync->lock);
180 destroy_q(avsync->frame_q);
181 destroy_pattern_detector(avsync->pattern_detector);
182 free(avsync);
183 log_info("done");
184}
185
186int av_sync_pause(void *sync, bool pause)
187{
188 struct av_sync_session *avsync = (struct av_sync_session *)sync;
189
190 if (!avsync)
191 return -1;
192
193 avsync->paused = pause;
194 tsync_send_video_pause(avsync->session_id, pause);
195 log_info("paused:%d\n", pause);
196 return 0;
197}
198
199int av_sync_push_frame(void *sync , struct vframe *frame)
200{
201 int ret;
202 struct av_sync_session *avsync = (struct av_sync_session *)sync;
203
204 if (!avsync)
205 return -1;
206
207 frame->hold_period = 0;
208 ret = queue_item(avsync->frame_q, frame);
209 if (avsync->state == AV_SYNC_STAT_INIT &&
210 queue_size(avsync->frame_q) >= avsync->start_thres) {
211 avsync->state = AV_SYNC_STAT_RUNNING;
212 log_info("state: init --> running");
213 }
214
215 if (ret)
216 log_error("%s queue fail:%d", ret);
217 return ret;
218
219}
220
221struct vframe *av_sync_pop_frame(void *sync)
222{
223 struct vframe *frame = NULL;
224 struct av_sync_session *avsync = (struct av_sync_session *)sync;
225 int toggle_cnt = 0;
226 uint32_t systime = tsync_get_pcr(avsync->session_id);
227
228 pthread_mutex_lock(&avsync->lock);
229 if (avsync->state == AV_SYNC_STAT_INIT)
230 goto exit;
231
232 if (!avsync->tsync_started) {
233 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
234 log_info("empty q");
235 goto exit;
236 }
237
238 tsync_enable(avsync->session_id, true);
239 /* video start event */
240 tsync_send_video_start(avsync->session_id, frame->pts);
241 log_info("video start %d", frame->pts);
242 avsync->tsync_started = true;
243 }
244
245 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
246 struct vframe *next_frame = NULL;
247
248 peek_item(avsync->frame_q, (void **)&next_frame, 1);
249 if (next_frame)
250 log_debug("cur_f %d next_f %d", frame->pts, next_frame->pts);
251 if (frame_expire(avsync, systime, frame, next_frame, toggle_cnt)) {
252 log_debug("cur_f %d expire", frame->pts);
253 toggle_cnt++;
254
255 pattern_detect(avsync,
256 (avsync->last_frame?avsync->last_frame->hold_period:0),
257 avsync->last_holding_peroid);
258 if (avsync->last_frame)
259 avsync->last_holding_peroid = avsync->last_frame->hold_period;
260
261 dqueue_item(avsync->frame_q, (void **)&frame);
262 if (avsync->last_frame) {
263 /* free frame that are not for display */
264 if (toggle_cnt > 1)
265 avsync->last_frame->free(avsync->last_frame);
266 } else {
267 avsync->first_frame_toggled = true;
268 log_info("first frame %d", frame->pts);
269 }
270 avsync->last_frame = frame;
271 } else
272 break;
273 }
274
275exit:
276 pthread_mutex_unlock(&avsync->lock);
277 if (avsync->last_frame)
278 log_debug("pop %d", avsync->last_frame->pts);
279 else
280 log_debug("pop (nil)");
281 if (avsync->last_frame)
282 avsync->last_frame->hold_period++;
283 return avsync->last_frame;
284}
285
286void av_sync_update_vsync_interval(void *sync, pts90K vsync_interval)
287{
288 struct av_sync_session *avsync = (struct av_sync_session *)sync;
289
290 pthread_mutex_lock(&avsync->lock);
291 avsync->vsync_interval = vsync_interval;
292 if (avsync->state >= AV_SYNC_STAT_RUNNING) {
293 reset_pattern(avsync->pattern_detector);
294 avsync->phase_set = false;
295 }
296 pthread_mutex_unlock(&avsync->lock);
297}
298
299static inline uint32_t abs_diff(uint32_t a, uint32_t b)
300{
301 return a > b ? a - b : b - a;
302}
303
304static bool frame_expire(struct av_sync_session* avsync,
305 uint32_t systime,
306 struct vframe * frame,
307 struct vframe * next_frame,
308 int toggle_cnt)
309{
310 uint32_t fpts = frame->pts;
311 bool expire = false;
312 uint32_t pts_correction = avsync->delay * avsync->vsync_interval;
313
314 if (!fpts) {
315 if (avsync->last_frame) {
316 /* try to accumulate duration as PTS */
317 fpts = avsync->vpts + avsync->last_frame->duration;
318 } else {
319 fpts = avsync->vpts;
320 }
321 }
322 systime += pts_correction;
323
324 /* phase adjustment */
325 if (avsync->phase_set)
326 systime += avsync->phase;
327
328 log_trace("systime:%d phase:%d correct:%d", systime,
329 avsync->phase_set?avsync->phase:0, pts_correction);
330 if (abs_diff(systime, fpts) > AV_DISCONTINUE_THREDHOLD_MIN &&
331 avsync->first_frame_toggled) {
332 /* ignore discontinity under pause */
333 if (avsync->paused && avsync->mode != AV_SYNC_MODE_PCR_MASTER)
334 return false;
335
336 log_warn("sync lost systime:%x fpts:%x", systime, fpts);
337 avsync->state = AV_SYNC_STAT_SYNC_LOST;
338 avsync->phase_set = false;
339 if (systime > fpts) {
340 if (frame->pts)
341 tsync_send_video_disc(avsync->session_id, frame->pts);
342 else if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
343 tsync_send_video_disc(avsync->session_id, frame->pts);
344 return false;
345 } else if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
346 if (frame->pts)
347 tsync_send_video_disc(avsync->session_id, frame->pts);
348 else {
349 tsync_send_video_disc(avsync->session_id, fpts);
350 return true;
351 }
352 }
353 } else {
354 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
355 log_info("sync setup");
356 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
357 }
358
359 expire = (systime >= fpts);
360
361 /* scatter the frame in different vsync whenever possible */
362 if (expire && next_frame && next_frame->pts && toggle_cnt) {
363 /* multi frame expired in current vsync but no frame in next vsync */
364 if (systime + avsync->vsync_interval < next_frame->pts) {
365 expire = false;
366 frame->hold_period++;
367 log_debug("unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
368 systime, avsync->vsync_interval, next_frame->pts, toggle_cnt);
369 }
370 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt) {
371 /* next vsync will have at least 2 frame expired */
372 if (systime + avsync->vsync_interval > next_frame->pts) {
373 expire = true;
374 log_debug("set expire systime:%d inter:%d next_pts:%d",
375 systime, avsync->vsync_interval, next_frame->pts);
376 }
377 }
378
379 correct_pattern(avsync->pattern_detector, frame, next_frame,
380 (avsync->last_frame?avsync->last_frame->hold_period:0),
381 avsync->last_holding_peroid, systime,
382 avsync->vsync_interval, &expire);
383
384 if (expire) {
385 avsync->vpts = fpts;
386 /* phase adjustment */
387 if (!avsync->phase_set) {
388 //systime = tsync_get_pcr(avsync->session_id);
389 if ( systime > fpts && (systime - fpts) < avsync->vsync_interval / 4) {
390 /* too aligned, separate them to 1/4 VSYNC */
391 avsync->phase += avsync->vsync_interval / 4 - (systime - fpts);
392 avsync->phase_set = true;
393 log_info("adjust phase to %d", avsync->phase);
394 }
395 }
396 }
397
398 return expire;
399}
400
401static void pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
402{
403 log_trace("cur_period: %d last_period: %d", cur_period, last_period);
404 detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period);
405 detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period);
406 detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period);
407 //TODO: add 11 support
408}