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