Commit eac93932 authored by Paul B Mahol's avatar Paul B Mahol

lavfi/geq: improve support for formats with alpha plane

Signed-off-by: 's avatarPaul B Mahol <onemda@gmail.com>
parent 875f8831
...@@ -3047,7 +3047,7 @@ For more information see: ...@@ -3047,7 +3047,7 @@ For more information see:
@section geq @section geq
The filter takes one, two or three equations as parameter, separated by ':'. The filter takes one, two, three or four equations as parameter, separated by ':'.
The first equation is mandatory and applies to the luma plane. The two The first equation is mandatory and applies to the luma plane. The two
following are respectively for chroma blue and chroma red planes. following are respectively for chroma blue and chroma red planes.
...@@ -3060,11 +3060,14 @@ the luminance expression ...@@ -3060,11 +3060,14 @@ the luminance expression
the chrominance blue expression the chrominance blue expression
@item cr_expr @item cr_expr
the chrominance red expression the chrominance red expression
@item alpha_expr
the alpha expression
@end table @end table
If one of the chrominance expression is not defined, it falls back on the other If one of the chrominance expression is not defined, it falls back on the other
one. If none of them are specified, they will evaluate the luminance one. If no alpha expression is specified it will evaluate to opaque value.
expression. If none of chrominance expressions are
specified, they will evaluate the luminance expression.
The expressions can use the following variables and functions: The expressions can use the following variables and functions:
...@@ -3097,11 +3100,15 @@ plane. ...@@ -3097,11 +3100,15 @@ plane.
@item cb(x, y) @item cb(x, y)
Return the value of the pixel at location (@var{x},@var{y}) of the Return the value of the pixel at location (@var{x},@var{y}) of the
blue-difference chroma plane. blue-difference chroma plane. Returns 0 if there is no such plane.
@item cr(x, y) @item cr(x, y)
Return the value of the pixel at location (@var{x},@var{y}) of the Return the value of the pixel at location (@var{x},@var{y}) of the
red-difference chroma plane. red-difference chroma plane. Returns 0 if there is no such plane.
@item alpha(x, y)
Return the value of the pixel at location (@var{x},@var{y}) of the alpha
plane. Returns 0 if there is no such plane.
@end table @end table
For functions, if @var{x} and @var{y} are outside the area, the value will be For functions, if @var{x} and @var{y} are outside the area, the value will be
......
...@@ -34,20 +34,22 @@ ...@@ -34,20 +34,22 @@
typedef struct { typedef struct {
const AVClass *class; const AVClass *class;
AVExpr *e[3]; ///< expressions for each plane AVExpr *e[4]; ///< expressions for each plane
char *expr_str[3]; ///< expression strings for each plane char *expr_str[4]; ///< expression strings for each plane
int framenum; ///< frame counter int framenum; ///< frame counter
AVFilterBufferRef *picref; ///< current input buffer AVFilterBufferRef *picref; ///< current input buffer
int hsub, vsub; ///< chroma subsampling int hsub, vsub; ///< chroma subsampling
int planes; ///< number of planes
} GEQContext; } GEQContext;
#define OFFSET(x) offsetof(GEQContext, x) #define OFFSET(x) offsetof(GEQContext, x)
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption geq_options[] = { static const AVOption geq_options[] = {
{ "lum_expr", "set luminance expression", OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, { "lum_expr", "set luminance expression", OFFSET(expr_str[0]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "cb_expr", "set chroma blue expression", OFFSET(expr_str) + sizeof(char*), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, { "cb_expr", "set chroma blue expression", OFFSET(expr_str[1]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "cr_expr", "set chroma red expression", OFFSET(expr_str) + 2*sizeof(char*), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, { "cr_expr", "set chroma red expression", OFFSET(expr_str[2]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
{ "alpha_expr", "set alpha expression", OFFSET(expr_str[3]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS },
{NULL}, {NULL},
}; };
...@@ -60,8 +62,11 @@ static inline double getpix(void *priv, double x, double y, int plane) ...@@ -60,8 +62,11 @@ static inline double getpix(void *priv, double x, double y, int plane)
AVFilterBufferRef *picref = geq->picref; AVFilterBufferRef *picref = geq->picref;
const uint8_t *src = picref->data[plane]; const uint8_t *src = picref->data[plane];
const int linesize = picref->linesize[plane]; const int linesize = picref->linesize[plane];
const int w = picref->video->w >> (plane ? geq->hsub : 0); const int w = picref->video->w >> ((plane == 1 || plane == 2) ? geq->hsub : 0);
const int h = picref->video->h >> (plane ? geq->vsub : 0); const int h = picref->video->h >> ((plane == 1 || plane == 2) ? geq->vsub : 0);
if (!src)
return 0;
xi = x = av_clipf(x, 0, w - 2); xi = x = av_clipf(x, 0, w - 2);
yi = y = av_clipf(y, 0, h - 2); yi = y = av_clipf(y, 0, h - 2);
...@@ -78,6 +83,7 @@ static inline double getpix(void *priv, double x, double y, int plane) ...@@ -78,6 +83,7 @@ static inline double getpix(void *priv, double x, double y, int plane)
static double lum(void *priv, double x, double y) { return getpix(priv, x, y, 0); } static double lum(void *priv, double x, double y) { return getpix(priv, x, y, 0); }
static double cb(void *priv, double x, double y) { return getpix(priv, x, y, 1); } static double cb(void *priv, double x, double y) { return getpix(priv, x, y, 1); }
static double cr(void *priv, double x, double y) { return getpix(priv, x, y, 2); } static double cr(void *priv, double x, double y) { return getpix(priv, x, y, 2); }
static double alpha(void *priv, double x, double y) { return getpix(priv, x, y, 3); }
static const char *const var_names[] = { "X", "Y", "W", "H", "N", "SW", "SH", "T", NULL }; static const char *const var_names[] = { "X", "Y", "W", "H", "N", "SW", "SH", "T", NULL };
enum { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_N, VAR_SW, VAR_SH, VAR_T, VAR_VARS_NB }; enum { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_N, VAR_SW, VAR_SH, VAR_T, VAR_VARS_NB };
...@@ -86,7 +92,7 @@ static av_cold int geq_init(AVFilterContext *ctx, const char *args) ...@@ -86,7 +92,7 @@ static av_cold int geq_init(AVFilterContext *ctx, const char *args)
{ {
GEQContext *geq = ctx->priv; GEQContext *geq = ctx->priv;
int plane, ret = 0; int plane, ret = 0;
static const char *shorthand[] = { "lum_expr", "cb_expr", "cr_expr", NULL }; static const char *shorthand[] = { "lum_expr", "cb_expr", "cr_expr", "alpha_expr", NULL };
geq->class = &geq_class; geq->class = &geq_class;
av_opt_set_defaults(geq); av_opt_set_defaults(geq);
...@@ -110,15 +116,18 @@ static av_cold int geq_init(AVFilterContext *ctx, const char *args) ...@@ -110,15 +116,18 @@ static av_cold int geq_init(AVFilterContext *ctx, const char *args)
if (!geq->expr_str[2]) geq->expr_str[2] = av_strdup(geq->expr_str[1]); if (!geq->expr_str[2]) geq->expr_str[2] = av_strdup(geq->expr_str[1]);
} }
if (!geq->expr_str[1] || !geq->expr_str[2]) { if (!geq->expr_str[3])
geq->expr_str[3] = av_strdup("255");
if (!geq->expr_str[1] || !geq->expr_str[2] || !geq->expr_str[3]) {
ret = AVERROR(ENOMEM); ret = AVERROR(ENOMEM);
goto end; goto end;
} }
for (plane = 0; plane < 3; plane++) { for (plane = 0; plane < 4; plane++) {
static double (*p[])(void *, double, double) = { lum, cb, cr }; static double (*p[])(void *, double, double) = { lum, cb, cr, alpha };
static const char *const func2_names[] = { "lum", "cb", "cr", "p", NULL }; static const char *const func2_names[] = { "lum", "cb", "cr", "alpha", "p", NULL };
double (*func2[])(void *, double, double) = { lum, cb, cr, p[plane], NULL }; double (*func2[])(void *, double, double) = { lum, cb, cr, alpha, p[plane], NULL };
ret = av_expr_parse(&geq->e[plane], geq->expr_str[plane], var_names, ret = av_expr_parse(&geq->e[plane], geq->expr_str[plane], var_names,
NULL, NULL, func2_names, func2, 0, ctx); NULL, NULL, func2_names, func2, 0, ctx);
...@@ -135,7 +144,8 @@ static int geq_query_formats(AVFilterContext *ctx) ...@@ -135,7 +144,8 @@ static int geq_query_formats(AVFilterContext *ctx)
static const enum PixelFormat pix_fmts[] = { static const enum PixelFormat pix_fmts[] = {
AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P,
AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
AV_PIX_FMT_GRAY8,
AV_PIX_FMT_NONE AV_PIX_FMT_NONE
}; };
ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
...@@ -149,6 +159,7 @@ static int geq_config_props(AVFilterLink *inlink) ...@@ -149,6 +159,7 @@ static int geq_config_props(AVFilterLink *inlink)
geq->hsub = desc->log2_chroma_w; geq->hsub = desc->log2_chroma_w;
geq->vsub = desc->log2_chroma_h; geq->vsub = desc->log2_chroma_h;
geq->planes = desc->nb_components;
return 0; return 0;
} }
...@@ -171,12 +182,12 @@ static int geq_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in) ...@@ -171,12 +182,12 @@ static int geq_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
} }
avfilter_copy_buffer_ref_props(out, in); avfilter_copy_buffer_ref_props(out, in);
for (plane = 0; plane < 3; plane++) { for (plane = 0; plane < geq->planes && out->data[plane]; plane++) {
int x, y; int x, y;
uint8_t *dst = out->data[plane]; uint8_t *dst = out->data[plane];
const int linesize = out->linesize[plane]; const int linesize = out->linesize[plane];
const int w = inlink->w >> (plane ? geq->hsub : 0); const int w = inlink->w >> ((plane == 1 || plane == 2) ? geq->hsub : 0);
const int h = inlink->h >> (plane ? geq->vsub : 0); const int h = inlink->h >> ((plane == 1 || plane == 2) ? geq->vsub : 0);
values[VAR_W] = w; values[VAR_W] = w;
values[VAR_H] = h; values[VAR_H] = h;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment