[FFmpeg-devel] [PATCH] lavfi: add blackdetect filter
Clément Bœsch
ubitux at gmail.com
Sat Mar 3 00:54:40 CET 2012
On Fri, Mar 02, 2012 at 04:46:20PM +0100, Stefano Sabatini wrote:
> Address trac ticket #901.
> ---
> doc/filters.texi | 50 ++++++++++
> libavfilter/Makefile | 1 +
> libavfilter/allfilters.c | 1 +
> libavfilter/vf_blackdetect.c | 209 ++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 261 insertions(+), 0 deletions(-)
> create mode 100644 libavfilter/vf_blackdetect.c
>
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 238401a..b5e8954 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -761,6 +761,56 @@ video, use the command:
> ass=sub.ass
> @end example
>
> + at section blackdetect
> +
Global comment: couldn't we have a "unified color" detector instead? So we
could detect bright frames for instance, or full green ones.
> +Detect black video intervals that are (almost) completely black. Can
> +be useful to detect chapter transitions or commercials. Output lines
> +consist of the frame number of the detected frame, the start, end and
> +duration of the detected black interval expressed in seconds.
> +
> +In order to display the output lines, you need to set the loglevel at
> +least to the AV_LOG_INFO value.
> +
> +This filter accepts a list of options in the form of
> + at var{key}=@var{value} pairs separated by ":". A description of the
> +accepted options follows.
> +
> + at table @option
> + at item min_black_duration, d
> +Set the minimum detected black duration expressed in seconds. It must
> +be a non-negative floating point number.
> +
> +Default value is 2.0 seconds.
> +
> + at item picture_black_ratio_th, pic_th
> +Set the threshold for considering a picture "black".
> +Express the minimum value for the ratio:
> + at example
> + at var{nb_black_pixels} / @var{nb_pixels}
> + at end example
> +
> +for which a picture is considered black.
> +Default value is 0.98.
> +
> + at item pixel_black_th, pix_th
> +Set the threshold for considering a pixel "black".
> +
> +Express the maximum pixel luminance value for which a pixel is
> +considered "black". The value is scaled according to the pixel format
> +luminance range, following the equation below:
> + at example
> + at var{absolute_threshold} = @var{minimum_luminance_value} + @var{pixel_black_th} * @var{luminance_range}
> + at end example
> +
The luminance_range is a nice thing; you might want to comment on it just
a bit.
> +Default value is 0.10.
> + at end table
> +
> +The following example sets the maximum pixel threshold to the minimum
> +value, and detects only black intervals of 2 or more seconds:
> + at example
> +blackdetect=d=2:pix_th=0.00
> + at end example
> +
> @section blackframe
>
> Detect frames that are (almost) completely black. Can be useful to
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index 6e7379c..df3a27f 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -48,6 +48,7 @@ OBJS-$(CONFIG_ABUFFERSINK_FILTER) += sink_buffer.o
> OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o
>
> OBJS-$(CONFIG_ASS_FILTER) += vf_ass.o
> +OBJS-$(CONFIG_BLACKDETECT_FILTER) += vf_blackdetect.o
> OBJS-$(CONFIG_BLACKFRAME_FILTER) += vf_blackframe.o
> OBJS-$(CONFIG_BOXBLUR_FILTER) += vf_boxblur.o
> OBJS-$(CONFIG_COPY_FILTER) += vf_copy.o
> diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
> index 487738a..f6230be 100644
> --- a/libavfilter/allfilters.c
> +++ b/libavfilter/allfilters.c
> @@ -56,6 +56,7 @@ void avfilter_register_all(void)
> REGISTER_FILTER (ANULLSINK, anullsink, asink);
>
> REGISTER_FILTER (ASS, ass, vf);
> + REGISTER_FILTER (BLACKDETECT, blackdetect, vf);
> REGISTER_FILTER (BLACKFRAME, blackframe, vf);
> REGISTER_FILTER (BOXBLUR, boxblur, vf);
> REGISTER_FILTER (COPY, copy, vf);
> diff --git a/libavfilter/vf_blackdetect.c b/libavfilter/vf_blackdetect.c
> new file mode 100644
> index 0000000..63336cd
> --- /dev/null
> +++ b/libavfilter/vf_blackdetect.c
> @@ -0,0 +1,209 @@
> +/*
> + * Copyright (c) 2012 Stefano Sabatini
> + *
> + * 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
> + */
> +
> +/**
> + * @file
> + * Video black detector, loosely based on blackframe with extended
> + * syntax and features
> + */
> +
> +#include <float.h>
> +#include "libavutil/opt.h"
> +#include "libavutil/timestamp.h"
> +#include "avfilter.h"
> +#include "internal.h"
> +
> +typedef struct {
> + const AVClass *class;
> + double min_black_duration_time; ///< minimum duration of detected black, in seconds
> + double min_black_duration; ///< minimum duration of detected black, in seconds
One of the comment looks wrong
> + int64_t black_start; ///< pts start time of the first black picture
> + int64_t black_end; ///< pts end time of the last black picture
> + int black_started;
> +
> + double picture_black_ratio_th;
> + double pixel_black_th;
> + unsigned int pixel_black_th_i;
> +
> + unsigned int frame_count; ///< frame number
> + unsigned int nb_black_pixels; ///< number of black pixels counted so far
> +} BlackDetectContext;
> +
> +#define OFFSET(x) offsetof(BlackDetectContext, x)
> +static const AVOption blackdetect_options[] = {
> + { "d", "set minimum detected black duration in seconds", OFFSET(min_black_duration_time), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, FLT_MAX},
> + { "min_black_duration", "set minimum detected black duration in seconds", OFFSET(min_black_duration_time), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, FLT_MAX},
Why not just "duration" for the long version? These option are in the
filter string scope, I don't think they need a long namespace like this.
Also, why FLT_MAX and not DBL_MAX? (which BTW is used in only one single
place).
> + { "picture_black_ratio_th", "set the picture black ratio threshold", OFFSET(picture_black_ratio_th), AV_OPT_TYPE_DOUBLE, {.dbl=.98}, 0, 1},
> + { "pic_th", "set the picture black ratio threshold", OFFSET(picture_black_ratio_th), AV_OPT_TYPE_DOUBLE, {.dbl=.98}, 0, 1},
Weird align around OFFSET()
> + { "pixel_black_th", "set the pixel black threshold", OFFSET(pixel_black_th), AV_OPT_TYPE_DOUBLE, {.dbl=.10}, 0, 1},
> + { "pix_th", "set the pixel black threshold", OFFSET(pixel_black_th), AV_OPT_TYPE_DOUBLE, {.dbl=.10}, 0, 1},
> + { NULL },
> +};
> +
> +static const char *blackdetect_get_name(void *ctx)
> +{
> + return "blackdetect";
> +}
> +
> +static const AVClass blackdetect_class = {
> + .class_name = "BlackDetectContext",
> + .item_name = blackdetect_get_name,
> + .option = blackdetect_options,
> +};
> +
> +#define YUVJ_FORMATS \
> + PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUVJ440P
> +
> +static enum PixelFormat yuvj_formats[] = {
> + YUVJ_FORMATS, PIX_FMT_NONE
> +};
> +
> +static int query_formats(AVFilterContext *ctx)
> +{
> + static const enum PixelFormat pix_fmts[] = {
> + PIX_FMT_YUV410P, PIX_FMT_YUV420P, PIX_FMT_GRAY8, PIX_FMT_NV12,
> + PIX_FMT_NV21, PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV411P,
> + YUVJ_FORMATS,
> + PIX_FMT_NONE
> + };
> +
> + avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
> + return 0;
> +}
> +
> +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
> +{
> + int ret;
> + BlackDetectContext *blackdetect = ctx->priv;
> +
> + blackdetect->class = &blackdetect_class;
> + av_opt_set_defaults(blackdetect);
> +
> + if ((ret = av_set_options_string(blackdetect, args, "=", ":")) < 0) {
> + av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int config_input(AVFilterLink *inlink)
> +{
> + AVFilterContext *ctx = inlink->dst;
> + BlackDetectContext *blackdetect = ctx->priv;
> +
> + blackdetect->min_black_duration =
> + blackdetect->min_black_duration_time / av_q2d(inlink->time_base);
> +
> + blackdetect->pixel_black_th_i = ff_fmt_is_in(inlink->format, yuvj_formats) ?
> + blackdetect->pixel_black_th * 255 :
> + 16 + blackdetect->pixel_black_th * (235 - 16);
This is all about the luminance range, right?
> +
> + av_log(blackdetect, AV_LOG_INFO,
> + "min_black_duration:%s pixel_black_th:%f pixel_black_th_i:%d picture_black_ratio_th:%f\n",
> + av_ts2timestr(blackdetect->min_black_duration, &inlink->time_base),
> + blackdetect->pixel_black_th, blackdetect->pixel_black_th_i,
> + blackdetect->picture_black_ratio_th);
> + return 0;
> +}
> +
> +static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
> +{
> + AVFilterContext *ctx = inlink->dst;
> + BlackDetectContext *blackdetect = ctx->priv;
> + AVFilterBufferRef *picref = inlink->cur_buf;
> + int x, i;
> + uint8_t *p = picref->data[0] + y * picref->linesize[0];
> +
const uint8_t *p?
[...]
--
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20120303/8b859dea/attachment.asc>
More information about the ffmpeg-devel
mailing list