On Wed, Dec 10, 2014 at 02:26:51PM +0000, Paul B Mahol wrote: > Signed-off-by: Paul B Mahol <one...@gmail.com> > --- > doc/filters.texi | 41 +++++++ > libavfilter/Makefile | 1 + > libavfilter/allfilters.c | 1 + > libavfilter/vf_colorlevels.c | 254 > +++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 297 insertions(+) > create mode 100644 libavfilter/vf_colorlevels.c > > diff --git a/doc/filters.texi b/doc/filters.texi > index 0ea3955..444dfda 100644 > --- a/doc/filters.texi > +++ b/doc/filters.texi > @@ -2934,6 +2934,47 @@ colorbalance=rs=.3 > @end example > @end itemize > > +@section colorlevels > + > +Adjust video input frames using levels. > + > +The filter accepts the following options: > + > +@table @option > +@item rimim > +@item gimin > +@item bimin > +@item aimin > +Adjust red, green, blue and alpha input black point. > +Allowed ranges for options are @code{[-1.0, 1.0]}. Defaults are @code{0}. > + > +@item rimax > +@item gimax > +@item bimax > +@item aimax > +Adjust red, green, blue and alpha input white point. > +Allowed ranges for options are @code{[-1.0, 1.0]}. Defaults are @code{1}. > + > +Input levels are used to lighten highlights (bright tones), darken shadows > +(dark tones), change the balance of bright and dark tones. > + > +@item romim > +@item gomin > +@item bomin > +@item aomin > +Adjust red, green, blue and alpha output black point. > +Allowed ranges for options are @code{[0, 1.0]}. Defaults are @code{0}. > + > +@item romax > +@item gomax > +@item bomax > +@item aomax > +Adjust red, green, blue and alpha output white point. > +Allowed ranges for options are @code{[0, 1.0]}. Defaults are @code{1}. > + > +Output levels allows manual selection of a constrained output level range. > +@end table > + > @section colorchannelmixer > > Adjust video input frames by re-mixing color channels. > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > index 2c56e38..5918e10 100644 > --- a/libavfilter/Makefile > +++ b/libavfilter/Makefile > @@ -100,6 +100,7 @@ OBJS-$(CONFIG_BOXBLUR_FILTER) += > vf_boxblur.o > OBJS-$(CONFIG_CODECVIEW_FILTER) += vf_codecview.o > OBJS-$(CONFIG_COLORBALANCE_FILTER) += vf_colorbalance.o > OBJS-$(CONFIG_COLORCHANNELMIXER_FILTER) += vf_colorchannelmixer.o > +OBJS-$(CONFIG_COLORLEVELS_FILTER) += vf_colorlevels.o > OBJS-$(CONFIG_COLORMATRIX_FILTER) += vf_colormatrix.o > OBJS-$(CONFIG_COPY_FILTER) += vf_copy.o > OBJS-$(CONFIG_CROP_FILTER) += vf_crop.o > diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c > index 2352d44..721a65d 100644 > --- a/libavfilter/allfilters.c > +++ b/libavfilter/allfilters.c > @@ -116,6 +116,7 @@ void avfilter_register_all(void) > REGISTER_FILTER(CODECVIEW, codecview, vf); > REGISTER_FILTER(COLORBALANCE, colorbalance, vf); > REGISTER_FILTER(COLORCHANNELMIXER, colorchannelmixer, vf); > + REGISTER_FILTER(COLORLEVELS, colorlevels, vf); > REGISTER_FILTER(COLORMATRIX, colormatrix, vf); > REGISTER_FILTER(COPY, copy, vf); > REGISTER_FILTER(CROP, crop, vf); > diff --git a/libavfilter/vf_colorlevels.c b/libavfilter/vf_colorlevels.c > new file mode 100644 > index 0000000..4ceea66 > --- /dev/null > +++ b/libavfilter/vf_colorlevels.c > @@ -0,0 +1,254 @@ > +/* > + * Copyright (c) 2013 Paul B Mahol > + * > + * This file is part of FFmpeg. > + * > + * FFmpeg is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * FFmpeg is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with FFmpeg; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +#include "libavutil/imgutils.h" > +#include "libavutil/opt.h" > +#include "libavutil/pixdesc.h" > +#include "avfilter.h" > +#include "drawutils.h" > +#include "formats.h" > +#include "internal.h" > +#include "video.h" > + > +#define R 0 > +#define G 1 > +#define B 2 > +#define A 3 > + > +typedef struct { > + double in_min, in_max; > + double out_min, out_max; > +} Range; > + > +typedef struct { > + const AVClass *class; > + Range range[4]; > + int nb_comp; > + int bpp; > + int step; > + uint8_t rgba_map[4]; > + int linesize; > +} ColorLevelsContext; > + > +#define OFFSET(x) offsetof(ColorLevelsContext, x) > +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM > +static const AVOption colorlevels_options[] = { > + { "rimin", "set input red black point", OFFSET(range[R].in_min), > AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS }, > + { "gimin", "set input green black point", OFFSET(range[G].in_min), > AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS }, > + { "bimin", "set input blue black point", OFFSET(range[B].in_min), > AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS }, > + { "aimin", "set input alpha black point", OFFSET(range[A].in_min), > AV_OPT_TYPE_DOUBLE, {.dbl=0}, -1, 1, FLAGS }, > + { "rimax", "set input red white point", OFFSET(range[R].in_max), > AV_OPT_TYPE_DOUBLE, {.dbl=1}, -1, 1, FLAGS }, > + { "gimax", "set input green white point", OFFSET(range[G].in_max), > AV_OPT_TYPE_DOUBLE, {.dbl=1}, -1, 1, FLAGS }, > + { "bimax", "set input blue white point", OFFSET(range[B].in_max), > AV_OPT_TYPE_DOUBLE, {.dbl=1}, -1, 1, FLAGS }, > + { "aimax", "set input alpha white point", OFFSET(range[A].in_max), > AV_OPT_TYPE_DOUBLE, {.dbl=1}, -1, 1, FLAGS }, > + { "romin", "set output red black point", OFFSET(range[R].out_min), > AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1, FLAGS }, > + { "gomin", "set output green black point", OFFSET(range[G].out_min), > AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1, FLAGS }, > + { "bomin", "set output blue black point", OFFSET(range[B].out_min), > AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1, FLAGS }, > + { "aomin", "set output alpha black point", OFFSET(range[A].out_min), > AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 1, FLAGS }, > + { "romax", "set output red white point", OFFSET(range[R].out_max), > AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, > + { "gomax", "set output green white point", OFFSET(range[G].out_max), > AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, > + { "bomax", "set output blue white point", OFFSET(range[B].out_max), > AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, > + { "aomax", "set output alpha white point", OFFSET(range[A].out_max), > AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS }, > + { NULL } > +}; > + > +AVFILTER_DEFINE_CLASS(colorlevels); > + > +static int query_formats(AVFilterContext *ctx) > +{ > + static const enum AVPixelFormat pix_fmts[] = { > + AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, > + AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, > + AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, > + AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, > + AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, > + AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, > + AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, > + AV_PIX_FMT_NONE > + }; > + > + ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); > + return 0; > +} > + > +static int config_input(AVFilterLink *inlink) > +{ > + AVFilterContext *ctx = inlink->dst; > + ColorLevelsContext *s = ctx->priv; > + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); > + > + s->nb_comp = desc->nb_components; > + s->bpp = (desc->comp[0].depth_minus1 + 1) >> 3; > + s->step = (av_get_padded_bits_per_pixel(desc) >> 3) / s->bpp; > + s->linesize = inlink->w * s->step; > + ff_fill_rgba_map(s->rgba_map, inlink->format); > + > + return 0; > +} > + > +static int filter_frame(AVFilterLink *inlink, AVFrame *in) > +{ > + AVFilterContext *ctx = inlink->dst; > + ColorLevelsContext *s = ctx->priv; > + AVFilterLink *outlink = ctx->outputs[0]; > + const int step = s->step; > + AVFrame *out; > + int x, y, i; > + > + if (av_frame_is_writable(in)) { > + out = in; > + } else { > + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); > + if (!out) { > + av_frame_free(&in); > + return AVERROR(ENOMEM); > + } > + av_frame_copy_props(out, in); > + } > + > + switch (s->bpp) { > + case 1: > + for (i = 0; i < s->nb_comp; i++) { > + Range *r = &s->range[i]; > + const uint8_t offset = s->rgba_map[i]; > + const uint8_t *srcrow = in->data[0]; > + uint8_t *dstrow = out->data[0]; > + int imin = round(r->in_min * UINT8_MAX); > + int imax = round(r->in_max * UINT8_MAX); > + int omin = round(r->out_min * UINT8_MAX); > + int omax = round(r->out_max * UINT8_MAX); > + double coeff; > + > + if (imin < 0) { > + imin = UINT8_MAX; > + for (y = 0; y < inlink->h; y++) { > + const uint8_t *src = srcrow; > + > + for (x = 0; x < s->linesize; x += step) > + imin = FFMIN(imin, src[x + offset]); > + srcrow += in->linesize[0]; > + } > + } > + if (imax < 0) { > + srcrow = in->data[0]; > + imax = 0; > + for (y = 0; y < inlink->h; y++) { > + const uint8_t *src = srcrow; > + > + for (x = 0; x < s->linesize; x += step) > + imax = FFMAX(imax, src[x + offset]); > + srcrow += in->linesize[0]; > + } > + }
It might be interresting to print the choosen imin/imax values when some debug option is set if you want other than this and what others suggested the patch LGTM thanks [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB I know you won't believe me, but the highest form of Human Excellence is to question oneself and others. -- Socrates
signature.asc
Description: Digital signature
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel