]> git.sesse.net Git - vlc/blobdiff - modules/codec/ffmpeg/video.c
Let's try this again. Detect older and new versions of ffmpeg and allow for their...
[vlc] / modules / codec / ffmpeg / video.c
index 450138fa4ae7b47464816067fdf995a1b6d526e9..9ae5fa4452acba9cb36bae9eb19390bbd1b1cfef 100644 (file)
@@ -1,11 +1,11 @@
 /*****************************************************************************
- * video.c: video decoder using ffmpeg library
+ * video.c: video decoder using the ffmpeg library
  *****************************************************************************
- * Copyright (C) 1999-2001 VideoLAN
- * $Id: video.c,v 1.40 2003/08/13 18:39:53 gbazin Exp $
+ * Copyright (C) 1999-2001 the VideoLAN team
+ * $Id$
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- *          Gildas Bazin <gbazin@netcourrier.com>
+ *          Gildas Bazin <gbazin@videolan.org>
  *
  * 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
  *
  * 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 <stdlib.h>                                      /* malloc(), free() */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
 
 #include <vlc/vlc.h>
-#include <vlc/vout.h>
-#include <vlc/aout.h>
-#include <vlc/decoder.h>
-#include <vlc/input.h>
-
-#include <string.h>
-
-#ifdef HAVE_SYS_TIMES_H
-#   include <sys/times.h>
-#endif
+#include <vlc_codec.h>
+#include <vlc_vout.h>
+#include <vlc_input.h>                  /* hmmm, just for INPUT_RATE_DEFAULT */
 
 /* ffmpeg header */
-#ifdef HAVE_FFMPEG_AVCODEC_H
+#ifdef HAVE_LIBAVCODEC_AVCODEC_H
+#   include <libavcodec/avcodec.h>
+#elif defined(HAVE_FFMPEG_AVCODEC_H)
 #   include <ffmpeg/avcodec.h>
 #else
 #   include <avcodec.h>
 
 #include "ffmpeg.h"
 
-#ifdef LIBAVCODEC_PP
-#   ifdef HAVE_POSTPROC_POSTPROCESS_H
-#       include <postproc/postprocess.h>
-#   else
-#       include <libpostproc/postprocess.h>
-#   endif
-#else
-#   include "postprocessing/postprocessing.h"
-#endif
+/*****************************************************************************
+ * decoder_sys_t : decoder descriptor
+ *****************************************************************************/
+struct decoder_sys_t
+{
+    FFMPEG_COMMON_MEMBERS
+
+    /* Video decoder specific part */
+    mtime_t input_pts;
+    mtime_t input_dts;
+    mtime_t i_pts;
+
+    AVFrame          *p_ff_pic;
+    BITMAPINFOHEADER *p_format;
+
+    /* for frame skipping algo */
+    int b_hurry_up;
+    enum AVDiscard i_skip_frame;
+    enum AVDiscard i_skip_idct;
+
+    /* how many decoded frames are late */
+    int     i_late_frames;
+    mtime_t i_late_frames_start;
+
+    /* for direct rendering */
+    int b_direct_rendering;
+
+    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;
 
-#include "video.h"
+    /* 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_CopyPicture( picture_t *, AVFrame *, vdec_thread_t * );
+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 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
  *****************************************************************************/
-static inline uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma )
+static uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma )
 {
-    /* FIXME FIXME some of them are wrong */
     switch( i_ff_chroma )
     {
-        case PIX_FMT_YUV420P:
-        case PIX_FMT_YUV422:
-            return( VLC_FOURCC('I','4','2','0') );
-        case PIX_FMT_RGB24:
-            return( VLC_FOURCC('R','V','2','4') );
+    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:
+        return VLC_FOURCC('Y','U','Y','2');
+
+    case PIX_FMT_RGB555:
+        return VLC_FOURCC('R','V','1','5');
+    case PIX_FMT_RGB565:
+        return VLC_FOURCC('R','V','1','6');
+    case PIX_FMT_RGB24:
+        return VLC_FOURCC('R','V','2','4');
+    case PIX_FMT_RGBA32:
+        return VLC_FOURCC('R','V','3','2');
+#ifdef PIX_FMT_RGBA
+    case PIX_FMT_RGBA:
+        return VLC_FOURCC('R','G','B','A');
+#endif
+    case PIX_FMT_GRAY8:
+        return VLC_FOURCC('G','R','E','Y');
 
-        case PIX_FMT_YUV422P:
-            return( VLC_FOURCC('I','4','2','2') );
-        case PIX_FMT_YUV444P:
-            return( VLC_FOURCC('I','4','4','4') );
-        case PIX_FMT_YUV410P:
-        case PIX_FMT_YUV411P:
-        case PIX_FMT_BGR24:
-        default:
-            return( 0 );
+    case PIX_FMT_YUV410P:
+    case PIX_FMT_YUV411P:
+    case PIX_FMT_BGR24:
+    default:
+        return 0;
     }
 }
 
