FFmpeg
Loading...
Searching...
No Matches
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/mem.h"
29#include "libavutil/opt.h"
30#include "libavutil/pixdesc.h"
31#include "libavutil/timestamp.h"
32#include "avfilter.h"
33#include "filters.h"
34#include "formats.h"
35#include "video.h"
36#include "vf_blackdetect.h"
37
38typedef struct BlackDetectContext {
39 const AVClass *class;
40 double black_min_duration_time; ///< minimum duration of detected black, in seconds
41 int64_t black_min_duration; ///< minimum duration of detected black, expressed in timebase units
42 int64_t black_start; ///< pts start time of the first black picture
43 int64_t black_end; ///< pts end time of the last black picture
44 int64_t last_picref_pts; ///< pts of the last input picture
46
49 unsigned int pixel_black_th_i;
50 int alpha;
51
52 unsigned int nb_black_pixels; ///< number of black pixels counted so far
54 int depth;
56 unsigned int *counter;
57
60
61#define OFFSET(x) offsetof(BlackDetectContext, x)
62#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
63
64static const AVOption blackdetect_options[] = {
65 { "d", "set minimum detected black duration in seconds", OFFSET(black_min_duration_time), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, DBL_MAX, FLAGS },
66 { "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 },
67 { "picture_black_ratio_th", "set the picture black ratio threshold", OFFSET(picture_black_ratio_th), AV_OPT_TYPE_DOUBLE, {.dbl=.98}, 0, 1, FLAGS },
68 { "pic_th", "set the picture black ratio threshold", OFFSET(picture_black_ratio_th), AV_OPT_TYPE_DOUBLE, {.dbl=.98}, 0, 1, FLAGS },
69 { "pixel_black_th", "set the pixel black threshold", OFFSET(pixel_black_th), AV_OPT_TYPE_DOUBLE, {.dbl=.10}, 0, 1, FLAGS },
70 { "pix_th", "set the pixel black threshold", OFFSET(pixel_black_th), AV_OPT_TYPE_DOUBLE, {.dbl=.10}, 0, 1, FLAGS },
71 { "alpha", "check alpha instead of luma", OFFSET(alpha), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
72 { NULL }
73};
74
76
77#define YUVJ_FORMATS \
78 AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P
79
80#define YUVA_FORMATS \
81 AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, \
82 AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA444P16, \
83 AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA422P16, \
84 AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA420P16
85
86static const enum AVPixelFormat yuvj_formats[] = {
88};
89
90static const enum AVPixelFormat yuva_formats[] = {
92};
93
112
114 AVFilterFormatsConfig **cfg_in,
115 AVFilterFormatsConfig **cfg_out)
116{
117 const BlackDetectContext *s = ctx->priv;
119 if (s->alpha)
121 else
123
124 return ff_set_common_formats2(ctx, cfg_in, cfg_out, formats);
125}
126
127static int config_input(AVFilterLink *inlink)
128{
129 AVFilterContext *ctx = inlink->dst;
130 BlackDetectContext *s = ctx->priv;
132 const int depth = desc->comp[0].depth;
133
134 s->depth = depth;
135 s->nb_threads = ff_filter_get_nb_threads(ctx);
136 s->time_base = inlink->time_base;
137 s->black_min_duration = s->black_min_duration_time / av_q2d(s->time_base);
138 s->counter = av_calloc(s->nb_threads, sizeof(*s->counter));
139 s->func = ff_blackdetect_get_fn(depth);
140 if (!s->counter)
141 return AVERROR(ENOMEM);
142
144 "black_min_duration:%s pixel_black_th:%f picture_black_ratio_th:%f alpha:%d\n",
145 av_ts2timestr(s->black_min_duration, &s->time_base),
146 s->pixel_black_th, s->picture_black_ratio_th, s->alpha);
147 return 0;
148}
149
151{
152 BlackDetectContext *s = ctx->priv;
153
154 if ((s->black_end - s->black_start) >= s->black_min_duration) {
156 "black_start:%s black_end:%s black_duration:%s\n",
157 av_ts2timestr(s->black_start, &s->time_base),
158 av_ts2timestr(s->black_end, &s->time_base),
159 av_ts2timestr(s->black_end - s->black_start, &s->time_base));
160 }
161}
162
164 int jobnr, int nb_jobs)
165{
166 BlackDetectContext *s = ctx->priv;
167 const AVFrame *in = arg;
168 const int plane = s->alpha ? 3 : 0;
169 const int linesize = in->linesize[plane];
170 const int h = in->height;
171 const int start = ff_slice_pos(h, jobnr, nb_jobs);
172 const int end = ff_slice_pos(h, jobnr + 1, nb_jobs);
173
174 s->counter[jobnr] = s->func(in->data[plane] + start * linesize,
175 linesize, in->width, end - start,
176 s->pixel_black_th_i);
177
178 return 0;
179}
180
181static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
182{
183 FilterLink *inl = ff_filter_link(inlink);
184 AVFilterContext *ctx = inlink->dst;
185 BlackDetectContext *s = ctx->priv;
186 double picture_black_ratio = 0;
187 const int max = (1 << s->depth) - 1;
188 const int factor = (1 << (s->depth - 8));
189 const int full = picref->color_range == AVCOL_RANGE_JPEG ||
191 s->alpha;
192
193 s->pixel_black_th_i = full ? s->pixel_black_th * max :
194 // luminance_minimum_value + pixel_black_th * luminance_range_size
195 16 * factor + s->pixel_black_th * (235 - 16) * factor;
196
198 FFMIN(inlink->h, s->nb_threads));
199
200 for (int i = 0; i < s->nb_threads; i++)
201 s->nb_black_pixels += s->counter[i];
202
203 picture_black_ratio = (double)s->nb_black_pixels / (inlink->w * inlink->h);
204
206 "frame:%"PRId64" picture_black_ratio:%f pts:%s t:%s type:%c\n",
207 inl->frame_count_out, picture_black_ratio,
208 av_ts2str(picref->pts), av_ts2timestr(picref->pts, &s->time_base),
210
211 if (picture_black_ratio >= s->picture_black_ratio_th) {
212 if (!s->black_started) {
213 /* black starts here */
214 s->black_started = 1;
215 s->black_start = picref->pts;
216 av_dict_set(&picref->metadata, "lavfi.black_start",
217 av_ts2timestr(s->black_start, &s->time_base), 0);
218 }
219 } else if (s->black_started) {
220 /* black ends here */
221 s->black_started = 0;
222 s->black_end = picref->pts;
224 av_dict_set(&picref->metadata, "lavfi.black_end",
225 av_ts2timestr(s->black_end, &s->time_base), 0);
226 }
227
228 s->last_picref_pts = picref->pts;
229 s->nb_black_pixels = 0;
230 return ff_filter_frame(inlink->dst->outputs[0], picref);
231}
232
234{
235 BlackDetectContext *s = ctx->priv;
236
237 av_freep(&s->counter);
238
239 if (s->black_started) {
240 // FIXME: black_end should be set to last_picref_pts + last_picref_duration
241 s->black_end = s->last_picref_pts;
243 }
244}
245
247 {
248 .name = "default",
249 .type = AVMEDIA_TYPE_VIDEO,
250 .config_props = config_input,
251 .filter_frame = filter_frame,
252 },
253};
254
256 .p.name = "blackdetect",
257 .p.description = NULL_IF_CONFIG_SMALL("Detect video intervals that are (almost) black."),
258 .p.priv_class = &blackdetect_class,
260 .priv_size = sizeof(BlackDetectContext),
264 .uninit = uninit,
265};
static int config_input(AVFilterLink *inlink)
const FFFilter ff_vf_blackdetect
static AVFormatContext * ctx
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition avfilter.c:1696
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition avfilter.c:846
Main libavfilter public API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define FLAGS
Definition cmdutils.c:598
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
#define max(a, b)
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
int ff_set_common_formats2(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out, AVFilterFormats *formats)
Definition formats.c:1137
av_warn_unused_result AVFilterFormats * ff_make_pixel_format_list(const enum AVPixelFormat *fmts)
Create a list of supported pixel formats.
@ AV_OPT_TYPE_DOUBLE
Underlying C type is double.
Definition opt.h:266
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition avfilter.h:166
#define AVFILTER_FLAG_METADATA_ONLY
The filter is a "metadata" filter - it does not modify the frame data in any way.
Definition avfilter.h:182
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:86
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_INFO
Standard information.
Definition log.h:221
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition rational.h:104
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
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:40
static const int16_t alpha[]
Definition ilbcdata.h:55
static av_cold void uninit(AVBitStreamFilterContext *ctx)
const char * arg
Definition jacosubdec.c:65
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
static int ff_slice_pos(int total, int jobnr, int nb_jobs)
Compute the boundary index for a slice when work of size total is split into nb_jobs slices.
Definition filters.h:763
int ff_pixfmt_is_in(enum AVPixelFormat fmt, const enum AVPixelFormat *fmts)
Tell if a pixel format is contained in the provided AV_PIX_FMT_NONE-terminated list.
Definition formats.c:471
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition filters.h:199
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define FILTER_QUERY_FUNC2(func)
Definition filters.h:241
static void check_black_end(AVFilterContext *ctx)
static int black_counter(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static enum AVPixelFormat yuva_formats[]
static int config_input(AVFilterLink *inlink)
#define YUVJ_FORMATS
static enum AVPixelFormat yuvj_formats[]
static const AVOption blackdetect_options[]
#define YUVA_FORMATS
static enum AVPixelFormat yuv_formats[]
static av_cold void uninit(AVFilterContext *ctx)
static int query_format(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
#define OFFSET(x)
static const AVFilterPad blackdetect_inputs[]
static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
static const int factor[16]
Definition vf_pp7.c:98
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
const char * desc
Definition libsvtav1.c:83
#define FFMIN(a, b)
Definition macros.h:49
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
AVOptions.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#define AV_PIX_FMT_YUV420P16
Definition pixfmt.h:556
#define AV_PIX_FMT_YUV444P12
Definition pixfmt.h:552
#define AV_PIX_FMT_YUV444P9
Definition pixfmt.h:544
#define AV_PIX_FMT_YUV420P10
Definition pixfmt.h:545
#define AV_PIX_FMT_YUV440P12
Definition pixfmt.h:551
#define AV_PIX_FMT_YUV422P9
Definition pixfmt.h:543
@ AVCOL_RANGE_JPEG
Full range content.
Definition pixfmt.h:783
#define AV_PIX_FMT_YUV420P12
Definition pixfmt.h:549
#define AV_PIX_FMT_YUV422P12
Definition pixfmt.h:550
#define AV_PIX_FMT_YUV422P10
Definition pixfmt.h:546
#define AV_PIX_FMT_GRAY12
Definition pixfmt.h:526
#define AV_PIX_FMT_YUV420P9
Definition pixfmt.h:542
#define AV_PIX_FMT_YUV420P14
Definition pixfmt.h:553
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ 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:96
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition pixfmt.h:106
@ AV_PIX_FMT_NV21
as above, but U and V bytes are swapped
Definition pixfmt.h:97
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:77
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition pixfmt.h:81
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition pixfmt.h:79
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition pixfmt.h:80
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition pixfmt.h:78
#define AV_PIX_FMT_YUV422P14
Definition pixfmt.h:554
#define AV_PIX_FMT_GRAY10
Definition pixfmt.h:525
#define AV_PIX_FMT_GRAY14
Definition pixfmt.h:527
#define AV_PIX_FMT_YUV422P16
Definition pixfmt.h:557
#define AV_PIX_FMT_YUV440P10
Definition pixfmt.h:547
#define AV_PIX_FMT_GRAY16
Definition pixfmt.h:528
#define AV_PIX_FMT_YUV444P14
Definition pixfmt.h:555
#define AV_PIX_FMT_YUV444P16
Definition pixfmt.h:558
#define AV_PIX_FMT_YUV444P10
Definition pixfmt.h:548
formats
Definition signature.h:47
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
AVFilterLink ** outputs
array of pointers to output links
Definition avfilter.h:285
Lists of formats / etc.
Definition avfilter.h:120
A list of supported formats for one end of a filter link.
Definition formats.h:64
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition frame.h:574
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition frame.h:493
int width
Definition frame.h:544
int height
Definition frame.h:544
AVDictionary * metadata
metadata.
Definition frame.h:750
enum AVColorRange color_range
MPEG vs JPEG YUV range.
Definition frame.h:723
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition frame.h:517
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition frame.h:559
enum AVPictureType pict_type
Picture type of the frame.
Definition frame.h:564
AVOption.
Definition opt.h:428
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
Rational number (pair of numerator and denominator).
Definition rational.h:58
unsigned int * counter
int64_t black_end
pts end time of the last black picture
int64_t black_min_duration
minimum duration of detected black, expressed in timebase units
int64_t last_picref_pts
pts of the last input picture
int64_t black_start
pts start time of the first black picture
double black_min_duration_time
minimum duration of detected black, in seconds
unsigned int pixel_black_th_i
ff_blackdetect_fn func
unsigned int nb_black_pixels
number of black pixels counted so far
#define av_freep(p)
#define av_log(a,...)
timestamp utils, mostly useful for debugging/logging purposes
#define av_ts2str(ts)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition timestamp.h:54
#define av_ts2timestr(ts, tb)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition timestamp.h:83
char full[32]
static ff_blackdetect_fn ff_blackdetect_get_fn(int depth)
unsigned(* ff_blackdetect_fn)(const uint8_t *src, ptrdiff_t stride, ptrdiff_t width, ptrdiff_t height, unsigned threshold)
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition video.c:37