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