]> git.sesse.net Git - vlc/blobdiff - modules/stream_out/transcode.c
Added sout_UpdateStatistic and fixed transcode module to use it.
[vlc] / modules / stream_out / transcode.c
index 6a052afbd4938ec18ebc082ded73ea98a7f69190..7c7b38fdfe33f4bbb9eda175c15559187e4e4109 100644 (file)
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
 #include <vlc/vlc.h>
-#include <vlc/input.h>
-#include <vlc/sout.h>
-#include <vlc/vout.h>
-#include <vlc/decoder.h>
+#include <vlc_input.h>
+#include <vlc_sout.h>
+#include <vlc_aout.h>
+#include <vlc_vout.h>
+#include <vlc_codec.h>
+#include <vlc_block.h>
 #include <vlc_filter.h>
 #include <vlc_osd.h>
 
+#include <math.h>
+
 #define MASTER_SYNC_MAX_DRIFT 100000
 
 /*****************************************************************************
 #define HURRYUP_LONGTEXT N_( "The transcoder will drop frames if your CPU " \
                 "can't keep up with the encoding rate." )
 
-static char *ppsz_deinterlace_type[] =
+static const char *ppsz_deinterlace_type[] =
 {
     "deinterlace", "ffmpeg-deinterlace"
 };
@@ -255,7 +255,7 @@ vlc_module_begin();
                 AENC_LONGTEXT, VLC_FALSE );
     add_string( SOUT_CFG_PREFIX "acodec", NULL, NULL, ACODEC_TEXT,
                 ACODEC_LONGTEXT, VLC_FALSE );
-    add_integer( SOUT_CFG_PREFIX "ab", 64000, NULL, AB_TEXT,
+    add_integer( SOUT_CFG_PREFIX "ab", 0, NULL, AB_TEXT,
                  AB_LONGTEXT, VLC_FALSE );
     add_integer( SOUT_CFG_PREFIX "channels", 0, NULL, ACHANS_TEXT,
                  ACHANS_LONGTEXT, VLC_FALSE );
@@ -292,8 +292,8 @@ vlc_module_end();
 
 static const char *ppsz_sout_options[] = {
     "venc", "vcodec", "vb", "croptop", "cropbottom", "cropleft", "cropright",
-    "paddtop", "paddbottom", "paddleft", "paddright", 
-    "canvas-width", "canvas-height", "canvas-aspect", 
+    "paddtop", "paddbottom", "paddleft", "paddright",
+    "canvas-width", "canvas-height", "canvas-aspect",
     "scale", "fps", "width", "height", "vfilter", "deinterlace",
     "deinterlace-module", "threads", "hurry-up", "aenc", "acodec", "ab",
     "afilter", "samplerate", "channels", "senc", "scodec", "soverlay",
@@ -372,18 +372,18 @@ struct sout_stream_sys_t
     /* Audio */
     vlc_fourcc_t    i_acodec;   /* codec audio (0 if not transcode) */
     char            *psz_aenc;
-    sout_cfg_t      *p_audio_cfg;
+    config_chain_t  *p_audio_cfg;
     int             i_sample_rate;
     int             i_channels;
     int             i_abitrate;
     char            *psz_afilters[TRANSCODE_FILTERS];
-    sout_cfg_t      *p_afilters_cfg[TRANSCODE_FILTERS];
+    config_chain_t  *p_afilters_cfg[TRANSCODE_FILTERS];
     int             i_afilters;
 
     /* Video */
     vlc_fourcc_t    i_vcodec;   /* codec video (0 if not transcode) */
     char            *psz_venc;
-    sout_cfg_t      *p_video_cfg;
+    config_chain_t  *p_video_cfg;
     int             i_vbitrate;
     double          f_scale;
     double          f_fps;
@@ -391,12 +391,12 @@ struct sout_stream_sys_t
     unsigned int    i_height, i_maxheight;
     vlc_bool_t      b_deinterlace;
     char            *psz_deinterlace;
-    sout_cfg_t      *p_deinterlace_cfg;
+    config_chain_t  *p_deinterlace_cfg;
     int             i_threads;
     vlc_bool_t      b_high_priority;
     vlc_bool_t      b_hurry_up;
     char            *psz_vfilters[TRANSCODE_FILTERS];
-    sout_cfg_t      *p_vfilters_cfg[TRANSCODE_FILTERS];
+    config_chain_t  *p_vfilters_cfg[TRANSCODE_FILTERS];
     int             i_vfilters;
 
     int             i_crop_top;
