]> git.sesse.net Git - vlc/blobdiff - modules/codec/ffmpeg/video.c
* modules/codec/ffmpeg/video.[ch]: another temporary workaround.
[vlc] / modules / codec / ffmpeg / video.c
index fb401c45a028409187e3fa1012f087c858c652ca..265b62236f68404d2714cf90811b2f99c465c720 100644 (file)
@@ -2,7 +2,7 @@
  * video.c: video decoder using ffmpeg library
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: video.c,v 1.14 2002/12/18 16:31:25 fenrir Exp $
+ * $Id: video.c,v 1.39 2003/08/12 17:01:35 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Gildas Bazin <gbazin@netcourrier.com>
 #   include <sys/times.h>
 #endif
 
-#include "avcodec.h"                                               /* ffmpeg */
-
-#include "postprocessing/postprocessing.h"
+/* ffmpeg header */
+#ifdef HAVE_FFMPEG_AVCODEC_H
+#   include <ffmpeg/avcodec.h>
+#else
+#   include <avcodec.h>
+#endif
 
 #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
+
 #include "video.h"
 
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-#if LIBAVCODEC_BUILD >= 4641
 static void ffmpeg_CopyPicture( picture_t *, AVFrame *, vdec_thread_t * );
-#else
-static void ffmpeg_CopyPicture( picture_t *, AVPicture *, vdec_thread_t * );
-#endif
 
-static void ffmpeg_PostProcPicture( vdec_thread_t *, picture_t * );
-
-#if LIBAVCODEC_BUILD >= 4641
-static int  ffmpeg_GetFrameBuf( struct AVCodecContext *, AVFrame *);
-static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *, AVFrame *);
-#endif
+static int  ffmpeg_GetFrameBuf      ( struct AVCodecContext *, AVFrame * );
+static void ffmpeg_ReleaseFrameBuf  ( struct AVCodecContext *, AVFrame * );
 
 /*****************************************************************************
  * Local Functions
  *****************************************************************************/
-
 static inline uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma )
 {
     /* FIXME FIXME some of them are wrong */
@@ -81,9 +87,8 @@ static inline uint32_t ffmpeg_PixFmtToChroma( int i_ff_chroma )
             return( VLC_FOURCC('I','4','2','2') );
         case PIX_FMT_YUV444P:
             return( VLC_FOURCC('I','4','4','4') );
-#if LIBAVCODEC_BUILD >= 4615
         case PIX_FMT_YUV410P:
-#endif
+        case PIX_FMT_YUV411P:
         case PIX_FMT_BGR24:
         default:
             return( 0 );
@@ -96,7 +101,7 @@ static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t  *p_vdec,
 {
     vout_thread_t *p_vout;
     unsigned int   i_width = p_context->width;
-    unsigned int   i_height =p_context->height;
+    unsigned int   i_height = p_context->height;
     uint32_t       i_chroma = ffmpeg_PixFmtToChroma( p_context->pix_fmt );
     unsigned int   i_aspect;
 
@@ -109,144 +114,58 @@ static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t  *p_vdec,
     {
         /* we make conversion if possible*/
         i_chroma = VLC_FOURCC('I','4','2','0');
-        msg_Warn( p_vdec->p_fifo, "Internal chroma conversion (FIXME)");
-        /* It's mainly for I410 -> I420 conversion that I've made,
-           it's buggy and very slow */
     }
-#if LIBAVCODEC_BUILD >= 4640
+
     i_aspect = VOUT_ASPECT_FACTOR * p_context->aspect_ratio;
     if( i_aspect == 0 )
     {
         i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
     }
-#else
-    switch( p_context->aspect_ratio_info )
-    {
-        case( FF_ASPECT_4_3_625 ):
-        case( FF_ASPECT_4_3_525 ):
-            i_aspect = VOUT_ASPECT_FACTOR * 4 / 3;
-            break;
-        case( FF_ASPECT_16_9_625 ):
-        case( FF_ASPECT_16_9_525 ):
-            i_aspect = VOUT_ASPECT_FACTOR * 16 / 9 ;
-            break;
-        case( FF_ASPECT_SQUARE ):
-        default:
-            i_aspect = VOUT_ASPECT_FACTOR * i_width / i_height;
-            break;
-        }
-#endif
 
     /* 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, NULL,
+    p_vout = vout_Request( p_vdec->p_fifo, p_vdec->p_vout,
                            i_width, i_height, i_chroma, i_aspect );
-
-    return p_vout;
-}
-
-/* FIXME FIXME FIXME this is a big shit
-   does someone want to rewrite this function ?
-   or said to me how write a better thing
-   FIXME FIXME FIXME
-*/
-#if LIBAVCODEC_BUILD >= 4641
-static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic,
-                                             AVFrame *p_ff_pic,
-                                             vdec_thread_t   *p_vdec )
-#else
-static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic,
-                                             AVPicture *p_ff_pic,
-                                             vdec_thread_t   *p_vdec )
-#endif
-{
-    uint8_t *p_src, *p_dst;
-    uint8_t *p_plane[3];
-    int i_plane;
-
-    int i_stride, i_lines;
-    int i_height, i_width;
-    int i_y, i_x;
-
-    i_height = p_vdec->p_context->height;
-    i_width  = p_vdec->p_context->width;
-
-    p_dst = p_pic->p[0].p_pixels;
-    p_src  = p_ff_pic->data[0];
-
-    /* copy first plane */
-    for( i_y = 0; i_y < i_height; i_y++ )
+#ifdef LIBAVCODEC_PP
+    if( p_vdec->pp_mode && !p_vdec->pp_context )
     {
-        p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_width);
-        p_dst += p_pic->p[0].i_pitch;
-        p_src += p_ff_pic->linesize[0];
-    }
+        int32_t i_cpu = p_vdec->p_fifo->p_libvlc->i_cpu;
+        int i_flags = 0;
 
