00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00030 #include "avfilter.h"
00031 #include "internal.h"
00032 #include "video.h"
00033
00034 typedef struct {
00035 unsigned int bamount;
00036 unsigned int bthresh;
00037 unsigned int frame;
00038 unsigned int nblack;
00039 unsigned int last_keyframe;
00040 } BlackFrameContext;
00041
00042 static int query_formats(AVFilterContext *ctx)
00043 {
00044 static const enum PixelFormat pix_fmts[] = {
00045 PIX_FMT_YUV410P, PIX_FMT_YUV420P, PIX_FMT_GRAY8, PIX_FMT_NV12,
00046 PIX_FMT_NV21, PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV411P,
00047 PIX_FMT_NONE
00048 };
00049
00050 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
00051 return 0;
00052 }
00053
00054 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
00055 {
00056 BlackFrameContext *blackframe = ctx->priv;
00057
00058 blackframe->bamount = 98;
00059 blackframe->bthresh = 32;
00060 blackframe->nblack = 0;
00061 blackframe->frame = 0;
00062 blackframe->last_keyframe = 0;
00063
00064 if (args)
00065 sscanf(args, "%u:%u", &blackframe->bamount, &blackframe->bthresh);
00066
00067 av_log(ctx, AV_LOG_INFO, "bamount:%u bthresh:%u\n",
00068 blackframe->bamount, blackframe->bthresh);
00069
00070 if (blackframe->bamount > 100 || blackframe->bthresh > 255) {
00071 av_log(ctx, AV_LOG_ERROR, "Too big value for bamount (max is 100) or bthresh (max is 255)\n");
00072 return AVERROR(EINVAL);
00073 }
00074
00075 return 0;
00076 }
00077
00078 static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
00079 {
00080 AVFilterContext *ctx = inlink->dst;
00081 BlackFrameContext *blackframe = ctx->priv;
00082 AVFilterBufferRef *picref = inlink->cur_buf;
00083 int x, i;
00084 uint8_t *p = picref->data[0] + y * picref->linesize[0];
00085
00086 for (i = 0; i < h; i++) {
00087 for (x = 0; x < inlink->w; x++)
00088 blackframe->nblack += p[x] < blackframe->bthresh;
00089 p += picref->linesize[0];
00090 }
00091
00092 avfilter_draw_slice(ctx->outputs[0], y, h, slice_dir);
00093 }
00094
00095 static void end_frame(AVFilterLink *inlink)
00096 {
00097 AVFilterContext *ctx = inlink->dst;
00098 BlackFrameContext *blackframe = ctx->priv;
00099 AVFilterBufferRef *picref = inlink->cur_buf;
00100 int pblack = 0;
00101
00102 if (picref->video->key_frame)
00103 blackframe->last_keyframe = blackframe->frame;
00104
00105 pblack = blackframe->nblack * 100 / (inlink->w * inlink->h);
00106 if (pblack >= blackframe->bamount)
00107 av_log(ctx, AV_LOG_INFO, "frame:%u pblack:%u pos:%"PRId64" pts:%"PRId64" t:%f "
00108 "type:%c last_keyframe:%d\n",
00109 blackframe->frame, pblack, picref->pos, picref->pts,
00110 picref->pts == AV_NOPTS_VALUE ? -1 : picref->pts * av_q2d(inlink->time_base),
00111 av_get_picture_type_char(picref->video->pict_type), blackframe->last_keyframe);
00112
00113 blackframe->frame++;
00114 blackframe->nblack = 0;
00115 avfilter_unref_buffer(picref);
00116 avfilter_end_frame(inlink->dst->outputs[0]);
00117 }
00118
00119 AVFilter avfilter_vf_blackframe = {
00120 .name = "blackframe",
00121 .description = NULL_IF_CONFIG_SMALL("Detect frames that are (almost) black."),
00122
00123 .priv_size = sizeof(BlackFrameContext),
00124 .init = init,
00125
00126 .query_formats = query_formats,
00127
00128 .inputs = (const AVFilterPad[]) {{ .name = "default",
00129 .type = AVMEDIA_TYPE_VIDEO,
00130 .draw_slice = draw_slice,
00131 .get_video_buffer = ff_null_get_video_buffer,
00132 .start_frame = ff_null_start_frame_keep_ref,
00133 .end_frame = end_frame, },
00134 { .name = NULL}},
00135
00136 .outputs = (const AVFilterPad[]) {{ .name = "default",
00137 .type = AVMEDIA_TYPE_VIDEO },
00138 { .name = NULL}},
00139 };