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