X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Fffmpeg%2Fvideo.c;h=0672e2d38c974f036d3843cbbbdd9b952352cf0d;hb=6f7b6bf6fd00917d97fb297db4c9f53bd44fe2bb;hp=966140574deb7f09ef855b465b613520438ccfbb;hpb=2d037953d9b39dce6fd6bd0f175fe78789029eef;p=vlc diff --git a/modules/codec/ffmpeg/video.c b/modules/codec/ffmpeg/video.c index 966140574d..0672e2d38c 100644 --- a/modules/codec/ffmpeg/video.c +++ b/modules/codec/ffmpeg/video.c @@ -1,11 +1,11 @@ /***************************************************************************** * video.c: video decoder using the ffmpeg library ***************************************************************************** - * Copyright (C) 1999-2001 VideoLAN - * $Id: video.c,v 1.49 2003/11/23 03:55:01 fenrir Exp $ + * Copyright (C) 1999-2001 the VideoLAN team + * $Id$ * * Authors: Laurent Aimar - * Gildas Bazin + * Gildas Bazin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,14 +19,16 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ #include -#include +#include +#include +#include /* hmmm, just for INPUT_RATE_DEFAULT */ /* ffmpeg header */ #ifdef HAVE_FFMPEG_AVCODEC_H @@ -42,16 +44,11 @@ *****************************************************************************/ struct decoder_sys_t { - /* Common part between video and audio decoder */ - int i_cat; - int i_codec_id; - char *psz_namecodec; - - AVCodecContext *p_context; - AVCodec *p_codec; + FFMPEG_COMMON_MEMBERS /* Video decoder specific part */ mtime_t input_pts; + mtime_t input_dts; mtime_t i_pts; AVFrame *p_ff_pic; @@ -59,7 +56,8 @@ struct decoder_sys_t /* for frame skipping algo */ int b_hurry_up; - int i_frame_skip; + enum AVDiscard i_skip_frame; + enum AVDiscard i_skip_idct; /* how many decoded frames are late */ int i_late_frames; @@ -70,21 +68,36 @@ struct decoder_sys_t vlc_bool_t b_has_b_frames; + /* Hack to force display of still pictures */ + vlc_bool_t b_first_frame; + int i_buffer_orig, i_buffer; char *p_buffer_orig, *p_buffer; /* Postprocessing handle */ void *p_pp; + vlc_bool_t b_pp; + vlc_bool_t b_pp_async; vlc_bool_t b_pp_init; }; +/* FIXME (dummy palette for now) */ +static AVPaletteControl palette_control; + /***************************************************************************** * Local prototypes *****************************************************************************/ +static void ffmpeg_InitCodec ( decoder_t * ); static void ffmpeg_CopyPicture ( decoder_t *, picture_t *, AVFrame * ); static int ffmpeg_GetFrameBuf ( struct AVCodecContext *, AVFrame * ); static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *, AVFrame * ); +static uint32_t ffmpeg_CodecTag( vlc_fourcc_t fcc ) +{ + uint8_t *p = (uint8_t*)&fcc; + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); +} + /***************************************************************************** * Local Functions *****************************************************************************/ @@ -93,10 +106,13 @@ static uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma ) switch( i_ff_chroma ) { case PIX_FMT_YUV420P: + case PIX_FMT_YUVJ420P: /* Hacky but better then chroma conversion */ return VLC_FOURCC('I','4','2','0'); case PIX_FMT_YUV422P: + case PIX_FMT_YUVJ422P: /* Hacky but better then chroma conversion */ return VLC_FOURCC('I','4','2','2'); case PIX_FMT_YUV444P: + case PIX_FMT_YUVJ444P: /* Hacky but better then chroma conversion */ return VLC_FOURCC('I','4','4','4'); case PIX_FMT_YUV422: @@ -110,6 +126,10 @@ static uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma ) return VLC_FOURCC('R','V','2','4'); case PIX_FMT_RGBA32: return VLC_FOURCC('R','V','3','2'); +#if defined(HAVE_FFMPEG_SWSCALE_H) || defined(HAVE_LIBSWSCALE_TREE) + case PIX_FMT_RGBA: + return VLC_FOURCC('R','G','B','A'); +#endif case PIX_FMT_GRAY8: return VLC_FOURCC('G','R','E','Y'); @@ -143,30 +163,48 @@ static inline picture_t *ffmpeg_NewPictBuf( decoder_t *p_dec, p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0'); } -#if LIBAVCODEC_BUILD >= 4687 - p_dec->fmt_out.video.i_aspect = - VOUT_ASPECT_FACTOR * ( av_q2d(p_context->sample_aspect_ratio) * - p_context->width / p_context->height ); -#else - p_dec->fmt_out.video.i_aspect = - VOUT_ASPECT_FACTOR * p_context->aspect_ratio; -#endif - if( p_dec->fmt_out.video.i_aspect == 0 ) + /* If an aspect-ratio was specified in the input format then force it */ + if( p_dec->fmt_in.video.i_aspect ) + { + p_dec->fmt_out.video.i_aspect = p_dec->fmt_in.video.i_aspect; + } + else { p_dec->fmt_out.video.i_aspect = - VOUT_ASPECT_FACTOR * p_context->width / p_context->height; + VOUT_ASPECT_FACTOR * ( av_q2d(p_context->sample_aspect_ratio) * + p_context->width / p_context->height ); + p_dec->fmt_out.video.i_sar_num = p_context->sample_aspect_ratio.num; + p_dec->fmt_out.video.i_sar_den = p_context->sample_aspect_ratio.den; + + if( p_dec->fmt_out.video.i_aspect == 0 ) + { + p_dec->fmt_out.video.i_aspect = + VOUT_ASPECT_FACTOR * p_context->width / p_context->height; + } + } + + if( p_dec->fmt_out.video.i_frame_rate > 0 && + p_dec->fmt_out.video.i_frame_rate_base > 0 ) + { + p_dec->fmt_out.video.i_frame_rate = + p_dec->fmt_in.video.i_frame_rate; + p_dec->fmt_out.video.i_frame_rate_base = + p_dec->fmt_in.video.i_frame_rate_base; + } + else if( p_context->time_base.num > 0 && p_context->time_base.den > 0 ) + { + p_dec->fmt_out.video.i_frame_rate = p_context->time_base.den; + p_dec->fmt_out.video.i_frame_rate_base = p_context->time_base.num; } p_pic = p_dec->pf_vout_buffer_new( p_dec ); -#ifdef LIBAVCODEC_PP - if( p_sys->p_pp && !p_sys->b_pp_init ) + if( p_sys->p_pp && p_sys->b_pp && !p_sys->b_pp_init ) { E_(InitPostproc)( p_dec, p_sys->p_pp, p_context->width, p_context->height, p_context->pix_fmt ); p_sys->b_pp_init = VLC_TRUE; } -#endif return p_pic; } @@ -178,19 +216,19 @@ static inline picture_t *ffmpeg_NewPictBuf( decoder_t *p_dec, * opened (done after the first decoded frame). *****************************************************************************/ int E_(InitVideoDec)( decoder_t *p_dec, AVCodecContext *p_context, - AVCodec *p_codec, int i_codec_id, char *psz_namecodec ) + AVCodec *p_codec, int i_codec_id, const char *psz_namecodec ) { decoder_sys_t *p_sys; vlc_value_t val; - int i_tmp; /* Allocate the memory needed to store the decoder's structure */ if( ( p_dec->p_sys = p_sys = (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL ) { msg_Err( p_dec, "out of memory" ); - return VLC_EGENERIC; + return VLC_ENOMEM; } + memset( p_sys, 0, sizeof(decoder_sys_t) ); p_dec->p_sys->p_context = p_context; p_dec->p_sys->p_codec = p_codec; @@ -199,70 +237,114 @@ int E_(InitVideoDec)( decoder_t *p_dec, AVCodecContext *p_context, p_sys->p_ff_pic = avcodec_alloc_frame(); /* ***** Fill p_context with init values ***** */ + p_sys->p_context->codec_tag = ffmpeg_CodecTag( p_dec->fmt_in.i_codec ); p_sys->p_context->width = p_dec->fmt_in.video.i_width; p_sys->p_context->height = p_dec->fmt_in.video.i_height; + p_sys->p_context->bits_per_sample = p_dec->fmt_in.video.i_bits_per_pixel; /* ***** Get configuration of ffmpeg plugin ***** */ - i_tmp = config_GetInt( p_dec, "ffmpeg-workaround-bugs" ); - p_sys->p_context->workaround_bugs = __MAX( __MIN( i_tmp, 99 ), 0 ); - - i_tmp = config_GetInt( p_dec, "ffmpeg-error-resilience" ); - p_sys->p_context->error_resilience = __MAX( __MIN( i_tmp, 99 ), -1 ); + p_sys->p_context->workaround_bugs = + config_GetInt( p_dec, "ffmpeg-workaround-bugs" ); + p_sys->p_context->error_resilience = + config_GetInt( p_dec, "ffmpeg-error-resilience" ); var_Create( p_dec, "grayscale", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_dec, "grayscale", &val ); if( val.b_bool ) p_sys->p_context->flags |= CODEC_FLAG_GRAY; - /* Decide if we set CODEC_FLAG_TRUNCATED */ -#if LIBAVCODEC_BUILD >= 4662 - var_Create( p_dec, "ffmpeg-truncated", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT ); - var_Get( p_dec, "ffmpeg-truncated", &val ); - if( val.i_int > 0 ) p_sys->p_context->flags |= CODEC_FLAG_TRUNCATED; -#endif + var_Create( p_dec, "ffmpeg-vismv", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); + var_Get( p_dec, "ffmpeg-vismv", &val ); + if( val.i_int ) p_sys->p_context->debug_mv = val.i_int; - /* ***** Open the codec ***** */ - if( avcodec_open( p_sys->p_context, p_sys->p_codec ) < 0 ) - { - msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec ); - return VLC_EGENERIC; - } - else - { - msg_Dbg( p_dec, "ffmpeg codec (%s) started", p_sys->psz_namecodec ); - } + var_Create( p_dec, "ffmpeg-lowres", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); + var_Get( p_dec, "ffmpeg-lowres", &val ); + if( val.i_int > 0 && val.i_int <= 2 ) p_sys->p_context->lowres = val.i_int; + + var_Create( p_dec, "ffmpeg-skiploopfilter", + VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); + var_Get( p_dec, "ffmpeg-skiploopfilter", &val ); + if( val.i_int > 0 ) p_sys->p_context->skip_loop_filter = AVDISCARD_NONREF; + if( val.i_int > 1 ) p_sys->p_context->skip_loop_filter = AVDISCARD_BIDIR; + if( val.i_int > 2 ) p_sys->p_context->skip_loop_filter = AVDISCARD_NONKEY; + if( val.i_int > 3 ) p_sys->p_context->skip_loop_filter = AVDISCARD_ALL; /* ***** ffmpeg frame skipping ***** */ var_Create( p_dec, "ffmpeg-hurry-up", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_dec, "ffmpeg-hurry-up", &val ); p_sys->b_hurry_up = val.b_bool; + var_Create( p_dec, "ffmpeg-skip-frame", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); + var_Get( p_dec, "ffmpeg-skip-frame", &val ); + switch( val.i_int ) + { + case -1: + p_sys->p_context->skip_frame = AVDISCARD_NONE; + break; + case 0: + p_sys->p_context->skip_frame = AVDISCARD_DEFAULT; + break; + case 1: + p_sys->p_context->skip_frame = AVDISCARD_BIDIR; + break; + case 2: + p_sys->p_context->skip_frame = AVDISCARD_NONKEY; + break; + case 3: + p_sys->p_context->skip_frame = AVDISCARD_ALL; + break; + default: + p_sys->p_context->skip_frame = AVDISCARD_NONE; + break; + } + p_sys->i_skip_frame = p_sys->p_context->skip_frame; + + var_Create( p_dec, "ffmpeg-skip-idct", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); + var_Get( p_dec, "ffmpeg-skip-idct", &val ); + switch( val.i_int ) + { + case -1: + p_sys->p_context->skip_idct = AVDISCARD_NONE; + break; + case 0: + p_sys->p_context->skip_idct = AVDISCARD_DEFAULT; + break; + case 1: + p_sys->p_context->skip_idct = AVDISCARD_BIDIR; + break; + case 2: + p_sys->p_context->skip_idct = AVDISCARD_NONKEY; + break; + case 3: + p_sys->p_context->skip_idct = AVDISCARD_ALL; + break; + default: + p_sys->p_context->skip_idct = AVDISCARD_NONE; + break; + } + p_sys->i_skip_idct = p_sys->p_context->skip_idct; + /* ***** ffmpeg direct rendering ***** */ p_sys->b_direct_rendering = 0; var_Create( p_dec, "ffmpeg-dr", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Get( p_dec, "ffmpeg-dr", &val ); if( val.b_bool && (p_sys->p_codec->capabilities & CODEC_CAP_DR1) && - ffmpeg_PixFmtToChroma( p_sys->p_context->pix_fmt ) && /* Apparently direct rendering doesn't work with YUV422P */ p_sys->p_context->pix_fmt != PIX_FMT_YUV422P && - !(p_sys->p_context->width % 16) && !(p_sys->p_context->height % 16) ) + /* H264 uses too many reference frames */ + p_sys->i_codec_id != CODEC_ID_H264 && + !p_sys->p_context->debug_mv ) { /* Some codecs set pix_fmt only after the 1st frame has been decoded, * so we need to do another check in ffmpeg_GetFrameBuf() */ p_sys->b_direct_rendering = 1; } -#ifdef LIBAVCODEC_PP p_sys->p_pp = NULL; - p_dec->p_sys->b_pp_init = VLC_FALSE; - if( E_(OpenPostproc)( p_dec, &p_sys->p_pp ) == VLC_SUCCESS ) - { - /* for now we cannot do postproc and dr */ - p_sys->b_direct_rendering = 0; - } -#endif + p_sys->b_pp = p_sys->b_pp_async = p_sys->b_pp_init = VLC_FALSE; + p_sys->p_pp = E_(OpenPostproc)( p_dec, &p_sys->b_pp_async ); /* ffmpeg doesn't properly release old pictures when frames are skipped */ - if( p_sys->b_hurry_up ) p_sys->b_direct_rendering = 0; + //if( p_sys->b_hurry_up ) p_sys->b_direct_rendering = 0; if( p_sys->b_direct_rendering ) { msg_Dbg( p_dec, "using direct rendering" ); @@ -276,60 +358,48 @@ int E_(InitVideoDec)( decoder_t *p_dec, AVCodecContext *p_context, p_sys->p_context->opaque = p_dec; /* ***** init this codec with special data ***** */ - if( p_dec->fmt_in.i_extra ) - { - int b_gotpicture; - int i_size = p_dec->fmt_in.i_extra; - - if( p_sys->i_codec_id == CODEC_ID_MPEG4 ) - { - uint8_t *p_vol = malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE ); - memcpy( p_vol, p_dec->fmt_in.p_extra, i_size ); - memset( &p_vol[i_size], 0, FF_INPUT_BUFFER_PADDING_SIZE ); - - avcodec_decode_video( p_sys->p_context, p_sys->p_ff_pic, - &b_gotpicture, p_vol, i_size ); - free( p_vol ); - } -#if LIBAVCODEC_BUILD >= 4666 - else if( p_sys->i_codec_id == CODEC_ID_SVQ3 ) - { - uint8_t *p; - - p_sys->p_context->extradata_size = i_size + 12; - p = p_sys->p_context->extradata = - malloc( p_sys->p_context->extradata_size ); - - memcpy( &p[0], "SVQ3", 4 ); - memset( &p[4], 0, 8 ); - memcpy( &p[12], p_dec->fmt_in.p_extra, i_size ); - } -#endif - else - { - p_sys->p_context->extradata_size = i_size; - p_sys->p_context->extradata = - malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE ); - memcpy( p_sys->p_context->extradata, - p_dec->fmt_in.p_extra, i_size ); - memset( &((uint8_t*)p_sys->p_context->extradata)[i_size], - 0, FF_INPUT_BUFFER_PADDING_SIZE ); - } - } + ffmpeg_InitCodec( p_dec ); /* ***** misc init ***** */ - p_sys->input_pts = 0; + p_sys->input_pts = p_sys->input_dts = 0; p_sys->i_pts = 0; p_sys->b_has_b_frames = VLC_FALSE; + p_sys->b_first_frame = VLC_TRUE; p_sys->i_late_frames = 0; p_sys->i_buffer = 0; p_sys->i_buffer_orig = 1; - p_sys->p_buffer_orig = p_sys->p_buffer = malloc( p_sys->i_buffer ); + p_sys->p_buffer_orig = p_sys->p_buffer = malloc( p_sys->i_buffer_orig ); /* Set output properties */ p_dec->fmt_out.i_cat = VIDEO_ES; p_dec->fmt_out.i_codec = ffmpeg_PixFmtToChroma( p_context->pix_fmt ); + /* Setup palette */ + if( p_dec->fmt_in.video.p_palette ) + p_sys->p_context->palctrl = + (AVPaletteControl *)p_dec->fmt_in.video.p_palette; + else + p_sys->p_context->palctrl = &palette_control; + + /* ***** Open the codec ***** */ + vlc_mutex_t *lock = var_AcquireMutex( "avcodec" ); + if( lock == NULL ) + { + free( p_sys ); + return VLC_ENOMEM; + } + + if( avcodec_open( p_sys->p_context, p_sys->p_codec ) < 0 ) + { + vlc_mutex_unlock( lock ); + msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec ); + free( p_sys ); + return VLC_EGENERIC; + } + vlc_mutex_unlock( lock ); + msg_Dbg( p_dec, "ffmpeg codec (%s) started", p_sys->psz_namecodec ); + + return VLC_SUCCESS; } @@ -340,32 +410,78 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; int b_drawpicture; + int b_null_size = VLC_FALSE; block_t *p_block; if( !pp_block || !*pp_block ) return NULL; + if( !p_sys->p_context->extradata_size && p_dec->fmt_in.i_extra ) + ffmpeg_InitCodec( p_dec ); + p_block = *pp_block; - if( p_block->i_pts > 0 ) + if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) + { + p_sys->i_buffer = 0; + p_sys->i_pts = 0; /* To make sure we recover properly */ + + p_sys->input_pts = p_sys->input_dts = 0; + p_sys->i_late_frames = 0; + + block_Release( p_block ); + + //if( p_block->i_flags & BLOCK_FLAG_CORRUPTED ) + //avcodec_flush_buffers( p_sys->p_context ); + return NULL; + } + + if( p_block->i_flags & BLOCK_FLAG_PREROLL ) + { + /* Do not care about late frames when prerolling + * TODO avoid decoding of non reference frame + * (ie all B except for H264 where it depends only on nal_ref_idc) */ + p_sys->i_late_frames = 0; + } + + if( !p_dec->b_pace_control && (p_sys->i_late_frames > 0) && + (mdate() - p_sys->i_late_frames_start > I64C(5000000)) ) + { + if( p_sys->i_pts ) + { + msg_Err( p_dec, "more than 5 seconds of late video -> " + "dropping frame (computer too slow ?)" ); + p_sys->i_pts = 0; /* To make sure we recover properly */ + } + block_Release( p_block ); + p_sys->i_late_frames--; + return NULL; + } + + if( p_block->i_pts > 0 || p_block->i_dts > 0 ) { p_sys->input_pts = p_block->i_pts; - p_block->i_pts = 0; /* Make sure we don't reuse the same pts twice */ + p_sys->input_dts = p_block->i_dts; + + /* Make sure we don't reuse the same timestamps twice */ + p_block->i_pts = p_block->i_dts = 0; } - /* TODO implement it in a better way */ /* A good idea could be to decode all I pictures and see for the other */ - if( p_sys->b_hurry_up && p_sys->i_late_frames > 4 ) + if( !p_dec->b_pace_control && + p_sys->b_hurry_up && + (p_sys->i_late_frames > 4) ) { b_drawpicture = 0; if( p_sys->i_late_frames < 8 ) { - p_sys->p_context->hurry_up = 2; + p_sys->p_context->skip_frame = + (p_sys->i_skip_frame <= AVDISCARD_BIDIR) ? + AVDISCARD_BIDIR : p_sys->i_skip_frame; } else { /* picture too late, won't decode * but break picture until a new I, and for mpeg4 ...*/ - p_sys->i_late_frames--; /* needed else it will never be decrease */ block_Release( p_block ); p_sys->i_buffer = 0; @@ -374,30 +490,28 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) } else { - b_drawpicture = 1; - p_sys->p_context->hurry_up = 0; - } - - if( p_sys->i_late_frames > 0 && - mdate() - p_sys->i_late_frames_start > I64C(5000000) ) - { - msg_Err( p_dec, "more than 5 seconds of late video -> " - "dropping frame (computer too slow ?)" ); - block_Release( p_block ); - p_sys->i_pts = 0; /* To make sure we recover properly */ - p_sys->i_late_frames--; - return VLC_SUCCESS; + if( p_sys->b_hurry_up ) + p_sys->p_context->skip_frame = p_sys->i_skip_frame; + if( !(p_block->i_flags & BLOCK_FLAG_PREROLL) ) + b_drawpicture = 1; + else + b_drawpicture = 0; } if( p_sys->p_context->width <= 0 || p_sys->p_context->height <= 0 ) { - p_sys->p_context->hurry_up = 5; + if( p_sys->b_hurry_up ) + p_sys->p_context->skip_frame = p_sys->i_skip_frame; + b_null_size = VLC_TRUE; } /* * Do the actual decoding now */ + /* Check if post-processing was enabled */ + p_sys->b_pp = p_sys->b_pp_async; + /* Don't forget that ffmpeg requires a little more bytes * that the real frame size */ if( p_block->i_buffer > 0 ) @@ -413,7 +527,7 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) } p_sys->p_buffer = p_sys->p_buffer_orig; p_sys->i_buffer = p_block->i_buffer; - p_dec->p_vlc->pf_memcpy( p_sys->p_buffer, p_block->p_buffer, + p_dec->p_libvlc->pf_memcpy( p_sys->p_buffer, p_block->p_buffer, p_block->i_buffer ); memset( p_sys->p_buffer + p_block->i_buffer, 0, FF_INPUT_BUFFER_PADDING_SIZE ); @@ -428,7 +542,19 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) i_used = avcodec_decode_video( p_sys->p_context, p_sys->p_ff_pic, &b_gotpicture, - p_sys->p_buffer, p_sys->i_buffer ); + (uint8_t*)p_sys->p_buffer, p_sys->i_buffer ); + if( b_null_size && p_sys->p_context->width > 0 && + p_sys->p_context->height > 0 ) + { + /* Reparse it to not drop the I frame */ + b_null_size = VLC_FALSE; + if( p_sys->b_hurry_up ) + p_sys->p_context->skip_frame = p_sys->i_skip_frame; + i_used = avcodec_decode_video( p_sys->p_context, p_sys->p_ff_pic, + &b_gotpicture, + (uint8_t*)p_sys->p_buffer, p_sys->i_buffer ); + } + if( i_used < 0 ) { msg_Warn( p_dec, "cannot decode one frame (%d bytes)", @@ -446,10 +572,15 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) p_sys->p_buffer += i_used; /* Nothing to display */ - if( !b_gotpicture ) continue; + if( !b_gotpicture ) + { + if( i_used == 0 ) break; + continue; + } - /* Update frame late count*/ - if( p_sys->i_pts && p_sys->i_pts <= mdate() ) + /* Update frame late count (except when doing preroll) */ + if( p_sys->i_pts && decoder_GetDisplayDate(p_dec, p_sys->i_pts) <= mdate() && + !(p_block->i_flags & BLOCK_FLAG_PREROLL) ) { p_sys->i_late_frames++; if( p_sys->i_late_frames == 1 ) @@ -460,13 +591,16 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) p_sys->i_late_frames = 0; } - if( !b_drawpicture || p_sys->p_ff_pic->linesize[0] == 0 ) + if( !b_drawpicture || !p_sys->p_ff_pic->linesize[0] ) { /* Do not display the picture */ + p_pic = (picture_t *)p_sys->p_ff_pic->opaque; + if( !b_drawpicture && p_pic ) + p_dec->pf_vout_buffer_del( p_dec, p_pic ); continue; } - if( !p_sys->b_direct_rendering ) + if( !p_sys->p_ff_pic->opaque ) { /* Get a new picture */ p_pic = ffmpeg_NewPictBuf( p_dec, p_sys->p_context ); @@ -485,17 +619,32 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) p_pic = (picture_t *)p_sys->p_ff_pic->opaque; } - /* Set the PTS - * There is an ugly hack here because some demuxers pass us a dts - * instead of a pts so this screw up things for streams with - * B frames. */ + /* Set the PTS */ + if( p_sys->p_ff_pic->pts ) p_sys->i_pts = p_sys->p_ff_pic->pts; + + /* Sanity check (seems to be needed for some streams) */ if( p_sys->p_ff_pic->pict_type == FF_B_TYPE ) + { p_sys->b_has_b_frames = VLC_TRUE; - if( p_sys->p_ff_pic->pts && - ( !p_sys->p_context->has_b_frames || !p_sys->b_has_b_frames || - p_sys->p_ff_pic->pict_type == FF_B_TYPE ) ) + } + + if( !p_dec->fmt_in.video.i_aspect ) { - p_sys->i_pts = p_sys->p_ff_pic->pts; + /* Fetch again the aspect ratio in case it changed */ + p_dec->fmt_out.video.i_aspect = + VOUT_ASPECT_FACTOR + * ( av_q2d(p_sys->p_context->sample_aspect_ratio) + * p_sys->p_context->width / p_sys->p_context->height ); + p_dec->fmt_out.video.i_sar_num + = p_sys->p_context->sample_aspect_ratio.num; + p_dec->fmt_out.video.i_sar_den + = p_sys->p_context->sample_aspect_ratio.den; + + if( p_dec->fmt_out.video.i_aspect == 0 ) + { + p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR + * p_sys->p_context->width / p_sys->p_context->height; + } } /* Send decoded frame to vout */ @@ -504,13 +653,35 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) p_pic->date = p_sys->i_pts; /* interpolate the next PTS */ - if( p_sys->p_context->frame_rate > 0 ) + if( p_dec->fmt_in.video.i_frame_rate > 0 && + p_dec->fmt_in.video.i_frame_rate_base > 0 ) { p_sys->i_pts += I64C(1000000) * (2 + p_sys->p_ff_pic->repeat_pict) * - p_sys->p_context->frame_rate_base / - (2 * p_sys->p_context->frame_rate); + p_dec->fmt_in.video.i_frame_rate_base * + p_block->i_rate / INPUT_RATE_DEFAULT / + (2 * p_dec->fmt_in.video.i_frame_rate); } + else if( p_sys->p_context->time_base.den > 0 ) + { + p_sys->i_pts += I64C(1000000) * + (2 + p_sys->p_ff_pic->repeat_pict) * + p_sys->p_context->time_base.num * + p_block->i_rate / INPUT_RATE_DEFAULT / + (2 * p_sys->p_context->time_base.den); + } + + if( p_sys->b_first_frame ) + { + /* Hack to force display of still pictures */ + p_sys->b_first_frame = VLC_FALSE; + p_pic->b_force = VLC_TRUE; + } + + p_pic->i_nb_fields = 2 + p_sys->p_ff_pic->repeat_pict; + p_pic->b_progressive = !p_sys->p_ff_pic->interlaced_frame; + p_pic->b_top_field_first = p_sys->p_ff_pic->top_field_first; + return p_pic; } else @@ -526,22 +697,94 @@ picture_t *E_(DecodeVideo)( decoder_t *p_dec, block_t **pp_block ) /***************************************************************************** * EndVideo: decoder destruction ***************************************************************************** - * This function is called when the thread ends after a sucessful + * This function is called when the thread ends after a successful * initialization. *****************************************************************************/ void E_(EndVideoDec)( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; - if( p_sys->p_ff_pic ) free( p_sys->p_ff_pic ); - -#ifdef LIBAVCODEC_PP + if( p_sys->p_ff_pic ) av_free( p_sys->p_ff_pic ); E_(ClosePostproc)( p_dec, p_sys->p_pp ); -#endif - free( p_sys->p_buffer_orig ); } +/***************************************************************************** + * ffmpeg_InitCodec: setup codec extra initialization data for ffmpeg + *****************************************************************************/ +static void ffmpeg_InitCodec( decoder_t *p_dec ) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + int i_size = p_dec->fmt_in.i_extra; + + if( !i_size ) return; + + if( p_sys->i_codec_id == CODEC_ID_SVQ3 ) + { + uint8_t *p; + + p_sys->p_context->extradata_size = i_size + 12; + p = p_sys->p_context->extradata = + malloc( p_sys->p_context->extradata_size ); + + memcpy( &p[0], "SVQ3", 4 ); + memset( &p[4], 0, 8 ); + memcpy( &p[12], p_dec->fmt_in.p_extra, i_size ); + + /* Now remove all atoms before the SMI one */ + if( p_sys->p_context->extradata_size > 0x5a && + strncmp( (char*)&p[0x56], "SMI ", 4 ) ) + { + uint8_t *psz = &p[0x52]; + + while( psz < &p[p_sys->p_context->extradata_size - 8] ) + { + int i_size = GetDWBE( psz ); + if( i_size <= 1 ) + { + /* FIXME handle 1 as long size */ + break; + } + if( !strncmp( (char*)&psz[4], "SMI ", 4 ) ) + { + memmove( &p[0x52], psz, + &p[p_sys->p_context->extradata_size] - psz ); + break; + } + + psz += i_size; + } + } + } + else if( p_dec->fmt_in.i_codec == VLC_FOURCC( 'R', 'V', '1', '0' ) || + p_dec->fmt_in.i_codec == VLC_FOURCC( 'R', 'V', '1', '3' ) || + p_dec->fmt_in.i_codec == VLC_FOURCC( 'R', 'V', '2', '0' ) ) + { + if( p_dec->fmt_in.i_extra == 8 ) + { + p_sys->p_context->extradata_size = 8; + p_sys->p_context->extradata = malloc( 8 ); + + memcpy( p_sys->p_context->extradata, + p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); + p_sys->p_context->sub_id= ((uint32_t*)p_dec->fmt_in.p_extra)[1]; + + msg_Warn( p_dec, "using extra data for RV codec sub_id=%08x", + p_sys->p_context->sub_id ); + } + } + else + { + p_sys->p_context->extradata_size = i_size; + p_sys->p_context->extradata = + malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE ); + memcpy( p_sys->p_context->extradata, + p_dec->fmt_in.p_extra, i_size ); + memset( &((uint8_t*)p_sys->p_context->extradata)[i_size], + 0, FF_INPUT_BUFFER_PADDING_SIZE ); + } +} + /***************************************************************************** * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a * picture_t structure (when not in direct rendering mode). @@ -557,24 +800,25 @@ static void ffmpeg_CopyPicture( decoder_t *p_dec, uint8_t *p_dst, *p_src; int i_src_stride, i_dst_stride; -#ifdef LIBAVCODEC_PP - if( p_sys->p_pp ) + if( p_sys->p_pp && p_sys->b_pp ) E_(PostprocPict)( p_dec, p_sys->p_pp, p_pic, p_ff_pic ); else -#endif - for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) { - p_src = p_ff_pic->data[i_plane]; - p_dst = p_pic->p[i_plane].p_pixels; - i_src_stride = p_ff_pic->linesize[i_plane]; - i_dst_stride = p_pic->p[i_plane].i_pitch; - - i_size = __MIN( i_src_stride, i_dst_stride ); - for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ ) + for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) { - p_dec->p_vlc->pf_memcpy( p_dst, p_src, i_size ); - p_src += i_src_stride; - p_dst += i_dst_stride; + p_src = p_ff_pic->data[i_plane]; + p_dst = p_pic->p[i_plane].p_pixels; + i_src_stride = p_ff_pic->linesize[i_plane]; + i_dst_stride = p_pic->p[i_plane].i_pitch; + + i_size = __MIN( i_src_stride, i_dst_stride ); + for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines; + i_line++ ) + { + p_dec->p_libvlc->pf_memcpy( p_dst, p_src, i_size ); + p_src += i_src_stride; + p_dst += i_dst_stride; + } } } } @@ -586,18 +830,22 @@ static void ffmpeg_CopyPicture( decoder_t *p_dec, /* we need to convert to I420 */ switch( p_sys->p_context->pix_fmt ) { - case( PIX_FMT_YUV410P ): - case( PIX_FMT_YUV411P ): + case PIX_FMT_YUV410P: + case PIX_FMT_YUV411P: + case PIX_FMT_BGR24: + case PIX_FMT_PAL8: for( i = 0; i < p_pic->i_planes; i++ ) { dest_pic.data[i] = p_pic->p[i].p_pixels; dest_pic.linesize[i] = p_pic->p[i].i_pitch; } +#if !defined(HAVE_FFMPEG_SWSCALE_H) && !defined(HAVE_LIBSWSCALE_TREE) img_convert( &dest_pic, PIX_FMT_YUV420P, (AVPicture *)p_ff_pic, p_sys->p_context->pix_fmt, p_sys->p_context->width, p_sys->p_context->height ); +#endif break; default: msg_Err( p_dec, "don't know how to convert chroma %i", @@ -622,11 +870,32 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context, picture_t *p_pic; /* Set picture PTS */ - p_ff_pic->pts = p_sys->input_pts; - p_sys->input_pts = 0; + if( p_sys->input_pts ) + { + p_ff_pic->pts = p_sys->input_pts; + } + else if( p_sys->input_dts ) + { + /* Some demuxers only set the dts so let's try to find a useful + * timestamp from this */ + if( !p_context->has_b_frames || !p_sys->b_has_b_frames || + !p_ff_pic->reference || !p_sys->i_pts ) + { + p_ff_pic->pts = p_sys->input_dts; + } + else p_ff_pic->pts = 0; + } + else p_ff_pic->pts = 0; + + if( p_sys->i_pts ) /* make sure 1st frame has a pts > 0 */ + { + p_sys->input_pts = p_sys->input_dts = 0; + } + + p_ff_pic->opaque = 0; /* Not much to do in indirect rendering mode */ - if( !p_sys->b_direct_rendering ) + if( !p_sys->b_direct_rendering || p_sys->b_pp ) { return avcodec_default_get_buffer( p_context, p_ff_pic ); } @@ -663,9 +932,10 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context, p_ff_pic->linesize[2] = p_pic->p[2].i_pitch; p_ff_pic->linesize[3] = 0; - if( p_ff_pic->reference != 0 ) + if( p_ff_pic->reference != 0 || + p_sys->i_codec_id == CODEC_ID_H264 /* Bug in libavcodec */ ) { - //vout_LinkPicture( p_sys->p_vout, p_pic ); + p_dec->pf_picture_link( p_dec, p_pic ); } /* FIXME what is that, should give good value */ @@ -680,7 +950,7 @@ static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context, decoder_t *p_dec = (decoder_t *)p_context->opaque; picture_t *p_pic; - if( p_ff_pic->type != FF_BUFFER_TYPE_USER ) + if( !p_ff_pic->opaque ) { avcodec_default_release_buffer( p_context, p_ff_pic ); return; @@ -693,8 +963,9 @@ static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context, p_ff_pic->data[2] = NULL; p_ff_pic->data[3] = NULL; - if( p_ff_pic->reference != 0 ) + if( p_ff_pic->reference != 0 || + p_dec->p_sys->i_codec_id == CODEC_ID_H264 /* Bug in libavcodec */ ) { - //vout_UnlinkPicture( p_sys->p_vout, p_pic ); + p_dec->pf_picture_unlink( p_dec, p_pic ); } }