@@ -428,16 +428,14 @@ struct sout_stream_sys_t
     vlc_fourcc_t    i_scodec;   /* codec spu (0 if not transcode) */
     char            *psz_senc;
     vlc_bool_t      b_soverlay;
-    sout_cfg_t      *p_spu_cfg;
+    config_chain_t  *p_spu_cfg;
     spu_t           *p_spu;
 
     /* OSD Menu */
-    sout_stream_id_t *id_osd;   /* extension for streaming OSD menus */
     vlc_fourcc_t    i_osdcodec; /* codec osd menu (0 if not transcode) */
     char            *psz_osdenc;
-    sout_cfg_t      *p_osd_cfg;
-    vlc_bool_t      b_es_osd;      /* VLC_TRUE when osd es is registered */
-    vlc_bool_t      b_sout_osd;
+    config_chain_t  *p_osd_cfg;
+    vlc_bool_t      b_osd;   /* VLC_TRUE when osd es is registered */
 
     /* Sync */
     vlc_bool_t      b_master_sync;
@@ -476,7 +474,7 @@ static int Open( vlc_object_t *p_this )
 
     p_sys->i_master_drift = 0;
 
-    sout_CfgParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
+    config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
                    p_stream->p_cfg );
 
     /* Audio transcoding parameters */
@@ -486,8 +484,8 @@ static int Open( vlc_object_t *p_this )
     if( val.psz_string && *val.psz_string )
     {
         char *psz_next;
-        psz_next = sout_CfgCreate( &p_sys->psz_aenc, &p_sys->p_audio_cfg,
-                                   val.psz_string );
+        psz_next = config_ChainCreate( &p_sys->psz_aenc, &p_sys->p_audio_cfg,
+                                       val.psz_string );
         if( psz_next ) free( psz_next );
     }
     if( val.psz_string ) free( val.psz_string );