-    /* process each plane in a temporary buffer */
-    for( i_plane = 1; i_plane < 3; i_plane++ )
-    {
-        i_stride = p_ff_pic->linesize[i_plane];
-        i_lines = i_height / 4;
-
-        p_dst = p_plane[i_plane] = malloc( i_lines * i_stride * 2 * 2 );
-        p_src  = p_ff_pic->data[i_plane];
-
-        /* for each source line */
-        for( i_y = 0; i_y < i_lines; i_y++ )
+        if( i_cpu & CPU_CAPABILITY_MMX )
         {
-            for( i_x = 0; i_x < i_stride - 1; i_x++ )
-            {
-                p_dst[2 * i_x    ] = p_src[i_x];
-                p_dst[2 * i_x + 1] = ( p_src[i_x] + p_src[i_x + 1]) / 2;
-
-            }
-            p_dst[2 * i_stride - 2] = p_src[i_x];
-            p_dst[2 * i_stride - 1] = p_src[i_x];
-
-            p_dst += 4 * i_stride; /* process the next even lines */
-            p_src += i_stride;
+            i_flags |= PP_CPU_CAPS_MMX;
         }
-    }
-
-    for( i_plane = 1; i_plane < 3; i_plane++ )
-    {
-        i_stride = p_ff_pic->linesize[i_plane];
-        i_lines = i_height / 4;
-
-        p_dst = p_plane[i_plane] + 2*i_stride;
-        p_src  = p_plane[i_plane];
-
-        for( i_y = 0; i_y < i_lines - 1; i_y++ )
+        if( i_cpu & CPU_CAPABILITY_MMXEXT )
         {
-            for( i_x = 0; i_x <  2 * i_stride ; i_x++ )
-            {
-                p_dst[i_x] = ( p_src[i_x] + p_src[i_x + 4*i_stride])/2;
-            }
-
-            p_dst += 4 * i_stride; /* process the next odd lines */
-            p_src += 4 * i_stride;
+            i_flags |= PP_CPU_CAPS_MMX2;
+        }
+        if( i_cpu & CPU_CAPABILITY_3DNOW )
+        {
+            i_flags |= PP_CPU_CAPS_3DNOW;
         }
-        /* last line */
-        p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, 2*i_stride );
-    }
-    /* copy to p_pic, by block
-       if I do pixel per pixel it segfault. It's why I use
-       temporaries buffers */
-    for( i_plane = 1; i_plane < 3; i_plane++ )
-    {
-        int i_size;
-        p_src  = p_plane[i_plane];
-        p_dst = p_pic->p[i_plane].p_pixels;
 
-        i_size = __MIN( 2*i_stride, p_pic->p[i_plane].i_pitch);
-        for( i_y = 0; i_y < __MIN(p_pic->p[i_plane].i_lines, 2 * i_lines); i_y++ )
+        switch( p_context->pix_fmt )
         {
-            p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
-            p_src += 2 * i_stride;
-            p_dst += p_pic->p[i_plane].i_pitch;
+            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;
         }
-        free( p_plane[i_plane] );
+
+        p_vdec->pp_context = pp_get_context( i_width, i_height, i_flags );
     }
