FFmpeg coverage


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