avfilter/vf_curves: add planar rgb support

pull/299/head
Paul B Mahol 6 years ago
parent bb660800a5
commit d6e50e0716
  1. 194
      libavfilter/vf_curves.c
  2. 10
      tests/ref/fate/filter-curves

@ -70,6 +70,9 @@ typedef struct CurvesContext {
int step; int step;
char *plot_filename; char *plot_filename;
int is_16bit; int is_16bit;
int depth;
int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
} CurvesContext; } CurvesContext;
typedef struct ThreadData { typedef struct ThreadData {
@ -209,7 +212,7 @@ static int get_nb_points(const struct keypoint *d)
* @see http://people.math.sfu.ca/~stockie/teaching/macm316/notes/splines.pdf * @see http://people.math.sfu.ca/~stockie/teaching/macm316/notes/splines.pdf
*/ */
#define CLIP(v) (nbits == 8 ? av_clip_uint8(v) : av_clip_uint16(v)) #define CLIP(v) (nbits == 8 ? av_clip_uint8(v) : av_clip_uintp2_c(v, nbits))
static inline int interpolate(void *log_ctx, uint16_t *y, static inline int interpolate(void *log_ctx, uint16_t *y,
const struct keypoint *points, int nbits) const struct keypoint *points, int nbits)
@ -341,6 +344,10 @@ static int interpolate##nbits(void *log_ctx, uint16_t *y, \
} }
DECLARE_INTERPOLATE_FUNC(8) DECLARE_INTERPOLATE_FUNC(8)
DECLARE_INTERPOLATE_FUNC(9)
DECLARE_INTERPOLATE_FUNC(10)
DECLARE_INTERPOLATE_FUNC(12)
DECLARE_INTERPOLATE_FUNC(14)
DECLARE_INTERPOLATE_FUNC(16) DECLARE_INTERPOLATE_FUNC(16)
static int parse_psfile(AVFilterContext *ctx, const char *fname) static int parse_psfile(AVFilterContext *ctx, const char *fname)
@ -512,6 +519,12 @@ static int query_formats(AVFilterContext *ctx)
AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0,
AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48,
AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64,
AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
AV_PIX_FMT_GBRP9,
AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12,
AV_PIX_FMT_GBRP14,
AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16,
AV_PIX_FMT_NONE AV_PIX_FMT_NONE
}; };
AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
@ -520,6 +533,120 @@ static int query_formats(AVFilterContext *ctx)
return ff_set_common_formats(ctx, fmts_list); return ff_set_common_formats(ctx, fmts_list);
} }
static int filter_slice_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{
int x, y;
const CurvesContext *curves = ctx->priv;
const ThreadData *td = arg;
const AVFrame *in = td->in;
const AVFrame *out = td->out;
const int direct = out == in;
const int step = curves->step;
const uint8_t r = curves->rgba_map[R];
const uint8_t g = curves->rgba_map[G];
const uint8_t b = curves->rgba_map[B];
const uint8_t a = curves->rgba_map[A];
const int slice_start = (in->height * jobnr ) / nb_jobs;
const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
if (curves->is_16bit) {
for (y = slice_start; y < slice_end; y++) {
uint16_t *dstp = ( uint16_t *)(out->data[0] + y * out->linesize[0]);
const uint16_t *srcp = (const uint16_t *)(in ->data[0] + y * in->linesize[0]);
for (x = 0; x < in->width * step; x += step) {
dstp[x + r] = curves->graph[R][srcp[x + r]];
dstp[x + g] = curves->graph[G][srcp[x + g]];
dstp[x + b] = curves->graph[B][srcp[x + b]];
if (!direct && step == 4)
dstp[x + a] = srcp[x + a];
}
}
} else {
uint8_t *dst = out->data[0] + slice_start * out->linesize[0];
const uint8_t *src = in->data[0] + slice_start * in->linesize[0];
for (y = slice_start; y < slice_end; y++) {
for (x = 0; x < in->width * step; x += step) {
dst[x + r] = curves->graph[R][src[x + r]];
dst[x + g] = curves->graph[G][src[x + g]];
dst[x + b] = curves->graph[B][src[x + b]];
if (!direct && step == 4)
dst[x + a] = src[x + a];
}
dst += out->linesize[0];
src += in ->linesize[0];
}
}
return 0;
}
static int filter_slice_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{
int x, y;
const CurvesContext *curves = ctx->priv;
const ThreadData *td = arg;
const AVFrame *in = td->in;
const AVFrame *out = td->out;
const int direct = out == in;
const int step = curves->step;
const uint8_t r = curves->rgba_map[R];
const uint8_t g = curves->rgba_map[G];
const uint8_t b = curves->rgba_map[B];
const uint8_t a = curves->rgba_map[A];
const int slice_start = (in->height * jobnr ) / nb_jobs;
const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
if (curves->is_16bit) {
for (y = slice_start; y < slice_end; y++) {
uint16_t *dstrp = ( uint16_t *)(out->data[r] + y * out->linesize[r]);
uint16_t *dstgp = ( uint16_t *)(out->data[g] + y * out->linesize[g]);
uint16_t *dstbp = ( uint16_t *)(out->data[b] + y * out->linesize[b]);
uint16_t *dstap = ( uint16_t *)(out->data[a] + y * out->linesize[a]);
const uint16_t *srcrp = (const uint16_t *)(in ->data[r] + y * in->linesize[r]);
const uint16_t *srcgp = (const uint16_t *)(in ->data[g] + y * in->linesize[g]);
const uint16_t *srcbp = (const uint16_t *)(in ->data[b] + y * in->linesize[b]);
const uint16_t *srcap = (const uint16_t *)(in ->data[a] + y * in->linesize[a]);
for (x = 0; x < in->width; x++) {
dstrp[x] = curves->graph[R][srcrp[x]];
dstgp[x] = curves->graph[G][srcgp[x]];
dstbp[x] = curves->graph[B][srcbp[x]];
if (!direct && step == 4)
dstap[x] = srcap[x];
}
}
} else {
uint8_t *dstr = out->data[r] + slice_start * out->linesize[r];
uint8_t *dstg = out->data[g] + slice_start * out->linesize[g];
uint8_t *dstb = out->data[b] + slice_start * out->linesize[b];
uint8_t *dsta = out->data[a] + slice_start * out->linesize[a];
const uint8_t *srcr = in->data[r] + slice_start * in->linesize[r];
const uint8_t *srcg = in->data[g] + slice_start * in->linesize[g];
const uint8_t *srcb = in->data[b] + slice_start * in->linesize[b];
const uint8_t *srca = in->data[a] + slice_start * in->linesize[a];
for (y = slice_start; y < slice_end; y++) {
for (x = 0; x < in->width; x++) {
dstr[x] = curves->graph[R][srcr[x]];
dstg[x] = curves->graph[G][srcg[x]];
dstb[x] = curves->graph[B][srcb[x]];
if (!direct && step == 4)
dsta[x] = srca[x];
}
dstr += out->linesize[r];
dstg += out->linesize[g];
dstb += out->linesize[b];
dsta += out->linesize[a];
srcr += in ->linesize[r];
srcg += in ->linesize[g];
srcb += in ->linesize[b];
srca += in ->linesize[a];
}
}
return 0;
}
static int config_input(AVFilterLink *inlink) static int config_input(AVFilterLink *inlink)
{ {
int i, j, ret; int i, j, ret;
@ -531,8 +658,10 @@ static int config_input(AVFilterLink *inlink)
ff_fill_rgba_map(curves->rgba_map, inlink->format); ff_fill_rgba_map(curves->rgba_map, inlink->format);
curves->is_16bit = desc->comp[0].depth > 8; curves->is_16bit = desc->comp[0].depth > 8;
curves->lut_size = curves->is_16bit ? 1<<16 : 1<<8; curves->depth = desc->comp[0].depth;
curves->lut_size = 1 << curves->depth;
curves->step = av_get_padded_bits_per_pixel(desc) >> (3 + curves->is_16bit); curves->step = av_get_padded_bits_per_pixel(desc) >> (3 + curves->is_16bit);
curves->filter_slice = desc->flags & AV_PIX_FMT_FLAG_PLANAR ? filter_slice_planar : filter_slice_packed;
for (i = 0; i < NB_COMP + 1; i++) { for (i = 0; i < NB_COMP + 1; i++) {
curves->graph[i] = av_mallocz_array(curves->lut_size, sizeof(*curves->graph[0])); curves->graph[i] = av_mallocz_array(curves->lut_size, sizeof(*curves->graph[0]));
@ -541,8 +670,14 @@ static int config_input(AVFilterLink *inlink)
ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i], curves->lut_size); ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i], curves->lut_size);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (curves->is_16bit) ret = interpolate16(ctx, curves->graph[i], comp_points[i]); switch (curves->depth) {
else ret = interpolate8(ctx, curves->graph[i], comp_points[i]); case 8: ret = interpolate8 (ctx, curves->graph[i], comp_points[i]); break;
case 9: ret = interpolate9 (ctx, curves->graph[i], comp_points[i]); break;
case 10: ret = interpolate10(ctx, curves->graph[i], comp_points[i]); break;
case 12: ret = interpolate12(ctx, curves->graph[i], comp_points[i]); break;
case 14: ret = interpolate14(ctx, curves->graph[i], comp_points[i]); break;
case 16: ret = interpolate16(ctx, curves->graph[i], comp_points[i]); break;
}
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
@ -579,57 +714,10 @@ static int config_input(AVFilterLink *inlink)
return 0; return 0;
} }
static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{
int x, y;
const CurvesContext *curves = ctx->priv;
const ThreadData *td = arg;
const AVFrame *in = td->in;
const AVFrame *out = td->out;
const int direct = out == in;
const int step = curves->step;
const uint8_t r = curves->rgba_map[R];
const uint8_t g = curves->rgba_map[G];
const uint8_t b = curves->rgba_map[B];
const uint8_t a = curves->rgba_map[A];
const int slice_start = (in->height * jobnr ) / nb_jobs;
const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
if (curves->is_16bit) {
for (y = slice_start; y < slice_end; y++) {
uint16_t *dstp = ( uint16_t *)(out->data[0] + y * out->linesize[0]);
const uint16_t *srcp = (const uint16_t *)(in ->data[0] + y * in->linesize[0]);
for (x = 0; x < in->width * step; x += step) {
dstp[x + r] = curves->graph[R][srcp[x + r]];
dstp[x + g] = curves->graph[G][srcp[x + g]];
dstp[x + b] = curves->graph[B][srcp[x + b]];
if (!direct && step == 4)
dstp[x + a] = srcp[x + a];
}
}
} else {
uint8_t *dst = out->data[0] + slice_start * out->linesize[0];
const uint8_t *src = in->data[0] + slice_start * in->linesize[0];
for (y = slice_start; y < slice_end; y++) {
for (x = 0; x < in->width * step; x += step) {
dst[x + r] = curves->graph[R][src[x + r]];
dst[x + g] = curves->graph[G][src[x + g]];
dst[x + b] = curves->graph[B][src[x + b]];
if (!direct && step == 4)
dst[x + a] = src[x + a];
}
dst += out->linesize[0];
src += in ->linesize[0];
}
}
return 0;
}
static int filter_frame(AVFilterLink *inlink, AVFrame *in) static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{ {
AVFilterContext *ctx = inlink->dst; AVFilterContext *ctx = inlink->dst;
CurvesContext *curves = ctx->priv;
AVFilterLink *outlink = ctx->outputs[0]; AVFilterLink *outlink = ctx->outputs[0];
AVFrame *out; AVFrame *out;
ThreadData td; ThreadData td;
@ -647,7 +735,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
td.in = in; td.in = in;
td.out = out; td.out = out;
ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); ctx->internal->execute(ctx, curves->filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx)));
if (out != in) if (out != in)
av_frame_free(&in); av_frame_free(&in);

@ -3,8 +3,8 @@
#codec_id 0: rawvideo #codec_id 0: rawvideo
#dimensions 0: 640x480 #dimensions 0: 640x480
#sar 0: 0/1 #sar 0: 0/1
0, 0, 0, 1, 921600, 0xcf426780 0, 0, 0, 1, 921600, 0x3ed36780
0, 1, 1, 1, 921600, 0x7642892d 0, 1, 1, 1, 921600, 0x7dbd892d
0, 2, 2, 1, 921600, 0x13c1ab7e 0, 2, 2, 1, 921600, 0x0894ab7e
0, 3, 3, 1, 921600, 0x3eca04bf 0, 3, 3, 1, 921600, 0x471004bf
0, 4, 4, 1, 921600, 0x61539162 0, 4, 4, 1, 921600, 0x79c79162

Loading…
Cancel
Save