+#endif
+
+    return p_vout;
 }
 
 /*****************************************************************************
@@ -269,25 +188,29 @@ static void ffmpeg_ConvertPictureI410toI420( picture_t *p_pic,
  * ffmpeg codec will be open, some memory allocated. But Vout is not yet
  * open (done after the first decoded frame)
  *****************************************************************************/
+static inline void SetDWBE( void *data, uint32_t dw )
+{
+    uint8_t *p = data;
+
+    p[0] = (dw >> 24 )&0xff;
+    p[1] = (dw >> 16 )&0xff;
+    p[2] = (dw >>  8 )&0xff;
+    p[3] = (dw )&0xff;
+}
+
 int E_( InitThread_Video )( vdec_thread_t *p_vdec )
 {
     int i_tmp;
-#if LIBAVCODEC_BUILD >= 4645
+    int i_truncated;
+
     p_vdec->p_ff_pic = avcodec_alloc_frame();
-#elif LIBAVCODEC_BUILD >= 4641
-    p_vdec->p_ff_pic = avcodec_alloc_picture();
-#else
-    p_vdec->p_ff_pic = &p_vdec->ff_pic;
-#endif
 
-    if( p_vdec->p_fifo->p_demux_data )
+    if( ( p_vdec->p_format =
+          (BITMAPINFOHEADER *)p_vdec->p_fifo->p_bitmapinfoheader ) != NULL )
     {
-        p_vdec->p_format = (BITMAPINFOHEADER *)p_vdec->p_fifo->p_demux_data;
-
         /* ***** 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;
-
     }
     else
     {
@@ -295,47 +218,31 @@ int E_( InitThread_Video )( vdec_thread_t *p_vdec )
         p_vdec->p_format = NULL;
     }
 
-
     /*  ***** Get configuration of ffmpeg plugin ***** */
-#if LIBAVCODEC_BUILD >= 4611
     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 );
-#endif
-#if LIBAVCODEC_BUILD >= 4614
+
     if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
     {
         p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
     }
-#endif
 
     p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
 
-    p_vdec->b_direct_rendering = 0;
-
-#if LIBAVCODEC_BUILD >= 4641
-    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr" ) &&
-        p_vdec->p_codec->capabilities & CODEC_CAP_DR1 &&
-        p_vdec->p_context->pix_fmt != PIX_FMT_YUV410P ) /* <- FIXME */
-    {
-        msg_Dbg( p_vdec->p_fifo, "using direct rendering" );
-        p_vdec->b_direct_rendering = 1;
-        p_vdec->p_context->flags|= CODEC_FLAG_EMU_EDGE;
-        p_vdec->p_context->get_buffer     = ffmpeg_GetFrameBuf;
-        p_vdec->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
-        p_vdec->p_context->opaque = p_vdec;
-
-    }
-#endif
+    /* CODEC_FLAG_TRUNCATED */
 
+    /* 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
-    /* check if codec support truncated frames */
-//    if( p_vdec->p_codec->capabilities & CODEC_FLAG_TRUNCATED )
-    if( p_vdec->i_codec_id == CODEC_ID_MPEG1VIDEO)
+        ||
+        ( i_truncated == -1 && ( p_vdec->p_context->width == 0 || p_vdec->p_context->height == 0 ) ) )
+#endif
     {
-        msg_Dbg( p_vdec->p_fifo, "CODEC_FLAG_TRUNCATED supported" );
         p_vdec->p_context->flags |= CODEC_FLAG_TRUNCATED;
     }
 #endif
@@ -345,7 +252,7 @@ int E_( InitThread_Video )( vdec_thread_t *p_vdec )
     {
         msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
                                  p_vdec->psz_namecodec );
