00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <vlc/vlc.h>
00029 #include <vlc/decoder.h>
00030 #include "vlc_filter.h"
00031
00032
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
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
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
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
00089 return VLC_EGENERIC;
00090 }
00091
00092
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
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
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
00128 E_(InitLibavcodec)(p_this);
00129
00130 return VLC_SUCCESS;
00131 }
00132
00133
00134
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
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
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
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
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
00244 if( CheckInit( p_filter ) != VLC_SUCCESS ) return 0;
00245
00246
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
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
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
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
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
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
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
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
00369 if( E_(GetFfmpegChroma)( p_filter->fmt_in.video.i_chroma ) < 0 )
00370 {
00371 return VLC_EGENERIC;
00372 }
00373
00374
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
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
00390 E_(InitLibavcodec)(p_this);
00391
00392 return VLC_SUCCESS;
00393 }
00394
00395
00396
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
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
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
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 }