@@ -535,7 +533,7 @@ static int Open( vlc_object_t *p_this )
         while( (psz_parser != NULL) && (*psz_parser != '\0')
                 && (p_sys->i_afilters < TRANSCODE_FILTERS) )
         {
-            psz_parser = sout_CfgCreate(
+            psz_parser = config_ChainCreate(
                                    &p_sys->psz_afilters[p_sys->i_afilters],
                                    &p_sys->p_afilters_cfg[p_sys->i_afilters],
                                    psz_parser );
@@ -557,7 +555,7 @@ static int Open( vlc_object_t *p_this )
     if( val.psz_string && *val.psz_string )
     {
         char *psz_next;
-        psz_next = sout_CfgCreate( &p_sys->psz_venc, &p_sys->p_video_cfg,
+        psz_next = config_ChainCreate( &p_sys->psz_venc, &p_sys->p_video_cfg,
                                    val.psz_string );
         if( psz_next ) free( psz_next );
     }
@@ -607,7 +605,7 @@ static int Open( vlc_object_t *p_this )
         while( (psz_parser != NULL) && (*psz_parser != '\0')
                 && (p_sys->i_vfilters < TRANSCODE_FILTERS) )
         {
-            psz_parser = sout_CfgCreate(
+            psz_parser = config_ChainCreate(
                                    &p_sys->psz_vfilters[p_sys->i_vfilters],
                                    &p_sys->p_vfilters_cfg[p_sys->i_vfilters],
                                    psz_parser );
@@ -631,7 +629,7 @@ static int Open( vlc_object_t *p_this )
     if( val.psz_string && *val.psz_string )
     {
         char *psz_next;
-        psz_next = sout_CfgCreate( &p_sys->psz_deinterlace,
+        psz_next = config_ChainCreate( &p_sys->psz_deinterlace,
                                    &p_sys->p_deinterlace_cfg,
                                    val.psz_string );
         if( psz_next ) free( psz_next );
@@ -699,7 +697,7 @@ static int Open( vlc_object_t *p_this )
     if( val.psz_string && *val.psz_string )
     {
         char *psz_next;
-        psz_next = sout_CfgCreate( &p_sys->psz_senc, &p_sys->p_spu_cfg,
+        psz_next = config_ChainCreate( &p_sys->psz_senc, &p_sys->p_spu_cfg,
                                    val.psz_string );
         if( psz_next ) free( psz_next );
     }
@@ -736,16 +734,15 @@ static int Open( vlc_object_t *p_this )
     p_sys->psz_osdenc = NULL;
     p_sys->p_osd_cfg  = NULL;
     p_sys->i_osdcodec = 0;
-    p_sys->b_es_osd   = VLC_FALSE;
+    p_sys->b_osd   = VLC_FALSE;
 
     var_Get( p_stream, SOUT_CFG_PREFIX "osd", &val );
-    p_sys->b_sout_osd = val.b_bool;
-    if( p_sys->b_sout_osd )
+    if( val.b_bool )
     {
         vlc_value_t osd_val;
         char *psz_next;
 
-        psz_next = sout_CfgCreate( &p_sys->psz_osdenc,
+        psz_next = config_ChainCreate( &p_sys->psz_osdenc,
                                    &p_sys->p_osd_cfg, strdup( "dvbsub") );
         if( psz_next ) free( psz_next );
 
@@ -793,9 +790,18 @@ static void Close( vlc_object_t * p_this )
 
     sout_StreamDelete( p_sys->p_out );
 
+    while( p_sys->i_afilters )
+    {
+        p_sys->i_afilters--;
+        if( p_sys->psz_afilters[p_sys->i_afilters] )
+            free( p_sys->psz_afilters[p_sys->i_afilters] );
+        if( p_sys->p_afilters_cfg[p_sys->i_afilters] )
+            free( p_sys->p_afilters_cfg[p_sys->i_afilters] );
+    }
+
     while( p_sys->p_audio_cfg != NULL )
     {
-        sout_cfg_t *p_next = p_sys->p_audio_cfg->p_next;
+        config_chain_t *p_next = p_sys->p_audio_cfg->p_next;
 
         if( p_sys->p_audio_cfg->psz_name )
             free( p_sys->p_audio_cfg->psz_name );
@@ -807,9 +813,18 @@ static void Close( vlc_object_t * p_this )
     }
     if( p_sys->psz_aenc ) free( p_sys->psz_aenc );
 
+    while( p_sys->i_vfilters )
+    {
+        p_sys->i_vfilters--;
+        if( p_sys->psz_vfilters[p_sys->i_vfilters] )
+            free( p_sys->psz_vfilters[p_sys->i_vfilters] );
+        if( p_sys->p_vfilters_cfg[p_sys->i_vfilters] )
+            free( p_sys->p_vfilters_cfg[p_sys->i_vfilters] );
+    }
+
     while( p_sys->p_video_cfg != NULL )
     {
-        sout_cfg_t *p_next = p_sys->p_video_cfg->p_next;
+        config_chain_t *p_next = p_sys->p_video_cfg->p_next;
 
         if( p_sys->p_video_cfg->psz_name )
             free( p_sys->p_video_cfg->psz_name );
@@ -823,7 +838,7 @@ static void Close( vlc_object_t * p_this )
 
     while( p_sys->p_deinterlace_cfg != NULL )
     {
-        sout_cfg_t *p_next = p_sys->p_deinterlace_cfg->p_next;
+        config_chain_t *p_next = p_sys->p_deinterlace_cfg->p_next;
 
         if( p_sys->p_deinterlace_cfg->psz_name )
             free( p_sys->p_deinterlace_cfg->psz_name );
@@ -837,7 +852,7 @@ static void Close( vlc_object_t * p_this )
 
     while( p_sys->p_spu_cfg != NULL )
     {
-        sout_cfg_t *p_next = p_sys->p_spu_cfg->p_next;
+        config_chain_t *p_next = p_sys->p_spu_cfg->p_next;
 
         if( p_sys->p_spu_cfg->psz_name )
             free( p_sys->p_spu_cfg->psz_name );
@@ -853,7 +868,7 @@ static void Close( vlc_object_t * p_this )
 
     while( p_sys->p_osd_cfg != NULL )
     {
-        sout_cfg_t *p_next = p_sys->p_osd_cfg->p_next;
+        config_chain_t *p_next = p_sys->p_osd_cfg->p_next;
 
         if( p_sys->p_osd_cfg->psz_name )
             free( p_sys->p_osd_cfg->psz_name );
@@ -898,6 +913,11 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
     sout_stream_id_t *id;
 
     id = malloc( sizeof( sout_stream_id_t ) );
+    if( !id )
+    {
+        msg_Err( p_stream, "out of memory" );
+        goto error;
+    }
     memset( id, 0, sizeof(sout_stream_id_t) );
 
     id->id = NULL;
@@ -1016,7 +1036,8 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
             id->p_encoder->fmt_out.video.i_frame_rate_base = 1001;
         }
     }
-    else if( p_fmt->i_cat == SPU_ES && (p_sys->i_scodec || p_sys->psz_senc) )
+    else if( ( p_fmt->i_cat == SPU_ES ) &&
+             ( p_sys->i_scodec || p_sys->psz_senc ) )
     {
         msg_Dbg( p_stream, "creating subtitles transcoding from fcc=`%4.4s' "
                  "to fcc=`%4.4s'", (char*)&p_fmt->i_codec,
@@ -1056,6 +1077,22 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
             goto error;
         }
     }
+    else if( !p_sys->b_osd && (p_sys->i_osdcodec != 0 || p_sys->psz_osdenc) )
+    {
+        msg_Dbg( p_stream, "creating osd transcoding from fcc=`%4.4s' "
+                 "to fcc=`%4.4s'", (char*)&p_fmt->i_codec,
+                 (char*)&p_sys->i_scodec );
+
+        id->b_transcode = VLC_TRUE;
+
+        /* Create a fake OSD menu elementary stream */
+        if( transcode_osd_new( p_stream, id ) )
+        {
+            msg_Err( p_stream, "cannot create osd chain" );
+            goto error;
+        }
+        p_sys->b_osd = VLC_TRUE;
+    }
     else
     {
         msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
@@ -1066,19 +1103,6 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
         if( !id->id ) goto error;
     }
 
-    if( p_sys->b_sout_osd )
-    {
-        /* Create a fake OSD menu elementary stream */
-        if( !p_sys->b_es_osd && (p_sys->i_osdcodec != 0 || p_sys->psz_osdenc) )
-        {
-            if( transcode_osd_new( p_stream, p_sys->id_osd ) )
-            {
-                msg_Err( p_stream, "cannot create osd chain" );
-                goto error;
-            }
-            p_sys->b_es_osd = VLC_TRUE;
-        }
-    }
     return id;
 
  error:
@@ -1105,9 +1129,6 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
 
-    if( p_sys->b_es_osd )
-        transcode_osd_close( p_stream, p_sys->id_osd );
-
     if( id->b_transcode )
     {
         switch( id->p_decoder->fmt_in.i_cat )
@@ -1119,7 +1140,10 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
             transcode_video_close( p_stream, id );
             break;
         case SPU_ES:
-            transcode_spu_close( p_stream, id );
+            if( p_sys->b_osd )
+                transcode_osd_close( p_stream, id );
+            else
+                transcode_spu_close( p_stream, id );
             break;
         }
     }
@@ -1153,11 +1177,6 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
 
     if( !id->b_transcode && id->id )
     {
-        /* Transcode OSD menu pictures. */
-        if( p_sys->b_es_osd )
-        {
-            transcode_osd_process( p_stream, id, p_buffer, &p_out );
-        }
         return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
     }
     else if( !id->b_transcode )
@@ -1181,7 +1200,16 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
         break;
 
     case SPU_ES:
-        if( transcode_spu_process( p_stream, id, p_buffer, &p_out ) !=
+        /* Transcode OSD menu pictures. */
+        if( p_sys->b_osd )
+        {
+            if( transcode_osd_process( p_stream, id, p_buffer, &p_out ) !=
+                VLC_SUCCESS )
+            {
+                return VLC_EGENERIC;
+            }
+        }
+        else if ( transcode_spu_process( p_stream, id, p_buffer, &p_out ) !=
             VLC_SUCCESS )
         {
             return VLC_EGENERIC;
@@ -1201,7 +1229,7 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
 /****************************************************************************
  * decoder reencoder part
  ****************************************************************************/
-int audio_BitsPerSample( vlc_fourcc_t i_format )
+static int audio_BitsPerSample( vlc_fourcc_t i_format )
 {
     switch( i_format )
     {
@@ -1253,7 +1281,8 @@ static filter_t *transcode_audio_filter_new( sout_stream_t *p_stream,
     if( psz_name )
         p_filter->p_cfg = p_sys->p_afilters_cfg[id->i_ufilter];
 
-    p_filter->p_module = module_Need( p_filter, "audio filter2", psz_name, 0 );
+    p_filter->p_module = module_Need( p_filter, "audio filter2", psz_name,
+                                      VLC_TRUE );
     if( p_filter->p_module )
     {
         p_filter->fmt_out.audio.i_bitspersample =
@@ -1285,7 +1314,7 @@ static int transcode_audio_new( sout_stream_t *p_stream,
     id->p_decoder->fmt_out = id->p_decoder->fmt_in;
     id->p_decoder->fmt_out.i_extra = 0;
     id->p_decoder->fmt_out.p_extra = 0;
-    id->p_decoder->pf_decode_audio = 0;
+    id->p_decoder->pf_decode_audio = NULL;
     id->p_decoder->pf_aout_buffer_new = audio_new_buffer;
     id->p_decoder->pf_aout_buffer_del = audio_del_buffer;
     /* id->p_decoder->p_cfg = p_sys->p_audio_cfg; */
@@ -1297,11 +1326,14 @@ static int transcode_audio_new( sout_stream_t *p_stream,
         msg_Err( p_stream, "cannot find decoder" );
         return VLC_EGENERIC;
     }
-    id->p_decoder->fmt_out.audio.i_bitspersample = 
+    id->p_decoder->fmt_out.audio.i_bitspersample =
         audio_BitsPerSample( id->p_decoder->fmt_out.i_codec );
     fmt_last = id->p_decoder->fmt_out;
-    /* FIX decoders so we don't have to do this */
-    fmt_last.audio.i_rate = id->p_decoder->fmt_in.audio.i_rate;
+    /* Fix AAC SBR changing number of channels and sampling rate */
+    if( !(id->p_decoder->fmt_in.i_codec == VLC_FOURCC('m','p','4','a') &&
+        fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate &&
+        fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels) )
+        fmt_last.audio.i_rate = id->p_decoder->fmt_in.audio.i_rate;
 
     /*
      * Open encoder
@@ -1340,6 +1372,15 @@ static int transcode_audio_new( sout_stream_t *p_stream,
     id->p_encoder->fmt_in.audio.i_bitspersample =
         audio_BitsPerSample( id->p_encoder->fmt_in.i_codec );
 
+    /* Fix AAC SBR changing number of channels and sampling rate */
+    if( id->p_decoder->fmt_in.i_codec == VLC_FOURCC('m','p','4','a') &&
+        fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate &&
+        fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels )
+    {
+      id->p_encoder->fmt_in.audio.i_rate = fmt_last.audio.i_rate;
+      id->p_encoder->fmt_out.audio.i_rate = fmt_last.audio.i_rate;
+    }
+
     /* Load conversion filters */
     if( fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels ||
         fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate )
@@ -1505,18 +1546,11 @@ static int transcode_audio_process( sout_stream_t *p_stream,
     block_t *p_block, *p_audio_block;
     int i;
     *out = NULL;
-    input_thread_t *p_input = NULL;
-
-    if( p_stream->p_parent->p_parent && p_stream->p_parent->p_parent->
-                                i_object_type == VLC_OBJECT_INPUT )
-        p_input = (input_thread_t *)p_stream->p_parent->p_parent;
 
     while( (p_audio_buf = id->p_decoder->pf_decode_audio( id->p_decoder,
                                                           &in )) )
     {
-        if( p_input )
-            stats_UpdateInteger( p_input, p_input->counters.p_decoded_audio,
-                                 1, NULL );
+        sout_UpdateStatistic( p_stream->p_sout, SOUT_STATISTIC_DECODED_AUDIO, 1 );
         if( p_sys->b_master_sync )
         {
             mtime_t i_dts = date_Get( &id->interpolated_pts ) + 1;
@@ -1601,6 +1635,8 @@ static aout_buffer_t *audio_new_buffer( decoder_t *p_dec, int i_samples )
     }
 
     p_buffer = malloc( sizeof(aout_buffer_t) );
+    if( !p_buffer ) return NULL;
+    p_buffer->b_discontinuity = VLC_FALSE;
     p_buffer->pf_release = audio_release_buffer;
     p_buffer->p_sys = p_block = block_New( p_dec, i_size );
 
@@ -1632,7 +1668,9 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
     id->p_decoder->fmt_out = id->p_decoder->fmt_in;
     id->p_decoder->fmt_out.i_extra = 0;
     id->p_decoder->fmt_out.p_extra = 0;
-    id->p_decoder->pf_decode_video = 0;
+    id->p_decoder->pf_decode_video = NULL;
+    id->p_decoder->pf_get_cc = NULL;
+    id->p_decoder->pf_get_cc = 0;
     id->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
     id->p_decoder->pf_vout_buffer_del = video_del_buffer_decoder;
     id->p_decoder->pf_picture_link    = video_link_picture_decoder;
@@ -1696,7 +1734,11 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
      * We'll open it only when we have the first frame. */
     module_Unneed( id->p_encoder, id->p_encoder->p_module );
     if( id->p_encoder->fmt_out.p_extra )
+    {
         free( id->p_encoder->fmt_out.p_extra );
+        id->p_encoder->fmt_out.p_extra = NULL;
+        id->p_encoder->fmt_out.i_extra = 0;
+    }
     id->p_encoder->p_module = NULL;
 
     if( p_sys->i_threads >= 1 )
@@ -2025,7 +2067,7 @@ static void transcode_video_close( sout_stream_t *p_stream,
     if( p_stream->p_sys->i_threads >= 1 )
     {
         vlc_mutex_lock( &p_stream->p_sys->lock_out );
-        p_stream->p_sys->b_die = 1;
+        vlc_object_kill( p_stream->p_sys );
         vlc_cond_signal( &p_stream->p_sys->cond );
         vlc_mutex_unlock( &p_stream->p_sys->lock_out );
         vlc_thread_join( p_stream->p_sys );
@@ -2099,18 +2141,12 @@ static int transcode_video_process( sout_stream_t *p_stream,
     int i_duplicate = 1, i;
     picture_t *p_pic, *p_pic2 = NULL;
     *out = NULL;
-    input_thread_t *p_input = NULL;
-
-    if( p_stream->p_parent->p_parent && p_stream->p_parent->p_parent->
-                                i_object_type == VLC_OBJECT_INPUT )
-        p_input = (input_thread_t *)p_stream->p_parent->p_parent;
 
     while( (p_pic = id->p_decoder->pf_decode_video( id->p_decoder, &in )) )
     {
-        subpicture_t *p_subpic = 0;
-        if( p_input )
-            stats_UpdateInteger( p_input, p_input->counters.p_decoded_video,
-                                 1, NULL );
+        subpicture_t *p_subpic = NULL;
+
+        sout_UpdateStatistic( p_stream->p_sout, SOUT_STATISTIC_DECODED_VIDEO, 1 );
 
         if( p_stream->p_sout->i_out_pace_nocontrol && p_sys->b_hurry_up )
         {
@@ -2144,7 +2180,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
             /* Set the pts of the frame being encoded */
             p_pic->date = i_pts;
 
-            if( i_video_drift < i_master_drift - 50000 )
+            if( i_video_drift < (i_master_drift - 50000) )
             {
 #if 0
                 msg_Dbg( p_stream, "dropping frame (%i)",
@@ -2153,7 +2189,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
                 p_pic->pf_release( p_pic );
                 continue;
             }
-            else if( i_video_drift > i_master_drift + 50000 )
+            else if( i_video_drift > (i_master_drift + 50000) )
             {
 #if 0
                 msg_Dbg( p_stream, "adding frame (%i)",
@@ -2190,7 +2226,8 @@ static int transcode_video_process( sout_stream_t *p_stream,
                 id->pp_filter[id->i_filter]->p_cfg = p_sys->p_deinterlace_cfg;
                 id->pp_filter[id->i_filter]->p_module =
                     module_Need( id->pp_filter[id->i_filter],
-                                 "video filter2", p_sys->psz_deinterlace, 0 );
+                                 "video filter2", p_sys->psz_deinterlace,
+                                 VLC_TRUE );
                 if( id->pp_filter[id->i_filter]->p_module )
                 {
                     id->pp_filter[id->i_filter]->p_owner =
@@ -2286,7 +2323,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
                 id->pp_ufilter[id->i_ufilter]->p_cfg = p_sys->p_vfilters_cfg[i];
                 id->pp_ufilter[id->i_ufilter]->p_module =
                     module_Need( id->pp_ufilter[id->i_ufilter],
-                          "video filter2", p_sys->psz_vfilters[i], 0 );
+                          "video filter2", p_sys->psz_vfilters[i], VLC_TRUE );
                 if( id->pp_ufilter[id->i_ufilter]->p_module )
                 {
                     id->pp_ufilter[id->i_ufilter]->p_owner =
@@ -2364,7 +2401,8 @@ static int transcode_video_process( sout_stream_t *p_stream,
         /* Run user specified filter chain */
         for( i = 0; i < id->i_ufilter; i++ )
         {
-            p_pic = id->pp_ufilter[i]->pf_video_filter(id->pp_ufilter[i], p_pic);
+            p_pic = id->pp_ufilter[i]->pf_video_filter( id->pp_ufilter[i],
+                                                        p_pic );
         }
 
         if( p_sys->i_threads == 0 )
@@ -2390,8 +2428,8 @@ static int transcode_video_process( sout_stream_t *p_stream,
         if( p_sys->b_master_sync && i_duplicate > 1 )
         {
             mtime_t i_pts = date_Get( &id->interpolated_pts ) + 1;
-            if ( p_pic->date - i_pts > MASTER_SYNC_MAX_DRIFT
-                  || p_pic->date - i_pts < -MASTER_SYNC_MAX_DRIFT )
+            if( (p_pic->date - i_pts > MASTER_SYNC_MAX_DRIFT)
+                 || ((p_pic->date - i_pts) < -MASTER_SYNC_MAX_DRIFT) )
             {
                 msg_Dbg( p_stream, "drift is too high, resetting master sync" );
                 date_Set( &id->interpolated_pts, p_pic->date );
@@ -2561,6 +2599,7 @@ static picture_t *video_new_buffer( vlc_object_t *p_this, picture_t **pp_ring,
     }
 
     p_pic = malloc( sizeof(picture_t) );
+    if( !p_pic ) return NULL;
     p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
     vout_AllocatePicture( VLC_OBJECT(p_dec), p_pic,
                           p_dec->fmt_out.video.i_chroma,
@@ -2571,11 +2610,17 @@ static picture_t *video_new_buffer( vlc_object_t *p_this, picture_t **pp_ring,
     if( !p_pic->i_planes )
     {
         free( p_pic );
-        return 0;
+        return NULL;
     }
 
     p_pic->pf_release = video_release_buffer;
     p_pic->p_sys = malloc( sizeof(picture_sys_t) );
+    if( !p_pic->p_sys )
+    {
+        free( p_pic );
+        return NULL;
+    }
+
     p_pic->p_sys->p_owner = p_this;
     p_pic->i_status = RESERVED_PICTURE;
 
@@ -2640,6 +2685,7 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id )
      */
 
     /* Initialization of decoder structures */
+    id->p_decoder->pf_decode_sub = NULL;
     id->p_decoder->pf_spu_buffer_new = spu_new_buffer;
     id->p_decoder->pf_spu_buffer_del = spu_del_buffer;
     id->p_decoder->p_owner = (decoder_owner_sys_t *)p_stream;
@@ -2703,7 +2749,10 @@ static int transcode_spu_process( sout_stream_t *p_stream,
     *out = NULL;
 
     p_subpic = id->p_decoder->pf_decode_sub( id->p_decoder, &in );
-    if( !p_subpic ) return VLC_EGENERIC;
+    if( !p_subpic )
+        return VLC_EGENERIC;
+
+    sout_UpdateStatistic( p_stream->p_sout, SOUT_STATISTIC_DECODED_SUBTITLE, 1 );
 
     if( p_sys->b_master_sync && p_sys->i_master_drift )
     {
@@ -2721,7 +2770,6 @@ static int transcode_spu_process( sout_stream_t *p_stream,
 
         p_block = id->p_encoder->pf_encode_sub( id->p_encoder, p_subpic );
         spu_del_buffer( id->p_decoder, p_subpic );
-
         if( p_block )
         {
             block_ChainAppend( out, p_block );
@@ -2750,50 +2798,23 @@ static void spu_del_buffer( decoder_t *p_dec, subpicture_t *p_subpic )
 static int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_t *id )
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
-    es_format_t fmt;
 
-    fmt.i_cat = SPU_ES;
-    fmt.i_id = 0xbd1f; /* pid ?? */
-    fmt.i_group = 3;   /* pmt entry ?? */
-    fmt.i_codec = VLC_FOURCC( 'Y', 'U', 'V', 'A' );
-    fmt.psz_language = strdup( "osd" );
-
-    id = malloc( sizeof( sout_stream_id_t ) );
-    memset( id, 0, sizeof(sout_stream_id_t) );
-
-    id->id = NULL;
-    id->p_decoder = NULL;
-    id->p_encoder = NULL;
-
-    /* Create encoder object */
-    id->p_encoder = vlc_object_create( p_stream, VLC_OBJECT_ENCODER );
-    if( !id->p_encoder )
-    {
-        msg_Err( p_stream, "out of memory" );
-        goto error;
-    }
-    vlc_object_attach( id->p_encoder, p_stream );
-    id->p_encoder->p_module = NULL;
-
-    /* Create fake destination format */
-    es_format_Init( &id->p_encoder->fmt_out, fmt.i_cat, 0 );
-    id->p_encoder->fmt_out.i_id    = fmt.i_id;
-    id->p_encoder->fmt_out.i_group = fmt.i_group;
-    id->p_encoder->fmt_out.psz_language = strdup( fmt.psz_language );
+    id->p_decoder->fmt_in.i_cat = SPU_ES;
+    id->p_encoder->fmt_out.psz_language = strdup( "osd" );
 
     if( p_sys->i_osdcodec != 0 || p_sys->psz_osdenc )
     {
         msg_Dbg( p_stream, "creating osdmenu transcoding from fcc=`%4.4s' "
-                 "to fcc=`%4.4s'", (char*)&fmt.i_codec,
+                 "to fcc=`%4.4s'", (char*)&id->p_encoder->fmt_out.i_codec,
                  (char*)&p_sys->i_osdcodec );
 
         /* Complete destination format */
         id->p_encoder->fmt_out.i_codec = p_sys->i_osdcodec;
 
         /* Open encoder */
-        /* Initialization of encoder format structures */
-        es_format_Init( &id->p_encoder->fmt_in, fmt.i_cat, fmt.i_codec );
-        id->p_encoder->fmt_in.psz_language = strdup( fmt.psz_language );
+        es_format_Init( &id->p_encoder->fmt_in, id->p_decoder->fmt_in.i_cat,
+                        VLC_FOURCC('Y','U','V','A') );
+        id->p_encoder->fmt_in.psz_language = strdup( "osd" );
 
         id->p_encoder->p_cfg = p_sys->p_osd_cfg;
 
@@ -2815,41 +2836,26 @@ static int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_t *id )
     else
     {
         msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
-                 (char*)&fmt.i_codec );
-        id->id = p_sys->p_out->pf_add( p_sys->p_out, &fmt );
+                 (char*)&id->p_decoder->fmt_out.i_codec );
+        id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->p_decoder->fmt_out );
         id->b_transcode = VLC_FALSE;
 
         if( !id->id ) goto error;
     }
 
-    p_sys->id_osd = id;
-    p_sys->b_es_osd = VLC_TRUE;
-
     if( !p_sys->p_spu )
     {
         p_sys->p_spu = spu_Create( p_stream );
-        if( spu_Init( p_sys->p_spu ) != VLC_SUCCESS )
-            msg_Err( p_sys, "spu initialisation failed" );
+        spu_Init( p_sys->p_spu );
     }
 
-    if( fmt.psz_language )
-        free( fmt.psz_language );
-
     return VLC_SUCCESS;
 
  error:
     msg_Err( p_stream, "starting osd encoding thread failed" );
     if( id->p_encoder->p_module )
             module_Unneed( id->p_encoder, id->p_encoder->p_module );
-    if( id->p_encoder )
-    {
-        vlc_object_detach( id->p_encoder );
-        vlc_object_destroy( id->p_encoder );
-    }
-    if( fmt.psz_language ) free( fmt.psz_language );
-    if( id ) free( id );
-    p_sys->id_osd = NULL;
-    p_sys->b_es_osd = VLC_FALSE;
+    p_sys->b_osd = VLC_FALSE;
     return VLC_EGENERIC;
 }
 
@@ -2858,21 +2864,12 @@ static void transcode_osd_close( sout_stream_t *p_stream, sout_stream_id_t *id)
     sout_stream_sys_t *p_sys = p_stream->p_sys;
 
     /* Close encoder */
-    if( p_sys->b_es_osd && id )
+    if( p_sys->b_osd && id )
     {
         if( id->p_encoder->p_module )
             module_Unneed( id->p_encoder, id->p_encoder->p_module );
-
-        if( id->id ) p_sys->p_out->pf_del( p_sys->p_out, id->id );
-
-        if( id->p_encoder )
-        {
-            vlc_object_detach( id->p_encoder );
-            vlc_object_destroy( id->p_encoder );
-        }
     }
-    p_sys->b_es_osd = VLC_FALSE;
-    if( id ) free( id );
+    p_sys->b_osd = VLC_FALSE;
 }
 
 static int transcode_osd_process( sout_stream_t *p_stream,
@@ -2893,8 +2890,7 @@ static int transcode_osd_process( sout_stream_t *p_stream,
         if( !p_sys->p_spu )
         {
             p_sys->p_spu = spu_Create( p_stream );
-            if( spu_Init( p_sys->p_spu ) != VLC_SUCCESS )
-                msg_Err( p_stream, "spu initialisation failed" );
+            spu_Init( p_sys->p_spu );
         }
     }
 
@@ -2908,16 +2904,12 @@ static int transcode_osd_process( sout_stream_t *p_stream,
             if( p_subpic->i_stop ) p_subpic->i_stop -= p_sys->i_master_drift;
         }
 
-        p_block = p_sys->id_osd->p_encoder->pf_encode_sub( p_sys->id_osd->p_encoder, p_subpic );
+        p_block = id->p_encoder->pf_encode_sub( id->p_encoder, p_subpic );
+        spu_DestroySubpicture( p_sys->p_spu, p_subpic );
         if( p_block )
         {
             p_block->i_dts = p_block->i_pts = in->i_dts;
             block_ChainAppend( out, p_block );
-            if( *out )
-            {
-                if( p_sys->p_out->pf_send( p_sys->p_out, p_sys->id_osd->id, *out ) == VLC_SUCCESS )
-                    spu_DestroySubpicture( p_sys->p_spu, p_subpic );
-            }
             return VLC_SUCCESS;
         }
     }