-/* Return a Vout */
-static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t  *p_vdec,
-                                         AVCodecContext *p_context )
+/* Returns a new picture buffer */
+static inline picture_t *ffmpeg_NewPictBuf( decoder_t *p_dec,
+                                            AVCodecContext *p_context )
 {
-    vout_thread_t *p_vout;
-    unsigned int   i_width = p_context->width;
-    unsigned int   i_height = p_context->height;
-    uint32_t       i_chroma = ffmpeg_PixFmtToChroma( p_context->pix_fmt );
-    unsigned int   i_aspect;
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    picture_t *p_pic;
 
-    if( !i_width || !i_height )
+    p_dec->fmt_out.video.i_width = p_context->width;
+    p_dec->fmt_out.video.i_height = p_context->height;
+    p_dec->fmt_out.i_codec = ffmpeg_PixFmtToChroma( p_context->pix_fmt );
+
+    if( !p_context->width || !p_context->height )
     {
-        return( NULL ); /* Can't create a new vout without display size */
+        return NULL; /* invalid display size */
     }
 
-    if( !i_chroma )
+    if( !p_dec->fmt_out.i_codec )
     {
         /* we make conversion if possible*/
-        i_chroma = VLC_FOURCC('I','4','2','0');
+        p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0');
     }
 
-    i_aspect = VOUT_ASPECT_FACTOR * p_context->aspect_ratio;
-    if( i_aspect == 0 )
+    /* If an aspect-ratio was specified in the input format then force it */
+    if( p_dec->fmt_in.video.i_aspect )
     {
-        i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
+        p_dec->fmt_out.video.i_aspect = p_dec->fmt_in.video.i_aspect;
     }
-
-    /* Spawn a video output if there is none. First we look for our children,
-     * then we look for any other vout that might be available. */
-    p_vout = vout_Request( p_vdec->p_fifo, p_vdec->p_vout,
-                           i_width, i_height, i_chroma, i_aspect );
-#ifdef LIBAVCODEC_PP
-    if( p_vdec->pp_mode && !p_vdec->pp_context )
+    else
     {
-        int32_t i_cpu = p_vdec->p_fifo->p_libvlc->i_cpu;
-        int i_flags = 0;
+        p_dec->fmt_out.video.i_aspect =
+            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( i_cpu & CPU_CAPABILITY_MMX )
-        {
-            i_flags |= PP_CPU_CAPS_MMX;
-        }
-        if( i_cpu & CPU_CAPABILITY_MMXEXT )
-        {
-            i_flags |= PP_CPU_CAPS_MMX2;
-        }
-        if( i_cpu & CPU_CAPABILITY_3DNOW )
+        if( p_dec->fmt_out.video.i_aspect == 0 )
         {
-            i_flags |= PP_CPU_CAPS_3DNOW;
+            p_dec->fmt_out.video.i_aspect =
+                VOUT_ASPECT_FACTOR * p_context->width / p_context->height;
         }
+    }
 
-        switch( p_context->pix_fmt )
-        {
-            case PIX_FMT_YUV444P:
-                i_flags |= PP_FORMAT_444;
-                break;
-            case PIX_FMT_YUV422P:
-                i_flags |= PP_FORMAT_422;
-                break;
-            case PIX_FMT_YUV411P:
-                i_flags |= PP_FORMAT_411;
-                break;
-            default:
-                i_flags |= PP_FORMAT_420;
-                break;
-        }
+    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_vdec->pp_context = pp_get_context( i_width, i_height, i_flags );
+    p_pic = p_dec->pf_vout_buffer_new( p_dec );
+
+    if( p_sys->p_pp && p_sys->b_pp && !p_sys->b_pp_init )
+    {
+        E_(InitPostproc)( p_sys->p_pp, p_context->width,
+                          p_context->height, p_context->pix_fmt );
+        p_sys->b_pp_init = VLC_TRUE;
     }
-#endif
 
-    return p_vout;
+    return p_pic;
 }
 
 /*****************************************************************************
- *
- * Functions that initialize, decode and end the decoding process
- *
- * Functions exported for ffmpeg.c
- *   * E_( InitThread_Video )
- *   * E_( DecodeThread )
- *   * E_( EndThread_Video )
- *****************************************************************************/
-
-/*****************************************************************************
- * InitThread: initialize vdec output thread
+ * InitVideo: initialize the video decoder
  *****************************************************************************
- * This function is called from decoder_Run and performs the second step
- * of the initialization. It returns 0 on success. Note that the thread's
- * flag are not modified inside this function.
- *
- * ffmpeg codec will be open, some memory allocated. But Vout is not yet
- * open (done after the first decoded frame)
+ * the ffmpeg codec will be opened, some memory allocated. The vout is not yet
+ * opened (done after the first decoded frame).
  *****************************************************************************/
