blob: 69f48405b29a050007fbaa0ded051ea5c6ef867b [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: 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
23#define PATTERN_32_DURATION 3750
24#define PATTERN_22_DURATION 3000
25
26struct pattern_detector {
27 int match_cnt[AV_SYNC_FRAME_PMAX];
28 int enter_cnt[AV_SYNC_FRAME_PMAX];
29 int exit_cnt[AV_SYNC_FRAME_PMAX];
30
31 int pattern_41[4];
32 int pattern_41_index;
33 int detected;
34
35 /* reset lock */
36 pthread_mutex_t lock;
37};
38
39void* create_pattern_detector()
40{
41 struct pattern_detector *pd;
42
43 pd = (struct pattern_detector *)calloc(1, sizeof(*pd));
44 if (!pd) {
45 log_error("OOM");
46 return NULL;
47 }
48 pthread_mutex_init(&pd->lock, NULL);
49 pd->detected = -1;
50 return pd;
51}
52
53void destroy_pattern_detector(void *handle)
54{
55 struct pattern_detector *pd = (struct pattern_detector *)handle;
56
57 if (pd) {
58 pthread_mutex_destroy(&pd->lock);
59 free(pd);
60 }
61}
62
63void reset_pattern(void *handle)
64{
65 struct pattern_detector *pd = (struct pattern_detector *)handle;
66
67 if (!pd)
68 return;
69
70 pthread_mutex_lock(&pd->lock);
71 pd->detected = -1;
72 memset(pd->match_cnt, 0, sizeof(pd->match_cnt));
73 pthread_mutex_unlock(&pd->lock);
74}
75
76void correct_pattern(void* handle, struct vframe *frame, struct vframe *nextframe,
77 int cur_peroid, int last_peroid,
78 pts90K systime, pts90K vsync_interval, bool *expire)
79{
80 struct pattern_detector *pd = (struct pattern_detector *)handle;
81 int pattern_range, expected_cur_peroid;
82 int expected_prev_interval;
83 int npts = 0;
84
85 /* Dont do anything if we have invalid data */
86 if (!pd || !frame || !frame->pts)
87 return;
88
89 if (nextframe)
90 npts = nextframe->pts;
91
92 pthread_mutex_lock(&pd->lock);
93 switch (pd->detected) {
94 case AV_SYNC_FRAME_P32:
95 pattern_range = PATTERN_32_D_RANGE;
96 switch (last_peroid) {
97 case 3:
98 expected_prev_interval = 3;
99 expected_cur_peroid = 2;
100 break;
101 case 2:
102 expected_prev_interval = 2;
103 expected_cur_peroid = 3;
104 break;
105 default:
106 goto exit;
107 }
108 if (!npts)
109 npts = frame->pts + PATTERN_32_DURATION;
110 break;
111 case AV_SYNC_FRAME_P22:
112 if (last_peroid != 2)
113 goto exit;
114 pattern_range = PATTERN_22_D_RANGE;
115 expected_prev_interval = 2;
116 expected_cur_peroid = 2;
117 if (!npts)
118 npts = frame->pts + PATTERN_22_DURATION;
119 break;
120 case AV_SYNC_FRAME_P41:
121 /* TODO */
122 default:
123 goto exit;
124 }
125
126 /* We do nothing if we dont have enough data*/
127 if (pd->match_cnt[pd->detected] != pattern_range)
128 goto exit;
129
130 if (*expire) {
131 if (cur_peroid < expected_cur_peroid) {
132 /* 2323232323..2233..2323, prev=2, curr=3,*/
133 /* check if next frame will toggle after 3 vsyncs */
134 /* 22222...22222 -> 222..2213(2)22...22 */
135 /* check if next frame will toggle after 3 vsyncs */
136
137 if (((int)(systime + (expected_prev_interval + 1) *
138 vsync_interval - npts) >= 0)) {
139 *expire = false;
140 log_info("hold frame for pattern: %d", pd->detected);
141 }
142
143#if 0 // Frame scattering is the right place to adjust the hold time.
144 /* here need to escape a vsync */
145 if (systime > (frame->pts + vsync_interval)) {
146 *expire = true;
147 pts_escape_vsync = 1;
148 log_info("escape a vsync pattern: %d", pd->detected);
149 }
150#endif
151 }
152 } else {
153 if (cur_peroid == expected_cur_peroid) {
154 /* 23232323..233223...2323 curr=2, prev=3 */
155 /* check if this frame will expire next vsyncs and */
156 /* next frame will expire after 3 vsyncs */
157 /* 22222...22222 -> 222..223122...22 */
158 /* check if this frame will expire next vsyncs and */
159 /* next frame will expire after 2 vsyncs */
160
161 if (((int)(systime + vsync_interval - frame->pts) >= 0) &&
162 ((int)(systime + vsync_interval * (expected_prev_interval - 1) - npts) < 0) &&
163 ((int)(systime + expected_prev_interval * vsync_interval - npts) >= 0)) {
164 *expire = true;
165 log_info("pull frame for pattern: %d", pd->detected);
166 }
167 }
168 }
169exit:
170 pthread_mutex_unlock(&pd->lock);
171}
172
173void detect_pattern(void* handle, enum frame_pattern pattern, int cur_peroid, int last_peroid)
174{
175 struct pattern_detector *pd = (struct pattern_detector *)handle;
176 int factor1 = 0, factor2 = 0, range = 0;
177
178 if (!pd || pattern >= AV_SYNC_FRAME_PMAX)
179 return;
180
181 pthread_mutex_lock(&pd->lock);
182 if (pattern == AV_SYNC_FRAME_P32) {
183 factor1 = 3;
184 factor2 = 2;
185 range = PATTERN_32_D_RANGE;
186 } else if (pattern == AV_SYNC_FRAME_P22) {
187 factor1 = 2;
188 factor2 = 2;
189 range = PATTERN_22_D_RANGE;
190 } else if (pattern == AV_SYNC_FRAME_P41) {
191 /* update 2111 mode detection */
192 if (cur_peroid == 2) {
193 if (pd->pattern_41[1] == 1 && pd->pattern_41[2] == 1 && pd->pattern_41[3] == 1 &&
194 (pd->match_cnt[pattern] < PATTERN_41_D_RANGE)) {
195 pd->match_cnt[pattern]++;
196 if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
197 pd->enter_cnt[pattern]++;
198 pd->detected = pattern;
199 log_info("video 4:1 mode detected");
200 }
201 }
202 pd->pattern_41[0] = 2;
203 pd->pattern_41_index = 1;
204 } else if (cur_peroid == 1) {
205 if ((pd->pattern_41_index < 4) &&
206 (pd->pattern_41_index > 0)) {
207 pd->pattern_41[pd->pattern_41_index] = 1;
208 pd->pattern_41_index++;
209 } else if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
210 pd->match_cnt[pattern] = 0;
211 pd->pattern_41_index = 0;
212 pd->exit_cnt[pattern]++;
213 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
214 log_info("video 4:1 mode broken");
215 } else {
216 pd->match_cnt[pattern] = 0;
217 pd->pattern_41_index = 0;
218 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
219 }
220 } else if (pd->match_cnt[pattern] == PATTERN_41_D_RANGE) {
221 pd->match_cnt[pattern] = 0;
222 pd->pattern_41_index = 0;
223 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
224 pd->exit_cnt[pattern]++;
225 log_info("video 4:1 mode broken");
226 } else {
227 pd->match_cnt[pattern] = 0;
228 pd->pattern_41_index = 0;
229 memset(&pd->pattern_41[0], 0, sizeof(pd->pattern_41));
230 }
231 goto exit;
232 }
233
234 /* update 3:2 or 2:2 mode detection */
235 if (((last_peroid == factor1) && (cur_peroid == factor2)) ||
236 ((last_peroid == factor2) && (cur_peroid == factor1))) {
237 if (pd->match_cnt[pattern] < range) {
238 pd->match_cnt[pattern]++;
239 if (pd->match_cnt[pattern] == range) {
240 pd->enter_cnt[pattern]++;
241 pd->detected = pattern;
242 log_info("video %d:%d mode detected", factor1, factor2);
243 }
244 }
245 } else if (pd->match_cnt[pattern] == range) {
246 pd->match_cnt[pattern] = 0;
247 pd->exit_cnt[pattern]++;
248 log_info("video %d:%d mode broken", factor1, factor2);
249 } else
250 pd->match_cnt[pattern] = 0;
251
252exit:
253 pthread_mutex_unlock(&pd->lock);
254}