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 <r57sh...@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

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to