]> git.sesse.net Git - vlc/blobdiff - modules/stream_out/transcode.c
* http.c: little fix
[vlc] / modules / stream_out / transcode.c
index c2d047caa1d6fe68722bd4a96767f4197e64b4f7..a693e403478bd15cabb9a19f3ba2c342a4c0f4bf 100644 (file)
@@ -2,9 +2,10 @@
  * transcode.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: transcode.c,v 1.9 2003/05/02 19:37:08 fenrir Exp $
+ * $Id: transcode.c,v 1.49 2003/11/05 18:59:01 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Gildas Bazin <gbazin@netcourrier.com>
  *
  * 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
@@ -30,6 +31,8 @@
 #include <vlc/vlc.h>
 #include <vlc/input.h>
 #include <vlc/sout.h>
+#include <vlc/vout.h>
+#include <vlc/decoder.h>
 
 /* ffmpeg header */
 #ifdef HAVE_FFMPEG_AVCODEC_H
@@ -56,6 +59,19 @@ static int  transcode_video_ffmpeg_new    ( sout_stream_t *, sout_stream_id_t *
 static void transcode_video_ffmpeg_close  ( sout_stream_t *, sout_stream_id_t * );
 static int  transcode_video_ffmpeg_process( sout_stream_t *, sout_stream_id_t *, sout_buffer_t *, sout_buffer_t ** );
 
+static int  transcode_video_ffmpeg_getframebuf( struct AVCodecContext *, AVFrame *);
+
+static int pi_channels_maps[6] =
+{
+    0,
+    AOUT_CHAN_CENTER,   AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
+    AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
+    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
+     | AOUT_CHAN_REARRIGHT,
+    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
+     | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
+};
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
@@ -77,14 +93,23 @@ struct sout_stream_sys_t
 
     vlc_fourcc_t    i_vcodec;   /*    "   video  " "   "      " */
     int             i_vbitrate;
+    int             i_vtolerance;
     int             i_width;
     int             i_height;
+    int             i_b_frames;
+    int             i_key_int;
+    int             i_qmin;
+    int             i_qmax;
+    vlc_bool_t      i_hq;
     vlc_bool_t      b_deinterlace;
 
     int             i_crop_top;
     int             i_crop_bottom;
     int             i_crop_right;
     int             i_crop_left;
+
+    mtime_t         i_input_pts;
+    mtime_t         i_output_pts;
 };
 
 /*****************************************************************************
@@ -106,8 +131,18 @@ static int Open( vlc_object_t *p_this )
 
     p_sys->i_vcodec     = 0;
     p_sys->i_vbitrate   = 0;
+    p_sys->i_vtolerance = -1;
     p_sys->i_width      = 0;
     p_sys->i_height     = 0;
+    p_sys->i_key_int    = -1;
+    p_sys->i_b_frames   = 0;
+    p_sys->i_qmin       = 2;
+    p_sys->i_qmax       = 31;
+#if LIBAVCODEC_BUILD >= 4673
+    p_sys->i_hq         = FF_MB_DECISION_SIMPLE;
+#else
+    p_sys->i_hq         = VLC_FALSE;
+#endif
     p_sys->b_deinterlace= VLC_FALSE;
 
     p_sys->i_crop_top   = 0;
@@ -135,10 +170,13 @@ static int Open( vlc_object_t *p_this )
         if( ( val = sout_cfg_find_value( p_stream->p_cfg, "ab" ) ) )
         {
             p_sys->i_abitrate = atoi( val );
+            if( p_sys->i_abitrate < 4000 )
+            {
+                p_sys->i_abitrate *= 1000;
+            }
         }
 
-        msg_Dbg( p_stream, "codec audio=%4.4s %dHz %d channels %dKb/s",
-                 fcc,
+        msg_Dbg( p_stream, "codec audio=%4.4s %dHz %d channels %dKb/s", fcc,
                  p_sys->i_sample_rate, p_sys->i_channels,
                  p_sys->i_abitrate / 1024 );
     }
@@ -163,6 +201,14 @@ static int Open( vlc_object_t *p_this )
         if( ( val = sout_cfg_find_value( p_stream->p_cfg, "vb" ) ) )
         {
             p_sys->i_vbitrate = atoi( val );
+            if( p_sys->i_vbitrate < 16000 )
+            {
+                p_sys->i_vbitrate *= 1000;
+            }
+        }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "vt" ) ) )
+        {
+            p_sys->i_vtolerance = atoi( val );
         }
         if( sout_cfg_find( p_stream->p_cfg, "deinterlace" ) )
         {
@@ -185,6 +231,48 @@ static int Open( vlc_object_t *p_this )
         {
             p_sys->i_crop_right = atoi( val );
         }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "keyint" ) ) )
+        {
+            p_sys->i_key_int    = atoi( val );
+        }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "bframes" ) ) )
+        {
+            p_sys->i_b_frames   = atoi( val );
+        }
+#if LIBAVCODEC_BUILD >= 4673
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "hq" ) ) )
+        {
+            if( !strcmp( val, "rd" ) )
+            {
+                p_sys->i_hq = FF_MB_DECISION_RD;
+            }
+            else if( !strcmp( val, "bits" ) )
+            {
+                p_sys->i_hq = FF_MB_DECISION_BITS;
+            }
+            else if( !strcmp( val, "simple" ) )
+            {
+                p_sys->i_hq = FF_MB_DECISION_SIMPLE;
+            }
+            else
+            {
+                p_sys->i_hq = FF_MB_DECISION_RD;
+            }
+        }
+#else
+        if( sout_cfg_find( p_stream->p_cfg, "hq" ) )
+        {
+            p_sys->i_hq = VLC_TRUE;
+        }
+#endif
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "qmin" ) ) )
+        {
+            p_sys->i_qmin   = atoi( val );
+        }
+        if( ( val = sout_cfg_find_value( p_stream->p_cfg, "qmax" ) ) )
+        {
+            p_sys->i_qmax   = atoi( val );
+        }
 
         msg_Dbg( p_stream, "codec video=%4.4s %dx%d %dkb/s",
                  fcc,
@@ -207,13 +295,15 @@ static int Open( vlc_object_t *p_this )
     avcodec_init();
     avcodec_register_all();
 
+    /* ffmpeg needs some padding at the end of each buffer */
+    p_stream->p_sout->i_padding += FF_INPUT_BUFFER_PADDING_SIZE;
+
     return VLC_SUCCESS;
 }
 
 /*****************************************************************************
  * Close:
  *****************************************************************************/
