Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * This file is part of FFmpeg.
  3.  *
  4.  * Copyright (c) 2011, 2012 Hyllian/Jararaca <sergiogdb@gmail.com>
  5.  * Copyright (c) 2014 Arwa Arif <arwaarif1994@gmail.com>
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. /**
  23.  * @file
  24.  * XBR Filter is used for depixelization of image.
  25.  * This is based on Hyllian's xBR shader.
  26.  *
  27.  * @see http://www.libretro.com/forums/viewtopic.php?f=6&t=134
  28.  * @see https://github.com/yoyofr/iFBA/blob/master/fba_src/src/intf/video/scalers/xbr.cpp
  29.  */
  30.  
  31. #include "libavutil/opt.h"
  32. #include "libavutil/avassert.h"
  33. #include "libavutil/pixdesc.h"
  34. #include "internal.h"
  35.  
  36. #define LB_MASK       0x00FEFEFE
  37. #define RED_BLUE_MASK 0x00FF00FF
  38. #define GREEN_MASK    0x0000FF00
  39.  
  40. typedef int (*xbrfunc_t)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
  41.  
  42. typedef struct {
  43.     const AVClass *class;
  44.     int n;
  45.     xbrfunc_t func;
  46.     uint32_t rgbtoyuv[1<<24];
  47. } XBRContext;
  48.  
  49. typedef struct ThreadData {
  50.     AVFrame *in, *out;
  51.     const uint32_t *rgbtoyuv;
  52. } ThreadData;
  53.  
  54. #define OFFSET(x) offsetof(XBRContext, x)
  55. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  56. static const AVOption xbr_options[] = {
  57.     { "n", "set scale factor", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 3}, 2, 4, .flags = FLAGS },
  58.     { NULL }
  59. };
  60.  
  61. AVFILTER_DEFINE_CLASS(xbr);
  62.  
  63. static uint32_t pixel_diff(uint32_t x, uint32_t y, const uint32_t *r2y)
  64. {
  65. #define YMASK 0xff0000
  66. #define UMASK 0x00ff00
  67. #define VMASK 0x0000ff
  68.  
  69.     uint32_t yuv1 = r2y[x & 0xffffff];
  70.     uint32_t yuv2 = r2y[y & 0xffffff];
  71.  
  72.     return (abs((yuv1 & YMASK) - (yuv2 & YMASK)) >> 16) +
  73.            (abs((yuv1 & UMASK) - (yuv2 & UMASK)) >>  8) +
  74.            abs((yuv1 & VMASK) - (yuv2 & VMASK));
  75. }
  76.  
  77. #define ALPHA_BLEND_128_W(a, b) ((((a) & LB_MASK) >> 1) + (((b) & LB_MASK) >> 1))
  78. #define ALPHA_BLEND_BASE(a, b, m, s) (  (RED_BLUE_MASK & (((a) & RED_BLUE_MASK) + (((((b) & RED_BLUE_MASK) - ((a) & RED_BLUE_MASK)) * (m)) >> (s)))) \
  79.                                       | (GREEN_MASK    & (((a) & GREEN_MASK)    + (((((b) & GREEN_MASK)    - ((a) & GREEN_MASK))    * (m)) >> (s)))))
  80. #define ALPHA_BLEND_32_W(a, b)  ALPHA_BLEND_BASE(a, b, 1, 3)
  81. #define ALPHA_BLEND_64_W(a, b)  ALPHA_BLEND_BASE(a, b, 1, 2)
  82. #define ALPHA_BLEND_192_W(a, b) ALPHA_BLEND_BASE(a, b, 3, 2)
  83. #define ALPHA_BLEND_224_W(a, b) ALPHA_BLEND_BASE(a, b, 7, 3)
  84.  
  85. #define df(A, B) pixel_diff(A, B, r2y)
  86. #define eq(A, B) (df(A, B) < 155)
  87.  
  88. #define FILT2(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1,   \
  89.               N0, N1, N2, N3) do {                                                                  \
  90.     if (PE != PH && PE != PF) {                                                                     \
  91.         const unsigned e = df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + (df(PH,PF)<<2);          \
  92.         const unsigned i = df(PH,PD) + df(PH,I5) + df(PF,I4) + df(PF,PB) + (df(PE,PI)<<2);          \
  93.         if (e <= i) {                                                                               \
  94.             const unsigned px = df(PE,PF) <= df(PE,PH) ? PF : PH;                                   \
  95.             if (e < i && (!eq(PF,PB) && !eq(PH,PD) || eq(PE,PI)                                     \
  96.                           && (!eq(PF,I4) && !eq(PH,I5))                                             \
  97.                           || eq(PE,PG) || eq(PE,PC))) {                                             \
  98.                 const unsigned ke = df(PF,PG);                                                      \
  99.                 const unsigned ki = df(PH,PC);                                                      \
  100.                 const int left    = ke<<1 <= ki && PE != PG && PD != PG;                            \
  101.                 const int up      = ke >= ki<<1 && PE != PC && PB != PC;                            \
  102.                 if (left && up) {                                                                   \
  103.                     E[N3] = ALPHA_BLEND_224_W(E[N3], px);                                           \
  104.                     E[N2] = ALPHA_BLEND_64_W( E[N2], px);                                           \
  105.                     E[N1] = E[N2];                                                                  \
  106.                 } else if (left) {                                                                  \
  107.                     E[N3] = ALPHA_BLEND_192_W(E[N3], px);                                           \
  108.                     E[N2] = ALPHA_BLEND_64_W( E[N2], px);                                           \
  109.                 } else if (up) {                                                                    \
  110.                     E[N3] = ALPHA_BLEND_192_W(E[N3], px);                                           \
  111.                     E[N1] = ALPHA_BLEND_64_W( E[N1], px);                                           \
  112.                 } else { /* diagonal */                                                             \
  113.                     E[N3] = ALPHA_BLEND_128_W(E[N3], px);                                           \
  114.                 }                                                                                   \
  115.             } else {                                                                                \
  116.                 E[N3] = ALPHA_BLEND_128_W(E[N3], px);                                               \
  117.             }                                                                                       \
  118.         }                                                                                           \
  119.     }                                                                                               \
  120. } while (0)
  121.  
  122. #define FILT3(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1,   \
  123.               N0, N1, N2, N3, N4, N5, N6, N7, N8) do {                                              \
  124.     if (PE != PH && PE != PF) {                                                                     \
  125.         const unsigned e = df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + (df(PH,PF)<<2);          \
  126.         const unsigned i = df(PH,PD) + df(PH,I5) + df(PF,I4) + df(PF,PB) + (df(PE,PI)<<2);          \
  127.         if (e <= i) {                                                                               \
  128.             const unsigned px = df(PE,PF) <= df(PE,PH) ? PF : PH;                                   \
  129.             if (e < i && (!eq(PF,PB) && !eq(PF,PC) || !eq(PH,PD) && !eq(PH,PG) || eq(PE,PI)         \
  130.                           && (!eq(PF,F4) && !eq(PF,I4) || !eq(PH,H5) && !eq(PH,I5))                 \
  131.                           || eq(PE,PG) || eq(PE,PC))) {                                             \
  132.                 const unsigned ke = df(PF,PG);                                                      \
  133.                 const unsigned ki = df(PH,PC);                                                      \
  134.                 const int left    = ke<<1 <= ki && PE != PG && PD != PG;                            \
  135.                 const int up      = ke >= ki<<1 && PE != PC && PB != PC;                            \
  136.                 if (left && up) {                                                                   \
  137.                     E[N7] = ALPHA_BLEND_192_W(E[N7], px);                                           \
  138.                     E[N6] = ALPHA_BLEND_64_W( E[N6], px);                                           \
  139.                     E[N5] = E[N7];                                                                  \
  140.                     E[N2] = E[N6];                                                                  \
  141.                     E[N8] = px;                                                                     \
  142.                 } else if (left) {                                                                  \
  143.                     E[N7] = ALPHA_BLEND_192_W(E[N7], px);                                           \
  144.                     E[N5] = ALPHA_BLEND_64_W( E[N5], px);                                           \
  145.                     E[N6] = ALPHA_BLEND_64_W( E[N6], px);                                           \
  146.                     E[N8] = px;                                                                     \
  147.                 } else if (up) {                                                                    \
  148.                     E[N5] = ALPHA_BLEND_192_W(E[N5], px);                                           \
  149.                     E[N7] = ALPHA_BLEND_64_W( E[N7], px);                                           \
  150.                     E[N2] = ALPHA_BLEND_64_W( E[N2], px);                                           \
  151.                     E[N8] = px;                                                                     \
  152.                 } else { /* diagonal */                                                             \
  153.                     E[N8] = ALPHA_BLEND_224_W(E[N8], px);                                           \
  154.                     E[N5] = ALPHA_BLEND_32_W( E[N5], px);                                           \
  155.                     E[N7] = ALPHA_BLEND_32_W( E[N7], px);                                           \
  156.                 }                                                                                   \
  157.             } else {                                                                                \
  158.                 E[N8] = ALPHA_BLEND_128_W(E[N8], px);                                               \
  159.             }                                                                                       \
  160.         }                                                                                           \
  161.     }                                                                                               \
  162. } while (0)
  163.  
  164. #define FILT4(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1,   \
  165.               N15, N14, N11, N3, N7, N10, N13, N12, N9, N6, N2, N1, N5, N8, N4, N0) do {            \
  166.     if (PE != PH && PE != PF) {                                                                     \
  167.         const unsigned e = df(PE,PC) + df(PE,PG) + df(PI,H5) + df(PI,F4) + (df(PH,PF)<<2);          \
  168.         const unsigned i = df(PH,PD) + df(PH,I5) + df(PF,I4) + df(PF,PB) + (df(PE,PI)<<2);          \
  169.         if (e <= i) {                                                                               \
  170.             const unsigned px = df(PE,PF) <= df(PE,PH) ? PF : PH;                                   \
  171.             if (e < i && (!eq(PF,PB) && !eq(PH,PD) || eq(PE,PI)                                     \
  172.                           && (!eq(PF,I4) && !eq(PH,I5))                                             \
  173.                           || eq(PE,PG) || eq(PE,PC))) {                                             \
  174.                 const unsigned ke = df(PF,PG);                                                      \
  175.                 const unsigned ki = df(PH,PC);                                                      \
  176.                 const int left    = ke<<1 <= ki && PE != PG && PD != PG;                            \
  177.                 const int up      = ke >= ki<<1 && PE != PC && PB != PC;                            \
  178.                 if (left && up) {                                                                   \
  179.                     E[N13] = ALPHA_BLEND_192_W(E[N13], px);                                         \
  180.                     E[N12] = ALPHA_BLEND_64_W( E[N12], px);                                         \
  181.                     E[N15] = E[N14] = E[N11] = px;                                                  \
  182.                     E[N10] = E[N3]  = E[N12];                                                       \
  183.                     E[N7]  = E[N13];                                                                \
  184.                 } else if (left) {                                                                  \
  185.                     E[N11] = ALPHA_BLEND_192_W(E[N11], px);                                         \
  186.                     E[N13] = ALPHA_BLEND_192_W(E[N13], px);                                         \
  187.                     E[N10] = ALPHA_BLEND_64_W( E[N10], px);                                         \
  188.                     E[N12] = ALPHA_BLEND_64_W( E[N12], px);                                         \
  189.                     E[N14] = px;                                                                    \
  190.                     E[N15] = px;                                                                    \
  191.                 } else if (up) {                                                                    \
  192.                     E[N14] = ALPHA_BLEND_192_W(E[N14], px);                                         \
  193.                     E[N7 ] = ALPHA_BLEND_192_W(E[N7 ], px);                                         \
  194.                     E[N10] = ALPHA_BLEND_64_W( E[N10], px);                                         \
  195.                     E[N3 ] = ALPHA_BLEND_64_W( E[N3 ], px);                                         \
  196.                     E[N11] = px;                                                                    \
  197.                     E[N15] = px;                                                                    \
  198.                 } else { /* diagonal */                                                             \
  199.                     E[N11] = ALPHA_BLEND_128_W(E[N11], px);                                         \
  200.                     E[N14] = ALPHA_BLEND_128_W(E[N14], px);                                         \
  201.                     E[N15] = px;                                                                    \
  202.                 }                                                                                   \
  203.             } else {                                                                                \
  204.                 E[N15] = ALPHA_BLEND_128_W(E[N15], px);                                             \
  205.             }                                                                                       \
  206.         }                                                                                           \
  207.     }                                                                                               \
  208. } while (0)
  209.  
  210. static av_always_inline void xbr_filter(const ThreadData *td, int jobnr, int nb_jobs, int n)
  211. {
  212.     int x, y;
  213.     const AVFrame *input = td->in;
  214.     AVFrame *output = td->out;
  215.     const uint32_t *r2y = td->rgbtoyuv;
  216.     const int slice_start = (input->height *  jobnr   ) / nb_jobs;
  217.     const int slice_end   = (input->height * (jobnr+1)) / nb_jobs;
  218.     const int nl = output->linesize[0] >> 2;
  219.     const int nl1 = nl + nl;
  220.     const int nl2 = nl1 + nl;
  221.  
  222.     for (y = slice_start; y < slice_end; y++) {
  223.  
  224.         uint32_t *E = (uint32_t *)(output->data[0] + y * output->linesize[0] * n);
  225.         const uint32_t *sa2 = (uint32_t *)(input->data[0] + y * input->linesize[0] - 8); /* center */
  226.         const uint32_t *sa1 = sa2 - (input->linesize[0]>>2); /* up x1 */
  227.         const uint32_t *sa0 = sa1 - (input->linesize[0]>>2); /* up x2 */
  228.         const uint32_t *sa3 = sa2 + (input->linesize[0]>>2); /* down x1 */
  229.         const uint32_t *sa4 = sa3 + (input->linesize[0]>>2); /* down x2 */
  230.  
  231.         if (y <= 1) {
  232.             sa0 = sa1;
  233.             if (y == 0) {
  234.                 sa0 = sa1 = sa2;
  235.             }
  236.         }
  237.  
  238.         if (y >= input->height - 2) {
  239.             sa4 = sa3;
  240.             if (y == input->height - 1) {
  241.                 sa4 = sa3 = sa2;
  242.             }
  243.         }
  244.  
  245.         for (x = 0; x < input->width; x++) {
  246.             const uint32_t B1 = sa0[2];
  247.             const uint32_t PB = sa1[2];
  248.             const uint32_t PE = sa2[2];
  249.             const uint32_t PH = sa3[2];
  250.             const uint32_t H5 = sa4[2];
  251.  
  252.             const int pprev = 2 - (x > 0);
  253.             const uint32_t A1 = sa0[pprev];
  254.             const uint32_t PA = sa1[pprev];
  255.             const uint32_t PD = sa2[pprev];
  256.             const uint32_t PG = sa3[pprev];
  257.             const uint32_t G5 = sa4[pprev];
  258.  
  259.             const int pprev2 = pprev - (x > 1);
  260.             const uint32_t A0 = sa1[pprev2];
  261.             const uint32_t D0 = sa2[pprev2];
  262.             const uint32_t G0 = sa3[pprev2];
  263.  
  264.             const int pnext = 3 - (x == input->width - 1);
  265.             const uint32_t C1 = sa0[pnext];
  266.             const uint32_t PC = sa1[pnext];
  267.             const uint32_t PF = sa2[pnext];
  268.             const uint32_t PI = sa3[pnext];
  269.             const uint32_t I5 = sa4[pnext];
  270.  
  271.             const int pnext2 = pnext + 1 - (x >= input->width - 2);
  272.             const uint32_t C4 = sa1[pnext2];
  273.             const uint32_t F4 = sa2[pnext2];
  274.             const uint32_t I4 = sa3[pnext2];
  275.  
  276.             if (n == 2) {
  277.                 E[0]  = E[1]      =     // 0, 1
  278.                 E[nl] = E[nl + 1] = PE; // 2, 3
  279.  
  280.                 FILT2(PE, PI, PH, PF, PG, PC, PD, PB, PA, G5, C4, G0, D0, C1, B1, F4, I4, H5, I5, A0, A1, 0, 1, nl, nl+1);
  281.                 FILT2(PE, PC, PF, PB, PI, PA, PH, PD, PG, I4, A1, I5, H5, A0, D0, B1, C1, F4, C4, G5, G0, nl, 0, nl+1, 1);
  282.                 FILT2(PE, PA, PB, PD, PC, PG, PF, PH, PI, C1, G0, C4, F4, G5, H5, D0, A0, B1, A1, I4, I5, nl+1, nl, 1, 0);
  283.                 FILT2(PE, PG, PD, PH, PA, PI, PB, PF, PC, A0, I5, A1, B1, I4, F4, H5, G5, D0, G0, C1, C4, 1, nl+1, 0, nl);
  284.             } else if (n == 3) {
  285.                 E[0]   = E[1]     = E[2]     =     // 0, 1, 2
  286.                 E[nl]  = E[nl+1]  = E[nl+2]  =     // 3, 4, 5
  287.                 E[nl1] = E[nl1+1] = E[nl1+2] = PE; // 6, 7, 8
  288.  
  289.                 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);
  290.                 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);
  291.                 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);
  292.                 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);
  293.             } else if (n == 4) {
  294.                 E[0]   = E[1]     = E[2]     = E[3]     =     //  0,  1,  2,  3
  295.                 E[nl]  = E[nl+1]  = E[nl+2]  = E[nl+3]  =     //  4,  5,  6,  7
  296.                 E[nl1] = E[nl1+1] = E[nl1+2] = E[nl1+3] =     //  8,  9, 10, 11
  297.                 E[nl2] = E[nl2+1] = E[nl2+2] = E[nl2+3] = PE; // 12, 13, 14, 15
  298.  
  299.                 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);
  300.                 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);
  301.                 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);
  302.                 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);
  303.             }
  304.  
  305.             sa0 += 1;
  306.             sa1 += 1;
  307.             sa2 += 1;
  308.             sa3 += 1;
  309.             sa4 += 1;
  310.  
  311.             E += n;
  312.         }
  313.     }
  314. }
  315.  
  316. #define XBR_FUNC(size) \
  317. static int xbr##size##x(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
  318. { \
  319.     xbr_filter(arg, jobnr, nb_jobs, size); \
  320.     return 0; \
  321. }
  322.  
  323. XBR_FUNC(2)
  324. XBR_FUNC(3)
  325. XBR_FUNC(4)
  326.  
  327.  
  328. static int config_output(AVFilterLink *outlink)
  329. {
  330.     AVFilterContext *ctx = outlink->src;
  331.     XBRContext *xbr = ctx->priv;
  332.     AVFilterLink *inlink = ctx->inputs[0];
  333.  
  334.     outlink->w = inlink->w * xbr->n;
  335.     outlink->h = inlink->h * xbr->n;
  336.     return 0;
  337. }
  338.  
  339. static int query_formats(AVFilterContext *ctx)
  340. {
  341.     static const enum AVPixelFormat pix_fmts[] = {
  342.         AV_PIX_FMT_0RGB32, AV_PIX_FMT_NONE,
  343.     };
  344.  
  345.     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
  346.     if (!fmts_list)
  347.         return AVERROR(ENOMEM);
  348.     return ff_set_common_formats(ctx, fmts_list);
  349. }
  350.  
  351. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  352. {
  353.     AVFilterContext *ctx = inlink->dst;
  354.     AVFilterLink *outlink = ctx->outputs[0];
  355.     XBRContext *xbr = ctx->priv;
  356.     ThreadData td;
  357.  
  358.     AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  359.     if (!out) {
  360.         av_frame_free(&in);
  361.         return AVERROR(ENOMEM);
  362.     }
  363.  
  364.     av_frame_copy_props(out, in);
  365.  
  366.     td.in = in;
  367.     td.out = out;
  368.     td.rgbtoyuv = xbr->rgbtoyuv;
  369.     ctx->internal->execute(ctx, xbr->func, &td, NULL, FFMIN(inlink->h, ctx->graph->nb_threads));
  370.  
  371.     out->width  = outlink->w;
  372.     out->height = outlink->h;
  373.  
  374.     av_frame_free(&in);
  375.     return ff_filter_frame(outlink, out);
  376. }
  377.  
  378. static int init(AVFilterContext *ctx)
  379. {
  380.     XBRContext *xbr = ctx->priv;
  381.     static const xbrfunc_t xbrfuncs[] = {xbr2x, xbr3x, xbr4x};
  382.  
  383.     uint32_t c;
  384.     int bg, rg, g;
  385.  
  386.     for (bg = -255; bg < 256; bg++) {
  387.         for (rg = -255; rg < 256; rg++) {
  388.             const uint32_t u = (uint32_t)((-169*rg + 500*bg)/1000) + 128;
  389.             const uint32_t v = (uint32_t)(( 500*rg -  81*bg)/1000) + 128;
  390.             int startg = FFMAX3(-bg, -rg, 0);
  391.             int endg = FFMIN3(255-bg, 255-rg, 255);
  392.             uint32_t y = (uint32_t)(( 299*rg + 1000*startg + 114*bg)/1000);
  393.             c = bg + (rg<<16) + 0x010101 * startg;
  394.             for (g = startg; g <= endg; g++) {
  395.                 xbr->rgbtoyuv[c] = ((y++) << 16) + (u << 8) + v;
  396.                 c+= 0x010101;
  397.             }
  398.         }
  399.     }
  400.  
  401.     xbr->func = xbrfuncs[xbr->n - 2];
  402.     return 0;
  403. }
  404.  
  405. static const AVFilterPad xbr_inputs[] = {
  406.     {
  407.         .name         = "default",
  408.         .type         = AVMEDIA_TYPE_VIDEO,
  409.         .filter_frame = filter_frame,
  410.     },
  411.     { NULL }
  412. };
  413.  
  414. static const AVFilterPad xbr_outputs[] = {
  415.     {
  416.         .name         = "default",
  417.         .type         = AVMEDIA_TYPE_VIDEO,
  418.         .config_props = config_output,
  419.     },
  420.     { NULL }
  421. };
  422.  
  423. AVFilter ff_vf_xbr = {
  424.     .name          = "xbr",
  425.     .description   = NULL_IF_CONFIG_SMALL("Scale the input using xBR algorithm."),
  426.     .inputs        = xbr_inputs,
  427.     .outputs       = xbr_outputs,
  428.     .query_formats = query_formats,
  429.     .priv_size     = sizeof(XBRContext),
  430.     .priv_class    = &xbr_class,
  431.     .init          = init,
  432.     .flags         = AVFILTER_FLAG_SLICE_THREADS,
  433. };
  434.