]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_xbr.c
Merge commit '3a6ddfb8745e4b306a5637927fb057f630345e2f'
[ffmpeg] / libavfilter / vf_xbr.c
1 /*
2  * This file is part of FFmpeg.
3  *
4  * Copyright (C) 2011, 2012 Hyllian/Jararaca - sergiogdb@gmail.com
5  *
6  * Copyright (c) 2014 Arwa Arif <arwaarif1994@gmail.com>
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  * XBR Filter is used for depixelization of image.
26  * This is based on Hyllian's xBR shader.
27  *
28  * @see http://www.libretro.com/forums/viewtopic.php?f=6&t=134
29  * @see https://github.com/yoyofr/iFBA/blob/master/fba_src/src/intf/video/scalers/xbr.cpp
30  *
31  * @todo add threading and FATE test
32  */
33
34 #include "libavutil/opt.h"
35 #include "libavutil/avassert.h"
36 #include "libavutil/pixdesc.h"
37 #include "internal.h"
38
39 #define RGB_MASK      0x00FFFFFF
40 #define LB_MASK       0x00FEFEFE
41 #define RED_BLUE_MASK 0x00FF00FF
42 #define GREEN_MASK    0x0000FF00
43
44 typedef struct {
45     const AVClass *class;
46     int n;
47     uint32_t rgbtoyuv[1<<24];
48 } XBRContext;
49
50 #define OFFSET(x) offsetof(XBRContext, x)
51 static const AVOption xbr_options[] = {
52     { "n", "set scale factor", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 3}, 2, 4, },
53     { NULL }
54 };
55
56 AVFILTER_DEFINE_CLASS(xbr);
57
58 static uint32_t df(uint32_t x, uint32_t y, const uint32_t *r2y)
59 {
60 #define YMASK 0xff0000
61 #define UMASK 0x00ff00
62 #define VMASK 0x0000ff
63
64     uint32_t yuv1 = r2y[x & 0xffffff];
65     uint32_t yuv2 = r2y[y & 0xffffff];
66
67     return (abs((yuv1 & YMASK) - (yuv2 & YMASK)) >> 16) +
68            (abs((yuv1 & UMASK) - (yuv2 & UMASK)) >>  8) +
69            abs((yuv1 & VMASK) - (yuv2 & VMASK));
70 }
71
72 #define ALPHA_BLEND_128_W(dst, src) dst = ((src & LB_MASK) >> 1) + ((dst & LB_MASK) >> 1)
73
74 #define ALPHA_BLEND_32_W(dst, src) \
75     dst = ((RED_BLUE_MASK & ((dst & RED_BLUE_MASK) + ((((src & RED_BLUE_MASK) - \
76           (dst & RED_BLUE_MASK))) >>3))) | (GREEN_MASK & ((dst & GREEN_MASK) + \
77           ((((src & GREEN_MASK) - (dst & GREEN_MASK))) >>3))))
78
79 #define ALPHA_BLEND_64_W(dst, src) \
80     dst = ((RED_BLUE_MASK & ((dst & RED_BLUE_MASK) + ((((src & RED_BLUE_MASK) - \
81           (dst & RED_BLUE_MASK))) >>2))) | (GREEN_MASK & ((dst & GREEN_MASK) + \
82           ((((src & GREEN_MASK) - (dst & GREEN_MASK))) >>2))))
83
84 #define ALPHA_BLEND_192_W(dst, src) \
85     dst = ((RED_BLUE_MASK & ((dst & RED_BLUE_MASK) + ((((src & RED_BLUE_MASK) - \
86           (dst & RED_BLUE_MASK)) * 3) >>2))) | (GREEN_MASK & ((dst & GREEN_MASK) + \
87           ((((src & GREEN_MASK) - (dst & GREEN_MASK)) * 3) >>2))))
88
89 #define ALPHA_BLEND_224_W(dst, src) \
90     dst = ((RED_BLUE_MASK & ((dst & RED_BLUE_MASK) + ((((src & RED_BLUE_MASK) - \
91           (dst & RED_BLUE_MASK)) * 7) >>3))) | (GREEN_MASK & ((dst & GREEN_MASK) + \
92           ((((src & GREEN_MASK) - (dst & GREEN_MASK)) * 7) >>3))))
93
94 #define LEFT_UP_2_2X(N3, N2, N1, PIXEL)\
95     ALPHA_BLEND_224_W(E[N3], PIXEL); \
96     ALPHA_BLEND_64_W( E[N2], PIXEL); \
97     E[N1] = E[N2]; \
98
99 #define LEFT_2_2X(N3, N2, PIXEL)\
100     ALPHA_BLEND_192_W(E[N3], PIXEL); \
101     ALPHA_BLEND_64_W( E[N2], PIXEL); \
102
103 #define UP_2_2X(N3, N1, PIXEL)\
104     ALPHA_BLEND_192_W(E[N3], PIXEL); \
105     ALPHA_BLEND_64_W( E[N1], PIXEL); \
106
107 #define DIA_2X(N3, PIXEL)\
108     ALPHA_BLEND_128_W(E[N3], PIXEL); \
109
110 #define eq(A, B, r2y)\
111     (df(A, B, r2y) < 155)\
112
113 #define FILTRO(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, N0, N1, N2, N3,r2y) \
114      ex   = (PE!=PH && PE!=PF); \
115      if ( ex )\
116      {\
117           e = (df(PE,PC,r2y)+df(PE,PG,r2y)+df(PI,H5,r2y)+df(PI,F4,r2y))+(df(PH,PF,r2y)<<2); \
118           i = (df(PH,PD,r2y)+df(PH,I5,r2y)+df(PF,I4,r2y)+df(PF,PB,r2y))+(df(PE,PI,r2y)<<2); \
119           if ((e<i)  && ( !eq(PF,PB,r2y) && !eq(PH,PD,r2y) || eq(PE,PI,r2y) && (!eq(PF,I4,r2y) && !eq(PH,I5,r2y)) || eq(PE,PG,r2y) || eq(PE,PC,r2y)) )\
120           {\
121               ke=df(PF,PG,r2y); ki=df(PH,PC,r2y); \
122               ex2 = (PE!=PC && PB!=PC); ex3 = (PE!=PG && PD!=PG); px = (df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH; \
123               if ( ((ke<<1)<=ki) && ex3 && (ke>=(ki<<1)) && ex2 ) \
124               {\
125                      LEFT_UP_2_2X(N3, N2, N1, px)\
126               }\
127               else if ( ((ke<<1)<=ki) && ex3 ) \
128               {\
129                      LEFT_2_2X(N3, N2, px);\
130               }\
131               else if ( (ke>=(ki<<1)) && ex2 ) \
132               {\
133                      UP_2_2X(N3, N1, px);\
134               }\
135               else \
136               {\
137                      DIA_2X(N3, px);\
138               }\
139           }\
140           else if (e<=i)\
141           {\
142                ALPHA_BLEND_128_W( E[N3], ((df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH)); \
143           }\
144      }\
145
146 static void xbr2x(AVFrame * input, AVFrame * output, const uint32_t * r2y)
147 {
148     unsigned int e, i,px;
149     unsigned int ex, ex2, ex3;
150     unsigned int ke, ki;
151     int x,y;
152
153     int next_line = output->linesize[0]>>2;
154
155     for (y = 0; y < input->height; y++) {
156
157         uint32_t pprev;
158         uint32_t pprev2;
159
160         uint32_t * E = (uint32_t *)(output->data[0] + y * output->linesize[0] * 2);
161
162         /* middle. Offset of -8 is given */
163         uint32_t * sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8);
164         /* up one */
165         uint32_t * sa1 = sa2 - (input->linesize[0]>>2);
166         /* up two */
167         uint32_t * sa0 = sa1 - (input->linesize[0]>>2);
168         /* down one */
169         uint32_t * sa3 = sa2 + (input->linesize[0]>>2);
170         /* down two */
171         uint32_t * sa4 = sa3 + (input->linesize[0]>>2);
172
173         if (y <= 1) {
174             sa0 = sa1;
175             if (y == 0) {
176                 sa0 = sa1 = sa2;
177             }
178         }
179
180         if (y >= input->height - 2) {
181             sa4 = sa3;
182             if (y == input->height - 1) {
183                 sa4 = sa3 = sa2;
184             }
185         }
186
187         pprev = pprev2 = 2;
188
189         for (x = 0; x < input->width; x++) {
190             uint32_t B1 = sa0[2];
191             uint32_t PB = sa1[2];
192             uint32_t PE = sa2[2];
193             uint32_t PH = sa3[2];
194             uint32_t H5 = sa4[2];
195
196             uint32_t A1 = sa0[pprev];
197             uint32_t PA = sa1[pprev];
198             uint32_t PD = sa2[pprev];
199             uint32_t PG = sa3[pprev];
200             uint32_t G5 = sa4[pprev];
201
202             uint32_t A0 = sa1[pprev2];
203             uint32_t D0 = sa2[pprev2];
204             uint32_t G0 = sa3[pprev2];
205
206             uint32_t C1 = 0;
207             uint32_t PC = 0;
208             uint32_t PF = 0;
209             uint32_t PI = 0;
210             uint32_t I5 = 0;
211
212             uint32_t C4 = 0;
213             uint32_t F4 = 0;
214             uint32_t I4 = 0;
215
216             if (x >= input->width - 2) {
217                 if (x == input->width - 1) {
218                     C1 = sa0[2];
219                     PC = sa1[2];
220                     PF = sa2[2];
221                     PI = sa3[2];
222                     I5 = sa4[2];
223
224                     C4 = sa1[2];
225                     F4 = sa2[2];
226                     I4 = sa3[2];
227                 } else {
228                     C1 = sa0[3];
229                     PC = sa1[3];
230                     PF = sa2[3];
231                     PI = sa3[3];
232                     I5 = sa4[3];
233
234                     C4 = sa1[3];
235                     F4 = sa2[3];
236                     I4 = sa3[3];
237                 }
238             } else {
239                 C1 = sa0[3];
240                 PC = sa1[3];
241                 PF = sa2[3];
242                 PI = sa3[3];
243                 I5 = sa4[3];
244
245                 C4 = sa1[4];
246                 F4 = sa2[4];
247                 I4 = sa3[4];
248             }
249
250             E[0] = E[1] = E[next_line] = E[next_line + 1] = PE; // 0, 1, 2, 3
251
252             FILTRO(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, 0, 1, next_line, next_line+1,r2y);
253             FILTRO(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, next_line, 0, next_line+1, 1,r2y);
254             FILTRO(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, next_line+1, next_line, 1, 0,r2y);
255             FILTRO(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, 1, next_line+1, 0, next_line,r2y);
256
257             sa0 += 1;
258             sa1 += 1;
259             sa2 += 1;
260             sa3 += 1;
261             sa4 += 1;
262
263             E += 2;
264
265             if (pprev2){
266                 pprev2--;
267                 pprev = 1;
268             }
269         }
270     }
271 }
272 #undef FILTRO
273
274 #define LEFT_UP_2_3X(N7, N5, N6, N2, N8, PIXEL)\
275     ALPHA_BLEND_192_W(E[N7], PIXEL); \
276     ALPHA_BLEND_64_W( E[N6], PIXEL); \
277     E[N5] = E[N7]; \
278     E[N2] = E[N6]; \
279     E[N8] =  PIXEL;\
280
281 #define LEFT_2_3X(N7, N5, N6, N8, PIXEL)\
282     ALPHA_BLEND_192_W(E[N7], PIXEL); \
283     ALPHA_BLEND_64_W( E[N5], PIXEL); \
284     ALPHA_BLEND_64_W( E[N6], PIXEL); \
285     E[N8] =  PIXEL;\
286
287 #define UP_2_3X(N5, N7, N2, N8, PIXEL)\
288     ALPHA_BLEND_192_W(E[N5], PIXEL); \
289     ALPHA_BLEND_64_W( E[N7], PIXEL); \
290     ALPHA_BLEND_64_W( E[N2], PIXEL); \
291     E[N8] =  PIXEL;\
292
293 #define DIA_3X(N8, N5, N7, PIXEL)\
294     ALPHA_BLEND_224_W(E[N8], PIXEL); \
295     ALPHA_BLEND_32_W(E[N5], PIXEL); \
296     ALPHA_BLEND_32_W(E[N7], PIXEL); \
297
298 #define FILTRO(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, N0, N1, N2, N3, N4, N5, N6, N7, N8,r2y) \
299      ex   = (PE!=PH && PE!=PF); \
300      if ( ex )\
301      {\
302           e = (df(PE,PC,r2y)+df(PE,PG,r2y)+df(PI,H5,r2y)+df(PI,F4,r2y))+(df(PH,PF,r2y)<<2); \
303           i = (df(PH,PD,r2y)+df(PH,I5,r2y)+df(PF,I4,r2y)+df(PF,PB,r2y))+(df(PE,PI,r2y)<<2); \
304           if ((e<i)  && ( !eq(PF,PB,r2y) && !eq(PF,PC,r2y) || !eq(PH,PD,r2y) && !eq(PH,PG,r2y) || eq(PE,PI,r2y) && (!eq(PF,F4,r2y) && !eq(PF,I4,r2y) || !eq(PH,H5,r2y) && !eq(PH,I5,r2y)) || eq(PE,PG,r2y) || eq(PE,PC,r2y)) )\
305           {\
306               ke=df(PF,PG,r2y); ki=df(PH,PC,r2y); \
307               ex2 = (PE!=PC && PB!=PC); ex3 = (PE!=PG && PD!=PG); px = (df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH; \
308               if ( ((ke<<1)<=ki) && ex3 && (ke>=(ki<<1)) && ex2 ) \
309               {\
310                      LEFT_UP_2_3X(N7, N5, N6, N2, N8, px)\
311               }\
312               else if ( ((ke<<1)<=ki) && ex3 ) \
313               {\
314                      LEFT_2_3X(N7, N5, N6, N8, px);\
315               }\
316               else if ( (ke>=(ki<<1)) && ex2 ) \
317               {\
318                      UP_2_3X(N5, N7, N2, N8, px);\
319               }\
320               else \
321               {\
322                      DIA_3X(N8, N5, N7, px);\
323               }\
324           }\
325           else if (e<=i)\
326           {\
327                ALPHA_BLEND_128_W( E[N8], ((df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH)); \
328           }\
329      }\
330
331 static void xbr3x(AVFrame *input, AVFrame *output, const uint32_t *r2y)
332 {
333     const int nl = output->linesize[0]>>2;
334     const int nl1 = nl + nl;
335
336     unsigned int e, i,px;
337     unsigned int ex, ex2, ex3;
338     unsigned int ke, ki;
339
340     uint32_t pprev;
341     uint32_t pprev2;
342
343     int x,y;
344
345     for (y = 0; y < input->height; y++) {
346
347         uint32_t * E = (uint32_t *)(output->data[0] + y * output->linesize[0] * 3);
348
349         /* middle. Offset of -8 is given */
350         uint32_t * sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8);
351         /* up one */
352         uint32_t * sa1 = sa2 - (input->linesize[0]>>2);
353         /* up two */
354         uint32_t * sa0 = sa1 - (input->linesize[0]>>2);
355         /* down one */
356         uint32_t * sa3 = sa2 + (input->linesize[0]>>2);
357         /* down two */
358         uint32_t * sa4 = sa3 + (input->linesize[0]>>2);
359
360         if (y <= 1){
361             sa0 = sa1;
362             if (y == 0){
363                 sa0 = sa1 = sa2;
364             }
365         }
366
367         if (y >= input->height - 2){
368             sa4 = sa3;
369             if (y == input->height - 1){
370                 sa4 = sa3 = sa2;
371             }
372         }
373
374         pprev = pprev2 = 2;
375
376         for (x = 0; x < input->width; x++){
377             uint32_t B1 = sa0[2];
378             uint32_t PB = sa1[2];
379             uint32_t PE = sa2[2];
380             uint32_t PH = sa3[2];
381             uint32_t H5 = sa4[2];
382
383             uint32_t A1 = sa0[pprev];
384             uint32_t PA = sa1[pprev];
385             uint32_t PD = sa2[pprev];
386             uint32_t PG = sa3[pprev];
387             uint32_t G5 = sa4[pprev];
388
389             uint32_t A0 = sa1[pprev2];
390             uint32_t D0 = sa2[pprev2];
391             uint32_t G0 = sa3[pprev2];
392
393             uint32_t C1 = 0;
394             uint32_t PC = 0;
395             uint32_t PF = 0;
396             uint32_t PI = 0;
397             uint32_t I5 = 0;
398
399             uint32_t C4 = 0;
400             uint32_t F4 = 0;
401             uint32_t I4 = 0;
402
403             if (x >= input->width - 2){
404                 if (x == input->width - 1){
405                     C1 = sa0[2];
406                     PC = sa1[2];
407                     PF = sa2[2];
408                     PI = sa3[2];
409                     I5 = sa4[2];
410
411                     C4 = sa1[2];
412                     F4 = sa2[2];
413                     I4 = sa3[2];
414                 } else {
415                     C1 = sa0[3];
416                     PC = sa1[3];
417                     PF = sa2[3];
418                     PI = sa3[3];
419                     I5 = sa4[3];
420
421                     C4 = sa1[3];
422                     F4 = sa2[3];
423                     I4 = sa3[3];
424                 }
425             } else {
426                 C1 = sa0[3];
427                 PC = sa1[3];
428                 PF = sa2[3];
429                 PI = sa3[3];
430                 I5 = sa4[3];
431
432                 C4 = sa1[4];
433                 F4 = sa2[4];
434                 I4 = sa3[4];
435             }
436
437             E[0]   = E[1]     = E[2]     = PE;
438             E[nl]  = E[nl+1]  = E[nl+2]  = PE; // 3, 4, 5
439             E[nl1] = E[nl1+1] = E[nl1+2] = PE; // 6, 7, 8
440
441             FILTRO(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, 0, 1, 2, nl, nl+1, nl+2, nl1, nl1+1, nl1+2,r2y);
442             FILTRO(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, nl1, nl, 0, nl1+1, nl+1, 1, nl1+2, nl+2, 2,r2y);
443             FILTRO(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, nl1+2, nl1+1, nl1, nl+2, nl+1, nl, 2, 1, 0,r2y);
444             FILTRO(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, 2, nl+2, nl1+2, 1, nl+1, nl1+1, 0, nl, nl1,r2y);
445
446             sa0 += 1;
447             sa1 += 1;
448             sa2 += 1;
449             sa3 += 1;
450             sa4 += 1;
451
452             E += 3;
453
454             if (pprev2){
455                 pprev2--;
456                 pprev = 1;
457             }
458         }
459     }
460 }
461 #undef FILTRO
462
463 #define LEFT_UP_2(N15, N14, N11, N13, N12, N10, N7, N3, PIXEL)\
464     ALPHA_BLEND_192_W(E[N13], PIXEL); \
465     ALPHA_BLEND_64_W( E[N12], PIXEL); \
466     E[N15] = E[N14] = E[N11] = PIXEL; \
467     E[N10] = E[N3] = E[N12]; \
468     E[N7]  = E[N13]; \
469
470 #define LEFT_2(N15, N14, N11, N13, N12, N10, PIXEL)\
471     ALPHA_BLEND_192_W(E[N11], PIXEL); \
472     ALPHA_BLEND_192_W(E[N13], PIXEL); \
473     ALPHA_BLEND_64_W( E[N10], PIXEL); \
474     ALPHA_BLEND_64_W( E[N12], PIXEL); \
475     E[N14] = PIXEL; \
476     E[N15] = PIXEL; \
477
478 #define UP_2(N15, N14, N11, N3, N7, N10, PIXEL)\
479     ALPHA_BLEND_192_W(E[N14], PIXEL); \
480     ALPHA_BLEND_192_W(E[N7 ], PIXEL); \
481     ALPHA_BLEND_64_W( E[N10], PIXEL); \
482     ALPHA_BLEND_64_W( E[N3 ], PIXEL); \
483     E[N11] = PIXEL; \
484     E[N15] = PIXEL; \
485
486 #define DIA(N15, N14, N11, PIXEL)\
487     ALPHA_BLEND_128_W(E[N11], PIXEL); \
488     ALPHA_BLEND_128_W(E[N14], PIXEL); \
489     E[N15] = PIXEL; \
490
491 #define FILTRO(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, N15, N14, N11, N3, N7, N10, N13, N12, N9, N6, N2, N1, N5, N8, N4, N0,r2y) \
492      ex   = (PE!=PH && PE!=PF); \
493      if ( ex )\
494      {\
495           e = (df(PE,PC,r2y)+df(PE,PG,r2y)+df(PI,H5,r2y)+df(PI,F4,r2y))+(df(PH,PF,r2y)<<2); \
496           i = (df(PH,PD,r2y)+df(PH,I5,r2y)+df(PF,I4,r2y)+df(PF,PB,r2y))+(df(PE,PI,r2y)<<2); \
497           if ((e<i)  && ( !eq(PF,PB,r2y) && !eq(PH,PD,r2y) || eq(PE,PI,r2y) && (!eq(PF,I4,r2y) && !eq(PH,I5,r2y)) || eq(PE,PG,r2y) || eq(PE,PC,r2y)) )\
498           {\
499               ke=df(PF,PG,r2y); ki=df(PH,PC,r2y); \
500               ex2 = (PE!=PC && PB!=PC); ex3 = (PE!=PG && PD!=PG); px = (df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH; \
501               if ( ((ke<<1)<=ki) && ex3 && (ke>=(ki<<1)) && ex2 ) \
502               {\
503                      LEFT_UP_2(N15, N14, N11, N13, N12, N10, N7, N3, px)\
504               }\
505               else if ( ((ke<<1)<=ki) && ex3 ) \
506               {\
507                      LEFT_2(N15, N14, N11, N13, N12, N10, px)\
508               }\
509               else if ( (ke>=(ki<<1)) && ex2 ) \
510               {\
511                      UP_2(N15, N14, N11, N3, N7, N10, px)\
512               }\
513               else \
514               {\
515                      DIA(N15, N14, N11, px)\
516               }\
517           }\
518           else if (e<=i)\
519           {\
520                ALPHA_BLEND_128_W( E[N15], ((df(PE,PF,r2y) <= df(PE,PH,r2y)) ? PF : PH)); \
521           }\
522      }\
523
524 static void xbr4x(AVFrame *input, AVFrame *output, const uint32_t *r2y)
525 {
526
527     const int nl = output->linesize[0]>>2;
528     const int nl1 = nl + nl;
529     const int nl2 = nl1 + nl;
530
531     unsigned int e, i, px;
532     unsigned int ex, ex2, ex3;
533     unsigned int ke, ki;
534
535     uint32_t pprev;
536     uint32_t pprev2;
537
538     int x, y;
539
540     for (y = 0; y < input->height; y++) {
541
542         uint32_t * E = (uint32_t *)(output->data[0] + y * output->linesize[0] * 4);
543
544         /* middle. Offset of -8 is given */
545         uint32_t * sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8);
546         /* up one */
547         uint32_t * sa1 = sa2 - (input->linesize[0]>>2);
548         /* up two */
549         uint32_t * sa0 = sa1 - (input->linesize[0]>>2);
550         /* down one */
551         uint32_t * sa3 = sa2 + (input->linesize[0]>>2);
552         /* down two */
553         uint32_t * sa4 = sa3 + (input->linesize[0]>>2);
554
555         if (y <= 1) {
556             sa0 = sa1;
557             if (y == 0) {
558                 sa0 = sa1 = sa2;
559             }
560         }
561
562         if (y >= input->height - 2) {
563             sa4 = sa3;
564             if (y == input->height - 1) {
565                 sa4 = sa3 = sa2;
566             }
567         }
568
569         pprev = pprev2 = 2;
570
571         for (x = 0; x < input->width; x++) {
572             uint32_t B1 = sa0[2];
573             uint32_t PB = sa1[2];
574             uint32_t PE = sa2[2];
575             uint32_t PH = sa3[2];
576             uint32_t H5 = sa4[2];
577
578             uint32_t A1 = sa0[pprev];
579             uint32_t PA = sa1[pprev];
580             uint32_t PD = sa2[pprev];
581             uint32_t PG = sa3[pprev];
582             uint32_t G5 = sa4[pprev];
583
584             uint32_t A0 = sa1[pprev2];
585             uint32_t D0 = sa2[pprev2];
586             uint32_t G0 = sa3[pprev2];
587
588             uint32_t C1 = 0;
589             uint32_t PC = 0;
590             uint32_t PF = 0;
591             uint32_t PI = 0;
592             uint32_t I5 = 0;
593
594             uint32_t C4 = 0;
595             uint32_t F4 = 0;
596             uint32_t I4 = 0;
597
598             if (x >= input->width - 2) {
599                 if (x == input->width - 1) {
600                     C1 = sa0[2];
601                     PC = sa1[2];
602                     PF = sa2[2];
603                     PI = sa3[2];
604                     I5 = sa4[2];
605
606                     C4 = sa1[2];
607                     F4 = sa2[2];
608                     I4 = sa3[2];
609                 } else {
610                     C1 = sa0[3];
611                     PC = sa1[3];
612                     PF = sa2[3];
613                     PI = sa3[3];
614                     I5 = sa4[3];
615
616                     C4 = sa1[3];
617                     F4 = sa2[3];
618                     I4 = sa3[3];
619                 }
620             } else {
621                 C1 = sa0[3];
622                 PC = sa1[3];
623                 PF = sa2[3];
624                 PI = sa3[3];
625                 I5 = sa4[3];
626
627                 C4 = sa1[4];
628                 F4 = sa2[4];
629                 I4 = sa3[4];
630             }
631
632             E[0]   = E[1]     = E[2]     = E[3]     = PE;
633             E[nl]  = E[nl+1]  = E[nl+2]  = E[nl+3]  = PE; //  4,  5,  6,  7
634             E[nl1] = E[nl1+1] = E[nl1+2] = E[nl1+3] = PE; //  8,  9, 10, 11
635             E[nl2] = E[nl2+1] = E[nl2+2] = E[nl2+3] = PE; // 12, 13, 14, 15
636
637             FILTRO(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, nl2+3, nl2+2, nl1+3,  3,  nl+3, nl1+2, nl2+1, nl2,  nl1+1,  nl+2, 2,  1, nl+1, nl1, nl, 0,r2y);
638             FILTRO(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0,  3,  nl+3,  2,  0,  1,  nl+2, nl1+3, nl2+3, nl1+2,  nl+1, nl,  nl1, nl1+1,nl2+2,nl2+1,nl2,r2y);
639             FILTRO(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5,  0,  1,  nl, nl2,  nl1,  nl+1,  2,  3,  nl+2,  nl1+1, nl2+1,nl2+2,nl1+2, nl+3,nl1+3,nl2+3,r2y);
640             FILTRO(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, nl2,  nl1, nl2+1, nl2+3, nl2+2,  nl1+1,  nl,  0,  nl+1, nl1+2, nl1+3, nl+3, nl+2, 1, 2, 3,r2y);
641
642             sa0 += 1;
643             sa1 += 1;
644             sa2 += 1;
645             sa3 += 1;
646             sa4 += 1;
647
648             E += 4;
649
650             if (pprev2){
651                 pprev2--;
652                 pprev = 1;
653             }
654         }
655     }
656 }
657 #undef FILTRO
658
659 static int config_output(AVFilterLink *outlink)
660 {
661     AVFilterContext *ctx = outlink->src;
662     XBRContext *xbr = ctx->priv;
663     AVFilterLink *inlink = ctx->inputs[0];
664
665     outlink->w = inlink->w * xbr->n;
666     outlink->h = inlink->h * xbr->n;
667     return 0;
668 }
669
670 static int query_formats(AVFilterContext *ctx)
671 {
672     static const enum AVPixelFormat pix_fmts[] = {
673         AV_PIX_FMT_0RGB32, AV_PIX_FMT_NONE,
674     };
675
676     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
677     return 0;
678 }
679
680 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
681 {
682     AVFilterContext *ctx = inlink->dst;
683     AVFilterLink *outlink = ctx->outputs[0];
684     XBRContext *xbr = ctx->priv;
685     const uint32_t *r2y = xbr->rgbtoyuv;
686
687     AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
688     if (!out) {
689         av_frame_free(&in);
690         return AVERROR(ENOMEM);
691     }
692
693     av_frame_copy_props(out, in);
694     if (xbr->n == 4)
695         xbr4x(in, out, r2y);
696     else if (xbr->n == 3)
697         xbr3x(in, out, r2y);
698     else
699         xbr2x(in, out, r2y);
700
701     out->width  = outlink->w;
702     out->height = outlink->h;
703
704     av_frame_free(&in);
705     return ff_filter_frame(outlink, out);
706 }
707
708 static int init(AVFilterContext *ctx)
709 {
710     XBRContext *xbr = ctx->priv;
711     uint32_t c;
712     int bg, rg, g;
713
714     for (bg = -255; bg < 256; bg++) {
715         for (rg = -255; rg < 256; rg++) {
716             const uint32_t u = (uint32_t)((-169*rg + 500*bg)/1000) + 128;
717             const uint32_t v = (uint32_t)(( 500*rg -  81*bg)/1000) + 128;
718             int startg = FFMAX3(-bg, -rg, 0);
719             int endg = FFMIN3(255-bg, 255-rg, 255);
720             uint32_t y = (uint32_t)(( 299*rg + 1000*startg + 114*bg)/1000);
721             c = bg + (rg<<16) + 0x010101 * startg;
722             for (g = startg; g <= endg; g++) {
723                 xbr->rgbtoyuv[c] = ((y++) << 16) + (u << 8) + v;
724                 c+= 0x010101;
725             }
726         }
727     }
728
729     return 0;
730 }
731
732 static const AVFilterPad xbr_inputs[] = {
733     {
734         .name         = "default",
735         .type         = AVMEDIA_TYPE_VIDEO,
736         .filter_frame = filter_frame,
737     },
738     { NULL }
739 };
740
741 static const AVFilterPad xbr_outputs[] = {
742     {
743         .name         = "default",
744         .type         = AVMEDIA_TYPE_VIDEO,
745         .config_props = config_output,
746     },
747     { NULL }
748 };
749
750 AVFilter ff_vf_xbr = {
751     .name          = "xbr",
752     .description   = NULL_IF_CONFIG_SMALL("Scale the input using xBR algorithm."),
753     .inputs        = xbr_inputs,
754     .outputs       = xbr_outputs,
755     .query_formats = query_formats,
756     .priv_size     = sizeof(XBRContext),
757     .priv_class    = &xbr_class,
758     .init          = init,
759 };