-
 static void Close( vlc_object_t * p_this )
 {
     sout_stream_t       *p_stream = (sout_stream_t*)p_this;
@@ -228,34 +318,26 @@ struct sout_stream_id_t
     vlc_fourcc_t  b_transcode;
     sout_format_t f_src;        /* only if transcoding */
     sout_format_t f_dst;        /*  "   "      " */
+    unsigned int  i_inter_pixfmt; /* intermediary format when transcoding */
 
     /* id of the out stream */
     void *id;
 
+    /* Encoder */
+    encoder_t       *p_encoder;
+    vlc_fourcc_t    b_enc_inited;
+
     /* ffmpeg part */
     AVCodec         *ff_dec;
     AVCodecContext  *ff_dec_c;
 
-
-    vlc_fourcc_t    b_enc_inited;
-    AVCodec         *ff_enc;
-    AVCodecContext  *ff_enc_c;
-
     mtime_t         i_dts;
     mtime_t         i_length;
 
-    int             i_buffer_in;
-    int             i_buffer_in_pos;
-    uint8_t         *p_buffer_in;
-
     int             i_buffer;
     int             i_buffer_pos;
     uint8_t         *p_buffer;
 
-    int             i_buffer_out;
-    int             i_buffer_out_pos;
-    uint8_t         *p_buffer_out;
-
     AVFrame         *p_ff_pic;
     AVFrame         *p_ff_pic_tmp0; /* to do deinterlace */
     AVFrame         *p_ff_pic_tmp1; /* to do pix conversion */
@@ -265,13 +347,16 @@ struct sout_stream_id_t
 };
 
 
-static sout_stream_id_t * Add      ( sout_stream_t *p_stream, sout_format_t *p_fmt )
+static sout_stream_id_t * Add( sout_stream_t *p_stream, sout_format_t *p_fmt )
 {
     sout_stream_sys_t   *p_sys = p_stream->p_sys;
     sout_stream_id_t    *id;
 
     id = malloc( sizeof( sout_stream_id_t ) );
     id->i_dts = 0;
+    id->id = NULL;
+    id->p_encoder = NULL;
+
     if( p_fmt->i_cat == AUDIO_ES && p_sys->i_acodec != 0 )
     {
         msg_Dbg( p_stream,
@@ -303,6 +388,12 @@ static sout_stream_id_t * Add      ( sout_stream_t *p_stream, sout_format_t *p_f
         /* open output stream */
         id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->f_dst );
         id->b_transcode = VLC_TRUE;
+
+        if( id->id == NULL )
+        {
+            free( id );
+            return NULL;
+        }
     }
     else if( p_fmt->i_cat == VIDEO_ES && p_sys->i_vcodec != 0 )
     {
@@ -367,13 +458,14 @@ static int     Del      ( sout_stream_t *p_stream, sout_stream_id_t *id )
         }
     }
 
-    p_sys->p_out->pf_del( p_sys->p_out, id->id );
+    if( id->id ) p_sys->p_out->pf_del( p_sys->p_out, id->id );
     free( id );
 
     return VLC_SUCCESS;
 }
 
-static int     Send     ( sout_stream_t *p_stream, sout_stream_id_t *id, sout_buffer_t *p_buffer )
+static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
+                 sout_buffer_t *p_buffer )
 {
     sout_stream_sys_t   *p_sys = p_stream->p_sys;
 
@@ -419,31 +511,46 @@ static struct
 {
     /* audio */
     { VLC_FOURCC( 'm', 'p', 'g', 'a' ), CODEC_ID_MP2 },
+    { VLC_FOURCC( 'm', 'p', '3', ' ' ), CODEC_ID_MP3LAME },
+    { VLC_FOURCC( 'm', 'p', '4', 'a' ), CODEC_ID_AAC },
     { VLC_FOURCC( 'a', '5', '2', ' ' ), CODEC_ID_AC3 },
     { VLC_FOURCC( 'a', 'c', '3', ' ' ), CODEC_ID_AC3 },
     { VLC_FOURCC( 'w', 'm', 'a', '1' ), CODEC_ID_WMAV1 },
     { VLC_FOURCC( 'w', 'm', 'a', '2' ), CODEC_ID_WMAV2 },
+    { VLC_FOURCC( 'v', 'o', 'r', 'b' ), CODEC_ID_VORBIS },
+    { VLC_FOURCC( 'a', 'l', 'a', 'w' ), CODEC_ID_PCM_ALAW },
 
     /* video */
-    { VLC_FOURCC( 'm', 'p', '4', 'v'),  CODEC_ID_MPEG4 },
     { VLC_FOURCC( 'm', 'p', 'g', 'v' ), CODEC_ID_MPEG1VIDEO },
+    { VLC_FOURCC( 'm', 'p', '1', 'v' ), CODEC_ID_MPEG1VIDEO },
+#if LIBAVCODEC_BUILD >= 4676
+    { VLC_FOURCC( 'm', 'p', '2', 'v' ), CODEC_ID_MPEG2VIDEO },
+#endif
+    { VLC_FOURCC( 'm', 'p', '4', 'v'),  CODEC_ID_MPEG4 },
     { VLC_FOURCC( 'D', 'I', 'V', '1' ), CODEC_ID_MSMPEG4V1 },
     { VLC_FOURCC( 'D', 'I', 'V', '2' ), CODEC_ID_MSMPEG4V2 },
     { VLC_FOURCC( 'D', 'I', 'V', '3' ), CODEC_ID_MSMPEG4V3 },
     { VLC_FOURCC( 'H', '2', '6', '3' ), CODEC_ID_H263 },
     { VLC_FOURCC( 'I', '2', '6', '3' ), CODEC_ID_H263I },
+    { VLC_FOURCC( 'h', 'u', 'f', 'f' ), CODEC_ID_HUFFYUV },
     { VLC_FOURCC( 'W', 'M', 'V', '1' ), CODEC_ID_WMV1 },
     { VLC_FOURCC( 'W', 'M', 'V', '2' ), CODEC_ID_WMV2 },
     { VLC_FOURCC( 'M', 'J', 'P', 'G' ), CODEC_ID_MJPEG },
     { VLC_FOURCC( 'm', 'j', 'p', 'b' ), CODEC_ID_MJPEGB },
     { VLC_FOURCC( 'd', 'v', 's', 'l' ), CODEC_ID_DVVIDEO },
     { VLC_FOURCC( 'S', 'V', 'Q', '1' ), CODEC_ID_SVQ1 },
+#if LIBAVCODEC_BUILD >= 4666
+    { VLC_FOURCC( 'S', 'V', 'Q', '3' ), CODEC_ID_SVQ3 },
+#endif
 
     /* raw video code, only used for 'encoding' */
     { VLC_FOURCC( 'I', '4', '2', '0' ), CODEC_ID_RAWVIDEO },
     { VLC_FOURCC( 'I', '4', '2', '2' ), CODEC_ID_RAWVIDEO },
     { VLC_FOURCC( 'I', '4', '4', '4' ), CODEC_ID_RAWVIDEO },
+    { VLC_FOURCC( 'R', 'V', '1', '5' ), CODEC_ID_RAWVIDEO },
+    { VLC_FOURCC( 'R', 'V', '1', '6' ), CODEC_ID_RAWVIDEO },
     { VLC_FOURCC( 'R', 'V', '2', '4' ), CODEC_ID_RAWVIDEO },
+    { VLC_FOURCC( 'R', 'V', '3', '2' ), CODEC_ID_RAWVIDEO },
     { VLC_FOURCC( 'Y', 'U', 'Y', '2' ), CODEC_ID_RAWVIDEO },
 
     { VLC_FOURCC(   0,   0,   0,   0 ), 0 }
@@ -474,8 +581,16 @@ static inline int get_ff_chroma( vlc_fourcc_t i_chroma )
             return PIX_FMT_YUV422P;
         case VLC_FOURCC( 'I', '4', '4', '4' ):
             return PIX_FMT_YUV444P;
+        case VLC_FOURCC( 'R', 'V', '1', '5' ):
+            return PIX_FMT_RGB555;
+        case VLC_FOURCC( 'R', 'V', '1', '6' ):
+            return PIX_FMT_RGB565;
         case VLC_FOURCC( 'R', 'V', '2', '4' ):
             return PIX_FMT_RGB24;
+        case VLC_FOURCC( 'R', 'V', '3', '2' ):
+            return PIX_FMT_RGBA32;
+        case VLC_FOURCC( 'G', 'R', 'E', 'Y' ):
+            return PIX_FMT_GRAY8;
         case VLC_FOURCC( 'Y', 'U', 'Y', '2' ):
             return PIX_FMT_YUV422;
         default:
@@ -483,7 +598,8 @@ static inline int get_ff_chroma( vlc_fourcc_t i_chroma )
     }
 }
 
