blob: 231b3999784085b5df52b8fe1f30990dc922b5cd [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 */
147
148 if (((int)(systime + (expected_prev_interval + 1) *
149 vsync_interval - npts) >= 0)) {
150 *expire = false;
151 log_debug("hold frame for pattern: %d", pd->detected);
152 }
153
154#if 0 // Frame scattering is the right place to adjust the hold time.
155 /* here need to escape a vsync */
156 if (systime > (frame->pts + vsync_interval)) {
157 *expire = true;
158 pts_escape_vsync = 1;
159 log_info("escape a vsync pattern: %d", pd->detected);
160 }
161#endif
162 }
163 } else {
164 if (cur_peroid == expected_cur_peroid) {
165 /* 23232323..233223...2323 curr=2, prev=3 */
166 /* check if this frame will expire next vsyncs and */
167 /* next frame will expire after 3 vsyncs */
168 /* 22222...22222 -> 222..223122...22 */
169 /* check if this frame will expire next vsyncs and */
170 /* next frame will expire after 2 vsyncs */
171
172 if (((int)(systime + vsync_interval - frame->pts) >= 0) &&
173 ((int)(systime + vsync_interval * (expected_prev_interval - 1) - npts) < 0) &&
174 ((int)(systime + expected_prev_interval * vsync_interval - npts) >= 0)) {
175 *expire = true;
176 log_debug("squeeze frame for pattern: %d", pd->detected);
177 }
178 }
179 }
180exit:
181 pthread_mutex_unlock(&pd->lock);
182}
183
Song Zhao35a82df2021-04-15 10:58:49 -0700184bool detect_pattern(void* handle, enum frame_pattern pattern, int cur_peroid, int last_peroid)
Song Zhaoc03ba122020-12-23 21:54:02 -0800185{
186 struct pattern_detector *pd = (struct pattern_detector *)handle;
187 int factor1 = 0, factor2 = 0, range = 0;
Song Zhao35a82df2021-04-15 10:58:49 -0700188 bool ret = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800189
190 if (!pd || pattern >= AV_SYNC_FRAME_PMAX)
Song Zhao35a82df2021-04-15 10:58:49 -0700191 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800192
193 pthread_mutex_lock(&pd->lock);
194 if (pattern == AV_SYNC_FRAME_P32) {
195 factor1 = 3;
196 factor2 = 2;
197 range = PATTERN_32_D_RANGE;
198 } else if (pattern == AV_SYNC_FRAME_P22) {
199 factor1 = 2;
200 factor2 = 2;
201 range = PATTERN_22_D_RANGE;
202 } else if (pattern == AV_SYNC_FRAME_P41) {
203 /* update 2111 mode detection */
204 if (cur_peroid == 2) {
205 if (pd->pattern_41[1] == 1 && pd->pattern_41[2] == 1 && pd->pattern_41[3] == 1 &&
206 (pd->match_cnt[pattern] < PATTERN_41_D_RANGE)) {
207 pd->match_cnt[pattern]++;
208 if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
209 pd->enter_cnt[pattern]++;
210 pd->detected = pattern;
211 log_info("video 4:1 mode detected");
212 }
213 }
214 pd->pattern_41[0] = 2;
215 pd->pattern_41_index = 1;
216 } else if (cur_peroid == 1) {
217 if ((pd->pattern_41_index < 4) &&
218 (pd->pattern_41_index > 0)) {
219 pd->pattern_41[pd->pattern_41_index] = 1;
220 pd->pattern_41_index++;
221 } else if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
222 pd->match_cnt[pattern] = 0;
223 pd->pattern_41_index = 0;
224 pd->exit_cnt[pattern]++;
225 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
226 log_info("video 4:1 mode broken");
227 } else {
228 pd->match_cnt[pattern] = 0;
229 pd->pattern_41_index = 0;
230 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
231 }
232 } else if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
233 pd->match_cnt[pattern] = 0;
234 pd->pattern_41_index = 0;
235 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
236 pd->exit_cnt[pattern]++;
237 log_info("video 4:1 mode broken");
238 } else {
239 pd->match_cnt[pattern] = 0;
240 pd->pattern_41_index = 0;
241 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
242 }
243 goto exit;
Song Zhao35a82df2021-04-15 10:58:49 -0700244 } else if (pattern == AV_SYNC_FRAME_P11) {
245 factor1 = 1;
246 factor2 = 1;
247 range = PATTERN_11_D_RANGE;
Song Zhaoc03ba122020-12-23 21:54:02 -0800248 }
249
Song Zhao35a82df2021-04-15 10:58:49 -0700250 /* update 1:1 3:2 or 2:2 mode detection */
Song Zhaoc03ba122020-12-23 21:54:02 -0800251 if (((last_peroid == factor1) && (cur_peroid == factor2)) ||
252 ((last_peroid == factor2) && (cur_peroid == factor1))) {
253 if (pd->match_cnt[pattern] < range) {
254 pd->match_cnt[pattern]++;
255 if (pd->match_cnt[pattern] == range) {
256 pd->enter_cnt[pattern]++;
257 pd->detected = pattern;
Song Zhao35a82df2021-04-15 10:58:49 -0700258 log_info("video %d:%d mode detected cnt %d", factor1, factor2,
259 pd->enter_cnt[pattern]);
Song Zhaoc03ba122020-12-23 21:54:02 -0800260 }
261 }
262 } else if (pd->match_cnt[pattern] == range) {
263 pd->match_cnt[pattern] = 0;
264 pd->exit_cnt[pattern]++;
Song Zhao35a82df2021-04-15 10:58:49 -0700265 log_info("video %d:%d mode broken by %d:%d cnt %d", factor1, factor2,
266 last_peroid, cur_peroid, pd->exit_cnt[pattern]);
267 ret = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800268 } else
269 pd->match_cnt[pattern] = 0;
270
271exit:
272 pthread_mutex_unlock(&pd->lock);
Song Zhao35a82df2021-04-15 10:58:49 -0700273 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800274}