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 
139 // TODO: document metadata
141 {
142  AVFilterContext *ctx = inlink->dst;
143  BlackDetectContext *blackdetect = ctx->priv;
144  double picture_black_ratio = 0;
145  const uint8_t *p = picref->data[0];
146  int x, i;
147 
148  for (i = 0; i < inlink->h; i++) {
149  for (x = 0; x < inlink->w; x++)
150  blackdetect->nb_black_pixels += p[x] <= blackdetect->pixel_black_th_i;
151  p += picref->linesize[0];
152  }
153 
154  picture_black_ratio = (double)blackdetect->nb_black_pixels / (inlink->w * inlink->h);
155 
156  av_log(ctx, AV_LOG_DEBUG,
157  "frame:%"PRId64" picture_black_ratio:%f pts:%s t:%s type:%c\n",
158  inlink->frame_count_out, picture_black_ratio,
159  av_ts2str(picref->pts), av_ts2timestr(picref->pts, &inlink->time_base),
161 
162  if (picture_black_ratio >= blackdetect->picture_black_ratio_th) {
163  if (!blackdetect->black_started) {
164  /* black starts here */
165  blackdetect->black_started = 1;
166  blackdetect->black_start = picref->pts;
167  av_dict_set(&picref->metadata, "lavfi.black_start",
168  av_ts2timestr(blackdetect->black_start, &inlink->time_base), 0);
169  }
170  } else if (blackdetect->black_started) {
171  /* black ends here */
172  blackdetect->black_started = 0;
173  blackdetect->black_end = picref->pts;
174  check_black_end(ctx);
175  av_dict_set(&picref->metadata, "lavfi.black_end",
176  av_ts2timestr(blackdetect->black_end, &inlink->time_base), 0);
177  }
178 
179  blackdetect->last_picref_pts = picref->pts;
180  blackdetect->nb_black_pixels = 0;
181  return ff_filter_frame(inlink->dst->outputs[0], picref);
182 }
183 
184 static const AVFilterPad blackdetect_inputs[] = {
185  {
186  .name = "default",
187  .type = AVMEDIA_TYPE_VIDEO,
188  .config_props = config_input,
189  .filter_frame = filter_frame,
190  },
191  { NULL }
192 };
193 
195  {
196  .name = "default",
197  .type = AVMEDIA_TYPE_VIDEO,
198  .request_frame = request_frame,
199  },
200  { NULL }
201 };
202 
204  .name = "blackdetect",
205  .description = NULL_IF_CONFIG_SMALL("Detect video intervals that are (almost) black."),
206  .priv_size = sizeof(BlackDetectContext),
208  .inputs = blackdetect_inputs,
209  .outputs = blackdetect_outputs,
210  .priv_class = &blackdetect_class,
211 };
#define NULL
Definition: coverity.c:32
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
AVOption.
Definition: opt.h:246
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:283
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:346
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:1093
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:388
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:192
AVDictionary * metadata
metadata.
Definition: frame.h:581
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:254
#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
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
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:569
#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:186
void * priv
private data for use by the filter
Definition: avfilter.h:353
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
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:378
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:187
static enum AVPixelFormat yuvj_formats[]
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:326
#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:144
const char * name
Filter name.
Definition: avfilter.h:148
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:309
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:64
An instance of a filter.
Definition: avfilter.h:338
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)