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
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 *****************************************************************************/
53 vlc_bool_t b_resize_first;
56 int i_src_ffmpeg_chroma;
58 int i_dst_ffmpeg_chroma;
61 ImgReSampleContext *p_rsc;
64 /*****************************************************************************
65 * OpenFilter: probe the filter and return score
66 *****************************************************************************/
67 int E_(OpenFilter)( vlc_object_t *p_this )
69 filter_t *p_filter = (filter_t*)p_this;
71 vlc_bool_t b_convert, b_resize;
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 )
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;
84 p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma;
86 if( !b_resize && !b_convert )
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 )
96 msg_Err( p_filter, "out of memory" );
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 /* 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 );
115 if( CheckInit( p_filter ) != VLC_SUCCESS )
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 );
127 /* libavcodec needs to be initialized for some chroma conversions */
128 E_(InitLibavcodec)(p_this);
133 /*****************************************************************************
134 * CloseFilter: clean up the filter
135 *****************************************************************************/
136 void E_(CloseFilter)( vlc_object_t *p_this )
138 filter_t *p_filter = (filter_t*)p_this;
139 filter_sys_t *p_sys = p_filter->p_sys;
141 if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
143 avpicture_free( &p_sys->tmp_pic );
148 /*****************************************************************************
149 * CheckInit: Initialise filter when necessary
150 *****************************************************************************/
151 static int CheckInit( filter_t *p_filter )
153 filter_sys_t *p_sys = p_filter->p_sys;
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 )
160 if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
164 p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma;
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;
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;
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 )
180 msg_Err( p_filter, "img_resample_init only deals with I420" );
183 else if( p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P &&
184 p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P )
186 p_sys->b_resize_first = VLC_FALSE;
188 else if( p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P &&
189 p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P )
191 p_sys->b_resize_first = VLC_TRUE;
194 if( p_sys->b_resize )
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 );
203 msg_Err( p_filter, "img_resample_init failed" );
208 avpicture_free( &p_sys->tmp_pic );
210 if( p_sys->b_resize_first )
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 );
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 );
225 p_sys->fmt_in = p_filter->fmt_in;
226 p_sys->fmt_out = p_filter->fmt_out;
232 /*****************************************************************************
233 * Do the processing here
234 *****************************************************************************/
235 static picture_t *Process( filter_t *p_filter, picture_t *p_pic )
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;
243 /* Check if format properties changed */
244 if( CheckInit( p_filter ) != VLC_SUCCESS ) return 0;
246 /* Request output picture */
247 p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
250 msg_Warn( p_filter, "can't get output picture" );
251 p_pic->pf_release( p_pic );
255 /* Prepare the AVPictures for the conversion */
256 for( i = 0; i < p_pic->i_planes; i++ )
258 src_pic.data[i] = p_pic->p[i].p_pixels;
259 src_pic.linesize[i] = p_pic->p[i].i_pitch;
261 for( i = 0; i < p_pic_dst->i_planes; i++ )
263 dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
264 dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
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') )
272 src_pic.data[1] = p_pic->p[2].p_pixels;
273 src_pic.data[2] = p_pic->p[1].p_pixels;
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') )
279 dest_pic.data[1] = p_pic_dst->p[2].p_pixels;
280 dest_pic.data[2] = p_pic_dst->p[1].p_pixels;
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;
288 if( p_sys->b_resize && p_sys->p_rsc )
291 if( p_sys->b_resize_first )
293 if( p_sys->b_convert ) p_dst = &p_sys->tmp_pic;
294 img_resample( p_sys->p_rsc, p_dst, p_src );
299 if( p_sys->b_convert )
301 video_format_t *p_fmt = &p_filter->fmt_out.video;
303 if( p_sys->b_resize && !p_sys->b_resize_first )
305 p_dst = &p_sys->tmp_pic;
306 p_fmt = &p_filter->fmt_in.video;
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 );
316 if( p_sys->b_resize && !p_sys->b_resize_first && p_sys->p_rsc )
319 img_resample( p_sys->p_rsc, p_dst, p_src );
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') )
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;
333 for( l = 0; l < p_filter->fmt_out.video.i_height; l++ )
335 for( j = 0; j < p_filter->fmt_out.video.i_width; j++ )
337 p_dst[j] = p_src[j*4+3];
339 p_src += i_src_pitch;
340 p_dst += i_dst_pitch;
343 else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
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 );
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;
356 p_pic->pf_release( p_pic );
360 /*****************************************************************************
361 * OpenDeinterlace: probe the filter and return score
362 *****************************************************************************/
363 int E_(OpenDeinterlace)( vlc_object_t *p_this )
365 filter_t *p_filter = (filter_t*)p_this;
368 /* Check if we can handle that formats */
369 if( E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ) < 0 )
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 )
378 msg_Err( p_filter, "out of memory" );
383 p_sys->i_src_ffmpeg_chroma =
384 E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma );
385 p_filter->pf_video_filter = Deinterlace;
387 msg_Dbg( p_filter, "deinterlacing" );
389 /* libavcodec needs to be initialized for some chroma conversions */
390 E_(InitLibavcodec)(p_this);
395 /*****************************************************************************
396 * CloseDeinterlace: clean up the filter
397 *****************************************************************************/
398 void E_(CloseDeinterlace)( vlc_object_t *p_this )
400 filter_t *p_filter = (filter_t*)p_this;
401 filter_sys_t *p_sys = p_filter->p_sys;
406 /*****************************************************************************
407 * Do the processing here
408 *****************************************************************************/
409 static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
411 filter_sys_t *p_sys = p_filter->p_sys;
412 AVPicture src_pic, dest_pic;
413 picture_t *p_pic_dst;
416 /* Request output picture */
417 p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
420 msg_Warn( p_filter, "can't get output picture" );
424 /* Prepare the AVPictures for the conversion */
425 for( i = 0; i < p_pic->i_planes; i++ )
427 src_pic.data[i] = p_pic->p[i].p_pixels;
428 src_pic.linesize[i] = p_pic->p[i].i_pitch;
430 for( i = 0; i < p_pic_dst->i_planes; i++ )
432 dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
433 dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
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 );
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;
446 p_pic->pf_release( p_pic );