@@ -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" },
@@ -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
@@ -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 |
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@uralweb.ru> --- libswscale/options.c | 1 + libswscale/swscale.h | 1 + libswscale/utils.c | 30 +++++++++++++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-)