swscale: Implement alphablendaway for planar 4:4:4 formats
Fixes Ticket4746 Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
parent
c382d9e8cb
commit
d0e0757e9a
@ -122,6 +122,19 @@ a_dither).
|
|||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@item alphablend
|
||||||
|
Set the alpha blending to use when the input has alpha but the output does not.
|
||||||
|
Default value is @samp{none}.
|
||||||
|
|
||||||
|
@table @samp
|
||||||
|
@item uniform_color
|
||||||
|
Blend onto a uniform background color
|
||||||
|
|
||||||
|
@item none
|
||||||
|
No blending
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@c man end SCALER OPTIONS
|
@c man end SCALER OPTIONS
|
||||||
|
@ -5,7 +5,8 @@ NAME = swscale
|
|||||||
HEADERS = swscale.h \
|
HEADERS = swscale.h \
|
||||||
version.h \
|
version.h \
|
||||||
|
|
||||||
OBJS = hscale_fast_bilinear.o \
|
OBJS = alphablend.o \
|
||||||
|
hscale_fast_bilinear.o \
|
||||||
input.o \
|
input.o \
|
||||||
options.o \
|
options.o \
|
||||||
output.o \
|
output.o \
|
||||||
|
74
libswscale/alphablend.c
Normal file
74
libswscale/alphablend.c
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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 "swscale_internal.h"
|
||||||
|
|
||||||
|
int ff_sws_alphablendaway(SwsContext *c, const uint8_t *src[],
|
||||||
|
int srcStride[], int srcSliceY, int srcSliceH,
|
||||||
|
uint8_t *dst[], int dstStride[])
|
||||||
|
{
|
||||||
|
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->srcFormat);
|
||||||
|
int nb_components = desc->nb_components;
|
||||||
|
int plane, x, y;
|
||||||
|
int plane_count = isGray(c->srcFormat) ? 1 : 3;
|
||||||
|
int sixteen_bits = desc->comp[0].depth_minus1 >= 8;
|
||||||
|
unsigned off = 1<<desc->comp[0].depth_minus1;
|
||||||
|
unsigned shift = desc->comp[0].depth_minus1 + 1;
|
||||||
|
unsigned max = (1<<shift) - 1;
|
||||||
|
|
||||||
|
av_assert0(plane_count == nb_components - 1);
|
||||||
|
if (desc->flags & AV_PIX_FMT_FLAG_PLANAR) {
|
||||||
|
for (plane = 0; plane < plane_count; plane++) {
|
||||||
|
int w = plane ? c->chrSrcW : c->srcW;
|
||||||
|
int y_subsample = plane ? desc->log2_chroma_h: 0;
|
||||||
|
for (y = srcSliceY >> y_subsample; y < FF_CEIL_RSHIFT(srcSliceH, y_subsample); y++) {
|
||||||
|
if (sixteen_bits) {
|
||||||
|
const uint16_t *s = src[plane ] + srcStride[plane] * y;
|
||||||
|
const uint16_t *a = src[plane_count] + srcStride[plane_count] * y;
|
||||||
|
uint16_t *d = dst[plane ] + dstStride[plane] * y;
|
||||||
|
unsigned target = plane && !(desc->flags & AV_PIX_FMT_FLAG_RGB) ? 1<<desc->comp[0].depth_minus1 : 0;
|
||||||
|
if ((!isBE(c->dstFormat)) == !HAVE_BIGENDIAN) {
|
||||||
|
for (x = 0; x < w; x++) {
|
||||||
|
unsigned u = s[x]*a[x] + target*(max-a[x]) + off;
|
||||||
|
d[x] = av_clip((u + (u >> shift)) >> shift, 0, max);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (x = 0; x < w; x++) {
|
||||||
|
unsigned aswap =av_bswap16(a[x]);
|
||||||
|
unsigned u = av_bswap16(s[x])*aswap + target*(max-aswap) + off;
|
||||||
|
d[x] = av_clip((u + (u >> shift)) >> shift, 0, max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const uint8_t *s = src[plane ] + srcStride[plane] * y;
|
||||||
|
const uint8_t *a = src[plane_count] + srcStride[plane_count] * y;
|
||||||
|
uint8_t *d = dst[plane ] + dstStride[plane] * y;
|
||||||
|
unsigned target = plane && !(desc->flags & AV_PIX_FMT_FLAG_RGB) ? 128 : 0;
|
||||||
|
for (x = 0; x < w; x++) {
|
||||||
|
unsigned u = s[x]*a[x] + target*(255-a[x]) + 128;
|
||||||
|
d[x] = (257*u) >> 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -78,6 +78,9 @@ static const AVOption swscale_options[] = {
|
|||||||
{ "gamma", "gamma correct scaling", OFFSET(gamma_flag), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE, "gamma" },
|
{ "gamma", "gamma correct scaling", OFFSET(gamma_flag), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE, "gamma" },
|
||||||
{ "true", "enable", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "gamma" },
|
{ "true", "enable", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "gamma" },
|
||||||
{ "false", "disable", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "gamma" },
|
{ "false", "disable", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "gamma" },
|
||||||
|
{ "alphablend", "mode for alpha -> non alpha", OFFSET(alphablend),AV_OPT_TYPE_INT, { .i64 = SWS_ALPHA_BLEND_NONE}, 0, SWS_ALPHA_BLEND_NB-1, VE, "alphablend" },
|
||||||
|
{ "none", "ignore alpha", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_NONE}, INT_MIN, INT_MAX, VE, "alphablend" },
|
||||||
|
{ "uniform_color", "blend onto a uniform color", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_ALPHA_BLEND_UNIFORM},INT_MIN, INT_MAX, VE, "alphablend" },
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
@ -75,6 +75,12 @@ typedef enum SwsDither {
|
|||||||
NB_SWS_DITHER,
|
NB_SWS_DITHER,
|
||||||
} SwsDither;
|
} SwsDither;
|
||||||
|
|
||||||
|
typedef enum SwsAlphaBlend {
|
||||||
|
SWS_ALPHA_BLEND_NONE = 0,
|
||||||
|
SWS_ALPHA_BLEND_UNIFORM,
|
||||||
|
SWS_ALPHA_BLEND_NB,
|
||||||
|
} SwsAlphaBlend;
|
||||||
|
|
||||||
typedef int (*SwsFunc)(struct SwsContext *context, const uint8_t *src[],
|
typedef int (*SwsFunc)(struct SwsContext *context, const uint8_t *src[],
|
||||||
int srcStride[], int srcSliceY, int srcSliceH,
|
int srcStride[], int srcSliceY, int srcSliceH,
|
||||||
uint8_t *dst[], int dstStride[]);
|
uint8_t *dst[], int dstStride[]);
|
||||||
@ -611,6 +617,8 @@ typedef struct SwsContext {
|
|||||||
int needs_hcscale; ///< Set if there are chroma planes to be converted.
|
int needs_hcscale; ///< Set if there are chroma planes to be converted.
|
||||||
|
|
||||||
SwsDither dither;
|
SwsDither dither;
|
||||||
|
|
||||||
|
SwsAlphaBlend alphablend;
|
||||||
} SwsContext;
|
} SwsContext;
|
||||||
//FIXME check init (where 0)
|
//FIXME check init (where 0)
|
||||||
|
|
||||||
@ -901,6 +909,10 @@ struct SwsContext *sws_alloc_set_opts(int srcW, int srcH, enum AVPixelFormat src
|
|||||||
int dstW, int dstH, enum AVPixelFormat dstFormat,
|
int dstW, int dstH, enum AVPixelFormat dstFormat,
|
||||||
int flags, const double *param);
|
int flags, const double *param);
|
||||||
|
|
||||||
|
int ff_sws_alphablendaway(SwsContext *c, const uint8_t *src[],
|
||||||
|
int srcStride[], int srcSliceY, int srcSliceH,
|
||||||
|
uint8_t *dst[], int dstStride[]);
|
||||||
|
|
||||||
static inline void fillPlane16(uint8_t *plane, int stride, int width, int height, int y,
|
static inline void fillPlane16(uint8_t *plane, int stride, int width, int height, int y,
|
||||||
int alpha, int bits, const int big_endian)
|
int alpha, int bits, const int big_endian)
|
||||||
{
|
{
|
||||||
|
@ -979,6 +979,58 @@ static uint16_t * alloc_gamma_tbl(double e)
|
|||||||
return tbl;
|
return tbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum AVPixelFormat alphaless_fmt(enum AVPixelFormat fmt)
|
||||||
|
{
|
||||||
|
switch(fmt) {
|
||||||
|
// case AV_PIX_FMT_ARGB: return AV_PIX_FMT_RGB24;
|
||||||
|
// case AV_PIX_FMT_RGBA: return AV_PIX_FMT_RGB24;
|
||||||
|
// case AV_PIX_FMT_ABGR: return AV_PIX_FMT_BGR24;
|
||||||
|
// case AV_PIX_FMT_BGRA: return AV_PIX_FMT_BGR24;
|
||||||
|
// case AV_PIX_FMT_YA8: return AV_PIX_FMT_GRAY8;
|
||||||
|
//
|
||||||
|
// case AV_PIX_FMT_YUVA420P: return AV_PIX_FMT_YUV420P;
|
||||||
|
// case AV_PIX_FMT_YUVA422P: return AV_PIX_FMT_YUV422P;
|
||||||
|
case AV_PIX_FMT_YUVA444P: return AV_PIX_FMT_YUV444P;
|
||||||
|
|
||||||
|
case AV_PIX_FMT_GBRAP: return AV_PIX_FMT_GBRP;
|
||||||
|
|
||||||
|
case AV_PIX_FMT_GBRAP16LE: return AV_PIX_FMT_GBRP16;
|
||||||
|
case AV_PIX_FMT_GBRAP16BE: return AV_PIX_FMT_GBRP16;
|
||||||
|
|
||||||
|
// case AV_PIX_FMT_RGBA64LE: return AV_PIX_FMT_RGB48;
|
||||||
|
// case AV_PIX_FMT_RGBA64BE: return AV_PIX_FMT_RGB48;
|
||||||
|
// case AV_PIX_FMT_BGRA64LE: return AV_PIX_FMT_BGR48;
|
||||||
|
// case AV_PIX_FMT_BGRA64BE: return AV_PIX_FMT_BGR48;
|
||||||
|
|
||||||
|
// case AV_PIX_FMT_YA16BE: return AV_PIX_FMT_GRAY16;
|
||||||
|
// case AV_PIX_FMT_YA16LE: return AV_PIX_FMT_GRAY16;
|
||||||
|
|
||||||
|
// case AV_PIX_FMT_YUVA420P9BE: return AV_PIX_FMT_YUV420P9;
|
||||||
|
// case AV_PIX_FMT_YUVA422P9BE: return AV_PIX_FMT_YUV422P9;
|
||||||
|
case AV_PIX_FMT_YUVA444P9BE: return AV_PIX_FMT_YUV444P9;
|
||||||
|
// case AV_PIX_FMT_YUVA420P9LE: return AV_PIX_FMT_YUV420P9;
|
||||||
|
// case AV_PIX_FMT_YUVA422P9LE: return AV_PIX_FMT_YUV422P9;
|
||||||
|
case AV_PIX_FMT_YUVA444P9LE: return AV_PIX_FMT_YUV444P9;
|
||||||
|
// case AV_PIX_FMT_YUVA420P10BE: return AV_PIX_FMT_YUV420P10;
|
||||||
|
// case AV_PIX_FMT_YUVA422P10BE: return AV_PIX_FMT_YUV422P10;
|
||||||
|
case AV_PIX_FMT_YUVA444P10BE: return AV_PIX_FMT_YUV444P10;
|
||||||
|
// case AV_PIX_FMT_YUVA420P10LE: return AV_PIX_FMT_YUV420P10;
|
||||||
|
// case AV_PIX_FMT_YUVA422P10LE: return AV_PIX_FMT_YUV422P10;
|
||||||
|
case AV_PIX_FMT_YUVA444P10LE: return AV_PIX_FMT_YUV444P10;
|
||||||
|
// case AV_PIX_FMT_YUVA420P16BE: return AV_PIX_FMT_YUV420P16;
|
||||||
|
// case AV_PIX_FMT_YUVA422P16BE: return AV_PIX_FMT_YUV422P16;
|
||||||
|
case AV_PIX_FMT_YUVA444P16BE: return AV_PIX_FMT_YUV444P16;
|
||||||
|
// case AV_PIX_FMT_YUVA420P16LE: return AV_PIX_FMT_YUV420P16;
|
||||||
|
// case AV_PIX_FMT_YUVA422P16LE: return AV_PIX_FMT_YUV422P16;
|
||||||
|
case AV_PIX_FMT_YUVA444P16LE: return AV_PIX_FMT_YUV444P16;
|
||||||
|
|
||||||
|
// case AV_PIX_FMT_AYUV64LE:
|
||||||
|
// case AV_PIX_FMT_AYUV64BE:
|
||||||
|
// case AV_PIX_FMT_PAL8:
|
||||||
|
default: return AV_PIX_FMT_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
|
av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
|
||||||
SwsFilter *dstFilter)
|
SwsFilter *dstFilter)
|
||||||
{
|
{
|
||||||
@ -1340,6 +1392,39 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CONFIG_SWSCALE_ALPHA && isALPHA(srcFormat) && !isALPHA(dstFormat)) {
|
||||||
|
enum AVPixelFormat tmpFormat = alphaless_fmt(srcFormat);
|
||||||
|
|
||||||
|
if (tmpFormat != AV_PIX_FMT_NONE && c->alphablend != SWS_ALPHA_BLEND_NONE)
|
||||||
|
if (!unscaled ||
|
||||||
|
dstFormat != tmpFormat ||
|
||||||
|
usesHFilter || usesVFilter ||
|
||||||
|
c->srcRange != c->dstRange
|
||||||
|
) {
|
||||||
|
ret = av_image_alloc(c->cascaded_tmp, c->cascaded_tmpStride,
|
||||||
|
srcW, srcH, tmpFormat, 64);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
c->cascaded_context[0] = sws_alloc_set_opts(srcW, srcH, srcFormat,
|
||||||
|
srcW, srcH, tmpFormat,
|
||||||
|
flags, c->param);
|
||||||
|
if (!c->cascaded_context[0])
|
||||||
|
return -1;
|
||||||
|
c->cascaded_context[0]->alphablend = c->alphablend;
|
||||||
|
ret = sws_init_context(c->cascaded_context[0], NULL , NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
c->cascaded_context[1] = sws_getContext(srcW, srcH, tmpFormat,
|
||||||
|
dstW, dstH, dstFormat,
|
||||||
|
flags, srcFilter, dstFilter, c->param);
|
||||||
|
if (!c->cascaded_context[1])
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#define USE_MMAP (HAVE_MMAP && HAVE_MPROTECT && defined MAP_ANONYMOUS)
|
#define USE_MMAP (HAVE_MMAP && HAVE_MPROTECT && defined MAP_ANONYMOUS)
|
||||||
|
|
||||||
/* precalculate horizontal scaler filter coefficients */
|
/* precalculate horizontal scaler filter coefficients */
|
||||||
@ -1586,6 +1671,22 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
|
|||||||
c->chrXInc, c->chrYInc);
|
c->chrXInc, c->chrYInc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* alpha blend special case, note this has been split via cascaded contexts if its scaled */
|
||||||
|
if (unscaled && !usesHFilter && !usesVFilter &&
|
||||||
|
c->alphablend != SWS_ALPHA_BLEND_NONE &&
|
||||||
|
isALPHA(srcFormat) &&
|
||||||
|
(c->srcRange == c->dstRange || isAnyRGB(dstFormat)) &&
|
||||||
|
alphaless_fmt(srcFormat) == dstFormat
|
||||||
|
) {
|
||||||
|
c->swscale = ff_sws_alphablendaway;
|
||||||
|
|
||||||
|
if (flags & SWS_PRINT_INFO)
|
||||||
|
av_log(c, AV_LOG_INFO,
|
||||||
|
"using alpha blendaway %s -> %s special converter\n",
|
||||||
|
av_get_pix_fmt_name(srcFormat), av_get_pix_fmt_name(dstFormat));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* unscaled special cases */
|
/* unscaled special cases */
|
||||||
if (unscaled && !usesHFilter && !usesVFilter &&
|
if (unscaled && !usesHFilter && !usesVFilter &&
|
||||||
(c->srcRange == c->dstRange || isAnyRGB(dstFormat))) {
|
(c->srcRange == c->dstRange || isAnyRGB(dstFormat))) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user