xref: /rockchip-linux_mpp/mpp/vproc/iep2/iep2_pd.c (revision 437bfbeb9567cca9cd9080e3f6954aa9d6a94f18)
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