-static int transcode_audio_ffmpeg_new   ( sout_stream_t *p_stream, sout_stream_id_t *id )
+static int transcode_audio_ffmpeg_new( sout_stream_t *p_stream,
+                                       sout_stream_id_t *id )
 {
     int i_ff_codec;
 
@@ -506,14 +622,14 @@ static int transcode_audio_ffmpeg_new   ( sout_stream_t *p_stream, sout_stream_i
         i_ff_codec = get_ff_codec( id->f_src.i_fourcc );
         if( i_ff_codec == 0 )
         {
-            msg_Err( p_stream, "cannot find decoder" );
+            msg_Err( p_stream, "cannot find decoder id" );
             return VLC_EGENERIC;
         }
 
         id->ff_dec = avcodec_find_decoder( i_ff_codec );
         if( !id->ff_dec )
         {
-            msg_Err( p_stream, "cannot find decoder" );
+            msg_Err( p_stream, "cannot find decoder (avcodec)" );
             return VLC_EGENERIC;
         }
 
@@ -532,241 +648,223 @@ static int transcode_audio_ffmpeg_new   ( sout_stream_t *p_stream, sout_stream_i
         }
     }
 
-    /* find encoder */
-    i_ff_codec = get_ff_codec( id->f_dst.i_fourcc );
-    if( i_ff_codec == 0 )
-    {
-        msg_Err( p_stream, "cannot find encoder" );
-        return VLC_EGENERIC;
-    }
-
-    id->ff_enc = avcodec_find_encoder( i_ff_codec );
-    if( !id->ff_enc )
-    {
-        msg_Err( p_stream, "cannot find encoder" );
-        return VLC_EGENERIC;
-    }
+    id->i_buffer     = 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE;
+    id->i_buffer_pos = 0;
+    id->p_buffer     = malloc( id->i_buffer );
 
-    id->ff_enc_c = avcodec_alloc_context();
-    id->ff_enc_c->bit_rate    = id->f_dst.i_bitrate;
-    id->ff_enc_c->sample_rate = id->f_dst.i_sample_rate;
-    id->ff_enc_c->channels    = id->f_dst.i_channels;
+    /* Sanity check for audio channels */
+    id->f_dst.i_channels = __MIN( id->f_dst.i_channels, id->f_src.i_channels );
 
-    if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
+    /* find encoder */
+    id->p_encoder = vlc_object_create( p_stream, VLC_OBJECT_ENCODER );
+    id->p_encoder->i_fourcc = id->f_dst.i_fourcc;
+    id->p_encoder->format.audio.i_format = AOUT_FMT_S16_NE;
+    id->p_encoder->format.audio.i_rate = id->f_dst.i_sample_rate;
+    id->p_encoder->format.audio.i_physical_channels =
+        id->p_encoder->format.audio.i_original_channels =
+            pi_channels_maps[id->f_dst.i_channels];
+    id->p_encoder->i_bitrate = id->f_dst.i_bitrate;
+    id->p_encoder->i_extra_data = 0;
+    id->p_encoder->p_extra_data = NULL;
+
+    id->p_encoder->p_module =
+        module_Need( id->p_encoder, "audio encoder", NULL );
+    if( !id->p_encoder->p_module )
     {
+        vlc_object_destroy( id->p_encoder );
         msg_Err( p_stream, "cannot open encoder" );
         return VLC_EGENERIC;
     }
 
+    id->b_enc_inited = VLC_FALSE;
 
-    id->i_buffer_in      = AVCODEC_MAX_AUDIO_FRAME_SIZE;
-    id->i_buffer_in_pos = 0;
-    id->p_buffer_in      = malloc( id->i_buffer_in );
+    id->f_dst.i_extra_data = id->p_encoder->i_extra_data;
+    id->f_dst.p_extra_data = id->p_encoder->p_extra_data;
 
-    id->i_buffer     = AVCODEC_MAX_AUDIO_FRAME_SIZE;
-    id->i_buffer_pos = 0;
-    id->p_buffer     = malloc( id->i_buffer );
-
-    id->i_buffer_out     = AVCODEC_MAX_AUDIO_FRAME_SIZE;
-    id->i_buffer_out_pos = 0;
-    id->p_buffer_out     = malloc( id->i_buffer_out );
+    /* Hack for mp3 transcoding support */
+    if( id->f_dst.i_fourcc == VLC_FOURCC( 'm','p','3',' ' ) )
+    {
+        id->f_dst.i_fourcc = VLC_FOURCC( 'm','p','g','a' );
+    }
 
     return VLC_SUCCESS;
 }
 
-static void transcode_audio_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_id_t *id )
+static void transcode_audio_ffmpeg_close( sout_stream_t *p_stream,
+                                          sout_stream_id_t *id )
 {
     if( id->ff_dec )
     {
         avcodec_close( id->ff_dec_c );
+        free( id->ff_dec_c );
     }
-    avcodec_close( id->ff_enc_c );
 
-    free( id->ff_dec_c );
-    free( id->ff_enc_c );
+    module_Unneed( id->p_encoder, id->p_encoder->p_module );
+    vlc_object_destroy( id->p_encoder );
 
     free( id->p_buffer );
 }
 