-static inline void SetDWBE( void *data, uint32_t dw )
+int E_(InitVideoDec)( decoder_t *p_dec, AVCodecContext *p_context,
+                      AVCodec *p_codec, int i_codec_id, const char *psz_namecodec )
 {
-    uint8_t *p = data;
+    decoder_sys_t *p_sys;
+    vlc_value_t val;
 
-    p[0] = (dw >> 24 )&0xff;
-    p[1] = (dw >> 16 )&0xff;
-    p[2] = (dw >>  8 )&0xff;
-    p[3] = (dw )&0xff;
-}
+    /* 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_ENOMEM;
+    }
+    memset( p_sys, 0, sizeof(decoder_sys_t) );
 
-int E_( InitThread_Video )( vdec_thread_t *p_vdec )
-{
-    int i_tmp;
-    int i_truncated;
+    p_dec->p_sys->p_context = p_context;
+    p_dec->p_sys->p_codec = p_codec;
+    p_dec->p_sys->i_codec_id = i_codec_id;
+    p_dec->p_sys->psz_namecodec = psz_namecodec;
+    p_sys->p_ff_pic = avcodec_alloc_frame();
 
-    p_vdec->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;
 
-    if( ( p_vdec->p_format =
-          (BITMAPINFOHEADER *)p_vdec->p_fifo->p_bitmapinfoheader ) != NULL )
-    {
-        /* ***** Fill p_context with init values ***** */
-        p_vdec->p_context->width  = p_vdec->p_format->biWidth;
-        p_vdec->p_context->height = p_vdec->p_format->biHeight;
+    /*  ***** Get configuration of ffmpeg plugin ***** */
+    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;
+
+    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;
+
+    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;
     }
-    else
+    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) &&
+        /* Apparently direct rendering doesn't work with YUV422P */
+        p_sys->p_context->pix_fmt != PIX_FMT_YUV422P &&
+        /* H264 uses too many reference frames */
+        p_sys->i_codec_id != CODEC_ID_H264 &&
+        !p_sys->p_context->debug_mv )
     {
-        msg_Warn( p_vdec->p_fifo, "display informations missing" );
-        p_vdec->p_format = NULL;
+        /* 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;
     }
 
-    /*  ***** Get configuration of ffmpeg plugin ***** */
-    i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-workaround-bugs" );
-    p_vdec->p_context->workaround_bugs  = __MAX( __MIN( i_tmp, 99 ), 0 );
-
-    i_tmp = config_GetInt( p_vdec->p_fifo, "ffmpeg-error-resilience" );
-    p_vdec->p_context->error_resilience = __MAX( __MIN( i_tmp, 99 ), -1 );
+    p_sys->p_pp = NULL;
+    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 );
 
-    if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
+    /* 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_direct_rendering )
     {
-        p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
+        msg_Dbg( p_dec, "using direct rendering" );
+        p_sys->p_context->flags |= CODEC_FLAG_EMU_EDGE;
     }
 
-    p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
-
-    /* CODEC_FLAG_TRUNCATED */
+    /* Always use our get_buffer wrapper so we can calculate the
+     * PTS correctly */
+    p_sys->p_context->get_buffer = ffmpeg_GetFrameBuf;
+    p_sys->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
+    p_sys->p_context->opaque = p_dec;
 
-    /* FIXME search real LIBAVCODEC_BUILD */
-#if LIBAVCODEC_BUILD >= 4662
-    i_truncated = config_GetInt( p_vdec->p_fifo, "ffmpeg-truncated" );
-    if( i_truncated == 1 )
-#if 0
-        ||
-        ( i_truncated == -1 && ( p_vdec->p_context->width == 0 || p_vdec->p_context->height == 0 ) ) )
-#endif
-    {
-        p_vdec->p_context->flags |= CODEC_FLAG_TRUNCATED;
-    }
-#endif
+    /* ***** init this codec with special data ***** */
+    ffmpeg_InitCodec( p_dec );
+
+    /* ***** misc init ***** */
+    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_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 ***** */
-    if( avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0 )
+    vlc_mutex_t *lock = var_AcquireMutex( "avcodec" );
+    if( lock == NULL )
     {
-        msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
-                                 p_vdec->psz_namecodec );
-        return( VLC_EGENERIC );
-    }
-    else
-    {
-        msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
-                                 p_vdec->psz_namecodec );
+        free( p_sys );
+        return VLC_ENOMEM;
     }
 
-    p_vdec->b_direct_rendering = 0;
-    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr" ) &&
-        p_vdec->p_codec->capabilities & CODEC_CAP_DR1 &&
-        ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) &&
-        /* Apparently direct rendering doesn't work with YUV422P */
-        p_vdec->p_context->pix_fmt != PIX_FMT_YUV422P &&
-        !(p_vdec->p_context->width % 16) && !(p_vdec->p_context->height % 16) )
+    if( avcodec_open( p_sys->p_context, p_sys->p_codec ) < 0 )
     {
-        /* Some codecs set pix_fmt only after the 1st frame has been decoded,
-         * so we need to do another check in ffmpeg_GetFrameBuf() */
-        p_vdec->b_direct_rendering = 1;
+        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 );
 
-    /* ***** Load post processing ***** */
-#ifdef LIBAVCODEC_PP
-    p_vdec->pp_context = NULL;
-    p_vdec->pp_mode    = NULL;
 
