]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_xbr.c
avfilter/xbr: use different macro names for each dimension
[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
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (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 GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License 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  * 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 pixel_diff(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 df(A, B) pixel_diff(A, B, r2y)
95
96 #define eq(A, B)\
97     (df(A, B) < 155)\
98
99 #define FILT2(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) do { \
100      unsigned ex = (PE!=PH && PE!=PF); \
101      if ( ex )\
102      {\
103           unsigned e = (df(PE,PC)+df(PE,PG)+df(PI,H5)+df(PI,F4))+(df(PH,PF)<<2); \
104           unsigned i = (df(PH,PD)+df(PH,I5)+df(PF,I4)+df(PF,PB))+(df(PE,PI)<<2); \
105           if ((e<i)  && ( !eq(PF,PB) && !eq(PH,PD) || eq(PE,PI) && (!eq(PF,I4) && !eq(PH,I5)) || eq(PE,PG) || eq(PE,PC)) )\
106           {\
107               unsigned ke = df(PF,PG); \
108               unsigned ki = df(PH,PC); \
109               unsigned ex2 = (PE!=PC && PB!=PC); \
110               unsigned ex3 = (PE!=PG && PD!=PG); \
111               unsigned px = (df(PE,PF) <= df(PE,PH)) ? PF : PH; \
112               if (ke<<1 <= ki && ex3 && ke >= ki<<1 && ex2) { /* left-up */ \
113                   ALPHA_BLEND_224_W(E[N3], px); \
114                   ALPHA_BLEND_64_W( E[N2], px); \
115                   E[N1] = E[N2]; \
116               } else if (ke<<1 <= ki && ex3) { /* left */ \
117                   ALPHA_BLEND_192_W(E[N3], px); \
118                   ALPHA_BLEND_64_W( E[N2], px); \
119               } else if (ke >= ki<<1 && ex2) { /* up */ \
120                   ALPHA_BLEND_192_W(E[N3], px); \
121                   ALPHA_BLEND_64_W( E[N1], px); \
122               } else { /* diagonal */ \
123                   ALPHA_BLEND_128_W(E[N3], px); \
124               }\
125           }\
126           else if (e<=i)\
127           {\
128                ALPHA_BLEND_128_W( E[N3], ((df(PE,PF) <= df(PE,PH)) ? PF : PH)); \
129           }\
130      }\
131 } while (0)
132
133 static void xbr2x(AVFrame * input, AVFrame * output, const uint32_t * r2y)
134 {
135     int x,y;
136     int next_line = output->linesize[0]>>2;
137
138     for (y = 0; y < input->height; y++) {
139
140         uint32_t pprev;
141         uint32_t pprev2;
142
143         uint32_t * E = (uint32_t *)(output->data[0] + y * output->linesize[0] * 2);
144
145         /* middle. Offset of -8 is given */
146         uint32_t * sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8);
147         /* up one */
148         uint32_t * sa1 = sa2 - (input->linesize[0]>>2);
149         /* up two */
150         uint32_t * sa0 = sa1 - (input->linesize[0]>>2);
151         /* down one */
152         uint32_t * sa3 = sa2 + (input->linesize[0]>>2);
153         /* down two */
154         uint32_t * sa4 = sa3 + (input->linesize[0]>>2);
155
156         if (y <= 1) {
157             sa0 = sa1;
158             if (y == 0) {
159                 sa0 = sa1 = sa2;
160             }
161         }
162
163         if (y >= input->height - 2) {
164             sa4 = sa3;
165             if (y == input->height - 1) {
166                 sa4 = sa3 = sa2;
167             }
168         }
169
170         pprev = pprev2 = 2;
171
172         for (x = 0; x < input->width; x++) {
173             uint32_t B1 = sa0[2];
174             uint32_t PB = sa1[2];
175             uint32_t PE = sa2[2];
176             uint32_t PH = sa3[2];
177             uint32_t H5 = sa4[2];
178
179             uint32_t A1 = sa0[pprev];
180             uint32_t PA = sa1[pprev];
181             uint32_t PD = sa2[pprev];
182             uint32_t PG = sa3[pprev];
183             uint32_t G5 = sa4[pprev];
184
185             uint32_t A0 = sa1[pprev2];
186             uint32_t D0 = sa2[pprev2];
187             uint32_t G0 = sa3[pprev2];
188
189             uint32_t C1 = 0;
190             uint32_t PC = 0;
191             uint32_t PF = 0;
192             uint32_t PI = 0;
193             uint32_t I5 = 0;
194
195             uint32_t C4 = 0;
196             uint32_t F4 = 0;
197             uint32_t I4 = 0;
198
199             if (x >= input->width - 2) {
200                 if (x == input->width - 1) {
201                     C1 = sa0[2];
202                     PC = sa1[2];
203                     PF = sa2[2];
204                     PI = sa3[2];
205                     I5 = sa4[2];
206
207                     C4 = sa1[2];
208                     F4 = sa2[2];
209                     I4 = sa3[2];
210                 } else {
211                     C1 = sa0[3];
212                     PC = sa1[3];
213                     PF = sa2[3];
214                     PI = sa3[3];
215                     I5 = sa4[3];
216
217                     C4 = sa1[3];
218                     F4 = sa2[3];
219                     I4 = sa3[3];
220                 }
221             } else {
222                 C1 = sa0[3];
223                 PC = sa1[3];
224                 PF = sa2[3];
225                 PI = sa3[3];
226                 I5 = sa4[3];
227
228                 C4 = sa1[4];
229                 F4 = sa2[4];
230                 I4 = sa3[4];
231             }
232
233             E[0] = E[1] = E[next_line] = E[next_line + 1] = PE; // 0, 1, 2, 3
234
235             FILT2(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);
236             FILT2(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);
237             FILT2(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);
238             FILT2(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);
239
240             sa0 += 1;
241             sa1 += 1;
242             sa2 += 1;
243             sa3 += 1;
244             sa4 += 1;
245
246             E += 2;
247
248             if (pprev2){
249                 pprev2--;
250                 pprev = 1;
251             }
252         }
253     }
254 }
255
256 #define FILT3(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) do { \
257      unsigned ex = (PE!=PH && PE!=PF); \
258      if ( ex )\
259      {\
260           unsigned e = (df(PE,PC)+df(PE,PG)+df(PI,H5)+df(PI,F4))+(df(PH,PF)<<2); \
261           unsigned i = (df(PH,PD)+df(PH,I5)+df(PF,I4)+df(PF,PB))+(df(PE,PI)<<2); \
262           if ((e<i)  && ( !eq(PF,PB) && !eq(PF,PC) || !eq(PH,PD) && !eq(PH,PG) || eq(PE,PI) && (!eq(PF,F4) && !eq(PF,I4) || !eq(PH,H5) && !eq(PH,I5)) || eq(PE,PG) || eq(PE,PC)) )\
263           {\
264               unsigned ke = df(PF,PG); \
265               unsigned ki = df(PH,PC); \
266               unsigned ex2 = (PE!=PC && PB!=PC); \
267               unsigned ex3 = (PE!=PG && PD!=PG); \
268               unsigned px = (df(PE,PF) <= df(PE,PH)) ? PF : PH; \
269               if (ke<<1 <= ki && ex3 && ke >= ki<<1 && ex2) { /* left-up */ \
270                   ALPHA_BLEND_192_W(E[N7], px); \
271                   ALPHA_BLEND_64_W( E[N6], px); \
272                   E[N5] = E[N7]; \
273                   E[N2] = E[N6]; \
274                   E[N8] = px;\
275               } else if (ke<<1 <= ki && ex3) { /* left */ \
276                   ALPHA_BLEND_192_W(E[N7], px); \
277                   ALPHA_BLEND_64_W( E[N5], px); \
278                   ALPHA_BLEND_64_W( E[N6], px); \
279                   E[N8] = px;\
280               } else if (ke >= ki<<1 && ex2) { /* up */ \
281                   ALPHA_BLEND_192_W(E[N5], px); \
282                   ALPHA_BLEND_64_W( E[N7], px); \
283                   ALPHA_BLEND_64_W( E[N2], px); \
284                   E[N8] = px;\
285               } else { /* diagonal */ \
286                   ALPHA_BLEND_224_W(E[N8], px); \
287                   ALPHA_BLEND_32_W(E[N5], px); \
288                   ALPHA_BLEND_32_W(E[N7], px); \
289               }\
290           }\
291           else if (e<=i)\
292           {\
293                ALPHA_BLEND_128_W( E[N8], ((df(PE,PF) <= df(PE,PH)) ? PF : PH)); \
294           }\
295      }\
296 } while (0)
297
298 static void xbr3x(AVFrame *input, AVFrame *output, const uint32_t *r2y)
299 {
300     const int nl = output->linesize[0]>>2;
301     const int nl1 = nl + nl;
302     uint32_t pprev;
303     uint32_t pprev2;
304
305     int x,y;
306
307     for (y = 0; y < input->height; y++) {
308
309         uint32_t * E = (uint32_t *)(output->data[0] + y * output->linesize[0] * 3);
310
311         /* middle. Offset of -8 is given */
312         uint32_t * sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8);
313         /* up one */
314         uint32_t * sa1 = sa2 - (input->linesize[0]>>2);
315         /* up two */
316         uint32_t * sa0 = sa1 - (input->linesize[0]>>2);
317         /* down one */
318         uint32_t * sa3 = sa2 + (input->linesize[0]>>2);
319         /* down two */
320         uint32_t * sa4 = sa3 + (input->linesize[0]>>2);
321
322         if (y <= 1){
323             sa0 = sa1;
324             if (y == 0){
325                 sa0 = sa1 = sa2;
326             }
327         }
328
329         if (y >= input->height - 2){
330             sa4 = sa3;
331             if (y == input->height - 1){
332                 sa4 = sa3 = sa2;
333             }
334         }
335
336         pprev = pprev2 = 2;
337
338         for (x = 0; x < input->width; x++){
339             uint32_t B1 = sa0[2];
340             uint32_t PB = sa1[2];
341             uint32_t PE = sa2[2];
342             uint32_t PH = sa3[2];
343             uint32_t H5 = sa4[2];
344
345             uint32_t A1 = sa0[pprev];
346             uint32_t PA = sa1[pprev];
347             uint32_t PD = sa2[pprev];
348             uint32_t PG = sa3[pprev];
349             uint32_t G5 = sa4[pprev];
350
351             uint32_t A0 = sa1[pprev2];
352             uint32_t D0 = sa2[pprev2];
353             uint32_t G0 = sa3[pprev2];
354
355             uint32_t C1 = 0;
356             uint32_t PC = 0;
357             uint32_t PF = 0;
358             uint32_t PI = 0;
359             uint32_t I5 = 0;
360
361             uint32_t C4 = 0;
362             uint32_t F4 = 0;
363             uint32_t I4 = 0;
364
365             if (x >= input->width - 2){
366                 if (x == input->width - 1){
367                     C1 = sa0[2];
368                     PC = sa1[2];
369                     PF = sa2[2];
370                     PI = sa3[2];
371                     I5 = sa4[2];
372
373                     C4 = sa1[2];
374                     F4 = sa2[2];
375                     I4 = sa3[2];
376                 } else {
377                     C1 = sa0[3];
378                     PC = sa1[3];
379                     PF = sa2[3];
380                     PI = sa3[3];
381                     I5 = sa4[3];
382
383                     C4 = sa1[3];
384                     F4 = sa2[3];
385                     I4 = sa3[3];
386                 }
387             } else {
388                 C1 = sa0[3];
389                 PC = sa1[3];
390                 PF = sa2[3];
391                 PI = sa3[3];
392                 I5 = sa4[3];
393
394                 C4 = sa1[4];
395                 F4 = sa2[4];
396                 I4 = sa3[4];
397             }
398
399             E[0]   = E[1]     = E[2]     = PE;
400             E[nl]  = E[nl+1]  = E[nl+2]  = PE; // 3, 4, 5
401             E[nl1] = E[nl1+1] = E[nl1+2] = PE; // 6, 7, 8
402
403             FILT3(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);
404             FILT3(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);
405             FILT3(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);
406             FILT3(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);
407
408             sa0 += 1;
409             sa1 += 1;
410             sa2 += 1;
411             sa3 += 1;
412             sa4 += 1;
413
414             E += 3;
415
416             if (pprev2){
417                 pprev2--;
418                 pprev = 1;
419             }
420         }
421     }
422 }
423
424 #define FILT4(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) do { \
425      unsigned ex   = (PE!=PH && PE!=PF); \
426      if ( ex )\
427      {\
428           unsigned e = (df(PE,PC)+df(PE,PG)+df(PI,H5)+df(PI,F4))+(df(PH,PF)<<2); \
429           unsigned i = (df(PH,PD)+df(PH,I5)+df(PF,I4)+df(PF,PB))+(df(PE,PI)<<2); \
430           if ((e<i)  && ( !eq(PF,PB) && !eq(PH,PD) || eq(PE,PI) && (!eq(PF,I4) && !eq(PH,I5)) || eq(PE,PG) || eq(PE,PC)) )\
431           {\
432               unsigned ke = df(PF,PG); \
433               unsigned ki = df(PH,PC); \
434               unsigned ex2 = (PE!=PC && PB!=PC); \
435               unsigned ex3 = (PE!=PG && PD!=PG); \
436               unsigned px = (df(PE,PF) <= df(PE,PH)) ? PF : PH; \
437               if (ke<<1 <= ki && ex3 && ke >= ki<<1 && ex2) { /* left-up */ \
438                   ALPHA_BLEND_192_W(E[N13], px); \
439                   ALPHA_BLEND_64_W( E[N12], px); \
440                   E[N15] = E[N14] = E[N11] = px; \
441                   E[N10] = E[N3] = E[N12]; \
442                   E[N7]  = E[N13]; \
443               } else if (ke<<1 <= ki && ex3) { /* left */ \
444                   ALPHA_BLEND_192_W(E[N11], px); \
445                   ALPHA_BLEND_192_W(E[N13], px); \
446                   ALPHA_BLEND_64_W( E[N10], px); \
447                   ALPHA_BLEND_64_W( E[N12], px); \
448                   E[N14] = px; \
449                   E[N15] = px; \
450               } else if (ke >= ki<<1 && ex2) { /* up */ \
451                   ALPHA_BLEND_192_W(E[N14], px); \
452                   ALPHA_BLEND_192_W(E[N7 ], px); \
453                   ALPHA_BLEND_64_W( E[N10], px); \
454                   ALPHA_BLEND_64_W( E[N3 ], px); \
455                   E[N11] = px; \
456                   E[N15] = px; \
457               } else { /* diagonal */ \
458                   ALPHA_BLEND_128_W(E[N11], px); \
459                   ALPHA_BLEND_128_W(E[N14], px); \
460                   E[N15] = px; \
461               }\
462           }\
463           else if (e<=i)\
464           {\
465                ALPHA_BLEND_128_W( E[N15], ((df(PE,PF) <= df(PE,PH)) ? PF : PH)); \
466           }\
467      }\
468 } while (0)
469
470 static void xbr4x(AVFrame *input, AVFrame *output, const uint32_t *r2y)
471 {
472
473     const int nl = output->linesize[0]>>2;
474     const int nl1 = nl + nl;
475     const int nl2 = nl1 + nl;
476     uint32_t pprev;
477     uint32_t pprev2;
478
479     int x, y;
480
481     for (y = 0; y < input->height; y++) {
482
483         uint32_t * E = (uint32_t *)(output->data[0] + y * output->linesize[0] * 4);
484
485         /* middle. Offset of -8 is given */
486         uint32_t * sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8);
487         /* up one */
488         uint32_t * sa1 = sa2 - (input->linesize[0]>>2);
489         /* up two */
490         uint32_t * sa0 = sa1 - (input->linesize[0]>>2);
491         /* down one */
492         uint32_t * sa3 = sa2 + (input->linesize[0]>>2);
493         /* down two */
494         uint32_t * sa4 = sa3 + (input->linesize[0]>>2);
495
496         if (y <= 1) {
497             sa0 = sa1;
498             if (y == 0) {
499                 sa0 = sa1 = sa2;
500             }
501         }
502
503         if (y >= input->height - 2) {
504             sa4 = sa3;
505             if (y == input->height - 1) {
506                 sa4 = sa3 = sa2;
507             }
508         }
509
510         pprev = pprev2 = 2;
511
512         for (x = 0; x < input->width; x++) {
513             uint32_t B1 = sa0[2];
514             uint32_t PB = sa1[2];
515             uint32_t PE = sa2[2];
516             uint32_t PH = sa3[2];
517             uint32_t H5 = sa4[2];
518
519             uint32_t A1 = sa0[pprev];
520             uint32_t PA = sa1[pprev];
521             uint32_t PD = sa2[pprev];
522             uint32_t PG = sa3[pprev];
523             uint32_t G5 = sa4[pprev];
524
525             uint32_t A0 = sa1[pprev2];
526             uint32_t D0 = sa2[pprev2];
527             uint32_t G0 = sa3[pprev2];
528
529             uint32_t C1 = 0;
530             uint32_t PC = 0;
531             uint32_t PF = 0;
532             uint32_t PI = 0;
533             uint32_t I5 = 0;
534
535             uint32_t C4 = 0;
536             uint32_t F4 = 0;
537             uint32_t I4 = 0;
538
539             if (x >= input->width - 2) {
540                 if (x == input->width - 1) {
541                     C1 = sa0[2];
542                     PC = sa1[2];
543                     PF = sa2[2];
544                     PI = sa3[2];
545                     I5 = sa4[2];
546
547                     C4 = sa1[2];
548                     F4 = sa2[2];
549                     I4 = sa3[2];
550                 } else {
551                     C1 = sa0[3];
552                     PC = sa1[3];
553                     PF = sa2[3];
554                     PI = sa3[3];
555                     I5 = sa4[3];
556
557                     C4 = sa1[3];
558                     F4 = sa2[3];
559                     I4 = sa3[3];
560                 }
561             } else {
562                 C1 = sa0[3];
563                 PC = sa1[3];
564                 PF = sa2[3];
565                 PI = sa3[3];
566                 I5 = sa4[3];
567
568                 C4 = sa1[4];
569                 F4 = sa2[4];
570                 I4 = sa3[4];
571             }
572
573             E[0]   = E[1]     = E[2]     = E[3]     = PE;
574             E[nl]  = E[nl+1]  = E[nl+2]  = E[nl+3]  = PE; //  4,  5,  6,  7
575             E[nl1] = E[nl1+1] = E[nl1+2] = E[nl1+3] = PE; //  8,  9, 10, 11
576             E[nl2] = E[nl2+1] = E[nl2+2] = E[nl2+3] = PE; // 12, 13, 14, 15
577
578             FILT4(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);
579             FILT4(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);
580             FILT4(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);
581             FILT4(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);
582
583             sa0 += 1;
584             sa1 += 1;
585             sa2 += 1;
586             sa3 += 1;
587             sa4 += 1;
588
589             E += 4;
590
591             if (pprev2){
592                 pprev2--;
593                 pprev = 1;
594             }
595         }
596     }
597 }
598
599 static int config_output(AVFilterLink *outlink)
600 {
601     AVFilterContext *ctx = outlink->src;
602     XBRContext *xbr = ctx->priv;
603     AVFilterLink *inlink = ctx->inputs[0];
604
605     outlink->w = inlink->w * xbr->n;
606     outlink->h = inlink->h * xbr->n;
607     return 0;
608 }
609
610 static int query_formats(AVFilterContext *ctx)
611 {
612     static const enum AVPixelFormat pix_fmts[] = {
613         AV_PIX_FMT_0RGB32, AV_PIX_FMT_NONE,
614     };
615
616     ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
617     return 0;
618 }
619
620 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
621 {
622     AVFilterContext *ctx = inlink->dst;
623     AVFilterLink *outlink = ctx->outputs[0];
624     XBRContext *xbr = ctx->priv;
625     const uint32_t *r2y = xbr->rgbtoyuv;
626
627     AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
628     if (!out) {
629         av_frame_free(&in);
630         return AVERROR(ENOMEM);
631     }
632
633     av_frame_copy_props(out, in);
634     if (xbr->n == 4)
635         xbr4x(in, out, r2y);
636     else if (xbr->n == 3)
637         xbr3x(in, out, r2y);
638     else
639         xbr2x(in, out, r2y);
640
641     out->width  = outlink->w;
642     out->height = outlink->h;
643
644     av_frame_free(&in);
645     return ff_filter_frame(outlink, out);
646 }
647
648 static int init(AVFilterContext *ctx)
649 {
650     XBRContext *xbr = ctx->priv;
651     uint32_t c;
652     int bg, rg, g;
653
654     for (bg = -255; bg < 256; bg++) {
655         for (rg = -255; rg < 256; rg++) {
656             const uint32_t u = (uint32_t)((-169*rg + 500*bg)/1000) + 128;
657             const uint32_t v = (uint32_t)(( 500*rg -  81*bg)/1000) + 128;
658             int startg = FFMAX3(-bg, -rg, 0);
659             int endg = FFMIN3(255-bg, 255-rg, 255);
660             uint32_t y = (uint32_t)(( 299*rg + 1000*startg + 114*bg)/1000);
661             c = bg + (rg<<16) + 0x010101 * startg;
662             for (g = startg; g <= endg; g++) {
663                 xbr->rgbtoyuv[c] = ((y++) << 16) + (u << 8) + v;
664                 c+= 0x010101;
665             }
666         }
667     }
668
669     return 0;
670 }
671
672 static const AVFilterPad xbr_inputs[] = {
673     {
674         .name         = "default",
675         .type         = AVMEDIA_TYPE_VIDEO,
676         .filter_frame = filter_frame,
677     },
678     { NULL }
679 };
680
681 static const AVFilterPad xbr_outputs[] = {
682     {
683         .name         = "default",
684         .type         = AVMEDIA_TYPE_VIDEO,
685         .config_props = config_output,
686     },
687     { NULL }
688 };
689
690 AVFilter ff_vf_xbr = {
691     .name          = "xbr",
692     .description   = NULL_IF_CONFIG_SMALL("Scale the input using xBR algorithm."),
693     .inputs        = xbr_inputs,
694     .outputs       = xbr_outputs,
695     .query_formats = query_formats,
696     .priv_size     = sizeof(XBRContext),
697     .priv_class    = &xbr_class,
698     .init          = init,
699 };