]> git.sesse.net Git - vlc/blob - modules/video_filter/swscale.c
Upgraded swscale mode to bicubic by default (fast bilinear is nearly
[vlc] / modules / video_filter / swscale.c
1 /*****************************************************************************
2  * swscale.c: scaling and chroma conversion using libswscale
3  *****************************************************************************
4  * Copyright (C) 1999-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Gildas Bazin <gbazin@videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_vout.h>
35 #include <vlc_filter.h>
36
37 #ifdef HAVE_LIBSWSCALE_SWSCALE_H
38 #   include <libswscale/swscale.h>
39 #elif defined(HAVE_FFMPEG_SWSCALE_H)
40 #   include <ffmpeg/swscale.h>
41 #endif
42
43 /* Gruikkkkkkkkkk!!!!! */
44 #include "../codec/avcodec/chroma.h"
45
46 /****************************************************************************
47  * Local prototypes
48  ****************************************************************************/
49 static int  OpenScaler( vlc_object_t * );
50 static void CloseScaler( vlc_object_t * );
51
52 void *( *swscale_fast_memcpy )( void *, const void *, size_t );
53 static picture_t *Filter( filter_t *, picture_t * );
54 static int CheckInit( filter_t * );
55
56 #define SCALEMODE_TEXT N_("Scaling mode")
57 #define SCALEMODE_LONGTEXT N_("Scaling mode to use.")
58
59 static const int pi_mode_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
60 const char *const ppsz_mode_descriptions[] =
61 { N_("Fast bilinear"), N_("Bilinear"), N_("Bicubic (good quality)"),
62   N_("Experimental"), N_("Nearest neighbour (bad quality)"),
63   N_("Area"), N_("Luma bicubic / chroma bilinear"), N_("Gauss"),
64   N_("SincR"), N_("Lanczos"), N_("Bicubic spline") };
65
66
67 /*****************************************************************************
68  * Module descriptor
69  *****************************************************************************/
70 vlc_module_begin();
71     set_description( N_("Video scaling filter") );
72     set_capability( "video filter2", 1000 );
73     set_category( CAT_VIDEO );
74     set_subcategory( SUBCAT_VIDEO_VFILTER );
75     set_callbacks( OpenScaler, CloseScaler );
76     add_integer( "swscale-mode", 2, NULL, SCALEMODE_TEXT, SCALEMODE_LONGTEXT, true );
77         change_integer_list( pi_mode_values, ppsz_mode_descriptions, 0 );
78 vlc_module_end();
79
80 /* Version checking */
81 #if LIBSWSCALE_VERSION_INT >= ((0<<16)+(5<<8)+0)
82 /*****************************************************************************
83  * filter_sys_t : filter descriptor
84  *****************************************************************************/
85 struct filter_sys_t
86 {
87     struct SwsContext *ctx;
88     SwsFilter *p_src_filter;
89     SwsFilter *p_dst_filter;
90     int i_cpu_mask, i_sws_flags;
91
92     es_format_t fmt_in;
93     es_format_t fmt_out;
94 };
95
96 /*****************************************************************************
97  * OpenScaler: probe the filter and return score
98  *****************************************************************************/
99 static int OpenScaler( vlc_object_t *p_this )
100 {
101     filter_t *p_filter = (filter_t*)p_this;
102     filter_sys_t *p_sys;
103     vlc_value_t val;
104
105     int i_fmt_in, i_fmt_out;
106     unsigned int i_cpu;
107     int i_sws_mode;
108
109     float sws_lum_gblur = 0.0, sws_chr_gblur = 0.0;
110     int sws_chr_vshift = 0, sws_chr_hshift = 0;
111     float sws_chr_sharpen = 0.0, sws_lum_sharpen = 0.0;
112
113     /* Supported Input formats: YV12, I420/IYUV, YUY2, UYVY, BGR32, BGR24,
114      * BGR16, BGR15, RGB32, RGB24, Y8/Y800, YVU9/IF09 */
115     i_fmt_in = GetFfmpegChroma(p_filter->fmt_in.video.i_chroma);
116     /* Supported output formats: YV12, I420/IYUV, YUY2, UYVY,
117      * {BGR,RGB}{1,4,8,15,16,24,32}, Y8/Y800, YVU9/IF09 */
118     i_fmt_out = GetFfmpegChroma(p_filter->fmt_out.video.i_chroma);
119     if( ( i_fmt_in < 0 ) || ( i_fmt_out < 0 ) )
120     {
121         return VLC_EGENERIC;
122     }
123
124     /* Allocate the memory needed to store the decoder's structure */
125     if( ( p_filter->p_sys = p_sys =
126           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
127     {
128         return VLC_ENOMEM;
129     }
130
131     swscale_fast_memcpy = vlc_memcpy;
132
133     /* Set CPU capabilities */
134     i_cpu = vlc_CPU();
135     p_sys->i_cpu_mask = 0;
136     if( i_cpu & CPU_CAPABILITY_MMX )
137     {
138         p_sys->i_cpu_mask |= SWS_CPU_CAPS_MMX;
139     }
140 #if (LIBSWSCALE_VERSION_INT >= ((0<<16)+(5<<8)+0))
141     if( i_cpu & CPU_CAPABILITY_MMXEXT )
142     {
143         p_sys->i_cpu_mask |= SWS_CPU_CAPS_MMX2;
144     }
145 #endif
146     if( i_cpu & CPU_CAPABILITY_3DNOW )
147     {
148         p_sys->i_cpu_mask |= SWS_CPU_CAPS_3DNOW;
149     }
150     if( i_cpu & CPU_CAPABILITY_ALTIVEC )
151     {
152         p_sys->i_cpu_mask |= SWS_CPU_CAPS_ALTIVEC;
153     }
154
155     var_Create( p_filter, "swscale-mode", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
156     var_Get( p_filter, "swscale-mode", &val );
157     i_sws_mode = val.i_int;
158
159     switch( i_sws_mode )
160     {
161     case 0:  p_sys->i_sws_flags = SWS_FAST_BILINEAR; break;
162     case 1:  p_sys->i_sws_flags = SWS_BILINEAR; break;
163     case 2:  p_sys->i_sws_flags = SWS_BICUBIC; break;
164     case 3:  p_sys->i_sws_flags = SWS_X; break;
165     case 4:  p_sys->i_sws_flags = SWS_POINT; break;
166     case 5:  p_sys->i_sws_flags = SWS_AREA; break;
167     case 6:  p_sys->i_sws_flags = SWS_BICUBLIN; break;
168     case 7:  p_sys->i_sws_flags = SWS_GAUSS; break;
169     case 8:  p_sys->i_sws_flags = SWS_SINC; break;
170     case 9:  p_sys->i_sws_flags = SWS_LANCZOS; break;
171     case 10: p_sys->i_sws_flags = SWS_SPLINE; break;
172     default: p_sys->i_sws_flags = SWS_FAST_BILINEAR; i_sws_mode = 0; break;
173     }
174
175     p_sys->p_src_filter = NULL;
176     p_sys->p_dst_filter = NULL;
177     p_sys->p_src_filter =
178         sws_getDefaultFilter( sws_lum_gblur, sws_chr_gblur,
179                               sws_lum_sharpen, sws_chr_sharpen,
180                               sws_chr_hshift, sws_chr_vshift, 0 );
181
182     /* Misc init */
183     p_sys->ctx = NULL;
184     p_filter->pf_video_filter = Filter;
185     es_format_Init( &p_sys->fmt_in, 0, 0 );
186     es_format_Init( &p_sys->fmt_out, 0, 0 );
187
188     if( CheckInit( p_filter ) != VLC_SUCCESS )
189     {
190         if( p_sys->p_src_filter ) sws_freeFilter( p_sys->p_src_filter );
191         free( p_sys );
192         return VLC_EGENERIC;
193     }
194     if( p_sys->ctx ) sws_freeContext( p_sys->ctx );
195     p_sys->ctx = NULL;
196
197     msg_Dbg( p_filter, "%ix%i chroma: %4.4s -> %ix%i chroma: %4.4s",
198              p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
199              (char *)&p_filter->fmt_in.video.i_chroma,
200              p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
201              (char *)&p_filter->fmt_out.video.i_chroma );
202
203     if( p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ||
204         p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height )
205     {
206         msg_Dbg( p_filter, "scaling mode: %s",
207                  ppsz_mode_descriptions[i_sws_mode] );
208     }
209
210     return VLC_SUCCESS;
211 }
212
213 /*****************************************************************************
214  * CloseFilter: clean up the filter
215  *****************************************************************************/
216 static void CloseScaler( vlc_object_t *p_this )
217 {
218     filter_t *p_filter = (filter_t*)p_this;
219     filter_sys_t *p_sys = p_filter->p_sys;
220
221     if( p_sys->ctx ) sws_freeContext( p_sys->ctx );
222     if( p_sys->p_src_filter ) sws_freeFilter( p_sys->p_src_filter );
223     free( p_sys );
224 }
225
226 /*****************************************************************************
227  * CheckInit: Initialise filter when necessary
228  *****************************************************************************/
229 static int CheckInit( filter_t *p_filter )
230 {
231     filter_sys_t *p_sys = p_filter->p_sys;
232
233     if( ( p_filter->fmt_in.video.i_width != p_sys->fmt_in.video.i_width ) ||
234         ( p_filter->fmt_in.video.i_height != p_sys->fmt_in.video.i_height ) ||
235         ( p_filter->fmt_out.video.i_width != p_sys->fmt_out.video.i_width ) ||
236         ( p_filter->fmt_out.video.i_height != p_sys->fmt_out.video.i_height ) ||
237         !p_sys->ctx )
238     {
239         int i_fmt_in, i_fmt_out;
240
241         i_fmt_in = GetFfmpegChroma(p_filter->fmt_in.video.i_chroma);
242         i_fmt_out = GetFfmpegChroma(p_filter->fmt_out.video.i_chroma);
243         if( (i_fmt_in < 0) || (i_fmt_out < 0) )
244         {
245             msg_Err( p_filter, "format not supported" );
246             return VLC_EGENERIC;
247         }
248
249         if( p_sys->ctx ) sws_freeContext( p_sys->ctx );
250
251         p_sys->ctx =
252             sws_getContext( p_filter->fmt_in.video.i_width,
253                             p_filter->fmt_in.video.i_height, i_fmt_in,
254                             p_filter->fmt_out.video.i_width,
255                             p_filter->fmt_out.video.i_height, i_fmt_out,
256                             p_sys->i_sws_flags | p_sys->i_cpu_mask,
257                             p_sys->p_src_filter, p_sys->p_dst_filter, 0 );
258         if( !p_sys->ctx )
259         {
260             msg_Err( p_filter, "could not init SwScaler" );
261             return VLC_EGENERIC;
262         }
263
264         p_sys->fmt_in = p_filter->fmt_in;
265         p_sys->fmt_out = p_filter->fmt_out;
266     }
267
268     return VLC_SUCCESS;
269 }
270
271 /****************************************************************************
272  * Filter: the whole thing
273  ****************************************************************************
274  * This function is called just after the thread is launched.
275  ****************************************************************************/
276 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
277 {
278     filter_sys_t *p_sys = p_filter->p_sys;
279     uint8_t *src[3]; int src_stride[3];
280     uint8_t *dst[3]; int dst_stride[3];
281     picture_t *p_pic_dst;
282     int i_plane;
283     int i_nb_planes = p_pic->i_planes;
284
285     /* Check if format properties changed */
286     if( CheckInit( p_filter ) != VLC_SUCCESS )
287     {
288         picture_Release( p_pic );
289         return NULL;
290     }
291
292     /* Request output picture */
293     p_pic_dst = filter_NewPicture( p_filter );
294     if( !p_pic_dst )
295     {
296         picture_Release( p_pic );
297         return NULL;
298     }
299
300     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
301     {
302         i_nb_planes = 3;
303         memset( p_pic_dst->p[3].p_pixels, 0xff, p_filter->fmt_out.video.i_height
304                                                  * p_pic_dst->p[3].i_pitch );
305     }
306
307     for( i_plane = 0; i_plane < __MIN(3, p_pic->i_planes); i_plane++ )
308     {
309         src[i_plane] = p_pic->p[i_plane].p_pixels;
310         src_stride[i_plane] = p_pic->p[i_plane].i_pitch;
311     }
312     for( i_plane = 0; i_plane < __MIN(3, i_nb_planes); i_plane++ )
313     {
314         dst[i_plane] = p_pic_dst->p[i_plane].p_pixels;
315         dst_stride[i_plane] = p_pic_dst->p[i_plane].i_pitch;
316     }
317
318 #if LIBSWSCALE_VERSION_INT  >= ((0<<16)+(5<<8)+0)
319     sws_scale( p_sys->ctx, src, src_stride,
320                0, p_filter->fmt_in.video.i_height,
321                dst, dst_stride );
322 #else
323     sws_scale_ordered( p_sys->ctx, src, src_stride,
324                0, p_filter->fmt_in.video.i_height,
325                dst, dst_stride );
326 #endif
327
328     picture_CopyProperties( p_pic_dst, p_pic );
329     picture_Release( p_pic );
330     return p_pic_dst;
331 }
332
333 #else /* LIBSWSCALE_VERSION_INT >= ((0<<16)+(5<<8)+0) */
334
335 int OpenScaler( vlc_object_t *p_this )
336 {
337     return VLC_EGENERIC;
338 }
339
340 void CloseScaler( vlc_object_t *p_this )
341 {
342 }
343
344 #endif /* LIBSWSCALE_VERSION_INT >= ((0<<16)+(5<<8)+0) */