]> git.sesse.net Git - vlc/commitdiff
* modules/codec/ffmpeg/*: ported the ffmpeg audio and video decoders to the new api.
authorGildas Bazin <gbazin@videolan.org>
Mon, 27 Oct 2003 01:04:38 +0000 (01:04 +0000)
committerGildas Bazin <gbazin@videolan.org>
Mon, 27 Oct 2003 01:04:38 +0000 (01:04 +0000)
   Isolated the video postprocessing routines in postprocess.c

* modules/codec/ffmpeg/encoder.c, modules/codec/vorbis.c, modules/stream_out/transcode.c,
   include/vlc_block.h, include/vlc_codec.h: extracted the encoders out of transcode.c.
   transcode now uses encoder plugins (currently ffmpeg, vorbis and theora).

PS: transcoding is currently a bit broken but I'll fix that ASAP.

15 files changed:
configure.ac
include/vlc_block.h
include/vlc_codec.h
modules/codec/ffmpeg/Modules.am
modules/codec/ffmpeg/audio.c
modules/codec/ffmpeg/audio.h [deleted file]
modules/codec/ffmpeg/chroma.c
modules/codec/ffmpeg/encoder.c [new file with mode: 0644]
modules/codec/ffmpeg/ffmpeg.c
modules/codec/ffmpeg/ffmpeg.h
modules/codec/ffmpeg/postprocess.c [new file with mode: 0644]
modules/codec/ffmpeg/video.c
modules/codec/ffmpeg/video.h [deleted file]
modules/codec/vorbis.c
modules/stream_out/transcode.c

index bed364fb5d8e23fcadab14273c0c220b054d51d9..7a7e7797e5c0e3e8360bd9e66c14d6a32d39526f 100644 (file)
@@ -1,5 +1,5 @@
 dnl Autoconf settings for vlc
-dnl $Id: configure.ac,v 1.98 2003/10/26 17:11:56 gbazin Exp $
+dnl $Id: configure.ac,v 1.99 2003/10/27 01:04:38 gbazin Exp $
 
 AC_INIT(vlc,0.6.3-cvs)
 
@@ -1706,13 +1706,6 @@ then
       AC_MSG_ERROR([cannot find ${real_ffmpeg_tree}/libavcodec/libavcodec.a, make sure you compiled libavcodec in ${with_ffmpeg_tree}])
     fi
   fi
-
-  ac_have_vorbis_headers=yes
-  AC_CHECK_HEADERS(vorbis/vorbisenc.h vorbis/codec.h,,
-      ac_have_vorbis_headers=no)
-  if test "$ac_have_vorbis_headers" = "yes"; then
-    AX_ADD_LDFLAGS([stream_out_transcode],[-lvorbisenc -lvorbis -logg])
-  fi
 fi
 
 dnl
@@ -2020,6 +2013,9 @@ then
   AC_CHECK_HEADERS(vorbis/codec.h, [
     AX_ADD_PLUGINS([vorbis])
     AX_ADD_LDFLAGS([vorbis],[-lvorbis -logg]) ],[])
+
+  AC_CHECK_HEADERS(vorbis/vorbisenc.h, [
+    AX_ADD_LDFLAGS([vorbis],[-lvorbisenc]) ],[])
 fi
 
 dnl
index e4282d606f9582254e3828a66e6168697f63f5a1..779183147fa9adb8dd7c66c8cf326682a07cf9ce 100644 (file)
@@ -2,7 +2,7 @@
  * vlc_block.h: Data blocks management functions
  *****************************************************************************
  * Copyright (C) 2003 VideoLAN
- * $Id: vlc_block.h,v 1.3 2003/09/30 20:23:03 gbazin Exp $
+ * $Id: vlc_block.h,v 1.4 2003/10/27 01:04:38 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
@@ -37,6 +37,7 @@ struct block_t
     vlc_bool_t  b_frame_start;
     mtime_t     i_pts;
     mtime_t     i_dts;
+    mtime_t     i_length;
 
     vlc_bool_t  b_discontinuity; /* only temporary */
 
index 5ab767cef300c4001af67cb16d894fbb6f4e09bf..466e1060edba92b7d137cafab07cca136a1eba91 100644 (file)
@@ -2,7 +2,7 @@
  * vlc_codec.h: codec related structures
  *****************************************************************************
  * Copyright (C) 1999-2003 VideoLAN
- * $Id: vlc_codec.h,v 1.1 2003/10/08 21:01:07 gbazin Exp $
+ * $Id: vlc_codec.h,v 1.2 2003/10/27 01:04:38 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -87,6 +87,20 @@ struct encoder_t
     /* Properties of the output of the encoder */
     vlc_fourcc_t i_fourcc;
     int          i_bitrate;
+
+    int          i_extra_data;
+    uint8_t      *p_extra_data;
+
+    /* FIXME: move these to the ffmpeg encoder */
+    int i_frame_rate;
+    int i_frame_rate_base;
+    int i_key_int;
+    int i_b_frames;
+    int i_vtolerance;
+    int i_qmin;
+    int i_qmax;
+    int i_hq;
+
 };
 
 /**
index 2dbb03acc009eaa8bdda875e53ce1a7e0ff20a9e..1a674bd32ea967c0f528c39f642b376bab5def85 100644 (file)
@@ -2,9 +2,9 @@ SOURCES_ffmpeg = \
        ffmpeg.c \
        ffmpeg.h \
        video.c \
-       video.h \
        audio.c \
-       audio.h \
        chroma.c \
+       encoder.c \
+       postprocess.c \
        $(NULL)
 
index 0bbbeac05c855fbdd64abebc1ea49bffe17fd117..36a43cc7ed05f73cdd6e7ca87d81bdb21bc36085 100644 (file)
@@ -1,10 +1,11 @@
 /*****************************************************************************
  * audio.c: audio decoder using ffmpeg library
  *****************************************************************************
- * Copyright (C) 1999-2001 VideoLAN
- * $Id: audio.c,v 1.19 2003/07/10 01:33:41 fenrir Exp $
+ * Copyright (C) 1999-2003 VideoLAN
+ * $Id: audio.c,v 1.20 2003/10/27 01:04:38 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
@@ -25,6 +26,7 @@
  * Preamble
  *****************************************************************************/
 #include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>
 
 #include <vlc/vlc.h>
 #include <vlc/vout.h>
 #include <unistd.h>                                              /* getpid() */
 #endif
 
-#include <errno.h>
-#include <string.h>
-
 #ifdef HAVE_SYS_TIMES_H
 #   include <sys/times.h>
 #endif
+
 #include "codecs.h"
 #include "aout_internal.h"
 
 #   include <avcodec.h>
 #endif
 
-//#include "postprocessing/postprocessing.h"
 #include "ffmpeg.h"
 #include "audio.h"
 
-/*
- * Local prototypes
- */
-int      E_( InitThread_Audio )   ( adec_thread_t * );
-void     E_( EndThread_Audio )    ( adec_thread_t * );
-void     E_( DecodeThread_Audio ) ( adec_thread_t * );
-
 static unsigned 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_REARLEFT
+     | AOUT_CHAN_REARRIGHT,
     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
      | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
 };
 
 /*****************************************************************************
- * locales Functions
- *****************************************************************************/
-
-/*****************************************************************************
- *
- * Functions that initialize, decode and end the decoding process
- *
- * Functions exported for ffmpeg.c
- *   * E_( InitThread_Audio )
- *   * E_( DecodeThread_Audio )
- *   * E_( EndThread_Video_Audio )
+ * decoder_sys_t : decoder descriptor
  *****************************************************************************/
+struct decoder_sys_t
+{
+    /* Common part between video and audio decoder */
+    int i_cat;
+    int i_codec_id;
+    char *psz_namecodec;
+    AVCodecContext      *p_context;
+    AVCodec             *p_codec;
+
+    /* Temporary buffer for libavcodec */
+    uint8_t *p_output;
+
+    /*
+     * Output properties
+     */
+    aout_instance_t       *p_aout;
+    aout_input_t          *p_aout_input;
+    audio_sample_format_t aout_format;
+    audio_date_t          end_date;
+};
 
 /*****************************************************************************
- * InitThread: initialize vdec output thread
+ * InitAudioDec: initialize audio 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.
+ * The ffmpeg codec will be opened, some memory allocated.
  *****************************************************************************/
-int E_( InitThread_Audio )( adec_thread_t *p_adec )
+int E_(InitAudioDec)( decoder_t *p_dec, AVCodecContext *p_context,
+                      AVCodec *p_codec, int i_codec_id, char *psz_namecodec )
 {
+    decoder_sys_t *p_sys;
     WAVEFORMATEX wf, *p_wf;
 
-    if( ( p_wf = p_adec->p_fifo->p_waveformatex ) == NULL )
+    /* 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_Warn( p_adec->p_fifo, "audio informations missing" );
+        msg_Err( p_dec, "out of memory" );
+        return VLC_EGENERIC;
+    }
+
+    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;
+
+    if( ( p_wf = p_dec->p_fifo->p_waveformatex ) == NULL )
+    {
+        msg_Warn( p_dec, "audio informations missing" );
         p_wf = &wf;
         memset( p_wf, 0, sizeof( WAVEFORMATEX ) );
     }
 
     /* ***** Fill p_context with init values ***** */
-    p_adec->p_context->sample_rate = p_wf->nSamplesPerSec;
-    p_adec->p_context->channels = p_wf->nChannels;
-    p_adec->p_context->block_align = p_wf->nBlockAlign;
-    p_adec->p_context->bit_rate = p_wf->nAvgBytesPerSec * 8;
+    p_sys->p_context->sample_rate = p_wf->nSamplesPerSec;
+    p_sys->p_context->channels = p_wf->nChannels;
+    p_sys->p_context->block_align = p_wf->nBlockAlign;
+    p_sys->p_context->bit_rate = p_wf->nAvgBytesPerSec * 8;
 
-    if( ( p_adec->p_context->extradata_size = p_wf->cbSize ) > 0 )
+    if( ( p_sys->p_context->extradata_size = p_wf->cbSize ) > 0 )
     {
-        p_adec->p_context->extradata = malloc( p_wf->cbSize + FF_INPUT_BUFFER_PADDING_SIZE );
-
-        memcpy( p_adec->p_context->extradata, &p_wf[1], p_wf->cbSize);
-        memset( &((uint8_t*)p_adec->p_context->extradata)[p_wf->cbSize], 0, FF_INPUT_BUFFER_PADDING_SIZE );
+        p_sys->p_context->extradata =
+            malloc( p_wf->cbSize + FF_INPUT_BUFFER_PADDING_SIZE );
+        memcpy( p_sys->p_context->extradata, &p_wf[1], p_wf->cbSize);
+        memset( &((uint8_t*)p_sys->p_context->extradata)[p_wf->cbSize], 0,
+                FF_INPUT_BUFFER_PADDING_SIZE );
     }
 
     /* ***** Open the codec ***** */
-    if (avcodec_open(p_adec->p_context, p_adec->p_codec) < 0)
+    if (avcodec_open( p_sys->p_context, p_sys->p_codec ) < 0)
     {
-        msg_Err( p_adec->p_fifo,
-                 "cannot open codec (%s)",
-                 p_adec->psz_namecodec );
-        return( -1 );
+        msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec );
+        return VLC_EGENERIC;
     }
     else
     {
-        msg_Dbg( p_adec->p_fifo,
-                 "ffmpeg codec (%s) started",
-                 p_adec->psz_namecodec );
+        msg_Dbg( p_dec, "ffmpeg codec (%s) started", p_sys->psz_namecodec );
     }
 
-    p_adec->p_output = malloc( 3 * AVCODEC_MAX_AUDIO_FRAME_SIZE );
-
+    p_sys->p_output = malloc( 3 * AVCODEC_MAX_AUDIO_FRAME_SIZE );
 
-    p_adec->output_format.i_format = AOUT_FMT_S16_NE;
-    p_adec->output_format.i_rate = p_wf->nSamplesPerSec;
-    p_adec->output_format.i_physical_channels
-        = p_adec->output_format.i_original_channels
-        = pi_channels_maps[p_wf->nChannels];
+    p_sys->p_aout = NULL;
+    p_sys->p_aout_input = NULL;
 
-    p_adec->p_aout = NULL;
-    p_adec->p_aout_input = NULL;
+    aout_DateSet( &p_sys->end_date, 0 );
 
-    return( 0 );
+    return VLC_SUCCESS;
 }
 
-
 /*****************************************************************************
- * DecodeThread: Called for decode one frame
+ * DecodeAudio: Called to decode one frame
  *****************************************************************************/
-void  E_( DecodeThread_Audio )( adec_thread_t *p_adec )
+int E_( DecodeAudio )( decoder_t *p_dec, block_t *p_block )
 {
-    pes_packet_t    *p_pes;
-    aout_buffer_t   *p_aout_buffer;
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    aout_buffer_t *p_aout_buffer;
+    mtime_t i_pts;
 
-    int     i_samplesperchannel;
-    int     i_output_size;
-    int     i_frame_size;
-    int     i_used;
+    uint8_t *p_buffer, *p_samples;
+    int i_buffer, i_samples;
 
-    uint8_t *p;
+    if( !aout_DateGet( &p_sys->end_date ) && !p_block->i_pts )
+    {
+        /* We've just started the stream, wait for the first PTS. */
+        block_Release( p_block );
+        return VLC_SUCCESS;
+    }
 
-    do
+    i_pts = p_block->i_pts;
+    i_buffer = p_block->i_buffer;
+    p_buffer = p_block->p_buffer;
+
+    while( i_buffer )
     {
-        input_ExtractPES( p_adec->p_fifo, &p_pes );
-        if( !p_pes )
+        int i_used, i_output;
+
+        i_used = avcodec_decode_audio( p_sys->p_context,
+                                       (int16_t*)p_sys->p_output, &i_output,
+                                       p_buffer, i_buffer );
+        if( i_used < 0 )
         {
-            p_adec->p_fifo->b_error = 1;
-            return;
+            msg_Warn( p_dec, "cannot decode one frame (%d bytes)", i_buffer );
+            break;
         }
-        p_adec->pts = p_pes->i_pts;
-        i_frame_size = p_pes->i_pes_size;
 
-        if( i_frame_size > 0 )
-        {
-            int     i_need;
+        i_buffer -= i_used;
+        p_buffer += i_used;
 
+        if( p_sys->p_context->channels <= 0 || p_sys->p_context->channels > 6 )
+        {
+            msg_Warn( p_dec, "invalid channels count %d",
+                      p_sys->p_context->channels );
+            break;
+        }
 
-            i_need = i_frame_size + FF_INPUT_BUFFER_PADDING_SIZE + p_adec->i_buffer;
-            if( p_adec->i_buffer_size < i_need )
+        /* **** First check if we have a valid output **** */
+        if( p_sys->p_aout_input == NULL ||
+            p_sys->aout_format.i_original_channels !=
+            pi_channels_maps[p_sys->p_context->channels] )
+        {
+            if( p_sys->p_aout_input != NULL )
             {
-                uint8_t *p_last = p_adec->p_buffer;
-
-                p_adec->p_buffer = malloc( i_need );
-                p_adec->i_buffer_size = i_need;
-                if( p_adec->i_buffer > 0 )
-                {
-                    memcpy( p_adec->p_buffer, p_last, p_adec->i_buffer );
-                }
-                FREE( p_last );
+                /* **** Delete the old **** */
+                aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
             }
-            i_frame_size =
-                E_( GetPESData )( p_adec->p_buffer + p_adec->i_buffer,
-                                  i_frame_size,
-                                  p_pes );
-            /* make ffmpeg happier but I'm not sure it's needed for audio */
-            memset( p_adec->p_buffer + p_adec->i_buffer + i_frame_size, 0, FF_INPUT_BUFFER_PADDING_SIZE );
-        }
-        input_DeletePES( p_adec->p_fifo->p_packets_mgt, p_pes );
-    } while( i_frame_size <= 0 );
-
 
-    i_frame_size += p_adec->i_buffer;
+            /* **** Create a new audio output **** */
+            p_sys->aout_format.i_format = AOUT_FMT_S16_NE;
+            p_sys->aout_format.i_rate = p_sys->p_context->sample_rate;
+            p_sys->aout_format.i_physical_channels =
+                p_sys->aout_format.i_original_channels =
+                    pi_channels_maps[p_sys->p_context->channels];
 
-usenextdata:
-    i_used = avcodec_decode_audio( p_adec->p_context,
-                                   (int16_t*)p_adec->p_output,
-                                   &i_output_size,
-                                   p_adec->p_buffer,
-                                   i_frame_size );
-    if( i_used < 0 )
-    {
-        msg_Warn( p_adec->p_fifo,
-                  "cannot decode one frame (%d bytes)",
-                  i_frame_size );
-        p_adec->i_buffer = 0;
-        return;
-    }
-    else if( i_used < i_frame_size )
-    {
-        memmove( p_adec->p_buffer,
-                 p_adec->p_buffer + i_used,
-                 p_adec->i_buffer_size - i_used );
-
-        p_adec->i_buffer = i_frame_size - i_used;
-    }
-    else
-    {
-        p_adec->i_buffer = 0;
-    }
-
-    i_frame_size -= i_used;
-
-    //msg_Dbg( p_adec->p_fifo, "frame size:%d buffer used:%d", i_frame_size, i_used );
-    if( i_output_size <= 0 )
-    {
-         msg_Warn( p_adec->p_fifo, 
-                  "decoded %d samples bytes",
-                  i_output_size );
-    }
-
-    if( p_adec->p_context->channels <= 0 ||
-        p_adec->p_context->channels > 5 )
-    {
-        msg_Warn( p_adec->p_fifo,
-                  "invalid channels count %d",
-                  p_adec->p_context->channels );
-    }
+            aout_DateInit( &p_sys->end_date, p_sys->aout_format.i_rate );
+            p_sys->p_aout_input = aout_DecNew( p_dec, &p_sys->p_aout,
+                                               &p_sys->aout_format );
+        }
 
-    /* **** First check if we have a valid output **** */
-    if( ( p_adec->p_aout_input == NULL )||
-        ( p_adec->output_format.i_original_channels !=
-                    pi_channels_maps[p_adec->p_context->channels] ) )
-    {
-        if( p_adec->p_aout_input != NULL )
+        if( !p_sys->p_aout_input )
         {
-            /* **** Delete the old **** */
-            aout_DecDelete( p_adec->p_aout, p_adec->p_aout_input );
+            msg_Err( p_dec, "cannot create audio output" );
+            block_Release( p_block );
+            return VLC_EGENERIC;
         }
 
-        /* **** Create a new audio output **** */
-        p_adec->output_format.i_physical_channels =
-            p_adec->output_format.i_original_channels =
-                pi_channels_maps[p_adec->p_context->channels];
-
-        aout_DateInit( &p_adec->date, p_adec->output_format.i_rate );
-        p_adec->p_aout_input = aout_DecNew( p_adec->p_fifo,
-                                            &p_adec->p_aout,
-                                            &p_adec->output_format );
-    }
-
-    if( !p_adec->p_aout_input )
-    {
-        msg_Err( p_adec->p_fifo, "cannot create aout" );
-        return;
-    }
-
-    if( p_adec->pts != 0 && p_adec->pts != aout_DateGet( &p_adec->date ) )
-    {
-        aout_DateSet( &p_adec->date, p_adec->pts );
-    }
-    else if( !aout_DateGet( &p_adec->date ) )
-    {
-        return;
-    }
-
-    /* **** Now we can output these samples **** */
-    i_samplesperchannel = i_output_size / 2
-                           / aout_FormatNbChannels( &p_adec->output_format );
-
-    p = &p_adec->p_output[0];
-    while( i_samplesperchannel > 0 )
-    {
-        int i_samples;
+        if( i_pts != 0 && i_pts != aout_DateGet( &p_sys->end_date ) )
+        {
+            aout_DateSet( &p_sys->end_date, i_pts );
+            i_pts = 0;
+        }
 
-        i_samples = __MIN( 8000, i_samplesperchannel );
+        /* **** Now we can output these samples **** */
+        i_samples = i_output / 2 / p_sys->p_context->channels;
 
-        p_aout_buffer = aout_DecNewBuffer( p_adec->p_aout,
-                                           p_adec->p_aout_input,
-                                           i_samples );
-        if( !p_aout_buffer )
+        p_samples = p_sys->p_output;
+        while( i_samples > 0 )
         {
-            msg_Err( p_adec->p_fifo, "cannot get aout buffer" );
-            p_adec->p_fifo->b_error = 1;
-            return;
-        }
+            int i_smaller_samples;
 
-        p_aout_buffer->start_date = aout_DateGet( &p_adec->date );
-        p_aout_buffer->end_date = aout_DateIncrement( &p_adec->date,
-                                                      i_samples );
-        memcpy( p_aout_buffer->p_buffer,
-                p,
-                p_aout_buffer->i_nb_bytes );
+            i_smaller_samples = __MIN( 8000, i_samples );
 
-        aout_DecPlay( p_adec->p_aout, p_adec->p_aout_input, p_aout_buffer );
+            p_aout_buffer = aout_DecNewBuffer( p_sys->p_aout,
+                                               p_sys->p_aout_input,
+                                               i_smaller_samples );
+            if( !p_aout_buffer )
+            {
+                msg_Err( p_dec, "cannot get aout buffer" );
+                block_Release( p_block );
+                return VLC_EGENERIC;
+            }
 
-        p += i_samples * 2 * aout_FormatNbChannels( &p_adec->output_format );
-        i_samplesperchannel -= i_samples;
+            p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date );
+            p_aout_buffer->end_date = aout_DateIncrement( &p_sys->end_date,
+                                                          i_smaller_samples );
+            memcpy( p_aout_buffer->p_buffer, p_samples,
+                    p_aout_buffer->i_nb_bytes );
 
-    }
+            aout_DecPlay( p_sys->p_aout, p_sys->p_aout_input, p_aout_buffer );
 
-    if( i_frame_size > 0 )
-    {
-        goto usenextdata;
+            p_samples += i_smaller_samples * 2 * p_sys->p_context->channels;
+            i_samples -= i_smaller_samples;
+        }
     }
 
-    return;
+    block_Release( p_block );
+    return VLC_SUCCESS;
 }
 
-
 /*****************************************************************************
- * EndThread: thread destruction
- *****************************************************************************
- * This function is called when the thread ends after a sucessful
- * initialization.
+ * EndAudioDec: audio decoder destruction
  *****************************************************************************/
-void E_( EndThread_Audio )( adec_thread_t *p_adec )
+void E_(EndAudioDec)( decoder_t *p_dec )
 {
-//    FREE( p_adec->format.p_data );
-    FREE( p_adec->p_output );
+    decoder_sys_t *p_sys = p_dec->p_sys;
+
+    if( p_sys->p_output ) free( p_sys->p_output );
 
-    if( p_adec->p_aout_input )
+    if( p_sys->p_aout_input )
     {
-        aout_DecDelete( p_adec->p_aout, p_adec->p_aout_input );
+        aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
     }
-
 }
-
diff --git a/modules/codec/ffmpeg/audio.h b/modules/codec/ffmpeg/audio.h
deleted file mode 100644 (file)
index 59258e0..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*****************************************************************************
- * audio.h: video decoder using ffmpeg library
- *****************************************************************************
- * Copyright (C) 1999-2001 VideoLAN
- * $Id: audio.h,v 1.4 2003/02/07 01:22:55 fenrir Exp $
- *
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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.
- *****************************************************************************/
-
-
-typedef struct adec_thread_s
-{
-    DECODER_THREAD_COMMON
-
-//    waveformatex_t  format;
-
-    /*
-     * Output properties
-     */
-
-    uint8_t *             p_output;
-
-    aout_instance_t *     p_aout;       /* opaque */
-    aout_input_t *        p_aout_input; /* opaque */
-    audio_sample_format_t output_format;
-
-    audio_date_t          date;
-
-} adec_thread_t;
-
-/*
- * Local prototypes
- */
-int      E_( InitThread_Audio )   ( adec_thread_t * );
-void     E_( EndThread_Audio )    ( adec_thread_t * );
-void     E_( DecodeThread_Audio ) ( adec_thread_t * );
-
index 227807214e6b9c21d598020a3d3151f357ffef39..dac452e048c9ccb264013401540feeadbb6d6114 100644 (file)
@@ -2,7 +2,7 @@
  * chroma.c: chroma conversion using ffmpeg library
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: chroma.c,v 1.2 2003/09/26 16:10:24 gbazin Exp $
+ * $Id: chroma.c,v 1.3 2003/10/27 01:04:38 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -38,7 +38,7 @@
 
 #include "ffmpeg.h"
 
-void E_(ffmpeg_InitLibavcodec) ( vlc_object_t *p_object );
+void E_(InitLibavcodec) ( vlc_object_t *p_object );
 static void ChromaConversion( vout_thread_t *, picture_t *, picture_t * );
 
 /*****************************************************************************
@@ -104,7 +104,7 @@ int E_(OpenChroma)( vlc_object_t *p_this )
         case VLC_FOURCC('U','Y','V','Y'):
             i_ffmpeg_chroma[i] = PIX_FMT_YUV422;
             break;
-           
+
         /* Packed RGB formats */
 
         case VLC_FOURCC('R','V','3','2'):
@@ -148,7 +148,7 @@ int E_(OpenChroma)( vlc_object_t *p_this )
     p_vout->chroma.p_sys->i_dst_ffmpeg_chroma = i_ffmpeg_chroma[1];
 
     /* libavcodec needs to be initialized for some chroma conversions */
-    E_(ffmpeg_InitLibavcodec)(p_this);
+    E_(InitLibavcodec)(p_this);
 
     return VLC_SUCCESS;
 }
diff --git a/modules/codec/ffmpeg/encoder.c b/modules/codec/ffmpeg/encoder.c
new file mode 100644 (file)
index 0000000..199cd04
--- /dev/null
@@ -0,0 +1,472 @@
+/*****************************************************************************
+ * encoder.c: video and audio encoder using the ffmpeg library
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ * $Id: encoder.c,v 1.1 2003/10/27 01:04:38 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/vout.h>
+#include <vlc/aout.h>
+#include <vlc/decoder.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#include "aout_internal.h"
+
+/* ffmpeg header */
+#ifdef HAVE_FFMPEG_AVCODEC_H
+#   include <ffmpeg/avcodec.h>
+#else
+#   include <avcodec.h>
+#endif
+
+#include "ffmpeg.h"
+
+#define AVCODEC_MAX_VIDEO_FRAME_SIZE (3*1024*1024)
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+int  E_(OpenVideoEncoder) ( vlc_object_t * );
+void E_(CloseVideoEncoder)( vlc_object_t * );
+
+int  E_(OpenAudioEncoder) ( vlc_object_t * );
+void E_(CloseAudioEncoder)( vlc_object_t * );
+
+static block_t *EncodeVideo( encoder_t *, picture_t * );
+static block_t *EncodeAudio( encoder_t *, aout_buffer_t * );
+
+/*****************************************************************************
+ * encoder_sys_t : ffmpeg encoder descriptor
+ *****************************************************************************/
+struct encoder_sys_t
+{
+    /*
+     * Ffmpeg properties
+     */
+    AVCodec         *p_codec;
+    AVCodecContext  *p_context;
+
+    /*
+     * Packetizer output properties
+     */
+    sout_packetizer_input_t *p_sout_input;
+    sout_format_t           sout_format;
+
+    /*
+     * Common properties
+     */
+    int i_last_block_size;
+    int i_samples_delay;
+    mtime_t i_pts;
+
+    mtime_t i_last_ref_pts;
+    mtime_t i_buggy_pts_detect;
+
+    int i_frame_size;
+
+    char *p_buffer;
+    char *p_buffer_out;
+};
+
+/*****************************************************************************
+ * OpenVideoEncoder: probe the encoder
+ *****************************************************************************/
+int E_(OpenVideoEncoder)( vlc_object_t *p_this )
+{
+    encoder_t *p_enc = (encoder_t *)p_this;
+    encoder_sys_t *p_sys = p_enc->p_sys;
+    AVCodecContext  *p_context;
+    AVCodec *p_codec;
+    int i_ff_codec;
+
+    /* find encoder */
+    i_ff_codec = E_(GetFfmpegCodec)( p_enc->i_fourcc, 0, 0, 0 );
+    if( !i_ff_codec )
+    {
+        return VLC_EGENERIC;
+    }
+
+    p_codec = avcodec_find_encoder( i_ff_codec );
+    if( !p_codec )
+    {
+        return VLC_EGENERIC;
+    }
+
+    /* libavcodec needs to be initialized */
+    E_(InitLibavcodec)(p_this);
+
+    /* Allocate the memory needed to store the decoder's structure */
+    if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
+    {
+        msg_Err( p_enc, "out of memory" );
+        return VLC_EGENERIC;
+    }
+    p_enc->p_sys = p_sys;
+    p_sys->p_codec = p_codec;
+
+    p_enc->pf_header = NULL;
+    p_enc->pf_encode_video = EncodeVideo;
+    p_enc->format.video.i_chroma = VLC_FOURCC('I','4','2','0');
+
+    if( p_enc->i_fourcc == VLC_FOURCC( 'm','p','1','v' ) ||
+        p_enc->i_fourcc == VLC_FOURCC( 'm','p','2','v' ) )
+    {
+        p_enc->i_fourcc = VLC_FOURCC( 'm','p','g','v' );
+    }
+
+    p_sys->p_context = p_context = avcodec_alloc_context();
+    p_context->width = p_enc->format.video.i_width;
+    p_context->height = p_enc->format.video.i_height;
+    p_context->bit_rate = p_enc->i_bitrate;
+
+    p_context->frame_rate = p_enc->i_frame_rate;
+    p_context->frame_rate_base= p_enc->i_frame_rate_base;
+
+    p_context->gop_size = p_enc->i_key_int >= 0 ? p_enc->i_key_int : 50;
+    p_context->max_b_frames =
+        __MIN( p_enc->i_b_frames, FF_MAX_B_FRAMES );
+    p_context->b_frame_strategy = 0;
+    p_context->b_quant_factor = 2.0;
+
+    if( p_enc->i_vtolerance >= 0 )
+    {
+        p_context->bit_rate_tolerance = p_enc->i_vtolerance;
+    }
+    p_context->qmin = p_enc->i_qmin;
+    p_context->qmax = p_enc->i_qmax;
+
+#if LIBAVCODEC_BUILD >= 4673
+    p_context->mb_decision = p_enc->i_hq;
+#else
+    if( p_enc->i_hq )
+    {
+        p_context->flags |= CODEC_FLAG_HQ;
+    }
+#endif
+
+    if( i_ff_codec == CODEC_ID_RAWVIDEO )
+    {
+        p_context->pix_fmt = E_(GetFfmpegChroma)( p_enc->i_fourcc );
+    }
+
+    /* Make sure we get extradata filled by the encoder */
+    p_context->extradata_size = 0;
+    p_context->extradata = NULL;
+    p_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+    if( avcodec_open( p_context, p_sys->p_codec ) )
+    {
+        msg_Err( p_enc, "cannot open encoder" );
+        return VLC_EGENERIC;
+    }
+
+    p_enc->i_extra_data = p_context->extradata_size;
+    p_enc->p_extra_data = p_context->extradata;
+    p_context->flags &= ~CODEC_FLAG_GLOBAL_HEADER;
+
+    p_sys->p_buffer_out = malloc( AVCODEC_MAX_VIDEO_FRAME_SIZE );
+    p_sys->i_last_ref_pts = 0;
+    p_sys->i_buggy_pts_detect = 0;
+
+    return VLC_SUCCESS;
+}
+
+/****************************************************************************
+ * EncodeVideo: the whole thing
+ ****************************************************************************/
+static block_t *EncodeVideo( encoder_t *p_enc, picture_t *p_pict )
+{
+    encoder_sys_t *p_sys = p_enc->p_sys;
+    AVFrame frame;
+    int i_out, i_plane;
+
+    for( i_plane = 0; i_plane < p_pict->i_planes; i_plane++ )
+    {
+        frame.data[i_plane] = p_pict->p[i_plane].p_pixels;
+        frame.linesize[i_plane] = p_pict->p[i_plane].i_pitch;
+    }
+
+    frame.pts = p_pict->date;
+
+    /* Let ffmpeg select the frame type */
+    frame.pict_type = 0;
+
+    i_out = avcodec_encode_video( p_sys->p_context, p_sys->p_buffer_out,
+                                  AVCODEC_MAX_VIDEO_FRAME_SIZE, &frame );
+    if( i_out > 0 )
+    {
+        block_t *p_block = block_New( p_enc, i_out );
+        memcpy( p_block->p_buffer, p_sys->p_buffer_out, i_out );
+
+        if( p_sys->p_context->coded_frame->pts != 0 &&
+            p_sys->i_buggy_pts_detect != p_sys->p_context->coded_frame->pts )
+        {
+            p_sys->i_buggy_pts_detect = p_sys->p_context->coded_frame->pts;
+
+            /* FIXME, 3-2 pulldown is not handled correctly */
+            p_block->i_length = 0;//in->i_length;
+            p_block->i_pts    = p_sys->p_context->coded_frame->pts;
+
+            if( !p_sys->p_context->delay ||
+                ( p_sys->p_context->coded_frame->pict_type != FF_I_TYPE &&
+                  p_sys->p_context->coded_frame->pict_type != FF_P_TYPE ) )
+            {
+                p_block->i_dts = p_block->i_pts;
+            }
+            else
+            {
+                if( p_sys->i_last_ref_pts )
+                {
+                    p_block->i_dts = p_sys->i_last_ref_pts;
+                }
+                else
+                {
+                    /* Let's put something sensible */
+                    p_block->i_dts = p_block->i_pts;
+                }
+
+                p_sys->i_last_ref_pts = p_block->i_pts;
+            }
+        }
+        else
+        {
+            /* Buggy libavcodec which doesn't update coded_frame->pts
+             * correctly */
+            p_block->i_length = 0;//in->i_length;
+            p_block->i_dts = p_block->i_pts = p_pict->date;
+        }
+
+        return p_block;
+    }
+
+    return NULL;
+}
+
+/*****************************************************************************
+ * CloseVideoEncoder: ffmpeg video encoder destruction
+ *****************************************************************************/
+void E_(CloseVideoEncoder)( vlc_object_t *p_this )
+{
+    encoder_t *p_enc = (encoder_t *)p_this;
+    encoder_sys_t *p_sys = p_enc->p_sys;
+
+    avcodec_close( p_sys->p_context );
+    free( p_sys->p_context );
+    free( p_sys->p_buffer_out );
+    free( p_sys );
+}
+
+/*****************************************************************************
+ * OpenAudioEncoder: probe the encoder
+ *****************************************************************************/
+int E_(OpenAudioEncoder)( vlc_object_t *p_this )
+{
+    encoder_t *p_enc = (encoder_t *)p_this;
+    encoder_sys_t *p_sys = p_enc->p_sys;
+    AVCodecContext  *p_context;
+    AVCodec *p_codec;
+    int i_ff_codec;
+
+    i_ff_codec = E_(GetFfmpegCodec)( p_enc->i_fourcc, 0, 0, 0 );
+    if( i_ff_codec == 0 )
+    {
+        msg_Err( p_enc, "cannot find encoder id" );
+        return VLC_EGENERIC;
+    }
+
+    p_codec = avcodec_find_encoder( i_ff_codec );
+    if( !p_codec )
+    {
+        msg_Err( p_enc, "cannot find encoder (avcodec)" );
+        return VLC_EGENERIC;
+    }
+
+    /* libavcodec needs to be initialized */
+    E_(InitLibavcodec)(p_this);
+
+    /* Allocate the memory needed to store the decoder's structure */
+    if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
+    {
+        msg_Err( p_enc, "out of memory" );
+        return VLC_EGENERIC;
+    }
+    p_enc->p_sys = p_sys;
+    p_sys->p_codec = p_codec;
+
+    p_enc->pf_header = NULL;
+    p_enc->pf_encode_audio = EncodeAudio;
+    p_enc->format.audio.i_format = VLC_FOURCC('s','1','6','n');
+
+    p_sys->p_context = p_context = avcodec_alloc_context();
+    p_context->bit_rate    = p_enc->i_bitrate;
+    p_context->sample_rate = p_enc->format.audio.i_rate;
+    p_context->channels    =
+        aout_FormatNbChannels( &p_enc->format.audio );
+
+    /* Make sure we get extradata filled by the encoder */
+    p_context->extradata_size = 0;
+    p_context->extradata = NULL;
+    p_context->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+    p_sys->i_samples_delay = 0;
+    p_sys->i_last_block_size = 0;
+    p_sys->i_pts = 0;
+
+    if( avcodec_open( p_context, p_sys->p_codec ) )
+    {
+#if 0
+        if( p_context->channels > 2 )
+        {
+            p_context->channels = 2;
+            id->f_dst.i_channels   = 2;
+            if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
+            {
+                msg_Err( p_enc, "cannot open encoder" );
+                return VLC_EGENERIC;
+            }
+            msg_Warn( p_enc, "stereo mode selected (codec limitation)" );
+        }
+        else
+        {
+            msg_Err( p_enc, "cannot open encoder" );
+            return VLC_EGENERIC;
+        }
+#endif
+    }
+
+    p_enc->i_extra_data = p_context->extradata_size;
+    p_enc->p_extra_data = p_context->extradata;
+    p_context->flags &= ~CODEC_FLAG_GLOBAL_HEADER;
+
+    p_sys->p_buffer = malloc( p_context->frame_size * 2 *
+                              p_context->channels * 2 );
+
+    p_sys->p_buffer_out = malloc( 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE );
+
+    p_sys->i_frame_size = p_sys->p_context->frame_size * 2 *
+                            p_context->channels;
+
+    /* Hack for mp3 transcoding support */
+    if( p_enc->i_fourcc == VLC_FOURCC( 'm','p','3',' ' ) )
+    {
+        p_enc->i_fourcc = VLC_FOURCC( 'm','p','g','a' );
+    }
+
+    return VLC_SUCCESS;
+}
+
+/****************************************************************************
+ * EncodeAudio: the whole thing
+ ****************************************************************************/
+static block_t *EncodeAudio( encoder_t *p_enc, aout_buffer_t *p_aout_buf )
+{
+    encoder_sys_t *p_sys = p_enc->p_sys;
+    block_t *p_block, *p_chain = NULL;
+    char *p_buffer = p_aout_buf->p_buffer;
+    int i_samples = p_aout_buf->i_nb_samples;
+    int i_samples_delay = p_sys->i_samples_delay;
+
+    p_sys->i_pts = p_aout_buf->start_date -
+                (mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay /
+                (mtime_t)p_enc->format.audio.i_rate;
+
+    p_sys->i_samples_delay += i_samples;
+
+    while( p_sys->i_samples_delay >= p_sys->p_context->frame_size )
+    {
+        int16_t *p_samples;
+        int i_out;
+
+        if( i_samples_delay )
+        {
+            /* Take care of the left-over from last time */
+            int i_delay_size = i_samples_delay  * 2 *
+                                 p_sys->p_context->channels;
+            int i_size = p_sys->i_frame_size - i_delay_size;
+
+            p_samples = (int16_t *)p_sys->p_buffer;
+            memcpy( p_sys->p_buffer + i_delay_size, p_buffer, i_size );
+            p_buffer -= i_delay_size;
+           i_samples += i_samples_delay;
+            i_samples_delay = 0;
+        }
+        else
+        {
+            p_samples = (int16_t *)p_buffer;
+        }
+
+        i_out = avcodec_encode_audio( p_sys->p_context, p_sys->p_buffer_out,
+                                      2 * AVCODEC_MAX_AUDIO_FRAME_SIZE,
+                                      p_samples );
+        if( i_out <= 0 )
+        {
+            break;
+        }
+
+        p_buffer += p_sys->i_frame_size;
+        p_sys->i_samples_delay -= p_sys->p_context->frame_size;
+       i_samples = p_sys->p_context->frame_size;
+
+        p_block = block_New( p_enc, i_out );
+        memcpy( p_block->p_buffer, p_sys->p_buffer_out, i_out );
+
+        p_block->i_length = (mtime_t)1000000 *
+            (mtime_t)p_sys->p_context->frame_size /
+            (mtime_t)p_sys->p_context->sample_rate;
+
+        p_block->i_dts = p_block->i_pts = p_sys->i_pts;
+
+        /* Update pts */
+        p_sys->i_pts += p_block->i_length;
+        block_ChainAppend( &p_chain, p_block );
+    }
+
+    /* Backup the remaining raw samples */
+    if( p_sys->i_samples_delay > 0 )
+    {
+        memcpy( p_sys->p_buffer, p_buffer + i_samples_delay,
+                i_samples * 2 * p_sys->p_context->channels );
+    }
+
+    return p_chain;
+}
+
+/*****************************************************************************
+ * CloseAudioEncoder: ffmpeg audio encoder destruction
+ *****************************************************************************/
+void E_(CloseAudioEncoder)( vlc_object_t *p_this )
+{
+    encoder_t *p_enc = (encoder_t *)p_this;
+    encoder_sys_t *p_sys = p_enc->p_sys;
+
+    avcodec_close( p_sys->p_context );
+    free( p_sys->p_context );
+    free( p_sys->p_buffer );
+    free( p_sys->p_buffer_out );
+    free( p_sys );
+}
index db2347abf913825700a58019ceb208af4322ab51..19a7a0ab56b88d086cea14f0399d066929ab8ce3 100644 (file)
@@ -2,9 +2,10 @@
  * ffmpeg.c: video decoder using ffmpeg library
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: ffmpeg.c,v 1.54 2003/10/25 00:49:13 sam Exp $
+ * $Id: ffmpeg.c,v 1.55 2003/10/27 01:04:38 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
@@ -25,6 +26,7 @@
  * Preamble
  *****************************************************************************/
 #include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>
 
 #include <vlc/vlc.h>
 #include <vlc/vout.h>
@@ -32,8 +34,6 @@
 #include <vlc/decoder.h>
 #include <vlc/input.h>
 
-#include <string.h>
-
 #ifdef HAVE_SYS_TIMES_H
 #   include <sys/times.h>
 #endif
@@ -49,7 +49,6 @@
 #   error You must have a libavcodec >= 4655 (get CVS)
 #endif
 
-
 #include "ffmpeg.h"
 
 #ifdef LIBAVCODEC_PP
 #   endif
 #endif
 
-#include "video.h" // video ffmpeg specific
-#include "audio.h" // audio ffmpeg specific
-
-/*
- * Local prototypes
- */
-int             E_(OpenChroma)  ( vlc_object_t * );
-void            E_(ffmpeg_InitLibavcodec) ( vlc_object_t *p_object );
-
-static int      OpenDecoder     ( vlc_object_t * );
-static int      RunDecoder      ( decoder_fifo_t * );
+/*****************************************************************************
+ * decoder_sys_t: decoder descriptor
+ *****************************************************************************/
+struct decoder_sys_t
+{
+    /* Common part between video and audio decoder */
+    int i_cat;
+    int i_codec_id;
+    char *psz_namecodec;
 
-static int      InitThread      ( generic_thread_t * );
-static void     EndThread       ( generic_thread_t * );
+    AVCodecContext *p_context;
+    AVCodec        *p_codec;
+};
 
-static int      b_ffmpeginit = 0;
+/****************************************************************************
+ * Local prototypes
+ ****************************************************************************/
+static int OpenDecoder( vlc_object_t * );
+static int InitDecoder( decoder_t * );
+static int EndDecoder( decoder_t * );
 
-static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t, int *, int *, char ** );
+static int b_ffmpeginit = 0;
 
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-#define DR_TEXT N_("Direct rendering")
-
-#define ERROR_TEXT N_("Error resilience")
-#define ERROR_LONGTEXT N_( \
-    "ffmpeg can make errors resiliences.          \n" \
-    "Nevertheless, with a buggy encoder (like ISO MPEG-4 encoder from M$) " \
-    "this will produce a lot of errors.\n" \
-    "Valid range is -1 to 99 (-1 disables all errors resiliences).")
-
-#define BUGS_TEXT N_("Workaround bugs")
-#define BUGS_LONGTEXT N_( \
-    "Try to fix some bugs\n" \
-    "1  autodetect\n" \
-    "2  old msmpeg4\n" \
-    "4  xvid interlaced\n" \
-    "8  ump4 \n" \
-    "16 no padding\n" \
-    "32 ac vlc\n" \
-    "64 Qpel chroma")
-
-#define HURRYUP_TEXT N_("Hurry up")
-#define HURRYUP_LONGTEXT N_( \
-    "Allow the decoder to partially decode or skip frame(s) " \
-    "when there is not enough time. It's useful with low CPU power " \
-    "but it can produce distorted pictures.")
-
-#define TRUNC_TEXT N_("Truncated stream")
-#define TRUNC_LONGTEXT N_("truncated stream -1:auto,0:disable,:1:enable")
-
-#define PP_Q_TEXT N_("Post processing quality")
-#define PP_Q_LONGTEXT N_( \
-    "Quality of post processing. Valid range is 0 to 6\n" \
-    "Higher levels require considerable more CPU power, but produce " \
-    "better looking pictures." )
-
-#define LIBAVCODEC_PP_TEXT N_("Ffmpeg postproc filter chains")
-/* FIXME (cut/past from ffmpeg */
-#define LIBAVCODEC_PP_LONGTEXT \
-"<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n" \
-"long form example:\n" \
-"vdeblock:autoq/hdeblock:autoq/linblenddeint    default,-vdeblock\n" \
-"short form example:\n" \
-"vb:a/hb:a/lb de,-vb\n" \
-"more examples:\n" \
-"tn:64:128:256\n" \
-"Filters                        Options\n" \
-"short  long name       short   long option     Description\n" \
-"*      *               a       autoq           cpu power dependant enabler\n" \
-"                       c       chrom           chrominance filtring enabled\n" \
-"                       y       nochrom         chrominance filtring disabled\n" \
-"hb     hdeblock        (2 Threshold)           horizontal deblocking filter\n" \
-"       1. difference factor: default=64, higher -> more deblocking\n" \
-"       2. flatness threshold: default=40, lower -> more deblocking\n" \
-"                       the h & v deblocking filters share these\n" \
-"                       so u cant set different thresholds for h / v\n" \
-"vb     vdeblock        (2 Threshold)           vertical deblocking filter\n" \
-"h1     x1hdeblock                              Experimental h deblock filter 1\n" \
-"v1     x1vdeblock                              Experimental v deblock filter 1\n" \
-"dr     dering                                  Deringing filter\n" \
-"al     autolevels                              automatic brightness / contrast\n" \
-"                       f       fullyrange      stretch luminance to (0..255)\n" \
-"lb     linblenddeint                           linear blend deinterlacer\n" \
-"li     linipoldeint                            linear interpolating deinterlace\n" \
-"ci     cubicipoldeint                          cubic interpolating deinterlacer\n" \
-"md     mediandeint                             median deinterlacer\n" \
-"fd     ffmpegdeint                             ffmpeg deinterlacer\n" \
-"de     default                                 hb:a,vb:a,dr:a,al\n" \
-"fa     fast                                    h1:a,v1:a,dr:a,al\n" \
-"tn     tmpnoise        (3 Thresholds)          Temporal Noise Reducer\n" \
-"                       1. <= 2. <= 3.          larger -> stronger filtering\n" \
-"fq     forceQuant      <quantizer>             Force quantizer\n"
-
 vlc_module_begin();
