Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

video_filter.c

00001 /*****************************************************************************
00002  * video filter: video filter doing chroma conversion and resizing
00003  *               using the ffmpeg library
00004  *****************************************************************************
00005  * Copyright (C) 1999-2001 the VideoLAN team
00006  * $Id: video_filter.c 12082 2005-08-09 13:42:11Z jpsaman $
00007  *
00008  * Authors: Gildas Bazin <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <vlc/vlc.h>
00029 #include <vlc/decoder.h>
00030 #include "vlc_filter.h"
00031 
00032 /* ffmpeg header */
00033 #ifdef HAVE_FFMPEG_AVCODEC_H
00034 #   include <ffmpeg/avcodec.h>
00035 #else
00036 #   include <avcodec.h>
00037 #endif
00038 
00039 #include "ffmpeg.h"
00040 
00041 void E_(InitLibavcodec) ( vlc_object_t *p_object );
00042 static int CheckInit( filter_t *p_filter );
00043 static picture_t *Process( filter_t *p_filter, picture_t *p_pic );
00044 static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic );
00045 
00046 /*****************************************************************************
00047  * filter_sys_t : filter descriptor
00048  *****************************************************************************/
00049 struct filter_sys_t
00050 {
00051     vlc_bool_t b_resize;
00052     vlc_bool_t b_convert;
00053     vlc_bool_t b_resize_first;
00054 
00055     es_format_t fmt_in;
00056     int i_src_ffmpeg_chroma;
00057     es_format_t fmt_out;
00058     int i_dst_ffmpeg_chroma;
00059 
00060     AVPicture tmp_pic;
00061     ImgReSampleContext *p_rsc;
00062 };
00063 
00064 /*****************************************************************************
00065  * OpenFilter: probe the filter and return score
00066  *****************************************************************************/
00067 int E_(OpenFilter)( vlc_object_t *p_this )
00068 {
00069     filter_t *p_filter = (filter_t*)p_this;
00070     filter_sys_t *p_sys;
00071     vlc_bool_t b_convert, b_resize;
00072 
00073     /* Check if we can handle that formats */
00074     if( E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ) < 0 ||
00075         E_(GetFfmpegChroma)( p_filter->fmt_out.video.i_chroma ) < 0 )
00076     {
00077         return VLC_EGENERIC;
00078     }
00079 
00080     b_resize =
00081         p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ||
00082         p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height;
00083     b_convert =
00084         p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma;
00085 
00086     if( !b_resize && !b_convert )
00087     {
00088         /* Nothing to do */
00089         return VLC_EGENERIC;
00090     }
00091 
00092     /* Allocate the memory needed to store the decoder's structure */
00093     if( ( p_filter->p_sys = p_sys =
00094           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
00095     {
00096         msg_Err( p_filter, "out of memory" );
00097         return VLC_EGENERIC;
00098     }
00099 
00100     /* Misc init */
00101     p_sys->p_rsc = NULL;
00102     p_sys->i_src_ffmpeg_chroma =
00103         E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma );
00104     p_sys->i_dst_ffmpeg_chroma =
00105         E_(GetFfmpegChroma)( p_filter->fmt_out.video.i_chroma );
00106     p_filter->pf_video_filter = Process;
00107     es_format_Init( &p_sys->fmt_in, 0, 0 );
00108     es_format_Init( &p_sys->fmt_out, 0, 0 );
00109 
00110     /* Dummy alloc, will be reallocated in CheckInit */
00111     avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma,
00112                      p_filter->fmt_out.video.i_width,
00113                      p_filter->fmt_out.video.i_height );
00114 
00115     if( CheckInit( p_filter ) != VLC_SUCCESS )
00116     {
00117         free( p_sys );
00118         return VLC_EGENERIC;
00119     }
00120 
00121     msg_Dbg( p_filter, "input: %ix%i %4.4s -> %ix%i %4.4s",
00122              p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height,
00123              (char *)&p_filter->fmt_in.video.i_chroma,
00124              p_filter->fmt_out.video.i_width, p_filter->fmt_out.video.i_height,
00125              (char *)&p_filter->fmt_out.video.i_chroma );
00126 
00127     /* libavcodec needs to be initialized for some chroma conversions */
00128     E_(InitLibavcodec)(p_this);
00129 
00130     return VLC_SUCCESS;
00131 }
00132 
00133 /*****************************************************************************
00134  * CloseFilter: clean up the filter
00135  *****************************************************************************/
00136 void E_(CloseFilter)( vlc_object_t *p_this )
00137 {
00138     filter_t *p_filter = (filter_t*)p_this;
00139     filter_sys_t *p_sys = p_filter->p_sys;
00140 
00141     if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
00142 
00143     avpicture_free( &p_sys->tmp_pic );
00144 
00145     free( p_sys );
00146 }
00147 
00148 /*****************************************************************************
00149  * CheckInit: Initialise filter when necessary
00150  *****************************************************************************/
00151 static int CheckInit( filter_t *p_filter )
00152 {
00153     filter_sys_t *p_sys = p_filter->p_sys;
00154 
00155     if( p_filter->fmt_in.video.i_width != p_sys->fmt_in.video.i_width ||
00156         p_filter->fmt_in.video.i_height != p_sys->fmt_in.video.i_height ||
00157         p_filter->fmt_out.video.i_width != p_sys->fmt_out.video.i_width ||
00158         p_filter->fmt_out.video.i_height != p_sys->fmt_out.video.i_height )
00159     {
00160         if( p_sys->p_rsc ) img_resample_close( p_sys->p_rsc );
00161         p_sys->p_rsc = 0;
00162 
00163         p_sys->b_convert =
00164           p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma;
00165 
00166         p_sys->b_resize =
00167           p_filter->fmt_in.video.i_width != p_filter->fmt_out.video.i_width ||
00168           p_filter->fmt_in.video.i_height != p_filter->fmt_out.video.i_height;
00169 
00170         p_sys->b_resize_first =
00171           p_filter->fmt_in.video.i_width * p_filter->fmt_in.video.i_height >
00172           p_filter->fmt_out.video.i_width * p_filter->fmt_out.video.i_height;
00173 
00174         if( p_sys->b_resize &&
00175             p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P &&
00176             p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P &&
00177             p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P &&
00178             p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P )
00179         {
00180             msg_Err( p_filter, "img_resample_init only deals with I420" );
00181             return VLC_EGENERIC;
00182         }
00183         else if( p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUV420P &&
00184                  p_sys->i_src_ffmpeg_chroma != PIX_FMT_YUVJ420P )
00185         {
00186             p_sys->b_resize_first = VLC_FALSE;
00187         }
00188         else if( p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUV420P &&
00189                  p_sys->i_dst_ffmpeg_chroma != PIX_FMT_YUVJ420P )
00190         {
00191             p_sys->b_resize_first = VLC_TRUE;
00192         }
00193 
00194         if( p_sys->b_resize )
00195         {
00196             p_sys->p_rsc = img_resample_init( p_filter->fmt_out.video.i_width,
00197                                p_filter->fmt_out.video.i_height,
00198                                p_filter->fmt_in.video.i_width,
00199                                p_filter->fmt_in.video.i_height );
00200 
00201             if( !p_sys->p_rsc )
00202             {
00203                 msg_Err( p_filter, "img_resample_init failed" );
00204                 return VLC_EGENERIC;
00205             }
00206         }
00207 
00208         avpicture_free( &p_sys->tmp_pic );
00209 
00210         if( p_sys->b_resize_first )
00211         {
00212             /* Resizing then conversion */
00213             avpicture_alloc( &p_sys->tmp_pic, p_sys->i_src_ffmpeg_chroma,
00214                              p_filter->fmt_out.video.i_width,
00215                              p_filter->fmt_out.video.i_height );
00216         }
00217         else
00218         {
00219             /* Conversion then resizing */
00220             avpicture_alloc( &p_sys->tmp_pic, p_sys->i_dst_ffmpeg_chroma,
00221                              p_filter->fmt_in.video.i_width,
00222                              p_filter->fmt_in.video.i_height );
00223         }
00224 
00225         p_sys->fmt_in = p_filter->fmt_in;
00226         p_sys->fmt_out = p_filter->fmt_out;
00227     }
00228 
00229     return VLC_SUCCESS;
00230 }
00231 
00232 /*****************************************************************************
00233  * Do the processing here
00234  *****************************************************************************/
00235 static picture_t *Process( filter_t *p_filter, picture_t *p_pic )
00236 {
00237     filter_sys_t *p_sys = p_filter->p_sys;
00238     AVPicture src_pic, dest_pic;
00239     AVPicture *p_src, *p_dst;
00240     picture_t *p_pic_dst;
00241     int i;
00242 
00243     /* Check if format properties changed */
00244     if( CheckInit( p_filter ) != VLC_SUCCESS ) return 0;
00245 
00246     /* Request output picture */
00247     p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
00248     if( !p_pic_dst )
00249     {
00250         msg_Warn( p_filter, "can't get output picture" );
00251         p_pic->pf_release( p_pic );
00252         return NULL;
00253     }
00254 
00255     /* Prepare the AVPictures for the conversion */
00256     for( i = 0; i < p_pic->i_planes; i++ )
00257     {
00258         src_pic.data[i] = p_pic->p[i].p_pixels;
00259         src_pic.linesize[i] = p_pic->p[i].i_pitch;
00260     }
00261     for( i = 0; i < p_pic_dst->i_planes; i++ )
00262     {
00263         dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
00264         dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
00265     }
00266 
00267     /* Special cases */
00268     if( p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
00269         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('Y','V','U','9') )
00270     {
00271         /* Invert U and V */
00272         src_pic.data[1] = p_pic->p[2].p_pixels;
00273         src_pic.data[2] = p_pic->p[1].p_pixels;
00274     }
00275     if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','1','2') ||
00276         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','V','U','9') )
00277     {
00278         /* Invert U and V */
00279         dest_pic.data[1] = p_pic_dst->p[2].p_pixels;
00280         dest_pic.data[2] = p_pic_dst->p[1].p_pixels;
00281     }
00282     if( p_sys->i_src_ffmpeg_chroma == PIX_FMT_RGB24 )
00283         if( p_filter->fmt_in.video.i_bmask == 0x00ff0000 )
00284             p_sys->i_src_ffmpeg_chroma = PIX_FMT_BGR24;
00285 
00286     p_src = &src_pic;
00287 
00288     if( p_sys->b_resize && p_sys->p_rsc )
00289     {
00290         p_dst = &dest_pic;
00291         if( p_sys->b_resize_first )
00292         {
00293             if( p_sys->b_convert ) p_dst = &p_sys->tmp_pic;
00294             img_resample( p_sys->p_rsc, p_dst, p_src );
00295             p_src = p_dst;
00296         }
00297     }
00298 
00299     if( p_sys->b_convert )
00300     {
00301         video_format_t *p_fmt = &p_filter->fmt_out.video;
00302         p_dst = &dest_pic;
00303         if( p_sys->b_resize && !p_sys->b_resize_first )
00304         {
00305             p_dst = &p_sys->tmp_pic;
00306             p_fmt = &p_filter->fmt_in.video;
00307         }
00308 
00309         img_convert( p_dst, p_sys->i_dst_ffmpeg_chroma,
00310                      p_src, p_sys->i_src_ffmpeg_chroma,
00311                      p_fmt->i_width, p_fmt->i_height );
00312 
00313         p_src = p_dst;
00314     }
00315 
00316     if( p_sys->b_resize && !p_sys->b_resize_first && p_sys->p_rsc )
00317     {
00318         p_dst = &dest_pic;
00319         img_resample( p_sys->p_rsc, p_dst, p_src );
00320     }
00321 
00322     /* Special case for RV32 -> YUVA */
00323     if( !p_sys->b_resize &&
00324         p_filter->fmt_in.video.i_chroma == VLC_FOURCC('R','V','3','2') &&
00325         p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
00326     {
00327         uint8_t *p_src = p_pic->p[0].p_pixels;
00328         int i_src_pitch = p_pic->p[0].i_pitch;
00329         uint8_t *p_dst = p_pic_dst->p[3].p_pixels;
00330         int i_dst_pitch = p_pic_dst->p[3].i_pitch;
00331         uint32_t l,j;
00332 
00333         for( l = 0; l < p_filter->fmt_out.video.i_height; l++ )
00334         {
00335             for( j = 0; j < p_filter->fmt_out.video.i_width; j++ )
00336             {
00337               p_dst[j] = p_src[j*4+3];
00338             }
00339             p_src += i_src_pitch;
00340             p_dst += i_dst_pitch;
00341         }
00342     }
00343     else if( p_filter->fmt_out.video.i_chroma == VLC_FOURCC('Y','U','V','A') )
00344     {
00345         /* Special case for YUVA */
00346         memset( p_pic_dst->p[3].p_pixels, 0xFF,
00347                 p_pic_dst->p[3].i_pitch * p_pic_dst->p[3].i_lines );
00348     }
00349 
00350     p_pic_dst->date = p_pic->date;
00351     p_pic_dst->b_force = p_pic->b_force;
00352     p_pic_dst->i_nb_fields = p_pic->i_nb_fields;
00353     p_pic_dst->b_progressive = p_pic->b_progressive;
00354     p_pic_dst->b_top_field_first = p_pic->b_top_field_first;
00355 
00356     p_pic->pf_release( p_pic );
00357     return p_pic_dst;
00358 }
00359 
00360 /*****************************************************************************
00361  * OpenDeinterlace: probe the filter and return score
00362  *****************************************************************************/
00363 int E_(OpenDeinterlace)( vlc_object_t *p_this )
00364 {
00365     filter_t *p_filter = (filter_t*)p_this;
00366     filter_sys_t *p_sys;
00367 
00368     /* Check if we can handle that formats */
00369     if( E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ) < 0 )
00370     {
00371         return VLC_EGENERIC;
00372     }
00373 
00374     /* Allocate the memory needed to store the decoder's structure */
00375     if( ( p_filter->p_sys = p_sys =
00376           (filter_sys_t *)malloc(sizeof(filter_sys_t)) ) == NULL )
00377     {
00378         msg_Err( p_filter, "out of memory" );
00379         return VLC_EGENERIC;
00380     }
00381 
00382     /* Misc init */
00383     p_sys->i_src_ffmpeg_chroma =
00384         E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma );
00385     p_filter->pf_video_filter = Deinterlace;
00386 
00387     msg_Dbg( p_filter, "deinterlacing" );
00388 
00389     /* libavcodec needs to be initialized for some chroma conversions */
00390     E_(InitLibavcodec)(p_this);
00391 
00392     return VLC_SUCCESS;
00393 }
00394 
00395 /*****************************************************************************
00396  * CloseDeinterlace: clean up the filter
00397  *****************************************************************************/
00398 void E_(CloseDeinterlace)( vlc_object_t *p_this )
00399 {
00400     filter_t *p_filter = (filter_t*)p_this;
00401     filter_sys_t *p_sys = p_filter->p_sys;
00402 
00403     free( p_sys );
00404 }
00405 
00406 /*****************************************************************************
00407  * Do the processing here
00408  *****************************************************************************/
00409 static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
00410 {
00411     filter_sys_t *p_sys = p_filter->p_sys;
00412     AVPicture src_pic, dest_pic;
00413     picture_t *p_pic_dst;
00414     int i;
00415 
00416     /* Request output picture */
00417     p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
00418     if( !p_pic_dst )
00419     {
00420         msg_Warn( p_filter, "can't get output picture" );
00421         return NULL;
00422     }
00423 
00424     /* Prepare the AVPictures for the conversion */
00425     for( i = 0; i < p_pic->i_planes; i++ )
00426     {
00427         src_pic.data[i] = p_pic->p[i].p_pixels;
00428         src_pic.linesize[i] = p_pic->p[i].i_pitch;
00429     }
00430     for( i = 0; i < p_pic_dst->i_planes; i++ )
00431     {
00432         dest_pic.data[i] = p_pic_dst->p[i].p_pixels;
00433         dest_pic.linesize[i] = p_pic_dst->p[i].i_pitch;
00434     }
00435 
00436     avpicture_deinterlace( &dest_pic, &src_pic, p_sys->i_src_ffmpeg_chroma,
00437                            p_filter->fmt_in.video.i_width,
00438                            p_filter->fmt_in.video.i_height );
00439 
00440     p_pic_dst->date = p_pic->date;
00441     p_pic_dst->b_force = p_pic->b_force;
00442     p_pic_dst->i_nb_fields = p_pic->i_nb_fields;
00443     p_pic_dst->b_progressive = VLC_TRUE;
00444     p_pic_dst->b_top_field_first = p_pic->b_top_field_first;
00445 
00446     p_pic->pf_release( p_pic );
00447     return p_pic_dst;
00448 }

Generated on Tue Dec 20 10:14:29 2005 for vlc-0.8.4a by  doxygen 1.4.2