[FFmpeg-devel] port mplayer eq filter to libavfilter
Stefano Sabatini
stefano.sabatini-lala
Tue Nov 23 19:18:11 CET 2010
On date Tuesday 2010-11-23 22:22:47 +0800, William Yu encoded:
> I have fix the problem mention below.
> and change to directly process the input picture.
> Please check it again.
> BTW, I had send a mail to D Richard Felker III <dalias <at> aerifal.cx>.
> If he agree relicense these under LGPL. I will patch it to LGPL. Thanks.
>
> 2010/11/22 Stefano Sabatini <stefano.sabatini-lala at poste.it>:
> > On date Monday 2010-11-22 15:15:25 +0100, Stefano Sabatini encoded:
> >> On date Monday 2010-11-22 20:33:11 +0800, William Yu encoded:
> > [...]
> >> > +}
> >> > +
> >> > +static void end_frame(AVFilterLink *link)
> >>
> >> inlink for enhanced readability
> >>
> >> > +{
> >> > + ? ?EQContext * eq = link->dst->priv;
> >> > + ? ?AVFilterBufferRef *in ?= link->cur_buf;
> >> > + ? ?AVFilterBufferRef *out = link->dst->outputs[0]->out_buf;
> >> > +
> >> > + ? ?eq->process(out->data[0], out->linesize[0],
> >> > + ? ? ? ?in->data[0], in->linesize[0],
> >> > + ? ? ? ?link->w, link->h, eq->brightness, eq->contrast);
> >> > + ? ?copy_chroma(in,out,link);
> >
> > Also is it really necessary to copy the chroma planes to a new frame?
> > Maybe It would be possible to directly process the input picture, no need to
> > allocate another one and to copy back the chroma planes.
> >
> > Regards.
> > --
> > FFmpeg = Fundamentalist & Free Multipurpose Portable Ecumenical God
> > _______________________________________________
> > ffmpeg-devel mailing list
> > ffmpeg-devel at mplayerhq.hu
> > https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-devel
> >
> diff --git a/Changelog b/Changelog
> index dc949cd..6a6a0c7 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -59,6 +59,7 @@ version <next>:
> - overlay filter added
> - rename aspect filter to setdar, and pixelaspect to setsar
> - IEC 61937 demuxer
> +- eq video filter added
>
>
> version 0.6:
> diff --git a/configure b/configure
> index 7dcb50f..c076ea9 100755
> --- a/configure
> +++ b/configure
> @@ -1405,6 +1405,7 @@ udp_protocol_deps="network"
> # filters
> blackframe_filter_deps="gpl"
> cropdetect_filter_deps="gpl"
> +eq_filter_deps="gpl"
> frei0r_filter_deps="frei0r dlopen strtok_r"
> ocv_smooth_filter_deps="libopencv"
> yadif_filter_deps="gpl"
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 1cba2d6..0a45e7b 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -257,6 +257,38 @@ drawbox
> drawbox=10:20:200:60:red@@0.5"
> @end example
>
> + at section eq
> +
> +Adjust brightness or contrast of the input video.
or -> and/or
> +
> +It accepts the following parameters:
> + at var{brightness}:@var{constrast}
> +
> +Negative values for the amount will descrease the corresponding value
> +for the lightness or contrast of the input video, while positive
> +values will increase the corresponding value.
> +
> + at table @option
> +
> + at item brightness
> +Set the brightness amount. It can be an integer between -100
> +and 100, default value is 0.
> +
> + at item contrast
> +Set the contrast amount. It can be an integer between -100
> +and 100, default value is 0.
> +
> + at end table
> +
> + at example
> +# increase lightness and contrast by 20 percent
> +eq=20:20
> +
> +# decrease lightness and contrast by 20 percent
> +eq=-20:-20
> +
> + at end example
> +
> @section fifo
>
> Buffer input images and send them when they are requested.
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index 210510f..37df7ee 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -23,6 +23,7 @@ OBJS-$(CONFIG_BLACKFRAME_FILTER) += vf_blackframe.o
> OBJS-$(CONFIG_CROP_FILTER) += vf_crop.o
> OBJS-$(CONFIG_CROPDETECT_FILTER) += vf_cropdetect.o
> OBJS-$(CONFIG_DRAWBOX_FILTER) += vf_drawbox.o
> +OBJS-$(CONFIG_EQ_FILTER) += vf_eq.o
> OBJS-$(CONFIG_FIFO_FILTER) += vf_fifo.o
> OBJS-$(CONFIG_FORMAT_FILTER) += vf_format.o
> OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o
> diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
> index 9e3ba14..dae6848 100644
> --- a/libavfilter/allfilters.c
> +++ b/libavfilter/allfilters.c
> @@ -44,6 +44,7 @@ void avfilter_register_all(void)
> REGISTER_FILTER (CROP, crop, vf);
> REGISTER_FILTER (CROPDETECT, cropdetect, vf);
> REGISTER_FILTER (DRAWBOX, drawbox, vf);
> + REGISTER_FILTER (EQ, eq, vf);
> REGISTER_FILTER (FIFO, fifo, vf);
> REGISTER_FILTER (FORMAT, format, vf);
> REGISTER_FILTER (FREI0R, frei0r, vf);
> diff --git a/libavfilter/eq.h b/libavfilter/eq.h
> new file mode 100644
> index 0000000..f6b98d2
> --- /dev/null
> +++ b/libavfilter/eq.h
> @@ -0,0 +1,18 @@
> +/*
> + * Ported to FFmpeg from MPlayer libmpcodecs/vf_eq.c
> + * Port copyright (C) 2010 William Yu <genwillyu at gmail dot com>
Ehm missing LGPL notice. Also I'd prefer to just use:
* Copyright (c) 2010 William Yu <genwillyu at gmail dot com>
* Copyright (c) 200X Richard Felker <genwillyu at gmail dot com>
so it's easier to understand which the copyright holders are. You can
mention this is a port in the @file notice of vf_eq.c.
> + *
> + * @file libavfilter/eq.h
> + */
> +
> +#ifndef AVFILTER_EQ_H
> +#define AVFILTER_EQ_H
> +
> +#include "avfilter.h"
> +
> +void ff_eq_filter_process_mmx(uint8_t *dest,
> + int dstride, uint8_t *src, int sstride,
> + int w, int h, int brightness,
> + int contrast);
> +
> +#endif /* AVFILTER_EQ_H */
> diff --git a/libavfilter/vf_eq.c b/libavfilter/vf_eq.c
> new file mode 100644
> index 0000000..dba556d
> --- /dev/null
> +++ b/libavfilter/vf_eq.c
> @@ -0,0 +1,138 @@
> +/*
> + * Ported to FFmpeg from MPlayer libmpcodecs/vf_eq.c
> + * Port copyright (C) 2010 William Yu <genwillyu at gmail dot com>
Same here as above.
> + *
> + * @file libavfilter/vf_eq.c
> + */
> +
> +#include "libavutil/cpu.h"
> +#include "libavutil/common.h"
> +#include "avfilter.h"
> +#include "eq.h"
> +
> +typedef struct EQContext {
> + int brightness; ///< scale from -100 to 100
> + int contrast; ///< scale from -100 to 100
> + void (*process)( ///< process function
> + unsigned char *dest,
> + int dstride,
> + unsigned char *src,
> + int sstride,
> + int w, int h,
> + int brightness,
> + int contrast);
> +} EQContext;
> +
> +static void process_c(unsigned char *dest, int dstride, unsigned char *src, int sstride,
> + int w, int h, int brightness, int contrast)
Nits: dest -> dst
sstride -> src_stride
dstride -> dst_stride
> +{
> + int i;
> + int pel;
> + int dstep = dstride-w;
> + int sstep = sstride-w;
> +
> + contrast = ((contrast+100)*256*256)/100;
> + brightness = ((brightness+100)*511)/200-128 - (contrast>>9);
> +
> + while (h--) {
> + for (i = w; i; i--) {
> + pel = ((*src++* contrast)>>16) + brightness;
> + if (pel&768) pel = (-pel)>>31;
> + *dest++ = pel;
> + }
> + src += sstep;
> + dest += dstep;
> + }
> +}
> +
> +static int query_formats(AVFilterContext *ctx)
> +{
> + enum PixelFormat pix_fmts[] = {
> + PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, PIX_FMT_YUV410P,
> + PIX_FMT_YUV411P, PIX_FMT_YUV440P, PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P,
> + PIX_FMT_YUVJ444P, PIX_FMT_YUVJ440P, PIX_FMT_NONE
> + };
> +
> + avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
> +
> + return 0;
> +}
> +
> +static av_cold int init(AVFilterContext *ctx, const char * args, void * opaque)
> +{
> + EQContext * eq = ctx->priv;
> + av_unused int cpu_flags = av_get_cpu_flags();
> +
> + eq->brightness = 0;
> + eq->contrast = 0;
> +
> + if (args)
> + sscanf(args, "%d:%d", &(eq->brightness), &(eq->contrast));
> +
> + if (eq->brightness < -100 || eq->brightness > 100 ||
> + eq->contrast < -100 || eq->contrast > 100) {
> + av_log(ctx, AV_LOG_ERROR,
> + "Invalid brightness or contrast value %d:%d\n",
> + eq->brightness, eq->contrast);
> + return AVERROR(EINVAL);
> + }
> +
> + av_log(ctx, AV_LOG_INFO,
> + "brightness and contrast value %d:%d\n",
> + eq->brightness, eq->contrast);
Nit:
av_log(ctx, AV_LOG_INFO, "brightness:%d contrast:%d\n",
eq->brightness, eq->contrast);
simpler and easier to parse, also more consistent with the other
filters.
> + eq->process = NULL;
> + if (eq->brightness || eq->contrast) {
> + eq->process = process_c;
> + if (HAVE_MMX && cpu_flags & AV_CPU_FLAG_MMX) {
> + av_log(ctx,AV_LOG_INFO,"use mmx\n");
> + eq->process = ff_eq_filter_process_mmx;
> + }
> + }
you can merge the two info logs and have:
"brightness:%d contrast:%d use_mmx:%d\n"
> + return 0;
> +}
> +
> +static void start_frame(AVFilterLink * link, AVFilterBufferRef *picref)
> +{
> + AVFilterBufferRef *ref2 = avfilter_ref_buffer(picref,~0);
> +
> + avfilter_start_frame(link->dst->outputs[0], ref2);
> +}
this is not required
> +
> +static void end_frame(AVFilterLink *inlink)
> +{
> + EQContext * eq = inlink->dst->priv;
> + AVFilterBufferRef *in = inlink->cur_buf;
> +
> + if ( eq->process )
> + eq->process(in->data[0], in->linesize[0],
> + in->data[0], in->linesize[0],
> + inlink->w, inlink->h, eq->brightness, eq->contrast);
> +
> + avfilter_unref_buffer(in);
> + avfilter_draw_slice(inlink->dst->outputs[0], 0, inlink->h, 1);
> + avfilter_end_frame(inlink->dst->outputs[0]);
> +}
> +
> +static void null_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
> +{
> +}
As Bobby pointed out you can exploit cache locality for enhanced
performance and put the code in draw_slice, as it is done in the
drawbox filter, check also the documentation of slicify.
[...]
--
FFmpeg = Freak and Fierce MultiPurpose Evil Guru
More information about the ffmpeg-devel
mailing list