-        return( -1 );
+        return( VLC_EGENERIC );
     }
     else
     {
@@ -353,125 +260,129 @@ int E_( InitThread_Video )( vdec_thread_t *p_vdec )
                                  p_vdec->psz_namecodec );
     }
 
+    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) )
+    {
+        /* 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;
+    }
+
+    /* ***** 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" );
+
+        if( !psz_name )
+        {
+            psz_name = strdup( "default" );
+        }
+        else if( *psz_name == '\0' )
+        {
+            free( psz_name );
+            psz_name = strdup( "default" );
+        }
+
+        p_vdec->pp_mode =
+            pp_get_mode_by_name_and_quality( psz_name, i_quality );
+
+        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 );
+
+        /* for now we cannot do postproc and dr */
+        p_vdec->b_direct_rendering = 0;
+    }
+    else
+    {
+        msg_Dbg( p_vdec->p_fifo, "no postproc" );
+    }
+#endif
+
+    /* ffmpeg doesn't properly release old pictures when frames are skipped */
+    if( p_vdec->b_hurry_up ) p_vdec->b_direct_rendering = 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;
+
+    if( p_vdec->b_direct_rendering )
+    {
+        msg_Dbg( p_vdec->p_fifo, "using direct rendering" );
+        p_vdec->p_context->flags |= CODEC_FLAG_EMU_EDGE;
+    }
+
     /* ***** init this codec with special data ***** */
     if( p_vdec->p_format &&
             p_vdec->p_format->biSize > sizeof(BITMAPINFOHEADER) )
     {
         int b_gotpicture;
+        int i_size = p_vdec->p_format->biSize - sizeof(BITMAPINFOHEADER);
 
-        switch( p_vdec->i_codec_id )
+        if( p_vdec->i_codec_id == CODEC_ID_MPEG4 )
         {
-            case( CODEC_ID_MPEG4 ):
-#if 0
-                avcodec_decode_video( p_vdec->p_context, p_vdec->p_ff_pic,
-                                      &b_gotpicture,
-                                      (void *)&p_vdec->p_format[1],
-                                      p_vdec->p_format->biSize
-                                        - sizeof(BITMAPINFOHEADER) );
-#endif
-                break;
-            default:
-                if( p_vdec->p_fifo->i_fourcc == FOURCC_MP4S ||
-                    p_vdec->p_fifo->i_fourcc == FOURCC_mp4s ||
-                    p_vdec->p_fifo->i_fourcc == FOURCC_M4S2 ||
-                    p_vdec->p_fifo->i_fourcc == FOURCC_m4s2 ||
-                    p_vdec->p_fifo->i_fourcc == FOURCC_WMV2 ||
-                    p_vdec->p_fifo->i_fourcc == FOURCC_MJPG ||
-                    p_vdec->p_fifo->i_fourcc == FOURCC_mjpg ||
-                    p_vdec->p_fifo->i_fourcc == FOURCC_mjpa ||
-                    p_vdec->p_fifo->i_fourcc == FOURCC_mjpb )
-                {
-                    p_vdec->p_context->extradata_size =
-                        p_vdec->p_format->biSize - sizeof(BITMAPINFOHEADER);
-                    p_vdec->p_context->extradata =
-                        malloc( p_vdec->p_context->extradata_size );
-                    memcpy( p_vdec->p_context->extradata,
-                            &p_vdec->p_format[1],
-                            p_vdec->p_context->extradata_size );
-                }
+            uint8_t *p_vol = malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE );
 
-                break;
+            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;
 
-    /* ***** Load post processing ***** */
+            p_vdec->p_context->extradata_size = i_size + 12;
+            p = p_vdec->p_context->extradata  =
+                malloc( p_vdec->p_context->extradata_size );
 
-    /* get overridding settings */
-    p_vdec->i_pp_mode = 0;
-    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yv" ) )
-        p_vdec->i_pp_mode |= PP_DEBLOCK_Y_V;
-    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-yh" ) )
-        p_vdec->i_pp_mode |= PP_DEBLOCK_Y_H;
-    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-cv" ) )
-        p_vdec->i_pp_mode |= PP_DEBLOCK_C_V;
-    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-db-ch" ) )
-        p_vdec->i_pp_mode |= PP_DEBLOCK_C_H;
-    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-y" ) )
-        p_vdec->i_pp_mode |= PP_DERING_Y;
-    if( config_GetInt( p_vdec->p_fifo, "ffmpeg-dr-c" ) )
-        p_vdec->i_pp_mode |= PP_DERING_C;
-
-    if( ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ) > 0 )||
-        ( config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )  )||
-        ( p_vdec->i_pp_mode != 0 ) )
-    {
-        /* check if the codec support postproc. */
-        switch( p_vdec->i_codec_id )
-        {
-#if LIBAVCODEC_BUILD > 4608
-            case( CODEC_ID_MSMPEG4V1 ):
-            case( CODEC_ID_MSMPEG4V2 ):
-            case( CODEC_ID_MSMPEG4V3 ):
-#else
-            case( CODEC_ID_MSMPEG4 ):
-#endif
-            case( CODEC_ID_MPEG4 ):
-            case( CODEC_ID_H263 ):
-//            case( CODEC_ID_H263P ): I don't use it up to now
-            case( CODEC_ID_H263I ):
-                /* Ok we can make postprocessing :)) */
-                /* first try to get a postprocess module */
-#if LIBAVCODEC_BUILD >= 4633
-                p_vdec->p_pp = vlc_object_create( p_vdec->p_fifo,
-                                                  sizeof( postprocessing_t ) );
-                p_vdec->p_pp->psz_object_name = "postprocessing";
-                p_vdec->p_pp->p_module =
-                   module_Need( p_vdec->p_pp, "postprocessing", "$ffmpeg-pp" );
-
-                if( !p_vdec->p_pp->p_module )
-                {
-                    msg_Warn( p_vdec->p_fifo,
-                              "no suitable postprocessing module" );
-                    vlc_object_destroy( p_vdec->p_pp );
-                    p_vdec->p_pp = NULL;
-                    p_vdec->i_pp_mode = 0;
-                }
-                else
-                {
-                    /* get mode upon quality */
-                    p_vdec->i_pp_mode |=
-                        p_vdec->p_pp->pf_getmode(
-                              config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-q" ),
-                              config_GetInt( p_vdec->p_fifo, "ffmpeg-pp-auto" )
-                                                );
-                }
-#else
-                p_vdec->i_pp_mode = 0;
-                msg_Warn( p_vdec->p_fifo,
-                          "post-processing not supported, upgrade ffmpeg" );
+            memcpy( &p[0],  "SVQ3", 4 );
+            memset( &p[4], 0, 8 );
+            memcpy( &p[12], &p_vdec->p_format[1], i_size );
+        }
 #endif
-                break;
-            default:
-                p_vdec->i_pp_mode = 0;
-                msg_Warn( p_vdec->p_fifo,
-                          "Post processing unsupported for this codec" );
-                break;
+        else
+        {
+            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 );
         }
