libavfilter/vf_lut.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Stefano Sabatini
00003  *
00004  * This file is part of FFmpeg.
00005  *
00006  * FFmpeg is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * FFmpeg is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with FFmpeg; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00027 #include "libavutil/eval.h"
00028 #include "libavutil/opt.h"
00029 #include "libavutil/pixdesc.h"
00030 #include "avfilter.h"
00031 #include "internal.h"
00032 
00033 static const char * const var_names[] = {
00034     "w",        
00035     "h",        
00036     "val",      
00037     "maxval",   
00038     "minval",   
00039     "negval",   
00040     "clipval",
00041     NULL
00042 };
00043 
00044 enum var_name {
00045     VAR_W,
00046     VAR_H,
00047     VAR_VAL,
00048     VAR_MAXVAL,
00049     VAR_MINVAL,
00050     VAR_NEGVAL,
00051     VAR_CLIPVAL,
00052     VAR_VARS_NB
00053 };
00054 
00055 typedef struct {
00056     const AVClass *class;
00057     uint8_t lut[4][256];  
00058     char   *comp_expr_str[4];
00059     AVExpr *comp_expr[4];
00060     int hsub, vsub;
00061     double var_values[VAR_VARS_NB];
00062     int is_rgb, is_yuv;
00063     int rgba_map[4];
00064     int step;
00065     int negate_alpha; /* only used by negate */
00066 } LutContext;
00067 
00068 #define Y 0
00069 #define U 1
00070 #define V 2
00071 #define R 0
00072 #define G 1
00073 #define B 2
00074 #define A 3
00075 
00076 #define OFFSET(x) offsetof(LutContext, x)
00077 
00078 static const AVOption lut_options[] = {
00079     {"c0", "set component #0 expression", OFFSET(comp_expr_str[0]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00080     {"c1", "set component #1 expression", OFFSET(comp_expr_str[1]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00081     {"c2", "set component #2 expression", OFFSET(comp_expr_str[2]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00082     {"c3", "set component #3 expression", OFFSET(comp_expr_str[3]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00083     {"y",  "set Y expression", OFFSET(comp_expr_str[Y]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00084     {"u",  "set U expression", OFFSET(comp_expr_str[U]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00085     {"v",  "set V expression", OFFSET(comp_expr_str[V]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00086     {"r",  "set R expression", OFFSET(comp_expr_str[R]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00087     {"g",  "set G expression", OFFSET(comp_expr_str[G]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00088     {"b",  "set B expression", OFFSET(comp_expr_str[B]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00089     {"a",  "set A expression", OFFSET(comp_expr_str[A]),  AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00090     {NULL},
00091 };
00092 
00093 static const char *lut_get_name(void *ctx)
00094 {
00095     return "lut";
00096 }
00097 
00098 static const AVClass lut_class = {
00099     "LutContext",
00100     lut_get_name,
00101     lut_options
00102 };
00103 
00104 static int init(AVFilterContext *ctx, const char *args, void *opaque)
00105 {
00106     LutContext *lut = ctx->priv;
00107     int ret;
00108 
00109     lut->class = &lut_class;
00110     av_opt_set_defaults(lut);
00111 
00112     lut->is_rgb = !strcmp(ctx->filter->name, "lutrgb");
00113     lut->is_yuv = !strcmp(ctx->filter->name, "lutyuv");
00114     if (args && (ret = av_set_options_string(lut, args, "=", ":")) < 0)
00115         return ret;
00116 
00117     return 0;
00118 }
00119 
00120 static av_cold void uninit(AVFilterContext *ctx)
00121 {
00122     LutContext *lut = ctx->priv;
00123     int i;
00124 
00125     for (i = 0; i < 4; i++) {
00126         av_expr_free(lut->comp_expr[i]);
00127         lut->comp_expr[i] = NULL;
00128         av_freep(&lut->comp_expr_str[i]);
00129     }
00130 }
00131 
00132 #define YUV_FORMATS                                         \
00133     PIX_FMT_YUV444P,  PIX_FMT_YUV422P,  PIX_FMT_YUV420P,    \
00134     PIX_FMT_YUV411P,  PIX_FMT_YUV410P,  PIX_FMT_YUV440P,    \
00135     PIX_FMT_YUVA420P,                                       \
00136     PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ420P,   \
00137     PIX_FMT_YUVJ440P
00138 
00139 #define RGB_FORMATS                             \
00140     PIX_FMT_ARGB,         PIX_FMT_RGBA,         \
00141     PIX_FMT_ABGR,         PIX_FMT_BGRA,         \
00142     PIX_FMT_RGB24,        PIX_FMT_BGR24
00143 
00144 static const enum PixelFormat yuv_pix_fmts[] = { YUV_FORMATS, PIX_FMT_NONE };
00145 static const enum PixelFormat rgb_pix_fmts[] = { RGB_FORMATS, PIX_FMT_NONE };
00146 static const enum PixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, PIX_FMT_NONE };
00147 
00148 static int query_formats(AVFilterContext *ctx)
00149 {
00150     LutContext *lut = ctx->priv;
00151 
00152     const enum PixelFormat *pix_fmts = lut->is_rgb ? rgb_pix_fmts :
00153                                        lut->is_yuv ? yuv_pix_fmts : all_pix_fmts;
00154 
00155     avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
00156     return 0;
00157 }
00158 
00162 static double clip(void *opaque, double val)
00163 {
00164     LutContext *lut = opaque;
00165     double minval = lut->var_values[VAR_MINVAL];
00166     double maxval = lut->var_values[VAR_MAXVAL];
00167 
00168     return av_clip(val, minval, maxval);
00169 }
00170 
00175 static double compute_gammaval(void *opaque, double gamma)
00176 {
00177     LutContext *lut = opaque;
00178     double val    = lut->var_values[VAR_CLIPVAL];
00179     double minval = lut->var_values[VAR_MINVAL];
00180     double maxval = lut->var_values[VAR_MAXVAL];
00181 
00182     return pow((val-minval)/(maxval-minval), gamma) * (maxval-minval)+minval;
00183 }
00184 
00185 static double (* const funcs1[])(void *, double) = {
00186     (void *)clip,
00187     (void *)compute_gammaval,
00188     NULL
00189 };
00190 
00191 static const char * const funcs1_names[] = {
00192     "clip",
00193     "gammaval",
00194     NULL
00195 };
00196 
00197 static int config_props(AVFilterLink *inlink)
00198 {
00199     AVFilterContext *ctx = inlink->dst;
00200     LutContext *lut = ctx->priv;
00201     const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[inlink->format];
00202     int min[4], max[4];
00203     int val, comp, ret;
00204 
00205     lut->hsub = desc->log2_chroma_w;
00206     lut->vsub = desc->log2_chroma_h;
00207 
00208     lut->var_values[VAR_W] = inlink->w;
00209     lut->var_values[VAR_H] = inlink->h;
00210 
00211     switch (inlink->format) {
00212     case PIX_FMT_YUV410P:
00213     case PIX_FMT_YUV411P:
00214     case PIX_FMT_YUV420P:
00215     case PIX_FMT_YUV422P:
00216     case PIX_FMT_YUV440P:
00217     case PIX_FMT_YUV444P:
00218     case PIX_FMT_YUVA420P:
00219         min[Y] = min[U] = min[V] = 16;
00220         max[Y] = 235;
00221         max[U] = max[V] = 240;
00222         min[A] = 0; max[A] = 255;
00223         break;
00224     default:
00225         min[0] = min[1] = min[2] = min[3] = 0;
00226         max[0] = max[1] = max[2] = max[3] = 255;
00227     }
00228 
00229     lut->is_yuv = lut->is_rgb = 0;
00230     if      (ff_fmt_is_in(inlink->format, yuv_pix_fmts)) lut->is_yuv = 1;
00231     else if (ff_fmt_is_in(inlink->format, rgb_pix_fmts)) lut->is_rgb = 1;
00232 
00233     if (lut->is_rgb) {
00234         switch (inlink->format) {
00235         case PIX_FMT_ARGB:  lut->rgba_map[A] = 0; lut->rgba_map[R] = 1; lut->rgba_map[G] = 2; lut->rgba_map[B] = 3; break;
00236         case PIX_FMT_ABGR:  lut->rgba_map[A] = 0; lut->rgba_map[B] = 1; lut->rgba_map[G] = 2; lut->rgba_map[R] = 3; break;
00237         case PIX_FMT_RGBA:
00238         case PIX_FMT_RGB24: lut->rgba_map[R] = 0; lut->rgba_map[G] = 1; lut->rgba_map[B] = 2; lut->rgba_map[A] = 3; break;
00239         case PIX_FMT_BGRA:
00240         case PIX_FMT_BGR24: lut->rgba_map[B] = 0; lut->rgba_map[G] = 1; lut->rgba_map[R] = 2; lut->rgba_map[A] = 3; break;
00241         }
00242         lut->step = av_get_bits_per_pixel(desc) >> 3;
00243     }
00244 
00245     for (comp = 0; comp < desc->nb_components; comp++) {
00246         double res;
00247 
00248         /* create the parsed expression */
00249         ret = av_expr_parse(&lut->comp_expr[comp], lut->comp_expr_str[comp],
00250                             var_names, funcs1_names, funcs1, NULL, NULL, 0, ctx);
00251         if (ret < 0) {
00252             av_log(ctx, AV_LOG_ERROR,
00253                    "Error when parsing the expression '%s' for the component %d.\n",
00254                    lut->comp_expr_str[comp], comp);
00255             return AVERROR(EINVAL);
00256         }
00257 
00258         /* compute the lut */
00259         lut->var_values[VAR_MAXVAL] = max[comp];
00260         lut->var_values[VAR_MINVAL] = min[comp];
00261 
00262         for (val = 0; val < 256; val++) {
00263             lut->var_values[VAR_VAL] = val;
00264             lut->var_values[VAR_CLIPVAL] = av_clip(val, min[comp], max[comp]);
00265             lut->var_values[VAR_NEGVAL] =
00266                 av_clip(min[comp] + max[comp] - lut->var_values[VAR_VAL],
00267                         min[comp], max[comp]);
00268 
00269             res = av_expr_eval(lut->comp_expr[comp], lut->var_values, lut);
00270             if (isnan(res)) {
00271                 av_log(ctx, AV_LOG_ERROR,
00272                        "Error when evaluating the expression '%s' for the value %d for the component #%d.\n",
00273                        lut->comp_expr_str[comp], val, comp);
00274                 return AVERROR(EINVAL);
00275             }
00276             lut->lut[comp][val] = av_clip((int)res, min[comp], max[comp]);
00277             av_log(ctx, AV_LOG_DEBUG, "val[%d][%d] = %d\n", comp, val, lut->lut[comp][val]);
00278         }
00279     }
00280 
00281     return 0;
00282 }
00283 
00284 static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
00285 {
00286     AVFilterContext *ctx = inlink->dst;
00287     LutContext *lut = ctx->priv;
00288     AVFilterLink *outlink = ctx->outputs[0];
00289     AVFilterBufferRef *inpic  = inlink ->cur_buf;
00290     AVFilterBufferRef *outpic = outlink->out_buf;
00291     uint8_t *inrow, *outrow, *inrow0, *outrow0;
00292     int i, j, k, plane;
00293 
00294     if (lut->is_rgb) {
00295         /* packed */
00296         inrow0  = inpic ->data[0] + y * inpic ->linesize[0];
00297         outrow0 = outpic->data[0] + y * outpic->linesize[0];
00298 
00299         for (i = 0; i < h; i ++) {
00300             inrow  = inrow0;
00301             outrow = outrow0;
00302             for (j = 0; j < inlink->w; j++) {
00303                 for (k = 0; k < lut->step; k++)
00304                     outrow[k] = lut->lut[lut->rgba_map[k]][inrow[k]];
00305                 outrow += lut->step;
00306                 inrow  += lut->step;
00307             }
00308             inrow0  += inpic ->linesize[0];
00309             outrow0 += outpic->linesize[0];
00310         }
00311     } else {
00312         /* planar */
00313         for (plane = 0; plane < 4 && inpic->data[plane]; plane++) {
00314             int vsub = plane == 1 || plane == 2 ? lut->vsub : 0;
00315             int hsub = plane == 1 || plane == 2 ? lut->hsub : 0;
00316 
00317             inrow  = inpic ->data[plane] + (y>>vsub) * inpic ->linesize[plane];
00318             outrow = outpic->data[plane] + (y>>vsub) * outpic->linesize[plane];
00319 
00320             for (i = 0; i < h>>vsub; i ++) {
00321                 for (j = 0; j < inlink->w>>hsub; j++)
00322                     outrow[j] = lut->lut[plane][inrow[j]];
00323                 inrow  += inpic ->linesize[plane];
00324                 outrow += outpic->linesize[plane];
00325             }
00326         }
00327     }
00328 
00329     avfilter_draw_slice(outlink, y, h, slice_dir);
00330 }
00331 
00332 #define DEFINE_LUT_FILTER(name_, description_, init_)                   \
00333     AVFilter avfilter_vf_##name_ = {                                    \
00334         .name          = #name_,                                        \
00335         .description   = NULL_IF_CONFIG_SMALL(description_),            \
00336         .priv_size     = sizeof(LutContext),                            \
00337                                                                         \
00338         .init          = init_,                                         \
00339         .uninit        = uninit,                                        \
00340         .query_formats = query_formats,                                 \
00341                                                                         \
00342         .inputs    = (const AVFilterPad[]) {{ .name      = "default",   \
00343                                         .type            = AVMEDIA_TYPE_VIDEO, \
00344                                         .draw_slice      = draw_slice,  \
00345                                         .config_props    = config_props, \
00346                                         .min_perms       = AV_PERM_READ, }, \
00347                                       { .name = NULL}},                 \
00348         .outputs   = (const AVFilterPad[]) {{ .name      = "default",   \
00349                                         .type            = AVMEDIA_TYPE_VIDEO, }, \
00350                                       { .name = NULL}},                 \
00351     }
00352 
00353 #if CONFIG_LUT_FILTER
00354 DEFINE_LUT_FILTER(lut,    "Compute and apply a lookup table to the RGB/YUV input video.", init);
00355 #endif
00356 #if CONFIG_LUTYUV_FILTER
00357 DEFINE_LUT_FILTER(lutyuv, "Compute and apply a lookup table to the YUV input video.",     init);
00358 #endif
00359 #if CONFIG_LUTRGB_FILTER
00360 DEFINE_LUT_FILTER(lutrgb, "Compute and apply a lookup table to the RGB input video.",     init);
00361 #endif
00362 
00363 #if CONFIG_NEGATE_FILTER
00364 
00365 static int negate_init(AVFilterContext *ctx, const char *args, void *opaque)
00366 {
00367     LutContext *lut = ctx->priv;
00368     char lut_params[64];
00369 
00370     if (args)
00371         sscanf(args, "%d", &lut->negate_alpha);
00372 
00373     av_log(ctx, AV_LOG_DEBUG, "negate_alpha:%d\n", lut->negate_alpha);
00374 
00375     snprintf(lut_params, sizeof(lut_params), "c0=negval:c1=negval:c2=negval:a=%s",
00376              lut->negate_alpha ? "negval" : "val");
00377 
00378     return init(ctx, lut_params, opaque);
00379 }
00380 
00381 DEFINE_LUT_FILTER(negate, "Negate input video.", negate_init);
00382 
00383 #endif