1 /*
2 * Copyright 2020 Rockchip Electronics Co. LTD
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "iep2_pd.h"
18
19 #include <stdio.h>
20 #ifdef SIMULATE
21 #include <malloc.h>
22 #endif
23 #include <string.h>
24 #include <stdlib.h>
25
26 #include "mpp_common.h"
27 #include "iep_common.h"
28
29 #include "iep2.h"
30 #include "iep2_api.h"
31
32 #define RKMIN(a, b) (((a) < (b)) ? (a) : (b))
33 #define RKMAX(a, b) (((a) > (b)) ? (a) : (b))
34
35 #define PD_TS 1 // Top field unchanged, Bottom field changed
36 #define PD_BS 2 // Top filed changed, Bottom field unchanged
37 #define PD_DF 0 // Both fileds changed.
38 #define PD_ID 3
39
40 #define PD_FRAME_PERIOD 5
41
42 #define FIELD_DIFF_SUM_THR 32
43
44 static int pd_table[][PD_FRAME_PERIOD] = {
45 { PD_TS, PD_DF, PD_BS, PD_DF, PD_DF }, // 3:2:3:2
46 { PD_DF, PD_BS, PD_DF, PD_TS, PD_DF }, // 2:3:2:3
47 { PD_TS, PD_BS, PD_DF, PD_DF, PD_DF }, // 2:3:3:2
48 { PD_BS, PD_DF, PD_DF, PD_TS, PD_DF }, // 3:2:2:3
49 { PD_DF, PD_DF, PD_DF, PD_DF, PD_DF } // unknown
50 };
51
52 // field intensity table
53 static int sp_table[][PD_FRAME_PERIOD] = {
54 { 0, 1, 1, 0, 0 },
55 { 0, 0, 1, 1, 0 },
56 { 0, 1, 0, 0, 0 },
57 { 0, 1, 1, 1, 0 },
58 { 1, 1, 1, 1, 1 }
59 };
60
61 static int fp_table[][PD_FRAME_PERIOD] = {
62 { 1, 1, 1, 0, 0 },
63 { 0, 1, 1, 1, 0 },
64 { 0, 1, 1, 0, 0 },
65 { 1, 1, 1, 1, 0 },
66 { 1, 1, 1, 1, 1 }
67 };
68
69 static char* pd_titles[] = {
70 "PULLDOWN 3:2:3:2",
71 "PULLDOWN 2:3:2:3",
72 "PULLDOWN 2:3:3:2",
73 "PULLDOWN 3:2:2:3",
74 "PULLDOWN UNKNOWN"
75 };
76
iep2_check_pd(struct iep2_api_ctx * ctx)77 void iep2_check_pd(struct iep2_api_ctx *ctx)
78 {
79 struct iep2_pd_info *pd_inf = &ctx->pd_inf;
80 int tcnt = ctx->output.dect_pd_tcnt;
81 int bcnt = ctx->output.dect_pd_bcnt;
82 int tdiff = ctx->output.ff_gradt_tcnt + 1;
83 int bdiff = ctx->output.ff_gradt_bcnt + 1;
84 int idx = pd_inf->i % PD_FRAME_PERIOD;
85 int ff00t = (ctx->output.dect_ff_cur_tcnt << 5) / tdiff;
86 int ff00b = (ctx->output.dect_ff_cur_bcnt << 5) / bdiff;
87 int nz = ctx->output.dect_ff_nz + 1;
88 int f = ctx->output.dect_ff_comb_f;
89 size_t i, j;
90
91 pd_inf->spatial[idx] = RKMIN(ff00t, ff00b);
92 pd_inf->temporal[idx] = (tcnt < FIELD_DIFF_SUM_THR) | ((bcnt < FIELD_DIFF_SUM_THR) << 1);
93 pd_inf->fcoeff[idx] = f * 100 / nz;
94
95 iep_dbg_trace("pd tcnt %d bcnt %d\n", tcnt, bcnt);
96 iep_dbg_trace("temporal(%d, %d) %d %d %d %d %d\n",
97 idx, pd_inf->step,
98 pd_inf->temporal[0],
99 pd_inf->temporal[1],
100 pd_inf->temporal[2],
101 pd_inf->temporal[3],
102 pd_inf->temporal[4]);
103 iep_dbg_trace("spatial(%d, %d) %d %d %d %d %d\n",
104 idx, pd_inf->step,
105 pd_inf->spatial[0],
106 pd_inf->spatial[1],
107 pd_inf->spatial[2],
108 pd_inf->spatial[3],
109 pd_inf->spatial[4]);
110 iep_dbg_trace("fcoeff(%d, %d) %d %d %d %d %d\n",
111 idx, pd_inf->step,
112 pd_inf->fcoeff[0],
113 pd_inf->fcoeff[1],
114 pd_inf->fcoeff[2],
115 pd_inf->fcoeff[3],
116 pd_inf->fcoeff[4]);
117
118 if (pd_inf->pdtype != PD_TYPES_UNKNOWN && pd_inf->step != -1) {
119 int n = (int)pd_inf->pdtype;
120 int type = pd_table[n][(pd_inf->step + 1) % 5];
121
122 if ((type == PD_TS && !(tcnt < FIELD_DIFF_SUM_THR)) ||
123 (type == PD_BS && !(bcnt < FIELD_DIFF_SUM_THR))) {
124 pd_inf->pdtype = PD_TYPES_UNKNOWN;
125 pd_inf->step = -1;
126 }
127 }
128
129 pd_inf->step = pd_inf->step != -1 ? (pd_inf->step + 1) % 5 : -1;
130
131 if (pd_inf->pdtype != PD_TYPES_UNKNOWN) {
132 pd_inf->i++;
133 return;
134 } else {
135 iep_dbg_trace("pulldown recheck start: old type %s\n", pd_titles[pd_inf->pdtype]);
136 }
137
138 for (i = 0; i < MPP_ARRAY_ELEMS(pd_table); ++i) {
139 if (pd_inf->temporal[idx] == pd_table[i][0] &&
140 pd_inf->temporal[(idx + 1) % 5] == pd_table[i][1] &&
141 pd_inf->temporal[(idx + 2) % 5] == pd_table[i][2] &&
142 pd_inf->temporal[(idx + 3) % 5] == pd_table[i][3] &&
143 pd_inf->temporal[(idx + 4) % 5] == pd_table[i][4]) {
144
145 iep_dbg_trace("[%d] match %s, current idx %d\n", i, pd_titles[i], idx % PD_FRAME_PERIOD);
146
147 if (i != PD_TYPES_UNKNOWN) {
148 int vmax = 0x7fffffff;
149 int vmin = 0;
150 int fmax = 0x7fffffff;
151 int fmin = 0;
152
153 iep_dbg_trace("get pulldown type %s\n", pd_titles[i]);
154
155 for (j = 0; j < MPP_ARRAY_ELEMS(sp_table[i]); ++j) {
156 if (sp_table[i][j] == 1) {
157 vmax = RKMIN(vmax, pd_inf->spatial[j]);
158 } else {
159 vmin = RKMAX(vmin, pd_inf->spatial[j]);
160 }
161 }
162
163 for (j = 0; j < MPP_ARRAY_ELEMS(fp_table[i]); ++j) {
164 if (fp_table[i][j] == 1) {
165 fmax = RKMIN(fmax, pd_inf->fcoeff[(idx + j) % 5]);
166 } else {
167 fmin = RKMAX(fmin, pd_inf->fcoeff[(idx + j) % 5]);
168 }
169 }
170
171 if (vmax > vmin || fmax > fmin) {
172 pd_inf->pdtype = i;
173
174 if (i == PD_TYPES_3_2_2_3 && pd_inf->spatial[1] > RKMAX(pd_inf->spatial[0],
175 pd_inf->spatial[4])) {
176 pd_inf->pdtype = PD_TYPES_3_2_3_2;
177 }
178
179 iep_dbg_trace("confirm pulldown type %s\n", pd_titles[i]);
180 pd_inf->step = 0;
181 }
182 }
183 break;
184 }
185 }
186
187 pd_inf->i++;
188 }
189
190 char *PD_COMP_STRING[] = {
191 "PD_COMP_CC",
192 "PD_COMP_CN",
193 "PD_COMP_NC",
194 "PD_COMP_NON"
195 };
196
197 /**
198 * @brief get pulldown compose flag
199 *
200 * @param pd_inf
201 * @return int see @PD_COMP_STRING
202 */
iep2_pd_get_output(struct iep2_pd_info * pd_inf)203 int iep2_pd_get_output(struct iep2_pd_info *pd_inf)
204 {
205 int flag = PD_COMP_FLAG_CC;
206 int step = (pd_inf->step + 1) % 5;
207
208 switch (pd_inf->pdtype) {
209 case PD_TYPES_3_2_3_2:
210 switch (step) {
211 case 1:
212 flag = PD_COMP_FLAG_NC;
213 break;
214 case 2:
215 flag = PD_COMP_FLAG_NON;
216 break;
217 }
218 break;
219 case PD_TYPES_2_3_2_3:
220 switch (step) {
221 case 2:
222 flag = PD_COMP_FLAG_CN;
223 break;
224 case 3:
225 flag = PD_COMP_FLAG_NON;
226 break;
227 }
228 break;
229 case PD_TYPES_2_3_3_2:
230 switch (step) {
231 case 2:
232 flag = PD_COMP_FLAG_NON;
233 break;
234 }
235 break;
236 case PD_TYPES_3_2_2_3:
237 switch (step) {
238 case 1:
239 case 2:
240 flag = PD_COMP_FLAG_CN;
241 break;
242 case 3:
243 flag = PD_COMP_FLAG_NON;
244 break;
245 }
246 break;
247 default:
248 mpp_log("unsupport telecine format %s\n",
249 pd_titles[(int)pd_inf->pdtype]);
250 return -1;
251 }
252
253 iep_dbg_trace("-------------------------------------------------\n");
254 iep_dbg_trace("step %d, idx %d, flag %s\n",
255 pd_inf->step, pd_inf->i, PD_COMP_STRING[flag]);
256
257 return flag;
258 }
259