-
     }
-//    memset( &p_vdec->statistic, 0, sizeof( statistic_t ) );
+    p_vdec->p_vout = NULL;
 
-    return( 0 );
+    p_vdec->input_pts_previous = 0;
+    p_vdec->input_pts = 0;
+
+    p_vdec->b_has_b_frames = VLC_FALSE;
+
+    return( VLC_SUCCESS );
 }
 
 /*****************************************************************************
@@ -487,12 +398,11 @@ void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
     int     i_used;
     int     b_drawpicture;
     int     b_gotpicture;
-    picture_t *p_pic;                                    /* videolan picture */
-    mtime_t   i_pts;
+    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_vdec->b_hurry_up && p_vdec->i_frame_late > 4 )
     {
         b_drawpicture = 0;
         if( p_vdec->i_frame_late < 8 )
@@ -514,6 +424,30 @@ void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
         p_vdec->p_context->hurry_up = 0;
     }
 
+    if( p_vdec->i_frame_late > 0 &&
+        mdate() - p_vdec->i_frame_late_start > (mtime_t)5000000 )
+    {
+        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_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 );
+
+        } while( p_vdec->input_pts <= 0 || p_vdec->input_pts < mdate() );
+    }
+
     if( !p_vdec->p_context->width || !p_vdec->p_context->height )
     {
         p_vdec->p_context->hurry_up = 5;
@@ -527,28 +461,11 @@ void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
             p_vdec->p_fifo->b_error = 1;
             return;
         }
