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