-    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )
-    {
-        int  i_quality = config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" );
-        char *psz_name = config_GetPsz( p_vdec->p_fifo, "ffmpeg-pp-name" );
+    return VLC_SUCCESS;
+}
 
-        if( !psz_name )
-        {
-            psz_name = strdup( "default" );
-        }
-        else if( *psz_name == '\0' )
-        {
-            free( psz_name );
-            psz_name = strdup( "default" );
-        }
+/*****************************************************************************
+ * DecodeVideo: Called to decode one or more frames
+ *****************************************************************************/
+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;
 
-        p_vdec->pp_mode =
-            pp_get_mode_by_name_and_quality( psz_name, i_quality );
+    if( !pp_block || !*pp_block ) return NULL;
 
-        if( !p_vdec->pp_mode )
-        {
-            msg_Err( p_vdec->p_fifo, "failed geting mode for postproc" );
-        }
-        else
-        {
-            msg_Info( p_vdec->p_fifo, "postproc activated" );
-        }
-        free( psz_name );
+    if( !p_sys->p_context->extradata_size && p_dec->fmt_in.i_extra )
+        ffmpeg_InitCodec( p_dec );
 
-        /* for now we cannot do postproc and dr */
-        p_vdec->b_direct_rendering = 0;
-    }
-    else
+    p_block = *pp_block;
+
+    if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
     {
-        msg_Dbg( p_vdec->p_fifo, "no postproc" );
-    }
-#endif
+        p_sys->i_buffer = 0;
+        p_sys->i_pts = 0; /* To make sure we recover properly */
 
-    /* ffmpeg doesn't properly release old pictures when frames are skipped */
-    if( p_vdec->b_hurry_up ) p_vdec->b_direct_rendering = 0;
+        p_sys->input_pts = p_sys->input_dts = 0;
+        p_sys->i_late_frames = 0;
 
-    /* Always use our get_buffer wrapper so we can calculate the
-     * PTS correctly */
-    p_vdec->p_context->get_buffer = ffmpeg_GetFrameBuf;
-    p_vdec->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
-    p_vdec->p_context->opaque = p_vdec;
+        block_Release( p_block );
 
-    if( p_vdec->b_direct_rendering )
-    {
-        msg_Dbg( p_vdec->p_fifo, "using direct rendering" );
-        p_vdec->p_context->flags |= CODEC_FLAG_EMU_EDGE;
+        //if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
+            //avcodec_flush_buffers( p_sys->p_context );
+        return NULL;
     }
 
-    /* ***** init this codec with special data ***** */
-    if( p_vdec->p_format &&
-            p_vdec->p_format->biSize > sizeof(BITMAPINFOHEADER) )
+    if( p_block->i_flags & BLOCK_FLAG_PREROLL )
     {
-        int b_gotpicture;
-        int i_size = p_vdec->p_format->biSize - sizeof(BITMAPINFOHEADER);
-
-        if( p_vdec->i_codec_id == CODEC_ID_MPEG4 )
-        {
-            uint8_t *p_vol = malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE );
-
-            memcpy( p_vol, &p_vdec->p_format[1], i_size );
-            memset( &p_vol[i_size], 0, FF_INPUT_BUFFER_PADDING_SIZE );
-
-            avcodec_decode_video( p_vdec->p_context, p_vdec->p_ff_pic,
-                                  &b_gotpicture,
-                                  p_vol,
-                                  i_size );
-            free( p_vol );
-        }
-#if LIBAVCODEC_BUILD >= 4666
-        else if( p_vdec->i_codec_id == CODEC_ID_SVQ3 )
-        {
-            uint8_t *p;
-
-            p_vdec->p_context->extradata_size = i_size + 12;
-            p = p_vdec->p_context->extradata  =
-                malloc( p_vdec->p_context->extradata_size );
+        /* 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;
+    }
 
-            memcpy( &p[0],  "SVQ3", 4 );
-            memset( &p[4], 0, 8 );
-            memcpy( &p[12], &p_vdec->p_format[1], i_size );
-        }
-#endif
-        else
+    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 )
         {
-            p_vdec->p_context->extradata_size = i_size;
-            p_vdec->p_context->extradata =
-                malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE );
-            memcpy( p_vdec->p_context->extradata,
-                    &p_vdec->p_format[1], i_size );
-            memset( &((uint8_t*)p_vdec->p_context->extradata)[i_size],
-                    0, FF_INPUT_BUFFER_PADDING_SIZE );
+            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;
     }
-    p_vdec->p_vout = NULL;
-
-    p_vdec->input_pts_previous = 0;
-    p_vdec->input_pts = 0;
 
-    p_vdec->b_has_b_frames = VLC_FALSE;
+    if( p_block->i_pts > 0 || p_block->i_dts > 0 )
+    {
+        p_sys->input_pts = p_block->i_pts;
+        p_sys->input_dts = p_block->i_dts;
 
-    return( VLC_SUCCESS );
-}
+        /* Make sure we don't reuse the same timestamps twice */
+        p_block->i_pts = p_block->i_dts = 0;
+    }
 