-static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream, sout_stream_id_t *id,
-                                           sout_buffer_t *in, sout_buffer_t **out )
+static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
+                                           sout_stream_id_t *id,
+                                           sout_buffer_t *in,
+                                           sout_buffer_t **out )
 {
+    aout_buffer_t aout_buf;
+    block_t *p_block;
+    int i_buffer = in->i_size;
+    char *p_buffer = in->p_buffer;
+    id->i_dts = in->i_dts;
     *out = NULL;
 
-    /* gather data into p_buffer_in */
-    id->i_dts = in->i_dts -
-                (mtime_t)1000000 *
-                (mtime_t)(id->i_buffer_pos / 2 / id->ff_enc_c->channels )/
-                (mtime_t)id->ff_enc_c->sample_rate;
-
-    if( id->i_buffer_in_pos + in->i_size > id->i_buffer_in )
+    while( i_buffer )
     {
-        /* extend buffer_in */
-        id->i_buffer_in = id->i_buffer_in_pos + in->i_size + 1024;
-        id->p_buffer_in = realloc( id->p_buffer_in, id->i_buffer_in );
-    }
-    memcpy( &id->p_buffer_in[id->i_buffer_in_pos],
-            in->p_buffer,
-            in->i_size );
-    id->i_buffer_in_pos += in->i_size;
+        id->i_buffer_pos = 0;
 
-    /* decode as many data as possible */
-    if( id->ff_dec )
-    {
-        for( ;; )
+        /* decode as much data as possible */
+        if( id->ff_dec )
         {
-            int i_buffer_size;
             int i_used;
 
-            i_buffer_size = id->i_buffer - id->i_buffer_pos;
-
             i_used = avcodec_decode_audio( id->ff_dec_c,
-                                           (int16_t*)&id->p_buffer[id->i_buffer_pos], &i_buffer_size,
-                                           id->p_buffer_in, id->i_buffer_in_pos );
-
-            /* msg_Warn( p_stream, "avcodec_decode_audio: %d used", i_used ); */
-            id->i_buffer_pos += i_buffer_size;
+                         (int16_t*)id->p_buffer, &id->i_buffer_pos,
+                         p_buffer, i_buffer );
 
+#if 0
+            msg_Warn( p_stream, "avcodec_decode_audio: %d used on %d",
+                      i_used, i_buffer );
+#endif
             if( i_used < 0 )
             {
-                msg_Warn( p_stream, "error");
-                id->i_buffer_in_pos = 0;
+                msg_Warn( p_stream, "error audio decoding");
                 break;
             }
-            else if( i_used < id->i_buffer_in_pos )
-            {
-                memmove( id->p_buffer_in,
-                         &id->p_buffer_in[i_used],
-                         id->i_buffer_in - i_used );
-                id->i_buffer_in_pos -= i_used;
-            }
-            else
-            {
-                id->i_buffer_in_pos = 0;
-                break;
-            }
-        }
-    }
-    else
-    {
-        int16_t *sout = (int16_t*)&id->p_buffer[id->i_buffer_pos];
-        int     i_used;
 
-        if( id->f_src.i_fourcc == VLC_FOURCC( 's', '8', ' ', ' ' ) )
-        {
-            int8_t *sin = (int8_t*)id->p_buffer_in;
-            int     i_samples = __MIN( ( id->i_buffer - id->i_buffer_pos ) / 2, id->i_buffer_in_pos );
-            i_used = i_samples;
-            while( i_samples > 0 )
-            {
-                *sout++ = ( *sin++ ) << 8;
-                i_samples--;
-            }
+            i_buffer -= i_used;
+            p_buffer += i_used;
         }
-        else if( id->f_src.i_fourcc == VLC_FOURCC( 'u', '8', ' ', ' ' ) )
+        else
         {
-            int8_t *sin = (int8_t*)id->p_buffer_in;
-            int     i_samples = __MIN( ( id->i_buffer - id->i_buffer_pos ) / 2, id->i_buffer_in_pos );
-            i_used = i_samples;
-            while( i_samples > 0 )
+            int16_t *sout = (int16_t*)id->p_buffer;
+
+            if( id->f_src.i_fourcc == VLC_FOURCC( 's', '8', ' ', ' ' ) ||
+                id->f_src.i_fourcc == VLC_FOURCC( 'u', '8', ' ', ' ' ) )
             {
-                *sout++ = ( *sin++ - 128 ) << 8;
-                i_samples--;
+                int8_t *sin = (int8_t*)p_buffer;
+                int i_used = __MIN( id->i_buffer/2, i_buffer );
+                int i_samples = i_used;
+
+                if( id->f_src.i_fourcc == VLC_FOURCC( 's', '8', ' ', ' ' ) )
+                    while( i_samples > 0 )
+                    {
+                        *sout++ = ( *sin++ ) << 8;
+                        i_samples--;
+                    }
+                else
+                    while( i_samples > 0 )
+                    {
+                        *sout++ = ( *sin++ - 128 ) << 8;
+                        i_samples--;
+                    }
+
+                i_buffer -= i_used;
+                p_buffer += i_used;
+                id->i_buffer_pos = i_used * 2;
             }
-        }
-        else if( id->f_src.i_fourcc == VLC_FOURCC( 's', '1', '6', 'l' ) )
-        {
-            int     i_samples = __MIN( ( id->i_buffer - id->i_buffer_pos ) / 2, id->i_buffer_in_pos / 2);
-#ifdef WORDS_BIGENDIAN
-            uint8_t *sin = (uint8_t*)id->p_buffer_in;
-            i_used = i_samples * 2;
-            while( i_samples > 0 )
+            else if( id->f_src.i_fourcc == VLC_FOURCC( 's', '1', '6', 'l' ) ||
+                     id->f_src.i_fourcc == VLC_FOURCC( 's', '1', '6', 'b' ) )
             {
-                uint8_t tmp[2];
-
-                tmp[1] = *sin++;
-                tmp[0] = *sin++;
-                *sout++ = *(int16_t*)tmp;
-                i_samples--;
-            }
+                int16_t *sin = (int16_t*)p_buffer;
+                int i_used = __MIN( id->i_buffer, i_buffer );
+                int i_samples = i_used / 2;
+                int b_invert_indianness;
 
+                if( id->f_src.i_fourcc == VLC_FOURCC( 's', '1', '6', 'l' ) )
+#ifdef WORDS_BIGENDIAN
+                    b_invert_indianness = 1;
 #else
-            memcpy( sout, id->p_buffer_in, i_samples * 2 );
-            sout += i_samples;
-            i_used = i_samples * 2;
+                    b_invert_indianness = 0;
 #endif
-        }
-        else if( id->f_src.i_fourcc == VLC_FOURCC( 's', '1', '6', 'b' ) )
-        {
-            int     i_samples = __MIN( ( id->i_buffer - id->i_buffer_pos ) / 2, id->i_buffer_in_pos / 2);
+                else
 #ifdef WORDS_BIGENDIAN
-            memcpy( sout, id->p_buffer_in, i_samples * 2 );
-            sout += i_samples;
-            i_used = i_samples * 2;
+                    b_invert_indianness = 0;
 #else
-            uint8_t *sin = (uint8_t*)id->p_buffer_in;
-            i_used = i_samples * 2;
-            while( i_samples > 0 )
-            {
-                uint8_t tmp[2];
+                    b_invert_indianness = 1;
+#endif
 
-                tmp[1] = *sin++;
-                tmp[0] = *sin++;
-                *sout++ = *(int16_t*)tmp;
-                i_samples--;
+                if( b_invert_indianness )
+                {
+                    while( i_samples > 0 )
+                    {
+                        uint8_t tmp[2];
+
+                        tmp[1] = *sin++;
+                        tmp[0] = *sin++;
+                        *sout++ = *(int16_t*)tmp;
+                        i_samples--;
+                    }
+                }
+                else
+                {
+                    memcpy( sout, sin, i_used );
+                    sout += i_samples;
+                }
+
+                i_buffer -= i_used;
+                p_buffer += i_used;
+                id->i_buffer_pos = i_used;
             }
-#endif
         }
 
-        id->i_buffer_pos = (uint8_t*)sout - id->p_buffer;
-        if( i_used < id->i_buffer_in_pos )
+        if( id->i_buffer_pos == 0 ) continue;
+
+        /* Encode as much data as possible */
+        if( !id->b_enc_inited && id->p_encoder->pf_header )
         {
-            memmove( id->p_buffer_in,
-                     &id->p_buffer_in[i_used],
-                     id->i_buffer_in - i_used );
-        }
-        id->i_buffer_in_pos -= i_used;
-    }
+            p_block = id->p_encoder->pf_header( id->p_encoder );
+            while( p_block )
+            {
+                sout_buffer_t *p_out;
+                block_t *p_prev_block = p_block;
 
-    /* encode as many data as possible */
-    for( ;; )
-    {
-        int i_frame_size = id->ff_enc_c->frame_size * 2 * id->ff_enc_c->channels;
-        int i_out_size;
-        sout_buffer_t *p_out;
+                p_out = sout_BufferNew( p_stream->p_sout, p_block->i_buffer );
+                memcpy( p_out->p_buffer, p_block->p_buffer, p_block->i_buffer);
+                p_out->i_dts = p_out->i_pts = in->i_dts;
+                p_out->i_length = 0;
+                sout_BufferChain( out, p_out );
 
-        if( id->i_buffer_pos < i_frame_size )
-        {
-            break;
+                p_block = p_block->p_next;
+                block_Release( p_prev_block );
+            }
+
+            id->b_enc_inited = VLC_TRUE;
         }
 
-        /* msg_Warn( p_stream, "avcodec_encode_audio: frame size%d", i_frame_size); */
-        i_out_size = avcodec_encode_audio( id->ff_enc_c,
-                                           id->p_buffer_out, id->i_buffer_out,
-                                           (int16_t*)id->p_buffer );
+        aout_buf.p_buffer = id->p_buffer;
+        aout_buf.i_nb_bytes = id->i_buffer_pos;
+        aout_buf.i_nb_samples = id->i_buffer_pos / 2 / id->f_src.i_channels;
+        aout_buf.start_date = id->i_dts;
+        aout_buf.end_date = id->i_dts;
 
-        if( i_out_size <= 0 )
+        id->i_dts += ( I64C(1000000) * id->i_buffer_pos / 2 /
+            id->f_src.i_channels / id->f_src.i_sample_rate );
+
+        p_block = id->p_encoder->pf_encode_audio( id->p_encoder, &aout_buf );
+        while( p_block )
         {
-            break;
+            sout_buffer_t *p_out;
+            block_t *p_prev_block = p_block;
+
+            p_out = sout_BufferNew( p_stream->p_sout, p_block->i_buffer );
+            memcpy( p_out->p_buffer, p_block->p_buffer, p_block->i_buffer);
+            p_out->i_dts = p_block->i_dts;
+            p_out->i_pts = p_block->i_pts;
+            p_out->i_length = p_block->i_length;
+            sout_BufferChain( out, p_out );
+
+            p_block = p_block->p_next;
+            block_Release( p_prev_block );
         }
-        memmove( id->p_buffer,
-                 &id->p_buffer[i_frame_size],
-                 id->i_buffer - i_frame_size );
-        id->i_buffer_pos -= i_frame_size;
-
-        p_out = sout_BufferNew( p_stream->p_sout, i_out_size );
-        memcpy( p_out->p_buffer, id->p_buffer_out, i_out_size );
-        p_out->i_size = i_out_size;
-        p_out->i_length = (mtime_t)1000000 * (mtime_t)id->ff_enc_c->frame_size / (mtime_t)id->ff_enc_c->sample_rate;
-        /* FIXME */
-        p_out->i_dts = id->i_dts;
-        p_out->i_pts = id->i_dts;
-
-        /* update dts */
-        id->i_dts += p_out->i_length;
-
-       /* msg_Warn( p_stream, "frame dts=%lld len %lld out=%d", p_out->i_dts, p_out->i_length, i_out_size ); */
-        sout_BufferChain( out, p_out );
     }
 
     return VLC_SUCCESS;
