avfilter/drawutils: >8 bit support

Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
Paul B Mahol 2016-02-15 17:07:33 +01:00
parent 6b706ce85f
commit 38ed528fa5
3 changed files with 239 additions and 43 deletions

View File

@ -24,6 +24,7 @@
#include "libavutil/avassert.h"
#include "libavutil/avutil.h"
#include "libavutil/colorspace.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mem.h"
#include "libavutil/pixdesc.h"
#include "drawutils.h"
@ -175,8 +176,10 @@ int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
return AVERROR(ENOSYS);
for (i = 0; i < desc->nb_components; i++) {
c = &desc->comp[i];
/* for now, only 8-bits formats */
if (c->depth != 8)
/* for now, only 8-16 bits formats */
if (c->depth < 8 || c->depth > 16)
return AVERROR(ENOSYS);
if (desc->flags & AV_PIX_FMT_FLAG_BE)
return AVERROR(ENOSYS);
if (c->plane >= MAX_PLANES)
return AVERROR(ENOSYS);
@ -184,6 +187,9 @@ int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
if (pixelstep[c->plane] != 0 &&
pixelstep[c->plane] != c->step)
return AVERROR(ENOSYS);
if (pixelstep[c->plane] == 6 &&
c->depth == 16)
return AVERROR(ENOSYS);
pixelstep[c->plane] = c->step;
if (pixelstep[c->plane] >= 8)
return AVERROR(ENOSYS);
@ -214,11 +220,18 @@ void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4
if ((draw->desc->flags & AV_PIX_FMT_FLAG_RGB) &&
ff_fill_rgba_map(rgba_map, draw->format) >= 0) {
if (draw->nb_planes == 1) {
for (i = 0; i < 4; i++)
for (i = 0; i < 4; i++) {
color->comp[0].u8[rgba_map[i]] = rgba[i];
if (draw->desc->comp[rgba_map[i]].depth > 8) {
color->comp[0].u16[rgba_map[i]] = color->comp[0].u8[rgba_map[i]] << 8;
}
}
} else {
for (i = 0; i < 4; i++)
for (i = 0; i < 4; i++) {
color->comp[rgba_map[i]].u8[0] = rgba[i];
if (draw->desc->comp[rgba_map[i]].depth > 8)
color->comp[rgba_map[i]].u16[0] = color->comp[rgba_map[i]].u8[0] << (draw->desc->comp[rgba_map[i]].depth - 8);
}
}
} else if (draw->nb_planes == 3 || draw->nb_planes == 4) {
/* assume YUV */
@ -226,9 +239,22 @@ void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4
color->comp[1].u8[0] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0);
color->comp[2].u8[0] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0);
color->comp[3].u8[0] = rgba[3];
if (draw->desc->comp[0].depth > 8)
color->comp[0].u16[0] = color->comp[0].u8[0] << (draw->desc->comp[0].depth - 8);
if (draw->desc->comp[1].depth > 8)
color->comp[1].u16[0] = color->comp[1].u8[0] << (draw->desc->comp[1].depth - 8);
if (draw->desc->comp[2].depth > 8)
color->comp[2].u16[0] = color->comp[2].u8[0] << (draw->desc->comp[2].depth - 8);
if (draw->desc->comp[3].depth > 8)
color->comp[3].u16[0] = color->comp[3].u8[0] << (draw->desc->comp[3].depth - 8);
} else if (draw->format == AV_PIX_FMT_GRAY8 || draw->format == AV_PIX_FMT_GRAY8A) {
color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
color->comp[1].u8[0] = rgba[3];
} else if (draw->format == AV_PIX_FMT_GRAY16 || draw->format == AV_PIX_FMT_YA16) {
color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]);
color->comp[0].u16[0] = color->comp[0].u8[0] << 8;
color->comp[1].u8[0] = rgba[3];
color->comp[1].u16[0] = color->comp[1].u8[0] << 8;
} else {
av_log(NULL, AV_LOG_WARNING,
"Color conversion not implemented for %s\n", draw->desc->name);
@ -361,6 +387,31 @@ static void blend_line(uint8_t *dst, unsigned src, unsigned alpha,
}
}
static void blend_line16(uint8_t *dst, unsigned src, unsigned alpha,
int dx, int w, unsigned hsub, int left, int right)
{
unsigned asrc = alpha * src;
unsigned tau = 0x10001 - alpha;
int x;
if (left) {
unsigned suba = (left * alpha) >> hsub;
uint16_t value = AV_RL16(dst);
AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
dst += dx;
}
for (x = 0; x < w; x++) {
uint16_t value = AV_RL16(dst);
AV_WL16(dst, (value * tau + asrc) >> 16);
dst += dx;
}
if (right) {
unsigned suba = (right * alpha) >> hsub;
uint16_t value = AV_RL16(dst);
AV_WL16(dst, (value * (0x10001 - suba) + src * suba) >> 16);
}
}
void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
uint8_t *dst[], int dst_linesize[],
int dst_w, int dst_h,
@ -375,8 +426,13 @@ void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
clip_interval(dst_h, &y0, &h, NULL);
if (w <= 0 || h <= 0 || !color->rgba[3])
return;
/* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
alpha = 0x10203 * color->rgba[3] + 0x2;
if (draw->desc->comp[0].depth <= 8) {
/* 0x10203 * alpha + 2 is in the [ 2 ; 0x1010101 - 2 ] range */
alpha = 0x10203 * color->rgba[3] + 0x2;
} else {
/* 0x101 * alpha is in the [ 2 ; 0x1001] range */
alpha = 0x101 * color->rgba[3] + 0x2;
}
nb_planes = (draw->nb_planes - 1) | 1; /* eliminate alpha */
for (plane = 0; plane < nb_planes; plane++) {
nb_comp = draw->pixelstep[plane];
@ -388,29 +444,77 @@ void ff_blend_rectangle(FFDrawContext *draw, FFDrawColor *color,
subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
for (comp = 0; comp < nb_comp; comp++) {
const int depth = draw->desc->comp[comp].depth;
if (!component_used(draw, plane, comp))
continue;
p = p0 + comp;
if (top) {
blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
draw->pixelstep[plane], w_sub,
draw->hsub[plane], left, right);
if (depth <= 8) {
blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
draw->pixelstep[plane], w_sub,
draw->hsub[plane], left, right);
} else {
blend_line16(p, color->comp[plane].u16[comp], alpha >> 1,
draw->pixelstep[plane], w_sub,
draw->hsub[plane], left, right);
}
p += dst_linesize[plane];
}
for (y = 0; y < h_sub; y++) {
blend_line(p, color->comp[plane].u8[comp], alpha,
draw->pixelstep[plane], w_sub,
draw->hsub[plane], left, right);
p += dst_linesize[plane];
if (depth <= 8) {
for (y = 0; y < h_sub; y++) {
blend_line(p, color->comp[plane].u8[comp], alpha,
draw->pixelstep[plane], w_sub,
draw->hsub[plane], left, right);
p += dst_linesize[plane];
}
} else {
for (y = 0; y < h_sub; y++) {
blend_line16(p, color->comp[plane].u16[comp], alpha,
draw->pixelstep[plane], w_sub,
draw->hsub[plane], left, right);
p += dst_linesize[plane];
}
}
if (bottom) {
if (depth <= 8) {
blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
draw->pixelstep[plane], w_sub,
draw->hsub[plane], left, right);
} else {
blend_line16(p, color->comp[plane].u16[comp], alpha >> 1,
draw->pixelstep[plane], w_sub,
draw->hsub[plane], left, right);
}
}
if (bottom)
blend_line(p, color->comp[plane].u8[comp], alpha >> 1,
draw->pixelstep[plane], w_sub,
draw->hsub[plane], left, right);
}
}
}
static void blend_pixel16(uint8_t *dst, unsigned src, unsigned alpha,
const uint8_t *mask, int mask_linesize, int l2depth,
unsigned w, unsigned h, unsigned shift, unsigned xm0)
{
unsigned xm, x, y, t = 0;
unsigned xmshf = 3 - l2depth;
unsigned xmmod = 7 >> l2depth;
unsigned mbits = (1 << (1 << l2depth)) - 1;
unsigned mmult = 255 / mbits;
uint16_t value = AV_RL16(dst);
for (y = 0; y < h; y++) {
xm = xm0;
for (x = 0; x < w; x++) {
t += ((mask[xm >> xmshf] >> ((~xm & xmmod) << l2depth)) & mbits)
* mmult;
xm++;
}
mask += mask_linesize;
}
alpha = (t >> shift) * alpha;
AV_WL16(dst, ((0x10001 - alpha) * value + alpha * src) >> 16);
}
static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha,
const uint8_t *mask, int mask_linesize, int l2depth,
unsigned w, unsigned h, unsigned shift, unsigned xm0)
@ -434,6 +538,31 @@ static void blend_pixel(uint8_t *dst, unsigned src, unsigned alpha,
*dst = ((0x1010101 - alpha) * *dst + alpha * src) >> 24;
}
static void blend_line_hv16(uint8_t *dst, int dst_delta,
unsigned src, unsigned alpha,
const uint8_t *mask, int mask_linesize, int l2depth, int w,
unsigned hsub, unsigned vsub,
int xm, int left, int right, int hband)
{
int x;
if (left) {
blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
left, hband, hsub + vsub, xm);
dst += dst_delta;
xm += left;
}
for (x = 0; x < w; x++) {
blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
1 << hsub, hband, hsub + vsub, xm);
dst += dst_delta;
xm += 1 << hsub;
}
if (right)
blend_pixel16(dst, src, alpha, mask, mask_linesize, l2depth,
right, hband, hsub + vsub, xm);
}
static void blend_line_hv(uint8_t *dst, int dst_delta,
unsigned src, unsigned alpha,
const uint8_t *mask, int mask_linesize, int l2depth, int w,
@ -474,9 +603,13 @@ void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
mask += ym0 * mask_linesize;
if (mask_w <= 0 || mask_h <= 0 || !color->rgba[3])
return;
/* alpha is in the [ 0 ; 0x10203 ] range,
alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */
alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
if (draw->desc->comp[0].depth <= 8) {
/* alpha is in the [ 0 ; 0x10203 ] range,
alpha * mask is in the [ 0 ; 0x1010101 - 4 ] range */
alpha = (0x10307 * color->rgba[3] + 0x3) >> 8;
} else {
alpha = (0x101 * color->rgba[3] + 0x2) >> 8;
}
nb_planes = (draw->nb_planes - 1) | 1; /* eliminate alpha */
for (plane = 0; plane < nb_planes; plane++) {
nb_comp = draw->pixelstep[plane];
@ -488,34 +621,65 @@ void ff_blend_mask(FFDrawContext *draw, FFDrawColor *color,
subsampling_bounds(draw->hsub[plane], &x_sub, &w_sub, &left, &right);
subsampling_bounds(draw->vsub[plane], &y_sub, &h_sub, &top, &bottom);
for (comp = 0; comp < nb_comp; comp++) {
const int depth = draw->desc->comp[comp].depth;
if (!component_used(draw, plane, comp))
continue;
p = p0 + comp;
m = mask;
if (top) {
blend_line_hv(p, draw->pixelstep[plane],
color->comp[plane].u8[comp], alpha,
m, mask_linesize, l2depth, w_sub,
draw->hsub[plane], draw->vsub[plane],
xm0, left, right, top);
if (depth <= 8) {
blend_line_hv(p, draw->pixelstep[plane],
color->comp[plane].u8[comp], alpha,
m, mask_linesize, l2depth, w_sub,
draw->hsub[plane], draw->vsub[plane],
xm0, left, right, top);
} else {
blend_line_hv16(p, draw->pixelstep[plane],
color->comp[plane].u16[comp], alpha,
m, mask_linesize, l2depth, w_sub,
draw->hsub[plane], draw->vsub[plane],
xm0, left, right, top);
}
p += dst_linesize[plane];
m += top * mask_linesize;
}
for (y = 0; y < h_sub; y++) {
blend_line_hv(p, draw->pixelstep[plane],
color->comp[plane].u8[comp], alpha,
m, mask_linesize, l2depth, w_sub,
draw->hsub[plane], draw->vsub[plane],
xm0, left, right, 1 << draw->vsub[plane]);
p += dst_linesize[plane];
m += mask_linesize << draw->vsub[plane];
if (depth <= 8) {
for (y = 0; y < h_sub; y++) {
blend_line_hv(p, draw->pixelstep[plane],
color->comp[plane].u8[comp], alpha,
m, mask_linesize, l2depth, w_sub,
draw->hsub[plane], draw->vsub[plane],
xm0, left, right, 1 << draw->vsub[plane]);
p += dst_linesize[plane];
m += mask_linesize << draw->vsub[plane];
}
} else {
for (y = 0; y < h_sub; y++) {
blend_line_hv16(p, draw->pixelstep[plane],
color->comp[plane].u16[comp], alpha,
m, mask_linesize, l2depth, w_sub,
draw->hsub[plane], draw->vsub[plane],
xm0, left, right, 1 << draw->vsub[plane]);
p += dst_linesize[plane];
m += mask_linesize << draw->vsub[plane];
}
}
if (bottom) {
if (depth <= 8) {
blend_line_hv(p, draw->pixelstep[plane],
color->comp[plane].u8[comp], alpha,
m, mask_linesize, l2depth, w_sub,
draw->hsub[plane], draw->vsub[plane],
xm0, left, right, bottom);
} else {
blend_line_hv16(p, draw->pixelstep[plane],
color->comp[plane].u16[comp], alpha,
m, mask_linesize, l2depth, w_sub,
draw->hsub[plane], draw->vsub[plane],
xm0, left, right, bottom);
}
}
if (bottom)
blend_line_hv(p, draw->pixelstep[plane],
color->comp[plane].u8[comp], alpha,
m, mask_linesize, l2depth, w_sub,
draw->hsub[plane], draw->vsub[plane],
xm0, left, right, bottom);
}
}
}

View File

@ -60,9 +60,9 @@ typedef struct FFDrawContext {
typedef struct FFDrawColor {
uint8_t rgba[4];
union {
uint32_t u32;
uint16_t u16;
uint8_t u8[4];
uint32_t u32[4];
uint16_t u16[8];
uint8_t u8[16];
} comp[MAX_PLANES];
} FFDrawColor;

View File

@ -7,20 +7,52 @@ bgr24 f8b65ad845905c7d0c93ca28dfbb826f
bgra 929aac15e848038e367c250037575f9f
gbrap 6712984b4a068ffa534f0cb35b2adc6f
gbrp 3c94d39256db2409015df913fd330a90
gbrp10le f206db2a32ad484a59cf3e596bdc2866
gbrp12le be6463331985e2c8ed7bd910093ca4a2
gbrp14le 9ae804cf217bec0a737c36c20573cbe5
gbrp9le 9a86dab5661c213ce2b7e00ae48b4d1f
gray ddc663a0491df3959d9c5795dceaa72e
gray16le 468bda6155bdc7a7a20c34d6e599fd16
rgb0 78d500c8361ab6423a4826a00268c908
rgb24 17f9e2e0c609009acaf2175c42d4a2a5
rgba b157c90191463d34fb3ce77b36c96386
xyz12le 85abf80b77a9236a76ba0b00fcbdea2d
ya8 5fc0f471207ddf7aa01b07027d56b672
yuv410p cb871dcc1e84a7ef1d21f9237b88cf6e
yuv411p aec2c1740de9a62db0d41f4dda9121b0
yuv420p 4398e408fc35436ce4b20468946f58b6
yuv420p10le 74518a7d68457c54da3300e80c683e9c
yuv420p12le 32086c64c814315aa9253580708a192e
yuv420p14le 265e9fefb8b92f3cae678eb3cf4e00b4
yuv420p16le 1ca89e47164d5f2481e39d4ac6eab2ed
yuv420p9le 59f0209084d1d1dd2861e058d1df63f4
yuv422p e43d68568d9f782908ba56bf1e09d5d5
yuv422p10le 18667cf7f87d8ffe1c4cc3db2100c559
yuv422p12le 71e32220fa1bbdcac95fb57ba0dbd4f0
yuv422p14le a0064be4d29079a811e5a315341da09a
yuv422p16le 836057e9999c763697c66c21869492b8
yuv422p9le 3213bed797e7b4cefa4f174dc33bf246
yuv440p a7e34de74c96b0224fe1381ec1db2ba7
yuv440p10le f91a481e27be7ea4a38a878e5e4330a3
yuv440p12le 0e9953a09ac09fe5f1523b350cf7cb72
yuv444p 6bfd89286dc36f2789b77d747ed8fa22
yuv444p10le b10afb5fda970dbce8aac5aab981a8cb
yuv444p12le 8f1b4b0f91d309fdaaec8a1ba6c7107f
yuv444p14le 2a87a84fa01237de9c08dd7e9ffbf78d
yuv444p16le 28508867fe7470c3539f8a84e8fb8271
yuv444p9le 99d39ef897c6037d6c7aa6e7a0398f84
yuva420p 842c27169ecdcf6de79f2b787367b51c
yuva420p10le 336fcb42c5b665c2028661e73325b359
yuva420p16le ff45de790e7bdd3c25d8aad51289aba9
yuva420p9le 8ef1f3b3e01b5ce222e4caeec3dec396
yuva422p 91dcecc4bfdff1f0db9ef8b9b5b9ac2a
yuva422p10le 1ba292c74c8646fd077a6116142b1bc8
yuva422p16le 383226550fe9c93d6e8bf0d45d1423d1
yuva422p9le 0fb76788c905c6d448143aa3c5eae116
yuva444p fb60941a57596b277417a3c7c00aa194
yuva444p10le 251ea4ead8300d752eb355a08cbb0352
yuva444p16le 5b65287e1862d2d9f1ad2cfdcde94661
yuva444p9le e6946c10b94c271e7ea24b3bcff314e1
yuvj411p ca967e68759a4956729dd366adc7e7fa
yuvj420p c00611cd5f1558047d579d8a7d30e381
yuvj422p b3acdf07147a7598836065836ad8420b