-/*****************************************************************************
- * DecodeThread: Called to decode one frame
- *****************************************************************************
- * We have to get a frame stored in a pes, give it to ffmpeg decoder and send
- * the image to the output.
- *****************************************************************************/
-void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
-{
-    pes_packet_t    *p_pes;
-    int     i_frame_size;
-    int     i_used;
-    int     b_drawpicture;
-    int     b_gotpicture;
-    picture_t *p_pic;                                         /* vlc picture */
-
-    /* TODO implement it in a better way */
     /* A good idea could be to decode all I pictures and see for the other */
-    if( p_vdec->b_hurry_up && p_vdec->i_frame_late > 4 )
+    if( !p_dec->b_pace_control &&
+        p_sys->b_hurry_up &&
+        (p_sys->i_late_frames > 4) )
     {
         b_drawpicture = 0;
-        if( p_vdec->i_frame_late < 8 )
+        if( p_sys->i_late_frames < 8 )
         {
-            p_vdec->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
         {
-            /* too much late picture, won't decode
-               but break picture until a new I, and for mpeg4 ...*/
-            p_vdec->i_frame_late--; /* needed else it will never be decrease */
-            input_ExtractPES( p_vdec->p_fifo, NULL );
-            return;
+            /* 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;
+            return NULL;
         }
     }
     else
     {
-        b_drawpicture = 1;
-        p_vdec->p_context->hurry_up = 0;
+        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_vdec->i_frame_late > 0 &&
-        mdate() - p_vdec->i_frame_late_start > (mtime_t)5000000 )
+    if( p_sys->p_context->width <= 0 || p_sys->p_context->height <= 0 )
     {
-        msg_Err( p_vdec->p_fifo, "more than 5 seconds of late video -> "
-                 "dropping (to slow computer ?)" );
-        do
-        {
-            input_ExtractPES( p_vdec->p_fifo, &p_pes );
-            if( !p_pes )
-            {
-                p_vdec->p_fifo->b_error = 1;
-                return;
-            }
+        if( p_sys->b_hurry_up )
+            p_sys->p_context->skip_frame = p_sys->i_skip_frame;
+        b_null_size = VLC_TRUE;
+    }
 
-            if( p_pes->i_pts > 0 )
-            {
-                p_vdec->input_pts_previous = p_vdec->input_pts;
-                p_vdec->input_pts = p_pes->i_pts;
-            }
-            input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
+    /*
+     * Do the actual decoding now
+     */
 
-        } while( p_vdec->input_pts <= 0 || p_vdec->input_pts < mdate() );
-    }
+    /* Check if post-processing was enabled */
+    p_sys->b_pp = p_sys->b_pp_async;
 
-    if( !p_vdec->p_context->width || !p_vdec->p_context->height )
+    /* Don't forget that ffmpeg requires a little more bytes
+     * that the real frame size */
+    if( p_block->i_buffer > 0 )
     {
-        p_vdec->p_context->hurry_up = 5;
+        p_sys->i_buffer = p_block->i_buffer;
+        if( p_sys->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE >
+            p_sys->i_buffer_orig )
+        {
+            free( p_sys->p_buffer_orig );
+            p_sys->i_buffer_orig =
+                p_block->i_buffer + FF_INPUT_BUFFER_PADDING_SIZE;
+            p_sys->p_buffer_orig = malloc( p_sys->i_buffer_orig );
+        }
+        p_sys->p_buffer = p_sys->p_buffer_orig;
+        p_sys->i_buffer = p_block->i_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 );
+
+        p_block->i_buffer = 0;
     }
 
-    do
+    while( p_sys->i_buffer > 0 )
     {
-        input_ExtractPES( p_vdec->p_fifo, &p_pes );
-        if( !p_pes )
+        int i_used, b_gotpicture;
+        picture_t *p_pic;
+
+        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( b_null_size && p_sys->p_context->width > 0 &&
+            p_sys->p_context->height > 0 )
         {
-            p_vdec->p_fifo->b_error = 1;
-            return;
+            /* 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( p_pes->i_pts > 0 )
+        if( i_used < 0 )
         {
-            p_vdec->input_pts_previous = p_vdec->input_pts;
-            p_vdec->input_pts = p_pes->i_pts;
+            msg_Warn( p_dec, "cannot decode one frame (%d bytes)",
+                      p_sys->i_buffer );
+            block_Release( p_block );
+            return NULL;
         }
-
-        i_frame_size = p_pes->i_pes_size;
-
-        if( i_frame_size > 0 )
+        else if( i_used > p_sys->i_buffer )
         {
-            uint8_t *p_last;
-            int i_need;
-            /* XXX Don't forget that ffmpeg required a little more bytes
-             * that the real frame size */
-            i_need = i_frame_size + FF_INPUT_BUFFER_PADDING_SIZE + p_vdec->i_buffer;
-            if( p_vdec->i_buffer_size < i_need)
-            {
-                p_last = p_vdec->p_buffer;
-                p_vdec->p_buffer = malloc( i_need );
-                p_vdec->i_buffer_size = i_need;
-                if( p_vdec->i_buffer > 0 )
-                {
-                    memcpy( p_vdec->p_buffer, p_last, p_vdec->i_buffer );
-                }
-                FREE( p_last );
-            }
-            i_frame_size =
-                E_( GetPESData )( p_vdec->p_buffer + p_vdec->i_buffer,
-                                  i_frame_size , p_pes );
-            memset( p_vdec->p_buffer + p_vdec->i_buffer + i_frame_size,
-                    0, FF_INPUT_BUFFER_PADDING_SIZE );
+            i_used = p_sys->i_buffer;
         }
 
-        input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
-
-    } while( i_frame_size <= 0 );
-
-    i_frame_size += p_vdec->i_buffer;
+        /* Consumed bytes */
+        p_sys->i_buffer -= i_used;
+        p_sys->p_buffer += i_used;
 
-usenextdata:
-    i_used = avcodec_decode_video( p_vdec->p_context,
-                                   p_vdec->p_ff_pic,
-                                   &b_gotpicture,
-                                   p_vdec->p_buffer,
-                                   i_frame_size );
-
-    if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error ) return;
+        /* Nothing to display */
+        if( !b_gotpicture )
+        {
+            if( i_used == 0 ) break;
+            continue;
+        }
 
