2010-09-27 00:36:05 +03:00
/*
2010-11-28 12:22:58 +02:00
* Copyright ( c ) 2010 Stefano Sabatini
* Copyright ( c ) 2006 Ivo van Poorten
* Copyright ( c ) 2006 Julian Hall
* Copyright ( c ) 2002 - 2003 Brian J . Murrell
2010-09-27 00:36:05 +03:00
*
* This file is part of FFmpeg .
*
* FFmpeg 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 .
*
* FFmpeg 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 FFmpeg ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
/**
* @ file
* Search for black frames to detect scene transitions .
* Ported from MPlayer libmpcodecs / vf_blackframe . c .
*/
2012-08-06 16:49:32 +03:00
# include <stdio.h>
# include <inttypes.h>
# include "libavutil/internal.h"
2013-03-16 02:07:15 +03:00
# include "libavutil/opt.h"
2010-09-27 00:36:05 +03:00
# include "avfilter.h"
2012-04-25 01:25:18 +03:00
# include "internal.h"
2012-05-30 11:12:55 +03:00
# include "formats.h"
2012-06-12 21:12:42 +03:00
# include "internal.h"
2012-05-19 11:37:56 +03:00
# include "video.h"
2010-09-27 00:36:05 +03:00
typedef struct {
2013-03-16 02:07:15 +03:00
const AVClass * class ;
2010-09-27 00:36:05 +03:00
unsigned int bamount ; ///< black amount
unsigned int bthresh ; ///< black threshold
unsigned int frame ; ///< frame number
unsigned int nblack ; ///< number of black pixels counted so far
2011-07-17 18:05:14 +03:00
unsigned int last_keyframe ; ///< frame number of the last received key-frame
2010-09-27 00:36:05 +03:00
} BlackFrameContext ;
2013-03-16 02:07:15 +03:00
# define OFFSET(x) offsetof(BlackFrameContext, x)
# define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption blackframe_options [ ] = {
{ " amount " , " set least percentual amount of pixels below the black threshold enabling black detection " , OFFSET ( bamount ) , AV_OPT_TYPE_INT , { . i64 = 98 } , 0 , 100 , FLAGS } ,
{ " thresh " , " set threshold below which a pixel value is considered black " , OFFSET ( bthresh ) , AV_OPT_TYPE_INT , { . i64 = 32 } , 0 , 255 , FLAGS } ,
{ NULL }
} ;
AVFILTER_DEFINE_CLASS ( blackframe ) ;
2010-09-27 00:36:05 +03:00
static int query_formats ( AVFilterContext * ctx )
{
2012-10-06 13:10:34 +03:00
static const enum AVPixelFormat pix_fmts [ ] = {
AV_PIX_FMT_YUV410P , AV_PIX_FMT_YUV420P , AV_PIX_FMT_GRAY8 , AV_PIX_FMT_NV12 ,
AV_PIX_FMT_NV21 , AV_PIX_FMT_YUV444P , AV_PIX_FMT_YUV422P , AV_PIX_FMT_YUV411P ,
AV_PIX_FMT_NONE
2010-09-27 00:36:05 +03:00
} ;
2012-05-30 11:12:55 +03:00
ff_set_common_formats ( ctx , ff_make_format_list ( pix_fmts ) ) ;
2010-09-27 00:36:05 +03:00
return 0 ;
}
2012-06-21 08:55:56 +03:00
static av_cold int init ( AVFilterContext * ctx , const char * args )
2010-09-27 00:36:05 +03:00
{
BlackFrameContext * blackframe = ctx - > priv ;
2012-06-25 07:31:38 +03:00
av_log ( ctx , AV_LOG_VERBOSE , " bamount:%u bthresh:%u \n " ,
2010-09-27 00:36:05 +03:00
blackframe - > bamount , blackframe - > bthresh ) ;
return 0 ;
}
2012-11-28 10:41:07 +03:00
static int filter_frame ( AVFilterLink * inlink , AVFrame * frame )
2010-09-27 00:36:05 +03:00
{
AVFilterContext * ctx = inlink - > dst ;
BlackFrameContext * blackframe = ctx - > priv ;
int x , i ;
2012-11-29 02:32:08 +03:00
int pblack = 0 ;
uint8_t * p = frame - > data [ 0 ] ;
2010-09-27 00:36:05 +03:00
2012-11-28 10:41:07 +03:00
for ( i = 0 ; i < frame - > height ; i + + ) {
2010-09-27 00:36:05 +03:00
for ( x = 0 ; x < inlink - > w ; x + + )
blackframe - > nblack + = p [ x ] < blackframe - > bthresh ;
2012-11-29 02:32:08 +03:00
p + = frame - > linesize [ 0 ] ;
2010-09-27 00:36:05 +03:00
}
2013-03-10 03:30:30 +03:00
if ( frame - > key_frame )
2011-07-17 18:05:14 +03:00
blackframe - > last_keyframe = blackframe - > frame ;
2010-09-27 00:36:05 +03:00
pblack = blackframe - > nblack * 100 / ( inlink - > w * inlink - > h ) ;
if ( pblack > = blackframe - > bamount )
2013-03-10 03:30:30 +03:00
av_log ( ctx , AV_LOG_INFO , " frame:%u pblack:%u pts:% " PRId64 " t:%f "
2011-07-17 18:05:14 +03:00
" type:%c last_keyframe:%d \n " ,
2012-11-28 10:41:07 +03:00
blackframe - > frame , pblack , frame - > pts ,
2012-11-29 02:32:08 +03:00
frame - > pts = = AV_NOPTS_VALUE ? - 1 : frame - > pts * av_q2d ( inlink - > time_base ) ,
2013-03-10 03:30:30 +03:00
av_get_picture_type_char ( frame - > pict_type ) , blackframe - > last_keyframe ) ;
2010-09-27 00:36:05 +03:00
blackframe - > frame + + ;
blackframe - > nblack = 0 ;
2012-11-29 02:32:08 +03:00
return ff_filter_frame ( inlink - > dst - > outputs [ 0 ] , frame ) ;
2010-09-27 00:36:05 +03:00
}
2012-07-24 16:14:01 +03:00
static const AVFilterPad avfilter_vf_blackframe_inputs [ ] = {
{
. name = " default " ,
. type = AVMEDIA_TYPE_VIDEO ,
. get_video_buffer = ff_null_get_video_buffer ,
2012-11-29 02:32:08 +03:00
. filter_frame = filter_frame ,
2012-07-24 16:14:01 +03:00
} ,
{ NULL }
} ;
static const AVFilterPad avfilter_vf_blackframe_outputs [ ] = {
{
. name = " default " ,
. type = AVMEDIA_TYPE_VIDEO
} ,
{ NULL }
} ;
2013-03-24 10:53:38 +03:00
static const char * const shorthand [ ] = { " amount " , " thresh " , NULL } ;
2010-09-27 00:36:05 +03:00
AVFilter avfilter_vf_blackframe = {
. name = " blackframe " ,
. description = NULL_IF_CONFIG_SMALL ( " Detect frames that are (almost) black. " ) ,
. priv_size = sizeof ( BlackFrameContext ) ,
. init = init ,
. query_formats = query_formats ,
2012-07-24 16:14:01 +03:00
. inputs = avfilter_vf_blackframe_inputs ,
. outputs = avfilter_vf_blackframe_outputs ,
2013-03-16 02:07:15 +03:00
. priv_class = & blackframe_class ,
2013-03-24 10:53:38 +03:00
. shorthand = shorthand ,
2010-09-27 00:36:05 +03:00
} ;