+
+    /* decoder main module */
     add_category_hint( N_("ffmpeg"), NULL, VLC_FALSE );
     set_capability( "decoder", 70 );
     set_callbacks( OpenDecoder, NULL );
     set_description( _("ffmpeg audio/video decoder((MS)MPEG4,SVQ1,H263,WMV,WMA)") );
 
     add_bool( "ffmpeg-dr", 1, NULL, DR_TEXT, DR_TEXT, VLC_TRUE );
-    add_integer ( "ffmpeg-error-resilience", -1, NULL, ERROR_TEXT, ERROR_LONGTEXT, VLC_TRUE );
-    add_integer ( "ffmpeg-workaround-bugs", 1, NULL, BUGS_TEXT, BUGS_LONGTEXT, VLC_FALSE );
-    add_bool( "ffmpeg-hurry-up", 0, NULL, HURRYUP_TEXT, HURRYUP_LONGTEXT, VLC_FALSE );
-    add_integer( "ffmpeg-truncated", -1, NULL, TRUNC_TEXT, TRUNC_LONGTEXT, VLC_FALSE );
+    add_integer ( "ffmpeg-error-resilience", -1, NULL, ERROR_TEXT,
+        ERROR_LONGTEXT, VLC_TRUE );
+    add_integer ( "ffmpeg-workaround-bugs", 1, NULL, BUGS_TEXT, BUGS_LONGTEXT,
+        VLC_FALSE );
+    add_bool( "ffmpeg-hurry-up", 0, NULL, HURRYUP_TEXT, HURRYUP_LONGTEXT,
+        VLC_FALSE );
+    add_integer( "ffmpeg-truncated", 0, NULL, TRUNC_TEXT, TRUNC_LONGTEXT,
+        VLC_FALSE );
 
-    add_category_hint( N_("Post processing"), NULL, VLC_FALSE );
-
-    add_integer( "ffmpeg-pp-q", 0, NULL, PP_Q_TEXT, PP_Q_LONGTEXT, VLC_FALSE );
 #ifdef LIBAVCODEC_PP
-    add_string( "ffmpeg-pp-name", "default", NULL, LIBAVCODEC_PP_TEXT, LIBAVCODEC_PP_LONGTEXT, VLC_TRUE );
+    add_integer( "ffmpeg-pp-q", 0, NULL, PP_Q_TEXT, PP_Q_LONGTEXT, VLC_FALSE );
+    add_string( "ffmpeg-pp-name", "default", NULL, LIBAVCODEC_PP_TEXT,
+        LIBAVCODEC_PP_LONGTEXT, VLC_TRUE );
 #endif
 
     /* chroma conversion submodule */
@@ -179,234 +115,124 @@ vlc_module_begin();
     set_callbacks( E_(OpenChroma), NULL );
     set_description( _("ffmpeg chroma conversion") );
 
+     /* video encoder submodule */
+     add_submodule();
+     set_description( _("ffmpeg video encoder") );
+     set_capability( "video encoder", 100 );
+     set_callbacks( E_(OpenVideoEncoder), E_(CloseVideoEncoder) );
+     /* audio encoder submodule */
+     add_submodule();
+     set_description( _("ffmpeg audio encoder") );
+     set_capability( "audio encoder", 10 );
+     set_callbacks( E_(OpenAudioEncoder), E_(CloseAudioEncoder) );
     var_Create( p_module->p_libvlc, "avcodec", VLC_VAR_MUTEX );
 vlc_module_end();
 
 /*****************************************************************************
  * OpenDecoder: probe the decoder and return score
- *****************************************************************************
- * Tries to launch a decoder and return score so that the interface is able
- * to chose.
  *****************************************************************************/
 static int OpenDecoder( vlc_object_t *p_this )
 {
     decoder_t *p_dec = (decoder_t*) p_this;
+    int i_cat;
 
-    if( !ffmpeg_GetFfmpegCodec( p_dec->p_fifo->i_fourcc, NULL, NULL, NULL ) )
+    if( !E_(GetFfmpegCodec)( p_dec->p_fifo->i_fourcc, &i_cat, NULL, NULL ) )
     {
         return VLC_EGENERIC;
     }
 
-    p_dec->pf_run = RunDecoder;
+    p_dec->pf_init = InitDecoder;
+    p_dec->pf_decode = (i_cat == VIDEO_ES) ? E_(DecodeVideo) : E_(DecodeAudio);
+    p_dec->pf_end = EndDecoder;
 
     return VLC_SUCCESS;
 }
 
-typedef union decoder_thread_u
-{
-    generic_thread_t gen;
-    adec_thread_t    audio;
-    vdec_thread_t    video;
-
-} decoder_thread_t;
-
 /*****************************************************************************
- * RunDecoder: this function is called just after the thread is created
+ * InitDecoder: Initalize the decoder
  *****************************************************************************/
-static int RunDecoder( decoder_fifo_t *p_fifo )
-{
-    generic_thread_t *p_decoder;
-    int b_error;
-
-    if ( !(p_decoder = malloc( sizeof( decoder_thread_t ) ) ) )
-    {
-        msg_Err( p_fifo, "out of memory" );
-        DecoderError( p_fifo );
-        return( -1 );
-    }
-    memset( p_decoder, 0, sizeof( decoder_thread_t ) );
-
-    p_decoder->p_fifo = p_fifo;
-
-    if( InitThread( p_decoder ) != 0 )
-    {
-        msg_Err( p_fifo, "initialization failed" );
-        DecoderError( p_fifo );
-        return( -1 );
-    }
-
-    while( (!p_decoder->p_fifo->b_die) && (!p_decoder->p_fifo->b_error) )
-    {
-        switch( p_decoder->i_cat )
-        {
-            case VIDEO_ES:
-                E_( DecodeThread_Video )( (vdec_thread_t*)p_decoder );
-                break;
-            case AUDIO_ES:
-                E_( DecodeThread_Audio )( (adec_thread_t*)p_decoder );
-                break;
-        }
-    }
-
-    if( ( b_error = p_decoder->p_fifo->b_error ) )
-    {
-        DecoderError( p_decoder->p_fifo );
-    }
-
-    EndThread( p_decoder );
-
-    if( b_error )
-    {
-        return( -1 );
-    }
-
-    return( 0 );
-}
-
-/*****************************************************************************
- *
- * Functions that initialize, decode and end the decoding process
- *
- *****************************************************************************/
-
-/*****************************************************************************
- * InitThread: initialize vdec output thread
- *****************************************************************************
- * 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)
- *****************************************************************************/
-
-static int InitThread( generic_thread_t *p_decoder )
+static int InitDecoder( decoder_t *p_dec )
 {
-    int i_result;
+    int i_cat, i_codec_id, i_result;
+    char *psz_namecodec;
+    AVCodecContext *p_context;
+    AVCodec        *p_codec;
 
-    E_(ffmpeg_InitLibavcodec)(VLC_OBJECT(p_decoder->p_fifo));
+    E_(InitLibavcodec)( VLC_OBJECT(p_dec->p_fifo) );
 
     /* *** determine codec type *** */
-    ffmpeg_GetFfmpegCodec( p_decoder->p_fifo->i_fourcc,
-                           &p_decoder->i_cat,
-                           &p_decoder->i_codec_id,
-                           &p_decoder->psz_namecodec );
+    E_(GetFfmpegCodec)( p_dec->p_fifo->i_fourcc,
+                        &i_cat, &i_codec_id, &psz_namecodec );
 
     /* *** ask ffmpeg for a decoder *** */
-    if( !( p_decoder->p_codec =
-                avcodec_find_decoder( p_decoder->i_codec_id ) ) )
+    if( !( p_codec = avcodec_find_decoder( i_codec_id ) ) )
     {
-        msg_Err( p_decoder->p_fifo,
-                 "codec not found (%s)",
-                 p_decoder->psz_namecodec );
-        return( -1 );
+        msg_Err( p_dec, "codec not found (%s)", psz_namecodec );
+        return VLC_EGENERIC;
     }
 
-     /* *** Get a p_context *** */
-    p_decoder->p_context = avcodec_alloc_context();
+    /* *** get a p_context *** */
+    p_context = avcodec_alloc_context();
 
-    switch( p_decoder->i_cat )
+    switch( i_cat )
     {
-        case VIDEO_ES:
-            i_result = E_( InitThread_Video )( (vdec_thread_t*)p_decoder );
-            break;
-        case AUDIO_ES:
-            i_result = E_( InitThread_Audio )( (adec_thread_t*)p_decoder );
-            break;
-        default:
-            i_result = -1;
+    case VIDEO_ES:
+        i_result = E_( InitVideoDec )( p_dec, p_context, p_codec,
+                                       i_codec_id, psz_namecodec );
+        p_dec->pf_decode = E_(DecodeVideo);
+        break;
+    case AUDIO_ES:
+        i_result = E_( InitAudioDec )( p_dec, p_context, p_codec,
+                                       i_codec_id, psz_namecodec );
+        p_dec->pf_decode = E_(DecodeAudio);
+        break;
+    default:
+        i_result = VLC_EGENERIC;
     }
 
-    p_decoder->pts = 0;
-    p_decoder->p_buffer = NULL;
-    p_decoder->i_buffer = 0;
-    p_decoder->i_buffer_size = 0;
+    p_dec->p_sys->i_cat = i_cat;
 
-    return( i_result );
+    return i_result;
 }
-
+  
 /*****************************************************************************
- * EndThread: thread destruction
- *****************************************************************************
- * This function is called when the thread ends after a sucessful
- * initialization.
+ * EndDecoder: decoder destruction
  *****************************************************************************/
-static void EndThread( generic_thread_t *p_decoder )
+static int EndDecoder( decoder_t *p_dec )
 {
+    decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if( !p_decoder )
+    if( !p_sys->p_context )
     {
-        return;
-    }
+        if( p_sys->p_context->extradata )
+            free( p_sys->p_context->extradata );
 
-    if( p_decoder->p_context != NULL)
-    {
-        FREE( p_decoder->p_context->extradata );
-        avcodec_close( p_decoder->p_context );
-        msg_Dbg( p_decoder->p_fifo,
-                 "ffmpeg codec (%s) stopped",
-                 p_decoder->psz_namecodec );
-        free( p_decoder->p_context );
+        avcodec_close( p_sys->p_context );
+        msg_Dbg( p_dec, "ffmpeg codec (%s) stopped", p_sys->psz_namecodec );
+        free( p_sys->p_context );
     }
 
-    FREE( p_decoder->p_buffer );
-
-    switch( p_decoder->i_cat )
+    switch( p_sys->i_cat )
     {
-        case AUDIO_ES:
-            E_( EndThread_Audio )( (adec_thread_t*)p_decoder );
-            break;
-        case VIDEO_ES:
-            E_( EndThread_Video )( (vdec_thread_t*)p_decoder );
-            break;
+    case AUDIO_ES:
+        E_( EndAudioDec )( p_dec );
+        break;
+    case VIDEO_ES:
+        E_( EndVideoDec )( p_dec );
+        break;
     }
 
-    free( p_decoder );
+    free( p_sys );
+    return VLC_SUCCESS;
 }
-
+  
 /*****************************************************************************
- * locales Functions
+ * local Functions
  *****************************************************************************/
