X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Fffmpeg%2Fvideo_filter.c;h=ba9f99e387a52d77b76b0e676b242428b8dac5af;hb=8c7506a011174bcb33ec74ae0091c01c51dee574;hp=a83689c7c89219dd07c3d78077f6584d5dd21864;hpb=dc7674b5895d6a59b6df6ca6f5f1a4f8a9167d3a;p=vlc diff --git a/modules/codec/ffmpeg/video_filter.c b/modules/codec/ffmpeg/video_filter.c index a83689c7c8..ba9f99e387 100644 --- a/modules/codec/ffmpeg/video_filter.c +++ b/modules/codec/ffmpeg/video_filter.c @@ -2,7 +2,7 @@ * video filter: video filter doing chroma conversion and resizing * using the ffmpeg library ***************************************************************************** - * Copyright (C) 1999-2001 VideoLAN + * Copyright (C) 1999-2001 the VideoLAN team * $Id$ * * Authors: Gildas Bazin @@ -19,7 +19,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -38,6 +38,8 @@ #include "ffmpeg.h" + +#if !defined(HAVE_FFMPEG_SWSCALE_H) && !defined(HAVE_LIBSWSCALE_TREE) void E_(InitLibavcodec) ( vlc_object_t *p_object ); static int CheckInit( filter_t *p_filter ); static picture_t *Process( filter_t *p_filter, picture_t *p_pic ); @@ -50,6 +52,8 @@ struct filter_sys_t { vlc_bool_t b_resize; vlc_bool_t b_convert; + vlc_bool_t b_resize_first; + vlc_bool_t b_enable_croppadd; es_format_t fmt_in; int i_src_ffmpeg_chroma; @@ -60,10 +64,11 @@ struct filter_sys_t ImgReSampleContext *p_rsc; }; + /***************************************************************************** - * OpenFilter: probe the filter and return score + * OpenFilterEx: common code to OpenFilter and OpenCropPadd *****************************************************************************/ -int E_(OpenFilter)( vlc_object_t *p_this ) +static int OpenFilterEx( vlc_object_t *p_this, vlc_bool_t b_enable_croppadd ) { filter_t *p_filter = (filter_t*)p_this; filter_sys_t *p_sys; @@ -79,6 +84,20 @@ int E_(OpenFilter)( vlc_object_t *p_this ) b_resize = p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width || p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height; + + if ( b_enable_croppadd ) + { + b_resize = b_resize || + p_filter->fmt_in.video.i_visible_width != p_filter->fmt_in.video.i_width || + p_filter->fmt_in.video.i_visible_height != p_filter->fmt_in.video.i_height || + p_filter->fmt_in.video.i_x_offset != 0 || + p_filter->fmt_in.video.i_y_offset != 0 || + p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width || + p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height || + p_filter->fmt_out.video.i_x_offset != 0 || + p_filter->fmt_out.video.i_y_offset != 0; + } + b_convert = p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma; @@ -98,7 +117,7 @@ int E_(OpenFilter)( vlc_object_t *p_this ) /* Misc init */ p_sys->p_rsc = NULL; - p_sys->b_convert = b_convert; + p_sys->b_enable_croppadd = b_enable_croppadd; p_sys->i_src_ffmpeg_chroma = E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ); p_sys->i_dst_ffmpeg_chroma = @@ -107,16 +126,17 @@ int E_(OpenFilter)( vlc_object_t *p_this ) es_format_Init( &p_sys->fmt_in, 0, 0 ); es_format_Init( &p_sys->fmt_out, 0, 0 ); + /* Dummy alloc, will be reallocated in CheckInit */ + avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma, + p_filter->fmt_out.video.i_width, + p_filter->fmt_out.video.i_height ); + if( CheckInit( p_filter ) != VLC_SUCCESS ) { free( p_sys ); return VLC_EGENERIC; } - avpicture_alloc( &p_sys->tmp_pic, p_sys->i_dst_ffmpeg_chroma, - p_filter->fmt_in.video.i_width, - p_filter->fmt_in.video.i_height ); - msg_Dbg( p_filter, "input: %ix%i %4.4s -> %ix%i %4.4s", p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height, (char *)&p_filter->fmt_in.video.i_chroma, @@ -129,6 +149,23 @@ int E_(OpenFilter)( vlc_object_t *p_this ) return VLC_SUCCESS; } +/***************************************************************************** + * OpenFilter: probe the filter and return score + *****************************************************************************/ +int E_(OpenFilter)( vlc_object_t *p_this ) +{ + return OpenFilterEx( p_this, VLC_FALSE ); +} + +/***************************************************************************** + * OpenCropPadd: probe the filter and return score + *****************************************************************************/ +int E_(OpenCropPadd)( vlc_object_t *p_this ) +{ + return OpenFilterEx( p_this, VLC_TRUE ); +} + + /***************************************************************************** * CloseFilter: clean up the filter *****************************************************************************/ @@ -150,25 +187,123 @@ void E_(CloseFilter)( vlc_object_t *p_this ) static int CheckInit( filter_t *p_filter ) { filter_sys_t *p_sys = p_filter->p_sys; - - if( p_filter->fmt_in.video.i_width != p_sys->fmt_in.video.i_width || + vlc_bool_t b_change; + int i_croptop=0; + int i_cropbottom=0; + int i_cropleft=0; + int i_cropright=0; + int i_paddtop=0; + int i_paddbottom=0; + int i_paddleft=0; + int i_paddright=0; + + + b_change= p_filter->fmt_in.video.i_width != p_sys->fmt_in.video.i_width || p_filter->fmt_in.video.i_height != p_sys->fmt_in.video.i_height || p_filter->fmt_out.video.i_width != p_sys->fmt_out.video.i_width || - p_filter->fmt_out.video.i_height != p_sys->fmt_out.video.i_height ) + p_filter->fmt_out.video.i_height != p_sys->fmt_out.video.i_height; + + if ( p_sys->b_enable_croppadd ) + { + b_change = b_change || + p_filter->fmt_in.video.i_y_offset != p_sys->fmt_in.video.i_y_offset || + p_filter->fmt_in.video.i_x_offset != p_sys->fmt_in.video.i_x_offset || + p_filter->fmt_in.video.i_visible_width != p_sys->fmt_in.video.i_visible_width || + p_filter->fmt_in.video.i_visible_height != p_sys->fmt_in.video.i_visible_height || + p_filter->fmt_out.video.i_y_offset != p_sys->fmt_out.video.i_y_offset || + p_filter->fmt_out.video.i_x_offset != p_sys->fmt_out.video.i_x_offset || + p_filter->fmt_out.video.i_visible_width != p_sys->fmt_out.video.i_visible_width || + p_filter->fmt_out.video.i_visible_height != p_sys->fmt_out.video.i_visible_height; + } + + if ( b_change ) { if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc ); p_sys->p_rsc = 0; + p_sys->b_convert = + p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma; + p_sys->b_resize = p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width || p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height; + p_sys->b_resize_first = + p_filter->fmt_in.video.i_width * p_filter->fmt_in.video.i_height > + p_filter->fmt_out.video.i_width * p_filter->fmt_out.video.i_height; + + if( p_sys->b_resize && + p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P && + p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P && + p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P && + p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P ) + { + msg_Err( p_filter, "img_resample_init only deals with I420" ); + return VLC_EGENERIC; + } + else if( p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P && + p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P ) + { + p_sys->b_resize_first = VLC_FALSE; + } + else if( p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P && + p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P ) + { + p_sys->b_resize_first = VLC_TRUE; + } + + if ( p_sys->b_enable_croppadd ) + { + p_sys->b_resize = p_sys->b_resize || + p_filter->fmt_in.video.i_visible_width != p_filter->fmt_in.video.i_width || + p_filter->fmt_in.video.i_visible_height != p_filter->fmt_in.video.i_height || + p_filter->fmt_in.video.i_x_offset != 0 || + p_filter->fmt_in.video.i_y_offset != 0 || + p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width || + p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height || + p_filter->fmt_out.video.i_x_offset != 0 || + p_filter->fmt_out.video.i_y_offset != 0; + } + if( p_sys->b_resize ) { - p_sys->p_rsc = img_resample_init( p_filter->fmt_out.video.i_width, + if ( p_sys->b_enable_croppadd ) + { + i_croptop=p_filter->fmt_in.video.i_y_offset; + i_cropbottom=p_filter->fmt_in.video.i_height + - p_filter->fmt_in.video.i_visible_height + - p_filter->fmt_in.video.i_y_offset; + i_cropleft=p_filter->fmt_in.video.i_x_offset; + i_cropright=p_filter->fmt_in.video.i_width + - p_filter->fmt_in.video.i_visible_width + - p_filter->fmt_in.video.i_x_offset; + + + i_paddtop=p_filter->fmt_out.video.i_y_offset; + i_paddbottom=p_filter->fmt_out.video.i_height + - p_filter->fmt_out.video.i_visible_height + - p_filter->fmt_out.video.i_y_offset; + i_paddleft=p_filter->fmt_out.video.i_x_offset; + i_paddright=p_filter->fmt_out.video.i_width + - p_filter->fmt_out.video.i_visible_width + - p_filter->fmt_out.video.i_x_offset; + } + + p_sys->p_rsc = img_resample_full_init( + p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height, p_filter->fmt_in.video.i_width, - p_filter->fmt_in.video.i_height ); + p_filter->fmt_in.video.i_height, + i_croptop,i_cropbottom, + i_cropleft,i_cropright, + i_paddtop,i_paddbottom, + i_paddleft,i_paddright ); + + msg_Dbg( p_filter, "input: %ix%i -> %ix%i", + p_filter->fmt_out.video.i_width, + p_filter->fmt_out.video.i_height, + p_filter->fmt_in.video.i_width, + p_filter->fmt_in.video.i_height); if( !p_sys->p_rsc ) { @@ -177,6 +312,23 @@ static int CheckInit( filter_t *p_filter ) } } + avpicture_free( &p_sys->tmp_pic ); + + if( p_sys->b_resize_first ) + { + /* Resizing then conversion */ + avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma, + p_filter->fmt_out.video.i_width, + p_filter->fmt_out.video.i_height ); + } + else + { + /* Conversion then resizing */ + avpicture_alloc( &p_sys->tmp_pic, p_sys->i_dst_ffmpeg_chroma, + p_filter->fmt_in.video.i_width, + p_filter->fmt_in.video.i_height ); + } + p_sys->fmt_in = p_filter->fmt_in; p_sys->fmt_out = p_filter->fmt_out; } @@ -184,15 +336,69 @@ static int CheckInit( filter_t *p_filter ) return VLC_SUCCESS; } +/* fill padd code from ffmpeg */ +static int padcolor[3] = { 16, 128, 128 }; + +/* Expects img to be yuv420 */ +static void fill_pad_region( AVPicture* img, int height, int width, + int padtop, int padbottom, int padleft, int padright, int *color ) +{ + int i, y, shift; + uint8_t *optr; + + for ( i = 0; i < 3; i++ ) + { + shift = ( i == 0 ) ? 0 : 1; + + if ( padtop || padleft ) + { + memset( img->data[i], color[i], ( ( ( img->linesize[i] * padtop ) + + padleft ) >> shift) ); + } + + if ( padleft || padright ) + { + optr = img->data[i] + ( img->linesize[i] * ( padtop >> shift ) ) + + ( img->linesize[i] - ( padright >> shift ) ); + + for ( y = 0; y < ( ( height - ( padtop + padbottom ) ) >> shift ); y++ ) + { + memset( optr, color[i], ( padleft + padright ) >> shift ); + optr += img->linesize[i]; + } + } + + if (padbottom) + { + optr = img->data[i] + ( img->linesize[i] * ( ( height - padbottom ) >> shift ) ); + memset( optr, color[i], ( ( img->linesize[i] * padbottom ) >> shift ) ); + } + } +} + +/* Workaround, because old libavcodec doesnt know how to padd */ +static void img_resample_padd( ImgReSampleContext *s, AVPicture *output, + const AVPicture *input, int padtop, int padleft ) +{ + AVPicture nopadd_pic = *output; + + /* shift out top and left padding for old ffmpeg */ + nopadd_pic.data[0] += ( nopadd_pic.linesize[0] * padtop + padleft ); + nopadd_pic.data[1] += ( nopadd_pic.linesize[1] * padtop + padleft ) >> 1; + nopadd_pic.data[2] += ( nopadd_pic.linesize[2] * padtop + padleft ) >> 1; + img_resample( s, &nopadd_pic, input ); +} + + /***************************************************************************** * Do the processing here *****************************************************************************/ static picture_t *Process( filter_t *p_filter, picture_t *p_pic ) { filter_sys_t *p_sys = p_filter->p_sys; - AVPicture src_pic, dest_pic, inter_pic; + AVPicture src_pic, dest_pic; + AVPicture *p_src, *p_dst; picture_t *p_pic_dst; - vlc_bool_t b_resize = p_sys->b_resize; int i; /* Check if format properties changed */ @@ -238,32 +444,85 @@ static picture_t *Process( filter_t *p_filter, picture_t *p_pic ) if( p_filter->fmt_in.video.i_bmask == 0x00ff0000 ) p_sys->i_src_ffmpeg_chroma = PIX_FMT_BGR24; -#if 0 - if( p_sys->b_resize && - p_filter->fmt_in.video.i_width * p_filter->fmt_in.video.i_height > - p_filter->fmt_out.video.i_width * p_filter->fmt_out.video.i_height ) + p_src = &src_pic; + + if( p_sys->b_resize && p_sys->p_rsc ) { - img_resample( p_sys->p_rsc, &dest_pic, &p_sys->tmp_pic ); - b_resize = 0; + p_dst = &dest_pic; + if( p_sys->b_resize_first ) + { + if( p_sys->b_convert ) p_dst = &p_sys->tmp_pic; + + img_resample( p_sys->p_rsc, p_dst, p_src ); + + if (p_sys->b_enable_croppadd) + { + if (p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width || + p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height || + p_filter->fmt_out.video.i_x_offset != 0 || + p_filter->fmt_out.video.i_y_offset != 0) + { + fill_pad_region(p_dst, p_filter->fmt_out.video.i_height, + p_filter->fmt_out.video.i_width, + p_filter->fmt_out.video.i_y_offset, + p_filter->fmt_out.video.i_height + - p_filter->fmt_out.video.i_visible_height + - p_filter->fmt_out.video.i_y_offset, + p_filter->fmt_out.video.i_x_offset, + p_filter->fmt_out.video.i_width + - p_filter->fmt_out.video.i_visible_width + - p_filter->fmt_out.video.i_x_offset, + padcolor); + } + } + + p_src = p_dst; + } } -#endif if( p_sys->b_convert ) { - if( p_sys->b_resize ) inter_pic = p_sys->tmp_pic; - else inter_pic = dest_pic; + video_format_t *p_fmt = &p_filter->fmt_out.video; + p_dst = &dest_pic; + if( p_sys->b_resize && !p_sys->b_resize_first ) + { + p_dst = &p_sys->tmp_pic; + p_fmt = &p_filter->fmt_in.video; + } - img_convert( &inter_pic, p_sys->i_dst_ffmpeg_chroma, - &src_pic, p_sys->i_src_ffmpeg_chroma, - p_filter->fmt_in.video.i_width, - p_filter->fmt_in.video.i_height ); + img_convert( p_dst, p_sys->i_dst_ffmpeg_chroma, + p_src, p_sys->i_src_ffmpeg_chroma, + p_fmt->i_width, p_fmt->i_height ); - src_pic = inter_pic; + p_src = p_dst; } - if( p_sys->b_resize && p_sys->p_rsc ) + if( p_sys->b_resize && !p_sys->b_resize_first && p_sys->p_rsc ) { - img_resample( p_sys->p_rsc, &dest_pic, &src_pic ); + p_dst = &dest_pic; + + img_resample( p_sys->p_rsc, p_dst, p_src ); + + if (p_sys->b_enable_croppadd) + { + if (p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width || + p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height || + p_filter->fmt_out.video.i_x_offset != 0 || + p_filter->fmt_out.video.i_y_offset != 0) + { + fill_pad_region(p_dst, p_filter->fmt_out.video.i_height, + p_filter->fmt_out.video.i_width, + p_filter->fmt_out.video.i_y_offset, + p_filter->fmt_out.video.i_height + - p_filter->fmt_out.video.i_visible_height + - p_filter->fmt_out.video.i_y_offset, + p_filter->fmt_out.video.i_x_offset, + p_filter->fmt_out.video.i_width + - p_filter->fmt_out.video.i_visible_width + - p_filter->fmt_out.video.i_x_offset, + padcolor); + } + } } /* Special case for RV32 -> YUVA */ @@ -275,9 +534,9 @@ static picture_t *Process( filter_t *p_filter, picture_t *p_pic ) int i_src_pitch = p_pic->p[0].i_pitch; uint8_t *p_dst = p_pic_dst->p[3].p_pixels; int i_dst_pitch = p_pic_dst->p[3].i_pitch; - int j; + uint32_t l,j; - for( i = 0; i < p_filter->fmt_out.video.i_height; i++ ) + for( l = 0; l < p_filter->fmt_out.video.i_height; l++ ) { for( j = 0; j < p_filter->fmt_out.video.i_width; j++ ) { @@ -287,6 +546,12 @@ static picture_t *Process( filter_t *p_filter, picture_t *p_pic ) p_dst += i_dst_pitch; } } + else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') ) + { + /* Special case for YUVA */ + memset( p_pic_dst->p[3].p_pixels, 0xFF, + p_pic_dst->p[3].i_pitch * p_pic_dst->p[3].i_lines ); + } p_pic_dst->date = p_pic->date; p_pic_dst->b_force = p_pic->b_force; @@ -387,3 +652,5 @@ static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic ) p_pic->pf_release( p_pic ); return p_pic_dst; } + +#endif /* ( (defined(HAVE_FFMPEG_SWSCALE_H) || defined(HAVE_LIBSWSCALE_TREE)) */