-#if 0
-        if( p_vdec->i_codec_id == CODEC_ID_MPEG1VIDEO )
-        {
-            if( p_pes->i_dts )
-            {
-                p_vdec->pts = p_pes->i_dts;
-                p_vdec->i_frame_count = 0;
-            }
-        }
-        else
-        {
-            if( p_pes->i_pts )
-            {
-                p_vdec->pts = p_pes->i_pts;
-                p_vdec->i_frame_count = 0;
-            }
-        }
-#endif
-        if( p_pes->i_pts )
+
+        if( p_pes->i_pts > 0 )
         {
-            p_vdec->pts = p_pes->i_pts;
-            p_vdec->i_frame_count = 0;
+            p_vdec->input_pts_previous = p_vdec->input_pts;
+            p_vdec->input_pts = p_pes->i_pts;
         }
 
         i_frame_size = p_pes->i_pes_size;
@@ -559,7 +476,7 @@ void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
             int i_need;
             /* XXX Don't forget that ffmpeg required a little more bytes
              * that the real frame size */
-            i_need = i_frame_size + 16 + p_vdec->i_buffer;
+            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;
@@ -573,13 +490,13 @@ void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
             }
             i_frame_size =
                 E_( GetPESData )( p_vdec->p_buffer + p_vdec->i_buffer,
-                                  i_frame_size ,
-                                  p_pes );
+                                  i_frame_size , p_pes );
             memset( p_vdec->p_buffer + p_vdec->i_buffer + i_frame_size,
-                    0,
-                    16 );
+                    0, FF_INPUT_BUFFER_PADDING_SIZE );
         }
+
         input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
+
     } while( i_frame_size <= 0 );
 
     i_frame_size += p_vdec->i_buffer;
@@ -591,6 +508,8 @@ usenextdata:
                                    p_vdec->p_buffer,
                                    i_frame_size );
 
+    if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error ) return;
+
 #if 0
     msg_Dbg( p_vdec->p_fifo,
              "used:%d framesize:%d (%s picture)",
@@ -606,10 +525,6 @@ usenextdata:
     }
     else if( i_used < i_frame_size )
     {
-#if 0
-        msg_Dbg( p_vdec->p_fifo,
-                 "didn't use all memory(%d  < %d)", i_used, i_frame_size );
-#endif
         memmove( p_vdec->p_buffer,
                  p_vdec->p_buffer + i_used,
                  p_vdec->i_buffer_size - i_used );
@@ -621,19 +536,17 @@ usenextdata:
         p_vdec->i_buffer = 0;
     }
 
-    if( b_gotpicture )
-    {
-        p_vdec->i_frame_count++;
-    }
-
     /* consumed bytes */
     i_frame_size -= i_used;
 
    /* Update frame late count*/
-    /* I don't make statistic on decoding time */
-    if( p_vdec->pts <= mdate())
+    if( p_vdec->pts <= mdate() )
     {
         p_vdec->i_frame_late++;
+        if( p_vdec->i_frame_late == 1 )
+        {
+            p_vdec->i_frame_late_start = mdate();
+        }
     }
     else
     {
@@ -665,48 +578,45 @@ usenextdata:
             msleep( VOUT_OUTMEM_SLEEP );
         }
 
-        /* fill p_picture_t from AVVideoFrame, do I410->I420 if needed */
+        /* fill p_picture_t from AVVideoFrame and do chroma conversion
+         * if needed */
         ffmpeg_CopyPicture( p_pic, p_vdec->p_ff_pic, p_vdec );
     }
     else
     {
-#if LIBAVCODEC_BUILD >= 4641
         p_pic = (picture_t *)p_vdec->p_ff_pic->opaque;
-#else
-        p_pic = NULL; /*  f**ck gcc warning */
-#endif
     }
 
