]> git.sesse.net Git - vlc/blob - modules/codec/ffmpeg/video_filter.c
* Don't use deprecated functions if libswscaler is present.
[vlc] / modules / codec / ffmpeg / video_filter.c
1 /*****************************************************************************
2  * video filter: video filter doing chroma conversion and resizing
3  *               using the ffmpeg library
4  *****************************************************************************
5  * Copyright (C) 1999-2001 the VideoLAN team
6  * $Id$
7  *
8  * Authors: 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 #include <vlc/vlc.h>
29 #include <vlc/decoder.h>
30 #include "vlc_filter.h"
31
32 /* ffmpeg header */
33 #ifdef HAVE_FFMPEG_AVCODEC_H
34 #   include <ffmpeg/avcodec.h>
35 #else
36 #   include <avcodec.h>
37 #endif
38
39 #include "ffmpeg.h"
40
41
42 #if !defined(HAVE_FFMPEG_SWSCALE_H) && !defined(HAVE_LIBSWSCALE_TREE)
43 void E_(InitLibavcodec) ( vlc_object_t *p_object );
44 static int CheckInit( filter_t *p_filter );
45 static picture_t *Process( filter_t *p_filter, picture_t *p_pic );
46 static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic );
47
48 /*****************************************************************************
49  * filter_sys_t : filter descriptor
50  *****************************************************************************/
51 struct filter_sys_t
52 {
53     vlc_bool_t b_resize;
54     vlc_bool_t b_convert;
55     vlc_bool_t b_resize_first;
56     vlc_bool_t b_enable_croppadd;
57
58     es_format_t fmt_in;
59     int i_src_ffmpeg_chroma;
60     es_format_t fmt_out;
61     int i_dst_ffmpeg_chroma;
62
63     AVPicture tmp_pic;
64     ImgReSampleContext *p_rsc;
65 };
66
67
68 /*****************************************************************************
69  * OpenFilterEx: common code to OpenFilter and OpenCropPadd
70  *****************************************************************************/
71 static int OpenFilterEx( vlc_object_t *p_this, vlc_bool_t b_enable_croppadd )
72 {
73     filter_t *p_filter = (filter_t*)p_this;
74     filter_sys_t *p_sys;
75     vlc_bool_t b_convert, b_resize;
76
77     /* Check if we can handle that formats */
78     if( E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ) < 0 ||
79         E_(GetFfmpegChroma)( p_filter->fmt_out.video.i_chroma ) < 0 )
80     {
81         return VLC_EGENERIC;
82     }
83
84     b_resize =
85         p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ||
86         p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height;
87
88     if ( b_enable_croppadd ) 
89     {
90         b_resize = b_resize ||
91             p_filter->fmt_in.video.i_visible_width != p_filter->fmt_in.video.i_width ||
92             p_filter->fmt_in.video.i_visible_height != p_filter->fmt_in.video.i_height ||
93             p_filter->fmt_in.video.i_x_offset != 0 ||
94             p_filter->fmt_in.video.i_y_offset != 0 ||
95             p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width ||
96             p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height ||
97             p_filter->fmt_out.video.i_x_offset != 0 ||
98             p_filter->fmt_out.video.i_y_offset != 0;
99     }
100
101     b_convert =
102         p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma;
103
104     if( !b_resize && !b_convert )
105     {
106         /* Nothing to do */
107         return VLC_EGENERIC;
108     }
109
110     /* Allocate the memory needed to store the decoder's structure */
111     if( ( p_filter->p_sys = p_sys =
112           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
113     {
114         msg_Err( p_filter, "out of memory" );
115         return VLC_EGENERIC;
116     }
117
118     /* Misc init */
119     p_sys->p_rsc = NULL;
120     p_sys->b_enable_croppadd = b_enable_croppadd;
121     p_sys->i_src_ffmpeg_chroma =
122         E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma );
123     p_sys->i_dst_ffmpeg_chroma =
124         E_(GetFfmpegChroma)( p_filter->fmt_out.video.i_chroma );
125     p_filter->pf_video_filter = Process;
126     es_format_Init( &p_sys->fmt_in, 0, 0 );
127     es_format_Init( &p_sys->fmt_out, 0, 0 );
128
129     /* Dummy alloc, will be reallocated in CheckInit */
130     avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma,
131                      p_filter->fmt_out.video.i_width,
132                      p_filter->fmt_out.video.i_height );
133
134     if( CheckInit( p_filter ) != VLC_SUCCESS )
135     {
136         free( p_sys );
137         return VLC_EGENERIC;
138     }
139
140     msg_Dbg( p_filter, "input: %ix%i %4.4s -> %ix%i %4.4s",
141              p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
142              (char *)&p_filter->fmt_in.video.i_chroma,
143              p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
144              (char *)&p_filter->fmt_out.video.i_chroma );
145
146     /* libavcodec needs to be initialized for some chroma conversions */
147     E_(InitLibavcodec)(p_this);
148
149     return VLC_SUCCESS;
150 }
151
152 /*****************************************************************************
153  * OpenFilter: probe the filter and return score
154  *****************************************************************************/
155 int E_(OpenFilter)( vlc_object_t *p_this )
156 {
157     return OpenFilterEx( p_this, VLC_FALSE );
158 }
159
160 /*****************************************************************************
161  * OpenCropPadd: probe the filter and return score
162  *****************************************************************************/
163 int E_(OpenCropPadd)( vlc_object_t *p_this )
164 {
165     return OpenFilterEx( p_this, VLC_TRUE );
166 }
167
168
169 /*****************************************************************************
170  * CloseFilter: clean up the filter
171  *****************************************************************************/
172 void E_(CloseFilter)( vlc_object_t *p_this )
173 {
174     filter_t *p_filter = (filter_t*)p_this;
175     filter_sys_t *p_sys = p_filter->p_sys;
176
177     if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
178
179     avpicture_free( &p_sys->tmp_pic );
180
181     free( p_sys );
182 }
183
184 /*****************************************************************************
185  * CheckInit: Initialise filter when necessary
186  *****************************************************************************/
187 static int CheckInit( filter_t *p_filter )
188 {
189     filter_sys_t *p_sys = p_filter->p_sys;
190     vlc_bool_t b_change;
191     int i_croptop=0;
192     int i_cropbottom=0;
193     int i_cropleft=0;
194     int i_cropright=0;
195     int i_paddtop=0;
196     int i_paddbottom=0;
197     int i_paddleft=0;
198     int i_paddright=0;
199
200
201     b_change= p_filter->fmt_in.video.i_width != p_sys->fmt_in.video.i_width ||
202         p_filter->fmt_in.video.i_height != p_sys->fmt_in.video.i_height ||
203         p_filter->fmt_out.video.i_width != p_sys->fmt_out.video.i_width ||
204         p_filter->fmt_out.video.i_height != p_sys->fmt_out.video.i_height;
205
206     if ( p_sys->b_enable_croppadd )
207     {
208         b_change = b_change ||
209             p_filter->fmt_in.video.i_y_offset != p_sys->fmt_in.video.i_y_offset ||
210             p_filter->fmt_in.video.i_x_offset != p_sys->fmt_in.video.i_x_offset ||
211             p_filter->fmt_in.video.i_visible_width != p_sys->fmt_in.video.i_visible_width ||
212             p_filter->fmt_in.video.i_visible_height != p_sys->fmt_in.video.i_visible_height ||
213             p_filter->fmt_out.video.i_y_offset != p_sys->fmt_out.video.i_y_offset ||
214             p_filter->fmt_out.video.i_x_offset != p_sys->fmt_out.video.i_x_offset ||
215             p_filter->fmt_out.video.i_visible_width != p_sys->fmt_out.video.i_visible_width ||
216             p_filter->fmt_out.video.i_visible_height != p_sys->fmt_out.video.i_visible_height;
217     }
218
219     if ( b_change )
220     {
221         if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
222         p_sys->p_rsc = 0;
223
224         p_sys->b_convert =
225           p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma;
226
227         p_sys->b_resize =
228           p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ||
229           p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height;
230
231         p_sys->b_resize_first =
232           p_filter->fmt_in.video.i_width * p_filter->fmt_in.video.i_height >
233           p_filter->fmt_out.video.i_width * p_filter->fmt_out.video.i_height;
234
235         if( p_sys->b_resize &&
236             p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P &&
237             p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P &&
238             p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P &&
239             p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P )
240         {
241             msg_Err( p_filter, "img_resample_init only deals with I420" );
242             return VLC_EGENERIC;
243         }
244         else if( p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P &&
245                  p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P )
246         {
247             p_sys->b_resize_first = VLC_FALSE;
248         }
249         else if( p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P &&
250                  p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P )
251         {
252             p_sys->b_resize_first = VLC_TRUE;
253         }
254
255         if ( p_sys->b_enable_croppadd )
256         {
257             p_sys->b_resize = p_sys->b_resize ||
258                 p_filter->fmt_in.video.i_visible_width != p_filter->fmt_in.video.i_width ||
259                 p_filter->fmt_in.video.i_visible_height != p_filter->fmt_in.video.i_height ||
260                 p_filter->fmt_in.video.i_x_offset != 0 ||
261                 p_filter->fmt_in.video.i_y_offset != 0 ||
262                 p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width ||
263                 p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height ||
264                 p_filter->fmt_out.video.i_x_offset != 0 ||
265                 p_filter->fmt_out.video.i_y_offset != 0;
266         }
267
268         if( p_sys->b_resize )
269         {
270             if ( p_sys->b_enable_croppadd )
271             {
272                 i_croptop=p_filter->fmt_in.video.i_y_offset;
273                 i_cropbottom=p_filter->fmt_in.video.i_height
274                                        - p_filter->fmt_in.video.i_visible_height
275                                        - p_filter->fmt_in.video.i_y_offset;
276                 i_cropleft=p_filter->fmt_in.video.i_x_offset;
277                 i_cropright=p_filter->fmt_in.video.i_width
278                                       - p_filter->fmt_in.video.i_visible_width
279                                       - p_filter->fmt_in.video.i_x_offset;
280
281
282                 i_paddtop=p_filter->fmt_out.video.i_y_offset;
283                 i_paddbottom=p_filter->fmt_out.video.i_height
284                                        - p_filter->fmt_out.video.i_visible_height
285                                        - p_filter->fmt_out.video.i_y_offset;
286                 i_paddleft=p_filter->fmt_out.video.i_x_offset;
287                 i_paddright=p_filter->fmt_out.video.i_width
288                                       - p_filter->fmt_out.video.i_visible_width
289                                       - p_filter->fmt_out.video.i_x_offset;
290             }
291
292             p_sys->p_rsc = img_resample_full_init( 
293                                p_filter->fmt_out.video.i_width,
294                                p_filter->fmt_out.video.i_height,
295                                p_filter->fmt_in.video.i_width,
296                                p_filter->fmt_in.video.i_height,
297                                i_croptop,i_cropbottom,
298                                i_cropleft,i_cropright,
299                                i_paddtop,i_paddbottom,
300                                i_paddleft,i_paddright );
301
302             msg_Dbg( p_filter, "input: %ix%i -> %ix%i",
303                 p_filter->fmt_out.video.i_width,
304                 p_filter->fmt_out.video.i_height,
305                 p_filter->fmt_in.video.i_width,
306                 p_filter->fmt_in.video.i_height);
307
308             if( !p_sys->p_rsc )
309             {
310                 msg_Err( p_filter, "img_resample_init failed" );
311                 return VLC_EGENERIC;
312             }
313         }
314
315         avpicture_free( &p_sys->tmp_pic );
316
317         if( p_sys->b_resize_first )
318         {
319             /* Resizing then conversion */
320             avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma,
321                              p_filter->fmt_out.video.i_width,
322                              p_filter->fmt_out.video.i_height );
323         }
324         else
325         {
326             /* Conversion then resizing */
327             avpicture_alloc( &p_sys->tmp_pic, p_sys->i_dst_ffmpeg_chroma,
328                              p_filter->fmt_in.video.i_width,
329                              p_filter->fmt_in.video.i_height );
330         }
331
332         p_sys->fmt_in = p_filter->fmt_in;
333         p_sys->fmt_out = p_filter->fmt_out;
334     }
335
336     return VLC_SUCCESS;
337 }
338
339 /* fill padd code from ffmpeg */
340 static int padcolor[3] = { 16, 128, 128 };
341
342 /* Expects img to be yuv420 */
343 static void fill_pad_region( AVPicture* img, int height, int width,
344         int padtop, int padbottom, int padleft, int padright, int *color ) 
345 {
346     int i, y, shift;
347     uint8_t *optr;
348
349     for ( i = 0; i < 3; i++ ) 
350     {
351         shift = ( i == 0 ) ? 0 : 1;
352
353         if ( padtop || padleft ) 
354         {
355             memset( img->data[i], color[i], ( ( ( img->linesize[i] * padtop ) +
356                             padleft ) >> shift) );
357         }
358
359         if ( padleft || padright ) 
360         {
361             optr = img->data[i] + ( img->linesize[i] * ( padtop >> shift ) ) +
362                 ( img->linesize[i] - ( padright >> shift ) );
363
364             for ( y = 0; y < ( ( height - ( padtop + padbottom ) ) >> shift ); y++ ) 
365             {
366                 memset( optr, color[i], ( padleft + padright ) >> shift );
367                 optr += img->linesize[i];
368             }
369         }
370
371         if (padbottom) 
372         {
373             optr = img->data[i] + ( img->linesize[i] * ( ( height - padbottom ) >> shift ) );
374             memset( optr, color[i], ( ( img->linesize[i] * padbottom ) >> shift ) );
375         }
376     }
377 }
378
379 /* Workaround, because old libavcodec doesnt know how to padd */
380 static void img_resample_padd( ImgReSampleContext *s, AVPicture *output, 
381         const AVPicture *input, int padtop, int padleft )
382 {
383     AVPicture nopadd_pic = *output;
384
385     /* shift out top and left padding for old ffmpeg */
386     nopadd_pic.data[0] += ( nopadd_pic.linesize[0] * padtop + padleft );
387     nopadd_pic.data[1] += ( nopadd_pic.linesize[1] * padtop + padleft ) >> 1;
388     nopadd_pic.data[2] += ( nopadd_pic.linesize[2] * padtop + padleft ) >> 1;
389     img_resample( s, &nopadd_pic, input );
390 }
391
392
393 /*****************************************************************************
394  * Do the processing here
395  *****************************************************************************/
396 static picture_t *Process( filter_t *p_filter, picture_t *p_pic )
397 {
398     filter_sys_t *p_sys = p_filter->p_sys;
399     AVPicture src_pic, dest_pic;
400     AVPicture *p_src, *p_dst;
401     picture_t *p_pic_dst;
402     int i;
403
404     /* Check if format properties changed */
405     if( CheckInit( p_filter ) != VLC_SUCCESS ) return 0;
406
407     /* Request output picture */
408     p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
409     if( !p_pic_dst )
410     {
411         msg_Warn( p_filter, "can't get output picture" );
412         p_pic->pf_release( p_pic );
413         return NULL;
414     }
415
416     /* Prepare the AVPictures for the conversion */
417     for( i = 0; i < p_pic->i_planes; i++ )
418     {
419         src_pic.data[i] = p_pic->p[i].p_pixels;
420         src_pic.linesize[i] = p_pic->p[i].i_pitch;
421     }
422     for( i = 0; i < p_pic_dst->i_planes; i++ )
423     {
424         dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
425         dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
426     }
427
428     /* Special cases */
429     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
430         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','U','9') )
431     {
432         /* Invert U and V */
433         src_pic.data[1] = p_pic->p[2].p_pixels;
434         src_pic.data[2] = p_pic->p[1].p_pixels;
435     }
436     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
437         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','U','9') )
438     {
439         /* Invert U and V */
440         dest_pic.data[1] = p_pic_dst->p[2].p_pixels;
441         dest_pic.data[2] = p_pic_dst->p[1].p_pixels;
442     }
443     if( p_sys->i_src_ffmpeg_chroma == PIX_FMT_RGB24 )
444         if( p_filter->fmt_in.video.i_bmask == 0x00ff0000 )
445             p_sys->i_src_ffmpeg_chroma = PIX_FMT_BGR24;
446
447     p_src = &src_pic;
448
449     if( p_sys->b_resize && p_sys->p_rsc )
450     {
451         p_dst = &dest_pic;
452         if( p_sys->b_resize_first )
453         {
454             if( p_sys->b_convert ) p_dst = &p_sys->tmp_pic;
455
456             img_resample( p_sys->p_rsc, p_dst, p_src );
457
458             if (p_sys->b_enable_croppadd)
459             {
460                 if (p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width ||
461                     p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height ||
462                     p_filter->fmt_out.video.i_x_offset != 0 ||
463                     p_filter->fmt_out.video.i_y_offset != 0)
464                 {
465                     fill_pad_region(p_dst, p_filter->fmt_out.video.i_height,
466                                     p_filter->fmt_out.video.i_width,
467                                     p_filter->fmt_out.video.i_y_offset,
468                                     p_filter->fmt_out.video.i_height
469                                       - p_filter->fmt_out.video.i_visible_height
470                                       - p_filter->fmt_out.video.i_y_offset,
471                                     p_filter->fmt_out.video.i_x_offset,
472                                     p_filter->fmt_out.video.i_width
473                                       - p_filter->fmt_out.video.i_visible_width
474                                       - p_filter->fmt_out.video.i_x_offset,
475                                     padcolor);
476                 }
477             }
478
479             p_src = p_dst;
480         }
481     }
482
483     if( p_sys->b_convert )
484     {
485         video_format_t *p_fmt = &p_filter->fmt_out.video;
486         p_dst = &dest_pic;
487         if( p_sys->b_resize && !p_sys->b_resize_first )
488         {
489             p_dst = &p_sys->tmp_pic;
490             p_fmt = &p_filter->fmt_in.video;
491         }
492
493         img_convert( p_dst, p_sys->i_dst_ffmpeg_chroma,
494                      p_src, p_sys->i_src_ffmpeg_chroma,
495                      p_fmt->i_width, p_fmt->i_height );
496
497         p_src = p_dst;
498     }
499
500     if( p_sys->b_resize && !p_sys->b_resize_first && p_sys->p_rsc )
501     {
502         p_dst = &dest_pic;
503
504         img_resample( p_sys->p_rsc, p_dst, p_src );
505  
506         if (p_sys->b_enable_croppadd)
507         {
508             if (p_filter->fmt_out.video.i_visible_width != p_filter->fmt_out.video.i_width ||
509                 p_filter->fmt_out.video.i_visible_height != p_filter->fmt_out.video.i_height ||
510                 p_filter->fmt_out.video.i_x_offset != 0 ||
511                 p_filter->fmt_out.video.i_y_offset != 0)
512             {
513                 fill_pad_region(p_dst, p_filter->fmt_out.video.i_height,
514                                 p_filter->fmt_out.video.i_width,
515                                 p_filter->fmt_out.video.i_y_offset,
516                                 p_filter->fmt_out.video.i_height
517                                   - p_filter->fmt_out.video.i_visible_height
518                                   - p_filter->fmt_out.video.i_y_offset,
519                                 p_filter->fmt_out.video.i_x_offset,
520                                 p_filter->fmt_out.video.i_width
521                                   - p_filter->fmt_out.video.i_visible_width
522                                   - p_filter->fmt_out.video.i_x_offset,
523                                 padcolor);
524             }
525         }
526     }
527
528     /* Special case for RV32 -> YUVA */
529     if( !p_sys->b_resize &&
530         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('R','V','3','2') &&
531         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
532     {
533         uint8_t *p_src = p_pic->p[0].p_pixels;
534         int i_src_pitch = p_pic->p[0].i_pitch;
535         uint8_t *p_dst = p_pic_dst->p[3].p_pixels;
536         int i_dst_pitch = p_pic_dst->p[3].i_pitch;
537         uint32_t l,j;
538
539         for( l = 0; l < p_filter->fmt_out.video.i_height; l++ )
540         {
541             for( j = 0; j < p_filter->fmt_out.video.i_width; j++ )
542             {
543               p_dst[j] = p_src[j*4+3];
544             }
545             p_src += i_src_pitch;
546             p_dst += i_dst_pitch;
547         }
548     }
549     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
550     {
551         /* Special case for YUVA */
552         memset( p_pic_dst->p[3].p_pixels, 0xFF,
553                 p_pic_dst->p[3].i_pitch * p_pic_dst->p[3].i_lines );
554     }
555
556     p_pic_dst->date = p_pic->date;
557     p_pic_dst->b_force = p_pic->b_force;
558     p_pic_dst->i_nb_fields = p_pic->i_nb_fields;
559     p_pic_dst->b_progressive = p_pic->b_progressive;
560     p_pic_dst->b_top_field_first = p_pic->b_top_field_first;
561
562     p_pic->pf_release( p_pic );
563     return p_pic_dst;
564 }
565
566 /*****************************************************************************
567  * OpenDeinterlace: probe the filter and return score
568  *****************************************************************************/
569 int E_(OpenDeinterlace)( vlc_object_t *p_this )
570 {
571     filter_t *p_filter = (filter_t*)p_this;
572     filter_sys_t *p_sys;
573
574     /* Check if we can handle that formats */
575     if( E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ) < 0 )
576     {
577         return VLC_EGENERIC;
578     }
579
580     /* Allocate the memory needed to store the decoder's structure */
581     if( ( p_filter->p_sys = p_sys =
582           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
583     {
584         msg_Err( p_filter, "out of memory" );
585         return VLC_EGENERIC;
586     }
587
588     /* Misc init */
589     p_sys->i_src_ffmpeg_chroma =
590         E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma );
591     p_filter->pf_video_filter = Deinterlace;
592
593     msg_Dbg( p_filter, "deinterlacing" );
594
595     /* libavcodec needs to be initialized for some chroma conversions */
596     E_(InitLibavcodec)(p_this);
597
598     return VLC_SUCCESS;
599 }
600
601 /*****************************************************************************
602  * CloseDeinterlace: clean up the filter
603  *****************************************************************************/
604 void E_(CloseDeinterlace)( vlc_object_t *p_this )
605 {
606     filter_t *p_filter = (filter_t*)p_this;
607     filter_sys_t *p_sys = p_filter->p_sys;
608
609     free( p_sys );
610 }
611
612 /*****************************************************************************
613  * Do the processing here
614  *****************************************************************************/
615 static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
616 {
617     filter_sys_t *p_sys = p_filter->p_sys;
618     AVPicture src_pic, dest_pic;
619     picture_t *p_pic_dst;
620     int i;
621
622     /* Request output picture */
623     p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
624     if( !p_pic_dst )
625     {
626         msg_Warn( p_filter, "can't get output picture" );
627         return NULL;
628     }
629
630     /* Prepare the AVPictures for the conversion */
631     for( i = 0; i < p_pic->i_planes; i++ )
632     {
633         src_pic.data[i] = p_pic->p[i].p_pixels;
634         src_pic.linesize[i] = p_pic->p[i].i_pitch;
635     }
636     for( i = 0; i < p_pic_dst->i_planes; i++ )
637     {
638         dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
639         dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
640     }
641
642     avpicture_deinterlace( &dest_pic, &src_pic, p_sys->i_src_ffmpeg_chroma,
643                            p_filter->fmt_in.video.i_width,
644                            p_filter->fmt_in.video.i_height );
645
646     p_pic_dst->date = p_pic->date;
647     p_pic_dst->b_force = p_pic->b_force;
648     p_pic_dst->i_nb_fields = p_pic->i_nb_fields;
649     p_pic_dst->b_progressive = VLC_TRUE;
650     p_pic_dst->b_top_field_first = p_pic->b_top_field_first;
651
652     p_pic->pf_release( p_pic );
653     return p_pic_dst;
654 }
655
656 #endif /* ( (defined(HAVE_FFMPEG_SWSCALE_H) || defined(HAVE_LIBSWSCALE_TREE)) */