blob: cc018f38e74ac39ab57b62ad3a0635e0ecd5ae87 [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: frame pattern API ported from kernel video.c
8 * Author: song.zhao@amlogic.com
9 */
10#include <pthread.h>
11#include <stdbool.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <string.h>
15
16#include "aml_avsync.h"
17#include "pattern.h"
18#include "aml_avsync_log.h"
19
20#define PATTERN_32_D_RANGE 10
21#define PATTERN_22_D_RANGE 10
22#define PATTERN_41_D_RANGE 2
Song Zhao35a82df2021-04-15 10:58:49 -070023#define PATTERN_11_D_RANGE 10
Song Zhaoc03ba122020-12-23 21:54:02 -080024#define PATTERN_32_DURATION 3750
25#define PATTERN_22_DURATION 3000
Song Zhao35a82df2021-04-15 10:58:49 -070026#define PATTERN_11_DURATION 1500
Song Zhaoc03ba122020-12-23 21:54:02 -080027
28struct pattern_detector {
29 int match_cnt[AV_SYNC_FRAME_PMAX];
30 int enter_cnt[AV_SYNC_FRAME_PMAX];
31 int exit_cnt[AV_SYNC_FRAME_PMAX];
32
33 int pattern_41[4];
34 int pattern_41_index;
35 int detected;
36
37 /* reset lock */
38 pthread_mutex_t lock;
39};
40
41void* create_pattern_detector()
42{
43 struct pattern_detector *pd;
44
45 pd = (struct pattern_detector *)calloc(1, sizeof(*pd));
46 if (!pd) {
47 log_error("OOM");
48 return NULL;
49 }
50 pthread_mutex_init(&pd->lock, NULL);
51 pd->detected = -1;
52 return pd;
53}
54
55void destroy_pattern_detector(void *handle)
56{
57 struct pattern_detector *pd = (struct pattern_detector *)handle;
58
59 if (pd) {
60 pthread_mutex_destroy(&pd->lock);
61 free(pd);
62 }
63}
64
65void reset_pattern(void *handle)
66{
67 struct pattern_detector *pd = (struct pattern_detector *)handle;
68
69 if (!pd)
70 return;
71
72 pthread_mutex_lock(&pd->lock);
73 pd->detected = -1;
74 memset(pd->match_cnt, 0, sizeof(pd->match_cnt));
75 pthread_mutex_unlock(&pd->lock);
76}
77
78void correct_pattern(void* handle, struct vframe *frame, struct vframe *nextframe,
79 int cur_peroid, int last_peroid,
80 pts90K systime, pts90K vsync_interval, bool *expire)
81{
82 struct pattern_detector *pd = (struct pattern_detector *)handle;
Song Zhao97330c42021-07-30 05:21:53 +000083 int pattern_range, expected_cur_peroid, remain_period;
Song Zhaoc03ba122020-12-23 21:54:02 -080084 int expected_prev_interval;
85 int npts = 0;
86
87 /* Dont do anything if we have invalid data */
88 if (!pd || !frame || !frame->pts)
89 return;
90
91 if (nextframe)
92 npts = nextframe->pts;
93
94 pthread_mutex_lock(&pd->lock);
95 switch (pd->detected) {
96 case AV_SYNC_FRAME_P32:
97 pattern_range = PATTERN_32_D_RANGE;
98 switch (last_peroid) {
99 case 3:
100 expected_prev_interval = 3;
101 expected_cur_peroid = 2;
102 break;
103 case 2:
104 expected_prev_interval = 2;
105 expected_cur_peroid = 3;
106 break;
107 default:
108 goto exit;
109 }
110 if (!npts)
111 npts = frame->pts + PATTERN_32_DURATION;
112 break;
113 case AV_SYNC_FRAME_P22:
114 if (last_peroid != 2)
115 goto exit;
116 pattern_range = PATTERN_22_D_RANGE;
117 expected_prev_interval = 2;
118 expected_cur_peroid = 2;
119 if (!npts)
120 npts = frame->pts + PATTERN_22_DURATION;
121 break;
122 case AV_SYNC_FRAME_P41:
123 /* TODO */
Song Zhao35a82df2021-04-15 10:58:49 -0700124 case AV_SYNC_FRAME_P11:
125 if (last_peroid != 1)
126 goto exit;
127 pattern_range = PATTERN_11_D_RANGE;
128 expected_prev_interval = 1;
129 expected_cur_peroid = 1;
130 if (!npts)
131 npts = frame->pts + PATTERN_11_DURATION;
132 break;
Song Zhaoc03ba122020-12-23 21:54:02 -0800133 default:
134 goto exit;
135 }
136
137 /* We do nothing if we dont have enough data*/
138 if (pd->match_cnt[pd->detected] != pattern_range)
139 goto exit;
140
141 if (*expire) {
142 if (cur_peroid < expected_cur_peroid) {
Song Zhao97330c42021-07-30 05:21:53 +0000143 remain_period = expected_cur_peroid - cur_peroid;
Song Zhaoc03ba122020-12-23 21:54:02 -0800144 /* 2323232323..2233..2323, prev=2, curr=3,*/
145 /* check if next frame will toggle after 3 vsyncs */
146 /* 22222...22222 -> 222..2213(2)22...22 */
147 /* check if next frame will toggle after 3 vsyncs */
yongchun.li12b14542021-05-19 18:56:31 -0700148 /* shall only allow one extra interval space to play around */
Song Zhao97330c42021-07-30 05:21:53 +0000149 if (systime - frame->pts <= 90) {
150 *expire = false;
151 log_debug("hold frame for pattern: %d sys: %u fpts: %u",
152 pd->detected, systime, frame->pts);
153 } else if (((int)(systime + (remain_period + 1) *
154 vsync_interval - npts) <= 0) &&
155 ((int)(systime + (remain_period + 2) *
156 vsync_interval - npts) > 0)) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800157 *expire = false;
158 log_debug("hold frame for pattern: %d", pd->detected);
Song Zhao97330c42021-07-30 05:21:53 +0000159 } else {
160 log_debug("not hold frame for pattern: %d sys: %u fpts: %u s-f %u nfps: %u",
161 pd->detected, systime, frame->pts, systime - frame->pts, npts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800162 }
163
164#if 0 // Frame scattering is the right place to adjust the hold time.
165 /* here need to escape a vsync */
166 if (systime > (frame->pts + vsync_interval)) {
167 *expire = true;
168 pts_escape_vsync = 1;
169 log_info("escape a vsync pattern: %d", pd->detected);
170 }
171#endif
172 }
173 } else {
174 if (cur_peroid == expected_cur_peroid) {
175 /* 23232323..233223...2323 curr=2, prev=3 */
176 /* check if this frame will expire next vsyncs and */
177 /* next frame will expire after 3 vsyncs */
178 /* 22222...22222 -> 222..223122...22 */
179 /* check if this frame will expire next vsyncs and */
180 /* next frame will expire after 2 vsyncs */
181
182 if (((int)(systime + vsync_interval - frame->pts) >= 0) &&
183 ((int)(systime + vsync_interval * (expected_prev_interval - 1) - npts) < 0) &&
184 ((int)(systime + expected_prev_interval * vsync_interval - npts) >= 0)) {
185 *expire = true;
186 log_debug("squeeze frame for pattern: %d", pd->detected);
187 }
188 }
189 }
190exit:
191 pthread_mutex_unlock(&pd->lock);
192}
193
Song Zhao35a82df2021-04-15 10:58:49 -0700194bool detect_pattern(void* handle, enum frame_pattern pattern, int cur_peroid, int last_peroid)
Song Zhaoc03ba122020-12-23 21:54:02 -0800195{
196 struct pattern_detector *pd = (struct pattern_detector *)handle;
197 int factor1 = 0, factor2 = 0, range = 0;
Song Zhao35a82df2021-04-15 10:58:49 -0700198 bool ret = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800199
200 if (!pd || pattern >= AV_SYNC_FRAME_PMAX)
Song Zhao35a82df2021-04-15 10:58:49 -0700201 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800202
203 pthread_mutex_lock(&pd->lock);
204 if (pattern == AV_SYNC_FRAME_P32) {
205 factor1 = 3;
206 factor2 = 2;
207 range = PATTERN_32_D_RANGE;
208 } else if (pattern == AV_SYNC_FRAME_P22) {
209 factor1 = 2;
210 factor2 = 2;
211 range = PATTERN_22_D_RANGE;
212 } else if (pattern == AV_SYNC_FRAME_P41) {
213 /* update 2111 mode detection */
214 if (cur_peroid == 2) {
215 if (pd->pattern_41[1] == 1 && pd->pattern_41[2] == 1 && pd->pattern_41[3] == 1 &&
216 (pd->match_cnt[pattern] < PATTERN_41_D_RANGE)) {
217 pd->match_cnt[pattern]++;
218 if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
219 pd->enter_cnt[pattern]++;
220 pd->detected = pattern;
221 log_info("video 4:1 mode detected");
222 }
223 }
224 pd->pattern_41[0] = 2;
225 pd->pattern_41_index = 1;
226 } else if (cur_peroid == 1) {
227 if ((pd->pattern_41_index < 4) &&
228 (pd->pattern_41_index > 0)) {
229 pd->pattern_41[pd->pattern_41_index] = 1;
230 pd->pattern_41_index++;
231 } else if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
232 pd->match_cnt[pattern] = 0;
233 pd->pattern_41_index = 0;
234 pd->exit_cnt[pattern]++;
235 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
236 log_info("video 4:1 mode broken");
237 } else {
238 pd->match_cnt[pattern] = 0;
239 pd->pattern_41_index = 0;
240 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
241 }
242 } else if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
243 pd->match_cnt[pattern] = 0;
244 pd->pattern_41_index = 0;
245 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
246 pd->exit_cnt[pattern]++;
247 log_info("video 4:1 mode broken");
248 } else {
249 pd->match_cnt[pattern] = 0;
250 pd->pattern_41_index = 0;
251 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
252 }
253 goto exit;
Song Zhao35a82df2021-04-15 10:58:49 -0700254 } else if (pattern == AV_SYNC_FRAME_P11) {
255 factor1 = 1;
256 factor2 = 1;
257 range = PATTERN_11_D_RANGE;
Song Zhaoc03ba122020-12-23 21:54:02 -0800258 }
259
Song Zhao35a82df2021-04-15 10:58:49 -0700260 /* update 1:1 3:2 or 2:2 mode detection */
Song Zhaoc03ba122020-12-23 21:54:02 -0800261 if (((last_peroid == factor1) && (cur_peroid == factor2)) ||
262 ((last_peroid == factor2) && (cur_peroid == factor1))) {
263 if (pd->match_cnt[pattern] < range) {
264 pd->match_cnt[pattern]++;
265 if (pd->match_cnt[pattern] == range) {
266 pd->enter_cnt[pattern]++;
267 pd->detected = pattern;
Song Zhao35a82df2021-04-15 10:58:49 -0700268 log_info("video %d:%d mode detected cnt %d", factor1, factor2,
269 pd->enter_cnt[pattern]);
Song Zhaoc03ba122020-12-23 21:54:02 -0800270 }
271 }
272 } else if (pd->match_cnt[pattern] == range) {
273 pd->match_cnt[pattern] = 0;
274 pd->exit_cnt[pattern]++;
Song Zhao35a82df2021-04-15 10:58:49 -0700275 log_info("video %d:%d mode broken by %d:%d cnt %d", factor1, factor2,
276 last_peroid, cur_peroid, pd->exit_cnt[pattern]);
277 ret = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800278 } else
279 pd->match_cnt[pattern] = 0;
280
281exit:
282 pthread_mutex_unlock(&pd->lock);
Song Zhao35a82df2021-04-15 10:58:49 -0700283 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800284}