-    /* Do post-processing if requested */
-    /* XXX: with dr it is not a good thing if the picture will be used as
-       reference... */
-    ffmpeg_PostProcPicture( p_vdec, p_pic );
-
-    /* fix date calculation */
-    if( p_vdec->pts > 0 )
+    /* 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 ) )
     {
-        i_pts = p_vdec->pts;
-
-        if( p_vdec->p_context->frame_rate > 0 )
-        {
-           i_pts += (uint64_t)1000000 *
-                    ( p_vdec->i_frame_count - 1) /
-                    FRAME_RATE_BASE /
-                    p_vdec->p_context->frame_rate;
-        }
+        p_vdec->pts = p_vdec->p_ff_pic->pts;
+msg_Err( p_vdec->p_fifo, "new pts: "I64Fd, p_vdec->pts );
     }
-    else
+
+    if( p_vdec->pts <= 0 )
     {
-        i_pts = mdate() + DEFAULT_PTS_DELAY;  // FIXME
+        p_vdec->pts = mdate() + DEFAULT_PTS_DELAY;  // FIXME
     }
 
-    vout_DatePicture( p_vdec->p_vout,
-                      p_pic,
-                      i_pts );
-
     /* Send decoded frame to vout */
+    vout_DatePicture( p_vdec->p_vout, p_pic, p_vdec->pts );
     vout_DisplayPicture( p_vdec->p_vout, p_pic );
 
+    /* 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);
+    }
+
     if( i_frame_size > 0 )
     {
         goto usenextdata; /* try to use all data */
@@ -722,20 +632,21 @@ usenextdata:
 void E_( EndThread_Video )( vdec_thread_t *p_vdec )
 {
 
-    if( p_vdec->p_pp )
+#ifdef LIBAVCODEC_PP
+    if( p_vdec->pp_mode )
     {
-        /* release postprocessing module */
-        module_Unneed( p_vdec->p_pp, p_vdec->p_pp->p_module );
-        vlc_object_destroy( p_vdec->p_pp );
-        p_vdec->p_pp = NULL;
+        pp_free_mode( p_vdec->pp_mode );
+        if( p_vdec->pp_context )
+        {
+            pp_free_context( p_vdec->pp_context );
+        }
     }
+#endif
 
-#if LIBAVCODEC_BUILD >= 4641
     if( p_vdec->p_ff_pic )
     {
         free( p_vdec->p_ff_pic );
     }
-#endif
 
     /* 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 );
@@ -745,15 +656,9 @@ void E_( EndThread_Video )( vdec_thread_t *p_vdec )
  * ffmpeg_CopyPicture: copy a picture from ffmpeg internal buffers to a
  *                     picture_t structure (when not in direct rendering mode).
  *****************************************************************************/
-#if LIBAVCODEC_BUILD >= 4641
 static void ffmpeg_CopyPicture( picture_t    *p_pic,
                                 AVFrame *p_ff_pic,
                                 vdec_thread_t *p_vdec )
-#else
-static void ffmpeg_CopyPicture( picture_t    *p_pic,
-                                AVPicture *p_ff_pic,
-                                vdec_thread_t *p_vdec )
-#endif
 {
     int i_plane;
     int i_size;
@@ -766,85 +671,130 @@ static void ffmpeg_CopyPicture( picture_t    *p_pic,
 
     if( ffmpeg_PixFmtToChroma( p_vdec->p_context->pix_fmt ) )
     {
-        for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
+#ifdef LIBAVCODEC_PP
+        if( p_vdec->pp_mode && p_vdec->pp_context )
         {
-            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;
+            uint8_t *src[3], *dst[3];
+            int     i_src_stride[3], i_dst_stride[3];
+
+            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_size = __MIN( i_src_stride, i_dst_stride );
-            for( i_line = 0; i_line < p_pic->p[i_plane].i_lines; i_line++ )
+                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 );
+        }
+        else
+        {
+#endif
+            for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
             {
-                p_vdec->p_fifo->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_lines; i_line++ )
+                {
+                    p_vdec->p_fifo->p_vlc->pf_memcpy( p_dst, p_src, i_size );
+                    p_src += i_src_stride;
+                    p_dst += i_dst_stride;
+                }
             }
+#ifdef LIBAVCODEC_PP
         }
+#endif
     }
     else
     {
         /* we need to convert to I420 */
         switch( p_vdec->p_context->pix_fmt )
         {
-#if LIBAVCODEC_BUILD >= 4615
+            AVPicture dest_pic;
+            int i;
+
             case( PIX_FMT_YUV410P ):
-                ffmpeg_ConvertPictureI410toI420( p_pic, p_ff_pic, p_vdec );
+            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;
-#endif
             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;
         }
     }
 }
 