@@ -776,17 +874,25 @@ static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
 /*
  * video
  */
-static int transcode_video_ffmpeg_new   ( sout_stream_t *p_stream, sout_stream_id_t *id )
+static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
+                                       sout_stream_id_t *id )
 {
+    sout_stream_sys_t   *p_sys = p_stream->p_sys;
+
     int i_ff_codec;
 
+    /* Open decoder */
     if( id->f_src.i_fourcc == VLC_FOURCC( 'I', '4', '2', '0' ) ||
         id->f_src.i_fourcc == VLC_FOURCC( 'I', '4', '2', '2' ) ||
         id->f_src.i_fourcc == VLC_FOURCC( 'I', '4', '4', '4' ) ||
         id->f_src.i_fourcc == VLC_FOURCC( 'Y', 'U', 'Y', '2' ) ||
-        id->f_src.i_fourcc == VLC_FOURCC( 'R', 'V', '2', '4' ) )
+        id->f_src.i_fourcc == VLC_FOURCC( 'R', 'V', '1', '5' ) ||
+        id->f_src.i_fourcc == VLC_FOURCC( 'R', 'V', '1', '6' ) ||
+        id->f_src.i_fourcc == VLC_FOURCC( 'R', 'V', '2', '4' ) ||
+        id->f_src.i_fourcc == VLC_FOURCC( 'R', 'V', '3', '2' ) ||
+        id->f_src.i_fourcc == VLC_FOURCC( 'G', 'R', 'E', 'Y' ) )
     {
-        id->ff_dec   = NULL;
+        id->ff_dec              = NULL;
         id->ff_dec_c            = avcodec_alloc_context();
         id->ff_dec_c->width     = id->f_src.i_width;
         id->ff_dec_c->height    = id->f_src.i_height;
@@ -817,10 +923,8 @@ static int transcode_video_ffmpeg_new   ( sout_stream_t *p_stream, sout_stream_i
         id->ff_dec_c->extradata     = id->f_src.p_extra_data;
         id->ff_dec_c->workaround_bugs = FF_BUG_AUTODETECT;
         id->ff_dec_c->error_resilience= -1;
-        if( id->ff_dec->capabilities & CODEC_CAP_TRUNCATED )
-        {
-            id->ff_dec_c->flags |= CODEC_FLAG_TRUNCATED;
-        }
+        id->ff_dec_c->get_buffer    = transcode_video_ffmpeg_getframebuf;
+        id->ff_dec_c->opaque        = p_sys;
 
         if( avcodec_open( id->ff_dec_c, id->ff_dec ) < 0 )
         {
@@ -832,80 +936,113 @@ static int transcode_video_ffmpeg_new   ( sout_stream_t *p_stream, sout_stream_i
         {
             int b_gotpicture;
             AVFrame frame;
-
-            avcodec_decode_video( id->ff_dec_c, &frame,
-                                  &b_gotpicture,
-                                  id->ff_dec_c->extradata, id->ff_dec_c->extradata_size );
+            uint8_t *p_vol = malloc( id->ff_dec_c->extradata_size +
+                                     FF_INPUT_BUFFER_PADDING_SIZE );
+
+            memcpy( p_vol, id->ff_dec_c->extradata,
+                    id->ff_dec_c->extradata_size );
+            memset( p_vol + id->ff_dec_c->extradata_size, 0,
+                    FF_INPUT_BUFFER_PADDING_SIZE );
+
+            avcodec_decode_video( id->ff_dec_c, &frame, &b_gotpicture,
+                                  id->ff_dec_c->extradata,
+                                  id->ff_dec_c->extradata_size );
+            free( p_vol );
         }
     }
 
-
-    /* find encoder */
-    i_ff_codec = get_ff_codec( id->f_dst.i_fourcc );
-    if( i_ff_codec == 0 )
+    /* Open encoder */
+    id->p_encoder = vlc_object_create( p_stream, VLC_OBJECT_ENCODER );
+    id->p_encoder->i_fourcc = id->f_dst.i_fourcc;
+    id->p_encoder->format.video.i_width = p_sys->i_width;
+    id->p_encoder->format.video.i_height = p_sys->i_height;
+    id->p_encoder->i_bitrate = p_sys->i_vbitrate;
+
+    id->p_encoder->i_vtolerance = p_sys->i_vtolerance;
+    id->p_encoder->i_key_int = p_sys->i_key_int;
+    id->p_encoder->i_b_frames = p_sys->i_b_frames;
+    id->p_encoder->i_qmin = p_sys->i_qmin;
+    id->p_encoder->i_qmax = p_sys->i_qmax;
+    id->p_encoder->i_hq = p_sys->i_hq;
+
+    if( id->p_encoder->format.video.i_width <= 0 )
     {
-        msg_Err( p_stream, "cannot find encoder" );
-        return VLC_EGENERIC;
+        id->p_encoder->format.video.i_width = id->f_dst.i_width =
+            id->ff_dec_c->width - p_sys->i_crop_left - p_sys->i_crop_right;
     }
-
-    id->ff_enc = avcodec_find_encoder( i_ff_codec );
-    if( !id->ff_enc )
+    if( id->p_encoder->format.video.i_height <= 0 )
     {
-        msg_Err( p_stream, "cannot find encoder" );
-        return VLC_EGENERIC;
+        id->p_encoder->format.video.i_height = id->f_dst.i_height =
+            id->ff_dec_c->height - p_sys->i_crop_top - p_sys->i_crop_bottom;
     }
 
-    id->ff_enc_c = avcodec_alloc_context();
-    id->ff_enc_c->width          = id->f_dst.i_width;
-    id->ff_enc_c->height         = id->f_dst.i_height;
-    id->ff_enc_c->bit_rate       = id->f_dst.i_bitrate;
+    id->p_ff_pic         = avcodec_alloc_frame();
+    id->p_ff_pic_tmp0    = NULL;
+    id->p_ff_pic_tmp1    = NULL;
+    id->p_ff_pic_tmp2    = NULL;
+    id->p_vresample      = NULL;
+
+    if( id->ff_dec )
+    {
+        id->p_encoder->i_frame_rate = id->ff_dec_c->frame_rate;
 #if LIBAVCODEC_BUILD >= 4662
-    id->ff_enc_c->frame_rate     = 25 ; /* FIXME as it break mpeg */
-    id->ff_enc_c->frame_rate_base= 1;
+        id->p_encoder->i_frame_rate_base= id->ff_dec_c->frame_rate_base;
+#endif
+
+#if LIBAVCODEC_BUILD >= 4687
+        id->p_encoder->i_aspect = VOUT_ASPECT_FACTOR *
+            ( av_q2d(id->ff_dec_c->sample_aspect_ratio) *
+              id->ff_dec_c->width / id->ff_dec_c->height );
 #else
-    id->ff_enc_c->frame_rate     = 25 * FRAME_RATE_BASE;
+        id->p_encoder->i_aspect = VOUT_ASPECT_FACTOR *
+            id->ff_dec_c->aspect_ratio;
 #endif
-    id->ff_enc_c->gop_size       = 25;
-    id->ff_enc_c->qmin           = 2;
-    id->ff_enc_c->qmax           = 31;
 
-    if( i_ff_codec == CODEC_ID_RAWVIDEO )
+    }
+    else
     {
-        id->ff_enc_c->pix_fmt = get_ff_chroma( id->f_dst.i_fourcc );
+#if LIBAVCODEC_BUILD >= 4662
+        id->p_encoder->i_frame_rate     = 25 ; /* FIXME as it break mpeg */
+        id->p_encoder->i_frame_rate_base= 1;
+#else
+        id->p_encoder->i_frame_rate     = 25 * FRAME_RATE_BASE;
+#endif
     }
-    /* XXX open it only when we have the first frame */
-    id->b_enc_inited     = VLC_FALSE;
-    id->i_buffer_in      = 0;
-    id->i_buffer_in_pos  = 0;
-    id->p_buffer_in      = NULL;
 
-    id->i_buffer     = 3*1024*1024;
-    id->i_buffer_pos = 0;
-    id->p_buffer     = malloc( id->i_buffer );
+    id->p_encoder->p_module =
+        module_Need( id->p_encoder, "video encoder", NULL );
+
+    if( !id->p_encoder->p_module )
+    {
+        vlc_object_destroy( id->p_encoder );
+        msg_Err( p_stream, "cannot find encoder" );
+        return VLC_EGENERIC;
+    }
 
-    id->i_buffer_out     = 0;
-    id->i_buffer_out_pos = 0;
-    id->p_buffer_out     = NULL;
+    /* Close the encoder.
+     * We'll open it only when we have the first frame */
+    module_Unneed( id->p_encoder, id->p_encoder->p_module );
+
+    id->b_enc_inited = VLC_FALSE;
 
-    id->p_ff_pic         = avcodec_alloc_frame();
-    id->p_ff_pic_tmp0    = NULL;
-    id->p_ff_pic_tmp1    = NULL;
-    id->p_ff_pic_tmp2    = NULL;
-    id->p_vresample      = NULL;
     return VLC_SUCCESS;
 }
 
-static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_id_t *id )
+static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream,
+                                           sout_stream_id_t *id )
 {
+    /* Close decoder */
     if( id->ff_dec )
     {
         avcodec_close( id->ff_dec_c );
+        free( id->ff_dec_c );
     }
-    if( id->b_enc_inited )
-    {
-        avcodec_close( id->ff_enc_c );
-    }
 
+    /* Close encoder */
+    module_Unneed( id->p_encoder, id->p_encoder->p_module );
+    vlc_object_destroy( id->p_encoder );
+
+    /* Misc cleanup */
     if( id->p_ff_pic)
     {
         free( id->p_ff_pic );
@@ -930,18 +1067,13 @@ static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_
     {
         free( id->p_vresample );
     }
-
-    free( id->ff_dec_c );
-    free( id->ff_enc_c );
-
-    free( id->p_buffer );
 }
 
-static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_id_t *id,
-                                           sout_buffer_t *in, sout_buffer_t **out )
+static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
+               sout_stream_id_t *id, sout_buffer_t *in, sout_buffer_t **out )
 {
+    sout_stream_sys_t   *p_sys = p_stream->p_sys;
     int     i_used;
-    int     i_out;
     int     b_gotpicture;
     AVFrame *frame;
 
@@ -952,12 +1084,17 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
 
     i_data = in->i_size;
     p_data = in->p_buffer;
-
     for( ;; )
     {
+        block_t *p_block;
+        picture_t pic;
+        int i_plane;
+
         /* decode frame */
         frame = id->p_ff_pic;
-        if( id->ff_dec )
+        p_sys->i_input_pts = in->i_pts;
+       if( id->ff_dec )
         {
             i_used = avcodec_decode_video( id->ff_dec_c, frame,
                                            &b_gotpicture,
@@ -972,6 +1109,9 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
                             id->ff_dec_c->width, id->ff_dec_c->height );
             i_used = i_data;
             b_gotpicture = 1;
+
+            /* Set PTS */
+            frame->pts = p_sys->i_input_pts;
         }
 
         if( i_used < 0 )
@@ -987,33 +1127,82 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
             return VLC_SUCCESS;
         }
 
+        /* Get the pts of the decoded frame if any, otherwise keep the
+         * interpolated one */
+        if( frame->pts > 0 )
+        {
+            p_sys->i_output_pts = frame->pts;
+        }
+
         if( !id->b_enc_inited )
         {
-            /* XXX hack because of copy packetizer and mpeg4video that can failed
-               detecting size */
-            if( id->ff_enc_c->width <= 0 || id->ff_enc_c->height <= 0 )
+            /* XXX hack because of copy packetizer and mpeg4video that can fail
+             * detecting size */
+            if( id->p_encoder->format.video.i_width <= 0 )
+            {
+                id->p_encoder->format.video.i_width = id->f_dst.i_width =
+                    id->ff_dec_c->width - p_sys->i_crop_left -
+                    p_sys->i_crop_right;
+            }
+            if( id->p_encoder->format.video.i_height <= 0 )
             {
-                id->ff_enc_c->width  = id->f_dst.i_width  = id->ff_dec_c->width;
-                id->ff_enc_c->height = id->f_dst.i_height = id->ff_dec_c->height;
+                id->p_encoder->format.video.i_height = id->f_dst.i_height =
+                    id->ff_dec_c->height - p_sys->i_crop_top -
+                    p_sys->i_crop_bottom;
             }
 
-            if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
+            id->p_encoder->i_bitrate = p_sys->i_vbitrate;
+
+            id->p_encoder->i_extra_data = 0;
+            id->p_encoder->p_extra_data = NULL;
+
+            id->p_encoder->p_module =
+                module_Need( id->p_encoder, "video encoder", NULL );
+            if( !id->p_encoder->p_module )
             {
-                msg_Err( p_stream, "cannot open encoder" );
+                vlc_object_destroy( id->p_encoder );
+                msg_Err( p_stream, "cannot find encoder" );
                 return VLC_EGENERIC;
             }
 
-            if( !( id->id = p_stream->p_sys->p_out->pf_add( p_stream->p_sys->p_out, &id->f_dst ) ) )
+            id->f_dst.i_extra_data = id->p_encoder->i_extra_data;
+            id->f_dst.p_extra_data = id->p_encoder->p_extra_data;
+
+            /* Hack for mp2v/mp1v transcoding support */
+            if( id->f_dst.i_fourcc == VLC_FOURCC( 'm','p','1','v' ) ||
+                id->f_dst.i_fourcc == VLC_FOURCC( 'm','p','2','v' ) )
+            {
+                id->f_dst.i_fourcc = VLC_FOURCC( 'm','p','g','v' );
+            }
+
+            if( !( id->id =
+                     p_stream->p_sys->p_out->pf_add( p_stream->p_sys->p_out,
+                                                     &id->f_dst ) ) )
             {
                 msg_Err( p_stream, "cannot add this stream" );
                 transcode_video_ffmpeg_close( p_stream, id );
                 id->b_transcode = VLC_FALSE;
                 return VLC_EGENERIC;
             }
+
+            while( id->p_encoder->pf_header &&
+                   (p_block = id->p_encoder->pf_header( id->p_encoder )) )
+            {
+                sout_buffer_t *p_out;
+                p_out = sout_BufferNew( p_stream->p_sout, p_block->i_buffer );
+                memcpy( p_out->p_buffer, p_block->p_buffer, p_block->i_buffer);
+                p_out->i_dts = in->i_dts;
+                p_out->i_pts = in->i_dts;
+                p_out->i_length = 0;
+                sout_BufferChain( out, p_out );
+            }
+
+            id->i_inter_pixfmt =
+                get_ff_chroma( id->p_encoder->format.video.i_chroma );
+
             id->b_enc_inited = VLC_TRUE;
         }
 
-
         /* deinterlace */
         if( p_stream->p_sys->b_deinterlace )
         {
@@ -1028,7 +1217,7 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
                 buf = malloc( i_size );
 
                 avpicture_fill( (AVPicture*)id->p_ff_pic_tmp0, buf,
-                                id->ff_enc_c->pix_fmt,
+                                id->i_inter_pixfmt,
                                 id->ff_dec_c->width, id->ff_dec_c->height );
             }
 
@@ -1040,50 +1229,55 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
         }
 
         /* convert pix format */
