00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
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
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
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
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
00101
00102 if( !(i_fmt_in = GetSwscaleChroma(p_filter->fmt_in.video.i_chroma)) )
00103 {
00104 return VLC_EGENERIC;
00105 }
00106
00107
00108
00109 if( !(i_fmt_out = GetSwscaleChroma(p_filter->fmt_out.video.i_chroma)) )
00110 {
00111 return VLC_EGENERIC;
00112 }
00113
00114
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
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
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
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
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
00256
00257
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
00269 if( CheckInit( p_filter ) != VLC_SUCCESS ) return 0;
00270
00271
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
00313
00314 static struct
00315 {
00316 vlc_fourcc_t i_chroma;
00317 unsigned int i_swscale_chroma;
00318
00319 } chroma_table[] =
00320 {
00321
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
00334 { VLC_FOURCC('U','Y','V','Y'), IMGFMT_UYVY },
00335 { VLC_FOURCC('Y','U','Y','2'), IMGFMT_YUY2 },
00336
00337
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 }