lavfi: port mp=fspp to a native libavfilter filter
[ffmpeg.git] / libavfilter / vf_fspp.c
1 /*
2  * Copyright (c) 2003 Michael Niedermayer <michaelni@gmx.at>
3  * Copyright (C) 2005 Nikolaj Poroshin <porosh3@psu.ru>
4  * Copyright (c) 2014 Arwa Arif <arwaarif1994@gmail.com>
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 along
19  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 /**
24  * @file
25  * Fast Simple Post-processing filter
26  * This implementation is based on an algorithm described in
27  * "Aria Nosratinia Embedded Post-Processing for
28  * Enhancement of Compressed Images (1999)"
29  * (http://www.utdallas.edu/~aria/papers/vlsisp99.pdf)
30  * Further, with splitting (I)DCT into horizontal/vertical passes, one of
31  * them can be performed once per block, not per pixel. This allows for much
32  * higher speed.
33  *
34  * Originally written by Michael Niedermayer and Nikolaj for the MPlayer
35  * project, and ported by Arwa Arif for FFmpeg.
36  */
37
38 #include "libavutil/avassert.h"
39 #include "libavutil/imgutils.h"
40 #include "libavutil/opt.h"
41 #include "libavutil/pixdesc.h"
42 #include "internal.h"
43 #include "libavcodec/avcodec.h" //for reference to FF_QSCALE_TYPE
44 #include "vf_fspp.h"
45
46 #define OFFSET(x) offsetof(FSPPContext, x)
47 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
48 static const AVOption fspp_options[] = {
49     { "quality",       "set quality",                          OFFSET(log2_count),    AV_OPT_TYPE_INT, {.i64 = 4},   4, MAX_LEVEL, FLAGS },
50     { "qp",            "force a constant quantizer parameter", OFFSET(qp),            AV_OPT_TYPE_INT, {.i64 = 0},   0, 64,        FLAGS },
51     { "strength",      "set filter strength",                  OFFSET(strength),      AV_OPT_TYPE_INT, {.i64 = 0}, -15, 32,        FLAGS },
52     { "use_bframe_qp", "use B-frames' QP",                     OFFSET(use_bframe_qp), AV_OPT_TYPE_INT, {.i64 = 0},   0, 1,         FLAGS },
53     { NULL }
54 };
55
56 AVFILTER_DEFINE_CLASS(fspp);
57
58 DECLARE_ALIGNED(32, static const uint8_t, dither)[8][8] = {
59     {  0,  48,  12,  60,   3,  51,  15,  63, },
60     { 32,  16,  44,  28,  35,  19,  47,  31, },
61     {  8,  56,   4,  52,  11,  59,   7,  55, },
62     { 40,  24,  36,  20,  43,  27,  39,  23, },
63     {  2,  50,  14,  62,   1,  49,  13,  61, },
64     { 34,  18,  46,  30,  33,  17,  45,  29, },
65     { 10,  58,   6,  54,   9,  57,   5,  53, },
66     { 42,  26,  38,  22,  41,  25,  37,  21, },
67 };
68
69 static const short custom_threshold[64] = {
70 // values (296) can't be too high
71 // -it causes too big quant dependence
72 // or maybe overflow(check), which results in some flashing
73      71, 296, 295, 237,  71,  40,  38,  19,
74     245, 193, 185, 121, 102,  73,  53,  27,
75     158, 129, 141, 107,  97,  73,  50,  26,
76     102, 116, 109,  98,  82,  66,  45,  23,
77      71,  94,  95,  81,  70,  56,  38,  20,
78      56,  77,  74,  66,  56,  44,  30,  15,
79      38,  53,  50,  45,  38,  30,  21,  11,
80      20,  27,  26,  23,  20,  15,  11,   5
81 };
82
83 static inline int norm_qscale(int qscale, int type)
84 {
85     switch (type) {
86     case FF_QSCALE_TYPE_MPEG1: return qscale;
87     case FF_QSCALE_TYPE_MPEG2: return qscale >> 1;
88     case FF_QSCALE_TYPE_H264:  return qscale >> 2;
89     case FF_QSCALE_TYPE_VP56:  return (63 - qscale + 2) >> 2;
90     }
91     return qscale;
92 }
93
94 //This func reads from 1 slice, 1 and clears 0 & 1
95 static void store_slice_c(uint8_t *dst, int16_t *src,
96                           ptrdiff_t dst_stride, ptrdiff_t src_stride,
97                           ptrdiff_t width, ptrdiff_t height, ptrdiff_t log2_scale)
98 {
99     int y, x;
100 #define STORE(pos)                                                             \
101     temp = (src[x + pos] + (d[pos] >> log2_scale)) >> (6 - log2_scale);        \
102     src[x + pos] = src[x + pos - 8 * src_stride] = 0;                          \
103     if (temp & 0x100) temp = ~(temp >> 31);                                    \
104     dst[x + pos] = temp;
105
106     for (y = 0; y < height; y++) {
107         const uint8_t *d = dither[y];
108         for (x = 0; x < width; x += 8) {
109             int temp;
110             STORE(0);
111             STORE(1);
112             STORE(2);
113             STORE(3);
114             STORE(4);
115             STORE(5);
116             STORE(6);
117             STORE(7);
118         }
119         src += src_stride;
120         dst += dst_stride;
121     }
122 }
123
124 //This func reads from 2 slices, 0 & 2  and clears 2-nd
125 static void store_slice2_c(uint8_t *dst, int16_t *src,
126                            ptrdiff_t dst_stride, ptrdiff_t src_stride,
127                            ptrdiff_t width, ptrdiff_t height, ptrdiff_t log2_scale)
128 {
129     int y, x;
130 #define STORE2(pos)                                                                                       \
131     temp = (src[x + pos] + src[x + pos + 16 * src_stride] + (d[pos] >> log2_scale)) >> (6 - log2_scale);  \
132     src[x + pos + 16 * src_stride] = 0;                                                                   \
133     if (temp & 0x100) temp = ~(temp >> 31);                                                               \
134     dst[x + pos] = temp;
135
136     for (y = 0; y < height; y++) {
137         const uint8_t *d = dither[y];
138         for (x = 0; x < width; x += 8) {
139             int temp;
140             STORE2(0);
141             STORE2(1);
142             STORE2(2);
143             STORE2(3);
144             STORE2(4);
145             STORE2(5);
146             STORE2(6);
147             STORE2(7);
148         }
149         src += src_stride;
150         dst += dst_stride;
151     }
152 }
153
154 static void mul_thrmat_c(FSPPContext *p, int q)
155 {
156     int a;
157     for (a = 0; a < 64; a++)
158         ((int16_t *)p->threshold_mtx)[a] = q * ((int16_t *)p->threshold_mtx_noq)[a];//ints faster in C
159 }
160
161 static void filter(FSPPContext *p, uint8_t *dst, uint8_t *src,
162                    int dst_stride, int src_stride,
163                    int width, int height,
164                    uint8_t *qp_store, int qp_stride, int is_luma)
165 {
166     int x, x0, y, es, qy, t;
167
168     const int stride = is_luma ? p->temp_stride : (width + 16);
169     const int step = 6 - p->log2_count;
170     const int qpsh = 4 - p->hsub * !is_luma;
171     const int qpsv = 4 - p->vsub * !is_luma;
172
173     DECLARE_ALIGNED(32, int32_t, block_align)[4 * 8 * BLOCKSZ + 4 * 8 * BLOCKSZ];
174     int16_t *block  = (int16_t *)block_align;
175     int16_t *block3 = (int16_t *)(block_align + 4 * 8 * BLOCKSZ);
176
177     memset(block3, 0, 4 * 8 * BLOCKSZ);
178
179     if (!src || !dst) return;
180
181     for (y = 0; y < height; y++) {
182         int index = 8 + 8 * stride + y * stride;
183         memcpy(p->src + index, src + y * src_stride, width);
184         for (x = 0; x < 8; x++) {
185             p->src[index         - x - 1] = p->src[index +         x    ];
186             p->src[index + width + x    ] = p->src[index + width - x - 1];
187         }
188     }
189
190     for (y = 0; y < 8; y++) {
191         memcpy(p->src + (     7 - y    ) * stride, p->src + (     y + 8    ) * stride, stride);
192         memcpy(p->src + (height + 8 + y) * stride, p->src + (height - y + 7) * stride, stride);
193     }
194     //FIXME (try edge emu)
195
196     for (y = 8; y < 24; y++)
197         memset(p->temp + 8 + y * stride, 0, width * sizeof(int16_t));
198
199     for (y = step; y < height + 8; y += step) {    //step= 1,2
200         const int y1 = y - 8 + step;                 //l5-7  l4-6;
201         qy = y - 4;
202
203         if (qy > height - 1) qy = height - 1;
204         if (qy < 0) qy = 0;
205
206         qy = (qy >> qpsv) * qp_stride;
207         p->row_fdct(block, p->src + y * stride + 2 - (y&1), stride, 2);
208
209         for (x0 = 0; x0 < width + 8 - 8 * (BLOCKSZ - 1); x0 += 8 * (BLOCKSZ - 1)) {
210             p->row_fdct(block + 8 * 8, p->src + y * stride + 8 + x0 + 2 - (y&1), stride, 2 * (BLOCKSZ - 1));
211
212             if (p->qp)
213                 p->column_fidct((int16_t *)(&p->threshold_mtx[0]), block + 0 * 8, block3 + 0 * 8, 8 * (BLOCKSZ - 1)); //yes, this is a HOTSPOT
214             else
215                 for (x = 0; x < 8 * (BLOCKSZ - 1); x += 8) {
216                     t = x + x0 - 2;                    //correct t=x+x0-2-(y&1), but its the same
217
218                     if (t < 0) t = 0;                   //t always < width-2
219
220                     t = qp_store[qy + (t >> qpsh)];
221                     t = norm_qscale(t, p->qscale_type);
222
223                     if (t != p->prev_q) p->prev_q = t, p->mul_thrmat(p, t);
224                     p->column_fidct((int16_t *)(&p->threshold_mtx[0]), block + x * 8, block3 + x * 8, 8); //yes, this is a HOTSPOT
225                 }
226             p->row_idct(block3 + 0 * 8, p->temp + (y & 15) * stride + x0 + 2 - (y & 1), stride, 2 * (BLOCKSZ - 1));
227             memmove(block,  block  + (BLOCKSZ - 1) * 64, 8 * 8 * sizeof(int16_t)); //cycling
228             memmove(block3, block3 + (BLOCKSZ - 1) * 64, 6 * 8 * sizeof(int16_t));
229         }
230
231         es = width + 8 - x0; //  8, ...
232         if (es > 8)
233             p->row_fdct(block + 8 * 8, p->src + y * stride + 8 + x0 + 2 - (y & 1), stride, (es - 4) >> 2);
234
235         p->column_fidct((int16_t *)(&p->threshold_mtx[0]), block, block3, es&(~1));
236         p->row_idct(block3 + 0 * 8, p->temp + (y & 15) * stride + x0 + 2 - (y & 1), stride, es >> 2);
237
238         if (!(y1 & 7) && y1) {
239             if (y1 & 8)
240                 p->store_slice(dst + (y1 - 8) * dst_stride, p->temp + 8 + 8 * stride,
241                                dst_stride, stride, width, 8, 5 - p->log2_count);
242             else
243                 p->store_slice2(dst + (y1 - 8) * dst_stride, p->temp + 8 + 0 * stride,
244                                 dst_stride, stride, width, 8, 5 - p->log2_count);
245         }
246     }
247
248     if (y & 7) {  // == height & 7
249         if (y & 8)
250             p->store_slice(dst + ((y - 8) & ~7) * dst_stride, p->temp + 8 + 8 * stride,
251                            dst_stride, stride, width, y&7, 5 - p->log2_count);
252         else
253             p->store_slice2(dst + ((y - 8) & ~7) * dst_stride, p->temp + 8 + 0 * stride,
254                             dst_stride, stride, width, y&7, 5 - p->log2_count);
255     }
256 }
257
258 static void column_fidct_c(int16_t *thr_adr, int16_t *data, int16_t *output, int cnt)
259 {
260     int_simd16_t tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
261     int_simd16_t tmp10, tmp11, tmp12, tmp13;
262     int_simd16_t z1,z2,z3,z4,z5, z10, z11, z12, z13;
263     int_simd16_t d0, d1, d2, d3, d4, d5, d6, d7;
264
265     int16_t *dataptr;
266     int16_t *wsptr;
267     int16_t *threshold;
268     int ctr;
269
270     dataptr = data;
271     wsptr = output;
272
273     for (; cnt > 0; cnt -= 2) { //start positions
274         threshold = (int16_t *)thr_adr;//threshold_mtx
275         for (ctr = DCTSIZE; ctr > 0; ctr--) {
276             // Process columns from input, add to output.
277             tmp0 = dataptr[DCTSIZE * 0] + dataptr[DCTSIZE * 7];
278             tmp7 = dataptr[DCTSIZE * 0] - dataptr[DCTSIZE * 7];
279
280             tmp1 = dataptr[DCTSIZE * 1] + dataptr[DCTSIZE * 6];
281             tmp6 = dataptr[DCTSIZE * 1] - dataptr[DCTSIZE * 6];
282
283             tmp2 = dataptr[DCTSIZE * 2] + dataptr[DCTSIZE * 5];
284             tmp5 = dataptr[DCTSIZE * 2] - dataptr[DCTSIZE * 5];
285
286             tmp3 = dataptr[DCTSIZE * 3] + dataptr[DCTSIZE * 4];
287             tmp4 = dataptr[DCTSIZE * 3] - dataptr[DCTSIZE * 4];
288
289             // Even part of FDCT
290
291             tmp10 = tmp0 + tmp3;
292             tmp13 = tmp0 - tmp3;
293             tmp11 = tmp1 + tmp2;
294             tmp12 = tmp1 - tmp2;
295
296             d0 = tmp10 + tmp11;
297             d4 = tmp10 - tmp11;
298
299             z1 = MULTIPLY16H((tmp12 + tmp13) << 2, FIX_0_707106781);
300             d2 = tmp13 + z1;
301             d6 = tmp13 - z1;
302
303             // Even part of IDCT
304
305             THRESHOLD(tmp0, d0, threshold[0 * 8]);
306             THRESHOLD(tmp1, d2, threshold[2 * 8]);
307             THRESHOLD(tmp2, d4, threshold[4 * 8]);
308             THRESHOLD(tmp3, d6, threshold[6 * 8]);
309             tmp0 += 2;
310             tmp10 = (tmp0 + tmp2) >> 2;
311             tmp11 = (tmp0 - tmp2) >> 2;
312
313             tmp13 = (tmp1 + tmp3) >>2; //+2 !  (psnr decides)
314             tmp12 = MULTIPLY16H((tmp1 - tmp3), FIX_1_414213562_A) - tmp13; //<<2
315
316             tmp0 = tmp10 + tmp13; //->temps
317             tmp3 = tmp10 - tmp13; //->temps
318             tmp1 = tmp11 + tmp12; //->temps
319             tmp2 = tmp11 - tmp12; //->temps
320
321             // Odd part of FDCT
322
323             tmp10 = tmp4 + tmp5;
324             tmp11 = tmp5 + tmp6;
325             tmp12 = tmp6 + tmp7;
326
327             z5 = MULTIPLY16H((tmp10 - tmp12) << 2, FIX_0_382683433);
328             z2 = MULTIPLY16H(tmp10 << 2, FIX_0_541196100) + z5;
329             z4 = MULTIPLY16H(tmp12 << 2, FIX_1_306562965) + z5;
330             z3 = MULTIPLY16H(tmp11 << 2, FIX_0_707106781);
331
332             z11 = tmp7 + z3;
333             z13 = tmp7 - z3;
334
335             d5 = z13 + z2;
336             d3 = z13 - z2;
337             d1 = z11 + z4;
338             d7 = z11 - z4;
339
340             // Odd part of IDCT
341
342             THRESHOLD(tmp4, d1, threshold[1 * 8]);
343             THRESHOLD(tmp5, d3, threshold[3 * 8]);
344             THRESHOLD(tmp6, d5, threshold[5 * 8]);
345             THRESHOLD(tmp7, d7, threshold[7 * 8]);
346
347             //Simd version uses here a shortcut for the tmp5,tmp6,tmp7 == 0
348             z13 = tmp6 + tmp5;
349             z10 = (tmp6 - tmp5) << 1;
350             z11 = tmp4 + tmp7;
351             z12 = (tmp4 - tmp7) << 1;
352
353             tmp7  = (z11 + z13) >> 2; //+2 !
354             tmp11 = MULTIPLY16H((z11 - z13) << 1, FIX_1_414213562);
355             z5    = MULTIPLY16H(z10 + z12,        FIX_1_847759065);
356             tmp10 = MULTIPLY16H(z12,              FIX_1_082392200) - z5;
357             tmp12 = MULTIPLY16H(z10,              FIX_2_613125930) + z5; // - !!
358
359             tmp6 = tmp12 - tmp7;
360             tmp5 = tmp11 - tmp6;
361             tmp4 = tmp10 + tmp5;
362
363             wsptr[DCTSIZE * 0] +=  (tmp0 + tmp7);
364             wsptr[DCTSIZE * 1] +=  (tmp1 + tmp6);
365             wsptr[DCTSIZE * 2] +=  (tmp2 + tmp5);
366             wsptr[DCTSIZE * 3] +=  (tmp3 - tmp4);
367             wsptr[DCTSIZE * 4] +=  (tmp3 + tmp4);
368             wsptr[DCTSIZE * 5] +=  (tmp2 - tmp5);
369             wsptr[DCTSIZE * 6]  =  (tmp1 - tmp6);
370             wsptr[DCTSIZE * 7]  =  (tmp0 - tmp7);
371             //
372             dataptr++; //next column
373             wsptr++;
374             threshold++;
375         }
376         dataptr += 8; //skip each second start pos
377         wsptr   += 8;
378     }
379 }
380
381 static void row_idct_c(int16_t *workspace, int16_t *output_adr, int output_stride, int cnt)
382 {
383     int_simd16_t tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
384     int_simd16_t tmp10, tmp11, tmp12, tmp13;
385     int_simd16_t z5, z10, z11, z12, z13;
386     int16_t *outptr;
387     int16_t *wsptr;
388
389     cnt *= 4;
390     wsptr = workspace;
391     outptr = output_adr;
392     for (; cnt > 0; cnt--) {
393         // Even part
394         //Simd version reads 4x4 block and transposes it
395         tmp10 = wsptr[2] +  wsptr[3];
396         tmp11 = wsptr[2] -  wsptr[3];
397
398         tmp13 = wsptr[0] +  wsptr[1];
399         tmp12 = (MULTIPLY16H(wsptr[0] - wsptr[1], FIX_1_414213562_A) << 2) - tmp13;//this shift order to avoid overflow
400
401         tmp0 = tmp10 + tmp13; //->temps
402         tmp3 = tmp10 - tmp13; //->temps
403         tmp1 = tmp11 + tmp12;
404         tmp2 = tmp11 - tmp12;
405
406         // Odd part
407         //Also transpose, with previous:
408         // ---- ----      ||||
409         // ---- ---- idct ||||
410         // ---- ---- ---> ||||
411         // ---- ----      ||||
412         z13 = wsptr[4] + wsptr[5];
413         z10 = wsptr[4] - wsptr[5];
414         z11 = wsptr[6] + wsptr[7];
415         z12 = wsptr[6] - wsptr[7];
416
417         tmp7 = z11 + z13;
418         tmp11 = MULTIPLY16H(z11 - z13, FIX_1_414213562);
419
420         z5 =    MULTIPLY16H(z10 + z12, FIX_1_847759065);
421         tmp10 = MULTIPLY16H(z12,       FIX_1_082392200) - z5;
422         tmp12 = MULTIPLY16H(z10,       FIX_2_613125930) + z5; // - FIX_
423
424         tmp6 = (tmp12 << 3) - tmp7;
425         tmp5 = (tmp11 << 3) - tmp6;
426         tmp4 = (tmp10 << 3) + tmp5;
427
428         // Final output stage: descale and write column
429         outptr[0 * output_stride] += DESCALE(tmp0 + tmp7, 3);
430         outptr[1 * output_stride] += DESCALE(tmp1 + tmp6, 3);
431         outptr[2 * output_stride] += DESCALE(tmp2 + tmp5, 3);
432         outptr[3 * output_stride] += DESCALE(tmp3 - tmp4, 3);
433         outptr[4 * output_stride] += DESCALE(tmp3 + tmp4, 3);
434         outptr[5 * output_stride] += DESCALE(tmp2 - tmp5, 3);
435         outptr[6 * output_stride] += DESCALE(tmp1 - tmp6, 3); //no += ?
436         outptr[7 * output_stride] += DESCALE(tmp0 - tmp7, 3); //no += ?
437         outptr++;
438
439         wsptr += DCTSIZE;       // advance pointer to next row
440     }
441 }
442
443 static void row_fdct_c(int16_t *data, const uint8_t *pixels, int line_size, int cnt)
444 {
445     int_simd16_t tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
446     int_simd16_t tmp10, tmp11, tmp12, tmp13;
447     int_simd16_t z1, z2, z3, z4, z5, z11, z13;
448     int16_t *dataptr;
449
450     cnt *= 4;
451     // Pass 1: process rows.
452
453     dataptr = data;
454     for (; cnt > 0; cnt--) {
455         tmp0 = pixels[line_size * 0] + pixels[line_size * 7];
456         tmp7 = pixels[line_size * 0] - pixels[line_size * 7];
457         tmp1 = pixels[line_size * 1] + pixels[line_size * 6];
458         tmp6 = pixels[line_size * 1] - pixels[line_size * 6];
459         tmp2 = pixels[line_size * 2] + pixels[line_size * 5];
460         tmp5 = pixels[line_size * 2] - pixels[line_size * 5];
461         tmp3 = pixels[line_size * 3] + pixels[line_size * 4];
462         tmp4 = pixels[line_size * 3] - pixels[line_size * 4];
463
464         // Even part
465
466         tmp10 = tmp0 + tmp3;
467         tmp13 = tmp0 - tmp3;
468         tmp11 = tmp1 + tmp2;
469         tmp12 = tmp1 - tmp2;
470         //Even columns are written first, this leads to different order of columns
471         //in column_fidct(), but they are processed independently, so all ok.
472         //Later in the row_idct() columns readed at the same order.
473         dataptr[2] = tmp10 + tmp11;
474         dataptr[3] = tmp10 - tmp11;
475
476         z1 = MULTIPLY16H((tmp12 + tmp13) << 2, FIX_0_707106781);
477         dataptr[0] = tmp13 + z1;
478         dataptr[1] = tmp13 - z1;
479
480         // Odd part
481
482         tmp10 = (tmp4 + tmp5) << 2;
483         tmp11 = (tmp5 + tmp6) << 2;
484         tmp12 = (tmp6 + tmp7) << 2;
485
486         z5 = MULTIPLY16H(tmp10 - tmp12, FIX_0_382683433);
487         z2 = MULTIPLY16H(tmp10,         FIX_0_541196100) + z5;
488         z4 = MULTIPLY16H(tmp12,         FIX_1_306562965) + z5;
489         z3 = MULTIPLY16H(tmp11,         FIX_0_707106781);
490
491         z11 = tmp7 + z3;
492         z13 = tmp7 - z3;
493
494         dataptr[4] = z13 + z2;
495         dataptr[5] = z13 - z2;
496         dataptr[6] = z11 + z4;
497         dataptr[7] = z11 - z4;
498
499         pixels++;               // advance pointer to next column
500         dataptr += DCTSIZE;
501     }
502 }
503
504 static int query_formats(AVFilterContext *ctx)
505 {
506     static const enum PixelFormat pix_fmts[] = {
507         AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV422P,
508         AV_PIX_FMT_YUV420P,  AV_PIX_FMT_YUV411P,
509         AV_PIX_FMT_YUV410P,  AV_PIX_FMT_YUV440P,
510         AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P,
511         AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ440P,
512         AV_PIX_FMT_NONE
513     };
514     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
515     return 0;
516 }
517
518 static int config_input(AVFilterLink *inlink)
519 {
520     AVFilterContext *ctx = inlink->dst;
521     FSPPContext *fspp = ctx->priv;
522     const int h = FFALIGN(inlink->h + 16, 16);
523     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
524
525     fspp->hsub = desc->log2_chroma_w;
526     fspp->vsub = desc->log2_chroma_h;
527
528     fspp->temp_stride = FFALIGN(inlink->w + 16, 16);
529     fspp->temp = av_malloc_array(fspp->temp_stride, h * sizeof(*fspp->temp));
530     fspp->src  = av_malloc_array(fspp->temp_stride, h * sizeof(*fspp->src));
531
532     if (!fspp->temp || !fspp->src)
533         return AVERROR(ENOMEM);
534
535     if (!fspp->use_bframe_qp && !fspp->qp) {
536         fspp->non_b_qp_alloc_size = FF_CEIL_RSHIFT(inlink->w, 4) * FF_CEIL_RSHIFT(inlink->h, 4);
537         fspp->non_b_qp_table = av_calloc(fspp->non_b_qp_alloc_size, sizeof(*fspp->non_b_qp_table));
538         if (!fspp->non_b_qp_table)
539             return AVERROR(ENOMEM);
540     }
541
542     fspp->store_slice  = store_slice_c;
543     fspp->store_slice2 = store_slice2_c;
544     fspp->mul_thrmat   = mul_thrmat_c;
545     fspp->column_fidct = column_fidct_c;
546     fspp->row_idct     = row_idct_c;
547     fspp->row_fdct     = row_fdct_c;
548
549     if (ARCH_X86)
550         ff_fspp_init_x86(fspp);
551
552     return 0;
553 }
554
555 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
556 {
557     AVFilterContext *ctx = inlink->dst;
558     FSPPContext *fspp = ctx->priv;
559     AVFilterLink *outlink = ctx->outputs[0];
560     AVFrame *out = in;
561
562     int qp_stride = 0;
563     uint8_t *qp_table = NULL;
564     int i, bias;
565     int custom_threshold_m[64];
566
567     bias = (1 << 4) + fspp->strength;
568
569     for (i = 0; i < 64; i++) //FIXME: tune custom_threshold[] and remove this !
570         custom_threshold_m[i] = (int)(custom_threshold[i] * (bias / 71.0) + 0.5);
571
572     for (i = 0; i < 8; i++) {
573         fspp->threshold_mtx_noq[2 * i] = (uint64_t)custom_threshold_m[i * 8 + 2]
574                                       |(((uint64_t)custom_threshold_m[i * 8 + 6]) << 16)
575                                       |(((uint64_t)custom_threshold_m[i * 8 + 0]) << 32)
576                                       |(((uint64_t)custom_threshold_m[i * 8 + 4]) << 48);
577
578         fspp->threshold_mtx_noq[2 * i + 1] = (uint64_t)custom_threshold_m[i * 8 + 5]
579                                           |(((uint64_t)custom_threshold_m[i * 8 + 3]) << 16)
580                                           |(((uint64_t)custom_threshold_m[i * 8 + 1]) << 32)
581                                           |(((uint64_t)custom_threshold_m[i * 8 + 7]) << 48);
582     }
583
584     if (fspp->qp)
585         fspp->prev_q = fspp->qp, fspp->mul_thrmat(fspp, fspp->qp);
586
587     /* if we are not in a constant user quantizer mode and we don't want to use
588      * the quantizers from the B-frames (B-frames often have a higher QP), we
589      * need to save the qp table from the last non B-frame; this is what the
590      * following code block does */
591     if (!fspp->qp) {
592         qp_table = av_frame_get_qp_table(in, &qp_stride, &fspp->qscale_type);
593
594         if (qp_table && !fspp->use_bframe_qp && in->pict_type != AV_PICTURE_TYPE_B) {
595             int w, h;
596
597             /* if the qp stride is not set, it means the QP are only defined on
598              * a line basis */
599            if (!qp_stride) {
600                 w = FF_CEIL_RSHIFT(inlink->w, 4);
601                 h = 1;
602             } else {
603                 w = qp_stride;
604                 h = FF_CEIL_RSHIFT(inlink->h, 4);
605             }
606             if (w * h > fspp->non_b_qp_alloc_size) {
607                 int ret = av_reallocp_array(&fspp->non_b_qp_table, w, h);
608                 if (ret < 0) {
609                     fspp->non_b_qp_alloc_size = 0;
610                     return ret;
611                 }
612                 fspp->non_b_qp_alloc_size = w * h;
613             }
614
615             av_assert0(w * h <= fspp->non_b_qp_alloc_size);
616             memcpy(fspp->non_b_qp_table, qp_table, w * h);
617         }
618     }
619
620     if (fspp->log2_count && !ctx->is_disabled) {
621         if (!fspp->use_bframe_qp && fspp->non_b_qp_table)
622             qp_table = fspp->non_b_qp_table;
623
624         if (qp_table || fspp->qp) {
625             const int cw = FF_CEIL_RSHIFT(inlink->w, fspp->hsub);
626             const int ch = FF_CEIL_RSHIFT(inlink->h, fspp->vsub);
627
628             /* get a new frame if in-place is not possible or if the dimensions
629              * are not multiple of 8 */
630             if (!av_frame_is_writable(in) || (inlink->w & 7) || (inlink->h & 7)) {
631                 const int aligned_w = FFALIGN(inlink->w, 8);
632                 const int aligned_h = FFALIGN(inlink->h, 8);
633
634                 out = ff_get_video_buffer(outlink, aligned_w, aligned_h);
635                 if (!out) {
636                     av_frame_free(&in);
637                     return AVERROR(ENOMEM);
638                 }
639                 av_frame_copy_props(out, in);
640             }
641
642             filter(fspp, out->data[0], in->data[0], out->linesize[0], in->linesize[0],
643                    inlink->w, inlink->h, qp_table, qp_stride, 1);
644             filter(fspp, out->data[1], in->data[1], out->linesize[1], in->linesize[1],
645                    cw,        ch,        qp_table, qp_stride, 0);
646             filter(fspp, out->data[2], in->data[2], out->linesize[2], in->linesize[2],
647                    cw,        ch,        qp_table, qp_stride, 0);
648             emms_c();
649         }
650     }
651
652     if (in != out) {
653         if (in->data[3])
654             av_image_copy_plane(out->data[3], out->linesize[3],
655                                 in ->data[3], in ->linesize[3],
656                                 inlink->w, inlink->h);
657         av_frame_free(&in);
658     }
659     return ff_filter_frame(outlink, out);
660 }
661
662 static av_cold void uninit(AVFilterContext *ctx)
663 {
664     FSPPContext *fspp = ctx->priv;
665     av_freep(&fspp->temp);
666     av_freep(&fspp->src);
667     av_freep(&fspp->non_b_qp_table);
668 }
669
670 static const AVFilterPad fspp_inputs[] = {
671     {
672         .name         = "default",
673         .type         = AVMEDIA_TYPE_VIDEO,
674         .config_props = config_input,
675         .filter_frame = filter_frame,
676     },
677     { NULL }
678 };
679
680 static const AVFilterPad fspp_outputs[] = {
681     {
682         .name = "default",
683         .type = AVMEDIA_TYPE_VIDEO,
684     },
685     { NULL }
686 };
687
688 AVFilter ff_vf_fspp = {
689     .name            = "fspp",
690     .description     = NULL_IF_CONFIG_SMALL("Apply Fast Simple Post-processing filter."),
691     .priv_size       = sizeof(FSPPContext),
692     .uninit          = uninit,
693     .query_formats   = query_formats,
694     .inputs          = fspp_inputs,
695     .outputs         = fspp_outputs,
696     .priv_class      = &fspp_class,
697     .flags           = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
698 };