int64_t black_min_duration; ///< minimum duration of detected black, expressed in timebase units
int64_t black_start; ///< pts start time of the first black picture
int64_t black_end; ///< pts end time of the last black picture
+ int64_t last_picref_pts; ///< pts of the last input picture
int black_started;
double picture_black_ratio_th;
{ NULL },
};
-static const AVClass blackdetect_class = {
- .class_name = "blackdetect",
- .item_name = av_default_item_name,
- .option = blackdetect_options,
- .version = LIBAVUTIL_VERSION_INT,
- .category = AV_CLASS_CATEGORY_FILTER,
-};
+AVFILTER_DEFINE_CLASS(blackdetect);
#define YUVJ_FORMATS \
PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUVJ440P
return 0;
}
-static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
+static av_cold int init(AVFilterContext *ctx, const char *args)
{
int ret;
BlackDetectContext *blackdetect = ctx->priv;
blackdetect->class = &blackdetect_class;
av_opt_set_defaults(blackdetect);
- if ((ret = av_set_options_string(blackdetect, args, "=", ":")) < 0) {
- av_log(ctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args);
+ if ((ret = av_set_options_string(blackdetect, args, "=", ":")) < 0)
return ret;
- }
return 0;
}
blackdetect->pixel_black_th * 255 :
16 + blackdetect->pixel_black_th * (235 - 16);
- av_log(blackdetect, AV_LOG_INFO,
+ av_log(blackdetect, AV_LOG_VERBOSE,
"black_min_duration:%s pixel_black_th:%f pixel_black_th_i:%d picture_black_ratio_th:%f\n",
av_ts2timestr(blackdetect->black_min_duration, &inlink->time_base),
blackdetect->pixel_black_th, blackdetect->pixel_black_th_i,
return 0;
}
-static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
+static void check_black_end(AVFilterContext *ctx)
+{
+ BlackDetectContext *blackdetect = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+
+ if ((blackdetect->black_end - blackdetect->black_start) >= blackdetect->black_min_duration) {
+ av_log(blackdetect, AV_LOG_INFO,
+ "black_start:%s black_end:%s black_duration:%s\n",
+ av_ts2timestr(blackdetect->black_start, &inlink->time_base),
+ av_ts2timestr(blackdetect->black_end, &inlink->time_base),
+ av_ts2timestr(blackdetect->black_end - blackdetect->black_start, &inlink->time_base));
+ }
+}
+
+static int request_frame(AVFilterLink *outlink)
+{
+ AVFilterContext *ctx = outlink->src;
+ BlackDetectContext *blackdetect = ctx->priv;
+ AVFilterLink *inlink = ctx->inputs[0];
+ int ret = ff_request_frame(inlink);
+
+ if (ret == AVERROR_EOF && blackdetect->black_started) {
+ // FIXME: black_end should be set to last_picref_pts + last_picref_duration
+ blackdetect->black_end = blackdetect->last_picref_pts;
+ check_black_end(ctx);
+ }
+ return ret;
+}
+
+static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
{
AVFilterContext *ctx = inlink->dst;
BlackDetectContext *blackdetect = ctx->priv;
p += picref->linesize[0];
}
- ff_draw_slice(ctx->outputs[0], y, h, slice_dir);
+ return ff_draw_slice(ctx->outputs[0], y, h, slice_dir);
}
-static void end_frame(AVFilterLink *inlink)
+static int end_frame(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
BlackDetectContext *blackdetect = ctx->priv;
av_log(ctx, AV_LOG_DEBUG,
"frame:%u picture_black_ratio:%f pos:%"PRId64" pts:%s t:%s type:%c\n",
blackdetect->frame_count, picture_black_ratio,
- picref->pos, av_ts2str(picref->pts),
- av_ts2timestr(blackdetect->black_start, &inlink->time_base),
+ picref->pos, av_ts2str(picref->pts), av_ts2timestr(picref->pts, &inlink->time_base),
av_get_picture_type_char(picref->video->pict_type));
if (picture_black_ratio >= blackdetect->picture_black_ratio_th) {
/* black ends here */
blackdetect->black_started = 0;
blackdetect->black_end = picref->pts;
-
- if ((blackdetect->black_end - blackdetect->black_start) >= blackdetect->black_min_duration) {
- av_log(blackdetect, AV_LOG_INFO,
- "black_start:%s black_end:%s black_duration:%s\n",
- av_ts2timestr(blackdetect->black_start, &inlink->time_base),
- av_ts2timestr(blackdetect->black_end, &inlink->time_base),
- av_ts2timestr(blackdetect->black_end - blackdetect->black_start, &inlink->time_base));
- }
+ check_black_end(ctx);
}
+ blackdetect->last_picref_pts = picref->pts;
blackdetect->frame_count++;
blackdetect->nb_black_pixels = 0;
- avfilter_unref_buffer(picref);
- ff_end_frame(inlink->dst->outputs[0]);
+ return ff_end_frame(inlink->dst->outputs[0]);
}
AVFilter avfilter_vf_blackdetect = {
.config_props = config_input,
.draw_slice = draw_slice,
.get_video_buffer = ff_null_get_video_buffer,
- .start_frame = ff_null_start_frame_keep_ref,
+ .start_frame = ff_null_start_frame,
.end_frame = end_frame, },
{ .name = NULL }
},
.outputs = (const AVFilterPad[]) {
{ .name = "default",
- .type = AVMEDIA_TYPE_VIDEO },
+ .type = AVMEDIA_TYPE_VIDEO,
+ .request_frame = request_frame, },
{ .name = NULL }
},
};