]> git.sesse.net Git - vlc/blob - modules/codec/ffmpeg/video_filter.c
f533f2900afcf5bef10b033a253358697efb6554
[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 VideoLAN (Centrale Réseaux) and its contributors
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., 59 Temple Place - Suite 330, Boston, MA  02111, 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 void E_(InitLibavcodec) ( vlc_object_t *p_object );
42 static int CheckInit( filter_t *p_filter );
43 static picture_t *Process( filter_t *p_filter, picture_t *p_pic );
44 static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic );
45
46 /*****************************************************************************
47  * filter_sys_t : filter descriptor
48  *****************************************************************************/
49 struct filter_sys_t
50 {
51     vlc_bool_t b_resize;
52     vlc_bool_t b_convert;
53     vlc_bool_t b_resize_first;
54
55     es_format_t fmt_in;
56     int i_src_ffmpeg_chroma;
57     es_format_t fmt_out;
58     int i_dst_ffmpeg_chroma;
59
60     AVPicture tmp_pic;
61     ImgReSampleContext *p_rsc;
62 };
63
64 /*****************************************************************************
65  * OpenFilter: probe the filter and return score
66  *****************************************************************************/
67 int E_(OpenFilter)( vlc_object_t *p_this )
68 {
69     filter_t *p_filter = (filter_t*)p_this;
70     filter_sys_t *p_sys;
71     vlc_bool_t b_convert, b_resize;
72
73     /* Check if we can handle that formats */
74     if( E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ) < 0 ||
75         E_(GetFfmpegChroma)( p_filter->fmt_out.video.i_chroma ) < 0 )
76     {
77         return VLC_EGENERIC;
78     }
79
80     b_resize =
81         p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ||
82         p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height;
83     b_convert =
84         p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma;
85
86     if( !b_resize && !b_convert )
87     {
88         /* Nothing to do */
89         return VLC_EGENERIC;
90     }
91
92     /* Allocate the memory needed to store the decoder's structure */
93     if( ( p_filter->p_sys = p_sys =
94           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
95     {
96         msg_Err( p_filter, "out of memory" );
97         return VLC_EGENERIC;
98     }
99
100     /* Misc init */
101     p_sys->p_rsc = NULL;
102     p_sys->i_src_ffmpeg_chroma =
103         E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma );
104     p_sys->i_dst_ffmpeg_chroma =
105         E_(GetFfmpegChroma)( p_filter->fmt_out.video.i_chroma );
106     p_filter->pf_video_filter = Process;
107     es_format_Init( &p_sys->fmt_in, 0, 0 );
108     es_format_Init( &p_sys->fmt_out, 0, 0 );
109
110     /* Dummy alloc, will be reallocated in CheckInit */
111     avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma,
112                      p_filter->fmt_out.video.i_width,
113                      p_filter->fmt_out.video.i_height );
114
115     if( CheckInit( p_filter ) != VLC_SUCCESS )
116     {
117         free( p_sys );
118         return VLC_EGENERIC;
119     }
120
121     msg_Dbg( p_filter, "input: %ix%i %4.4s -> %ix%i %4.4s",
122              p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
123              (char *)&p_filter->fmt_in.video.i_chroma,
124              p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
125              (char *)&p_filter->fmt_out.video.i_chroma );
126
127     /* libavcodec needs to be initialized for some chroma conversions */
128     E_(InitLibavcodec)(p_this);
129
130     return VLC_SUCCESS;
131 }
132
133 /*****************************************************************************
134  * CloseFilter: clean up the filter
135  *****************************************************************************/
136 void E_(CloseFilter)( vlc_object_t *p_this )
137 {
138     filter_t *p_filter = (filter_t*)p_this;
139     filter_sys_t *p_sys = p_filter->p_sys;
140
141     if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
142
143     avpicture_free( &p_sys->tmp_pic );
144
145     free( p_sys );
146 }
147
148 /*****************************************************************************
149  * CheckInit: Initialise filter when necessary
150  *****************************************************************************/
151 static int CheckInit( filter_t *p_filter )
152 {
153     filter_sys_t *p_sys = p_filter->p_sys;
154
155     if( p_filter->fmt_in.video.i_width != p_sys->fmt_in.video.i_width ||
156         p_filter->fmt_in.video.i_height != p_sys->fmt_in.video.i_height ||
157         p_filter->fmt_out.video.i_width != p_sys->fmt_out.video.i_width ||
158         p_filter->fmt_out.video.i_height != p_sys->fmt_out.video.i_height )
159     {
160         if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
161         p_sys->p_rsc = 0;
162
163         p_sys->b_convert =
164           p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma;
165
166         p_sys->b_resize =
167           p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ||
168           p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height;
169
170         p_sys->b_resize_first =
171           p_filter->fmt_in.video.i_width * p_filter->fmt_in.video.i_height >
172           p_filter->fmt_out.video.i_width * p_filter->fmt_out.video.i_height;
173
174         if( p_sys->b_resize &&
175             p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P &&
176             p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P &&
177             p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P &&
178             p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P )
179         {
180             msg_Err( p_filter, "img_resample_init only deals with I420" );
181             return VLC_EGENERIC;
182         }
183         else if( p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P &&
184                  p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P )
185         {
186             p_sys->b_resize_first = VLC_FALSE;
187         }
188         else if( p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P &&
189                  p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P )
190         {
191             p_sys->b_resize_first = VLC_TRUE;
192         }
193
194         if( p_sys->b_resize )
195         {
196             p_sys->p_rsc = img_resample_init( p_filter->fmt_out.video.i_width,
197                                p_filter->fmt_out.video.i_height,
198                                p_filter->fmt_in.video.i_width,
199                                p_filter->fmt_in.video.i_height );
200
201             if( !p_sys->p_rsc )
202             {
203                 msg_Err( p_filter, "img_resample_init failed" );
204                 return VLC_EGENERIC;
205             }
206         }
207
208         avpicture_free( &p_sys->tmp_pic );
209
210         if( p_sys->b_resize_first )
211         {
212             /* Resizing then conversion */
213             avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma,
214                              p_filter->fmt_out.video.i_width,
215                              p_filter->fmt_out.video.i_height );
216         }
217         else
218         {
219             /* Conversion then resizing */
220             avpicture_alloc( &p_sys->tmp_pic, p_sys->i_dst_ffmpeg_chroma,
221                              p_filter->fmt_in.video.i_width,
222                              p_filter->fmt_in.video.i_height );
223         }
224
225         p_sys->fmt_in = p_filter->fmt_in;
226         p_sys->fmt_out = p_filter->fmt_out;
227     }
228
229     return VLC_SUCCESS;
230 }
231
232 /*****************************************************************************
233  * Do the processing here
234  *****************************************************************************/
235 static picture_t *Process( filter_t *p_filter, picture_t *p_pic )
236 {
237     filter_sys_t *p_sys = p_filter->p_sys;
238     AVPicture src_pic, dest_pic;
239     AVPicture *p_src, *p_dst;
240     picture_t *p_pic_dst;
241     int i;
242
243     /* Check if format properties changed */
244     if( CheckInit( p_filter ) != VLC_SUCCESS ) return 0;
245
246     /* Request output picture */
247     p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
248     if( !p_pic_dst )
249     {
250         msg_Warn( p_filter, "can't get output picture" );
251         p_pic->pf_release( p_pic );
252         return NULL;
253     }
254
255     /* Prepare the AVPictures for the conversion */
256     for( i = 0; i < p_pic->i_planes; i++ )
257     {
258         src_pic.data[i] = p_pic->p[i].p_pixels;
259         src_pic.linesize[i] = p_pic->p[i].i_pitch;
260     }
261     for( i = 0; i < p_pic_dst->i_planes; i++ )
262     {
263         dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
264         dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
265     }
266
267     /* Special cases */
268     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
269         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','U','9') )
270     {
271         /* Invert U and V */
272         src_pic.data[1] = p_pic->p[2].p_pixels;
273         src_pic.data[2] = p_pic->p[1].p_pixels;
274     }
275     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
276         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','U','9') )
277     {
278         /* Invert U and V */
279         dest_pic.data[1] = p_pic_dst->p[2].p_pixels;
280         dest_pic.data[2] = p_pic_dst->p[1].p_pixels;
281     }
282     if( p_sys->i_src_ffmpeg_chroma == PIX_FMT_RGB24 )
283         if( p_filter->fmt_in.video.i_bmask == 0x00ff0000 )
284             p_sys->i_src_ffmpeg_chroma = PIX_FMT_BGR24;
285
286     p_src = &src_pic;
287
288     if( p_sys->b_resize && p_sys->p_rsc )
289     {
290         p_dst = &dest_pic;
291         if( p_sys->b_resize_first )
292         {
293             if( p_sys->b_convert ) p_dst = &p_sys->tmp_pic;
294             img_resample( p_sys->p_rsc, p_dst, p_src );
295             p_src = p_dst;
296         }
297     }
298
299     if( p_sys->b_convert )
300     {
301         video_format_t *p_fmt = &p_filter->fmt_out.video;
302         p_dst = &dest_pic;
303         if( p_sys->b_resize && !p_sys->b_resize_first )
304         {
305             p_dst = &p_sys->tmp_pic;
306             p_fmt = &p_filter->fmt_in.video;
307         }
308
309         img_convert( p_dst, p_sys->i_dst_ffmpeg_chroma,
310                      p_src, p_sys->i_src_ffmpeg_chroma,
311                      p_fmt->i_width, p_fmt->i_height );
312
313         p_src = p_dst;
314     }
315
316     if( p_sys->b_resize && !p_sys->b_resize_first && p_sys->p_rsc )
317     {
318         p_dst = &dest_pic;
319         img_resample( p_sys->p_rsc, p_dst, p_src );
320     }
321
322     /* Special case for RV32 -> YUVA */
323     if( !p_sys->b_resize &&
324         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('R','V','3','2') &&
325         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
326     {
327         uint8_t *p_src = p_pic->p[0].p_pixels;
328         int i_src_pitch = p_pic->p[0].i_pitch;
329         uint8_t *p_dst = p_pic_dst->p[3].p_pixels;
330         int i_dst_pitch = p_pic_dst->p[3].i_pitch;
331         int j;
332
333         for( i = 0; i < p_filter->fmt_out.video.i_height; i++ )
334         {
335             for( j = 0; j < p_filter->fmt_out.video.i_width; j++ )
336             {
337               p_dst[j] = p_src[j*4+3];
338             }
339             p_src += i_src_pitch;
340             p_dst += i_dst_pitch;
341         }
342     }
343     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
344     {
345         /* Special case for YUVA */
346         memset( p_pic_dst->p[3].p_pixels, 0xFF,
347                 p_pic_dst->p[3].i_pitch * p_pic_dst->p[3].i_lines );
348     }
349
350     p_pic_dst->date = p_pic->date;
351     p_pic_dst->b_force = p_pic->b_force;
352     p_pic_dst->i_nb_fields = p_pic->i_nb_fields;
353     p_pic_dst->b_progressive = p_pic->b_progressive;
354     p_pic_dst->b_top_field_first = p_pic->b_top_field_first;
355
356     p_pic->pf_release( p_pic );
357     return p_pic_dst;
358 }
359
360 /*****************************************************************************
361  * OpenDeinterlace: probe the filter and return score
362  *****************************************************************************/
363 int E_(OpenDeinterlace)( vlc_object_t *p_this )
364 {
365     filter_t *p_filter = (filter_t*)p_this;
366     filter_sys_t *p_sys;
367
368     /* Check if we can handle that formats */
369     if( E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ) < 0 )
370     {
371         return VLC_EGENERIC;
372     }
373
374     /* Allocate the memory needed to store the decoder's structure */
375     if( ( p_filter->p_sys = p_sys =
376           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
377     {
378         msg_Err( p_filter, "out of memory" );
379         return VLC_EGENERIC;
380     }
381
382     /* Misc init */
383     p_sys->i_src_ffmpeg_chroma =
384         E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma );
385     p_filter->pf_video_filter = Deinterlace;
386
387     msg_Dbg( p_filter, "deinterlacing" );
388
389     /* libavcodec needs to be initialized for some chroma conversions */
390     E_(InitLibavcodec)(p_this);
391
392     return VLC_SUCCESS;
393 }
394
395 /*****************************************************************************
396  * CloseDeinterlace: clean up the filter
397  *****************************************************************************/
398 void E_(CloseDeinterlace)( vlc_object_t *p_this )
399 {
400     filter_t *p_filter = (filter_t*)p_this;
401     filter_sys_t *p_sys = p_filter->p_sys;
402
403     free( p_sys );
404 }
405
406 /*****************************************************************************
407  * Do the processing here
408  *****************************************************************************/
409 static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
410 {
411     filter_sys_t *p_sys = p_filter->p_sys;
412     AVPicture src_pic, dest_pic;
413     picture_t *p_pic_dst;
414     int i;
415
416     /* Request output picture */
417     p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
418     if( !p_pic_dst )
419     {
420         msg_Warn( p_filter, "can't get output picture" );
421         return NULL;
422     }
423
424     /* Prepare the AVPictures for the conversion */
425     for( i = 0; i < p_pic->i_planes; i++ )
426     {
427         src_pic.data[i] = p_pic->p[i].p_pixels;
428         src_pic.linesize[i] = p_pic->p[i].i_pitch;
429     }
430     for( i = 0; i < p_pic_dst->i_planes; i++ )
431     {
432         dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
433         dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
434     }
435
436     avpicture_deinterlace( &dest_pic, &src_pic, p_sys->i_src_ffmpeg_chroma,
437                            p_filter->fmt_in.video.i_width,
438                            p_filter->fmt_in.video.i_height );
439
440     p_pic_dst->date = p_pic->date;
441     p_pic_dst->b_force = p_pic->b_force;
442     p_pic_dst->i_nb_fields = p_pic->i_nb_fields;
443     p_pic_dst->b_progressive = VLC_TRUE;
444     p_pic_dst->b_top_field_first = p_pic->b_top_field_first;
445
446     p_pic->pf_release( p_pic );
447     return p_pic_dst;
448 }