1 /*****************************************************************************
2 * video filter: video filter doing chroma conversion and resizing
3 * using the ffmpeg library
4 *****************************************************************************
5 * Copyright (C) 1999-2001 VideoLAN
8 * Authors: Gildas Bazin <gbazin@videolan.org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
29 #include <vlc/decoder.h>
30 #include "vlc_filter.h"
33 #ifdef HAVE_FFMPEG_AVCODEC_H
34 # include <ffmpeg/avcodec.h>
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 );
46 /*****************************************************************************
47 * filter_sys_t : filter descriptor
48 *****************************************************************************/
55 int i_src_ffmpeg_chroma;
57 int i_dst_ffmpeg_chroma;
60 ImgReSampleContext *p_rsc;
63 /*****************************************************************************
64 * OpenFilter: probe the filter and return score
65 *****************************************************************************/
66 int E_(OpenFilter)( vlc_object_t *p_this )
68 filter_t *p_filter = (filter_t*)p_this;
70 vlc_bool_t b_convert, b_resize;
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 )
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;
83 p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma;
85 if( !b_resize && !b_convert )
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 )
95 msg_Err( p_filter, "out of memory" );
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 );
110 if( CheckInit( p_filter ) != VLC_SUCCESS )
116 if( p_sys->b_resize && p_sys->b_convert )
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 )
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 );
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 );
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 );
141 /* libavcodec needs to be initialized for some chroma conversions */
142 E_(InitLibavcodec)(p_this);
147 /*****************************************************************************
148 * CloseFilter: clean up the filter
149 *****************************************************************************/
150 void E_(CloseFilter)( vlc_object_t *p_this )
152 filter_t *p_filter = (filter_t*)p_this;
153 filter_sys_t *p_sys = p_filter->p_sys;
155 if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
157 avpicture_free( &p_sys->tmp_pic );
162 /*****************************************************************************
163 * CheckInit: Initialise filter when necessary
164 *****************************************************************************/
165 static int CheckInit( filter_t *p_filter )
167 filter_sys_t *p_sys = p_filter->p_sys;
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 )
174 if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
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;
181 if( p_sys->b_resize )
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 );
190 msg_Err( p_filter, "img_resample_init failed" );
195 p_sys->fmt_in = p_filter->fmt_in;
196 p_sys->fmt_out = p_filter->fmt_out;
202 /*****************************************************************************
203 * Do the processing here
204 *****************************************************************************/
205 static picture_t *Process( filter_t *p_filter, picture_t *p_pic )
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;
214 /* Check if format properties changed */
215 if( CheckInit( p_filter ) != VLC_SUCCESS ) return 0;
217 /* Request output picture */
218 p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
221 msg_Warn( p_filter, "can't get output picture" );
222 p_pic->pf_release( p_pic );
226 /* Prepare the AVPictures for the conversion */
227 for( i = 0; i < p_pic->i_planes; i++ )
229 src_pic.data[i] = p_pic->p[i].p_pixels;
230 src_pic.linesize[i] = p_pic->p[i].i_pitch;
232 for( i = 0; i < p_pic_dst->i_planes; i++ )
234 dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
235 dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
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') )
243 src_pic.data[1] = p_pic->p[2].p_pixels;
244 src_pic.data[2] = p_pic->p[1].p_pixels;
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') )
250 dest_pic.data[1] = p_pic_dst->p[2].p_pixels;
251 dest_pic.data[2] = p_pic_dst->p[1].p_pixels;
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;
259 if( b_resize && p_sys->p_rsc )
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 )
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;
272 if( p_sys->b_convert )
274 video_format_t *p_fmt = &p_filter->fmt_out.video;
278 p_dst = &p_sys->tmp_pic;
279 p_fmt = &p_filter->fmt_in.video;
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 );
289 if( b_resize && p_sys->p_rsc )
292 img_resample( p_sys->p_rsc, p_dst, p_src );
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') )
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;
306 for( i = 0; i < p_filter->fmt_out.video.i_height; i++ )
308 for( j = 0; j < p_filter->fmt_out.video.i_width; j++ )
310 p_dst[j] = p_src[j*4+3];
312 p_src += i_src_pitch;
313 p_dst += i_dst_pitch;
316 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
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 );
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;
329 p_pic->pf_release( p_pic );
333 /*****************************************************************************
334 * OpenDeinterlace: probe the filter and return score
335 *****************************************************************************/
336 int E_(OpenDeinterlace)( vlc_object_t *p_this )
338 filter_t *p_filter = (filter_t*)p_this;
341 /* Check if we can handle that formats */
342 if( E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ) < 0 )
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 )
351 msg_Err( p_filter, "out of memory" );
356 p_sys->i_src_ffmpeg_chroma =
357 E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma );
358 p_filter->pf_video_filter = Deinterlace;
360 msg_Dbg( p_filter, "deinterlacing" );
362 /* libavcodec needs to be initialized for some chroma conversions */
363 E_(InitLibavcodec)(p_this);
368 /*****************************************************************************
369 * CloseDeinterlace: clean up the filter
370 *****************************************************************************/
371 void E_(CloseDeinterlace)( vlc_object_t *p_this )
373 filter_t *p_filter = (filter_t*)p_this;
374 filter_sys_t *p_sys = p_filter->p_sys;
379 /*****************************************************************************
380 * Do the processing here
381 *****************************************************************************/
382 static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
384 filter_sys_t *p_sys = p_filter->p_sys;
385 AVPicture src_pic, dest_pic;
386 picture_t *p_pic_dst;
389 /* Request output picture */
390 p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
393 msg_Warn( p_filter, "can't get output picture" );
397 /* Prepare the AVPictures for the conversion */
398 for( i = 0; i < p_pic->i_planes; i++ )
400 src_pic.data[i] = p_pic->p[i].p_pixels;
401 src_pic.linesize[i] = p_pic->p[i].i_pitch;
403 for( i = 0; i < p_pic_dst->i_planes; i++ )
405 dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
406 dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
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 );
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;
419 p_pic->pf_release( p_pic );