Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

filter.c

00001 /*****************************************************************************
00002  * filter.c: video scaling module using the swscale library
00003  *****************************************************************************
00004  * Copyright (C) 2003 the VideoLAN team
00005  * $Id: filter.c 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Author: Gildas Bazin <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <vlc/vlc.h>
00028 #include <vlc/decoder.h>
00029 #include "vlc_filter.h"
00030 
00031 #include "common.h"
00032 #include "swscale.h"
00033 
00034 void *( *swscale_fast_memcpy )( void *, const void *, size_t );
00035 
00036 /*****************************************************************************
00037  * filter_sys_t : filter descriptor
00038  *****************************************************************************/
00039 struct filter_sys_t
00040 {
00041     struct SwsContext *ctx;
00042     SwsFilter *p_src_filter;
00043     SwsFilter *p_dst_filter;
00044     int i_cpu_mask, i_sws_flags;
00045 
00046     es_format_t fmt_in;
00047     es_format_t fmt_out;
00048 };
00049 
00050 /****************************************************************************
00051  * Local prototypes
00052  ****************************************************************************/
00053 static int  OpenFilter ( vlc_object_t * );
00054 static void CloseFilter( vlc_object_t * );
00055 
00056 static picture_t *Filter( filter_t *, picture_t * );
00057 static int CheckInit( filter_t * );
00058 static int GetSwscaleChroma( vlc_fourcc_t );
00059 
00060 /*****************************************************************************
00061  * Module descriptor
00062  *****************************************************************************/
00063 #define MODE_TEXT N_("Scaling mode")
00064 #define MODE_LONGTEXT N_("You can choose the default scaling mode.")
00065 
00066 static int pi_mode_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
00067 static char *ppsz_mode_descriptions[] =
00068 { N_("Fast bilinear"), N_("Bilinear"), N_("Bicubic (good quality)"),
00069   N_("Experimental"), N_("Nearest neighbour (bad quality)"),
00070   N_("Area"), N_("Luma bicubic / chroma bilinear"), N_("Gauss"),
00071   N_("SincR"), N_("Lanczos"), N_("Bicubic spline") };
00072 
00073 vlc_module_begin();
00074     set_description( _("Video scaling filter") );
00075     set_capability( "video filter2", 1000 );
00076     set_category( CAT_VIDEO );
00077     set_subcategory( SUBCAT_VIDEO_VFILTER );
00078     set_callbacks( OpenFilter, CloseFilter );
00079 
00080     add_integer( "swscale-mode", 0, NULL, MODE_TEXT, MODE_LONGTEXT, VLC_TRUE );
00081         change_integer_list( pi_mode_values, ppsz_mode_descriptions, 0 );
00082 vlc_module_end();
00083 
00084 /*****************************************************************************
00085  * OpenFilter: probe the filter and return score
00086  *****************************************************************************/
00087 static int OpenFilter( vlc_object_t *p_this )
00088 {
00089     filter_t *p_filter = (filter_t*)p_this;
00090     filter_sys_t *p_sys;
00091     vlc_value_t val;
00092 
00093     unsigned int i_fmt_in, i_fmt_out;
00094     int i_sws_mode;
00095 
00096     float sws_lum_gblur = 0.0, sws_chr_gblur = 0.0;
00097     int sws_chr_vshift = 0, sws_chr_hshift = 0;
00098     float sws_chr_sharpen = 0.0, sws_lum_sharpen = 0.0;
00099 
00100     /* Supported Input formats: YV12, I420/IYUV, YUY2, UYVY, BGR32, BGR24,
00101      * BGR16, BGR15, RGB32, RGB24, Y8/Y800, YVU9/IF09 */
00102     if( !(i_fmt_in = GetSwscaleChroma(p_filter->fmt_in.video.i_chroma)) )
00103     {
00104         return VLC_EGENERIC;
00105     }
00106 
00107     /* Supported output formats: YV12, I420/IYUV, YUY2, UYVY,
00108      * {BGR,RGB}{1,4,8,15,16,24,32}, Y8/Y800, YVU9/IF09 */
00109     if( !(i_fmt_out = GetSwscaleChroma(p_filter->fmt_out.video.i_chroma)) )
00110     {
00111         return VLC_EGENERIC;
00112     }
00113 
00114     /* Allocate the memory needed to store the decoder's structure */
00115     if( ( p_filter->p_sys = p_sys =
00116           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
00117     {
00118         msg_Err( p_filter, "out of memory" );
00119         return VLC_EGENERIC;
00120     }
00121 
00122     swscale_fast_memcpy = p_filter->p_vlc->pf_memcpy;
00123 
00124     /* Set CPU capabilities */
00125     p_sys->i_cpu_mask = 0;
00126     if( p_filter->p_libvlc->i_cpu & CPU_CAPABILITY_MMX )
00127     {
00128         p_sys->i_cpu_mask |= SWS_CPU_CAPS_MMX;
00129     }
00130     if( p_filter->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT )
00131     {
00132         p_sys->i_cpu_mask |= SWS_CPU_CAPS_MMX2;
00133     }
00134     if( p_filter->p_libvlc->i_cpu & CPU_CAPABILITY_3DNOW )
00135     {
00136         p_sys->i_cpu_mask |= SWS_CPU_CAPS_3DNOW;
00137     }
00138     if( p_filter->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC )
00139     {
00140         p_sys->i_cpu_mask |= SWS_CPU_CAPS_ALTIVEC;
00141     }
00142 
00143     var_Create( p_filter, "swscale-mode", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
00144     var_Get( p_filter, "swscale-mode", &val );
00145     i_sws_mode = val.i_int;
00146 
00147     switch( i_sws_mode )
00148     {
00149     case 0:  p_sys->i_sws_flags = SWS_FAST_BILINEAR; break;
00150     case 1:  p_sys->i_sws_flags = SWS_BILINEAR; break;
00151     case 2:  p_sys->i_sws_flags = SWS_BICUBIC; break;
00152     case 3:  p_sys->i_sws_flags = SWS_X; break;
00153     case 4:  p_sys->i_sws_flags = SWS_POINT; break;
00154     case 5:  p_sys->i_sws_flags = SWS_AREA; break;
00155     case 6:  p_sys->i_sws_flags = SWS_BICUBLIN; break;
00156     case 7:  p_sys->i_sws_flags = SWS_GAUSS; break;
00157     case 8:  p_sys->i_sws_flags = SWS_SINC; break;
00158     case 9:  p_sys->i_sws_flags = SWS_LANCZOS; break;
00159     case 10: p_sys->i_sws_flags = SWS_SPLINE; break;
00160     default: p_sys->i_sws_flags = SWS_FAST_BILINEAR; i_sws_mode = 0; break;
00161     }
00162 
00163     p_sys->p_src_filter = 0; p_sys->p_dst_filter = 0;
00164     p_sys->p_src_filter =
00165         sws_getDefaultFilter( sws_lum_gblur, sws_chr_gblur,
00166                               sws_lum_sharpen, sws_chr_sharpen,
00167                               sws_chr_hshift, sws_chr_vshift, 0 );
00168 
00169     /* Misc init */
00170     p_sys->ctx = NULL;
00171     p_filter->pf_video_filter = Filter;
00172     es_format_Init( &p_sys->fmt_in, 0, 0 );
00173     es_format_Init( &p_sys->fmt_out, 0, 0 );
00174 
00175     if( CheckInit( p_filter ) != VLC_SUCCESS )
00176     {
00177         if( p_sys->p_src_filter ) sws_freeFilter( p_sys->p_src_filter );
00178         free( p_sys );
00179         return VLC_EGENERIC;
00180     }
00181 
00182     msg_Dbg( p_filter, "%ix%i chroma: %4.4s -> %ix%i chroma: %4.4s",
00183              p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
00184              (char *)&p_filter->fmt_in.video.i_chroma,
00185              p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
00186              (char *)&p_filter->fmt_out.video.i_chroma );
00187 
00188     if( p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ||
00189         p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height )
00190     {
00191         msg_Dbg( p_filter, "scaling mode: %s",
00192                  ppsz_mode_descriptions[i_sws_mode] );
00193     }
00194 
00195     return VLC_SUCCESS;
00196 }
00197 
00198 /*****************************************************************************
00199  * CloseFilter: clean up the filter
00200  *****************************************************************************/
00201 static void CloseFilter( vlc_object_t *p_this )
00202 {
00203     filter_t *p_filter = (filter_t*)p_this;
00204     filter_sys_t *p_sys = p_filter->p_sys;
00205 
00206     if( p_sys->ctx ) sws_freeContext( p_sys->ctx );
00207     if( p_sys->p_src_filter ) sws_freeFilter( p_sys->p_src_filter );
00208     free( p_sys );
00209 }
00210 
00211 /*****************************************************************************
00212  * CheckInit: Initialise filter when necessary
00213  *****************************************************************************/
00214 static int CheckInit( filter_t *p_filter )
00215 {
00216     filter_sys_t *p_sys = p_filter->p_sys;
00217 
00218     if( p_filter->fmt_in.video.i_width != p_sys->fmt_in.video.i_width ||
00219         p_filter->fmt_in.video.i_height != p_sys->fmt_in.video.i_height ||
00220         p_filter->fmt_out.video.i_width != p_sys->fmt_out.video.i_width ||
00221         p_filter->fmt_out.video.i_height != p_sys->fmt_out.video.i_height )
00222     {
00223         unsigned int i_fmt_in, i_fmt_out;
00224 
00225         if( !(i_fmt_in = GetSwscaleChroma(p_filter->fmt_in.video.i_chroma)) ||
00226             !(i_fmt_out = GetSwscaleChroma(p_filter->fmt_out.video.i_chroma)) )
00227         {
00228             msg_Err( p_filter, "format not supported" );
00229             return VLC_EGENERIC;
00230         }
00231 
00232         if( p_sys->ctx ) sws_freeContext( p_sys->ctx );
00233 
00234         p_sys->ctx =
00235             sws_getContext( p_filter->fmt_in.video.i_width,
00236                             p_filter->fmt_in.video.i_height, i_fmt_in,
00237                             p_filter->fmt_out.video.i_width,
00238                             p_filter->fmt_out.video.i_height, i_fmt_out,
00239                             p_sys->i_sws_flags | p_sys->i_cpu_mask,
00240                             p_sys->p_src_filter, p_sys->p_dst_filter );
00241         if( !p_sys->ctx )
00242         {
00243             msg_Err( p_filter, "could not init SwScaler" );
00244             return VLC_EGENERIC;
00245         }
00246 
00247         p_sys->fmt_in = p_filter->fmt_in;
00248         p_sys->fmt_out = p_filter->fmt_out;
00249     }
00250 
00251     return VLC_SUCCESS;
00252 }
00253 
00254 /****************************************************************************
00255  * Filter: the whole thing
00256  ****************************************************************************
00257  * This function is called just after the thread is launched.
00258  ****************************************************************************/
00259 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
00260 {
00261     filter_sys_t *p_sys = p_filter->p_sys;
00262     uint8_t *src[3]; int src_stride[3];
00263     uint8_t *dst[3]; int dst_stride[3];
00264     picture_t *p_pic_dst;
00265     int i_plane;
00266     int i_nb_planes = p_pic->i_planes;
00267 
00268     /* Check if format properties changed */
00269     if( CheckInit( p_filter ) != VLC_SUCCESS ) return 0;
00270 
00271     /* Request output picture */
00272     p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
00273     if( !p_pic_dst )
00274     {
00275         msg_Warn( p_filter, "can't get output picture" );
00276         return NULL;
00277     }
00278 
00279     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
00280     {
00281         i_nb_planes = 3;
00282         memset( p_pic_dst->p[3].p_pixels, 0xff, p_filter->fmt_out.video.i_height
00283                                                  * p_pic_dst->p[3].i_pitch );
00284     }
00285 
00286     for( i_plane = 0; i_plane < __MIN(3, p_pic->i_planes); i_plane++ )
00287     {
00288         src[i_plane] = p_pic->p[i_plane].p_pixels;
00289         src_stride[i_plane] = p_pic->p[i_plane].i_pitch;
00290     }
00291     for( i_plane = 0; i_plane < __MIN(3, i_nb_planes); i_plane++ )
00292     {
00293         dst[i_plane] = p_pic_dst->p[i_plane].p_pixels;
00294         dst_stride[i_plane] = p_pic_dst->p[i_plane].i_pitch;
00295     }
00296 
00297     sws_scale_ordered( p_sys->ctx, src, src_stride,
00298                        0, p_filter->fmt_in.video.i_height,
00299                        dst, dst_stride );
00300 
00301     p_pic_dst->date = p_pic->date;
00302     p_pic_dst->b_force = p_pic->b_force;
00303     p_pic_dst->i_nb_fields = p_pic->i_nb_fields;
00304     p_pic_dst->b_progressive = p_pic->b_progressive;
00305     p_pic_dst->b_top_field_first = p_pic->b_top_field_first;
00306 
00307     p_pic->pf_release( p_pic );
00308     return p_pic_dst;
00309 }
00310 
00311 /*****************************************************************************
00312  * Chroma fourcc -> ffmpeg_id mapping
00313  *****************************************************************************/
00314 static struct
00315 {
00316     vlc_fourcc_t  i_chroma;
00317     unsigned int  i_swscale_chroma;
00318 
00319 } chroma_table[] =
00320 {
00321     /* Planar YUV formats */
00322     { VLC_FOURCC('Y','V','1','2'), IMGFMT_YV12 },
00323     { VLC_FOURCC('I','4','2','0'), IMGFMT_I420 },
00324     { VLC_FOURCC('I','Y','U','V'), IMGFMT_IYUV },
00325     { VLC_FOURCC('I','4','4','4'), IMGFMT_444P },
00326     { VLC_FOURCC('Y','U','V','A'), IMGFMT_444P },
00327     { VLC_FOURCC('I','4','2','2'), IMGFMT_422P },
00328     { VLC_FOURCC('I','4','1','1'), IMGFMT_411P },
00329 #if 0
00330     { VLC_FOURCC('Y','U','V','P'), IMGFMT_Y800 },
00331 #endif
00332 
00333     /* Packed YUV formats */
00334     { VLC_FOURCC('U','Y','V','Y'), IMGFMT_UYVY },
00335     { VLC_FOURCC('Y','U','Y','2'), IMGFMT_YUY2 },
00336 
00337     /* Packed RGB formats */
00338     { VLC_FOURCC('R','V','1','5'), IMGFMT_RGB15 },
00339     { VLC_FOURCC('R','V','1','6'), IMGFMT_RGB16 },
00340     { VLC_FOURCC('R','V','2','4'), IMGFMT_RGB24 },
00341     { VLC_FOURCC('R','V','3','2'), IMGFMT_RGB32 },
00342     { VLC_FOURCC('G','R','E','Y'), IMGFMT_RGB8 },
00343 
00344     {0}
00345 };
00346 
00347 static int GetSwscaleChroma( vlc_fourcc_t i_chroma )
00348 {
00349     int i;
00350 
00351     for( i = 0; chroma_table[i].i_chroma != 0; i++ )
00352     {
00353         if( chroma_table[i].i_chroma == i_chroma )
00354             return chroma_table[i].i_swscale_chroma;
00355     }
00356     return 0;
00357 }

Generated on Tue Dec 20 10:14:53 2005 for vlc-0.8.4a by  doxygen 1.4.2