FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libpostproc/postprocess.c
Date: 2024-05-04 02:01:39
Exec Total Coverage
Lines: 390 455 85.7%
Functions: 18 19 94.7%
Branches: 189 266 71.1%

Line Branch Exec Source
1 /*
2 * Copyright (C) 2001-2003 Michael Niedermayer (michaelni@gmx.at)
3 *
4 * AltiVec optimizations (C) 2004 Romain Dolbeau <romain@dolbeau.org>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /**
24 * @file
25 * postprocessing.
26 */
27
28 /*
29 C MMX MMX2 AltiVec
30 isVertDC Ec Ec Ec
31 isVertMinMaxOk Ec Ec Ec
32 doVertLowPass E e Ec
33 doVertDefFilter Ec Ec e Ec
34 isHorizDC Ec Ec Ec
35 isHorizMinMaxOk a E Ec
36 doHorizLowPass E e Ec
37 doHorizDefFilter Ec Ec e Ec
38 do_a_deblock Ec E Ec
39 deRing E e Ecp
40 Vertical RKAlgo1 E a
41 Horizontal RKAlgo1 a
42 Vertical X1# a E
43 Horizontal X1# a E
44 LinIpolDeinterlace e E
45 CubicIpolDeinterlace a e
46 LinBlendDeinterlace e E
47 MedianDeinterlace# E Ec Ec
48 TempDeNoiser# E e Ec
49
50 # more or less selfinvented filters so the exactness is not too meaningful
51 E = Exact implementation
52 e = almost exact implementation (slightly different rounding,...)
53 a = alternative / approximate impl
54 c = checked against the other implementations (-vo md5)
55 p = partially optimized, still some work to do
56 */
57
58 /*
59 TODO:
60 reduce the time wasted on the mem transfer
61 unroll stuff if instructions depend too much on the prior one
62 move YScale thing to the end instead of fixing QP
63 write a faster and higher quality deblocking filter :)
64 make the mainloop more flexible (variable number of blocks at once
65 (the if/else stuff per block is slowing things down)
66 compare the quality & speed of all filters
67 split this huge file
68 optimize c versions
69 try to unroll inner for(x=0 ... loop to avoid these damn if(x ... checks
70 ...
71 */
72
73 //Changelog: use git log
74
75 #include <stddef.h>
76 #include <stdlib.h>
77 #include <string.h>
78
79 #include "config.h"
80 #include "libavutil/common.h"
81 #include "libavutil/cpu.h"
82 #include "libavutil/intreadwrite.h"
83 #include "libavutil/mem.h"
84 //#undef HAVE_MMXEXT_INLINE
85 //#undef HAVE_MMX_INLINE
86 //#undef ARCH_X86
87 //#define DEBUG_BRIGHTNESS
88 #include "postprocess.h"
89 #include "postprocess_internal.h"
90 #include "libavutil/avstring.h"
91
92 #define GET_MODE_BUFFER_SIZE 500
93 #define OPTIONS_ARRAY_SIZE 10
94 #define BLOCK_SIZE 8
95 #define TEMP_STRIDE 8
96 //#define NUM_BLOCKS_AT_ONCE 16 //not used yet
97
98 #if ARCH_X86 && HAVE_INLINE_ASM
99 DECLARE_ASM_CONST(8, uint64_t, w05)= 0x0005000500050005LL;
100 DECLARE_ASM_CONST(8, uint64_t, w04)= 0x0004000400040004LL;
101 DECLARE_ASM_CONST(8, uint64_t, w20)= 0x0020002000200020LL;
102 DECLARE_ASM_CONST(8, uint64_t, b00)= 0x0000000000000000LL;
103 DECLARE_ASM_CONST(8, uint64_t, b01)= 0x0101010101010101LL;
104 DECLARE_ASM_CONST(8, uint64_t, b02)= 0x0202020202020202LL;
105 DECLARE_ASM_CONST(8, uint64_t, b08)= 0x0808080808080808LL;
106 DECLARE_ASM_CONST(8, uint64_t, b80)= 0x8080808080808080LL;
107 #endif
108
109 DECLARE_ASM_CONST(8, int, deringThreshold)= 20;
110
111
112 static const struct PPFilter filters[]=
113 {
114 {"hb", "hdeblock", 1, 1, 3, H_DEBLOCK},
115 {"vb", "vdeblock", 1, 2, 4, V_DEBLOCK},
116 /* {"hr", "rkhdeblock", 1, 1, 3, H_RK1_FILTER},
117 {"vr", "rkvdeblock", 1, 2, 4, V_RK1_FILTER},*/
118 {"h1", "x1hdeblock", 1, 1, 3, H_X1_FILTER},
119 {"v1", "x1vdeblock", 1, 2, 4, V_X1_FILTER},
120 {"ha", "ahdeblock", 1, 1, 3, H_A_DEBLOCK},
121 {"va", "avdeblock", 1, 2, 4, V_A_DEBLOCK},
122 {"dr", "dering", 1, 5, 6, DERING},
123 {"al", "autolevels", 0, 1, 2, LEVEL_FIX},
124 {"lb", "linblenddeint", 1, 1, 4, LINEAR_BLEND_DEINT_FILTER},
125 {"li", "linipoldeint", 1, 1, 4, LINEAR_IPOL_DEINT_FILTER},
126 {"ci", "cubicipoldeint", 1, 1, 4, CUBIC_IPOL_DEINT_FILTER},
127 {"md", "mediandeint", 1, 1, 4, MEDIAN_DEINT_FILTER},
128 {"fd", "ffmpegdeint", 1, 1, 4, FFMPEG_DEINT_FILTER},
129 {"l5", "lowpass5", 1, 1, 4, LOWPASS5_DEINT_FILTER},
130 {"tn", "tmpnoise", 1, 7, 8, TEMP_NOISE_FILTER},
131 {"fq", "forcequant", 1, 0, 0, FORCE_QUANT},
132 {"be", "bitexact", 1, 0, 0, BITEXACT},
133 {"vi", "visualize", 1, 0, 0, VISUALIZE},
134 {NULL, NULL,0,0,0,0} //End Marker
135 };
136
137 static const char * const replaceTable[]=
138 {
139 "default", "hb:a,vb:a,dr:a",
140 "de", "hb:a,vb:a,dr:a",
141 "fast", "h1:a,v1:a,dr:a",
142 "fa", "h1:a,v1:a,dr:a",
143 "ac", "ha:a:128:7,va:a,dr:a",
144 NULL //End Marker
145 };
146
147 /* The horizontal functions exist only in C because the MMX
148 * code is faster with vertical filters and transposing. */
149
150 /**
151 * Check if the given 8x8 Block is mostly "flat"
152 */
153 34560 static inline int isHorizDC_C(const uint8_t src[], int stride, const PPContext *c)
154 {
155 34560 int numEq= 0;
156 int y;
157 34560 const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
158 34560 const int dcThreshold= dcOffset*2 + 1;
159
160
2/2
✓ Branch 0 taken 276480 times.
✓ Branch 1 taken 34560 times.
311040 for(y=0; y<BLOCK_SIZE; y++){
161 276480 numEq += ((unsigned)(src[0] - src[1] + dcOffset)) < dcThreshold;
162 276480 numEq += ((unsigned)(src[1] - src[2] + dcOffset)) < dcThreshold;
163 276480 numEq += ((unsigned)(src[2] - src[3] + dcOffset)) < dcThreshold;
164 276480 numEq += ((unsigned)(src[3] - src[4] + dcOffset)) < dcThreshold;
165 276480 numEq += ((unsigned)(src[4] - src[5] + dcOffset)) < dcThreshold;
166 276480 numEq += ((unsigned)(src[5] - src[6] + dcOffset)) < dcThreshold;
167 276480 numEq += ((unsigned)(src[6] - src[7] + dcOffset)) < dcThreshold;
168 276480 src+= stride;
169 }
170 34560 return numEq > c->ppMode.flatnessThreshold;
171 }
172
173 /**
174 * Check if the middle 8x8 Block in the given 8x16 block is flat
175 */
176 34320 static inline int isVertDC_C(const uint8_t src[], int stride, const PPContext *c)
177 {
178 34320 int numEq= 0;
179 int y;
180 34320 const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
181 34320 const int dcThreshold= dcOffset*2 + 1;
182
183 34320 src+= stride*4; // src points to begin of the 8x8 Block
184
2/2
✓ Branch 0 taken 240240 times.
✓ Branch 1 taken 34320 times.
274560 for(y=0; y<BLOCK_SIZE-1; y++){
185 240240 numEq += ((unsigned)(src[0] - src[0+stride] + dcOffset)) < dcThreshold;
186 240240 numEq += ((unsigned)(src[1] - src[1+stride] + dcOffset)) < dcThreshold;
187 240240 numEq += ((unsigned)(src[2] - src[2+stride] + dcOffset)) < dcThreshold;
188 240240 numEq += ((unsigned)(src[3] - src[3+stride] + dcOffset)) < dcThreshold;
189 240240 numEq += ((unsigned)(src[4] - src[4+stride] + dcOffset)) < dcThreshold;
190 240240 numEq += ((unsigned)(src[5] - src[5+stride] + dcOffset)) < dcThreshold;
191 240240 numEq += ((unsigned)(src[6] - src[6+stride] + dcOffset)) < dcThreshold;
192 240240 numEq += ((unsigned)(src[7] - src[7+stride] + dcOffset)) < dcThreshold;
193 240240 src+= stride;
194 }
195 34320 return numEq > c->ppMode.flatnessThreshold;
196 }
197
198 701 static inline int isHorizMinMaxOk_C(const uint8_t src[], int stride, int QP)
199 {
200 int i;
201
2/2
✓ Branch 0 taken 1020 times.
✓ Branch 1 taken 129 times.
1149 for(i=0; i<2; i++){
202
2/2
✓ Branch 0 taken 368 times.
✓ Branch 1 taken 652 times.
1020 if((unsigned)(src[0] - src[5] + 2*QP) > 4*QP) return 0;
203 652 src += stride;
204
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 510 times.
652 if((unsigned)(src[2] - src[7] + 2*QP) > 4*QP) return 0;
205 510 src += stride;
206
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 508 times.
510 if((unsigned)(src[4] - src[1] + 2*QP) > 4*QP) return 0;
207 508 src += stride;
208
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 448 times.
508 if((unsigned)(src[6] - src[3] + 2*QP) > 4*QP) return 0;
209 448 src += stride;
210 }
211 129 return 1;
212 }
213
214 352 static inline int isVertMinMaxOk_C(const uint8_t src[], int stride, int QP)
215 {
216 int x;
217 352 src+= stride*4;
218
2/2
✓ Branch 0 taken 526 times.
✓ Branch 1 taken 85 times.
611 for(x=0; x<BLOCK_SIZE; x+=4){
219
2/2
✓ Branch 0 taken 177 times.
✓ Branch 1 taken 349 times.
526 if((unsigned)(src[ x + 0*stride] - src[ x + 5*stride] + 2*QP) > 4*QP) return 0;
220
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 291 times.
349 if((unsigned)(src[1+x + 2*stride] - src[1+x + 7*stride] + 2*QP) > 4*QP) return 0;
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 291 times.
291 if((unsigned)(src[2+x + 4*stride] - src[2+x + 1*stride] + 2*QP) > 4*QP) return 0;
222
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 259 times.
291 if((unsigned)(src[3+x + 6*stride] - src[3+x + 3*stride] + 2*QP) > 4*QP) return 0;
223 }
224 85 return 1;
225 }
226
227 34560 static inline int horizClassify_C(const uint8_t src[], int stride, const PPContext *c)
228 {
229
2/2
✓ Branch 1 taken 701 times.
✓ Branch 2 taken 33859 times.
34560 if( isHorizDC_C(src, stride, c) ){
230 701 return isHorizMinMaxOk_C(src, stride, c->QP);
231 }else{
232 33859 return 2;
233 }
234 }
235
236 34320 static inline int vertClassify_C(const uint8_t src[], int stride, const PPContext *c)
237 {
238
2/2
✓ Branch 1 taken 352 times.
✓ Branch 2 taken 33968 times.
34320 if( isVertDC_C(src, stride, c) ){
239 352 return isVertMinMaxOk_C(src, stride, c->QP);
240 }else{
241 33968 return 2;
242 }
243 }
244
245 33859 static inline void doHorizDefFilter_C(uint8_t dst[], int stride, const PPContext *c)
246 {
247 int y;
248
2/2
✓ Branch 0 taken 270872 times.
✓ Branch 1 taken 33859 times.
304731 for(y=0; y<BLOCK_SIZE; y++){
249 270872 const int middleEnergy= 5*(dst[4] - dst[3]) + 2*(dst[2] - dst[5]);
250
251
2/2
✓ Branch 0 taken 183772 times.
✓ Branch 1 taken 87100 times.
270872 if(FFABS(middleEnergy) < 8*c->QP){
252 183772 const int q=(dst[3] - dst[4])/2;
253 183772 const int leftEnergy= 5*(dst[2] - dst[1]) + 2*(dst[0] - dst[3]);
254 183772 const int rightEnergy= 5*(dst[6] - dst[5]) + 2*(dst[4] - dst[7]);
255
256 183772 int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
257 183772 d= FFMAX(d, 0);
258
259 183772 d= (5*d + 32) >> 6;
260
2/2
✓ Branch 0 taken 118280 times.
✓ Branch 1 taken 65492 times.
183772 d*= FFSIGN(-middleEnergy);
261
262
2/2
✓ Branch 0 taken 42478 times.
✓ Branch 1 taken 141294 times.
183772 if(q>0)
263 {
264 42478 d = FFMAX(d, 0);
265 42478 d = FFMIN(d, q);
266 }
267 else
268 {
269 141294 d = FFMIN(d, 0);
270 141294 d = FFMAX(d, q);
271 }
272
273 183772 dst[3]-= d;
274 183772 dst[4]+= d;
275 }
276 270872 dst+= stride;
277 }
278 33859 }
279
280 /**
281 * Do a horizontal low pass filter on the 10x8 block (dst points to middle 8x8 Block)
282 * using the 9-Tap Filter (1,1,2,2,4,2,2,1,1)/16 (C version)
283 */
284 129 static inline void doHorizLowPass_C(uint8_t dst[], int stride, const PPContext *c)
285 {
286 int y;
287
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 129 times.
1161 for(y=0; y<BLOCK_SIZE; y++){
288
2/2
✓ Branch 0 taken 855 times.
✓ Branch 1 taken 177 times.
1032 const int first= FFABS(dst[-1] - dst[0]) < c->QP ? dst[-1] : dst[0];
289
2/2
✓ Branch 0 taken 828 times.
✓ Branch 1 taken 204 times.
1032 const int last= FFABS(dst[8] - dst[7]) < c->QP ? dst[8] : dst[7];
290
291 int sums[10];
292 1032 sums[0] = 4*first + dst[0] + dst[1] + dst[2] + 4;
293 1032 sums[1] = sums[0] - first + dst[3];
294 1032 sums[2] = sums[1] - first + dst[4];
295 1032 sums[3] = sums[2] - first + dst[5];
296 1032 sums[4] = sums[3] - first + dst[6];
297 1032 sums[5] = sums[4] - dst[0] + dst[7];
298 1032 sums[6] = sums[5] - dst[1] + last;
299 1032 sums[7] = sums[6] - dst[2] + last;
300 1032 sums[8] = sums[7] - dst[3] + last;
301 1032 sums[9] = sums[8] - dst[4] + last;
302
303 1032 dst[0]= (sums[0] + sums[2] + 2*dst[0])>>4;
304 1032 dst[1]= (sums[1] + sums[3] + 2*dst[1])>>4;
305 1032 dst[2]= (sums[2] + sums[4] + 2*dst[2])>>4;
306 1032 dst[3]= (sums[3] + sums[5] + 2*dst[3])>>4;
307 1032 dst[4]= (sums[4] + sums[6] + 2*dst[4])>>4;
308 1032 dst[5]= (sums[5] + sums[7] + 2*dst[5])>>4;
309 1032 dst[6]= (sums[6] + sums[8] + 2*dst[6])>>4;
310 1032 dst[7]= (sums[7] + sums[9] + 2*dst[7])>>4;
311
312 1032 dst+= stride;
313 }
314 129 }
315
316 /**
317 * Experimental Filter 1 (Horizontal)
318 * will not damage linear gradients
319 * Flat blocks should look like they were passed through the (1,1,2,2,4,2,2,1,1) 9-Tap filter
320 * can only smooth blocks at the expected locations (it cannot smooth them if they did move)
321 * MMX2 version does correct clipping C version does not
322 * not identical with the vertical one
323 */
324 11520 static inline void horizX1Filter(uint8_t *src, int stride, int QP)
325 {
326 int y;
327 static uint64_t lut[256];
328
1/2
✓ Branch 0 taken 11520 times.
✗ Branch 1 not taken.
11520 if(!lut[255])
329 {
330 int i;
331
2/2
✓ Branch 0 taken 2949120 times.
✓ Branch 1 taken 11520 times.
2960640 for(i=0; i<256; i++)
332 {
333
2/2
✓ Branch 0 taken 1474560 times.
✓ Branch 1 taken 1474560 times.
2949120 int v= i < 128 ? 2*i : 2*(i-256);
334 /*
335 //Simulate 112242211 9-Tap filter
336 uint64_t a= (v/16) & 0xFF;
337 uint64_t b= (v/8) & 0xFF;
338 uint64_t c= (v/4) & 0xFF;
339 uint64_t d= (3*v/8) & 0xFF;
340 */
341 //Simulate piecewise linear interpolation
342 2949120 uint64_t a= (v/16) & 0xFF;
343 2949120 uint64_t b= (v*3/16) & 0xFF;
344 2949120 uint64_t c= (v*5/16) & 0xFF;
345 2949120 uint64_t d= (7*v/16) & 0xFF;
346 2949120 uint64_t A= (0x100 - a)&0xFF;
347 2949120 uint64_t B= (0x100 - b)&0xFF;
348 2949120 uint64_t C= (0x100 - c)&0xFF;
349 2949120 uint64_t D= (0x100 - c)&0xFF;
350
351 2949120 lut[i] = (a<<56) | (b<<48) | (c<<40) | (d<<32) |
352 2949120 (D<<24) | (C<<16) | (B<<8) | (A);
353 //lut[i] = (v<<32) | (v<<24);
354 }
355 }
356
357
2/2
✓ Branch 0 taken 92160 times.
✓ Branch 1 taken 11520 times.
103680 for(y=0; y<BLOCK_SIZE; y++){
358 92160 int a= src[1] - src[2];
359 92160 int b= src[3] - src[4];
360 92160 int c= src[5] - src[6];
361
362 92160 int d= FFMAX(FFABS(b) - (FFABS(a) + FFABS(c))/2, 0);
363
364
2/2
✓ Branch 0 taken 84620 times.
✓ Branch 1 taken 7540 times.
92160 if(d < QP){
365
2/2
✓ Branch 0 taken 56059 times.
✓ Branch 1 taken 28561 times.
84620 int v = d * FFSIGN(-b);
366
367 84620 src[1] +=v/8;
368 84620 src[2] +=v/4;
369 84620 src[3] +=3*v/8;
370 84620 src[4] -=3*v/8;
371 84620 src[5] -=v/4;
372 84620 src[6] -=v/8;
373 }
374 92160 src+=stride;
375 }
376 11520 }
377
378 /**
379 * accurate deblock filter
380 */
381 22960 static av_always_inline void do_a_deblock_C(uint8_t *src, int step,
382 int stride, const PPContext *c, int mode)
383 {
384 int y;
385 22960 const int QP= c->QP;
386 22960 const int dcOffset= ((c->nonBQP*c->ppMode.baseDcDiff)>>8) + 1;
387 22960 const int dcThreshold= dcOffset*2 + 1;
388
389 22960 src+= step*4; // src points to begin of the 8x8 Block
390
2/2
✓ Branch 0 taken 183680 times.
✓ Branch 1 taken 22960 times.
206640 for(y=0; y<8; y++){
391 183680 int numEq= 0;
392
393 183680 numEq += ((unsigned)(src[-1*step] - src[0*step] + dcOffset)) < dcThreshold;
394 183680 numEq += ((unsigned)(src[ 0*step] - src[1*step] + dcOffset)) < dcThreshold;
395 183680 numEq += ((unsigned)(src[ 1*step] - src[2*step] + dcOffset)) < dcThreshold;
396 183680 numEq += ((unsigned)(src[ 2*step] - src[3*step] + dcOffset)) < dcThreshold;
397 183680 numEq += ((unsigned)(src[ 3*step] - src[4*step] + dcOffset)) < dcThreshold;
398 183680 numEq += ((unsigned)(src[ 4*step] - src[5*step] + dcOffset)) < dcThreshold;
399 183680 numEq += ((unsigned)(src[ 5*step] - src[6*step] + dcOffset)) < dcThreshold;
400 183680 numEq += ((unsigned)(src[ 6*step] - src[7*step] + dcOffset)) < dcThreshold;
401 183680 numEq += ((unsigned)(src[ 7*step] - src[8*step] + dcOffset)) < dcThreshold;
402
2/2
✓ Branch 0 taken 82036 times.
✓ Branch 1 taken 101644 times.
183680 if(numEq > c->ppMode.flatnessThreshold){
403 int min, max, x;
404
405
2/2
✓ Branch 0 taken 17783 times.
✓ Branch 1 taken 64253 times.
82036 if(src[0] > src[step]){
406 17783 max= src[0];
407 17783 min= src[step];
408 }else{
409 64253 max= src[step];
410 64253 min= src[0];
411 }
412
2/2
✓ Branch 0 taken 246108 times.
✓ Branch 1 taken 82036 times.
328144 for(x=2; x<8; x+=2){
413
2/2
✓ Branch 0 taken 53874 times.
✓ Branch 1 taken 192234 times.
246108 if(src[x*step] > src[(x+1)*step]){
414
2/2
✓ Branch 0 taken 14943 times.
✓ Branch 1 taken 38931 times.
53874 if(src[x *step] > max) max= src[ x *step];
415
2/2
✓ Branch 0 taken 34856 times.
✓ Branch 1 taken 19018 times.
53874 if(src[(x+1)*step] < min) min= src[(x+1)*step];
416 }else{
417
2/2
✓ Branch 0 taken 152013 times.
✓ Branch 1 taken 40221 times.
192234 if(src[(x+1)*step] > max) max= src[(x+1)*step];
418
2/2
✓ Branch 0 taken 21617 times.
✓ Branch 1 taken 170617 times.
192234 if(src[ x *step] < min) min= src[ x *step];
419 }
420 }
421
2/2
✓ Branch 0 taken 42585 times.
✓ Branch 1 taken 39451 times.
82036 if(max-min < 2*QP){
422
2/2
✓ Branch 0 taken 38883 times.
✓ Branch 1 taken 3702 times.
42585 const int first= FFABS(src[-1*step] - src[0]) < QP ? src[-1*step] : src[0];
423
2/2
✓ Branch 0 taken 41154 times.
✓ Branch 1 taken 1431 times.
42585 const int last= FFABS(src[8*step] - src[7*step]) < QP ? src[8*step] : src[7*step];
424
425 int sums[10];
426 42585 sums[0] = 4*first + src[0*step] + src[1*step] + src[2*step] + 4;
427 42585 sums[1] = sums[0] - first + src[3*step];
428 42585 sums[2] = sums[1] - first + src[4*step];
429 42585 sums[3] = sums[2] - first + src[5*step];
430 42585 sums[4] = sums[3] - first + src[6*step];
431 42585 sums[5] = sums[4] - src[0*step] + src[7*step];
432 42585 sums[6] = sums[5] - src[1*step] + last;
433 42585 sums[7] = sums[6] - src[2*step] + last;
434 42585 sums[8] = sums[7] - src[3*step] + last;
435 42585 sums[9] = sums[8] - src[4*step] + last;
436
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42585 times.
42585 if (mode & VISUALIZE) {
438 src[0*step] =
439 src[1*step] =
440 src[2*step] =
441 src[3*step] =
442 src[4*step] =
443 src[5*step] =
444 src[6*step] =
445 src[7*step] = 128;
446 }
447 42585 src[0*step]= (sums[0] + sums[2] + 2*src[0*step])>>4;
448 42585 src[1*step]= (sums[1] + sums[3] + 2*src[1*step])>>4;
449 42585 src[2*step]= (sums[2] + sums[4] + 2*src[2*step])>>4;
450 42585 src[3*step]= (sums[3] + sums[5] + 2*src[3*step])>>4;
451 42585 src[4*step]= (sums[4] + sums[6] + 2*src[4*step])>>4;
452 42585 src[5*step]= (sums[5] + sums[7] + 2*src[5*step])>>4;
453 42585 src[6*step]= (sums[6] + sums[8] + 2*src[6*step])>>4;
454 42585 src[7*step]= (sums[7] + sums[9] + 2*src[7*step])>>4;
455 }
456 }else{
457 101644 const int middleEnergy= 5*(src[4*step] - src[3*step]) + 2*(src[2*step] - src[5*step]);
458
459
2/2
✓ Branch 0 taken 86530 times.
✓ Branch 1 taken 15114 times.
101644 if(FFABS(middleEnergy) < 8*QP){
460 86530 const int q=(src[3*step] - src[4*step])/2;
461 86530 const int leftEnergy= 5*(src[2*step] - src[1*step]) + 2*(src[0*step] - src[3*step]);
462 86530 const int rightEnergy= 5*(src[6*step] - src[5*step]) + 2*(src[4*step] - src[7*step]);
463
464 86530 int d= FFABS(middleEnergy) - FFMIN( FFABS(leftEnergy), FFABS(rightEnergy) );
465 86530 d= FFMAX(d, 0);
466
467 86530 d= (5*d + 32) >> 6;
468
2/2
✓ Branch 0 taken 54380 times.
✓ Branch 1 taken 32150 times.
86530 d*= FFSIGN(-middleEnergy);
469
470
2/2
✓ Branch 0 taken 27119 times.
✓ Branch 1 taken 59411 times.
86530 if(q>0){
471 27119 d = FFMAX(d, 0);
472 27119 d = FFMIN(d, q);
473 }else{
474 59411 d = FFMIN(d, 0);
475 59411 d = FFMAX(d, q);
476 }
477
478
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 86530 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
86530 if ((mode & VISUALIZE) && d) {
479 d= (d < 0) ? 32 : -32;
480 src[3*step]= av_clip_uint8(src[3*step] - d);
481 src[4*step]= av_clip_uint8(src[4*step] + d);
482 d = 0;
483 }
484
485 86530 src[3*step]-= d;
486 86530 src[4*step]+= d;
487 }
488 }
489
490 183680 src += stride;
491 }
492 22960 }
493
494 //Note: we have C and SSE2 version (which uses MMX(EXT) when advantageous)
495 //Plain C versions
496 //we always compile C for testing which needs bitexactness
497 #define TEMPLATE_PP_C 1
498 #include "postprocess_template.c"
499
500 #if HAVE_ALTIVEC
501 #include "libavutil/ppc/util_altivec.h"
502
503 # define TEMPLATE_PP_ALTIVEC 1
504 # include "postprocess_altivec_template.c"
505 # include "postprocess_template.c"
506 #endif
507
508 #if ARCH_X86 && HAVE_INLINE_ASM
509 # if CONFIG_RUNTIME_CPUDETECT
510 # define TEMPLATE_PP_SSE2 1
511 # include "postprocess_template.c"
512 # else
513 # if HAVE_SSE2_INLINE
514 # define TEMPLATE_PP_SSE2 1
515 # include "postprocess_template.c"
516 # endif
517 # endif
518 #endif
519
520 typedef void (*pp_fn)(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
521 const int8_t QPs[], int QPStride, int isColor, PPContext *c2);
522
523 120 static inline void postProcess(const uint8_t src[], int srcStride, uint8_t dst[], int dstStride, int width, int height,
524 const int8_t QPs[], int QPStride, int isColor, pp_mode *vm, pp_context *vc)
525 {
526 120 pp_fn pp = postProcess_C;
527 120 PPContext *c= (PPContext *)vc;
528 120 PPMode *ppMode= (PPMode *)vm;
529 120 c->ppMode= *ppMode; //FIXME
530
531
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 105 times.
120 if (!(ppMode->lumMode & BITEXACT)) {
532 #if CONFIG_RUNTIME_CPUDETECT
533 #if ARCH_X86 && HAVE_INLINE_ASM
534 // ordered per speed fastest first
535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (c->cpuCaps & AV_CPU_FLAG_SSE2) pp = postProcess_SSE2;
536 #elif HAVE_ALTIVEC
537 if (c->cpuCaps & AV_CPU_FLAG_ALTIVEC) pp = postProcess_altivec;
538 #endif
539 #else /* CONFIG_RUNTIME_CPUDETECT */
540 #if HAVE_SSE2_INLINE
541 pp = postProcess_SSE2;
542 #elif HAVE_ALTIVEC
543 pp = postProcess_altivec;
544 #endif
545 #endif /* !CONFIG_RUNTIME_CPUDETECT */
546 }
547
548 120 pp(src, srcStride, dst, dstStride, width, height, QPs, QPStride, isColor, c);
549 120 }
550
551 /* -pp Command line Help
552 */
553 const char pp_help[] =
554 "Available postprocessing filters:\n"
555 "Filters Options\n"
556 "short long name short long option Description\n"
557 "* * a autoq CPU power dependent enabler\n"
558 " c chrom chrominance filtering enabled\n"
559 " y nochrom chrominance filtering disabled\n"
560 " n noluma luma filtering disabled\n"
561 "hb hdeblock (2 threshold) horizontal deblocking filter\n"
562 " 1. difference factor: default=32, higher -> more deblocking\n"
563 " 2. flatness threshold: default=39, lower -> more deblocking\n"
564 " the h & v deblocking filters share these\n"
565 " so you can't set different thresholds for h / v\n"
566 "vb vdeblock (2 threshold) vertical deblocking filter\n"
567 "ha hadeblock (2 threshold) horizontal deblocking filter\n"
568 "va vadeblock (2 threshold) vertical deblocking filter\n"
569 "h1 x1hdeblock experimental h deblock filter 1\n"
570 "v1 x1vdeblock experimental v deblock filter 1\n"
571 "dr dering deringing filter\n"
572 "al autolevels automatic brightness / contrast\n"
573 " f fullyrange stretch luminance to (0..255)\n"
574 "lb linblenddeint linear blend deinterlacer\n"
575 "li linipoldeint linear interpolating deinterlace\n"
576 "ci cubicipoldeint cubic interpolating deinterlacer\n"
577 "md mediandeint median deinterlacer\n"
578 "fd ffmpegdeint ffmpeg deinterlacer\n"
579 "l5 lowpass5 FIR lowpass deinterlacer\n"
580 "de default hb:a,vb:a,dr:a\n"
581 "fa fast h1:a,v1:a,dr:a\n"
582 "ac ha:a:128:7,va:a,dr:a\n"
583 "tn tmpnoise (3 threshold) temporal noise reducer\n"
584 " 1. <= 2. <= 3. larger -> stronger filtering\n"
585 "fq forceQuant <quantizer> force quantizer\n"
586 "Usage:\n"
587 "<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n"
588 "long form example:\n"
589 "vdeblock:autoq/hdeblock:autoq/linblenddeint default,-vdeblock\n"
590 "short form example:\n"
591 "vb:a/hb:a/lb de,-vb\n"
592 "more examples:\n"
593 "tn:64:128:256\n"
594 "\n"
595 ;
596
597 112 pp_mode *pp_get_mode_by_name_and_quality(const char *name, int quality)
598 {
599 char temp[GET_MODE_BUFFER_SIZE];
600 112 char *p= temp;
601 static const char filterDelimiters[] = ",/";
602 static const char optionDelimiters[] = ":|";
603 struct PPMode *ppMode;
604 char *filterToken;
605
606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (!name) {
607 av_log(NULL, AV_LOG_ERROR, "pp: Missing argument\n");
608 return NULL;
609 }
610
611
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (!strcmp(name, "help")) {
612 const char *p;
613 for (p = pp_help; strchr(p, '\n'); p = strchr(p, '\n') + 1) {
614 av_strlcpy(temp, p, FFMIN(sizeof(temp), strchr(p, '\n') - p + 2));
615 av_log(NULL, AV_LOG_INFO, "%s", temp);
616 }
617 return NULL;
618 }
619
620 112 ppMode= av_malloc(sizeof(PPMode));
621
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (!ppMode)
622 return NULL;
623
624 112 ppMode->lumMode= 0;
625 112 ppMode->chromMode= 0;
626 112 ppMode->maxTmpNoise[0]= 700;
627 112 ppMode->maxTmpNoise[1]= 1500;
628 112 ppMode->maxTmpNoise[2]= 3000;
629 112 ppMode->maxAllowedY= 234;
630 112 ppMode->minAllowedY= 16;
631 112 ppMode->baseDcDiff= 256/8;
632 112 ppMode->flatnessThreshold= 56-16-1;
633 112 ppMode->maxClippedThreshold= (AVRational){1,100};
634 112 ppMode->error=0;
635
636 112 memset(temp, 0, GET_MODE_BUFFER_SIZE);
637 112 av_strlcpy(temp, name, GET_MODE_BUFFER_SIZE - 1);
638
639 112 av_log(NULL, AV_LOG_DEBUG, "pp: %s\n", name);
640
641 448 for(;;){
642 const char *filterName;
643 560 int q= 1000000; //PP_QUALITY_MAX;
644 560 int chrom=-1;
645 560 int luma=-1;
646 const char *option;
647 const char *options[OPTIONS_ARRAY_SIZE];
648 int i;
649 560 int filterNameOk=0;
650 560 int numOfUnknownOptions=0;
651 560 int enable=1; //does the user want us to enabled or disabled the filter
652 char *tokstate;
653
654 560 filterToken= av_strtok(p, filterDelimiters, &tokstate);
655
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 448 times.
560 if(!filterToken) break;
656 448 p+= strlen(filterToken) + 1; // p points to next filterToken
657 448 filterName= av_strtok(filterToken, optionDelimiters, &tokstate);
658
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 448 times.
448 if (!filterName) {
659 ppMode->error++;
660 break;
661 }
662 448 av_log(NULL, AV_LOG_DEBUG, "pp: %s::%s\n", filterToken, filterName);
663
664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 448 times.
448 if(*filterName == '-'){
665 enable=0;
666 filterName++;
667 }
668
669 for(;;){ //for all options
670 490 option= av_strtok(NULL, optionDelimiters, &tokstate);
671
2/2
✓ Branch 0 taken 448 times.
✓ Branch 1 taken 42 times.
490 if(!option) break;
672
673 42 av_log(NULL, AV_LOG_DEBUG, "pp: option: %s\n", option);
674
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
42 if(!strcmp("autoq", option) || !strcmp("a", option)) q= quality;
675
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
42 else if(!strcmp("nochrom", option) || !strcmp("y", option)) chrom=0;
676
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
42 else if(!strcmp("chrom", option) || !strcmp("c", option)) chrom=1;
677
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
42 else if(!strcmp("noluma", option) || !strcmp("n", option)) luma=0;
678 else{
679 42 options[numOfUnknownOptions] = option;
680 42 numOfUnknownOptions++;
681 }
682
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if(numOfUnknownOptions >= OPTIONS_ARRAY_SIZE-1) break;
683 }
684 448 options[numOfUnknownOptions] = NULL;
685
686 /* replace stuff from the replace Table */
687
2/2
✓ Branch 0 taken 2240 times.
✓ Branch 1 taken 448 times.
2688 for(i=0; replaceTable[2*i]; i++){
688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2240 times.
2240 if(!strcmp(replaceTable[2*i], filterName)){
689 size_t newlen = strlen(replaceTable[2*i + 1]);
690 int plen;
691 int spaceLeft;
692
693 p--, *p=',';
694
695 plen= strlen(p);
696 spaceLeft= p - temp + plen;
697 if(spaceLeft + newlen >= GET_MODE_BUFFER_SIZE - 1){
698 ppMode->error++;
699 break;
700 }
701 memmove(p + newlen, p, plen+1);
702 memcpy(p, replaceTable[2*i + 1], newlen);
703 filterNameOk=1;
704 }
705 }
706
707
2/2
✓ Branch 0 taken 8064 times.
✓ Branch 1 taken 448 times.
8512 for(i=0; filters[i].shortName; i++){
708
1/2
✓ Branch 0 taken 8064 times.
✗ Branch 1 not taken.
8064 if( !strcmp(filters[i].longName, filterName)
709
2/2
✓ Branch 0 taken 448 times.
✓ Branch 1 taken 7616 times.
8064 || !strcmp(filters[i].shortName, filterName)){
710 448 ppMode->lumMode &= ~filters[i].mask;
711 448 ppMode->chromMode &= ~filters[i].mask;
712
713 448 filterNameOk=1;
714
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 448 times.
448 if(!enable) break; // user wants to disable it
715
716
2/4
✓ Branch 0 taken 448 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 448 times.
✗ Branch 3 not taken.
448 if(q >= filters[i].minLumQuality && luma)
717 448 ppMode->lumMode|= filters[i].mask;
718
4/6
✓ Branch 0 taken 448 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 448 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 406 times.
✓ Branch 5 taken 42 times.
448 if(chrom==1 || (chrom==-1 && filters[i].chromDefault))
719
1/2
✓ Branch 0 taken 406 times.
✗ Branch 1 not taken.
406 if(q >= filters[i].minChromQuality)
720 406 ppMode->chromMode|= filters[i].mask;
721
722
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 406 times.
448 if(filters[i].mask == LEVEL_FIX){
723 int o;
724 42 ppMode->minAllowedY= 16;
725 42 ppMode->maxAllowedY= 234;
726
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 for(o=0; options[o]; o++){
727 if( !strcmp(options[o],"fullyrange")
728 ||!strcmp(options[o],"f")){
729 ppMode->minAllowedY= 0;
730 ppMode->maxAllowedY= 255;
731 numOfUnknownOptions--;
732 }
733 }
734 }
735
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 364 times.
406 else if(filters[i].mask == TEMP_NOISE_FILTER)
736 {
737 int o;
738 42 int numOfNoises=0;
739
740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 for(o=0; options[o]; o++){
741 char *tail;
742 ppMode->maxTmpNoise[numOfNoises]=
743 strtol(options[o], &tail, 0);
744 if(tail!=options[o]){
745 numOfNoises++;
746 numOfUnknownOptions--;
747 if(numOfNoises >= 3) break;
748 }
749 }
750 }
751
4/4
✓ Branch 0 taken 322 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 280 times.
✓ Branch 3 taken 42 times.
364 else if(filters[i].mask == V_DEBLOCK || filters[i].mask == H_DEBLOCK
752
4/4
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 252 times.
392 || filters[i].mask == V_A_DEBLOCK || filters[i].mask == H_A_DEBLOCK){
753 int o;
754
755
3/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
140 for(o=0; options[o] && o<2; o++){
756 char *tail;
757 28 int val= strtol(options[o], &tail, 0);
758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if(tail==options[o]) break;
759
760 28 numOfUnknownOptions--;
761
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 if(o==0) ppMode->baseDcDiff= val;
762 14 else ppMode->flatnessThreshold= val;
763 }
764 }
765
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 238 times.
252 else if(filters[i].mask == FORCE_QUANT){
766 int o;
767 14 ppMode->forcedQuant= 15;
768
769
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
28 for(o=0; options[o] && o<1; o++){
770 char *tail;
771 14 int val= strtol(options[o], &tail, 0);
772
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if(tail==options[o]) break;
773
774 14 numOfUnknownOptions--;
775 14 ppMode->forcedQuant= val;
776 }
777 }
778 }
779 }
780
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 448 times.
448 if(!filterNameOk) ppMode->error++;
781 448 ppMode->error += numOfUnknownOptions;
782 }
783
784 112 av_log(NULL, AV_LOG_DEBUG, "pp: lumMode=%X, chromMode=%X\n", ppMode->lumMode, ppMode->chromMode);
785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if(ppMode->error){
786 av_log(NULL, AV_LOG_ERROR, "%d errors in postprocess string \"%s\"\n", ppMode->error, name);
787 av_free(ppMode);
788 return NULL;
789 }
790 112 return ppMode;
791 }
792
793 112 void pp_free_mode(pp_mode *mode){
794 112 av_free(mode);
795 112 }
796
797 224 static void reallocAlign(void **p, int size){
798 224 av_free(*p);
799 224 *p= av_mallocz(size);
800 224 }
801
802 16 static void reallocBuffers(PPContext *c, int width, int height, int stride, int qpStride){
803 16 int mbWidth = (width+15)>>4;
804 16 int mbHeight= (height+15)>>4;
805 int i;
806
807 16 c->stride= stride;
808 16 c->qpStride= qpStride;
809
810 16 reallocAlign((void **)&c->tempDst, stride*24+32);
811 16 reallocAlign((void **)&c->tempSrc, stride*24);
812 16 reallocAlign((void **)&c->tempBlocks, 2*16*8);
813 16 reallocAlign((void **)&c->yHistogram, 256*sizeof(uint64_t));
814
2/2
✓ Branch 0 taken 4096 times.
✓ Branch 1 taken 16 times.
4112 for(i=0; i<256; i++)
815 4096 c->yHistogram[i]= width*height/64*15/256;
816
817
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
64 for(i=0; i<3; i++){
818 //Note: The +17*1024 is just there so I do not have to worry about r/w over the end.
819 48 reallocAlign((void **)&c->tempBlurred[i], stride*mbHeight*16 + 17*1024);
820 48 reallocAlign((void **)&c->tempBlurredPast[i], 256*((height+7)&(~7))/2 + 17*1024);//FIXME size
821 }
822
823 16 reallocAlign((void **)&c->deintTemp, 2*width+32);
824 16 reallocAlign((void **)&c->nonBQPTable, qpStride*mbHeight*sizeof(int8_t));
825 16 reallocAlign((void **)&c->stdQPTable, qpStride*mbHeight*sizeof(int8_t));
826 16 reallocAlign((void **)&c->forcedQPTable, mbWidth*sizeof(int8_t));
827 16 }
828
829 static const char * context_to_name(void * ptr) {
830 return "postproc";
831 }
832
833 static const AVClass av_codec_context_class = { "Postproc", context_to_name, NULL };
834
835 8 av_cold pp_context *pp_get_context(int width, int height, int cpuCaps){
836 8 PPContext *c= av_mallocz(sizeof(PPContext));
837 8 int stride= FFALIGN(width, 16); //assumed / will realloc if needed
838 8 int qpStride= (width+15)/16 + 2; //assumed / will realloc if needed
839
840
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (!c)
841 return NULL;
842
843 8 c->av_class = &av_codec_context_class;
844
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if(cpuCaps&PP_FORMAT){
845 8 c->hChromaSubSample= cpuCaps&0x3;
846 8 c->vChromaSubSample= (cpuCaps>>4)&0x3;
847 }else{
848 c->hChromaSubSample= 1;
849 c->vChromaSubSample= 1;
850 }
851
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (cpuCaps & PP_CPU_CAPS_AUTO) {
852 8 c->cpuCaps = av_get_cpu_flags();
853 } else {
854 c->cpuCaps = 0;
855 if (cpuCaps & PP_CPU_CAPS_ALTIVEC) c->cpuCaps |= AV_CPU_FLAG_ALTIVEC;
856 }
857
858 8 reallocBuffers(c, width, height, stride, qpStride);
859
860 8 c->frameNum=-1;
861
862 8 return c;
863 }
864
865 8 av_cold void pp_free_context(void *vc){
866 8 PPContext *c = (PPContext*)vc;
867 int i;
868
869
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 for(i=0; i<FF_ARRAY_ELEMS(c->tempBlurred); i++)
870 24 av_free(c->tempBlurred[i]);
871
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
32 for(i=0; i<FF_ARRAY_ELEMS(c->tempBlurredPast); i++)
872 24 av_free(c->tempBlurredPast[i]);
873
874 8 av_free(c->tempBlocks);
875 8 av_free(c->yHistogram);
876 8 av_free(c->tempDst);
877 8 av_free(c->tempSrc);
878 8 av_free(c->deintTemp);
879 8 av_free(c->stdQPTable);
880 8 av_free(c->nonBQPTable);
881 8 av_free(c->forcedQPTable);
882
883 8 memset(c, 0, sizeof(PPContext));
884
885 8 av_free(c);
886 8 }
887
888 40 void pp_postprocess(const uint8_t * src[3], const int srcStride[3],
889 uint8_t * dst[3], const int dstStride[3],
890 int width, int height,
891 const int8_t *QP_store, int QPStride,
892 pp_mode *vm, void *vc, int pict_type)
893 {
894 40 int mbWidth = (width+15)>>4;
895 40 int mbHeight= (height+15)>>4;
896 40 PPMode *mode = vm;
897 40 PPContext *c = vc;
898 40 int minStride= FFMAX(FFABS(srcStride[0]), FFABS(dstStride[0]));
899 40 int absQPStride = FFABS(QPStride);
900
901 // c->stride and c->QPStride are always positive
902
3/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
40 if(c->stride < minStride || c->qpStride < absQPStride)
903 8 reallocBuffers(c, width, height,
904 8 FFMAX(minStride, c->stride),
905 8 FFMAX(c->qpStride, absQPStride));
906
907
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
40 if(!QP_store || (mode->lumMode & FORCE_QUANT)){
908 int i;
909 20 QP_store= c->forcedQPTable;
910 20 absQPStride = QPStride = 0;
911
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 15 times.
20 if(mode->lumMode & FORCE_QUANT)
912
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 5 times.
115 for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= mode->forcedQuant;
913 else
914
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 15 times.
345 for(i=0; i<mbWidth; i++) c->forcedQPTable[i]= 1;
915 }
916
917
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if(pict_type & PP_PICT_TYPE_QP2){
918 int i;
919 20 const int count= FFMAX(mbHeight * absQPStride, mbWidth);
920
2/2
✓ Branch 0 taken 1980 times.
✓ Branch 1 taken 20 times.
2000 for(i=0; i<(count>>2); i++){
921 1980 AV_WN32(c->stdQPTable + (i<<2), AV_RN32(QP_store + (i<<2)) >> 1 & 0x7F7F7F7F);
922 }
923
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 for(i<<=2; i<count; i++){
924 c->stdQPTable[i] = QP_store[i]>>1;
925 }
926 20 QP_store= c->stdQPTable;
927 20 QPStride= absQPStride;
928 }
929
930 if(0){
931 int x,y;
932 for(y=0; y<mbHeight; y++){
933 for(x=0; x<mbWidth; x++){
934 av_log(c, AV_LOG_INFO, "%2d ", QP_store[x + y*QPStride]);
935 }
936 av_log(c, AV_LOG_INFO, "\n");
937 }
938 av_log(c, AV_LOG_INFO, "\n");
939 }
940
941
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 3 times.
40 if((pict_type&7)!=3){
942
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 if (QPStride >= 0){
943 int i;
944 37 const int count= FFMAX(mbHeight * QPStride, mbWidth);
945
2/2
✓ Branch 0 taken 1783 times.
✓ Branch 1 taken 37 times.
1820 for(i=0; i<(count>>2); i++){
946 1783 AV_WN32(c->nonBQPTable + (i<<2), AV_RN32(QP_store + (i<<2)) & 0x3F3F3F3F);
947 }
948
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 37 times.
77 for(i<<=2; i<count; i++){
949 40 c->nonBQPTable[i] = QP_store[i] & 0x3F;
950 }
951 } else {
952 int i,j;
953 for(i=0; i<mbHeight; i++) {
954 for(j=0; j<absQPStride; j++) {
955 c->nonBQPTable[i*absQPStride+j] = QP_store[i*QPStride+j] & 0x3F;
956 }
957 }
958 }
959 }
960
961 40 av_log(c, AV_LOG_DEBUG, "using npp filters 0x%X/0x%X\n",
962 mode->lumMode, mode->chromMode);
963
964 40 postProcess(src[0], srcStride[0], dst[0], dstStride[0],
965 width, height, QP_store, QPStride, 0, mode, c);
966
967
4/8
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 40 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 40 times.
40 if (!(src[1] && src[2] && dst[1] && dst[2]))
968 return;
969
970 40 width = (width )>>c->hChromaSubSample;
971 40 height = (height)>>c->vChromaSubSample;
972
973
1/2
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
40 if(mode->chromMode){
974 40 postProcess(src[1], srcStride[1], dst[1], dstStride[1],
975 width, height, QP_store, QPStride, 1, mode, c);
976 40 postProcess(src[2], srcStride[2], dst[2], dstStride[2],
977 width, height, QP_store, QPStride, 2, mode, c);
978 }
979 else if(srcStride[1] == dstStride[1] && srcStride[2] == dstStride[2]){
980 linecpy(dst[1], src[1], height, srcStride[1]);
981 linecpy(dst[2], src[2], height, srcStride[2]);
982 }else{
983 int y;
984 for(y=0; y<height; y++){
985 memcpy(&(dst[1][y*dstStride[1]]), &(src[1][y*srcStride[1]]), width);
986 memcpy(&(dst[2][y*dstStride[2]]), &(src[2][y*srcStride[2]]), width);
987 }
988 }
989 }
990