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