blob: 8210c08195ab45c82456e8df94f1cf90349b2759 [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;
83 int pattern_range, expected_cur_peroid;
84 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) {
143 /* 2323232323..2233..2323, prev=2, curr=3,*/
144 /* check if next frame will toggle after 3 vsyncs */
145 /* 22222...22222 -> 222..2213(2)22...22 */
146 /* check if next frame will toggle after 3 vsyncs */
yongchun.li12b14542021-05-19 18:56:31 -0700147 /* shall only allow one extra interval space to play around */
Song Zhaoc03ba122020-12-23 21:54:02 -0800148 if (((int)(systime + (expected_prev_interval + 1) *
yongchun.li12b14542021-05-19 18:56:31 -0700149 vsync_interval - npts) >= 0) &&
150 ((int)(systime + (expected_prev_interval + 2) *
151 vsync_interval - npts) < 0)) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800152 *expire = false;
153 log_debug("hold frame for pattern: %d", pd->detected);
154 }
155
156#if 0 // Frame scattering is the right place to adjust the hold time.
157 /* here need to escape a vsync */
158 if (systime > (frame->pts + vsync_interval)) {
159 *expire = true;
160 pts_escape_vsync = 1;
161 log_info("escape a vsync pattern: %d", pd->detected);
162 }
163#endif
164 }
165 } else {
166 if (cur_peroid == expected_cur_peroid) {
167 /* 23232323..233223...2323 curr=2, prev=3 */
168 /* check if this frame will expire next vsyncs and */
169 /* next frame will expire after 3 vsyncs */
170 /* 22222...22222 -> 222..223122...22 */
171 /* check if this frame will expire next vsyncs and */
172 /* next frame will expire after 2 vsyncs */
173
174 if (((int)(systime + vsync_interval - frame->pts) >= 0) &&
175 ((int)(systime + vsync_interval * (expected_prev_interval - 1) - npts) < 0) &&
176 ((int)(systime + expected_prev_interval * vsync_interval - npts) >= 0)) {
177 *expire = true;
178 log_debug("squeeze frame for pattern: %d", pd->detected);
179 }
180 }
181 }
182exit:
183 pthread_mutex_unlock(&pd->lock);
184}
185
Song Zhao35a82df2021-04-15 10:58:49 -0700186bool detect_pattern(void* handle, enum frame_pattern pattern, int cur_peroid, int last_peroid)
Song Zhaoc03ba122020-12-23 21:54:02 -0800187{
188 struct pattern_detector *pd = (struct pattern_detector *)handle;
189 int factor1 = 0, factor2 = 0, range = 0;
Song Zhao35a82df2021-04-15 10:58:49 -0700190 bool ret = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800191
192 if (!pd || pattern >= AV_SYNC_FRAME_PMAX)
Song Zhao35a82df2021-04-15 10:58:49 -0700193 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800194
195 pthread_mutex_lock(&pd->lock);
196 if (pattern == AV_SYNC_FRAME_P32) {
197 factor1 = 3;
198 factor2 = 2;
199 range = PATTERN_32_D_RANGE;
200 } else if (pattern == AV_SYNC_FRAME_P22) {
201 factor1 = 2;
202 factor2 = 2;
203 range = PATTERN_22_D_RANGE;
204 } else if (pattern == AV_SYNC_FRAME_P41) {
205 /* update 2111 mode detection */
206 if (cur_peroid == 2) {
207 if (pd->pattern_41[1] == 1 && pd->pattern_41[2] == 1 && pd->pattern_41[3] == 1 &&
208 (pd->match_cnt[pattern] < PATTERN_41_D_RANGE)) {
209 pd->match_cnt[pattern]++;
210 if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
211 pd->enter_cnt[pattern]++;
212 pd->detected = pattern;
213 log_info("video 4:1 mode detected");
214 }
215 }
216 pd->pattern_41[0] = 2;
217 pd->pattern_41_index = 1;
218 } else if (cur_peroid == 1) {
219 if ((pd->pattern_41_index < 4) &&
220 (pd->pattern_41_index > 0)) {
221 pd->pattern_41[pd->pattern_41_index] = 1;
222 pd->pattern_41_index++;
223 } else if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
224 pd->match_cnt[pattern] = 0;
225 pd->pattern_41_index = 0;
226 pd->exit_cnt[pattern]++;
227 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
228 log_info("video 4:1 mode broken");
229 } else {
230 pd->match_cnt[pattern] = 0;
231 pd->pattern_41_index = 0;
232 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
233 }
234 } else if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
235 pd->match_cnt[pattern] = 0;
236 pd->pattern_41_index = 0;
237 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
238 pd->exit_cnt[pattern]++;
239 log_info("video 4:1 mode broken");
240 } else {
241 pd->match_cnt[pattern] = 0;
242 pd->pattern_41_index = 0;
243 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
244 }
245 goto exit;
Song Zhao35a82df2021-04-15 10:58:49 -0700246 } else if (pattern == AV_SYNC_FRAME_P11) {
247 factor1 = 1;
248 factor2 = 1;
249 range = PATTERN_11_D_RANGE;
Song Zhaoc03ba122020-12-23 21:54:02 -0800250 }
251
Song Zhao35a82df2021-04-15 10:58:49 -0700252 /* update 1:1 3:2 or 2:2 mode detection */
Song Zhaoc03ba122020-12-23 21:54:02 -0800253 if (((last_peroid == factor1) && (cur_peroid == factor2)) ||
254 ((last_peroid == factor2) && (cur_peroid == factor1))) {
255 if (pd->match_cnt[pattern] < range) {
256 pd->match_cnt[pattern]++;
257 if (pd->match_cnt[pattern] == range) {
258 pd->enter_cnt[pattern]++;
259 pd->detected = pattern;
Song Zhao35a82df2021-04-15 10:58:49 -0700260 log_info("video %d:%d mode detected cnt %d", factor1, factor2,
261 pd->enter_cnt[pattern]);
Song Zhaoc03ba122020-12-23 21:54:02 -0800262 }
263 }
264 } else if (pd->match_cnt[pattern] == range) {
265 pd->match_cnt[pattern] = 0;
266 pd->exit_cnt[pattern]++;
Song Zhao35a82df2021-04-15 10:58:49 -0700267 log_info("video %d:%d mode broken by %d:%d cnt %d", factor1, factor2,
268 last_peroid, cur_peroid, pd->exit_cnt[pattern]);
269 ret = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800270 } else
271 pd->match_cnt[pattern] = 0;
272
273exit:
274 pthread_mutex_unlock(&pd->lock);
Song Zhao35a82df2021-04-15 10:58:49 -0700275 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800276}