FFmpeg
vf_blackdetect.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012 Stefano Sabatini
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * Video black detector, loosely based on blackframe with extended
24  * syntax and features
25  */
26 
27 #include <float.h>
28 #include "libavutil/opt.h"
29 #include "libavutil/timestamp.h"
30 #include "avfilter.h"
31 #include "internal.h"
32 
33 typedef struct BlackDetectContext {
34  const AVClass *class;
35  double black_min_duration_time; ///< minimum duration of detected black, in seconds
36  int64_t black_min_duration; ///< minimum duration of detected black, expressed in timebase units
37  int64_t black_start; ///< pts start time of the first black picture
38  int64_t black_end; ///< pts end time of the last black picture
39  int64_t last_picref_pts; ///< pts of the last input picture
41 
44  unsigned int pixel_black_th_i;
45 
46  unsigned int nb_black_pixels; ///< number of black pixels counted so far
48 
49 #define OFFSET(x) offsetof(BlackDetectContext, x)
50 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
51 
52 static const AVOption blackdetect_options[] = {
53  { "d", "set minimum detected black duration in seconds", OFFSET(black_min_duration_time), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, DBL_MAX, FLAGS },
54  { "black_min_duration", "set minimum detected black duration in seconds", OFFSET(black_min_duration_time), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, DBL_MAX, FLAGS },
55  { "picture_black_ratio_th", "set the picture black ratio threshold", OFFSET(picture_black_ratio_th), AV_OPT_TYPE_DOUBLE, {.dbl=.98}, 0, 1, FLAGS },
56  { "pic_th", "set the picture black ratio threshold", OFFSET(picture_black_ratio_th), AV_OPT_TYPE_DOUBLE, {.dbl=.98}, 0, 1, FLAGS },
57  { "pixel_black_th", "set the pixel black threshold", OFFSET(pixel_black_th), AV_OPT_TYPE_DOUBLE, {.dbl=.10}, 0, 1, FLAGS },
58  { "pix_th", "set the pixel black threshold", OFFSET(pixel_black_th), AV_OPT_TYPE_DOUBLE, {.dbl=.10}, 0, 1, FLAGS },
59  { NULL }
60 };
61 
62 AVFILTER_DEFINE_CLASS(blackdetect);
63 
64 #define YUVJ_FORMATS \
65  AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P
66 
67 static const enum AVPixelFormat yuvj_formats[] = {
69 };
70 
72 {
73  static const enum AVPixelFormat pix_fmts[] = {
81  };
82 
83  AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
84  if (!fmts_list)
85  return AVERROR(ENOMEM);
86  return ff_set_common_formats(ctx, fmts_list);
87 }
88 
90 {
91  AVFilterContext *ctx = inlink->dst;
92  BlackDetectContext *blackdetect = ctx->priv;
93 
94  blackdetect->black_min_duration =
95  blackdetect->black_min_duration_time / av_q2d(inlink->time_base);
96 
97  blackdetect->pixel_black_th_i = ff_fmt_is_in(inlink->format, yuvj_formats) ?
98  // luminance_minimum_value + pixel_black_th * luminance_range_size
99  blackdetect->pixel_black_th * 255 :
100  16 + blackdetect->pixel_black_th * (235 - 16);
101 
102  av_log(blackdetect, AV_LOG_VERBOSE,
103  "black_min_duration:%s pixel_black_th:%f pixel_black_th_i:%d picture_black_ratio_th:%f\n",
104  av_ts2timestr(blackdetect->black_min_duration, &inlink->time_base),
105  blackdetect->pixel_black_th, blackdetect->pixel_black_th_i,
106  blackdetect->picture_black_ratio_th);
107  return 0;
108 }
109 
111 {
112  BlackDetectContext *blackdetect = ctx->priv;
113  AVFilterLink *inlink = ctx->inputs[0];
114 
115  if ((blackdetect->black_end - blackdetect->black_start) >= blackdetect->black_min_duration) {
116  av_log(blackdetect, AV_LOG_INFO,
117  "black_start:%s black_end:%s black_duration:%s\n",
118  av_ts2timestr(blackdetect->black_start, &inlink->time_base),
119  av_ts2timestr(blackdetect->black_end, &inlink->time_base),
120  av_ts2timestr(blackdetect->black_end - blackdetect->black_start, &inlink->time_base));
121  }
122 }
123 
124 static int request_frame(AVFilterLink *outlink)
125 {
126  AVFilterContext *ctx = outlink->src;
127  BlackDetectContext *blackdetect = ctx->priv;
128  AVFilterLink *inlink = ctx->inputs[0];
129  int ret = ff_request_frame(inlink);
130 
131  if (ret == AVERROR_EOF && blackdetect->black_started) {
132  // FIXME: black_end should be set to last_picref_pts + last_picref_duration
133  blackdetect->black_end = blackdetect->last_picref_pts;
134  check_black_end(ctx);
135  }
136  return ret;
137 }
138 
140 {
141  AVFilterContext *ctx = inlink->dst;
142  BlackDetectContext *blackdetect = ctx->priv;
143  double picture_black_ratio = 0;
144  const uint8_t *p = picref->data[0];
145  int x, i;
146 
147  for (i = 0; i < inlink->h; i++) {
148  for (x = 0; x < inlink->w; x++)
149  blackdetect->nb_black_pixels += p[x] <= blackdetect->pixel_black_th_i;
150  p += picref->linesize[0];
151  }
152 
153  picture_black_ratio = (double)blackdetect->nb_black_pixels / (inlink->w * inlink->h);
154 
155  av_log(ctx, AV_LOG_DEBUG,
156  "frame:%"PRId64" picture_black_ratio:%f pts:%s t:%s type:%c\n",
157  inlink->frame_count_out, picture_black_ratio,
158  av_ts2str(picref->pts), av_ts2timestr(picref->pts, &inlink->time_base),
160 
161  if (picture_black_ratio >= blackdetect->picture_black_ratio_th) {
162  if (!blackdetect->black_started) {
163  /* black starts here */
164  blackdetect->black_started = 1;
165  blackdetect->black_start = picref->pts;
166  av_dict_set(&picref->metadata, "lavfi.black_start",
167  av_ts2timestr(blackdetect->black_start, &inlink->time_base), 0);
168  }
169  } else if (blackdetect->black_started) {
170  /* black ends here */
171  blackdetect->black_started = 0;
172  blackdetect->black_end = picref->pts;
173  check_black_end(ctx);
174  av_dict_set(&picref->metadata, "lavfi.black_end",
175  av_ts2timestr(blackdetect->black_end, &inlink->time_base), 0);
176  }
177 
178  blackdetect->last_picref_pts = picref->pts;
179  blackdetect->nb_black_pixels = 0;
180  return ff_filter_frame(inlink->dst->outputs[0], picref);
181 }
182 
183 static const AVFilterPad blackdetect_inputs[] = {
184  {
185  .name = "default",
186  .type = AVMEDIA_TYPE_VIDEO,
187  .config_props = config_input,
188  .filter_frame = filter_frame,
189  },
190  { NULL }
191 };
192 
194  {
195  .name = "default",
196  .type = AVMEDIA_TYPE_VIDEO,
197  .request_frame = request_frame,
198  },
199  { NULL }
200 };
201 
203  .name = "blackdetect",
204  .description = NULL_IF_CONFIG_SMALL("Detect video intervals that are (almost) black."),
205  .priv_size = sizeof(BlackDetectContext),
207  .inputs = blackdetect_inputs,
208  .outputs = blackdetect_outputs,
209  .priv_class = &blackdetect_class,
210 };
#define NULL
Definition: coverity.c:32
This structure describes decoded (raw) audio or video data.
Definition: frame.h:308
AVOption.
Definition: opt.h:248
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
Main libavfilter public API header.
AVFilter ff_vf_blackdetect
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:287
unsigned int nb_black_pixels
number of black pixels counted so far
const char * name
Pad name.
Definition: internal.h:60
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:347
static const AVFilterPad blackdetect_inputs[]
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1091
uint8_t
AVOptions.
static int config_input(AVFilterLink *inlink)
timestamp utils, mostly useful for debugging/logging purposes
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:401
static int query_formats(AVFilterContext *ctx)
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
char av_get_picture_type_char(enum AVPictureType pict_type)
Return a single letter to describe the given picture type pict_type.
Definition: utils.c:88
#define AVERROR_EOF
End of file.
Definition: error.h:55
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:210
AVDictionary * metadata
metadata.
Definition: frame.h:594
int ff_fmt_is_in(int fmt, const int *fmts)
Tell if an integer is contained in the provided -1-terminated list of integers.
Definition: formats.c:258
#define av_log(a,...)
int64_t black_min_duration
minimum duration of detected black, expressed in timebase units
double picture_black_ratio_th
A filter pad used for either input or output.
Definition: internal.h:54
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:588
#define av_ts2timestr(ts, tb)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: timestamp.h:76
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:153
void * priv
private data for use by the filter
Definition: avfilter.h:354
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:89
#define OFFSET(x)
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
static const AVFilterPad blackdetect_outputs[]
as above, but U and V bytes are swapped
Definition: pixfmt.h:90
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:391
double black_min_duration_time
minimum duration of detected black, in seconds
int64_t last_picref_pts
pts of the last input picture
#define FLAGS
AVFormatContext * ctx
Definition: movenc.c:48
unsigned int pixel_black_th_i
AVFILTER_DEFINE_CLASS(blackdetect)
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
static void check_black_end(AVFilterContext *ctx)
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
static enum AVPixelFormat yuvj_formats[]
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:339
#define YUVJ_FORMATS
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:70
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:72
int64_t black_end
pts end time of the last black picture
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:145
const char * name
Filter name.
Definition: avfilter.h:149
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:351
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:300
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:322
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
Y , 8bpp.
Definition: pixfmt.h:74
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:73
int64_t black_start
pts start time of the first black picture
#define av_ts2str(ts)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: timestamp.h:54
A list of supported formats for one end of a filter link.
Definition: formats.h:65
An instance of a filter.
Definition: avfilter.h:339
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:99
static int request_frame(AVFilterLink *outlink)
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition: avfilter.c:407
static const AVOption blackdetect_options[]
internal API functions
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
int i
Definition: input.c:407