lavfi/tests/filtfmts: fix the build warning.
[ffmpeg.git] / libavfilter / vf_hqx.c
index c412229..16a1be7 100644 (file)
@@ -24,6 +24,7 @@
  *
  * @see http://en.wikipedia.org/wiki/Hqx
  * @see http://web.archive.org/web/20131114143602/http://www.hiend3d.com/hq3x.html
+ * @see http://blog.pkh.me/p/19-butchering-hqx-scaling-filters.html
  */
 
 #include "libavutil/opt.h"
@@ -33,7 +34,7 @@
 
 typedef int (*hqxfunc_t)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
 
-typedef struct {
+typedef struct HQXContext {
     const AVClass *class;
     int n;
     hqxfunc_t func;
@@ -64,9 +65,11 @@ static av_always_inline int yuv_diff(uint32_t yuv1, uint32_t yuv2)
 #define YMASK 0xff0000
 #define UMASK 0x00ff00
 #define VMASK 0x0000ff
-    return abs((yuv1 & YMASK) - (yuv2 & YMASK)) > (48 << 16) ||
-           abs((yuv1 & UMASK) - (yuv2 & UMASK)) > ( 7 <<  8) ||
-           abs((yuv1 & VMASK) - (yuv2 & VMASK)) > ( 6 <<  0);
+#define ABSDIFF(a,b) (abs((int)(a)-(int)(b)))
+
+    return ABSDIFF(yuv1 & YMASK, yuv2 & YMASK) > (48 << 16) ||
+           ABSDIFF(yuv1 & UMASK, yuv2 & UMASK) > ( 7 <<  8) ||
+           ABSDIFF(yuv1 & VMASK, yuv2 & VMASK) > ( 6 <<  0);
 }
 
 /* (c1*w1 + c2*w2) >> s */
@@ -401,28 +404,22 @@ static av_always_inline void hqx_filter(const ThreadData *td, int jobnr, int nb_
         const int nextline = y < height - 1 ?  src32_linesize : 0;
 
         for (x = 0; x < width; x++) {
-            uint32_t yuv1, yuv2;
             const int prevcol = x > 0        ? -1 : 0;
             const int nextcol = x < width -1 ?  1 : 0;
-            int pattern = 0, flag = 1, k;
             const uint32_t w[3*3] = {
                 src32[prevcol + prevline], src32[prevline], src32[prevline + nextcol],
                 src32[prevcol           ], src32[       0], src32[           nextcol],
                 src32[prevcol + nextline], src32[nextline], src32[nextline + nextcol]
             };
-
-            yuv1 = rgb2yuv(r2y, w[4]);
-
-            for (k = 0; k < FF_ARRAY_ELEMS(w); k++) {
-                if (k == 4)
-                    continue;
-                if (w[k] != w[4]) {
-                    yuv2 = rgb2yuv(r2y, w[k]);
-                    if (yuv_diff(yuv1, yuv2))
-                        pattern |= flag;
-                }
-                flag <<= 1;
-            }
+            const uint32_t yuv1 = rgb2yuv(r2y, w[4]);
+            const int pattern = (w[4] != w[0] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[0]))) : 0)
+                              | (w[4] != w[1] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[1]))) : 0) << 1
+                              | (w[4] != w[2] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[2]))) : 0) << 2
+                              | (w[4] != w[3] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[3]))) : 0) << 3
+                              | (w[4] != w[5] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[5]))) : 0) << 4
+                              | (w[4] != w[6] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[6]))) : 0) << 5
+                              | (w[4] != w[7] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[7]))) : 0) << 6
+                              | (w[4] != w[8] ? (yuv_diff(yuv1, rgb2yuv(r2y, w[8]))) : 0) << 7;
 
             if (n == 2) {
                 dst32[dst32_linesize*0 + 0] = hq2x_interp_1x1(r2y, pattern, w, 0,1,2,3,4,5,6,7,8);  // 00
@@ -466,9 +463,11 @@ HQX_FUNC(4)
 
 static int query_formats(AVFilterContext *ctx)
 {
-    static const enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE};
-    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
-    return 0;
+    static const enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_RGB32, AV_PIX_FMT_NONE};
+    AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+    if (!fmts_list)
+        return AVERROR(ENOMEM);
+    return ff_set_common_formats(ctx, fmts_list);
 }
 
 static int config_output(AVFilterLink *outlink)
@@ -503,7 +502,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     td.in = in;
     td.out = out;
     td.rgbtoyuv = hqx->rgbtoyuv;
-    ctx->internal->execute(ctx, hqx->func, &td, NULL, FFMIN(inlink->h, ctx->graph->nb_threads));
+    ctx->internal->execute(ctx, hqx->func, &td, NULL, FFMIN(inlink->h, ff_filter_get_nb_threads(ctx)));
 
     av_frame_free(&in);
     return ff_filter_frame(outlink, out);
@@ -515,14 +514,21 @@ static av_cold int init(AVFilterContext *ctx)
     static const hqxfunc_t hqxfuncs[] = {hq2x, hq3x, hq4x};
 
     uint32_t c;
-    for (c = 0; c < FF_ARRAY_ELEMS(hqx->rgbtoyuv); c++) {
-        const uint32_t r = c >> 16 & 0xff;
-        const uint32_t g = c >>  8 & 0xff;
-        const uint32_t b = c       & 0xff;
-        const uint32_t y = (uint32_t)( 0.299*r + 0.587*g + 0.114*b);
-        const uint32_t u = (uint32_t)(-0.169*r - 0.331*g +   0.5*b) + 128;
-        const uint32_t v = (uint32_t)(   0.5*r - 0.419*g - 0.081*b) + 128;
-        hqx->rgbtoyuv[c] = (y << 16) + (u << 8) + v;
+    int bg, rg, g;
+
+    for (bg=-255; bg<256; bg++) {
+        for (rg=-255; rg<256; rg++) {
+            const uint32_t u = (uint32_t)((-169*rg + 500*bg)/1000) + 128;
+            const uint32_t v = (uint32_t)(( 500*rg -  81*bg)/1000) + 128;
+            int startg = FFMAX3(-bg, -rg, 0);
+            int endg = FFMIN3(255-bg, 255-rg, 255);
+            uint32_t y = (uint32_t)(( 299*rg + 1000*startg + 114*bg)/1000);
+            c = bg + (rg<<16) + 0x010101 * startg;
+            for (g = startg; g <= endg; g++) {
+                hqx->rgbtoyuv[c] = ((y++) << 16) + (u << 8) + v;
+                c+= 0x010101;
+            }
+        }
     }
 
     hqx->func = hqxfuncs[hqx->n - 2];