• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

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 
00032 static const char *var_names[] = {
00033     "E",
00034     "PHI",
00035     "PI",
00036     "w",        
00037     "h",        
00038     "val",      
00039     "maxval",   
00040     "minval",   
00041     "negval",   
00042     "clipval",
00043     NULL
00044 };
00045 
00046 enum var_name {
00047     VAR_E,
00048     VAR_PHI,
00049     VAR_PI,
00050     VAR_W,
00051     VAR_H,
00052     VAR_VAL,
00053     VAR_MAXVAL,
00054     VAR_MINVAL,
00055     VAR_NEGVAL,
00056     VAR_CLIPVAL,
00057     VAR_VARS_NB
00058 };
00059 
00060 typedef struct {
00061     const AVClass *class;
00062     uint8_t lut[4][256];  
00063     char   *comp_expr_str[4];
00064     AVExpr *comp_expr[4];
00065     int hsub, vsub;
00066     double var_values[VAR_VARS_NB];
00067     int is_rgb, is_yuv;
00068     int rgba_map[4];
00069     int step;
00070     int negate_alpha; /* only used by negate */
00071 } LutContext;
00072 
00073 #define Y 0
00074 #define U 1
00075 #define V 2
00076 #define R 0
00077 #define G 1
00078 #define B 2
00079 #define A 3
00080 
00081 #define OFFSET(x) offsetof(LutContext, x)
00082 
00083 static const AVOption lut_options[] = {
00084     {"c0", "set component #0 expression", OFFSET(comp_expr_str[0]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00085     {"c1", "set component #1 expression", OFFSET(comp_expr_str[1]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00086     {"c2", "set component #2 expression", OFFSET(comp_expr_str[2]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00087     {"c3", "set component #3 expression", OFFSET(comp_expr_str[3]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00088     {"y",  "set Y expression", OFFSET(comp_expr_str[Y]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00089     {"u",  "set U expression", OFFSET(comp_expr_str[U]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00090     {"v",  "set V expression", OFFSET(comp_expr_str[V]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00091     {"r",  "set R expression", OFFSET(comp_expr_str[R]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00092     {"g",  "set G expression", OFFSET(comp_expr_str[G]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00093     {"b",  "set B expression", OFFSET(comp_expr_str[B]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00094     {"a",  "set A expression", OFFSET(comp_expr_str[A]),  FF_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX},
00095     {NULL},
00096 };
00097 
00098 static const char *lut_get_name(void *ctx)
00099 {
00100     return "lut";
00101 }
00102 
00103 static const AVClass lut_class = {
00104     "LutContext",
00105     lut_get_name,
00106     lut_options
00107 };
00108 
00109 static int init(AVFilterContext *ctx, const char *args, void *opaque)
00110 {
00111     LutContext *lut = ctx->priv;
00112     int ret;
00113 
00114     lut->class = &lut_class;
00115     av_opt_set_defaults2(lut, 0, 0);
00116 
00117     lut->var_values[VAR_PHI] = M_PHI;
00118     lut->var_values[VAR_PI]  = M_PI;
00119     lut->var_values[VAR_E ]  = M_E;
00120 
00121     lut->is_rgb = !strcmp(ctx->filter->name, "lutrgb");
00122     lut->is_yuv = !strcmp(ctx->filter->name, "lutyuv");
00123     if (args && (ret = av_set_options_string(lut, args, "=", ":")) < 0)
00124         return ret;
00125 
00126     return 0;
00127 }
00128 
00129 static av_cold void uninit(AVFilterContext *ctx)
00130 {
00131     LutContext *lut = ctx->priv;
00132     int i;
00133 
00134     for (i = 0; i < 4; i++) {
00135         av_expr_free(lut->comp_expr[i]);
00136         lut->comp_expr[i] = NULL;
00137         av_freep(&lut->comp_expr_str[i]);
00138     }
00139 }
00140 
00141 #define YUV_FORMATS                                         \
00142     PIX_FMT_YUV444P,  PIX_FMT_YUV422P,  PIX_FMT_YUV420P,    \
00143     PIX_FMT_YUV411P,  PIX_FMT_YUV410P,  PIX_FMT_YUV440P,    \
00144     PIX_FMT_YUVA420P,                                       \
00145     PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ420P,   \
00146     PIX_FMT_YUVJ440P
00147 
00148 #define RGB_FORMATS                             \
00149     PIX_FMT_ARGB,         PIX_FMT_RGBA,         \
00150     PIX_FMT_ABGR,         PIX_FMT_BGRA,         \
00151     PIX_FMT_RGB24,        PIX_FMT_BGR24
00152 
00153 static enum PixelFormat yuv_pix_fmts[] = { YUV_FORMATS, PIX_FMT_NONE };
00154 static enum PixelFormat rgb_pix_fmts[] = { RGB_FORMATS, PIX_FMT_NONE };
00155 static enum PixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, PIX_FMT_NONE };
00156 
00157 static int query_formats(AVFilterContext *ctx)
00158 {
00159     LutContext *lut = ctx->priv;
00160 
00161     enum PixelFormat *pix_fmts = lut->is_rgb ? rgb_pix_fmts :
00162                                  lut->is_yuv ? yuv_pix_fmts : all_pix_fmts;
00163 
00164     avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
00165     return 0;
00166 }
00167 
00168 static int pix_fmt_is_in(enum PixelFormat pix_fmt, enum PixelFormat *pix_fmts)
00169 {
00170     enum PixelFormat *p;
00171     for (p = pix_fmts; *p != PIX_FMT_NONE; p++) {
00172         if (pix_fmt == *p)
00173             return 1;
00174     }
00175     return 0;
00176 }
00177 
00181 static double clip(void *opaque, double val)
00182 {
00183     LutContext *lut = opaque;
00184     double minval = lut->var_values[VAR_MINVAL];
00185     double maxval = lut->var_values[VAR_MAXVAL];
00186 
00187     return av_clip(val, minval, maxval);
00188 }
00189 
00194 static double compute_gammaval(void *opaque, double gamma)
00195 {
00196     LutContext *lut = opaque;
00197     double val    = lut->var_values[VAR_CLIPVAL];
00198     double minval = lut->var_values[VAR_MINVAL];
00199     double maxval = lut->var_values[VAR_MAXVAL];
00200 
00201     return pow((val-minval)/(maxval-minval), gamma) * (maxval-minval)+minval;
00202 }
00203 
00204 static double (* const funcs1[])(void *, double) = {
00205     (void *)clip,
00206     (void *)compute_gammaval,
00207     NULL
00208 };
00209 
00210 static const char * const funcs1_names[] = {
00211     "clip",
00212     "gammaval",
00213     NULL
00214 };
00215 
00216 static int config_props(AVFilterLink *inlink)
00217 {
00218     AVFilterContext *ctx = inlink->dst;
00219     LutContext *lut = ctx->priv;
00220     const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[inlink->format];
00221     int min[4], max[4];
00222     int val, comp, ret;
00223 
00224     lut->hsub = desc->log2_chroma_w;
00225     lut->vsub = desc->log2_chroma_h;
00226 
00227     lut->var_values[VAR_W] = inlink->w;
00228     lut->var_values[VAR_H] = inlink->h;
00229 
00230     switch (inlink->format) {
00231     case PIX_FMT_YUV410P:
00232     case PIX_FMT_YUV411P:
00233     case PIX_FMT_YUV420P:
00234     case PIX_FMT_YUV422P:
00235     case PIX_FMT_YUV440P:
00236     case PIX_FMT_YUV444P:
00237     case PIX_FMT_YUVA420P:
00238         min[Y] = min[U] = min[V] = 16;
00239         max[Y] = 235;
00240         max[U] = max[V] = 240;
00241         break;
00242     default:
00243         min[0] = min[1] = min[2] = min[3] = 0;
00244         max[0] = max[1] = max[2] = max[3] = 255;
00245     }
00246 
00247     lut->is_yuv = lut->is_rgb = 0;
00248     if      (pix_fmt_is_in(inlink->format, yuv_pix_fmts)) lut->is_yuv = 1;
00249     else if (pix_fmt_is_in(inlink->format, rgb_pix_fmts)) lut->is_rgb = 1;
00250 
00251     if (lut->is_rgb) {
00252         switch (inlink->format) {
00253         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;
00254         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;
00255         case PIX_FMT_RGBA:
00256         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;
00257         case PIX_FMT_BGRA:
00258         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;
00259         }
00260         lut->step = av_get_bits_per_pixel(desc) >> 3;
00261     }
00262 
00263     for (comp = 0; comp < desc->nb_components; comp++) {
00264         double res;
00265 
00266         /* create the parsed expression */
00267         ret = av_expr_parse(&lut->comp_expr[comp], lut->comp_expr_str[comp],
00268                             var_names, funcs1_names, funcs1, NULL, NULL, 0, ctx);
00269         if (ret < 0) {
00270             av_log(ctx, AV_LOG_ERROR,
00271                    "Error when parsing the expression '%s' for the component %d.\n",
00272                    lut->comp_expr_str[comp], comp);
00273             return AVERROR(EINVAL);
00274         }
00275 
00276         /* compute the lut */
00277         lut->var_values[VAR_MAXVAL] = max[comp];
00278         lut->var_values[VAR_MINVAL] = min[comp];
00279 
00280         for (val = 0; val < 256; val++) {
00281             lut->var_values[VAR_VAL] = val;
00282             lut->var_values[VAR_CLIPVAL] = av_clip(val, min[comp], max[comp]);
00283             lut->var_values[VAR_NEGVAL] =
00284                 av_clip(min[comp] + max[comp] - lut->var_values[VAR_VAL],
00285                         min[comp], max[comp]);
00286 
00287             res = av_expr_eval(lut->comp_expr[comp], lut->var_values, lut);
00288             if (isnan(res)) {
00289                 av_log(ctx, AV_LOG_ERROR,
00290                        "Error when evaluating the expression '%s' for the value %d for the component #%d.\n",
00291                        lut->comp_expr_str[comp], val, comp);
00292                 return AVERROR(EINVAL);
00293             }
00294             lut->lut[comp][val] = av_clip((int)res, min[comp], max[comp]);
00295             av_log(ctx, AV_LOG_DEBUG, "val[%d][%d] = %d\n", comp, val, lut->lut[comp][val]);
00296         }
00297     }
00298 
00299     return 0;
00300 }
00301 
00302 static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
00303 {
00304     AVFilterContext *ctx = inlink->dst;
00305     LutContext *lut = ctx->priv;
00306     AVFilterLink *outlink = ctx->outputs[0];
00307     AVFilterBufferRef *inpic  = inlink ->cur_buf;
00308     AVFilterBufferRef *outpic = outlink->out_buf;
00309     uint8_t *inrow, *outrow;
00310     int i, j, k, plane;
00311 
00312     if (lut->is_rgb) {
00313         /* packed */
00314         inrow  = inpic ->data[0] + y * inpic ->linesize[0];
00315         outrow = outpic->data[0] + y * outpic->linesize[0];
00316 
00317         for (i = 0; i < h; i ++) {
00318             for (j = 0; j < inlink->w; j++) {
00319                 for (k = 0; k < lut->step; k++)
00320                     outrow[k] = lut->lut[lut->rgba_map[k]][inrow[k]];
00321                 outrow += lut->step;
00322                 inrow  += lut->step;
00323             }
00324         }
00325     } else {
00326         /* planar */
00327         for (plane = 0; inpic->data[plane]; plane++) {
00328             int vsub = plane == 1 || plane == 2 ? lut->vsub : 0;
00329             int hsub = plane == 1 || plane == 2 ? lut->hsub : 0;
00330 
00331             inrow  = inpic ->data[plane] + (y>>vsub) * inpic ->linesize[plane];
00332             outrow = outpic->data[plane] + (y>>vsub) * outpic->linesize[plane];
00333 
00334             for (i = 0; i < h>>vsub; i ++) {
00335                 for (j = 0; j < inlink->w>>hsub; j++)
00336                     outrow[j] = lut->lut[plane][inrow[j]];
00337                 inrow  += inpic ->linesize[plane];
00338                 outrow += outpic->linesize[plane];
00339             }
00340         }
00341     }
00342 
00343     avfilter_draw_slice(outlink, y, h, slice_dir);
00344 }
00345 
00346 #define DEFINE_LUT_FILTER(name_, description_, init_)                   \
00347     AVFilter avfilter_vf_##name_ = {                                    \
00348         .name          = #name_,                                        \
00349         .description   = NULL_IF_CONFIG_SMALL(description_),            \
00350         .priv_size     = sizeof(LutContext),                            \
00351                                                                         \
00352         .init          = init_,                                         \
00353         .uninit        = uninit,                                        \
00354         .query_formats = query_formats,                                 \
00355                                                                         \
00356         .inputs    = (AVFilterPad[]) {{ .name            = "default",   \
00357                                         .type            = AVMEDIA_TYPE_VIDEO, \
00358                                         .draw_slice      = draw_slice,  \
00359                                         .config_props    = config_props, \
00360                                         .min_perms       = AV_PERM_READ, }, \
00361                                       { .name = NULL}},                 \
00362         .outputs   = (AVFilterPad[]) {{ .name            = "default",   \
00363                                         .type            = AVMEDIA_TYPE_VIDEO, }, \
00364                                       { .name = NULL}},                 \
00365     }
00366 
00367 DEFINE_LUT_FILTER(lut,    "Compute and apply a lookup table to the RGB/YUV input video.", init);
00368 DEFINE_LUT_FILTER(lutyuv, "Compute and apply a lookup table to the YUV input video.",     init);
00369 DEFINE_LUT_FILTER(lutrgb, "Compute and apply a lookup table to the RGB input video.",     init);
00370 
00371 #if CONFIG_NEGATE_FILTER
00372 
00373 static int negate_init(AVFilterContext *ctx, const char *args, void *opaque)
00374 {
00375     LutContext *lut = ctx->priv;
00376     char lut_params[1024];
00377 
00378     if (args)
00379         sscanf(args, "%d", &lut->negate_alpha);
00380 
00381     av_log(ctx, AV_LOG_INFO, "negate_alpha:%d\n", lut->negate_alpha);
00382 
00383     snprintf(lut_params, sizeof(lut_params), "c0=negval:c1=negval:c2=negval:a=%s",
00384              lut->negate_alpha ? "negval" : "val");
00385 
00386     return init(ctx, lut_params, opaque);
00387 }
00388 
00389 DEFINE_LUT_FILTER(negate, "Negate input video.", negate_init);
00390 
00391 #endif

Generated on Wed Apr 11 2012 07:31:36 for FFmpeg by  doxygen 1.7.1