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 
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;
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 
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;
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),
210  .priv_class = &blackdetect_class,
211 };
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
AVERROR
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
opt.h
ff_make_format_list
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
blackdetect_options
static const AVOption blackdetect_options[]
Definition: vf_blackdetect.c:52
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1080
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:55
inlink
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
Definition: filter_design.txt:212
BlackDetectContext::black_end
int64_t black_end
pts end time of the last black picture
Definition: vf_blackdetect.c:38
BlackDetectContext::black_min_duration_time
double black_min_duration_time
minimum duration of detected black, in seconds
Definition: vf_blackdetect.c:35
BlackDetectContext::last_picref_pts
int64_t last_picref_pts
pts of the last input picture
Definition: vf_blackdetect.c:39
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
AVFrame::pts
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:388
AVOption
AVOption.
Definition: opt.h:246
ff_request_frame
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition: avfilter.c:407
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
float.h
YUVJ_FORMATS
#define YUVJ_FORMATS
Definition: vf_blackdetect.c:64
AV_PIX_FMT_YUV440P
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:99
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:148
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:309
AVFilterFormats
A list of supported formats for one end of a filter link.
Definition: formats.h:64
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:54
ff_set_common_formats
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:568
blackdetect_inputs
static const AVFilterPad blackdetect_inputs[]
Definition: vf_blackdetect.c:184
AV_OPT_TYPE_DOUBLE
@ AV_OPT_TYPE_DOUBLE
Definition: opt.h:225
av_q2d
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
config_input
static int config_input(AVFilterLink *inlink)
Definition: vf_blackdetect.c:89
outputs
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
ctx
AVFormatContext * ctx
Definition: movenc.c:48
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
BlackDetectContext::pixel_black_th
double pixel_black_th
Definition: vf_blackdetect.c:43
request_frame
static int request_frame(AVFilterLink *outlink)
Definition: vf_blackdetect.c:124
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:67
NULL
#define NULL
Definition: coverity.c:32
ff_fmt_is_in
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
inputs
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
Definition: filter_design.txt:243
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:74
yuvj_formats
static enum AVPixelFormat yuvj_formats[]
Definition: vf_blackdetect.c:67
AVFrame::pict_type
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:378
av_ts2timestr
#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
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:188
BlackDetectContext::black_started
int black_started
Definition: vf_blackdetect.c:40
BlackDetectContext::black_start
int64_t black_start
pts start time of the first black picture
Definition: vf_blackdetect.c:37
FLAGS
#define FLAGS
Definition: vf_blackdetect.c:50
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
internal.h
av_get_picture_type_char
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
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
BlackDetectContext
Definition: vf_blackdetect.c:33
uint8_t
uint8_t
Definition: audio_convert.c:194
check_black_end
static void check_black_end(AVFilterContext *ctx)
Definition: vf_blackdetect.c:110
AV_PIX_FMT_NV21
@ AV_PIX_FMT_NV21
as above, but U and V bytes are swapped
Definition: pixfmt.h:90
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:60
AVFilter
Filter definition.
Definition: avfilter.h:144
BlackDetectContext::picture_black_ratio_th
double picture_black_ratio_th
Definition: vf_blackdetect.c:42
ret
ret
Definition: filter_design.txt:187
BlackDetectContext::black_min_duration
int64_t black_min_duration
minimum duration of detected black, expressed in timebase units
Definition: vf_blackdetect.c:36
AV_PIX_FMT_NV12
@ AV_PIX_FMT_NV12
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
BlackDetectContext::pixel_black_th_i
unsigned int pixel_black_th_i
Definition: vf_blackdetect.c:44
blackdetect_outputs
static const AVFilterPad blackdetect_outputs[]
Definition: vf_blackdetect.c:194
BlackDetectContext::nb_black_pixels
unsigned int nb_black_pixels
number of black pixels counted so far
Definition: vf_blackdetect.c:46
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
avfilter.h
AVFrame::metadata
AVDictionary * metadata
metadata.
Definition: frame.h:581
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
AVFilterContext
An instance of a filter.
Definition: avfilter.h:338
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
Definition: vf_blackdetect.c:140
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
ff_vf_blackdetect
AVFilter ff_vf_blackdetect
Definition: vf_blackdetect.c:203
AV_PIX_FMT_YUV422P
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(blackdetect)
av_dict_set
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
AV_PIX_FMT_YUV411P
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:73
timestamp.h
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:326
AV_PIX_FMT_YUV410P
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:72
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
av_ts2str
#define av_ts2str(ts)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: timestamp.h:54
OFFSET
#define OFFSET(x)
Definition: vf_blackdetect.c:49
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: vf_blackdetect.c:71