-/*****************************************************************************
- * ffmpeg_PostProcPicture: Postprocessing is done here.
- *****************************************************************************/
-static void ffmpeg_PostProcPicture( vdec_thread_t *p_vdec, picture_t *p_pic )
-{
-    if( ( p_vdec->i_pp_mode )&&
-        ( ( p_vdec->p_vout->render.i_chroma ==
-            VLC_FOURCC( 'I','4','2','0' ) )||
-          ( p_vdec->p_vout->render.i_chroma ==
-            VLC_FOURCC( 'Y','V','1','2' ) ) ) )
-    {
-#if LIBAVCODEC_BUILD >= 4641
-       /* Make postproc */
-        p_vdec->p_pp->pf_postprocess( p_pic,
-                                      p_vdec->p_ff_pic->qscale_table,
-                                      p_vdec->p_ff_pic->qstride,
-                                      p_vdec->i_pp_mode );
-#elif LIBAVCODEC_BUILD >= 4633
-        p_vdec->p_pp->pf_postprocess( p_pic,
-                                      p_vdec->p_context->display_qscale_table,
-                                      p_vdec->p_context->qstride,
-                                      p_vdec->i_pp_mode );
-#endif
-    }
-}
-
-#if LIBAVCODEC_BUILD >= 4641
 /*****************************************************************************
  * ffmpeg_GetFrameBuf: callback used by ffmpeg to get a frame buffer.
- *                     (used for direct rendering)
+ *****************************************************************************
+ * It is used for direct rendering as well as to get the right PTS for each
+ * decoded picture (even in indirect rendering mode).
  *****************************************************************************/
-
 static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
                                AVFrame *p_ff_pic )
 {
     vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
     picture_t *p_pic;
 
-    /* Check and (re)create if needed our vout */
+    /* Set picture PTS */
+    if( p_context->flags & CODEC_FLAG_TRUNCATED )
+    {
+        p_ff_pic->pts = p_vdec->input_pts_previous;
+        p_vdec->input_pts_previous = 0;
+    }
+    else
+    {
+        p_ff_pic->pts = p_vdec->input_pts;
+        p_vdec->input_pts = 0;
+    }
+
+    /* Not much to do in indirect rendering mode */
+    if( !p_vdec->b_direct_rendering )
+    {
+        return avcodec_default_get_buffer( p_context, p_ff_pic );
+    }
+
+    /* 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 )
     {
         msg_Err( p_vdec->p_fifo, "cannot create vout" );
         p_vdec->p_fifo->b_error = 1; /* abort */
-        return -1;
+        p_vdec->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 */
@@ -852,16 +802,15 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
     {
         if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
         {
-            return -1;
+            p_vdec->b_direct_rendering = 0;
+            return avcodec_default_get_buffer( p_context, p_ff_pic );
         }
         msleep( VOUT_OUTMEM_SLEEP );
     }
-    p_vdec->p_context->draw_horiz_band= NULL;
+    p_vdec->p_context->draw_horiz_band = NULL;
 
     p_ff_pic->opaque = (void*)p_pic;
-#if LIBAVCODEC_BUILD >= 4645
     p_ff_pic->type = FF_BUFFER_TYPE_USER;
-#endif
     p_ff_pic->data[0] = p_pic->p[0].p_pixels;
     p_ff_pic->data[1] = p_pic->p[1].p_pixels;
     p_ff_pic->data[2] = p_pic->p[2].p_pixels;
@@ -888,7 +837,12 @@ static void  ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
     vdec_thread_t *p_vdec = (vdec_thread_t *)p_context->opaque;
     picture_t *p_pic;
 
-    //msg_Dbg( p_vdec->p_fifo, "ffmpeg_ReleaseFrameBuf" );
+    if( p_ff_pic->type != FF_BUFFER_TYPE_USER )
+    {
+        avcodec_default_release_buffer( p_context, p_ff_pic );
+        return;
+    }
+
     p_pic = (picture_t*)p_ff_pic->opaque;
 
     p_ff_pic->data[0] = NULL;
@@ -896,9 +850,8 @@ static void  ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
     p_ff_pic->data[2] = NULL;
     p_ff_pic->data[3] = NULL;
 
-    vout_UnlinkPicture( p_vdec->p_vout, p_pic );
+    if( p_ff_pic->reference != 0 )
+    {
+        vout_UnlinkPicture( p_vdec->p_vout, p_pic );
+    }
 }
-
-
-#endif
-