[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