[FFmpeg-devel] [PATCH] avfilter/select: add metadata detection function
Timo Rothenpieler
timo at rothenpieler.org
Fri Jun 18 15:50:22 EEST 2021
---
doc/filters.texi | 18 ++++++++++
libavfilter/f_select.c | 79 ++++++++++++++++++++++++++++++++++++++++--
libavfilter/version.h | 2 +-
3 files changed, 96 insertions(+), 3 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index da8f7d7726..05fec04b55 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -5404,6 +5404,7 @@ Set sidechain gain. Default is 1. Range is from 0.015625 to 64.
This filter supports the all above options as @ref{commands}.
+ at anchor{silencedetect}
@section silencedetect
Detect silence in an audio stream.
@@ -7263,6 +7264,7 @@ Filter out noisy pixels from @code{bitplane} set above.
Default is disabled.
@end table
+ at anchor{blackdetect}
@section blackdetect
Detect video intervals that are (almost) completely black. Can be
@@ -12518,6 +12520,7 @@ Select frame after every @code{step} frames.
Allowed values are positive integers higher than 0. Default value is @code{1}.
@end table
+ at anchor{freezedetect}
@section freezedetect
Detect frozen video.
@@ -25564,6 +25567,21 @@ missing.
That basically means that an input frame is selected if its pts is within the
interval set by the concat demuxer.
+ at item detected(kind)
+Evaluates the metadata added to frames by various detection filters.
+Returns -1 if the respective filter has detected what it was looking for,
+0 otherwise.
+
+Possible values for the @var{kind} parameter:
+ at table @option
+ at item SILENCE (audio only)
+Looks for metadata added by @ref{silencedetect}.
+ at item FREEZE (video only)
+Looks for metadata added by @ref{freezedetect}.
+ at item BLACK (video only)
+Looks for metadata added by @ref{blackdetect}.
+ at end table
+
@end table
The default value of the select expression is "1".
diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c
index f0468078e8..b1eba67876 100644
--- a/libavfilter/f_select.c
+++ b/libavfilter/f_select.c
@@ -86,6 +86,10 @@ static const char *const var_names[] = {
"concatdec_select", ///< frame is within the interval set by the concat demuxer
+ "SILENCE", ///< silencedetect detected silence for this frame
+ "FREEZE", ///< freezedetect detected frozen frames
+ "BLACK", ///< blackdetect detected black frames
+
NULL
};
@@ -138,14 +142,42 @@ enum var_name {
VAR_CONCATDEC_SELECT,
+ VAR_SILENCE,
+ VAR_FREEZE,
+ VAR_BLACK,
+
VAR_VARS_NB
};
+enum meta_name {
+ META_SILENCE,
+ META_FREEZE,
+ META_BLACK,
+
+ META_NAMES_NB
+};
+
+static const char *const func1_names[] = {
+ "detected", ///< function to eval metadata from various detection filters (silencedetect, ...)
+
+ NULL
+};
+
+static double detect_metadata(void *p, double kind);
+
+static double (*func1_funcs[])(void *, double) = {
+ detect_metadata,
+
+ NULL
+};
+
typedef struct SelectContext {
const AVClass *class;
char *expr_str;
AVExpr *expr;
double var_values[VAR_VARS_NB];
+ int meta_detected[META_NAMES_NB];
+ AVFrame *cur_frame; ///< current frame, for use in expression parser functions ONLY
int bitdepth;
int nb_planes;
ptrdiff_t width[4];
@@ -177,7 +209,7 @@ static av_cold int init(AVFilterContext *ctx)
int i, ret;
if ((ret = av_expr_parse(&select->expr, select->expr_str,
- var_names, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
+ var_names, func1_names, func1_funcs, NULL, NULL, 0, ctx)) < 0) {
av_log(ctx, AV_LOG_ERROR, "Error while parsing expression '%s'\n",
select->expr_str);
return ret;
@@ -267,6 +299,11 @@ static int config_input(AVFilterLink *inlink)
if (!select->sad)
return AVERROR(EINVAL);
}
+
+ select->var_values[VAR_SILENCE] = META_SILENCE;
+ select->var_values[VAR_FREEZE] = META_FREEZE;
+ select->var_values[VAR_BLACK] = META_BLACK;
+
return 0;
}
@@ -325,6 +362,40 @@ static double get_concatdec_select(AVFrame *frame, int64_t pts)
return NAN;
}
+static double detect_metadata(void *p, double kind)
+{
+ AVFilterContext *ctx = p;
+ SelectContext *select = ctx->priv;
+ AVDictionary *metadata = select->cur_frame->metadata;
+ int kind_i = (int)(kind + 0.5);
+ const char *start, *end;
+
+ switch(kind_i) {
+ case META_SILENCE:
+ start = "lavfi.silence_start";
+ end = "lavfi.silence_end";
+ break;
+ case META_FREEZE:
+ start = "lavfi.freezedetect.freeze_start";
+ end = "lavfi.freezedetect.freeze_end";
+ break;
+ case META_BLACK:
+ start = "lavfi.black_start";
+ end = "lavfi.black_end";
+ break;
+ default:
+ av_log(ctx, AV_LOG_WARNING, "Invalid metadata detection kind!\n");
+ return NAN;
+ }
+
+ if (av_dict_get(metadata, start, NULL, 0))
+ select->meta_detected[kind_i] = -1;
+ if (av_dict_get(metadata, end, NULL, 0))
+ select->meta_detected[kind_i] = 0;
+
+ return select->meta_detected[kind_i];
+}
+
static void select_frame(AVFilterContext *ctx, AVFrame *frame)
{
SelectContext *select = ctx->priv;
@@ -363,7 +434,9 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame)
break;
}
- select->select = res = av_expr_eval(select->expr, select->var_values, NULL);
+ select->cur_frame = frame;
+
+ select->select = res = av_expr_eval(select->expr, select->var_values, ctx);
av_log(inlink->dst, AV_LOG_DEBUG,
"n:%f pts:%f t:%f key:%d",
select->var_values[VAR_N],
@@ -371,6 +444,8 @@ static void select_frame(AVFilterContext *ctx, AVFrame *frame)
select->var_values[VAR_T],
frame->key_frame);
+ select->cur_frame = NULL;
+
switch (inlink->type) {
case AVMEDIA_TYPE_VIDEO:
av_log(inlink->dst, AV_LOG_DEBUG, " interlace_type:%c pict_type:%c scene:%f",
diff --git a/libavfilter/version.h b/libavfilter/version.h
index 5052681653..fbb81ef31c 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -31,7 +31,7 @@
#define LIBAVFILTER_VERSION_MAJOR 8
#define LIBAVFILTER_VERSION_MINOR 0
-#define LIBAVFILTER_VERSION_MICRO 102
+#define LIBAVFILTER_VERSION_MICRO 103
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
--
2.25.1
More information about the ffmpeg-devel
mailing list