[FFmpeg-devel] [PATCH 1/1] libswscale: add area upscale

Pavel Klimov r57shell at uralweb.ru
Sun Feb 2 02:29:13 EET 2020


area upscale is similar to neighbor upscale,
just better with non integer factors.
math comes from assumption that
neighbor filter works fine,
and then integrate it over pixel width.

Signed-off-by: Pavel Klimov <r57shell at uralweb.ru>
---
 libswscale/options.c |  1 +
 libswscale/swscale.h |  1 +
 libswscale/utils.c   | 30 +++++++++++++++++++++++++++++-
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/libswscale/options.c b/libswscale/options.c
index 7eb2752543..bbf71997fb 100644
--- a/libswscale/options.c
+++ b/libswscale/options.c
@@ -41,6 +41,7 @@ static const AVOption swscale_options[] = {
     { "experimental",    "experimental",                  0,                 AV_OPT_TYPE_CONST,  { .i64  = SWS_X              }, INT_MIN, INT_MAX,        VE, "sws_flags" },
     { "neighbor",        "nearest neighbor",              0,                 AV_OPT_TYPE_CONST,  { .i64  = SWS_POINT          }, INT_MIN, INT_MAX,        VE, "sws_flags" },
     { "area",            "averaging area",                0,                 AV_OPT_TYPE_CONST,  { .i64  = SWS_AREA           }, INT_MIN, INT_MAX,        VE, "sws_flags" },
+    { "area_upscale",    "averaging area upscale",        0,                 AV_OPT_TYPE_CONST,  { .i64  = SWS_AREA_UPSCALE   }, INT_MIN, INT_MAX,        VE, "sws_flags" },
     { "bicublin",        "luma bicubic, chroma bilinear", 0,                 AV_OPT_TYPE_CONST,  { .i64  = SWS_BICUBLIN       }, INT_MIN, INT_MAX,        VE, "sws_flags" },
     { "gauss",           "Gaussian",                      0,                 AV_OPT_TYPE_CONST,  { .i64  = SWS_GAUSS          }, INT_MIN, INT_MAX,        VE, "sws_flags" },
     { "sinc",            "sinc",                          0,                 AV_OPT_TYPE_CONST,  { .i64  = SWS_SINC           }, INT_MIN, INT_MAX,        VE, "sws_flags" },
diff --git a/libswscale/swscale.h b/libswscale/swscale.h
index 7713f51ec6..1d677e0a94 100644
--- a/libswscale/swscale.h
+++ b/libswscale/swscale.h
@@ -66,6 +66,7 @@ const char *swscale_license(void);
 #define SWS_SINC          0x100
 #define SWS_LANCZOS       0x200
 #define SWS_SPLINE        0x400
+#define SWS_AREA_UPSCALE  0x800
 
 #define SWS_SRC_V_CHR_DROP_MASK     0x30000
 #define SWS_SRC_V_CHR_DROP_SHIFT    16
diff --git a/libswscale/utils.c b/libswscale/utils.c
index b2c08a5983..b713c40812 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -316,6 +316,7 @@ typedef struct {
 
 static const ScaleAlgorithm scale_algorithms[] = {
     { SWS_AREA,          "area averaging",                  1 /* downscale only, for upscale it is bilinear */ },
+    { SWS_AREA_UPSCALE,  "area averaging upscale",          1 },
     { SWS_BICUBIC,       "bicubic",                         4 },
     { SWS_BICUBLIN,      "luma bicubic / chroma bilinear", -1 },
     { SWS_BILINEAR,      "bilinear",                        2 },
@@ -398,6 +399,32 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
             }
             xDstInSrc += xInc;
         }
+    } else if (xInc <= (1 << 16) && (flags & SWS_AREA_UPSCALE)) { // area upscale
+        int i;
+        int64_t xDstInSrc;
+        double dInc, x, x1;
+
+        filterSize = 2;
+        FF_ALLOC_ARRAY_OR_GOTO(NULL, filter,
+                               dstW, sizeof(*filter) * filterSize, fail);
+
+        xDstInSrc = ((dstPos*(int64_t)xInc)>>8) - ((srcPos*0x8000LL)>>7);
+
+        xDstInSrc += (1 << 15) - xInc / 2;
+        dInc = (double)srcW / dstW * (1 << 16);
+        for (i = 0; i < dstW; i++) {
+            x = i * dInc;
+
+            (*filterPos)[i] = (xDstInSrc + (int)x) >> 16;
+            x1 = xDstInSrc - ((*filterPos)[i] << 16) + x;
+            if (x1 + dInc <= (1 << 16)) {
+                filter[i * filterSize + 0] = fone;
+                filter[i * filterSize + 1] = 0;
+            } else {
+                filter[i * filterSize + 0] = fone * (((1 << 16) - x1) / dInc);
+                filter[i * filterSize + 1] = fone - filter[i * filterSize + 0];
+            }
+        }
     } else {
         int64_t xDstInSrc;
         int sizeFactor = -1;
@@ -471,7 +498,7 @@ static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos,
                     else
                         c = pow(c, A);
                     coeff = (c * 0.5 + 0.5) * fone;
-                } else if (flags & SWS_AREA) {
+                } else if (flags & (SWS_AREA | SWS_AREA_UPSCALE)) {
                     int64_t d2 = d - (1 << 29);
                     if (d2 * xInc < -(1LL << (29 + 16)))
                         coeff = 1.0 * (1LL << (30 + 16));
@@ -1229,6 +1256,7 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
 
     i = flags & (SWS_POINT         |
                  SWS_AREA          |
+                 SWS_AREA_UPSCALE  |
                  SWS_BILINEAR      |
                  SWS_FAST_BILINEAR |
                  SWS_BICUBIC       |
-- 
2.17.0.windows.1



More information about the ffmpeg-devel mailing list