-#if 0
-    msg_Dbg( p_vdec->p_fifo,
-             "used:%d framesize:%d (%s picture)",
-             i_used, i_frame_size, b_gotpicture ? "got":"no got" );
-#endif
-    if( i_used < 0 )
-    {
-        msg_Warn( p_vdec->p_fifo, "cannot decode one frame (%d bytes)",
-                                  i_frame_size );
-        p_vdec->i_frame_error++;
-        p_vdec->i_buffer = 0;
-        return;
-    }
-    else if( i_used < i_frame_size )
-    {
-        memmove( p_vdec->p_buffer,
-                 p_vdec->p_buffer + i_used,
-                 p_vdec->i_buffer_size - i_used );
+        /* 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 )
+                p_sys->i_late_frames_start = mdate();
+        }
+        else
+        {
+            p_sys->i_late_frames = 0;
+        }
 
-        p_vdec->i_buffer = i_frame_size - i_used;
-    }
-    else
-    {
-        p_vdec->i_buffer = 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;
+        }
 
-    /* consumed bytes */
-    i_frame_size -= i_used;
+        if( !p_sys->p_ff_pic->opaque )
+        {
+            /* Get a new picture */
+            p_pic = ffmpeg_NewPictBuf( p_dec, p_sys->p_context );
+            if( !p_pic )
+            {
+                block_Release( p_block );
+                return NULL;
+            }
 
-   /* Update frame late count*/
-    if( p_vdec->pts <= mdate() )
-    {
-        p_vdec->i_frame_late++;
-        if( p_vdec->i_frame_late == 1 )
+            /* Fill p_picture_t from AVVideoFrame and do chroma conversion
+             * if needed */
+            ffmpeg_CopyPicture( p_dec, p_pic, p_sys->p_ff_pic );
+        }
+        else
         {
-            p_vdec->i_frame_late_start = mdate();
+            p_pic = (picture_t *)p_sys->p_ff_pic->opaque;
         }
-    }
-    else
-    {
-        p_vdec->i_frame_late = 0;
-    }
 
-    if( !b_gotpicture || p_vdec->p_ff_pic->linesize[0] == 0 || !b_drawpicture )
-    {
-        return;
-    }
+        /* Set the PTS */
+        if( p_sys->p_ff_pic->pts ) p_sys->i_pts = p_sys->p_ff_pic->pts;
 
-    if( !p_vdec->b_direct_rendering )
-    {
-        p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
-        if( !p_vdec->p_vout )
+        /* Sanity check (seems to be needed for some streams) */
+        if( p_sys->p_ff_pic->pict_type == FF_B_TYPE )
         {
-            msg_Err( p_vdec->p_fifo, "cannot create vout" );
-            p_vdec->p_fifo->b_error = 1; /* abort */
-            return;
+            p_sys->b_has_b_frames = VLC_TRUE;
         }
 
-        /* Get a new picture */
-        while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
+        if( !p_dec->fmt_in.video.i_aspect )
         {
-            if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
+            /* 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 )
             {
-                return;
+                p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR
+                    * p_sys->p_context->width / p_sys->p_context->height;
             }
-            msleep( VOUT_OUTMEM_SLEEP );
         }
 
-        /* fill p_picture_t from AVVideoFrame and do chroma conversion
-         * if needed */
-        ffmpeg_CopyPicture( p_pic, p_vdec->p_ff_pic, p_vdec );
-    }
-    else
-    {
-        p_pic = (picture_t *)p_vdec->p_ff_pic->opaque;
-    }
+        /* Send decoded frame to vout */
+        if( p_sys->i_pts )
+        {
+            p_pic->date = p_sys->i_pts;
 
-    /* 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. */
-    if( p_vdec->p_ff_pic->pict_type == FF_B_TYPE )
-        p_vdec->b_has_b_frames = VLC_TRUE;
-    if( p_vdec->p_ff_pic->pts &&
-        ( !p_vdec->p_context->has_b_frames || !p_vdec->b_has_b_frames ||
-          p_vdec->p_ff_pic->pict_type == FF_B_TYPE ) )
-    {
-        p_vdec->pts = p_vdec->p_ff_pic->pts;
-    }
+            /* interpolate the next PTS */
+            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_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_vdec->pts <= 0 )
-    {
-        p_vdec->pts = mdate() + DEFAULT_PTS_DELAY;  // FIXME
-    }
+            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;
+            }
 
-    /* Send decoded frame to vout */
-    vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->pts );
-    vout_DisplayPicture( p_vdec->p_vout, p_pic );
+            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;
 
