/* * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at> * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #define _DEFAULT_SOURCE#define _SVID_SOURCE // needed for MAP_ANONYMOUS#define _DARWIN_C_SOURCE // needed for MAP_ANON#include <inttypes.h>#include <math.h>#include <stdio.h>#include <string.h>#if HAVE_SYS_MMAN_H#include <sys/mman.h>#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)#define MAP_ANONYMOUS MAP_ANON#endif#endif#if HAVE_VIRTUALALLOC#define WIN32_LEAN_AND_MEAN#include <windows.h>#endif #include "libavutil/attributes.h"#include "libavutil/avassert.h"#include "libavutil/avutil.h"#include "libavutil/bswap.h"#include "libavutil/cpu.h"#include "libavutil/imgutils.h"#include "libavutil/intreadwrite.h"#include "libavutil/libm.h"#include "libavutil/mathematics.h"#include "libavutil/opt.h"#include "libavutil/pixdesc.h"#include "libavutil/aarch64/cpu.h"#include "libavutil/ppc/cpu.h"#include "libavutil/x86/asm.h"#include "libavutil/x86/cpu.h" // We have to implement deprecated functions until they are removed, this is the// simplest way to prevent warnings#undef attribute_deprecated#define attribute_deprecated #include "rgb2rgb.h"#include "swscale.h"#include "swscale_internal.h" #if !FF_API_SWS_VECTORstatic SwsVector *sws_getIdentityVec(void);static void sws_addVec(SwsVector *a, SwsVector *b);static void sws_shiftVec(SwsVector *a, int shift);static void sws_printVec2(SwsVector *a, AVClass *log_ctx, int log_level);#endif static void handle_formats(SwsContext *c); unsigned swscale_version(void){ av_assert0(LIBSWSCALE_VERSION_MICRO >= 100); return LIBSWSCALE_VERSION_INT;} const char *swscale_configuration(void){ return FFMPEG_CONFIGURATION;} const char *swscale_license(void){#define LICENSE_PREFIX "libswscale license: " return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1;} typedef struct FormatEntry { uint8_t is_supported_in :1; uint8_t is_supported_out :1; uint8_t is_supported_endianness :1;} FormatEntry; static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_YUV420P] = { 1, 1 }, [AV_PIX_FMT_YUYV422] = { 1, 1 }, [AV_PIX_FMT_RGB24] = { 1, 1 }, [AV_PIX_FMT_BGR24] = { 1, 1 }, [AV_PIX_FMT_YUV422P] = { 1, 1 }, [AV_PIX_FMT_YUV444P] = { 1, 1 }, [AV_PIX_FMT_YUV410P] = { 1, 1 }, [AV_PIX_FMT_YUV411P] = { 1, 1 }, [AV_PIX_FMT_GRAY8] = { 1, 1 }, [AV_PIX_FMT_MONOWHITE] = { 1, 1 }, [AV_PIX_FMT_MONOBLACK] = { 1, 1 }, [AV_PIX_FMT_PAL8] = { 1, 0 }, [AV_PIX_FMT_YUVJ420P] = { 1, 1 }, [AV_PIX_FMT_YUVJ411P] = { 1, 1 }, [AV_PIX_FMT_YUVJ422P] = { 1, 1 }, [AV_PIX_FMT_YUVJ444P] = { 1, 1 }, [AV_PIX_FMT_YVYU422] = { 1, 1 }, [AV_PIX_FMT_UYVY422] = { 1, 1 }, [AV_PIX_FMT_UYYVYY411] = { 0, 0 }, [AV_PIX_FMT_BGR8] = { 1, 1 }, [AV_PIX_FMT_BGR4] = { 0, 1 }, [AV_PIX_FMT_BGR4_BYTE] = { 1, 1 }, [AV_PIX_FMT_RGB8] = { 1, 1 }, [AV_PIX_FMT_RGB4] = { 0, 1 }, [AV_PIX_FMT_RGB4_BYTE] = { 1, 1 }, [AV_PIX_FMT_NV12] = { 1, 1 }, [AV_PIX_FMT_NV21] = { 1, 1 }, [AV_PIX_FMT_ARGB] = { 1, 1 }, [AV_PIX_FMT_RGBA] = { 1, 1 }, [AV_PIX_FMT_ABGR] = { 1, 1 }, [AV_PIX_FMT_BGRA] = { 1, 1 }, [AV_PIX_FMT_0RGB] = { 1, 1 }, [AV_PIX_FMT_RGB0] = { 1, 1 }, [AV_PIX_FMT_0BGR] = { 1, 1 }, [AV_PIX_FMT_BGR0] = { 1, 1 }, [AV_PIX_FMT_GRAY10BE] = { 1, 1 }, [AV_PIX_FMT_GRAY10LE] = { 1, 1 }, [AV_PIX_FMT_GRAY12BE] = { 1, 1 }, [AV_PIX_FMT_GRAY12LE] = { 1, 1 }, [AV_PIX_FMT_GRAY16BE] = { 1, 1 }, [AV_PIX_FMT_GRAY16LE] = { 1, 1 }, [AV_PIX_FMT_YUV440P] = { 1, 1 }, [AV_PIX_FMT_YUVJ440P] = { 1, 1 }, [AV_PIX_FMT_YUV440P10LE] = { 1, 1 }, [AV_PIX_FMT_YUV440P10BE] = { 1, 1 }, [AV_PIX_FMT_YUV440P12LE] = { 1, 1 }, [AV_PIX_FMT_YUV440P12BE] = { 1, 1 }, [AV_PIX_FMT_YUVA420P] = { 1, 1 }, [AV_PIX_FMT_YUVA422P] = { 1, 1 }, [AV_PIX_FMT_YUVA444P] = { 1, 1 }, [AV_PIX_FMT_YUVA420P9BE] = { 1, 1 }, [AV_PIX_FMT_YUVA420P9LE] = { 1, 1 }, [AV_PIX_FMT_YUVA422P9BE] = { 1, 1 }, [AV_PIX_FMT_YUVA422P9LE] = { 1, 1 }, [AV_PIX_FMT_YUVA444P9BE] = { 1, 1 }, [AV_PIX_FMT_YUVA444P9LE] = { 1, 1 }, [AV_PIX_FMT_YUVA420P10BE]= { 1, 1 }, [AV_PIX_FMT_YUVA420P10LE]= { 1, 1 }, [AV_PIX_FMT_YUVA422P10BE]= { 1, 1 }, [AV_PIX_FMT_YUVA422P10LE]= { 1, 1 }, [AV_PIX_FMT_YUVA444P10BE]= { 1, 1 }, [AV_PIX_FMT_YUVA444P10LE]= { 1, 1 }, [AV_PIX_FMT_YUVA420P16BE]= { 1, 1 }, [AV_PIX_FMT_YUVA420P16LE]= { 1, 1 }, [AV_PIX_FMT_YUVA422P16BE]= { 1, 1 }, [AV_PIX_FMT_YUVA422P16LE]= { 1, 1 }, [AV_PIX_FMT_YUVA444P16BE]= { 1, 1 }, [AV_PIX_FMT_YUVA444P16LE]= { 1, 1 }, [AV_PIX_FMT_RGB48BE] = { 1, 1 }, [AV_PIX_FMT_RGB48LE] = { 1, 1 }, [AV_PIX_FMT_RGBA64BE] = { 1, 1, 1 }, [AV_PIX_FMT_RGBA64LE] = { 1, 1, 1 }, [AV_PIX_FMT_RGB565BE] = { 1, 1 }, [AV_PIX_FMT_RGB565LE] = { 1, 1 }, [AV_PIX_FMT_RGB555BE] = { 1, 1 }, [AV_PIX_FMT_RGB555LE] = { 1, 1 }, [AV_PIX_FMT_BGR565BE] = { 1, 1 }, [AV_PIX_FMT_BGR565LE] = { 1, 1 }, [AV_PIX_FMT_BGR555BE] = { 1, 1 }, [AV_PIX_FMT_BGR555LE] = { 1, 1 }, [AV_PIX_FMT_YUV420P16LE] = { 1, 1 }, [AV_PIX_FMT_YUV420P16BE] = { 1, 1 }, [AV_PIX_FMT_YUV422P16LE] = { 1, 1 }, [AV_PIX_FMT_YUV422P16BE] = { 1, 1 }, [AV_PIX_FMT_YUV444P16LE] = { 1, 1 }, [AV_PIX_FMT_YUV444P16BE] = { 1, 1 }, [AV_PIX_FMT_RGB444LE] = { 1, 1 }, [AV_PIX_FMT_RGB444BE] = { 1, 1 }, [AV_PIX_FMT_BGR444LE] = { 1, 1 }, [AV_PIX_FMT_BGR444BE] = { 1, 1 }, [AV_PIX_FMT_YA8] = { 1, 1 }, [AV_PIX_FMT_YA16BE] = { 1, 0 }, [AV_PIX_FMT_YA16LE] = { 1, 0 }, [AV_PIX_FMT_BGR48BE] = { 1, 1 }, [AV_PIX_FMT_BGR48LE] = { 1, 1 }, [AV_PIX_FMT_BGRA64BE] = { 1, 1, 1 }, [AV_PIX_FMT_BGRA64LE] = { 1, 1, 1 }, [AV_PIX_FMT_YUV420P9BE] = { 1, 1 }, [AV_PIX_FMT_YUV420P9LE] = { 1, 1 }, [AV_PIX_FMT_YUV420P10BE] = { 1, 1 }, [AV_PIX_FMT_YUV420P10LE] = { 1, 1 }, [AV_PIX_FMT_YUV420P12BE] = { 1, 1 }, [AV_PIX_FMT_YUV420P12LE] = { 1, 1 }, [AV_PIX_FMT_YUV420P14BE] = { 1, 1 }, [AV_PIX_FMT_YUV420P14LE] = { 1, 1 }, [AV_PIX_FMT_YUV422P9BE] = { 1, 1 }, [AV_PIX_FMT_YUV422P9LE] = { 1, 1 }, [AV_PIX_FMT_YUV422P10BE] = { 1, 1 }, [AV_PIX_FMT_YUV422P10LE] = { 1, 1 }, [AV_PIX_FMT_YUV422P12BE] = { 1, 1 }, [AV_PIX_FMT_YUV422P12LE] = { 1, 1 }, [AV_PIX_FMT_YUV422P14BE] = { 1, 1 }, [AV_PIX_FMT_YUV422P14LE] = { 1, 1 }, [AV_PIX_FMT_YUV444P9BE] = { 1, 1 }, [AV_PIX_FMT_YUV444P9LE] = { 1, 1 }, [AV_PIX_FMT_YUV444P10BE] = { 1, 1 }, [AV_PIX_FMT_YUV444P10LE] = { 1, 1 }, [AV_PIX_FMT_YUV444P12BE] = { 1, 1 }, [AV_PIX_FMT_YUV444P12LE] = { 1, 1 }, [AV_PIX_FMT_YUV444P14BE] = { 1, 1 }, [AV_PIX_FMT_YUV444P14LE] = { 1, 1 }, [AV_PIX_FMT_GBRP] = { 1, 1 }, [AV_PIX_FMT_GBRP9LE] = { 1, 1 }, [AV_PIX_FMT_GBRP9BE] = { 1, 1 }, [AV_PIX_FMT_GBRP10LE] = { 1, 1 }, [AV_PIX_FMT_GBRP10BE] = { 1, 1 }, [AV_PIX_FMT_GBRAP10LE] = { 1, 1 }, [AV_PIX_FMT_GBRAP10BE] = { 1, 1 }, [AV_PIX_FMT_GBRP12LE] = { 1, 1 }, [AV_PIX_FMT_GBRP12BE] = { 1, 1 }, [AV_PIX_FMT_GBRAP12LE] = { 1, 1 }, [AV_PIX_FMT_GBRAP12BE] = { 1, 1 }, [AV_PIX_FMT_GBRP14LE] = { 1, 1 }, [AV_PIX_FMT_GBRP14BE] = { 1, 1 }, [AV_PIX_FMT_GBRP16LE] = { 1, 1 }, [AV_PIX_FMT_GBRP16BE] = { 1, 1 }, [AV_PIX_FMT_GBRAP] = { 1, 1 }, [AV_PIX_FMT_GBRAP16LE] = { 1, 1 }, [AV_PIX_FMT_GBRAP16BE] = { 1, 1 }, [AV_PIX_FMT_BAYER_BGGR8] = { 1, 0 }, [AV_PIX_FMT_BAYER_RGGB8] = { 1, 0 }, [AV_PIX_FMT_BAYER_GBRG8] = { 1, 0 }, [AV_PIX_FMT_BAYER_GRBG8] = { 1, 0 }, [AV_PIX_FMT_BAYER_BGGR16LE] = { 1, 0 }, [AV_PIX_FMT_BAYER_BGGR16BE] = { 1, 0 }, [AV_PIX_FMT_BAYER_RGGB16LE] = { 1, 0 }, [AV_PIX_FMT_BAYER_RGGB16BE] = { 1, 0 }, [AV_PIX_FMT_BAYER_GBRG16LE] = { 1, 0 }, [AV_PIX_FMT_BAYER_GBRG16BE] = { 1, 0 }, [AV_PIX_FMT_BAYER_GRBG16LE] = { 1, 0 }, [AV_PIX_FMT_BAYER_GRBG16BE] = { 1, 0 }, [AV_PIX_FMT_XYZ12BE] = { 1, 1, 1 }, [AV_PIX_FMT_XYZ12LE] = { 1, 1, 1 }, [AV_PIX_FMT_AYUV64LE] = { 1, 1}, [AV_PIX_FMT_P010LE] = { 1, 1 }, [AV_PIX_FMT_P010BE] = { 1, 1 }, [AV_PIX_FMT_P016LE] = { 1, 0 }, [AV_PIX_FMT_P016BE] = { 1, 0 },}; int sws_isSupportedInput(enum AVPixelFormat pix_fmt){ return (unsigned)pix_fmt < AV_PIX_FMT_NB ? format_entries[pix_fmt].is_supported_in : 0;} int sws_isSupportedOutput(enum AVPixelFormat pix_fmt){ return (unsigned)pix_fmt < AV_PIX_FMT_NB ? format_entries[pix_fmt].is_supported_out : 0;} int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt){ return (unsigned)pix_fmt < AV_PIX_FMT_NB ? format_entries[pix_fmt].is_supported_endianness : 0;} static double getSplineCoeff(double a, double b, double c, double d, double dist){ if (dist <= 1.0) return ((d * dist + c) * dist + b) * dist + a; else return getSplineCoeff(0.0, b + 2.0 * c + 3.0 * d, c + 3.0 * d, -b - 3.0 * c - 6.0 * d, dist - 1.0);} static av_cold int get_local_pos(SwsContext *s, int chr_subsample, int pos, int dir){ if (pos == -1 || pos <= -513) { pos = (128 << chr_subsample) - 128; } pos += 128; // relative to ideal left edge return pos >> chr_subsample;} typedef struct { int flag; ///< flag associated to the algorithm const char *description; ///< human-readable description int size_factor; ///< size factor used when initing the filters} ScaleAlgorithm; static const ScaleAlgorithm scale_algorithms[] = { { SWS_AREA, "area averaging", 1 /* downscale only, for upscale it is bilinear */ }, { SWS_BICUBIC, "bicubic", 4 }, { SWS_BICUBLIN, "luma bicubic / chroma bilinear", -1 }, { SWS_BILINEAR, "bilinear", 2 }, { SWS_FAST_BILINEAR, "fast bilinear", -1 }, { SWS_GAUSS, "Gaussian", 8 /* infinite ;) */ }, { SWS_LANCZOS, "Lanczos", -1 /* custom */ }, { SWS_POINT, "nearest neighbor / point", -1 }, { SWS_SINC, "sinc", 20 /* infinite ;) */ }, { SWS_SPLINE, "bicubic spline", 20 /* infinite :)*/ }, { SWS_X, "experimental", 8 },}; static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos, int *outFilterSize, int xInc, int srcW, int dstW, int filterAlign, int one, int flags, int cpu_flags, SwsVector *srcFilter, SwsVector *dstFilter, double param[2], int srcPos, int dstPos){ int i; int filterSize; int filter2Size; int minFilterSize; int64_t *filter = NULL; int64_t *filter2 = NULL; const int64_t fone = 1LL << (54 - FFMIN(av_log2(srcW/dstW), 8)); int ret = -1; emms_c(); // FIXME should not be required but IS (even for non-MMX versions) // NOTE: the +3 is for the MMX(+1) / SSE(+3) scaler which reads over the end FF_ALLOC_ARRAY_OR_GOTO(NULL, *filterPos, (dstW + 3), sizeof(**filterPos), fail); if (FFABS(xInc - 0x10000) < 10 && srcPos == dstPos) { // unscaled int i; filterSize = 1; FF_ALLOCZ_ARRAY_OR_GOTO(NULL, filter, dstW, sizeof(*filter) * filterSize, fail); for (i = 0; i < dstW; i++) { filter[i * filterSize] = fone; (*filterPos)[i] = i; } } else if (flags & SWS_POINT) { // lame looking point sampling mode int i; int64_t xDstInSrc; filterSize = 1; FF_ALLOC_ARRAY_OR_GOTO(NULL, filter, dstW, sizeof(*filter) * filterSize, fail); xDstInSrc = ((dstPos*(int64_t)xInc)>>8) - ((srcPos*0x8000LL)>>7); for (i = 0; i < dstW; i++) { int xx = (xDstInSrc - ((filterSize - 1) << 15) + (1 << 15)) >> 16; (*filterPos)[i] = xx; filter[i] = fone; xDstInSrc += xInc; } } else if ((xInc <= (1 << 16) && (flags & SWS_AREA)) || (flags & SWS_FAST_BILINEAR)) { // bilinear upscale int i; int64_t xDstInSrc; filterSize = 2; FF_ALLOC_ARRAY_OR_GOTO(NULL, filter, dstW, sizeof(*filter) * filterSize, fail); xDstInSrc = ((dstPos*(int64_t)xInc)>>8) - ((srcPos*0x8000LL)>>7); for (i = 0; i < dstW; i++) { int xx = (xDstInSrc - ((filterSize - 1) << 15) + (1 << 15)) >> 16; int j; (*filterPos)[i] = xx; // bilinear upscale / linear interpolate / area averaging for (j = 0; j < filterSize; j++) { int64_t coeff= fone - FFABS(((int64_t)xx<<16) - xDstInSrc)*(fone>>16); if (coeff < 0) coeff = 0; filter[i * filterSize + j] = coeff; xx++; } xDstInSrc += xInc; } } else { int64_t xDstInSrc; int sizeFactor = -1; for (i = 0; i < FF_ARRAY_ELEMS(scale_algorithms); i++) { if (flags & scale_algorithms[i].flag && scale_algorithms[i].size_factor > 0) { sizeFactor = scale_algorithms[i].size_factor; break; } } if (flags & SWS_LANCZOS) sizeFactor = param[0] != SWS_PARAM_DEFAULT ? ceil(2 * param[0]) : 6; av_assert0(sizeFactor > 0); if (xInc <= 1 << 16) filterSize = 1 + sizeFactor; // upscale else filterSize = 1 + (sizeFactor * srcW + dstW - 1) / dstW; filterSize = FFMIN(filterSize, srcW - 2); filterSize = FFMAX(filterSize, 1); FF_ALLOC_ARRAY_OR_GOTO(NULL, filter, dstW, sizeof(*filter) * filterSize, fail); xDstInSrc = ((dstPos*(int64_t)xInc)>>7) - ((srcPos*0x10000LL)>>7); for (i = 0; i < dstW; i++) { int xx = (xDstInSrc - (filterSize - 2) * (1LL<<16)) / (1 << 17); int j; (*filterPos)[i] = xx; for (j = 0; j < filterSize; j++) { int64_t d = (FFABS(((int64_t)xx * (1 << 17)) - xDstInSrc)) << 13; double floatd; int64_t coeff; if (xInc > 1 << 16) d = d * dstW / srcW; floatd = d * (1.0 / (1 << 30)); if (flags & SWS_BICUBIC) { int64_t B = (param[0] != SWS_PARAM_DEFAULT ? param[0] : 0) * (1 << 24); int64_t C = (param[1] != SWS_PARAM_DEFAULT ? param[1] : 0.6) * (1 << 24); if (d >= 1LL << 31) { coeff = 0.0; } else { int64_t dd = (d * d) >> 30; int64_t ddd = (dd * d) >> 30; if (d < 1LL << 30) coeff = (12 * (1 << 24) - 9 * B - 6 * C) * ddd + (-18 * (1 << 24) + 12 * B + 6 * C) * dd + (6 * (1 << 24) - 2 * B) * (1 << 30); else coeff = (-B - 6 * C) * ddd + (6 * B + 30 * C) * dd + (-12 * B - 48 * C) * d + (8 * B + 24 * C) * (1 << 30); } coeff /= (1LL<<54)/fone; }#if 0 else if (flags & SWS_X) { double p = param ? param * 0.01 : 0.3; coeff = d ? sin(d * M_PI) / (d * M_PI) : 1.0; coeff *= pow(2.0, -p * d * d); }#endif else if (flags & SWS_X) { double A = param[0] != SWS_PARAM_DEFAULT ? param[0] : 1.0; double c; if (floatd < 1.0) c = cos(floatd * M_PI); else c = -1.0; if (c < 0.0) c = -pow(-c, A); else c = pow(c, A); coeff = (c * 0.5 + 0.5) * fone; } else if (flags & SWS_AREA) { int64_t d2 = d - (1 << 29); if (d2 * xInc < -(1LL << (29 + 16))) coeff = 1.0 * (1LL << (30 + 16)); else if (d2 * xInc < (1LL << (29 + 16))) coeff = -d2 * xInc + (1LL << (29 + 16)); else coeff = 0.0; coeff *= fone >> (30 + 16); } else if (flags & SWS_GAUSS) { double p = param[0] != SWS_PARAM_DEFAULT ? param[0] : 3.0; coeff = exp2(-p * floatd * floatd) * fone; } else if (flags & SWS_SINC) { coeff = (d ? sin(floatd * M_PI) / (floatd * M_PI) : 1.0) * fone; } else if (flags & SWS_LANCZOS) { double p = param[0] != SWS_PARAM_DEFAULT ? param[0] : 3.0; coeff = (d ? sin(floatd * M_PI) * sin(floatd * M_PI / p) / (floatd * floatd * M_PI * M_PI / p) : 1.0) * fone; if (floatd > p) coeff = 0; } else if (flags & SWS_BILINEAR) { coeff = (1 << 30) - d; if (coeff < 0) coeff = 0; coeff *= fone >> 30; } else if (flags & SWS_SPLINE) { double p = -2.196152422706632; coeff = getSplineCoeff(1.0, 0.0, p, -p - 1.0, floatd) * fone; } else { av_assert0(0); }Lines 1–500 of 2399. Load more
/* * Copyright (C) 2001-2003 Michael Niedermayer <michaelni@gmx.at> * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #define _DEFAULT_SOURCE #define _SVID_SOURCE // needed for MAP_ANONYMOUS #define _DARWIN_C_SOURCE // needed for MAP_ANON #include <inttypes.h> #include <math.h> #include <stdio.h> #include <string.h> #if HAVE_SYS_MMAN_H #include <sys/mman.h> #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #endif #endif #if HAVE_VIRTUALALLOC #define WIN32_LEAN_AND_MEAN #include <windows.h> #endif #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/avutil.h" #include "libavutil/bswap.h" #include "libavutil/cpu.h" #include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "libavutil/libm.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/aarch64/cpu.h" #include "libavutil/ppc/cpu.h" #include "libavutil/x86/asm.h" #include "libavutil/x86/cpu.h" // We have to implement deprecated functions until they are removed, this is the // simplest way to prevent warnings #undef attribute_deprecated #define attribute_deprecated #include "rgb2rgb.h" #include "swscale.h" #include "swscale_internal.h" #if !FF_API_SWS_VECTOR static SwsVector *sws_getIdentityVec(void); static void sws_addVec(SwsVector *a, SwsVector *b); static void sws_shiftVec(SwsVector *a, int shift); static void sws_printVec2(SwsVector *a, AVClass *log_ctx, int log_level); #endif static void handle_formats(SwsContext *c); unsigned swscale_version(void) { av_assert0(LIBSWSCALE_VERSION_MICRO >= 100); return LIBSWSCALE_VERSION_INT; } const char *swscale_configuration(void) { return FFMPEG_CONFIGURATION; } const char *swscale_license(void) { #define LICENSE_PREFIX "libswscale license: " return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; } typedef struct FormatEntry { uint8_t is_supported_in :1; uint8_t is_supported_out :1; uint8_t is_supported_endianness :1; } FormatEntry; static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_YUV420P] = { 1, 1 }, [AV_PIX_FMT_YUYV422] = { 1, 1 }, [AV_PIX_FMT_RGB24] = { 1, 1 }, [AV_PIX_FMT_BGR24] = { 1, 1 }, [AV_PIX_FMT_YUV422P] = { 1, 1 }, [AV_PIX_FMT_YUV444P] = { 1, 1 }, [AV_PIX_FMT_YUV410P] = { 1, 1 }, [AV_PIX_FMT_YUV411P] = { 1, 1 }, [AV_PIX_FMT_GRAY8] = { 1, 1 }, [AV_PIX_FMT_MONOWHITE] = { 1, 1 }, [AV_PIX_FMT_MONOBLACK] = { 1, 1 }, [AV_PIX_FMT_PAL8] = { 1, 0 }, [AV_PIX_FMT_YUVJ420P] = { 1, 1 }, [AV_PIX_FMT_YUVJ411P] = { 1, 1 }, [AV_PIX_FMT_YUVJ422P] = { 1, 1 }, [AV_PIX_FMT_YUVJ444P] = { 1, 1 }, [AV_PIX_FMT_YVYU422] = { 1, 1 }, [AV_PIX_FMT_UYVY422] = { 1, 1 }, [AV_PIX_FMT_UYYVYY411] = { 0, 0 }, [AV_PIX_FMT_BGR8] = { 1, 1 }, [AV_PIX_FMT_BGR4] = { 0, 1 }, [AV_PIX_FMT_BGR4_BYTE] = { 1, 1 }, [AV_PIX_FMT_RGB8] = { 1, 1 }, [AV_PIX_FMT_RGB4] = { 0, 1 }, [AV_PIX_FMT_RGB4_BYTE] = { 1, 1 }, [AV_PIX_FMT_NV12] = { 1, 1 }, [AV_PIX_FMT_NV21] = { 1, 1 }, [AV_PIX_FMT_ARGB] = { 1, 1 }, [AV_PIX_FMT_RGBA] = { 1, 1 }, [AV_PIX_FMT_ABGR] = { 1, 1 }, [AV_PIX_FMT_BGRA] = { 1, 1 }, [AV_PIX_FMT_0RGB] = { 1, 1 }, [AV_PIX_FMT_RGB0] = { 1, 1 }, [AV_PIX_FMT_0BGR] = { 1, 1 }, [AV_PIX_FMT_BGR0] = { 1, 1 }, [AV_PIX_FMT_GRAY10BE] = { 1, 1 }, [AV_PIX_FMT_GRAY10LE] = { 1, 1 }, [AV_PIX_FMT_GRAY12BE] = { 1, 1 }, [AV_PIX_FMT_GRAY12LE] = { 1, 1 }, [AV_PIX_FMT_GRAY16BE] = { 1, 1 }, [AV_PIX_FMT_GRAY16LE] = { 1, 1 }, [AV_PIX_FMT_YUV440P] = { 1, 1 }, [AV_PIX_FMT_YUVJ440P] = { 1, 1 }, [AV_PIX_FMT_YUV440P10LE] = { 1, 1 }, [AV_PIX_FMT_YUV440P10BE] = { 1, 1 }, [AV_PIX_FMT_YUV440P12LE] = { 1, 1 }, [AV_PIX_FMT_YUV440P12BE] = { 1, 1 }, [AV_PIX_FMT_YUVA420P] = { 1, 1 }, [AV_PIX_FMT_YUVA422P] = { 1, 1 }, [AV_PIX_FMT_YUVA444P] = { 1, 1 }, [AV_PIX_FMT_YUVA420P9BE] = { 1, 1 }, [AV_PIX_FMT_YUVA420P9LE] = { 1, 1 }, [AV_PIX_FMT_YUVA422P9BE] = { 1, 1 }, [AV_PIX_FMT_YUVA422P9LE] = { 1, 1 }, [AV_PIX_FMT_YUVA444P9BE] = { 1, 1 }, [AV_PIX_FMT_YUVA444P9LE] = { 1, 1 }, [AV_PIX_FMT_YUVA420P10BE]= { 1, 1 }, [AV_PIX_FMT_YUVA420P10LE]= { 1, 1 }, [AV_PIX_FMT_YUVA422P10BE]= { 1, 1 }, [AV_PIX_FMT_YUVA422P10LE]= { 1, 1 }, [AV_PIX_FMT_YUVA444P10BE]= { 1, 1 }, [AV_PIX_FMT_YUVA444P10LE]= { 1, 1 }, [AV_PIX_FMT_YUVA420P16BE]= { 1, 1 }, [AV_PIX_FMT_YUVA420P16LE]= { 1, 1 }, [AV_PIX_FMT_YUVA422P16BE]= { 1, 1 }, [AV_PIX_FMT_YUVA422P16LE]= { 1, 1 }, [AV_PIX_FMT_YUVA444P16BE]= { 1, 1 }, [AV_PIX_FMT_YUVA444P16LE]= { 1, 1 }, [AV_PIX_FMT_RGB48BE] = { 1, 1 }, [AV_PIX_FMT_RGB48LE] = { 1, 1 }, [AV_PIX_FMT_RGBA64BE] = { 1, 1, 1 }, [AV_PIX_FMT_RGBA64LE] = { 1, 1, 1 }, [AV_PIX_FMT_RGB565BE] = { 1, 1 }, [AV_PIX_FMT_RGB565LE] = { 1, 1 }, [AV_PIX_FMT_RGB555BE] = { 1, 1 }, [AV_PIX_FMT_RGB555LE] = { 1, 1 }, [AV_PIX_FMT_BGR565BE] = { 1, 1 }, [AV_PIX_FMT_BGR565LE] = { 1, 1 }, [AV_PIX_FMT_BGR555BE] = { 1, 1 }, [AV_PIX_FMT_BGR555LE] = { 1, 1 }, [AV_PIX_FMT_YUV420P16LE] = { 1, 1 }, [AV_PIX_FMT_YUV420P16BE] = { 1, 1 }, [AV_PIX_FMT_YUV422P16LE] = { 1, 1 }, [AV_PIX_FMT_YUV422P16BE] = { 1, 1 }, [AV_PIX_FMT_YUV444P16LE] = { 1, 1 }, [AV_PIX_FMT_YUV444P16BE] = { 1, 1 }, [AV_PIX_FMT_RGB444LE] = { 1, 1 }, [AV_PIX_FMT_RGB444BE] = { 1, 1 }, [AV_PIX_FMT_BGR444LE] = { 1, 1 }, [AV_PIX_FMT_BGR444BE] = { 1, 1 }, [AV_PIX_FMT_YA8] = { 1, 1 }, [AV_PIX_FMT_YA16BE] = { 1, 0 }, [AV_PIX_FMT_YA16LE] = { 1, 0 }, [AV_PIX_FMT_BGR48BE] = { 1, 1 }, [AV_PIX_FMT_BGR48LE] = { 1, 1 }, [AV_PIX_FMT_BGRA64BE] = { 1, 1, 1 }, [AV_PIX_FMT_BGRA64LE] = { 1, 1, 1 }, [AV_PIX_FMT_YUV420P9BE] = { 1, 1 }, [AV_PIX_FMT_YUV420P9LE] = { 1, 1 }, [AV_PIX_FMT_YUV420P10BE] = { 1, 1 }, [AV_PIX_FMT_YUV420P10LE] = { 1, 1 }, [AV_PIX_FMT_YUV420P12BE] = { 1, 1 }, [AV_PIX_FMT_YUV420P12LE] = { 1, 1 }, [AV_PIX_FMT_YUV420P14BE] = { 1, 1 }, [AV_PIX_FMT_YUV420P14LE] = { 1, 1 }, [AV_PIX_FMT_YUV422P9BE] = { 1, 1 }, [AV_PIX_FMT_YUV422P9LE] = { 1, 1 }, [AV_PIX_FMT_YUV422P10BE] = { 1, 1 }, [AV_PIX_FMT_YUV422P10LE] = { 1, 1 }, [AV_PIX_FMT_YUV422P12BE] = { 1, 1 }, [AV_PIX_FMT_YUV422P12LE] = { 1, 1 }, [AV_PIX_FMT_YUV422P14BE] = { 1, 1 }, [AV_PIX_FMT_YUV422P14LE] = { 1, 1 }, [AV_PIX_FMT_YUV444P9BE] = { 1, 1 }, [AV_PIX_FMT_YUV444P9LE] = { 1, 1 }, [AV_PIX_FMT_YUV444P10BE] = { 1, 1 }, [AV_PIX_FMT_YUV444P10LE] = { 1, 1 }, [AV_PIX_FMT_YUV444P12BE] = { 1, 1 }, [AV_PIX_FMT_YUV444P12LE] = { 1, 1 }, [AV_PIX_FMT_YUV444P14BE] = { 1, 1 }, [AV_PIX_FMT_YUV444P14LE] = { 1, 1 }, [AV_PIX_FMT_GBRP] = { 1, 1 }, [AV_PIX_FMT_GBRP9LE] = { 1, 1 }, [AV_PIX_FMT_GBRP9BE] = { 1, 1 }, [AV_PIX_FMT_GBRP10LE] = { 1, 1 }, [AV_PIX_FMT_GBRP10BE] = { 1, 1 }, [AV_PIX_FMT_GBRAP10LE] = { 1, 1 }, [AV_PIX_FMT_GBRAP10BE] = { 1, 1 }, [AV_PIX_FMT_GBRP12LE] = { 1, 1 }, [AV_PIX_FMT_GBRP12BE] = { 1, 1 }, [AV_PIX_FMT_GBRAP12LE] = { 1, 1 }, [AV_PIX_FMT_GBRAP12BE] = { 1, 1 }, [AV_PIX_FMT_GBRP14LE] = { 1, 1 }, [AV_PIX_FMT_GBRP14BE] = { 1, 1 }, [AV_PIX_FMT_GBRP16LE] = { 1, 1 }, [AV_PIX_FMT_GBRP16BE] = { 1, 1 }, [AV_PIX_FMT_GBRAP] = { 1, 1 }, [AV_PIX_FMT_GBRAP16LE] = { 1, 1 }, [AV_PIX_FMT_GBRAP16BE] = { 1, 1 }, [AV_PIX_FMT_BAYER_BGGR8] = { 1, 0 }, [AV_PIX_FMT_BAYER_RGGB8] = { 1, 0 }, [AV_PIX_FMT_BAYER_GBRG8] = { 1, 0 }, [AV_PIX_FMT_BAYER_GRBG8] = { 1, 0 }, [AV_PIX_FMT_BAYER_BGGR16LE] = { 1, 0 }, [AV_PIX_FMT_BAYER_BGGR16BE] = { 1, 0 }, [AV_PIX_FMT_BAYER_RGGB16LE] = { 1, 0 }, [AV_PIX_FMT_BAYER_RGGB16BE] = { 1, 0 }, [AV_PIX_FMT_BAYER_GBRG16LE] = { 1, 0 }, [AV_PIX_FMT_BAYER_GBRG16BE] = { 1, 0 }, [AV_PIX_FMT_BAYER_GRBG16LE] = { 1, 0 }, [AV_PIX_FMT_BAYER_GRBG16BE] = { 1, 0 }, [AV_PIX_FMT_XYZ12BE] = { 1, 1, 1 }, [AV_PIX_FMT_XYZ12LE] = { 1, 1, 1 }, [AV_PIX_FMT_AYUV64LE] = { 1, 1}, [AV_PIX_FMT_P010LE] = { 1, 1 }, [AV_PIX_FMT_P010BE] = { 1, 1 }, [AV_PIX_FMT_P016LE] = { 1, 0 }, [AV_PIX_FMT_P016BE] = { 1, 0 }, }; int sws_isSupportedInput(enum AVPixelFormat pix_fmt) { return (unsigned)pix_fmt < AV_PIX_FMT_NB ? format_entries[pix_fmt].is_supported_in : 0; } int sws_isSupportedOutput(enum AVPixelFormat pix_fmt) { return (unsigned)pix_fmt < AV_PIX_FMT_NB ? format_entries[pix_fmt].is_supported_out : 0; } int sws_isSupportedEndiannessConversion(enum AVPixelFormat pix_fmt) { return (unsigned)pix_fmt < AV_PIX_FMT_NB ? format_entries[pix_fmt].is_supported_endianness : 0; } static double getSplineCoeff(double a, double b, double c, double d, double dist) { if (dist <= 1.0) return ((d * dist + c) * dist + b) * dist + a; else return getSplineCoeff(0.0, b + 2.0 * c + 3.0 * d, c + 3.0 * d, -b - 3.0 * c - 6.0 * d, dist - 1.0); } static av_cold int get_local_pos(SwsContext *s, int chr_subsample, int pos, int dir) { if (pos == -1 || pos <= -513) { pos = (128 << chr_subsample) - 128; } pos += 128; // relative to ideal left edge return pos >> chr_subsample; } typedef struct { int flag; ///< flag associated to the algorithm const char *description; ///< human-readable description int size_factor; ///< size factor used when initing the filters } ScaleAlgorithm; static const ScaleAlgorithm scale_algorithms[] = { { SWS_AREA, "area averaging", 1 /* downscale only, for upscale it is bilinear */ }, { SWS_BICUBIC, "bicubic", 4 }, { SWS_BICUBLIN, "luma bicubic / chroma bilinear", -1 }, { SWS_BILINEAR, "bilinear", 2 }, { SWS_FAST_BILINEAR, "fast bilinear", -1 }, { SWS_GAUSS, "Gaussian", 8 /* infinite ;) */ }, { SWS_LANCZOS, "Lanczos", -1 /* custom */ }, { SWS_POINT, "nearest neighbor / point", -1 }, { SWS_SINC, "sinc", 20 /* infinite ;) */ }, { SWS_SPLINE, "bicubic spline", 20 /* infinite :)*/ }, { SWS_X, "experimental", 8 }, }; static av_cold int initFilter(int16_t **outFilter, int32_t **filterPos, int *outFilterSize, int xInc, int srcW, int dstW, int filterAlign, int one, int flags, int cpu_flags, SwsVector *srcFilter, SwsVector *dstFilter, double param[2], int srcPos, int dstPos) { int i; int filterSize; int filter2Size; int minFilterSize; int64_t *filter = NULL; int64_t *filter2 = NULL; const int64_t fone = 1LL << (54 - FFMIN(av_log2(srcW/dstW), 8)); int ret = -1; emms_c(); // FIXME should not be required but IS (even for non-MMX versions) // NOTE: the +3 is for the MMX(+1) / SSE(+3) scaler which reads over the end FF_ALLOC_ARRAY_OR_GOTO(NULL, *filterPos, (dstW + 3), sizeof(**filterPos), fail); if (FFABS(xInc - 0x10000) < 10 && srcPos == dstPos) { // unscaled int i; filterSize = 1; FF_ALLOCZ_ARRAY_OR_GOTO(NULL, filter, dstW, sizeof(*filter) * filterSize, fail); for (i = 0; i < dstW; i++) { filter[i * filterSize] = fone; (*filterPos)[i] = i; } } else if (flags & SWS_POINT) { // lame looking point sampling mode int i; int64_t xDstInSrc; filterSize = 1; FF_ALLOC_ARRAY_OR_GOTO(NULL, filter, dstW, sizeof(*filter) * filterSize, fail); xDstInSrc = ((dstPos*(int64_t)xInc)>>8) - ((srcPos*0x8000LL)>>7); for (i = 0; i < dstW; i++) { int xx = (xDstInSrc - ((filterSize - 1) << 15) + (1 << 15)) >> 16; (*filterPos)[i] = xx; filter[i] = fone; xDstInSrc += xInc; } } else if ((xInc <= (1 << 16) && (flags & SWS_AREA)) || (flags & SWS_FAST_BILINEAR)) { // bilinear upscale int i; int64_t xDstInSrc; filterSize = 2; FF_ALLOC_ARRAY_OR_GOTO(NULL, filter, dstW, sizeof(*filter) * filterSize, fail); xDstInSrc = ((dstPos*(int64_t)xInc)>>8) - ((srcPos*0x8000LL)>>7); for (i = 0; i < dstW; i++) { int xx = (xDstInSrc - ((filterSize - 1) << 15) + (1 << 15)) >> 16; int j; (*filterPos)[i] = xx; // bilinear upscale / linear interpolate / area averaging for (j = 0; j < filterSize; j++) { int64_t coeff= fone - FFABS(((int64_t)xx<<16) - xDstInSrc)*(fone>>16); if (coeff < 0) coeff = 0; filter[i * filterSize + j] = coeff; xx++; } xDstInSrc += xInc; } } else { int64_t xDstInSrc; int sizeFactor = -1; for (i = 0; i < FF_ARRAY_ELEMS(scale_algorithms); i++) { if (flags & scale_algorithms[i].flag && scale_algorithms[i].size_factor > 0) { sizeFactor = scale_algorithms[i].size_factor; break; } } if (flags & SWS_LANCZOS) sizeFactor = param[0] != SWS_PARAM_DEFAULT ? ceil(2 * param[0]) : 6; av_assert0(sizeFactor > 0); if (xInc <= 1 << 16) filterSize = 1 + sizeFactor; // upscale else filterSize = 1 + (sizeFactor * srcW + dstW - 1) / dstW; filterSize = FFMIN(filterSize, srcW - 2); filterSize = FFMAX(filterSize, 1); FF_ALLOC_ARRAY_OR_GOTO(NULL, filter, dstW, sizeof(*filter) * filterSize, fail); xDstInSrc = ((dstPos*(int64_t)xInc)>>7) - ((srcPos*0x10000LL)>>7); for (i = 0; i < dstW; i++) { int xx = (xDstInSrc - (filterSize - 2) * (1LL<<16)) / (1 << 17); int j; (*filterPos)[i] = xx; for (j = 0; j < filterSize; j++) { int64_t d = (FFABS(((int64_t)xx * (1 << 17)) - xDstInSrc)) << 13; double floatd; int64_t coeff; if (xInc > 1 << 16) d = d * dstW / srcW; floatd = d * (1.0 / (1 << 30)); if (flags & SWS_BICUBIC) { int64_t B = (param[0] != SWS_PARAM_DEFAULT ? param[0] : 0) * (1 << 24); int64_t C = (param[1] != SWS_PARAM_DEFAULT ? param[1] : 0.6) * (1 << 24); if (d >= 1LL << 31) { coeff = 0.0; } else { int64_t dd = (d * d) >> 30; int64_t ddd = (dd * d) >> 30; if (d < 1LL << 30) coeff = (12 * (1 << 24) - 9 * B - 6 * C) * ddd + (-18 * (1 << 24) + 12 * B + 6 * C) * dd + (6 * (1 << 24) - 2 * B) * (1 << 30); else coeff = (-B - 6 * C) * ddd + (6 * B + 30 * C) * dd + (-12 * B - 48 * C) * d + (8 * B + 24 * C) * (1 << 30); } coeff /= (1LL<<54)/fone; } #if 0 else if (flags & SWS_X) { double p = param ? param * 0.01 : 0.3; coeff = d ? sin(d * M_PI) / (d * M_PI) : 1.0; coeff *= pow(2.0, -p * d * d); } #endif else if (flags & SWS_X) { double A = param[0] != SWS_PARAM_DEFAULT ? param[0] : 1.0; double c; if (floatd < 1.0) c = cos(floatd * M_PI); else c = -1.0; if (c < 0.0) c = -pow(-c, A); else c = pow(c, A); coeff = (c * 0.5 + 0.5) * fone; } else if (flags & SWS_AREA) { int64_t d2 = d - (1 << 29); if (d2 * xInc < -(1LL << (29 + 16))) coeff = 1.0 * (1LL << (30 + 16)); else if (d2 * xInc < (1LL << (29 + 16))) coeff = -d2 * xInc + (1LL << (29 + 16)); else coeff = 0.0; coeff *= fone >> (30 + 16); } else if (flags & SWS_GAUSS) { double p = param[0] != SWS_PARAM_DEFAULT ? param[0] : 3.0; coeff = exp2(-p * floatd * floatd) * fone; } else if (flags & SWS_SINC) { coeff = (d ? sin(floatd * M_PI) / (floatd * M_PI) : 1.0) * fone; } else if (flags & SWS_LANCZOS) { double p = param[0] != SWS_PARAM_DEFAULT ? param[0] : 3.0; coeff = (d ? sin(floatd * M_PI) * sin(floatd * M_PI / p) / (floatd * floatd * M_PI * M_PI / p) : 1.0) * fone; if (floatd > p) coeff = 0; } else if (flags & SWS_BILINEAR) { coeff = (1 << 30) - d; if (coeff < 0) coeff = 0; coeff *= fone >> 30; } else if (flags & SWS_SPLINE) { double p = -2.196152422706632; coeff = getSplineCoeff(1.0, 0.0, p, -p - 1.0, floatd) * fone; } else { av_assert0(0); }