Hi: There are HDTV channel in the broadcast here, but since lack of HDTV program, the provider will transcode SDTV program to HDTV program, the result black margin around the original SDTV video content. So this filter is used for detect it.
For the patches: Current ffplay had not put video key_frame and pict_type to refpic, so the first one is to add this info, for the blackmargin filter will only check if it's key frame; The second patch is the filter itself. Best Regards! -- wucan
From 81281bc59003a779442c3eebc71bda44b3b9b0e2 Mon Sep 17 00:00:00 2001 From: Can Wu <[email protected]> Date: Tue, 17 May 2011 11:30:19 +0800 Subject: ffplay: fillin more video props for filter Maybe our video filter will use it... --- ffplay.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/ffplay.c b/ffplay.c index a5dc358..d31d56a 100644 --- a/ffplay.c +++ b/ffplay.c @@ -1706,6 +1706,10 @@ static int input_request_frame(AVFilterLink *link) picref->pts = pts; picref->pos = pkt.pos; picref->video->pixel_aspect = priv->is->video_st->codec->sample_aspect_ratio; + picref->video->interlaced = priv->frame->interlaced_frame; + picref->video->top_field_first = priv->frame->top_field_first; + picref->video->pict_type = priv->frame->pict_type; + picref->video->key_frame = priv->frame->key_frame; avfilter_start_frame(link, picref); avfilter_draw_slice(link, 0, link->h, 1); avfilter_end_frame(link); -- 1.7.3.2.168.gd6b63
From 256eaff7d1df6cdd8a6df21ea836242e5ebc7194 Mon Sep 17 00:00:00 2001 From: Can Wu <[email protected]> Date: Tue, 17 May 2011 11:38:25 +0800 Subject: libavfilter: add blackmargin filter Used to detect black margin around video content. --- libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/vf_blackmargin.c | 196 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+), 0 deletions(-) create mode 100644 libavfilter/vf_blackmargin.c diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 2ed1f93..14da707 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -22,6 +22,7 @@ OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o OBJS-$(CONFIG_BLACKFRAME_FILTER) += vf_blackframe.o +OBJS-$(CONFIG_BLACKMARGIN_FILTER) += vf_blackmargin.o OBJS-$(CONFIG_COPY_FILTER) += vf_copy.o OBJS-$(CONFIG_CROP_FILTER) += vf_crop.o OBJS-$(CONFIG_CROPDETECT_FILTER) += vf_cropdetect.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index e29b4f9..bdc3dba 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -41,6 +41,7 @@ void avfilter_register_all(void) REGISTER_FILTER (ANULLSINK, anullsink, asink); REGISTER_FILTER (BLACKFRAME, blackframe, vf); + REGISTER_FILTER (BLACKMARGIN, blackmargin, vf); REGISTER_FILTER (COPY, copy, vf); REGISTER_FILTER (CROP, crop, vf); REGISTER_FILTER (CROPDETECT, cropdetect, vf); diff --git a/libavfilter/vf_blackmargin.c b/libavfilter/vf_blackmargin.c new file mode 100644 index 0000000..2e48795 --- /dev/null +++ b/libavfilter/vf_blackmargin.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2011 Can Wu + * Copyright (c) 2010 Stefano Sabatini + * Copyright (c) 2006 Ivo van Poorten + * Copyright (c) 2006 Julian Hall + * Copyright (c) 2002-2003 Brian J. Murrell + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with Libav; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** + * @file + * Search for black margin around video content + * based on vf_blackframe.c + */ + +#include "avfilter.h" + +typedef struct { + unsigned int bamount; ///< black amount + unsigned int bthresh; ///< black threshold + unsigned int frame; ///< frame number + + unsigned short margin_top; + unsigned short margin_bottom; + unsigned short margin_left; + unsigned short margin_right; +} BlackMarginContext; + +static int query_formats(AVFilterContext *ctx) +{ + static const enum PixelFormat pix_fmts[] = { + PIX_FMT_YUV410P, PIX_FMT_YUV420P, PIX_FMT_GRAY8, PIX_FMT_NV12, + PIX_FMT_NV21, PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV411P, + PIX_FMT_NONE + }; + + avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts)); + return 0; +} + +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) +{ + BlackMarginContext *blackmargin = ctx->priv; + + blackmargin->bamount = 98; + blackmargin->bthresh = 32; + blackmargin->frame = 0; + + if (args) + sscanf(args, "%u:%u", &blackmargin->bamount, &blackmargin->bthresh); + + av_log(ctx, AV_LOG_INFO, "bamount:%u bthresh:%u\n", + blackmargin->bamount, blackmargin->bthresh); + + if (blackmargin->bamount > 100 || blackmargin->bthresh > 255) { + av_log(ctx, AV_LOG_ERROR, "Too big value for bamount (max is 100) or bthresh (max is 255)\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static void end_frame(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + BlackMarginContext *blackmargin = ctx->priv; + AVFilterBufferRef *picref = inlink->cur_buf; + int pblack; + int x, y; + uint8_t *p; + unsigned int nblack; + int margin_top, margin_bottom, margin_left, margin_right; + + /* only check on key frame */ + if (!picref->video->key_frame) + return; + + /* up */ + p = picref->data[0]; + for (y = 0; y < (inlink->h >> 2); y++) { + p += picref->linesize[0]; + nblack = 0; + for (x = 0; x < inlink->w; x++) { + nblack += p[x] < blackmargin->bthresh; + } + pblack = nblack * 100 / inlink->w; + if (pblack < blackmargin->bamount) { + break; + } + } + margin_top = y; + + /* down */ + p = picref->data[0] + picref->linesize[0] * inlink->h; + for (y = inlink->h; y > (inlink->h >> 2); y--) { + p -= picref->linesize[0]; + nblack = 0; + for (x = 0; x < inlink->w; x++) { + nblack += p[x] < blackmargin->bthresh; + } + pblack = nblack * 100 / inlink->w; + if (pblack < blackmargin->bamount) { + break; + } + } + margin_bottom = (inlink->h - y); + + if (margin_top + margin_bottom >= inlink->h) { + margin_left = 0; + margin_right = 0; + av_log(ctx, AV_LOG_WARNING, "full black frame!\n"); + goto done; + } + + /* left */ + p = picref->data[0] + picref->linesize[0] * margin_top; + for (x = 0; x < (inlink->w >> 2); x++) { + p++; + nblack = 0; + for (y = margin_top; y < (inlink->h - margin_bottom); y++) { + nblack += p[x + y * picref->linesize[0]] < blackmargin->bthresh; + } + pblack = nblack * 100 / (inlink->h - margin_top - margin_bottom); + if (pblack < blackmargin->bamount) { + break; + } + } + margin_left = x; + + /* right */ + p = picref->data[0] + picref->linesize[0] * margin_top; + for (x = inlink->w; x > (inlink->w >> 2); x--) { + p--; + nblack = 0; + for (y = margin_top; y < (inlink->h - margin_bottom); y++) { + nblack += p[x + y * picref->linesize[0]] < blackmargin->bthresh; + } + pblack = nblack * 100 / (inlink->h - margin_top - margin_bottom); + if (pblack < blackmargin->bamount) { + break; + } + } + margin_right = inlink->w - x; + +done: + av_log(ctx, AV_LOG_INFO, "frame:%u pos:%"PRId64" pts:%"PRId64" t:%f" + " %d %d %d %d\n", + blackmargin->frame, picref->pos, picref->pts, + picref->pts == AV_NOPTS_VALUE ? + -1 : picref->pts * av_q2d(inlink->time_base), + margin_top, margin_bottom, margin_left, margin_right); + + blackmargin->margin_top = margin_top; + blackmargin->margin_bottom = margin_bottom; + blackmargin->margin_left = margin_left; + blackmargin->margin_right = margin_right; + + blackmargin->frame++; + avfilter_end_frame(inlink->dst->outputs[0]); +} + +AVFilter avfilter_vf_blackmargin = { + .name = "blackmargin", + .description = NULL_IF_CONFIG_SMALL("Detect black around video content."), + + .priv_size = sizeof(BlackMarginContext), + .init = init, + + .query_formats = query_formats, + + .inputs = (AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .get_video_buffer = avfilter_null_get_video_buffer, + .start_frame = avfilter_null_start_frame, + .end_frame = end_frame, }, + { .name = NULL}}, + + .outputs = (AVFilterPad[]) {{ .name = "default", + .type = AVMEDIA_TYPE_VIDEO }, + { .name = NULL}}, +}; -- 1.7.3.2.168.gd6b63
_______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