-    /* interpolate the next PTS */
-    if( p_vdec->p_context->frame_rate > 0 )
-    {
-        p_vdec->pts += I64C(1000000) * (2 + p_vdec->p_ff_pic->repeat_pict) *
-                       p_vdec->p_context->frame_rate_base /
-                       (2 * p_vdec->p_context->frame_rate);
+            return p_pic;
+        }
+        else
+        {
+            p_dec->pf_vout_buffer_del( p_dec, p_pic );
+        }
     }
 
-    if( i_frame_size > 0 )
-    {
-        goto usenextdata; /* try to use all data */
-    }
+    block_Release( p_block );
+    return NULL;
 }
 
 /*****************************************************************************
- * EndThread: thread destruction
+ * 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_( EndThread_Video )( vdec_thread_t *p_vdec )
+void E_(EndVideoDec)( decoder_t *p_dec )
+{
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
+    if( p_sys->p_ff_pic ) av_free( p_sys->p_ff_pic );
+    E_(ClosePostproc)( p_dec, p_sys->p_pp );
+    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;
 
-#ifdef LIBAVCODEC_PP
-    if( p_vdec->pp_mode )
+    if( !i_size ) return;
+
+    if( p_sys->i_codec_id == CODEC_ID_SVQ3 )
     {
-        pp_free_mode( p_vdec->pp_mode );
-        if( p_vdec->pp_context )
+        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 ) )
         {
-            pp_free_context( p_vdec->pp_context );
+            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;
+            }
         }
     }
-#endif
+    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];
 
-    if( p_vdec->p_ff_pic )
+            msg_Warn( p_dec, "using extra data for RV codec sub_id=%08x",
+                      p_sys->p_context->sub_id );
+        }
+    }
+    else
     {
-        free( p_vdec->p_ff_pic );
+        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 );
     }
-
-    /* We are about to die. Reattach video output to p_vlc. */
-    vout_Request( p_vdec->p_fifo, p_vdec->p_vout, 0, 0, 0, 0 );
 }
 
 /*****************************************************************************
  * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a
  *                     picture_t structure (when not in direct rendering mode).
  *****************************************************************************/
-static void ffmpeg_CopyPicture( picture_t    *p_pic,
-                                AVFrame *p_ff_pic,
-                                vdec_thread_t *p_vdec )
+static void ffmpeg_CopyPicture( decoder_t *p_dec,
+                                picture_t *p_pic, AVFrame *p_ff_pic )
 {
-    int i_plane;
-    int i_size;
-    int i_line;
+    decoder_sys_t *p_sys = p_dec->p_sys;
 
-    uint8_t *p_dst;
-    uint8_t *p_src;
-    int i_src_stride;
-    int i_dst_stride;
-
-    if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
+    if( ffmpeg_PixFmtToChroma( p_sys->p_context->pix_fmt ) )
     {
-#ifdef LIBAVCODEC_PP
-        if( p_vdec->pp_mode && p_vdec->pp_context )
-        {
-            uint8_t *src[3], *dst[3];
-            int     i_src_stride[3], i_dst_stride[3];
+        int i_plane, i_size, i_line;
+        uint8_t *p_dst, *p_src;
+        int i_src_stride, i_dst_stride;
 
-            for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
-            {
-                src[i_plane] = p_ff_pic->data[i_plane];
-                dst[i_plane] = p_pic->p[i_plane].p_pixels;
-
-                i_src_stride[i_plane] = p_ff_pic->linesize[i_plane];
-                i_dst_stride[i_plane] = p_pic->p[i_plane].i_pitch;
-            }
-            pp_postprocess( src, i_src_stride,
-                            dst, i_dst_stride,
-                            p_vdec->p_context->width,
-                            p_vdec->p_context->height,
-                            p_ff_pic->qscale_table, p_ff_pic->qstride,
-                            p_vdec->pp_mode, p_vdec->pp_context,
-                            p_ff_pic->pict_type );
-        }
+        if( p_sys->p_pp && p_sys->b_pp )
+            E_(PostprocPict)( 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];
@@ -703,43 +818,46 @@ static void ffmpeg_CopyPicture( picture_t    *p_pic,
                 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_line = 0; i_line < p_pic->p[i_plane].i_visible_lines;
+                     i_line++ )
                 {
-                    p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
+                    p_dec->p_libvlc->pf_memcpy( p_dst, p_src, i_size );
                     p_src += i_src_stride;
                     p_dst += i_dst_stride;
                 }
             }
-#ifdef LIBAVCODEC_PP
         }