-
-int E_( GetPESData )( uint8_t *p_buf, int i_max, pes_packet_t *p_pes )
-{
-    int i_copy;
-    int i_count;
-
-    data_packet_t   *p_data;
-
-    i_count = 0;
-    p_data = p_pes->p_first;
-    while( p_data != NULL && i_count < i_max )
-    {
-
-        i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start,
-                        i_max - i_count );
-
-        if( i_copy > 0 )
-        {
-            memcpy( p_buf,
-                    p_data->p_payload_start,
-                    i_copy );
-        }
-
-        p_data = p_data->p_next;
-        i_count += i_copy;
-        p_buf   += i_copy;
-    }
-
-    if( i_count < i_max )
-    {
-        memset( p_buf, 0, i_max - i_count );
-    }
-    return( i_count );
-}
-
-
-static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
-                                  int *pi_cat,
-                                  int *pi_ffmpeg_codec,
-                                  char **ppsz_name )
+int E_(GetFfmpegCodec)( vlc_fourcc_t i_fourcc, int *pi_cat,
+                        int *pi_ffmpeg_codec, char **ppsz_name )
 {
     int i_cat;
     int i_codec;
@@ -414,302 +240,391 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
 
     switch( i_fourcc )
     {
-        case FOURCC_mpgv:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_MPEG1VIDEO;
-            psz_name = "MPEG-1/2 Video";
-            break;
-
-        case FOURCC_DIV1:
-        case FOURCC_div1:
-        case FOURCC_MPG4:
-        case FOURCC_mpg4:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_MSMPEG4V1;
-            psz_name = "MS MPEG-4 v1";
-            break;
-
-        case FOURCC_DIV2:
-        case FOURCC_div2:
-        case FOURCC_MP42:
-        case FOURCC_mp42:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_MSMPEG4V2;
-            psz_name = "MS MPEG-4 v2";
-            break;
-
-        case FOURCC_MPG3:
-        case FOURCC_mpg3:
-        case FOURCC_div3:
-        case FOURCC_MP43:
-        case FOURCC_mp43:
-        case FOURCC_DIV3:
-        case FOURCC_DIV4:
-        case FOURCC_div4:
-        case FOURCC_DIV5:
-        case FOURCC_div5:
-        case FOURCC_DIV6:
-        case FOURCC_div6:
-        case FOURCC_AP41:
-        case FOURCC_3VID:
-        case FOURCC_3vid:
-        case FOURCC_3IVD:
-        case FOURCC_3ivd:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_MSMPEG4V3;
-            psz_name = "MS MPEG-4 v3";
-            break;
-
-        case FOURCC_SVQ1:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_SVQ1;
-            psz_name = "SVQ-1 (Sorenson Video v1)";
-            break;
-#if LIBAVCODEC_BUILD >= 4666
-        case FOURCC_SVQ3:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_SVQ3;
-            psz_name = "SVQ-3 (Sorenson Video v3)";
-            break;
-#endif
 
-        case FOURCC_DIVX:
-        case FOURCC_divx:
-        case FOURCC_MP4S:
-        case FOURCC_mp4s:
-        case FOURCC_M4S2:
-        case FOURCC_m4s2:
-        case FOURCC_xvid:
-        case FOURCC_XVID:
-        case FOURCC_XviD:
-        case FOURCC_DX50:
-        case FOURCC_mp4v:
-        case FOURCC_4:
-        case FOURCC_m4cc:
-        case FOURCC_M4CC:
-        /* 3iv1 is unsupported by ffmpeg
-           putting it here gives extreme distorted images
-        case FOURCC_3IV1:
-        case FOURCC_3iv1:
-        */
-        case FOURCC_3IV2:
-        case FOURCC_3iv2:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_MPEG4;
-            psz_name = "MPEG-4";
-            break;
+    /*
+     *  Video Codecs
+     */
+
+    /* MPEG-1 Video */
+    case VLC_FOURCC('m','p','1','v'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_MPEG1VIDEO;
+        psz_name = "MPEG-1/2 Video";
+        break;
+
+    /* MPEG-2 Video */
+    case VLC_FOURCC('m','p','2','v'):
+    case VLC_FOURCC('m','p','g','v'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_MPEG2VIDEO;
+        psz_name = "MPEG-2 Video";
+        break;
+
+    /* MPEG-4 Video */
+    case VLC_FOURCC('D','I','V','X'):
+    case VLC_FOURCC('d','i','v','x'):
+    case VLC_FOURCC('M','P','4','S'):
+    case VLC_FOURCC('m','p','4','s'):
+    case VLC_FOURCC('M','4','S','2'):
+    case VLC_FOURCC('m','4','s','2'):
+    case VLC_FOURCC('x','v','i','d'):
+    case VLC_FOURCC('X','V','I','D'):
+    case VLC_FOURCC('X','v','i','D'):
+    case VLC_FOURCC('D','X','5','0'):
+    case VLC_FOURCC('m','p','4','v'):
+    case VLC_FOURCC( 4,  0,  0,  0 ):
+    case VLC_FOURCC('m','4','c','c'):
+    case VLC_FOURCC('M','4','C','C'):
+    /* 3ivx delta 3.5 Unsupported
+     * putting it here gives extreme distorted images
+    case VLC_FOURCC('3','I','V','1'):
+    case VLC_FOURCC('3','i','v','1'): */
+    /* 3ivx delta 4 */
+    case VLC_FOURCC('3','I','V','2'):
+    case VLC_FOURCC('3','i','v','2'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_MPEG4;
+        psz_name = "MPEG-4";
+        break;
+
+    /* MSMPEG4 v1 */
+    case VLC_FOURCC('D','I','V','1'):
+    case VLC_FOURCC('d','i','v','1'):
+    case VLC_FOURCC('M','P','G','4'):
+    case VLC_FOURCC('m','p','g','4'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_MSMPEG4V1;
+        psz_name = "MS MPEG-4 v1";
+        break;
+
+    /* MSMPEG4 v2 */
+    case VLC_FOURCC('D','I','V','2'):
+    case VLC_FOURCC('d','i','v','2'):
+    case VLC_FOURCC('M','P','4','2'):
+    case VLC_FOURCC('m','p','4','2'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_MSMPEG4V2;
+        psz_name = "MS MPEG-4 v2";
+        break;
+
+    /* MSMPEG4 v3 / M$ mpeg4 v3 */
+    case VLC_FOURCC('M','P','G','3'):
+    case VLC_FOURCC('m','p','g','3'):
+    case VLC_FOURCC('d','i','v','3'):
+    case VLC_FOURCC('M','P','4','3'):
+    case VLC_FOURCC('m','p','4','3'):
+    /* DivX 3.20 */
+    case VLC_FOURCC('D','I','V','3'):
+    case VLC_FOURCC('D','I','V','4'):
+    case VLC_FOURCC('d','i','v','4'):
+    case VLC_FOURCC('D','I','V','5'):
+    case VLC_FOURCC('d','i','v','5'):
+    case VLC_FOURCC('D','I','V','6'):
+    case VLC_FOURCC('d','i','v','6'):
+    /* AngelPotion stuff */
+    case VLC_FOURCC('A','P','4','1'):
+    /* 3ivx doctered divx files */
+    case VLC_FOURCC('3','I','V','D'):
+    case VLC_FOURCC('3','i','v','d'):
+    /* who knows? */
+    case VLC_FOURCC('3','V','I','D'):
+    case VLC_FOURCC('3','v','i','d'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_MSMPEG4V3;
+        psz_name = "MS MPEG-4 v3";
+        break;
+
+    /* Sorenson v1 */
+    case VLC_FOURCC('S','V','Q','1'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_SVQ1;
+        psz_name = "SVQ-1 (Sorenson Video v1)";
+        break;
+
+    /* Sorenson v3 */
+    case VLC_FOURCC('S','V','Q','3'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_SVQ3;
+        psz_name = "SVQ-3 (Sorenson Video v3)";
+        break;
+
+/* H263 and H263i */
+/* H263(+) is also known as Real Video 1.0 */
 
 /* FIXME FOURCC_H263P exist but what fourcc ? */
-        case FOURCC_H263:
-        case FOURCC_h263:
-        case FOURCC_U263:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_H263;
-            psz_name = "H263";
-            break;
-
-        case FOURCC_I263:
-        case FOURCC_i263:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_H263I;
-            psz_name = "I263.I";
-            break;
-        case FOURCC_WMV1:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_WMV1;
-            psz_name ="Windows Media Video 1";
-            break;
-        case FOURCC_WMV2:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_WMV2;
-            psz_name ="Windows Media Video 2";
-            break;
-        case FOURCC_MJPG:
-        case FOURCC_mjpg:
-        case FOURCC_mjpa:
-        case FOURCC_jpeg:
-        case FOURCC_JPEG:
-        case FOURCC_JFIF:
-        case FOURCC_JPGL:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_MJPEG;
-            psz_name = "Motion JPEG";
-            break;
-        case FOURCC_mjpb:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_MJPEGB;
-            psz_name = "Motion JPEG B";
-            break;
-        case FOURCC_dvsl:
-        case FOURCC_dvsd:
-        case FOURCC_DVSD:
-        case FOURCC_dvhd:
-        case FOURCC_dvc:
-        case FOURCC_dvp:
-        case FOURCC_CDVC:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_DVVIDEO;
-            psz_name = "DV video";
-            break;
-
-        case FOURCC_MAC3:
-            i_cat = AUDIO_ES;
-            i_codec = CODEC_ID_MACE3;
-            psz_name = "MACE-3 audio";
-            break;
-        case FOURCC_MAC6:
-            i_cat = AUDIO_ES;
-            i_codec = CODEC_ID_MACE6;
-            psz_name = "MACE-6 audio";
-            break;
-        case FOURCC_dvau:
-            i_cat = AUDIO_ES;
-            i_codec = CODEC_ID_DVAUDIO;
-            psz_name = "DV audio";
-            break;
-
-        case FOURCC_WMA1:
-        case FOURCC_wma1:
-            i_cat = AUDIO_ES;
-            i_codec = CODEC_ID_WMAV1;
-            psz_name ="Windows Media Audio 1";
-            break;
-        case FOURCC_WMA2:
-        case FOURCC_wma2:
-            i_cat = AUDIO_ES;
-            i_codec = CODEC_ID_WMAV2;
-            psz_name ="Windows Media Audio 2";
-            break;
-
-        case FOURCC_HFYU:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_HUFFYUV;
-            psz_name ="Huff YUV";
-            break;
-
-        case FOURCC_CYUV:
-            i_cat = VIDEO_ES;
-            i_codec = CODEC_ID_CYUV;
-            psz_name ="Creative YUV";
-            break;
 
+    /* H263 */
+    case VLC_FOURCC('H','2','6','3'):
+    case VLC_FOURCC('h','2','6','3'):
+    case VLC_FOURCC('U','2','6','3'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_H263;
+        psz_name = "H263";
+        break;
+
+    /* H263i */
+    case VLC_FOURCC('I','2','6','3'):
+    case VLC_FOURCC('i','2','6','3'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_H263I;
+        psz_name = "I263.I";
+        break;
+
+#if LIBAVCODEC_BUILD >= 4669
+    /* Flash (H263) variant */
+    case VLC_FOURCC('F','L','V','1'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_FLV1;
+        psz_name = "Flash Video";
+        break;
+#endif
+
+    /* MJPEG */
+    case VLC_FOURCC( 'M', 'J', 'P', 'G' ):
+    case VLC_FOURCC( 'm', 'j', 'p', 'g' ):
+    case VLC_FOURCC( 'm', 'j', 'p', 'a' ): /* for mov file */
+    case VLC_FOURCC( 'j', 'p', 'e', 'g' ):
+    case VLC_FOURCC( 'J', 'P', 'E', 'G' ):
+    case VLC_FOURCC( 'J', 'F', 'I', 'F' ):
+    case VLC_FOURCC( 'J', 'P', 'G', 'L' ):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_MJPEG;
+        psz_name = "Motion JPEG";
+        break;
+    case VLC_FOURCC( 'm', 'j', 'p', 'b' ): /* for mov file */
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_MJPEGB;
+        psz_name = "Motion JPEG B";
+        break;
+
+    /* DV */
+    case VLC_FOURCC('d','v','s','l'):
+    case VLC_FOURCC('d','v','s','d'):
+    case VLC_FOURCC('D','V','S','D'):
+    case VLC_FOURCC('d','v','h','d'):
+    case VLC_FOURCC('d','v','c',' '):
+    case VLC_FOURCC('d','v','p',' '):
+    case VLC_FOURCC('C','D','V','C'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_DVVIDEO;
+        psz_name = "DV video";
+        break;
+
+    /* Windows Media Video */
+    case VLC_FOURCC('W','M','V','1'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_WMV1;
+        psz_name ="Windows Media Video 1";
+        break;
+    case VLC_FOURCC('W','M','V','2'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_WMV2;
+        psz_name ="Windows Media Video 2";
+        break;
+
+#if LIBAVCODEC_BUILD >= 4683
+    /* Microsoft Video 1 */
+    case VLC_FOURCC('M','S','V','C'):
+    case VLC_FOURCC('m','s','v','c'):
+    case VLC_FOURCC('C','R','A','M'):
+    case VLC_FOURCC('c','r','a','m'):
+    case VLC_FOURCC('W','H','A','M'):
+    case VLC_FOURCC('w','h','a','m'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_MSVIDEO1;
+        psz_name = "Microsoft Video 1";
+        break;
+
+    /* Microsoft RLE */
+    case VLC_FOURCC('m','r','l','e'):
+    case VLC_FOURCC(0x1,0x0,0x0,0x0):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_MSRLE;
+        psz_name = "Microsoft RLE";
+        break;
+#endif
 
 #if( ( LIBAVCODEC_BUILD >= 4663 ) && ( !defined( WORDS_BIGENDIAN ) ) )
-        /* Quality of this decoder on ppc is not good */
-        case FOURCC_IV31:
-        case FOURCC_iv31:
-        case FOURCC_IV32:
-        case FOURCC_iv32:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_INDEO3;
-            psz_name = "Indeo v3";
-            break;
+    /* Indeo Video Codecs (Quality of this decoder on ppc is not good) */
+    case VLC_FOURCC('I','V','3','1'):
+    case VLC_FOURCC('i','v','3','1'):
+    case VLC_FOURCC('I','V','3','2'):
+    case VLC_FOURCC('i','v','3','2'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_INDEO3;
+        psz_name = "Indeo v3";
+        break;
 #endif
 
+    /* Huff YUV */
+    case VLC_FOURCC('H','F','Y','U'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_HUFFYUV;
+        psz_name ="Huff YUV";
+        break;
+
+    /* Creative YUV */
+    case VLC_FOURCC('C','Y','U','V'):
+        i_cat = VIDEO_ES;
+        i_codec = CODEC_ID_CYUV;
+        psz_name ="Creative YUV";
+        break;
+
 #if LIBAVCODEC_BUILD >= 4668
-/* Sorta works */
-        case FOURCC_vp31:
-        case FOURCC_VP31:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_VP3;
-            psz_name = "On2's VP3 Video";
-            break;
+    /* On2 VP3 Video Codecs */
+    case VLC_FOURCC('V','P','3','1'):
+    case VLC_FOURCC('v','p','3','1'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_VP3;
+        psz_name = "On2's VP3 Video";
+        break;
+#endif
 
 #if ( !defined( WORDS_BIGENDIAN ) )
-/* Another thing that doesn't work */
-        case FOURCC_ASV1:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_ASV1;
-            psz_name = "Asus V1";
-            break;
+#if LIBAVCODEC_BUILD >= 4668
+    /* Asus Video (Another thing that doesn't work on PPC) */
+    case VLC_FOURCC('A','S','V','1'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_ASV1;
+        psz_name = "Asus V1";
+        break;
+#endif
+#if LIBAVCODEC_BUILD >= 4677
+    case VLC_FOURCC('A','S','V','2'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_ASV2;
+        psz_name = "Asus V2";
+        break;
+#endif
 #endif
 
-        case FOURCC_FFV1:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_FFV1;
-            psz_name = "FFMpeg Video 1";
-            break;
-
-        case FOURCC_RA10:
-            i_cat    = AUDIO_ES;
-            i_codec  = CODEC_ID_RA_144;
-            psz_name = "RealAudio 1.0";
-            break;
-
-        case FOURCC_RA20:
-            i_cat    = AUDIO_ES;
-            i_codec  = CODEC_ID_RA_288;
-            psz_name = "RealAudio 2.0";
-            break;
+#if LIBAVCODEC_BUILD >= 4668
+    /* FFMPEG Video 1 (lossless codec) */
+    case VLC_FOURCC('F','F','V','1'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_FFV1;
+        psz_name = "FFMpeg Video 1";
+        break;
 #endif
 
 #if LIBAVCODEC_BUILD >= 4669
-        case FOURCC_FLV1:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_FLV1;
-            psz_name = "Flash Video";
-            break;
-
-        case FOURCC_VCR1:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_VCR1;
-            psz_name = "ATI VCR1";
-            break;
-
+    /* ATI VCR1 */
+    case VLC_FOURCC('V','C','R','1'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_VCR1;
+        psz_name = "ATI VCR1";
+        break;
 #endif
 
 #if LIBAVCODEC_BUILD >= 4672
-        case FOURCC_CLJR:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_CLJR;
-            psz_name = "Creative Logic AccuPak";
-            break;
+    /* Cirrus Logic AccuPak */
+    case VLC_FOURCC('C','L','J','R'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_CLJR;
+        psz_name = "Creative Logic AccuPak";
+        break;
 #endif
 
-#if LIBAVCODEC_BUILD >= 4677
-        case FOURCC_ASV2:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_ASV2;
-            psz_name = "Asus V2";
-            break;
+#if LIBAVCODEC_BUILD >= 4683
+    /* Apple Video */
+    case VLC_FOURCC('r','p','z','a'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_RPZA;
+        psz_name = "Apple Video";
+        break;
 #endif
 
 #if LIBAVCODEC_BUILD >= 4683
-        case FOURCC_rpza:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_RPZA;
-            psz_name = "Apple Video";
-            break;
-
-        case FOURCC_cvid:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_CINEPAK;
-            psz_name = "Cinepak";
-            break;
-
-        case FOURCC_mrle:
-        case FOURCC_1000:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_MSRLE;
-            psz_name = "Microsoft RLE";
-            break;
-
-        case FOURCC_cram:
-        case FOURCC_CRAM:
-        case FOURCC_msvc:
-        case FOURCC_MSVC:
-        case FOURCC_wham:
-        case FOURCC_WHAM:
-            i_cat    = VIDEO_ES;
-            i_codec  = CODEC_ID_MSVIDEO1;
-            psz_name = "Microsoft Video 1";
-            break;
+    /* Cinepak */
+    case VLC_FOURCC('c','v','i','d'):
+        i_cat    = VIDEO_ES;
+        i_codec  = CODEC_ID_CINEPAK;
+        psz_name = "Cinepak";
+        break;
+#endif
+
+    /*
+     *  Audio Codecs
+     */
+
+    /* Windows Media Audio 1 */
+    case VLC_FOURCC('W','M','A','1'):
+    case VLC_FOURCC('w','m','a','1'):
+        i_cat = AUDIO_ES;
+        i_codec = CODEC_ID_WMAV1;
+        psz_name ="Windows Media Audio 1";
+        break;
+
+    /* Windows Media Audio 2 */
+    case VLC_FOURCC('W','M','A','2'):
+    case VLC_FOURCC('w','m','a','2'):
+        i_cat = AUDIO_ES;
+        i_codec = CODEC_ID_WMAV2;
+        psz_name ="Windows Media Audio 2";
+        break;
+
+    /* DV Audio */
+    case VLC_FOURCC('d','v','a','u'):
+        i_cat = AUDIO_ES;
+        i_codec = CODEC_ID_DVAUDIO;
+        psz_name = "DV audio";
+        break;
+
+    /* MACE-3 Audio */
+    case VLC_FOURCC('M','A','C','3'):
+        i_cat = AUDIO_ES;
+        i_codec = CODEC_ID_MACE3;
+        psz_name = "MACE-3 audio";
+        break;
+
+    /* MACE-6 Audio */
+    case VLC_FOURCC('M','A','C','6'):
+        i_cat = AUDIO_ES;
+        i_codec = CODEC_ID_MACE6;
+        psz_name = "MACE-6 audio";
+        break;
+
+#if LIBAVCODEC_BUILD >= 4668
+    /* RealAudio 1.0 */
+    case VLC_FOURCC('1','4','_','4'):
+        i_cat    = AUDIO_ES;
+        i_codec  = CODEC_ID_RA_144;
+        psz_name = "RealAudio 1.0";
+        break;
+
+    /* RealAudio 2.0 */
+    case VLC_FOURCC('2','8','_','8'):
+        i_cat    = AUDIO_ES;
+        i_codec  = CODEC_ID_RA_288;
+        psz_name = "RealAudio 2.0";
+        break;
 #endif
-        default:
-            i_cat = UNKNOWN_ES;
-            i_codec = CODEC_ID_NONE;
-            psz_name = NULL;
-            break;
+
+    /* MPEG Audio layer 1/2/3 */
+    case VLC_FOURCC('m','p','g','a'):
+        i_cat    = AUDIO_ES;
+        i_codec  = CODEC_ID_MP2;
+        psz_name = "MPEG Audio layer 1/2";
+        break;
+    case VLC_FOURCC('m','p','3',' '):
+        i_cat    = AUDIO_ES;
+        i_codec  = CODEC_ID_MP3;
+        psz_name = "MPEG Audio layer 1/2/3";
+        break;
+
+    /* A52 Audio (aka AC3) */
+    case VLC_FOURCC('a','5','2',' '):
+    case VLC_FOURCC('a','5','2','b'): /* VLC specific hack */
+        i_cat    = AUDIO_ES;
+        i_codec  = CODEC_ID_AC3;
+        psz_name = "A52 Audio (aka AC3)";
+        break;
+
+    default:
+        i_cat = UNKNOWN_ES;
+        i_codec = CODEC_ID_NONE;
+        psz_name = NULL;
+        break;
     }
 
     if( i_codec != CODEC_ID_NONE )
@@ -723,7 +638,34 @@ static int ffmpeg_GetFfmpegCodec( vlc_fourcc_t i_fourcc,
     return( VLC_FALSE );
 }
 
-void E_ (ffmpeg_InitLibavcodec) ( vlc_object_t *p_object )
+int E_(GetFfmpegChroma)( vlc_fourcc_t i_chroma )
+{
+    switch( i_chroma )
+    {
+    case VLC_FOURCC( 'I', '4', '2', '0' ):
+        return PIX_FMT_YUV420P;
+    case VLC_FOURCC( 'I', '4', '2', '2' ):
+        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:
+        return 0;
+    }
+}
+
+void E_(InitLibavcodec)( vlc_object_t *p_object )
 {
     vlc_value_t lockval;
 
index 6cc1bc5959cdadc1fa8b9a076bcb1045c1229956..2393c21948f8cd251c6a32f2ebca8edc2b97c065 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- * ffmpeg_vdec.h: video decoder using ffmpeg library
+ * ffmpeg.h: decoder using the ffmpeg library
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: ffmpeg.h,v 1.26 2003/10/25 00:49:13 sam Exp $
+ * $Id: ffmpeg.h,v 1.27 2003/10/27 01:04:38 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
 
 #include "codecs.h"                                      /* BITMAPINFOHEADER */
 
-
-#define DECODER_THREAD_COMMON \
-    decoder_fifo_t      *p_fifo; \
-    \
-    int i_cat; /* AUDIO_ES, VIDEO_ES */ \
-    int i_codec_id; \
-    char *psz_namecodec; \
-    \
-    AVCodecContext      *p_context; \
-    AVCodec             *p_codec; \
-    mtime_t input_pts_previous; \
-    mtime_t input_pts; \
-    mtime_t pts; \
-    \
-    /* Private stuff for frame gathering */ \
-    uint8_t *p_buffer;      /* buffer for gather pes */  \
-    int     i_buffer_size;  /* size of allocated p_buffer */ \
-    int     i_buffer;       /* bytes already present in p_buffer */
-
-
-typedef struct generic_thread_s
-{
-    DECODER_THREAD_COMMON
-
-} generic_thread_t;
-
 #if LIBAVCODEC_BUILD >= 4663
 #   define LIBAVCODEC_PP
 #else
 #   undef  LIBAVCODEC_PP
 #endif
 
-#define FREE( p ) if( p ) free( p ); p = NULL
+struct picture_t;
+struct AVFrame;
+struct AVCodecContext;
+struct AVCodec;
 
-int E_( GetPESData )( uint8_t *p_buf, int i_max, pes_packet_t *p_pes );
+void E_(InitLibavcodec)( vlc_object_t * );
+int E_(GetFfmpegCodec)( vlc_fourcc_t, int *, int *, char ** );
+int E_(GetFfmpegChroma)( vlc_fourcc_t );
 
-/*****************************************************************************
- * Video codec fourcc
- *****************************************************************************/
+/* Video decoder module */
+int  E_( InitVideoDec )( decoder_t *, AVCodecContext *, AVCodec *,
+                         int, char * );
+void E_( EndVideoDec ) ( decoder_t * );
+int  E_( DecodeVideo ) ( decoder_t *, block_t * );
 
-/* MPEG 1/2 video */
-#define FOURCC_mpgv         VLC_FOURCC('m','p','g','v')
-
-/* MPEG4 video */
-#define FOURCC_DIVX         VLC_FOURCC('D','I','V','X')
-#define FOURCC_divx         VLC_FOURCC('d','i','v','x')
-#define FOURCC_DIV1         VLC_FOURCC('D','I','V','1')
-#define FOURCC_div1         VLC_FOURCC('d','i','v','1')
-#define FOURCC_MP4S         VLC_FOURCC('M','P','4','S')
-#define FOURCC_mp4s         VLC_FOURCC('m','p','4','s')
-#define FOURCC_M4S2         VLC_FOURCC('M','4','S','2')
-#define FOURCC_m4s2         VLC_FOURCC('m','4','s','2')
-#define FOURCC_xvid         VLC_FOURCC('x','v','i','d')
-#define FOURCC_XVID         VLC_FOURCC('X','V','I','D')
-#define FOURCC_XviD         VLC_FOURCC('X','v','i','D')
-#define FOURCC_DX50         VLC_FOURCC('D','X','5','0')
-#define FOURCC_mp4v         VLC_FOURCC('m','p','4','v')
-#define FOURCC_4            VLC_FOURCC( 4,  0,  0,  0 )
-#define FOURCC_m4cc         VLC_FOURCC('m','4','c','c')
-#define FOURCC_M4CC         VLC_FOURCC('M','4','C','C')
-
-/* MSMPEG4 v2 */
-#define FOURCC_MPG4         VLC_FOURCC('M','P','G','4')
-#define FOURCC_mpg4         VLC_FOURCC('m','p','g','4')
-#define FOURCC_DIV2         VLC_FOURCC('D','I','V','2')
-#define FOURCC_div2         VLC_FOURCC('d','i','v','2')
-#define FOURCC_MP42         VLC_FOURCC('M','P','4','2')
-#define FOURCC_mp42         VLC_FOURCC('m','p','4','2')
-
-/* MSMPEG4 v3 / M$ mpeg4 v3 */
-#define FOURCC_MPG3         VLC_FOURCC('M','P','G','3')
-#define FOURCC_mpg3         VLC_FOURCC('m','p','g','3')
-#define FOURCC_div3         VLC_FOURCC('d','i','v','3')
-#define FOURCC_MP43         VLC_FOURCC('M','P','4','3')
-#define FOURCC_mp43         VLC_FOURCC('m','p','4','3')
-
-/* DivX 3.20 */
-#define FOURCC_DIV3         VLC_FOURCC('D','I','V','3')
-#define FOURCC_DIV4         VLC_FOURCC('D','I','V','4')
-#define FOURCC_div4         VLC_FOURCC('d','i','v','4')
-#define FOURCC_DIV5         VLC_FOURCC('D','I','V','5')
-#define FOURCC_div5         VLC_FOURCC('d','i','v','5')
-#define FOURCC_DIV6         VLC_FOURCC('D','I','V','6')
-#define FOURCC_div6         VLC_FOURCC('d','i','v','6')
-
-/* AngelPotion stuff */
-#define FOURCC_AP41         VLC_FOURCC('A','P','4','1')
-
-/* 3ivx doctered divx files */
-#define FOURCC_3IVD         VLC_FOURCC('3','I','V','D')
-#define FOURCC_3ivd         VLC_FOURCC('3','i','v','d')
-
-/* 3ivx delta 3.5 Unsupported */
-#define FOURCC_3IV1         VLC_FOURCC('3','I','V','1')
-#define FOURCC_3iv1         VLC_FOURCC('3','i','v','1')
-
-/* 3ivx delta 4 */
-#define FOURCC_3IV2         VLC_FOURCC('3','I','V','2')
-#define FOURCC_3iv2         VLC_FOURCC('3','i','v','2')
-
-/* who knows? */
-#define FOURCC_3VID         VLC_FOURCC('3','V','I','D')
-#define FOURCC_3vid         VLC_FOURCC('3','v','i','d')
-
-/* H263 and H263i */
-/* H263(+) is also known as Real Video 1.0 */
-#define FOURCC_H263         VLC_FOURCC('H','2','6','3')
-#define FOURCC_h263         VLC_FOURCC('h','2','6','3')
-#define FOURCC_U263         VLC_FOURCC('U','2','6','3')
-#define FOURCC_I263         VLC_FOURCC('I','2','6','3')
-#define FOURCC_i263         VLC_FOURCC('i','2','6','3')
-/* Flash (H263) variant */
-#define FOURCC_FLV1         VLC_FOURCC('F','L','V','1')
-
-
-/* Sorenson v1/3 */
-#define FOURCC_SVQ1         VLC_FOURCC('S','V','Q','1')
-#define FOURCC_SVQ3         VLC_FOURCC('S','V','Q','3')
-
-/* mjpeg */
-#define FOURCC_MJPG         VLC_FOURCC( 'M', 'J', 'P', 'G' )
-#define FOURCC_mjpg         VLC_FOURCC( 'm', 'j', 'p', 'g' )
-    /* for mov file */
-#define FOURCC_mjpa         VLC_FOURCC( 'm', 'j', 'p', 'a' )
-    /* for mov file XXX: untested */
-#define FOURCC_mjpb         VLC_FOURCC( 'm', 'j', 'p', 'b' )
-
-#define FOURCC_jpeg         VLC_FOURCC( 'j', 'p', 'e', 'g' )
-#define FOURCC_JPEG         VLC_FOURCC( 'J', 'P', 'E', 'G' )
-#define FOURCC_JFIF         VLC_FOURCC( 'J', 'F', 'I', 'F' )
-#define FOURCC_JPGL         VLC_FOURCC( 'J', 'P', 'G', 'L' )
-
-/* Microsoft Video 1 */
-#define FOURCC_MSVC         VLC_FOURCC('M','S','V','C')
-#define FOURCC_msvc         VLC_FOURCC('m','s','v','c')
-#define FOURCC_CRAM         VLC_FOURCC('C','R','A','M')
-#define FOURCC_cram         VLC_FOURCC('c','r','a','m')
-#define FOURCC_WHAM         VLC_FOURCC('W','H','A','M')
-#define FOURCC_wham         VLC_FOURCC('w','h','a','m')
-
-/* Windows Screen Video */
-#define FOURCC_MSS1         VLC_FOURCC('M','S','S','1')
-
-/* Microsoft RLE */
-#define FOURCC_mrle         VLC_FOURCC('m','r','l','e')
-#define FOURCC_1000         VLC_FOURCC(0x1,0x0,0x0,0x0)
-
-/* Windows Media Video */
-#define FOURCC_WMV1         VLC_FOURCC('W','M','V','1')
-#define FOURCC_WMV2         VLC_FOURCC('W','M','V','2')
-
-/* DV */
-#define FOURCC_dvsl         VLC_FOURCC('d','v','s','l')
-#define FOURCC_dvsd         VLC_FOURCC('d','v','s','d')
-#define FOURCC_DVSD         VLC_FOURCC('D','V','S','D')
-#define FOURCC_dvhd         VLC_FOURCC('d','v','h','d')
-#define FOURCC_dvc          VLC_FOURCC('d','v','c',' ')
-#define FOURCC_dvp          VLC_FOURCC('d','v','p',' ')
-#define FOURCC_CDVC         VLC_FOURCC('C','D','V','C')
-
-/* Indeo Video Codecs */
-#define FOURCC_IV31         VLC_FOURCC('I','V','3','1')
-#define FOURCC_iv31         VLC_FOURCC('i','v','3','1')
-#define FOURCC_IV32         VLC_FOURCC('I','V','3','2')
-#define FOURCC_iv32         VLC_FOURCC('i','v','3','2')
-
-/* On2 VP3 Video Codecs */
-#define FOURCC_VP31         VLC_FOURCC('V','P','3','1')
-#define FOURCC_vp31         VLC_FOURCC('v','p','3','1')
-
-/* Asus Video */
-#define FOURCC_ASV1         VLC_FOURCC('A','S','V','1')
-#define FOURCC_ASV2         VLC_FOURCC('A','S','V','2')
-
-/* ATI VCR1 */
-#define FOURCC_VCR1         VLC_FOURCC('V','C','R','1')
-
-/* FFMPEG Video 1 (lossless codec) */
-#define FOURCC_FFV1         VLC_FOURCC('F','F','V','1')
-
-/* Cirrus Logic AccuPak */
-#define FOURCC_CLJR         VLC_FOURCC('C','L','J','R')
-
-/* Creative YUV */
-#define FOURCC_CYUV         VLC_FOURCC('C','Y','U','V')
-
-/* Huff YUV */
-#define FOURCC_HFYU         VLC_FOURCC('H','F','Y','U')
-
-/* Apple Video */
-#define FOURCC_rpza         VLC_FOURCC('r','p','z','a')
-
-/* Cinepak */
-#define FOURCC_cvid         VLC_FOURCC('c','v','i','d')
+/* Audio decoder module */
+int  E_( InitAudioDec )( decoder_t *, AVCodecContext *, AVCodec *,
+                         int, char * );
+void E_( EndAudioDec ) ( decoder_t * );
+int  E_( DecodeAudio ) ( decoder_t *, block_t * );
 
+/* Chroma conversion module */
+int  E_(OpenChroma)( vlc_object_t * );
 
-/*****************************************************************************
- * Audio codec fourcc
- *****************************************************************************/
-#define FOURCC_WMA1         VLC_FOURCC('W','M','A','1')
-#define FOURCC_wma1         VLC_FOURCC('w','m','a','1')
-#define FOURCC_WMA2         VLC_FOURCC('W','M','A','2')
-#define FOURCC_wma2         VLC_FOURCC('w','m','a','2')
-#define FOURCC_dvau         VLC_FOURCC('d','v','a','u')
+/* Video encoder module */
+int  E_(OpenVideoEncoder) ( vlc_object_t * );
+void E_(CloseVideoEncoder)( vlc_object_t * );
 
-#define FOURCC_MAC3         VLC_FOURCC('M','A','C','3')
-#define FOURCC_MAC6         VLC_FOURCC('M','A','C','6')
+/* Audio encoder module */
+int  E_(OpenAudioEncoder) ( vlc_object_t * );
+void E_(CloseAudioEncoder)( vlc_object_t * );
 
-#define FOURCC_RA10         VLC_FOURCC('1','4','_','4')
-#define FOURCC_RA20         VLC_FOURCC('2','8','_','8')
+/* Postprocessing module */
+int E_(OpenPostproc)( decoder_t *, void ** );
+int E_(InitPostproc)( decoder_t *, void *, int, int, int );
+int E_(PostprocPict)( decoder_t *, void *, picture_t *, AVFrame * );
+void E_(ClosePostproc)( decoder_t *, void * );
 
+/*****************************************************************************
+ * Module descriptor help strings
+ *****************************************************************************/
+#define DR_TEXT N_("Direct rendering")
+
+#define ERROR_TEXT N_("Error resilience")
+#define ERROR_LONGTEXT N_( \
+    "ffmpeg can make errors resiliences.          \n" \
+    "Nevertheless, with a buggy encoder (like ISO MPEG-4 encoder from M$) " \
+    "this will produce a lot of errors.\n" \
+    "Valid range is -1 to 99 (-1 disables all errors resiliences).")
+
+#define BUGS_TEXT N_("Workaround bugs")
+#define BUGS_LONGTEXT N_( \
+    "Try to fix some bugs\n" \
+    "1  autodetect\n" \
+    "2  old msmpeg4\n" \
+    "4  xvid interlaced\n" \
+    "8  ump4 \n" \
+    "16 no padding\n" \
+    "32 ac vlc\n" \
+    "64 Qpel chroma")
+
+#define HURRYUP_TEXT N_("Hurry up")
+#define HURRYUP_LONGTEXT N_( \
+    "Allow the decoder to partially decode or skip frame(s) " \
+    "when there is not enough time. It's useful with low CPU power " \
+    "but it can produce distorted pictures.")
+
+#define TRUNC_TEXT N_("Truncated stream")
+#define TRUNC_LONGTEXT N_("truncated stream -1:auto,0:disable,:1:enable")
+
+#define PP_Q_TEXT N_("Post processing quality")
+#define PP_Q_LONGTEXT N_( \
+    "Quality of post processing. Valid range is 0 to 6\n" \
+    "Higher levels require considerable more CPU power, but produce " \
+    "better looking pictures." )
+
+#define LIBAVCODEC_PP_TEXT N_("Ffmpeg postproc filter chains")
+/* FIXME (cut/past from ffmpeg */
+#define LIBAVCODEC_PP_LONGTEXT \
+"<filterName>[:<option>[:<option>...]][[,|/][-]<filterName>[:<option>...]]...\n" \
+"long form example:\n" \
+"vdeblock:autoq/hdeblock:autoq/linblenddeint    default,-vdeblock\n" \
+"short form example:\n" \
+"vb:a/hb:a/lb de,-vb\n" \
+"more examples:\n" \
+"tn:64:128:256\n" \
+"Filters                        Options\n" \
+"short  long name       short   long option     Description\n" \
+"*      *               a       autoq           cpu power dependant enabler\n" \
+"                       c       chrom           chrominance filtring enabled\n" \
+"                       y       nochrom         chrominance filtring disabled\n" \
+"hb     hdeblock        (2 Threshold)           horizontal deblocking filter\n" \
+"       1. difference factor: default=64, higher -> more deblocking\n" \
+"       2. flatness threshold: default=40, lower -> more deblocking\n" \
+"                       the h & v deblocking filters share these\n" \
+"                       so u cant set different thresholds for h / v\n" \
+"vb     vdeblock        (2 Threshold)           vertical deblocking filter\n" \
+"h1     x1hdeblock                              Experimental h deblock filter 1\n" \
+"v1     x1vdeblock                              Experimental v deblock filter 1\n" \
+"dr     dering                                  Deringing filter\n" \
+"al     autolevels                              automatic brightness / contrast\n" \
+"                       f       fullyrange      stretch luminance to (0..255)\n" \
+"lb     linblenddeint                           linear blend deinterlacer\n" \
+"li     linipoldeint                            linear interpolating deinterlace\n" \
+"ci     cubicipoldeint                          cubic interpolating deinterlacer\n" \
+"md     mediandeint                             median deinterlacer\n" \
+"fd     ffmpegdeint                             ffmpeg deinterlacer\n" \
+"de     default                                 hb:a,vb:a,dr:a,al\n" \
+"fa     fast                                    h1:a,v1:a,dr:a,al\n" \
+"tn     tmpnoise        (3 Thresholds)          Temporal Noise Reducer\n" \
+"                       1. <= 2. <= 3.          larger -> stronger filtering\n" \
+"fq     forceQuant      <quantizer>             Force quantizer\n"
diff --git a/modules/codec/ffmpeg/postprocess.c b/modules/codec/ffmpeg/postprocess.c
new file mode 100644 (file)
index 0000000..07dcf68
--- /dev/null
@@ -0,0 +1,202 @@
+/*****************************************************************************
+ * postprocess.c: video postprocessing using the ffmpeg library
+ *****************************************************************************
+ * Copyright (C) 1999-2001 VideoLAN
+ * $Id: postprocess.c,v 1.1 2003/10/27 01:04:38 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *****************************************************************************/
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/vout.h>
+#include <vlc/decoder.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
+
+/*****************************************************************************
+ * video_postproc_sys_t : ffmpeg video postprocessing descriptor
+ *****************************************************************************/
+typedef struct video_postproc_sys_t
+{
+    pp_context_t *pp_context;
+    pp_mode_t    *pp_mode;
+
+    int i_width;
+    int i_height;
+
+} video_postproc_sys_t;
+
+/*****************************************************************************
+ * OpenPostproc: probe and open the postproc
+ *****************************************************************************/
+int E_(OpenPostproc)( decoder_t *p_dec, void **pp_data )
+{
+    video_postproc_sys_t **pp_sys = (video_postproc_sys_t **)pp_data;
+    pp_mode_t *pp_mode;
+    vlc_value_t val;
+
+    /* ***** Load post processing if enabled ***** */
+    var_Create( p_dec, "ffmpeg-pp-q", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
+    var_Get( p_dec, "ffmpeg-pp-q", &val );
+    if( val.i_int > 0 )
+    {
+        int  i_quality = val.i_int;
+        char *psz_name = config_GetPsz( p_dec, "ffmpeg-pp-name" );
+
+        if( !psz_name )
+        {
+            psz_name = strdup( "default" );
+        }
+        else if( *psz_name == '\0' )
+        {
+            free( psz_name );
+            psz_name = strdup( "default" );
+        }
+
+        pp_mode = pp_get_mode_by_name_and_quality( psz_name, i_quality );
+
+        if( !pp_mode )
+        {
+            msg_Err( p_dec, "failed geting mode for postproc" );
+        }
+        else
+        {
+            msg_Info( p_dec, "postprocessing activated" );
+        }
+        free( psz_name );
+
+        *pp_sys = malloc( sizeof(video_postproc_sys_t) );
+        (*pp_sys)->pp_context = NULL;
+        (*pp_sys)->pp_mode    = NULL;
+
+        return VLC_SUCCESS;
+    }
+    else
+    {
+        msg_Dbg( p_dec, "no postprocessing enabled" );
+        return VLC_EGENERIC;
+    }
+}
+
+/*****************************************************************************
+ * InitPostproc: 
+ *****************************************************************************/
+int E_(InitPostproc)( decoder_t *p_dec, void *p_data,
+                      int i_width, int i_height, int pix_fmt )
+{
+    video_postproc_sys_t *p_sys = (video_postproc_sys_t *)p_data;
+    int32_t i_cpu = p_dec->p_libvlc->i_cpu;
+    int i_flags = 0;
+
+    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 )
+    {
+        i_flags |= PP_CPU_CAPS_3DNOW;
+    }
+
+    switch( 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;
+    }
+
+    p_sys->pp_context = pp_get_context( i_width, i_height, i_flags );
+    p_sys->i_width = i_width;
+    p_sys->i_height = i_height;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * PostprocPict: 
+ *****************************************************************************/
+int E_(PostprocPict)( decoder_t *p_dec, void *p_data,
+                      picture_t *p_pic, AVFrame *p_ff_pic )
+{
+    video_postproc_sys_t *p_sys = (video_postproc_sys_t *)p_data;
+
+    uint8_t *src[3], *dst[3];
+    int i_plane, 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_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_sys->i_width, p_sys->i_height,
+                    p_ff_pic->qscale_table, p_ff_pic->qstride,
+                    p_sys->pp_mode, p_sys->pp_context,
+                    p_ff_pic->pict_type );
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * ClosePostproc: 
+ *****************************************************************************/
+void E_(ClosePostproc)( decoder_t *p_dec, void *p_data )
+{
+    video_postproc_sys_t *p_sys = (video_postproc_sys_t *)p_data;
+
+    if( p_sys && p_sys->pp_mode )
+    {
+        pp_free_mode( p_sys->pp_mode );
+        if( p_sys->pp_context ) pp_free_context( p_sys->pp_context );
+    }
+}
+
+#endif /* LIBAVCODEC_PP */
index efaf4f2307f30811ea1ff1706a49f90a090ec53e..cbe9d210ca32f6b185c623f9f441e7c70af09da6 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- * 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.41 2003/10/21 18:33:53 gbazin Exp $
+ * $Id: video.c,v 1.42 2003/10/27 01:04:38 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Gildas Bazin <gbazin@netcourrier.com>
  * Preamble
  *****************************************************************************/
 #include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>
 
 #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 "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
+{
+    /* Common part between video and audio decoder */
+    int i_cat;
+    int i_codec_id;
+    char *psz_namecodec;
+
+    AVCodecContext      *p_context;
+    AVCodec             *p_codec;
+
+    /* Video decoder specific part */
+    mtime_t input_pts;
+    mtime_t i_pts;
+
+    AVFrame          *p_ff_pic;
+    BITMAPINFOHEADER *p_format;
 
-#include "video.h"
+    vout_thread_t    *p_vout;
 
+    /* for frame skipping algo */
+    int b_hurry_up;
+    int i_frame_error;
+    int i_frame_skip;
+
+    /* 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;
+
+    int i_buffer;
+    char *p_buffer;
+
+    /* Postprocessing handle */
+    void *p_pp;
+};
 
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static void ffmpeg_CopyPicture( picture_t *, AVFrame *, vdec_thread_t * );
-
-static int  ffmpeg_GetFrameBuf      ( struct AVCodecContext *, AVFrame * );
-static void ffmpeg_ReleaseFrameBuf  ( struct AVCodecContext *, AVFrame * );
+static void ffmpeg_CopyPicture    ( decoder_t *, picture_t *, AVFrame * );
+static int  ffmpeg_GetFrameBuf    ( struct AVCodecContext *, AVFrame * );
+static void ffmpeg_ReleaseFrameBuf( struct AVCodecContext *, AVFrame * );
 
 /*****************************************************************************
  * Local Functions
@@ -77,26 +104,25 @@ static inline 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_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_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_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;
     }
 }
 
 /* Return a Vout */
-static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t  *p_vdec,
+static vout_thread_t *ffmpeg_CreateVout( decoder_t  *p_dec,
                                          AVCodecContext *p_context )
 {
     vout_thread_t *p_vout;
@@ -129,622 +155,445 @@ static vout_thread_t *ffmpeg_CreateVout( vdec_thread_t  *p_vdec,
 
     /* 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,
+    p_vout = vout_Request( p_dec, p_dec->p_sys->p_vout,
                            i_width, i_height, i_chroma, i_aspect );
-#ifdef LIBAVCODEC_PP
-    if( p_vdec->pp_mode && !p_vdec->pp_context )
-    {
-        int32_t i_cpu = p_vdec->p_fifo->p_libvlc->i_cpu;
-        int i_flags = 0;
-
-        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 )
-        {
-            i_flags |= PP_CPU_CAPS_3DNOW;
-        }
-
-        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;
-        }
 
-        p_vdec->pp_context = pp_get_context( i_width, i_height, i_flags );
-    }
+#ifdef LIBAVCODEC_PP
+    if( p_dec->p_sys->p_pp )
+        E_(InitPostproc)( p_dec, p_dec->p_sys->p_pp, i_width, i_height,
+                          p_context->pix_fmt );
 #endif
 
     return p_vout;
 }
 
 /*****************************************************************************
- *
- * 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 )
-{
-    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 E_(InitVideoDec)( decoder_t *p_dec, AVCodecContext *p_context,
+                      AVCodec *p_codec, int i_codec_id, char *psz_namecodec )
 {
+    decoder_sys_t *p_sys;
+    vlc_value_t val;
     int i_tmp;
-    int i_truncated;
 
-    p_vdec->p_ff_pic = avcodec_alloc_frame();
+    /* Allocate the memory needed to store the decoder's structure */
+    if( ( p_dec->p_sys = p_sys =
+          (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
+    {
+        msg_Err( p_dec, "out of memory" );
+        return VLC_EGENERIC;
+    }
+
+    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();
 
-    if( ( p_vdec->p_format =
-          (BITMAPINFOHEADER *)p_vdec->p_fifo->p_bitmapinfoheader ) != NULL )
+    if( ( p_sys->p_format =
+          (BITMAPINFOHEADER *)p_dec->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;
+        p_sys->p_context->width  = p_sys->p_format->biWidth;
+        p_sys->p_context->height = p_sys->p_format->biHeight;
     }
     else
     {
-        msg_Warn( p_vdec->p_fifo, "display informations missing" );
-        p_vdec->p_format = NULL;
+        msg_Warn( p_dec, "display informations missing" );
+        p_sys->p_format = NULL;
     }
 
     /*  ***** 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_dec, "ffmpeg-workaround-bugs" );
+    p_sys->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 );
+    i_tmp = config_GetInt( p_dec, "ffmpeg-error-resilience" );
+    p_sys->p_context->error_resilience = __MAX( __MIN( i_tmp, 99 ), -1 );
 
-    if( config_GetInt( p_vdec->p_fifo, "grayscale" ) )
-    {
-        p_vdec->p_context->flags|= CODEC_FLAG_GRAY;
-    }
-
-    p_vdec->b_hurry_up = config_GetInt(p_vdec->p_fifo, "ffmpeg-hurry-up");
+    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;
 
-    /* CODEC_FLAG_TRUNCATED */
-
-    /* FIXME search real LIBAVCODEC_BUILD */
+    /* Decide if we set CODEC_FLAG_TRUNCATED */
 #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;
-    }
+    var_Create( p_dec, "ffmpeg-truncated", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
+    var_Get( p_dec, "ffmpeg-truncated", &val );
+    if( val.i_int > 0 ) p_sys->p_context->flags |= CODEC_FLAG_TRUNCATED;
 #endif
 
     /* ***** Open the codec ***** */
-    if( avcodec_open(p_vdec->p_context, p_vdec->p_codec) < 0 )
+    if( avcodec_open( p_sys->p_context, p_sys->p_codec ) < 0 )
     {
-        msg_Err( p_vdec->p_fifo, "cannot open codec (%s)",
-                                 p_vdec->psz_namecodec );
-        return( VLC_EGENERIC );
+        msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec );
+        return VLC_EGENERIC;
     }
     else
     {
-        msg_Dbg( p_vdec->p_fifo, "ffmpeg codec (%s) started",
-                                 p_vdec->psz_namecodec );
+        msg_Dbg( p_dec, "ffmpeg codec (%s) started", p_sys->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 ) &&
+    /* ***** 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;
+
+    /* ***** ffmpeg direct rendering ***** */
+    p_sys->b_direct_rendering = 0;
+    var_Create( p_dec, "ffmpeg-dr", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+    var_Get( p_dec, "ffmpeg-dr", &val );
+    if( val.b_bool && (p_sys->p_codec->capabilities & CODEC_CAP_DR1) &&
+        ffmpeg_PixFmtToChroma( p_sys->p_context->pix_fmt ) &&
         /* Apparently direct rendering doesn't work with YUV422P */
-        p_vdec->p_context->pix_fmt != PIX_FMT_YUV422P &&
-        !(p_vdec->p_context->width % 16) && !(p_vdec->p_context->height % 16) )
+        p_sys->p_context->pix_fmt != PIX_FMT_YUV422P &&
+        !(p_sys->p_context->width % 16) && !(p_sys->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;
+        p_sys->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 )
+    if( E_(OpenPostproc)( p_dec, &p_sys->p_pp ) == VLC_SUCCESS )
     {
-        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" );
+        p_sys->b_direct_rendering = 0;
     }
 #endif
 
     /* ffmpeg doesn't properly release old pictures when frames are skipped */
-    if( p_vdec->b_hurry_up ) p_vdec->b_direct_rendering = 0;
+    if( p_sys->b_hurry_up ) p_sys->b_direct_rendering = 0;
+    if( p_sys->b_direct_rendering )
+    {
+        msg_Dbg( p_dec, "using direct rendering" );
+        p_sys->p_context->flags |= CODEC_FLAG_EMU_EDGE;
+    }
 
     /* 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;
-    }
+    p_sys->p_context->get_buffer = ffmpeg_GetFrameBuf;
+    p_sys->p_context->release_buffer = ffmpeg_ReleaseFrameBuf;
+    p_sys->p_context->opaque = p_dec;
 
     /* ***** init this codec with special data ***** */
-    if( p_vdec->p_format &&
-            p_vdec->p_format->biSize > sizeof(BITMAPINFOHEADER) )
+    if( p_sys->p_format && p_sys->p_format->biSize > sizeof(BITMAPINFOHEADER) )
     {
         int b_gotpicture;
-        int i_size = p_vdec->p_format->biSize - sizeof(BITMAPINFOHEADER);
+        int i_size = p_sys->p_format->biSize - sizeof(BITMAPINFOHEADER);
 
-        if( p_vdec->i_codec_id == CODEC_ID_MPEG4 )
+        if( p_sys->i_codec_id == CODEC_ID_MPEG4 )
         {
             uint8_t *p_vol = malloc( i_size + FF_INPUT_BUFFER_PADDING_SIZE );
 
-            memcpy( p_vol, &p_vdec->p_format[1], i_size );
+            memcpy( p_vol, &p_sys->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 );
+            avcodec_decode_video( p_sys->p_context, p_sys->p_ff_pic,
+                                  &b_gotpicture, p_vol, i_size );
             free( p_vol );
         }
 #if LIBAVCODEC_BUILD >= 4666
-        else if( p_vdec->i_codec_id == CODEC_ID_SVQ3 )
+        else if( p_sys->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 );
+            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_vdec->p_format[1], i_size );
+            memcpy( &p[12], &p_sys->p_format[1], i_size );
         }
 #endif
         else
         {
-            p_vdec->p_context->extradata_size = i_size;
-            p_vdec->p_context->extradata =
+            p_sys->p_context->extradata_size = i_size;
+            p_sys->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],
+            memcpy( p_sys->p_context->extradata,
+                    &p_sys->p_format[1], i_size );
+            memset( &((uint8_t*)p_sys->p_context->extradata)[i_size],
                     0, FF_INPUT_BUFFER_PADDING_SIZE );
         }
     }
-    p_vdec->p_vout = NULL;
-
-    p_vdec->input_pts_previous = 0;
-    p_vdec->input_pts = 0;
 
-    p_vdec->b_has_b_frames = VLC_FALSE;
+    /* ***** misc init ***** */
+    p_sys->p_vout = NULL;
+    p_sys->input_pts = 0;
+    p_sys->i_pts = 0;
+    p_sys->b_has_b_frames = VLC_FALSE;
+    p_sys->i_late_frames = 0;
+    p_sys->i_buffer = 1;
+    p_sys->p_buffer = malloc( p_sys->i_buffer );
+    p_sys->p_pp = NULL;
 
-    return( VLC_SUCCESS );
+    return VLC_SUCCESS;
 }
 
 /*****************************************************************************
- * 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.
+ * DecodeVideo: Called to decode one or more frames
  *****************************************************************************/
-void  E_( DecodeThread_Video )( vdec_thread_t *p_vdec )
+int E_(DecodeVideo)( decoder_t *p_dec, block_t *p_block )
 {
-    pes_packet_t    *p_pes;
-    int     i_frame_size;
-    int     i_used;
-    int     b_drawpicture;
-    int     b_gotpicture;
-    picture_t *p_pic;                                         /* vlc picture */
+    decoder_sys_t *p_sys = p_dec->p_sys;
+    int i_buffer, b_drawpicture;
+    char *p_buffer;
+
+    if( p_block->i_pts > 0 )
+    {
+        p_sys->input_pts = p_block->i_pts;
+    }
 
     /* 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_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->hurry_up = 2;
         }
         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 );
+            return VLC_SUCCESS;
         }
     }
     else
     {
         b_drawpicture = 1;
-        p_vdec->p_context->hurry_up = 0;
+        p_sys->p_context->hurry_up = 0;
     }
 
-    if( p_vdec->i_frame_late > 0 &&
-        mdate() - p_vdec->i_frame_late_start > (mtime_t)5000000 )
+    if( p_sys->i_late_frames > 0 &&
+        mdate() - p_sys->i_late_frames_start > I64C(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 );
+        msg_Err( p_dec, "more than 5 seconds of late video -> "
+                 "dropping frame (computer too slow ?)" );
+        block_Release( p_block );
+        p_sys->i_pts = 0; /* To make sure we recover properly */
+        p_sys->i_late_frames--;
+        return VLC_SUCCESS;
+    }
 
-        } while( p_vdec->input_pts <= 0 || p_vdec->input_pts < mdate() );
+    if( !p_sys->p_context->width || !p_sys->p_context->height )
+    {
+        p_sys->p_context->hurry_up = 5;
     }
 
-    if( !p_vdec->p_context->width || !p_vdec->p_context->height )
+    /*
+     * Do the actual decoding now
+     */
+
+    /* Don't forget that ffmpeg requires a little more bytes
+     * that the real frame size */
+    i_buffer = p_block->i_buffer;
+    if( i_buffer + FF_INPUT_BUFFER_PADDING_SIZE > p_sys->i_buffer )
     {
-        p_vdec->p_context->hurry_up = 5;
+        free( p_sys->p_buffer );
+        p_sys->p_buffer = malloc( i_buffer + FF_INPUT_BUFFER_PADDING_SIZE );
     }
+    p_buffer = p_sys->p_buffer;
+    p_dec->p_vlc->pf_memcpy( p_buffer, p_block->p_buffer, p_block->i_buffer );
+    memset( p_buffer + i_buffer, 0, FF_INPUT_BUFFER_PADDING_SIZE );
 
-    do
+    while( i_buffer )
     {
-        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,
+                                       p_buffer, i_buffer );
+        if( i_used < 0 )
         {
-            p_vdec->p_fifo->b_error = 1;
-            return;
+            msg_Warn( p_dec, "cannot decode one frame (%d bytes)", i_buffer );
+            p_sys->i_frame_error++;
+            block_Release( p_block );
+            return VLC_SUCCESS;
         }
 
-        if( p_pes->i_pts > 0 )
+        /* Consumed bytes */
+        i_buffer -= i_used;
+        p_buffer += i_used;
+
+        /* Nothing to display */
+        if( !b_gotpicture ) continue;
+
+        /* Update frame late count*/
+        if( p_sys->i_pts && p_sys->i_pts <= mdate() )
+        {
+            p_sys->i_late_frames++;
+            if( p_sys->i_late_frames == 1 )
+                p_sys->i_late_frames_start = mdate();
+        }
+        else
         {
-            p_vdec->input_pts_previous = p_vdec->input_pts;
-            p_vdec->input_pts = p_pes->i_pts;
+            p_sys->i_late_frames = 0;
         }
 
-        i_frame_size = p_pes->i_pes_size;
+        if( !b_drawpicture || p_sys->p_ff_pic->linesize[0] == 0 )
+        {
+            /* Do not display the picture */
+            continue;
+        }
 
-        if( i_frame_size > 0 )
+        if( !p_sys->b_direct_rendering )
         {
-            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_sys->p_vout = ffmpeg_CreateVout( p_dec, p_sys->p_context );
+            if( !p_sys->p_vout )
+            {
+                msg_Err( p_dec, "cannot create vout" );
+                block_Release( p_block );
+                return VLC_EGENERIC;
+            }
+
+            /* Get a new picture */
+            while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) )
             {
-                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 )
+                if( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error )
                 {
-                    memcpy( p_vdec->p_buffer, p_last, p_vdec->i_buffer );
+                    block_Release( p_block );
+                    return VLC_EGENERIC;
                 }
-                FREE( p_last );
+                msleep( VOUT_OUTMEM_SLEEP );
             }
-            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 );
-        }
-
-        input_DeletePES( p_vdec->p_fifo->p_packets_mgt, p_pes );
-
-    } while( i_frame_size <= 0 );
-
-    i_frame_size += p_vdec->i_buffer;
-
-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;
-
-#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 );
 
-        p_vdec->i_buffer = i_frame_size - i_used;
-    }
-    else
-    {
-        p_vdec->i_buffer = 0;
-    }
-
-    /* consumed bytes */
-    i_frame_size -= i_used;
-
-   /* 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;
-    }
 
-    if( !p_vdec->b_direct_rendering )
-    {
-        p_vdec->p_vout = ffmpeg_CreateVout( p_vdec, p_vdec->p_context );
-        if( !p_vdec->p_vout )
+        /* 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_sys->p_ff_pic->pict_type == FF_B_TYPE )
+            p_sys->b_has_b_frames = VLC_TRUE;
+        if( p_sys->p_ff_pic->pts &&
+            ( !p_sys->p_context->has_b_frames || !p_sys->b_has_b_frames ||
+              p_sys->p_ff_pic->pict_type == FF_B_TYPE ) )
         {
-            msg_Err( p_vdec->p_fifo, "cannot create vout" );
-            p_vdec->p_fifo->b_error = 1; /* abort */
-            return;
+            p_sys->i_pts = p_sys->p_ff_pic->pts;
         }
 
-        /* Get a new picture */
-        while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
+        /* Send decoded frame to vout */
+        if( p_sys->i_pts )
         {
-            if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
+            vout_DatePicture( p_sys->p_vout, p_pic, p_sys->i_pts );
+            vout_DisplayPicture( p_sys->p_vout, p_pic );
+
+            /* interpolate the next PTS */
+            if( p_sys->p_context->frame_rate > 0 )
             {
-                return;
+                p_sys->i_pts += I64C(1000000) *
+                    (2 + p_sys->p_ff_pic->repeat_pict) *
+                    p_sys->p_context->frame_rate_base /
+                    (2 * p_sys->p_context->frame_rate);
             }
-            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;
     }
 
-    /* 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;
-    }
-
-    if( p_vdec->pts <= 0 )
-    {
-        p_vdec->pts = mdate() + DEFAULT_PTS_DELAY;  // FIXME
-    }
-
-    /* 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 */
-    }
+    block_Release( p_block );
+    return VLC_SUCCESS;
 }
 
 /*****************************************************************************
- * EndThread: thread destruction
+ * EndVideo: decoder destruction
  *****************************************************************************
  * This function is called when the thread ends after a sucessful
  * 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 ) free( p_sys->p_ff_pic );
 
 #ifdef LIBAVCODEC_PP
-    if( p_vdec->pp_mode )
-    {
-        pp_free_mode( p_vdec->pp_mode );
-        if( p_vdec->pp_context )
-        {
-            pp_free_context( p_vdec->pp_context );
-        }
-    }
+    E_(ClosePostproc)( p_dec, p_sys->p_pp );
 #endif
 
-    if( p_vdec->p_ff_pic )
-    {
-        free( p_vdec->p_ff_pic );
-    }
+    free( p_sys->p_buffer );
 
     /* 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 );
+    vout_Request( p_dec, p_sys->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;
-
-    uint8_t *p_dst;
-    uint8_t *p_src;
-    int i_src_stride;
-    int i_dst_stride;
+    decoder_sys_t *p_sys = p_dec->p_sys;
 
-    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];
-
-            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;
+        if( p_sys->p_pp )
+            E_(PostprocPict)( p_dec, p_sys->p_pp, p_pic, p_ff_pic );
+#else
+        int i_plane, i_size, i_line;
+        uint8_t *p_dst, *p_src;
+        int i_src_stride, i_dst_stride;
 
-                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
+        for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
         {
-#endif
-            for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
-            {
-                p_src  = p_ff_pic->data[i_plane];
-                p_dst = p_pic->p[i_plane].p_pixels;
-                i_src_stride = p_ff_pic->linesize[i_plane];
-                i_dst_stride = p_pic->p[i_plane].i_pitch;
+            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;
-                }
+            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_dec->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
     {
+        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 ):
+            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_sys->p_context->pix_fmt,
+                         p_sys->p_context->width,
+                         p_sys->p_context->height );
+            break;
+        default:
+            msg_Err( p_dec, "don't know how to convert chroma %i",
+                     p_sys->p_context->pix_fmt );
+            p_dec->p_fifo->b_error = 1;
+            break;
         }
     }
 }
@@ -758,23 +607,16 @@ 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 )
-    {
-        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;
-    }
+    p_ff_pic->pts = p_sys->input_pts;
+    p_sys->input_pts = 0;
 
     /* Not much to do in indirect rendering mode */
-    if( !p_vdec->b_direct_rendering )
+    if( !p_sys->b_direct_rendering )
     {
         return avcodec_default_get_buffer( p_context, p_ff_pic );
     }
@@ -782,36 +624,36 @@ 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 )
+        p_sys->p_context->width % 16 || p_sys->p_context->height % 16 )
     {
-        msg_Dbg( p_vdec->p_fifo, "disabling direct rendering" );
-        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 );
     }
 
     /* 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_vout = ffmpeg_CreateVout( p_dec, p_sys->p_context );
+    if( !p_sys->p_vout )
     {
-        msg_Err( p_vdec->p_fifo, "cannot create vout" );
-        p_vdec->p_fifo->b_error = 1; /* abort */
-        p_vdec->b_direct_rendering = 0;
+        msg_Err( p_dec, "cannot create vout" );
+        p_dec->p_fifo->b_error = 1; /* abort */
+        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;
+    p_sys->p_vout->render.b_allow_modify_pics = 0;
 
     /* Get a new picture */
-    while( !(p_pic = vout_CreatePicture( p_vdec->p_vout, 0, 0, 0 ) ) )
+    while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) )
     {
-        if( p_vdec->p_fifo->b_die || p_vdec->p_fifo->b_error )
+        if( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error )
         {
-            p_vdec->b_direct_rendering = 0;
+            p_sys->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_sys->p_context->draw_horiz_band = NULL;
 
     p_ff_pic->opaque = (void*)p_pic;
     p_ff_pic->type = FF_BUFFER_TYPE_USER;
@@ -827,8 +669,9 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
 
     if( p_ff_pic->reference != 0 )
     {
-        vout_LinkPicture( p_vdec->p_vout, p_pic );
+        vout_LinkPicture( p_sys->p_vout, p_pic );
     }
+
     /* FIXME what is that, should give good value */
     p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg
 
@@ -838,7 +681,8 @@ static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
 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;
+    decoder_sys_t *p_sys = p_dec->p_sys;
     picture_t *p_pic;
 
     if( p_ff_pic->type != FF_BUFFER_TYPE_USER )
@@ -856,6 +700,6 @@ static void  ffmpeg_ReleaseFrameBuf( struct AVCodecContext *p_context,
 
     if( p_ff_pic->reference != 0 )
     {
-        vout_UnlinkPicture( p_vdec->p_vout, p_pic );
+        vout_UnlinkPicture( p_sys->p_vout, p_pic );
     }
 }
diff --git a/modules/codec/ffmpeg/video.h b/modules/codec/ffmpeg/video.h
deleted file mode 100644 (file)
index 8124682..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*****************************************************************************
- * video.h: video decoder using ffmpeg library
- *****************************************************************************
- * Copyright (C) 1999-2001 VideoLAN
- * $Id: video.h,v 1.11 2003/08/12 17:01:35 gbazin Exp $
- *
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * 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.
- *****************************************************************************/
-
-typedef struct vdec_thread_s
-{
-    DECODER_THREAD_COMMON
-
-    AVFrame        *p_ff_pic;
-    BITMAPINFOHEADER    *p_format;
-
-    vout_thread_t       *p_vout;
-
-    /* for post processing */
-#ifdef LIBAVCODEC_PP
-    pp_context_t        *pp_context;
-    pp_mode_t           *pp_mode;
-#endif
-
-    /* for frame skipping algo */
-    int b_hurry_up;
-    int i_frame_error;
-    int i_frame_skip;
-
-    vlc_bool_t b_has_b_frames;
-
-    int     i_frame_late;   /* how many decoded frames are late */
-    mtime_t i_frame_late_start;
-
-    /* for direct rendering */
-    int b_direct_rendering;
-} vdec_thread_t;
-
-
-int      E_( InitThread_Video )   ( vdec_thread_t * );
-void     E_( EndThread_Video )    ( vdec_thread_t * );
-void     E_( DecodeThread_Video ) ( vdec_thread_t * );
index 8efdcf9e356032c994e344e43987eb931e8339f9..34da93bf1fdb06bfa05434dfe9142918333fc187 100644 (file)
@@ -2,7 +2,7 @@
  * vorbis.c: vorbis decoder module making use of libvorbis.
  *****************************************************************************
  * Copyright (C) 1999-2001 VideoLAN
- * $Id: vorbis.c,v 1.19 2003/09/28 16:50:05 gbazin Exp $
+ * $Id: vorbis.c,v 1.20 2003/10/27 01:04:38 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
 #include <vlc/input.h>
 
 #include <ogg/ogg.h>
+
 #ifdef MODULE_NAME_IS_tremor
 #include <tremor/ivorbiscodec.h>
+
 #else
 #include <vorbis/codec.h>
+
+/* vorbis header */
+#ifdef HAVE_VORBIS_VORBISENC_H
+#   include <vorbis/vorbisenc.h>
+#   ifndef OV_ECTL_RATEMANAGE_AVG
+#       define OV_ECTL_RATEMANAGE_AVG 0x0
+#   endif
+#endif
+
 #endif
 
 /*****************************************************************************
@@ -121,10 +132,18 @@ static void Interleave   ( int32_t *, const int32_t **, int, int );
 static void Interleave   ( float *, const float **, int, int );
 #endif
 
+#ifndef MODULE_NAME_IS_tremor
+static int OpenEncoder   ( vlc_object_t * );
+static void CloseEncoder ( vlc_object_t * );
+static block_t *Headers  ( encoder_t * );
+static block_t *Encode   ( encoder_t *, aout_buffer_t * );
+#endif
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
 vlc_module_begin();
+
     set_description( _("Vorbis audio decoder") );
 #ifdef MODULE_NAME_IS_tremor
     set_capability( "decoder", 90 );
@@ -137,6 +156,14 @@ vlc_module_begin();
     set_description( _("Vorbis audio packetizer") );
     set_capability( "packetizer", 100 );
     set_callbacks( OpenPacketizer, NULL );
+
+#ifndef MODULE_NAME_IS_tremor
+    add_submodule();
+    set_description( _("Vorbis audio encoder") );
+    set_capability( "audio encoder", 100 );
+    set_callbacks( OpenEncoder, CloseEncoder );
+#endif
+
 vlc_module_end();
 
 /*****************************************************************************
@@ -576,3 +603,229 @@ static int EndDecoder( decoder_t * p_dec )
 
     return VLC_SUCCESS;
 }
+
+
+#if defined(HAVE_VORBIS_VORBISENC_H) && !defined(MODULE_NAME_IS_tremor)
+
+/*****************************************************************************
+ * encoder_sys_t : theora encoder descriptor
+ *****************************************************************************/
+struct encoder_sys_t
+{
+    /*
+     * Input properties
+     */
+    int i_headers;
+
+    /*
+     * Vorbis properties
+     */
+    vorbis_info      vi; /* struct that stores all the static vorbis bitstream
+                            settings */
+    vorbis_comment   vc; /* struct that stores all the bitstream user
+                          * comments */
+    vorbis_dsp_state vd; /* central working state for the packet->PCM
+                          * decoder */
+    vorbis_block     vb; /* local working space for packet->PCM decode */
+
+    int i_last_block_size;
+    int i_samples_delay;
+
+    /*
+     * Packetizer output properties
+     */
+    sout_packetizer_input_t *p_sout_input;
+    sout_format_t           sout_format;
+
+    /*
+     * Common properties
+     */
+    mtime_t i_pts;
+};
+
+/*****************************************************************************
+ * OpenEncoder: probe the encoder and return score
+ *****************************************************************************/
+static int OpenEncoder( vlc_object_t *p_this )
+{
+    encoder_t *p_enc = (encoder_t *)p_this;
+    encoder_sys_t *p_sys = p_enc->p_sys;
+
+    if( p_enc->i_fourcc != VLC_FOURCC('v','o','r','b') )
+    {
+        return VLC_EGENERIC;
+    }
+
+    /* Allocate the memory needed to store the decoder's structure */
+    if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
+    {
+        msg_Err( p_enc, "out of memory" );
+        return VLC_EGENERIC;
+    }
+    p_enc->p_sys = p_sys;
+
+    p_enc->pf_header = Headers;
+    p_enc->pf_encode_audio = Encode;
+    p_enc->format.audio.i_format = VLC_FOURCC('f','l','3','2');
+
+    /* Initialize vorbis encoder */
+    vorbis_info_init( &p_sys->vi );
+
+    if( vorbis_encode_setup_managed( &p_sys->vi,
+            aout_FormatNbChannels( &p_enc->format.audio ),
+            p_enc->format.audio.i_rate, -1, p_enc->i_bitrate, -1 ) ||
+        vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_AVG, NULL ) ||
+        vorbis_encode_setup_init( &p_sys->vi ) ){}
+
+    /* add a comment */
+    vorbis_comment_init( &p_sys->vc);
+    vorbis_comment_add_tag( &p_sys->vc, "ENCODER", "VLC media player");
+
+    /* set up the analysis state and auxiliary encoding storage */
+    vorbis_analysis_init( &p_sys->vd, &p_sys->vi );
+    vorbis_block_init( &p_sys->vd, &p_sys->vb );
+
+    p_sys->i_last_block_size = 0;
+    p_sys->i_samples_delay = 0;
+    p_sys->i_headers = 0;
+    p_sys->i_pts = 0;
+
+    return VLC_SUCCESS;
+}
+
+/****************************************************************************
+ * Encode: the whole thing
+ ****************************************************************************
+ * This function spits out ogg packets.
+ ****************************************************************************/
+static block_t *Headers( encoder_t *p_enc )
+{
+    encoder_sys_t *p_sys = p_enc->p_sys;
+    block_t *p_block, **pp_block = NULL;
+
+    /* Create theora headers */
+    if( !p_sys->i_headers )
+    {
+        ogg_packet header[3];
+        int i;
+
+        vorbis_analysis_headerout( &p_sys->vd, &p_sys->vc,
+                                   &header[0], &header[1], &header[2]);
+        for( i = 0; i < 3; i++ )
+        {
+            p_block = block_New( p_enc, header[i].bytes );
+            memcpy( p_block->p_buffer, header[i].packet, header[i].bytes );
+
+            p_block->i_dts = p_block->i_pts = p_block->i_length = 0;
+
+            block_ChainAppend( pp_block, p_block );
+        }
+        p_sys->i_headers = 3;
+
+        return *pp_block;
+    }
+
+    return NULL;
+}
+
+/****************************************************************************
+ * Encode: the whole thing
+ ****************************************************************************
+ * This function spits out ogg packets.
+ ****************************************************************************/
+static block_t *Encode( encoder_t *p_enc, aout_buffer_t *p_aout_buf )
+{
+    encoder_sys_t *p_sys = p_enc->p_sys;
+    ogg_packet oggpacket;
+    block_t *p_block, *p_chain = NULL;
+    float **buffer;
+    int i_samples;
+
+    p_sys->i_pts = p_aout_buf->start_date -
+                (mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay /
+                (mtime_t)p_enc->format.audio.i_rate;
+
+    i_samples = p_aout_buf->i_nb_samples;
+    p_sys->i_samples_delay += i_samples;
+
+    buffer = vorbis_analysis_buffer( &p_sys->vd, i_samples );
+
+#if 0
+    if( id->ff_dec_c->channels != id->ff_enc_c->channels )
+    {
+        int i, j;
+
+        /* dumb downmixing */
+        for( i = 0; i < id->ff_enc_c->frame_size; i++ )
+        {
+            for( j = 0 ; j < id->f_dst.i_channels; j++ )
+            {
+                p_buffer[i*id->f_dst.i_channels+j] =
+                    p_buffer[i*id->f_src.i_channels+j];
+            }
+        }
+    }
+
+    /* convert samples to float and uninterleave */
+    for( i = 0; i < id->f_dst.i_channels; i++ )
+    {
+        for( j = 0 ; j < i_samples ; j++ )
+        {
+            buffer[i][j]= ((float)( ((int16_t *)id->p_buffer)
+                                    [j*id->f_src.i_channels + i ] ))/ 32768.f;
+        }
+    }
+#endif
+
+    vorbis_analysis_wrote( &p_sys->vd, i_samples );
+
+    while( vorbis_analysis_blockout( &p_sys->vd, &p_sys->vb ) == 1 )
+    {
+        vorbis_analysis( &p_sys->vb, NULL );
+        vorbis_bitrate_addblock( &p_sys->vb );
+
+        while( vorbis_bitrate_flushpacket( &p_sys->vd, &oggpacket ) )
+        {
+            int i_block_size;
+            p_block = block_New( p_enc, oggpacket.bytes );
+            memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes );
+
+            i_block_size = vorbis_packet_blocksize( &p_sys->vi, &oggpacket );
+
+            if( i_block_size < 0 ) i_block_size = 0;
+            i_samples = ( p_sys->i_last_block_size + i_block_size ) >> 2;
+            p_sys->i_last_block_size = i_block_size;
+
+            p_block->i_length = (mtime_t)1000000 *
+                (mtime_t)i_samples / (mtime_t)p_enc->format.audio.i_rate;
+
+            p_block->i_dts = p_block->i_pts = p_sys->i_pts;
+
+            p_sys->i_samples_delay -= i_samples;
+
+            /* Update pts */
+            p_sys->i_pts += p_block->i_length;
+            block_ChainAppend( &p_chain, p_block );
+        }
+    }
+
+    return p_chain;
+}
+
+/*****************************************************************************
+ * CloseEncoder: theora encoder destruction
+ *****************************************************************************/
+static void CloseEncoder( vlc_object_t *p_this )
+{
+    encoder_t *p_enc = (encoder_t *)p_this;
+    encoder_sys_t *p_sys = p_enc->p_sys;
+
+    vorbis_block_clear( &p_sys->vb );
+    vorbis_dsp_clear( &p_sys->vd );
+    vorbis_comment_clear( &p_sys->vc );
+    vorbis_info_clear( &p_sys->vi );  /* must be called last */
+
+    free( p_sys );
+}
+
+#endif /* HAVE_VORBIS_VORBISENC_H && !MODULE_NAME_IS_tremor */
index f5c115f772b073baa0e171ddffb438e0e373928a..9b24835a5bd5f62e6293ce4b2a06ebb04f4fe335 100644 (file)
@@ -2,9 +2,10 @@
  * transcode.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: transcode.c,v 1.43 2003/10/24 21:27:06 gbazin Exp $
+ * $Id: transcode.c,v 1.44 2003/10/27 01:04:38 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
 #   include <avcodec.h>
 #endif
 
-/* vorbis header */
-#ifdef HAVE_VORBIS_VORBISENC_H
-#   include <vorbis/vorbisenc.h>
-#   ifndef OV_ECTL_RATEMANAGE_AVG
-#       define OV_ECTL_RATEMANAGE_AVG 0x0
-#   endif
-#endif
-
 /*****************************************************************************
  * Exported prototypes
  *****************************************************************************/
@@ -68,6 +61,17 @@ static int  transcode_video_ffmpeg_process( sout_stream_t *, sout_stream_id_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
  *****************************************************************************/
@@ -106,9 +110,6 @@ struct sout_stream_sys_t
 
     mtime_t         i_input_pts;
     mtime_t         i_output_pts;
-    mtime_t         i_last_ref_pts;
-
-    mtime_t         i_buggy_pts_detect;
 };
 
 /*****************************************************************************
@@ -303,7 +304,6 @@ static int Open( vlc_object_t *p_this )
 /*****************************************************************************
  * Close:
  *****************************************************************************/
-
 static void Close( vlc_object_t * p_this )
 {
     sout_stream_t       *p_stream = (sout_stream_t*)p_this;
@@ -324,17 +324,13 @@ struct sout_stream_id_t
     void *id;
 
     /* Encoder */
-    encoder_t *p_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;
 
@@ -346,28 +342,12 @@ struct sout_stream_id_t
     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 */
     AVFrame         *p_ff_pic_tmp2; /* to do resample */
 
     ImgReSampleContext *p_vresample;
-
-#ifdef HAVE_VORBIS_VORBISENC_H
-
-    /* Vorbis part */
-    vorbis_info      *p_vi;
-    vorbis_dsp_state *p_vd;
-    vorbis_block     *p_vb;
-    vorbis_comment   *p_vc;
-    int              i_last_block_size;
-    int              i_samples_delay;
-    vlc_bool_t       b_headers_sent;
-#endif
 };
 
 
@@ -672,7 +652,6 @@ static int transcode_audio_ffmpeg_new( sout_stream_t *p_stream,
         }
     }
 
-    /* find encoder */
     id->i_buffer_in      = 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE;
     id->i_buffer_in_pos = 0;
     id->p_buffer_in      = malloc( id->i_buffer_in );
@@ -681,97 +660,33 @@ static int transcode_audio_ffmpeg_new( sout_stream_t *p_stream,
     id->i_buffer_pos = 0;
     id->p_buffer     = malloc( id->i_buffer );
 
-    id->i_buffer_out     = 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE;
-    id->i_buffer_out_pos = 0;
-    id->p_buffer_out     = malloc( id->i_buffer_out );
-
     /* Sanity check for audio channels */
     id->f_dst.i_channels = __MIN( id->f_dst.i_channels, id->f_src.i_channels );
 
-#ifdef HAVE_VORBIS_VORBISENC_H
-    if( id->f_dst.i_fourcc == VLC_FOURCC('v','o','r','b') )
-    {
-        id->p_vi = (vorbis_info *)malloc( sizeof(vorbis_info) );
-        id->p_vd = (vorbis_dsp_state *)malloc( sizeof(vorbis_dsp_state) );
-        id->p_vb = (vorbis_block *)malloc( sizeof(vorbis_block) );
-        id->p_vc = (vorbis_comment *)malloc( sizeof(vorbis_comment) );
-
-        vorbis_info_init( id->p_vi );
-
-        if( vorbis_encode_setup_managed( id->p_vi, id->f_dst.i_channels,
-              id->f_dst.i_sample_rate, -1, id->f_dst.i_bitrate, -1 ) ||
-            vorbis_encode_ctl( id->p_vi, OV_ECTL_RATEMANAGE_AVG, NULL ) ||
-             vorbis_encode_setup_init( id->p_vi ) ){}
-
-        /* add a comment */
-        vorbis_comment_init( id->p_vc);
-        vorbis_comment_add_tag( id->p_vc, "ENCODER", "VLC media player");
-
-        /* set up the analysis state and auxiliary encoding storage */
-        vorbis_analysis_init( id->p_vd, id->p_vi );
-        vorbis_block_init( id->p_vd, id->p_vb );
-
-        id->b_headers_sent = VLC_FALSE;
-        id->i_last_block_size = 0;
-        id->i_samples_delay = 0;
-
-        return VLC_SUCCESS;
-    }
-#endif
-
-    i_ff_codec = get_ff_codec( id->f_dst.i_fourcc );
-    if( i_ff_codec == 0 )
-    {
-        msg_Err( p_stream, "cannot find encoder id" );
-        return VLC_EGENERIC;
-    }
-
-    id->ff_enc = avcodec_find_encoder( i_ff_codec );
-    if( !id->ff_enc )
-    {
-        msg_Err( p_stream, "cannot find encoder (avcodec)" );
-        return VLC_EGENERIC;
-    }
-
-    /* Hack for mp3 transcoding support */
-    if( id->f_dst.i_fourcc == VLC_FOURCC( 'm','p','3',' ' ) )
+    /* 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 )
     {
-        id->f_dst.i_fourcc = VLC_FOURCC( 'm','p','g','a' );
+        vlc_object_destroy( id->p_encoder );
+       id->p_encoder = NULL;
     }
 
-    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;
+    id->b_enc_inited = VLC_FALSE;
 
-    /* Make sure we get extradata filled by the encoder */
-    id->ff_enc_c->extradata_size = 0;
-    id->ff_enc_c->extradata = NULL;
-    id->ff_enc_c->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
-    if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
-    {
-        if( id->ff_enc_c->channels > 2 )
-        {
-            id->ff_enc_c->channels = 2;
-            id->f_dst.i_channels   = 2;
-            if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
-            {
-                msg_Err( p_stream, "cannot open encoder" );
-                return VLC_EGENERIC;
-            }
-            msg_Warn( p_stream, "stereo mode selected (codec limitation)" );
-        }
-        else
-        {
-            msg_Err( p_stream, "cannot open encoder" );
-            return VLC_EGENERIC;
-        }
-    }
-
-    id->f_dst.i_extra_data = id->ff_enc_c->extradata_size;
-    id->f_dst.p_extra_data = id->ff_enc_c->extradata;
-    id->ff_enc_c->flags &= ~CODEC_FLAG_GLOBAL_HEADER;
+    id->f_dst.i_extra_data = id->p_encoder->i_extra_data;
+    id->f_dst.p_extra_data = id->p_encoder->p_extra_data;
 
     return VLC_SUCCESS;
 }
@@ -782,32 +697,14 @@ static void transcode_audio_ffmpeg_close( sout_stream_t *p_stream,
     if( id->ff_dec )
     {
         avcodec_close( id->ff_dec_c );
+        free( id->ff_dec_c );
     }
 
-#ifdef HAVE_VORBIS_VORBISENC_H
-    if( id->f_dst.i_fourcc == VLC_FOURCC('v','o','r','b') )
-    {
-        vorbis_block_clear( id->p_vb );
-        vorbis_dsp_clear( id->p_vd );
-        vorbis_comment_clear( id->p_vc );
-        vorbis_info_clear( id->p_vi );  /* must be called last */
-
-        free( id->p_vi );
-        free( id->p_vd );
-        free( id->p_vb );
-        free( id->p_vc );
-    }
-    else
-#endif
-        avcodec_close( id->ff_enc_c );
-
-    free( id->ff_dec_c );
-    if( id->f_dst.i_fourcc != VLC_FOURCC('v','o','r','b') )
-        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_in );
     free( id->p_buffer );
-    free( id->p_buffer_out );
 }
 
 static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
@@ -816,17 +713,11 @@ static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
                                            sout_buffer_t **out )
 {
     vlc_bool_t b_again = VLC_FALSE;
-
+    aout_buffer_t aout_buf;
+    block_t *p_block;
     *out = NULL;
 
     /* gather data into p_buffer_in */
-#ifdef HAVE_VORBIS_VORBISENC_H
-    if( id->f_dst.i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
-    id->i_dts = in->i_dts -
-                (mtime_t)1000000 * (mtime_t)id->i_samples_delay /
-                (mtime_t)id->f_dst.i_sample_rate;
-    else
-#endif
     id->i_dts = in->i_dts -
                 (mtime_t)1000000 *
                 (mtime_t)(id->i_buffer_pos / 2 / id->ff_dec_c->channels )/
@@ -844,8 +735,6 @@ static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
 
     do
     {
-        int i_buffer_pos;
-
         /* decode as much data as possible */
         if( id->ff_dec )
         {
@@ -854,20 +743,21 @@ static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
                 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],
+                         (int16_t*)&id->p_buffer,
                          &i_buffer_size, id->p_buffer_in,
                          id->i_buffer_in_pos );
 
-                /* msg_Warn( p_stream, "avcodec_decode_audio: %d used",
-                             i_used ); */
+#if 0
+                msg_Warn( p_stream, "avcodec_decode_audio: %d used on %d",
+                          i_used, id->i_buffer_in_pos );
+#endif
+
                 id->i_buffer_pos += i_buffer_size;
 
                 if( i_used < 0 )
                 {
-                    msg_Warn( p_stream, "error");
+                    msg_Warn( p_stream, "error audio decoding");
                     id->i_buffer_in_pos = 0;
                     break;
                 }
@@ -977,164 +867,48 @@ static int transcode_audio_ffmpeg_process( sout_stream_t *p_stream,
             id->i_buffer_in_pos -= i_used;
         }
 
-        i_buffer_pos = id->i_buffer_pos;
-
-        /* encode as much data as possible */
-
-#ifdef HAVE_VORBIS_VORBISENC_H
-        if( id->i_buffer_pos == 0 );
-        else if( id->f_dst.i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
-        {
-            float **buffer;
-            int i, j, i_samples;
-            sout_buffer_t *p_out;
-            ogg_packet op;
-
-            if( !id->b_headers_sent )
-            {
-                ogg_packet header[3];
-                vorbis_analysis_headerout( id->p_vd, id->p_vc,
-                                           &header[0], &header[1], &header[2]);
-                for( i = 0; i < 3; i++ )
-                {
-                    p_out = sout_BufferNew( p_stream->p_sout, header[i].bytes);
-                    memcpy( p_out->p_buffer, header[i].packet,
-                            header[i].bytes );
-
-                    p_out->i_size = header[i].bytes;
-                    p_out->i_length = 0;
-
-                    p_out->i_dts = p_out->i_pts = id->i_dts;
-
-                    sout_BufferChain( out, p_out );
-                }
-                id->b_headers_sent = VLC_TRUE;
-            }
-
-            i_samples = id->i_buffer_pos / id->f_src.i_channels / 2;
-            id->i_samples_delay += i_samples;
-            id->i_buffer_pos = 0;
-
-            buffer = vorbis_analysis_buffer( id->p_vd, i_samples );
-
-            /* convert samples to float and uninterleave */
-            for( i = 0; i < id->f_dst.i_channels; i++ )
-            {
-                for( j = 0 ; j < i_samples ; j++ )
-                {
-                    buffer[i][j]= ((float)( ((int16_t *)id->p_buffer)
-                                  [j*id->f_src.i_channels + i ] ))/ 32768.f;
-                }
-            }
-
-            vorbis_analysis_wrote( id->p_vd, i_samples );
-
-            while( vorbis_analysis_blockout( id->p_vd, id->p_vb ) == 1 )
-            {
-                vorbis_analysis( id->p_vb, NULL );
-                vorbis_bitrate_addblock( id->p_vb );
-
-                while( vorbis_bitrate_flushpacket( id->p_vd, &op ) )
-                {
-                    int i_block_size;
-                    p_out = sout_BufferNew( p_stream->p_sout, op.bytes );
-                    memcpy( p_out->p_buffer, op.packet, op.bytes );
-
-                    i_block_size = vorbis_packet_blocksize( id->p_vi, &op );
-
-                    if( i_block_size < 0 ) i_block_size = 0;
-                    i_samples = ( id->i_last_block_size +
-                                  i_block_size ) >> 2;
-                    id->i_last_block_size = i_block_size;
-
-                    p_out->i_size = op.bytes;
-                    p_out->i_length = (mtime_t)1000000 *
-                      (mtime_t)i_samples /
-                      (mtime_t)id->f_dst.i_sample_rate;
-
-                    //msg_Err( p_stream, "i_dts: %lld", id->i_dts );
-
-                    /* FIXME */
-                    p_out->i_dts = id->i_dts;
-                    p_out->i_pts = id->i_dts;
-
-                    id->i_samples_delay -= i_samples;
-
-                    /* update dts */
-                    id->i_dts += p_out->i_length;
-                    sout_BufferChain( out, p_out );
-
-                }
-            }
-        }
-        else
-#endif
-
-        for( ;; )
-        {
-            int i_frame_size = id->ff_enc_c->frame_size * 2 *
-                                 id->ff_dec_c->channels;
-            int i_out_size, i, j;
-            sout_buffer_t *p_out;
-            int16_t *p_buffer = (int16_t *)(id->p_buffer + i_buffer_pos -
-                                            id->i_buffer_pos);
-
-            if( id->i_buffer_pos < i_frame_size )
-            {
-                break;
-            }
-
-            if( id->ff_dec_c->channels != id->ff_enc_c->channels )
-            {
-                /* dumb downmixing */
-                for( i = 0; i < id->ff_enc_c->frame_size; i++ )
-                {
-                    for( j = 0 ; j < id->f_dst.i_channels; j++ )
-                    {
-                        p_buffer[i*id->f_dst.i_channels+j] = p_buffer[i*id->f_src.i_channels+j];
-                    }
-                }
-            }
-
-            /* 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, p_buffer );
+        if( id->i_buffer_pos == 0 ) continue;
 
-            if( i_out_size <= 0 )
+        /* Encode as much data as possible */
+       if( id->b_enc_inited )
+       {
+            while( id->p_encoder->pf_header &&
+                  (p_block = id->p_encoder->pf_header( id->p_encoder )) )
             {
-                break;
+                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;
+                sout_BufferChain( out, p_out );
             }
 
-            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 );
-        }
-
-        /* Copy the remaining raw samples */
-        if( id->i_buffer_pos != 0 )
-        {
-            memmove( id->p_buffer,
-                     &id->p_buffer[i_buffer_pos - id->i_buffer_pos],
-                     id->i_buffer_pos );
-        }
+            id->b_enc_inited = VLC_TRUE;
+       }
+
+        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->ff_dec_c->channels;
+        aout_buf.start_date = id->i_dts;
+        aout_buf.end_date = id->i_dts;
+
+       p_block = id->p_encoder->pf_encode_audio( id->p_encoder, &aout_buf );
+       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 );
+       }
+       id->i_buffer_pos = 0;
 
     } while( b_again );
 
@@ -1152,6 +926,7 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
 
     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' ) ||
@@ -1162,7 +937,7 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
         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;
@@ -1221,154 +996,88 @@ static int transcode_video_ffmpeg_new( sout_stream_t *p_stream,
         }
     }
 
-
-    /* find encoder */
-    id->ff_enc = id->ff_enc_c = NULL;
-    i_ff_codec = get_ff_codec( id->f_dst.i_fourcc );
-    if( i_ff_codec != 0 )
-    {
-        id->ff_enc = avcodec_find_encoder( i_ff_codec );
-    }
-
-    /* Hack for external encoders */
-    if( !id->ff_enc )
+    /* 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 )
     {
-        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;
-
-            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->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->p_encoder->p_module =
-            module_Need( id->p_encoder, "video encoder", NULL );
-
-        if( !id->p_encoder->p_module )
-        {
-            free( id->p_encoder );
-            id->p_encoder = NULL;
-        }
+        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;
     }
-    /* End hack for external encoders */
-
-    if( !id->ff_enc && !id->p_encoder )
+    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;
     }
 
-    /* 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->i_buffer_out     = 0;
-    id->i_buffer_out_pos = 0;
-    id->p_buffer_out     = NULL;
-
     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;
 
-    p_sys->i_last_ref_pts = 0;
-    p_sys->i_buggy_pts_detect = 0;
-
-    /* This is enough for external encoders */
-    if( id->p_encoder && id->p_encoder->p_module ) return VLC_SUCCESS;
-
-    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' );
-    }
-
-    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;
-
     if( id->ff_dec )
     {
-        id->ff_enc_c->frame_rate     = id->ff_dec_c->frame_rate;
+        id->p_encoder->i_frame_rate = id->ff_dec_c->frame_rate;
 #if LIBAVCODEC_BUILD >= 4662
-        id->ff_enc_c->frame_rate_base= id->ff_dec_c->frame_rate_base;
+        id->p_encoder->i_frame_rate_base= id->ff_dec_c->frame_rate_base;
 #endif
     }
     else
     {
 #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     = 25 ; /* FIXME as it break mpeg */
+        id->p_encoder->i_frame_rate_base= 1;
 #else
-        id->ff_enc_c->frame_rate     = 25 * FRAME_RATE_BASE;
+        id->p_encoder->i_frame_rate     = 25 * FRAME_RATE_BASE;
 #endif
     }
 
-    id->ff_enc_c->gop_size       = p_sys->i_key_int >= 0 ? p_sys->i_key_int : 50;
-    id->ff_enc_c->max_b_frames   = __MIN( p_sys->i_b_frames, FF_MAX_B_FRAMES );
-    id->ff_enc_c->b_frame_strategy = 0;
-    id->ff_enc_c->b_quant_factor = 2.0;
+    id->p_encoder->p_module =
+        module_Need( id->p_encoder, "video encoder", NULL );
 
-    if( p_sys->i_vtolerance >= 0 )
+    if( !id->p_encoder->p_module )
     {
-        id->ff_enc_c->bit_rate_tolerance = p_sys->i_vtolerance;
+        vlc_object_destroy( id->p_encoder );
+        msg_Err( p_stream, "cannot find encoder" );
+        return VLC_EGENERIC;
     }
-    id->ff_enc_c->qmin           = p_sys->i_qmin;
-    id->ff_enc_c->qmax           = p_sys->i_qmax;
 
-#if LIBAVCODEC_BUILD >= 4673
-    id->ff_enc_c->mb_decision = p_sys->i_hq;
-#else
-    if( p_sys->i_hq )
-    {
-        id->ff_enc_c->flags      |= CODEC_FLAG_HQ;
-    }
-#endif
+    /* Close the encoder.
+     * We'll open it only when we have the first frame */
+    module_Unneed( id->p_encoder, id->p_encoder->p_module );
 
-    if( i_ff_codec == CODEC_ID_RAWVIDEO )
-    {
-        id->ff_enc_c->pix_fmt = get_ff_chroma( id->f_dst.i_fourcc );
-    }
+    id->b_enc_inited = VLC_FALSE;
 
     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 );
-    }
-    if( id->p_encoder )
-    {
-        /* External encoding */
-        module_Unneed( id->p_encoder, id->p_encoder->p_module );
-        vlc_object_destroy( id->p_encoder->p_module );
-    }
-    else if( id->b_enc_inited )
-    {
-        avcodec_close( id->ff_enc_c );
+        free( id->ff_dec_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 );
@@ -1393,10 +1102,6 @@ static void transcode_video_ffmpeg_close ( sout_stream_t *p_stream, sout_stream_
     {
         free( id->p_vresample );
     }
-
-    free( id->ff_dec_c );
-    if( id->ff_enc_c ) free( id->ff_enc_c );
-    free( id->p_buffer );
 }
 
 static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
@@ -1404,7 +1109,6 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
 {
     sout_stream_sys_t   *p_sys = p_stream->p_sys;
     int     i_used;
-    int     i_out;
     int     b_gotpicture;
     AVFrame *frame;
 
@@ -1461,37 +1165,54 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
             p_sys->i_output_pts = frame->pts;
         }
 
-        if( !id->b_enc_inited && id->p_encoder )
+        if( !id->b_enc_inited )
         {
             block_t *p_block;
 
             /* XXX hack because of copy packetizer and mpeg4video that can fail
              * detecting size */
-#if 0
-            if( id->p_encoder->i_width <= 0 )
+            if( id->p_encoder->format.video.i_width <= 0 )
             {
-                id->p_encoder->i_width = id->f_dst.i_width =
+                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->i_height <= 0 )
+            if( id->p_encoder->format.video.i_height <= 0 )
             {
-                id->p_encoder->i_height = id->f_dst.i_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;
             }
-#endif
 
             id->p_encoder->i_bitrate = p_sys->i_vbitrate;
 
-            if( !( id->id = p_stream->p_sys->p_out->pf_add( p_stream->p_sys->p_out, &id->f_dst ) ) )
+            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 )
+           {
+               vlc_object_destroy( id->p_encoder );
+               msg_Err( p_stream, "cannot find encoder" );
+               return VLC_EGENERIC;
+           }
+
+            id->f_dst.i_extra_data = id->p_encoder->i_extra_data;
+            id->f_dst.p_extra_data = id->p_encoder->p_extra_data;
+
+            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( (p_block = id->p_encoder->pf_header( id->p_encoder )) )
+            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 );
@@ -1506,49 +1227,6 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
 
             id->b_enc_inited = VLC_TRUE;
         }
-        else if( !id->b_enc_inited )
-        {
-            /* XXX hack because of copy packetizer and mpeg4video that can fail
-             * detecting size */
-            if( id->ff_enc_c->width <= 0 )
-            {
-                id->ff_enc_c->width    =
-                    id->f_dst.i_width  = id->ff_dec_c->width - p_sys->i_crop_left - p_sys->i_crop_right;
-            }
-            if( id->ff_enc_c->height <= 0 )
-            {
-                id->ff_enc_c->height   =
-                    id->f_dst.i_height = id->ff_dec_c->height - p_sys->i_crop_top - p_sys->i_crop_bottom;
-            }
-
-            /* Make sure we get extradata filled by the encoder */
-            id->ff_enc_c->extradata_size = 0;
-            id->ff_enc_c->extradata = NULL;
-            id->ff_enc_c->flags |= CODEC_FLAG_GLOBAL_HEADER;
-
-            if( avcodec_open( id->ff_enc_c, id->ff_enc ) )
-            {
-                msg_Err( p_stream, "cannot open encoder" );
-                return VLC_EGENERIC;
-            }
-
-            id->f_dst.i_extra_data = id->ff_enc_c->extradata_size;
-            id->f_dst.p_extra_data = id->ff_enc_c->extradata;
-            id->ff_enc_c->flags &= ~CODEC_FLAG_GLOBAL_HEADER;
-
-            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;
-            }
-
-            id->i_inter_pixfmt = id->ff_enc_c->pix_fmt;
-
-            id->b_enc_inited = VLC_TRUE;
-        }
-
 
         /* deinterlace */
         if( p_stream->p_sys->b_deinterlace )
@@ -1653,97 +1331,41 @@ static int transcode_video_ffmpeg_process( sout_stream_t *p_stream,
               id->ff_dec_c->frame_rate_base / (2 * id->ff_dec_c->frame_rate);
         }
 
-        if( id->p_encoder )
-        {
-            /* External encoding */
-            block_t *p_block;
-            picture_t pic;
-            int i_plane;
-
-            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++ )
-            {
-                pic.p[i_plane].p_pixels = frame->data[i_plane];
-                pic.p[i_plane].i_pitch = frame->linesize[i_plane];
-            }
-
-            pic.date = frame->pts;
-
-            p_block = id->p_encoder->pf_encode_video( id->p_encoder, &pic );
-            if( p_block )
-            {
-                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_block->i_dts;
-                p_out->i_pts = p_block->i_pts;
-                sout_BufferChain( out, p_out );
-                block_Release( p_block );
-            }
-
-            return VLC_SUCCESS;
-        }
-
-        /* Let ffmpeg select the frame type */
-        frame->pict_type = 0;
-
-        i_out = avcodec_encode_video( id->ff_enc_c, id->p_buffer,
-                                      id->i_buffer, frame );
-        if( i_out > 0 )
-        {
-            sout_buffer_t *p_out;
-            p_out = sout_BufferNew( p_stream->p_sout, i_out );
-
-            memcpy( p_out->p_buffer, id->p_buffer, i_out );
-
-            p_out->i_size   = i_out;
-
-            if( id->ff_enc_c->coded_frame->pts != 0 &&
-                p_sys->i_buggy_pts_detect != id->ff_enc_c->coded_frame->pts )
-            {
-                p_sys->i_buggy_pts_detect = id->ff_enc_c->coded_frame->pts;
-
-                /* FIXME, 3-2 pulldown is not handled correctly */
-                p_out->i_length = in->i_length;
-                p_out->i_pts    = id->ff_enc_c->coded_frame->pts;
-
-                if( !id->ff_enc_c->delay ||
-                    ( id->ff_enc_c->coded_frame->pict_type != FF_I_TYPE &&
-                      id->ff_enc_c->coded_frame->pict_type != FF_P_TYPE ) )
-                {
-                    p_out->i_dts    = p_out->i_pts;
-                }
-                else
-                {
-                    if( p_sys->i_last_ref_pts )
-                    {
-                        p_out->i_dts = p_sys->i_last_ref_pts;
-                    }
-                    else
-                    {
-                        /* Let's put something sensible */
-                        p_out->i_dts = p_out->i_pts;
-                    }
-
-                    p_sys->i_last_ref_pts = p_out->i_pts;
-                }
-            }
-            else
-            {
-                /* Buggy libavcodec which doesn't update coded_frame->pts
-                 * correctly */
-                p_out->i_length = in->i_length;
-                p_out->i_dts    = in->i_dts;
-                p_out->i_pts    = in->i_dts;
-            }
-
-            sout_BufferChain( out, p_out );
-        }
+       /* Encoding */
+       block_t *p_block;
+       picture_t pic;
+       int i_plane;
+
+       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++ )
+       {
+           pic.p[i_plane].p_pixels = frame->data[i_plane];
+           pic.p[i_plane].i_pitch = frame->linesize[i_plane];
+       }
+
+       pic.date = frame->pts;
+
+       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 )
         {