-        if( id->ff_dec_c->pix_fmt != id->ff_enc_c->pix_fmt )
+        if( id->ff_dec_c->pix_fmt != id->i_inter_pixfmt )
         {
             if( id->p_ff_pic_tmp1 == NULL )
             {
                 int     i_size;
                 uint8_t *buf;
                 id->p_ff_pic_tmp1 = avcodec_alloc_frame();
-                i_size = avpicture_get_size( id->ff_enc_c->pix_fmt,
-                                             id->ff_dec_c->width, id->ff_dec_c->height );
+                i_size = avpicture_get_size( id->i_inter_pixfmt,
+                                             id->ff_dec_c->width,
+                                             id->ff_dec_c->height );
 
                 buf = malloc( i_size );
 
                 avpicture_fill( (AVPicture*)id->p_ff_pic_tmp1, buf,
-                                id->ff_enc_c->pix_fmt,
+                                id->i_inter_pixfmt,
                                 id->ff_dec_c->width, id->ff_dec_c->height );
             }
 
-            img_convert( (AVPicture*)id->p_ff_pic_tmp1, id->ff_enc_c->pix_fmt,
-                         (AVPicture*)frame,             id->ff_dec_c->pix_fmt,
+            img_convert( (AVPicture*)id->p_ff_pic_tmp1, id->i_inter_pixfmt,
+                         (AVPicture*)frame, id->ff_dec_c->pix_fmt,
                          id->ff_dec_c->width, id->ff_dec_c->height );
 
             frame = id->p_ff_pic_tmp1;
         }
 
         /* convert size and crop */
-        if( ( id->ff_dec_c->width  != id->ff_enc_c->width ) ||
-            ( id->ff_dec_c->height != id->ff_enc_c->height ) )
+        if( id->ff_dec_c->width  != id->f_dst.i_width ||
+            id->ff_dec_c->height != id->f_dst.i_height ||
+            p_sys->i_crop_top > 0 || p_sys->i_crop_bottom > 0 ||
+            p_sys->i_crop_left > 0 || p_sys->i_crop_right )
         {
             if( id->p_ff_pic_tmp2 == NULL )
             {
                 int     i_size;
                 uint8_t *buf;
                 id->p_ff_pic_tmp2 = avcodec_alloc_frame();
-                i_size = avpicture_get_size( id->ff_enc_c->pix_fmt,
-                                             id->ff_enc_c->width, id->ff_enc_c->height );
+                i_size = avpicture_get_size( id->i_inter_pixfmt,
+                                             id->f_dst.i_width,
+                                             id->f_dst.i_height );
 
                 buf = malloc( i_size );
 
                 avpicture_fill( (AVPicture*)id->p_ff_pic_tmp2, buf,
-                                id->ff_enc_c->pix_fmt,
-                                id->ff_enc_c->width, id->ff_enc_c->height );
+                                id->i_inter_pixfmt,
+                                id->f_dst.i_width, id->f_dst.i_height );
 
                 id->p_vresample =
-                    img_resample_full_init( id->ff_enc_c->width, id->ff_enc_c->height,
+                    img_resample_full_init( id->f_dst.i_width,
+                                            id->f_dst.i_height,
                                             id->ff_dec_c->width, id->ff_dec_c->height,
                                             p_stream->p_sys->i_crop_top,
                                             p_stream->p_sys->i_crop_bottom,
@@ -1091,25 +1285,51 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
                                             p_stream->p_sys->i_crop_right );
             }
 
-            img_resample( id->p_vresample, (AVPicture*)id->p_ff_pic_tmp2, (AVPicture*)frame );
+            img_resample( id->p_vresample, (AVPicture*)id->p_ff_pic_tmp2,
+                          (AVPicture*)frame );
 
             frame = id->p_ff_pic_tmp2;
         }
 
-        i_out = avcodec_encode_video( id->ff_enc_c, id->p_buffer, id->i_buffer, frame );
-        if( i_out > 0 )
+        /* Encoding */
+        vout_InitPicture( VLC_OBJECT(p_stream), &pic,
+                          id->p_encoder->format.video.i_chroma,
+                          id->f_dst.i_width, id->f_dst.i_height,
+                          id->f_dst.i_width * VOUT_ASPECT_FACTOR /
+                          id->f_dst.i_height );
+
+        for( i_plane = 0; i_plane < pic.i_planes; i_plane++ )
         {
-            sout_buffer_t *p_out;
-            p_out = sout_BufferNew( p_stream->p_sout, i_out );
+            pic.p[i_plane].p_pixels = frame->data[i_plane];
+            pic.p[i_plane].i_pitch = frame->linesize[i_plane];
+        }
 
-            memcpy( p_out->p_buffer, id->p_buffer, i_out );
+        /* Set the pts of the frame being encoded */
+        pic.date = p_sys->i_output_pts;
 
-            p_out->i_size   = i_out;
-            p_out->i_length = in->i_length;
-            p_out->i_dts    = in->i_dts;
-            p_out->i_pts    = in->i_dts; /* FIXME */
+        /* Interpolate the next PTS
+         * (needed by the mpeg video packetizer which can send pts <= 0 ) */
+        if( id->ff_dec_c && id->ff_dec_c->frame_rate > 0 )
+        {
+            p_sys->i_output_pts += I64C(1000000) * (2 + frame->repeat_pict) *
+              id->ff_dec_c->frame_rate_base / (2 * id->ff_dec_c->frame_rate);
+        }
 
+        p_block = id->p_encoder->pf_encode_video( id->p_encoder, &pic );
+        while( p_block )
+        {
+            sout_buffer_t *p_out;
+            block_t *p_prev_block = p_block;
+
+            p_out = sout_BufferNew( p_stream->p_sout, p_block->i_buffer );
+            memcpy( p_out->p_buffer, p_block->p_buffer, p_block->i_buffer);
+            p_out->i_dts = p_block->i_dts;
+            p_out->i_pts = p_block->i_pts;
+            p_out->i_length = p_block->i_length;
             sout_BufferChain( out, p_out );
+
+            p_block = p_block->p_next;
+            block_Release( p_prev_block );
         }
 
         if( i_data <= 0 )
@@ -1121,3 +1341,19 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream, sout_stream_
     return VLC_SUCCESS;
 }
 
+/*****************************************************************************
+ * transcode_video_ffmpeg_getframebuf:
+ *
+ * Callback used by ffmpeg to get a frame buffer.
+ * We use it to get the right PTS for each decoded picture.
+ *****************************************************************************/
+static int transcode_video_ffmpeg_getframebuf(struct AVCodecContext *p_context,
+                                              AVFrame *p_frame)
+{
+    sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_context->opaque;
+
+    /* Set PTS */
+    p_frame->pts = p_sys->i_input_pts;
+
+    return avcodec_default_get_buffer( p_context, p_frame );
+}