-#endif
     }
     else
     {
+        AVPicture dest_pic;
+        int i;
+
         /* we need to convert to I420 */
-        switch( p_vdec->p_context->pix_fmt )
+        switch( p_sys->p_context->pix_fmt )
         {
-            AVPicture dest_pic;
-            int i;
-
-            case( PIX_FMT_YUV410P ):
-            case( PIX_FMT_YUV411P ):
-                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;
-                }
-                img_convert( &dest_pic, PIX_FMT_YUV420P,
-                             (AVPicture *)p_ff_pic,
-                             p_vdec->p_context->pix_fmt,
-                             p_vdec->p_context->width,
-                             p_vdec->p_context->height );
-                break;
-            default:
-                msg_Err( p_vdec->p_fifo, "don't know how to convert chroma %i",
-                         p_vdec->p_context->pix_fmt );
-                p_vdec->p_fifo->b_error = 1;
-                break;
+        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_LIBSWSCALE_SWSCALE_H)  && !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",
+                     p_sys->p_context->pix_fmt );
+            p_dec->b_error = 1;
+            break;
         }
     }
 }
@@ -753,23 +871,37 @@ static void ffmpeg_CopyPicture( picture_t    *p_pic,
 static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
                                AVFrame *p_ff_pic )
 {
-    vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
+    decoder_t *p_dec = (decoder_t *)p_context->opaque;
+    decoder_sys_t *p_sys = p_dec->p_sys;
     picture_t *p_pic;
 
     /* Set picture PTS */
-    if( p_context->flags & CODEC_FLAG_TRUNCATED )
+    if( p_sys->input_pts )
     {
-        p_ff_pic->pts = p_vdec->input_pts_previous;
-        p_vdec->input_pts_previous = 0;
+        p_ff_pic->pts = p_sys->input_pts;
     }
-    else
+    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_ff_pic->pts = p_vdec->input_pts;
-        p_vdec->input_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_vdec->b_direct_rendering )
+    if( !p_sys->b_direct_rendering || p_sys->b_pp )
     {
         return avcodec_default_get_buffer( p_context, p_ff_pic );
     }
@@ -777,36 +909,22 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
     /* Some codecs set pix_fmt only after the 1st frame has been decoded,
      * so this check is necessary. */
     if( !ffmpeg_PixFmtToChroma( p_context->pix_fmt ) ||
-        p_vdec->p_context->width % 16 || p_vdec->p_context->height % 16 )
-    {
-        msg_Dbg( p_vdec->p_fifo, "disabling direct rendering" );
-        p_vdec->b_direct_rendering = 0;
-        return avcodec_default_get_buffer( p_context, p_ff_pic );
-    }
-
-    /* Check and (re)create our vout if needed */
-    p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
-    if( !p_vdec->p_vout )
+        p_sys->p_context->width % 16 || p_sys->p_context->height % 16 )
     {
-        msg_Err( p_vdec->p_fifo, "cannot create vout" );
-        p_vdec->p_fifo->b_error = 1; /* abort */
-        p_vdec->b_direct_rendering = 0;
+        msg_Dbg( p_dec, "disabling direct rendering" );
+        p_sys->b_direct_rendering = 0;
         return avcodec_default_get_buffer( p_context, p_ff_pic );
     }
 
-    p_vdec->p_vout->render.b_allow_modify_pics = 0;
-
     /* Get a new picture */
-    while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
+    //p_sys->p_vout->render.b_allow_modify_pics = 0;
+    p_pic = ffmpeg_NewPictBuf( p_dec, p_sys->p_context );
+    if( !p_pic )
     {
-        if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
-        {
-            p_vdec->b_direct_rendering = 0;
-            return avcodec_default_get_buffer( p_context, p_ff_pic );
-        }
-        msleep( VOUT_OUTMEM_SLEEP );
+        p_sys->b_direct_rendering = 0;
+        return avcodec_default_get_buffer( p_context, p_ff_pic );
     }
-    p_vdec->p_context->draw_horiz_band = NULL;
+    p_sys->p_context->draw_horiz_band = NULL;
 
     p_ff_pic->opaque = (void*)p_pic;
     p_ff_pic->type = FF_BUFFER_TYPE_USER;
@@ -820,23 +938,25 @@ 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_vdec->p_vout, p_pic );
+        p_dec->pf_picture_link( p_dec, p_pic );
     }
+
     /* FIXME what is that, should give good value */
     p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg
 
-    return( 0 );
+    return 0;
 }
 
-static void  ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
-                                     AVFrame *p_ff_pic )
+static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
+                                    AVFrame *p_ff_pic )
 {
-    vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
+    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;
@@ -849,8 +969,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_vdec->p_vout, p_pic );
+        p_dec->pf_picture_unlink( p_dec, p_pic );
     }
 }