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