]> git.sesse.net Git - vlc/blobdiff - modules/stream_out/transcode.c
Make aout_buffer_t an alias for block_t
[vlc] / modules / stream_out / transcode.c
index e43362aebf9b44401339b45da92777dc3d8eba73..5bd52ad895bb82caa0ad79fa3eca5a00c8424488 100644 (file)
@@ -38,6 +38,7 @@
 #include <vlc_aout.h>
 #include <vlc_vout.h>
 #include <vlc_codec.h>
+#include <vlc_meta.h>
 #include <vlc_block.h>
 #include <vlc_filter.h>
 #include <vlc_osd.h>
@@ -157,84 +158,84 @@ static void Close( vlc_object_t * );
 
 #define SOUT_CFG_PREFIX "sout-transcode-"
 
-vlc_module_begin();
-    set_shortname( N_("Transcode"));
-    set_description( N_("Transcode stream output") );
-    set_capability( "sout stream", 50 );
-    add_shortcut( "transcode" );
-    set_callbacks( Open, Close );
-    set_category( CAT_SOUT );
-    set_subcategory( SUBCAT_SOUT_STREAM );
-    set_section( N_("Video"), NULL );
-    add_string( SOUT_CFG_PREFIX "venc", NULL, NULL, VENC_TEXT,
-                VENC_LONGTEXT, false );
+vlc_module_begin ()
+    set_shortname( N_("Transcode"))
+    set_description( N_("Transcode stream output") )
+    set_capability( "sout stream", 50 )
+    add_shortcut( "transcode" )
+    set_callbacks( Open, Close )
+    set_category( CAT_SOUT )
+    set_subcategory( SUBCAT_SOUT_STREAM )
+    set_section( N_("Video"), NULL )
+    add_module( SOUT_CFG_PREFIX "venc", "encoder", NULL, NULL, VENC_TEXT,
+                VENC_LONGTEXT, false )
     add_string( SOUT_CFG_PREFIX "vcodec", NULL, NULL, VCODEC_TEXT,
-                VCODEC_LONGTEXT, false );
-    add_integer( SOUT_CFG_PREFIX "vb", 800 * 1000, NULL, VB_TEXT,
-                 VB_LONGTEXT, false );
+                VCODEC_LONGTEXT, false )
+    add_integer( SOUT_CFG_PREFIX "vb", 0, NULL, VB_TEXT,
+                 VB_LONGTEXT, false )
     add_float( SOUT_CFG_PREFIX "scale", 1, NULL, SCALE_TEXT,
-               SCALE_LONGTEXT, false );
+               SCALE_LONGTEXT, false )
     add_float( SOUT_CFG_PREFIX "fps", 0, NULL, FPS_TEXT,
-               FPS_LONGTEXT, false );
+               FPS_LONGTEXT, false )
     add_bool( SOUT_CFG_PREFIX "hurry-up", true, NULL, HURRYUP_TEXT,
-               HURRYUP_LONGTEXT, false );
-    add_bool( SOUT_CFG_PREFIX "deinterlace", 0, NULL, DEINTERLACE_TEXT,
-              DEINTERLACE_LONGTEXT, false );
+               HURRYUP_LONGTEXT, false )
+    add_bool( SOUT_CFG_PREFIX "deinterlace", false, NULL, DEINTERLACE_TEXT,
+              DEINTERLACE_LONGTEXT, false )
     add_string( SOUT_CFG_PREFIX "deinterlace-module", "deinterlace", NULL,
                 DEINTERLACE_MODULE_TEXT, DEINTERLACE_MODULE_LONGTEXT,
-                false );
-        change_string_list( ppsz_deinterlace_type, 0, 0 );
+                false )
+        change_string_list( ppsz_deinterlace_type, 0, 0 )
     add_integer( SOUT_CFG_PREFIX "width", 0, NULL, WIDTH_TEXT,
-                 WIDTH_LONGTEXT, true );
+                 WIDTH_LONGTEXT, true )
     add_integer( SOUT_CFG_PREFIX "height", 0, NULL, HEIGHT_TEXT,
-                 HEIGHT_LONGTEXT, true );
+                 HEIGHT_LONGTEXT, true )
     add_integer( SOUT_CFG_PREFIX "maxwidth", 0, NULL, MAXWIDTH_TEXT,
-                 MAXWIDTH_LONGTEXT, true );
+                 MAXWIDTH_LONGTEXT, true )
     add_integer( SOUT_CFG_PREFIX "maxheight", 0, NULL, MAXHEIGHT_TEXT,
-                 MAXHEIGHT_LONGTEXT, true );
+                 MAXHEIGHT_LONGTEXT, true )
     add_module_list( SOUT_CFG_PREFIX "vfilter", "video filter2",
                      NULL, NULL,
-                     VFILTER_TEXT, VFILTER_LONGTEXT, false );
+                     VFILTER_TEXT, VFILTER_LONGTEXT, false )
 
-    set_section( N_("Audio"), NULL );
-    add_string( SOUT_CFG_PREFIX "aenc", NULL, NULL, AENC_TEXT,
-                AENC_LONGTEXT, false );
+    set_section( N_("Audio"), NULL )
+    add_module( SOUT_CFG_PREFIX "aenc", "encoder", NULL, NULL, AENC_TEXT,
+                AENC_LONGTEXT, false )
     add_string( SOUT_CFG_PREFIX "acodec", NULL, NULL, ACODEC_TEXT,
-                ACODEC_LONGTEXT, false );
+                ACODEC_LONGTEXT, false )
     add_integer( SOUT_CFG_PREFIX "ab", 0, NULL, AB_TEXT,
-                 AB_LONGTEXT, false );
+                 AB_LONGTEXT, false )
     add_integer( SOUT_CFG_PREFIX "channels", 0, NULL, ACHANS_TEXT,
-                 ACHANS_LONGTEXT, false );
+                 ACHANS_LONGTEXT, false )
     add_integer( SOUT_CFG_PREFIX "samplerate", 0, NULL, ARATE_TEXT,
-                 ARATE_LONGTEXT, true );
-    add_bool( SOUT_CFG_PREFIX "audio-sync", 0, NULL, ASYNC_TEXT,
-              ASYNC_LONGTEXT, false );
+                 ARATE_LONGTEXT, true )
+    add_bool( SOUT_CFG_PREFIX "audio-sync", false, NULL, ASYNC_TEXT,
+              ASYNC_LONGTEXT, false )
     add_module_list( SOUT_CFG_PREFIX "afilter",  "audio filter2",
                      NULL, NULL,
-                     AFILTER_TEXT, AFILTER_LONGTEXT, false );
+                     AFILTER_TEXT, AFILTER_LONGTEXT, false )
 
-    set_section( N_("Overlays/Subtitles"), NULL );
-    add_string( SOUT_CFG_PREFIX "senc", NULL, NULL, SENC_TEXT,
-                SENC_LONGTEXT, false );
+    set_section( N_("Overlays/Subtitles"), NULL )
+    add_module( SOUT_CFG_PREFIX "senc", "encoder", NULL, NULL, SENC_TEXT,
+                SENC_LONGTEXT, false )
     add_string( SOUT_CFG_PREFIX "scodec", NULL, NULL, SCODEC_TEXT,
-                SCODEC_LONGTEXT, false );
-    add_bool( SOUT_CFG_PREFIX "soverlay", 0, NULL, SCODEC_TEXT,
-               SCODEC_LONGTEXT, false );
+                SCODEC_LONGTEXT, false )
+    add_bool( SOUT_CFG_PREFIX "soverlay", false, NULL, SCODEC_TEXT,
+               SCODEC_LONGTEXT, false )
     add_module_list( SOUT_CFG_PREFIX "sfilter", "video filter",
                      NULL, NULL,
-                     SFILTER_TEXT, SFILTER_LONGTEXT, false );
+                     SFILTER_TEXT, SFILTER_LONGTEXT, false )
 
-    set_section( N_("On Screen Display"), NULL );
-    add_bool( SOUT_CFG_PREFIX "osd", 0, NULL, OSD_TEXT,
-              OSD_LONGTEXT, false );
+    set_section( N_("On Screen Display"), NULL )
+    add_bool( SOUT_CFG_PREFIX "osd", false, NULL, OSD_TEXT,
+              OSD_LONGTEXT, false )
 
-    set_section( N_("Miscellaneous"), NULL );
+    set_section( N_("Miscellaneous"), NULL )
     add_integer( SOUT_CFG_PREFIX "threads", 0, NULL, THREADS_TEXT,
-                 THREADS_LONGTEXT, true );
-    add_bool( SOUT_CFG_PREFIX "high-priority", 0, NULL, HP_TEXT, HP_LONGTEXT,
-              true );
+                 THREADS_LONGTEXT, true )
+    add_bool( SOUT_CFG_PREFIX "high-priority", false, NULL, HP_TEXT, HP_LONGTEXT,
+              true )
 
-vlc_module_end();
+vlc_module_end ()
 
 static const char *const ppsz_sout_options[] = {
     "venc", "vcodec", "vb",
@@ -267,13 +268,10 @@ static int  transcode_video_encoder_open( sout_stream_t *, sout_stream_id_t *);
 static int  transcode_video_process( sout_stream_t *, sout_stream_id_t *,
                                      block_t *, block_t ** );
 
-static void video_del_buffer( vlc_object_t *, picture_t * );
 static picture_t *video_new_buffer_decoder( decoder_t * );
 static void video_del_buffer_decoder( decoder_t *, picture_t * );
 static void video_link_picture_decoder( decoder_t *, picture_t * );
 static void video_unlink_picture_decoder( decoder_t *, picture_t * );
-static picture_t *video_new_buffer_filter( filter_t * );
-static void video_del_buffer_filter( filter_t *, picture_t * );
 
 static int  transcode_spu_new    ( sout_stream_t *, sout_stream_id_t * );
 static void transcode_spu_close  ( sout_stream_id_t * );
@@ -364,12 +362,6 @@ struct sout_stream_sys_t
 
 struct decoder_owner_sys_t
 {
-    picture_t *pp_pics[PICTURE_RING_SIZE];
-    sout_stream_sys_t *p_sys;
-};
-struct filter_owner_sys_t
-{
-    picture_t *pp_pics[PICTURE_RING_SIZE];
     sout_stream_sys_t *p_sys;
 };
 
@@ -432,8 +424,8 @@ static int Open( vlc_object_t *p_this )
 
     if( p_sys->i_acodec )
     {
-        if( p_sys->i_acodec == VLC_FOURCC('m','p','3',0) &&
-            p_sys->i_channels > 2 )
+        if( ( p_sys->i_acodec == VLC_CODEC_MP3 ||
+              p_sys->i_acodec == VLC_CODEC_MPGA ) && p_sys->i_channels > 2 )
         {
             msg_Warn( p_stream, "%d channels invalid for mp3, forcing to 2",
                       p_sys->i_channels );
@@ -597,7 +589,7 @@ static int Open( vlc_object_t *p_this )
                                    &p_sys->p_osd_cfg, strdup( "dvbsub") );
         free( psz_next );
 
-        p_sys->i_osdcodec = VLC_FOURCC('Y','U','V','P' );
+        p_sys->i_osdcodec = VLC_CODEC_YUVP;
 
         msg_Dbg( p_stream, "codec osd=%4.4s", (char *)&p_sys->i_osdcodec );
 
@@ -643,68 +635,23 @@ static void Close( vlc_object_t * p_this )
 
     free( p_sys->psz_af2 );
 
-    while( p_sys->p_audio_cfg != NULL )
-    {
-        config_chain_t *p_next = p_sys->p_audio_cfg->p_next;
-
-        free( p_sys->p_audio_cfg->psz_name );
-        free( p_sys->p_audio_cfg->psz_value );
-        free( p_sys->p_audio_cfg );
-
-        p_sys->p_audio_cfg = p_next;
-    }
+    config_ChainDestroy( p_sys->p_audio_cfg );
     free( p_sys->psz_aenc );
 
     free( p_sys->psz_vf2 );
 
-    while( p_sys->p_video_cfg != NULL )
-    {
-        config_chain_t *p_next = p_sys->p_video_cfg->p_next;
-
-        free( p_sys->p_video_cfg->psz_name );
-        free( p_sys->p_video_cfg->psz_value );
-        free( p_sys->p_video_cfg );
-
-        p_sys->p_video_cfg = p_next;
-    }
+    config_ChainDestroy( p_sys->p_video_cfg );
     free( p_sys->psz_venc );
 
-    while( p_sys->p_deinterlace_cfg != NULL )
-    {
-        config_chain_t *p_next = p_sys->p_deinterlace_cfg->p_next;
-
-        free( p_sys->p_deinterlace_cfg->psz_name );
-        free( p_sys->p_deinterlace_cfg->psz_value );
-        free( p_sys->p_deinterlace_cfg );
-
-        p_sys->p_deinterlace_cfg = p_next;
-    }
+    config_ChainDestroy( p_sys->p_deinterlace_cfg );
     free( p_sys->psz_deinterlace );
 
-    while( p_sys->p_spu_cfg != NULL )
-    {
-        config_chain_t *p_next = p_sys->p_spu_cfg->p_next;
-
-        free( p_sys->p_spu_cfg->psz_name );
-        free( p_sys->p_spu_cfg->psz_value );
-        free( p_sys->p_spu_cfg );
-
-        p_sys->p_spu_cfg = p_next;
-    }
+    config_ChainDestroy( p_sys->p_spu_cfg );
     free( p_sys->psz_senc );
 
     if( p_sys->p_spu ) spu_Destroy( p_sys->p_spu );
 
-    while( p_sys->p_osd_cfg != NULL )
-    {
-        config_chain_t *p_next = p_sys->p_osd_cfg->p_next;
-
-        free( p_sys->p_osd_cfg->psz_name );
-        free( p_sys->p_osd_cfg->psz_value );
-        free( p_sys->p_osd_cfg );
-
-        p_sys->p_osd_cfg = p_next;
-    }
+    config_ChainDestroy( p_sys->p_osd_cfg );
     free( p_sys->psz_osdenc );
 
     vlc_object_release( p_sys );
@@ -712,7 +659,7 @@ static void Close( vlc_object_t * p_this )
 
 struct sout_stream_id_t
 {
-    vlc_fourcc_t  b_transcode;
+    bool            b_transcode;
 
     /* id of the out stream */
     void *id;
@@ -737,10 +684,9 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
     sout_stream_sys_t *p_sys = p_stream->p_sys;
     sout_stream_id_t *id;
 
-    id = malloc( sizeof( sout_stream_id_t ) );
+    id = calloc( 1, sizeof( sout_stream_id_t ) );
     if( !id )
         goto error;
-    memset( id, 0, sizeof(sout_stream_id_t) );
 
     id->id = NULL;
     id->p_decoder = NULL;
@@ -756,7 +702,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
     id->p_decoder->b_pace_control = true;
 
     /* Create encoder object */
-    id->p_encoder = vlc_object_create( p_stream, VLC_OBJECT_ENCODER );
+    id->p_encoder = sout_EncoderCreate( p_stream );
     if( !id->p_encoder )
         goto error;
     vlc_object_attach( id->p_encoder, p_stream );
@@ -810,7 +756,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
         }
 
         /* Open output stream */
-        id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->p_encoder->fmt_out );
+        id->id = sout_StreamIdAdd( p_sys->p_out, &id->p_encoder->fmt_out );
         id->b_transcode = true;
 
         if( !id->id )
@@ -871,7 +817,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
         }
 
         /* open output stream */
-        id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->p_encoder->fmt_out );
+        id->id = sout_StreamIdAdd( p_sys->p_out, &id->p_encoder->fmt_out );
         id->b_transcode = true;
 
         if( !id->id )
@@ -914,7 +860,7 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
     {
         msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
                  (char*)&p_fmt->i_codec );
-        id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
+        id->id = sout_StreamIdAdd( p_sys->p_out, p_fmt );
         id->b_transcode = false;
 
         if( !id->id ) goto error;
@@ -968,7 +914,7 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
         }
     }
 
-    if( id->id ) p_sys->p_out->pf_del( p_sys->p_out, id->id );
+    if( id->id ) sout_StreamIdDel( p_sys->p_out, id->id );
 
     if( id->p_decoder )
     {
@@ -995,12 +941,11 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
     sout_stream_sys_t *p_sys = p_stream->p_sys;
     block_t *p_out = NULL;
 
-    if( !id->b_transcode && id->id )
-    {
-        return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
-    }
-    else if( !id->b_transcode )
+    if( !id->b_transcode )
     {
+        if( id->id )
+            return sout_StreamIdSend( p_sys->p_out, id->id, p_buffer );
+
         block_Release( p_buffer );
         return VLC_EGENERIC;
     }
@@ -1042,7 +987,8 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
         break;
     }
 
-    if( p_out ) return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_out );
+    if( p_out )
+        return sout_StreamIdSend( p_sys->p_out, id->id, p_out );
     return VLC_SUCCESS;
 }
 
@@ -1101,12 +1047,107 @@ static int transcode_audio_filter_allocation_init( filter_t *p_filter,
     return VLC_SUCCESS;
 }
 
+static bool transcode_audio_filter_needed( const es_format_t *p_fmt1, const es_format_t *p_fmt2 )
+{
+    if( p_fmt1->i_codec != p_fmt2->i_codec ||
+        p_fmt1->audio.i_channels != p_fmt2->audio.i_channels ||
+        p_fmt1->audio.i_rate != p_fmt2->audio.i_rate )
+        return true;
+    return false;
+}
+static int transcode_audio_filter_chain_build( sout_stream_t *p_stream, filter_chain_t *p_chain,
+                                               const es_format_t *p_dst, const es_format_t *p_src )
+{
+    if( !transcode_audio_filter_needed( p_dst, p_src ) )
+        return VLC_SUCCESS;
+
+    es_format_t current = *p_src;
+
+    msg_Dbg( p_stream, "Looking for filter "
+             "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)",
+         (const char *)&p_src->i_codec,
+         (const char *)&p_dst->i_codec,
+         p_src->audio.i_channels,
+         p_dst->audio.i_channels,
+         p_src->audio.i_rate,
+         p_dst->audio.i_rate );
+
+    /* If any filter is needed, convert to fl32 */
+    if( current.i_codec != VLC_CODEC_FL32 )
+    {
+        /* First step, convert to fl32 */
+        current.i_codec =
+        current.audio.i_format = VLC_CODEC_FL32;
+
+        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
+        {
+            msg_Err( p_stream, "Failed to find conversion filter to fl32" );
+            return VLC_EGENERIC;
+        }
+        current = *filter_chain_GetFmtOut( p_chain );
+    }
+
+    /* Fix sample rate */
+    if( current.audio.i_rate != p_dst->audio.i_rate )
+    {
+        current.audio.i_rate = p_dst->audio.i_rate;
+        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
+        {
+            msg_Err( p_stream, "Failed to find conversion filter for resampling" );
+            return VLC_EGENERIC;
+        }
+        current = *filter_chain_GetFmtOut( p_chain );
+    }
+
+    /* Fix channels */
+    if( current.audio.i_channels != p_dst->audio.i_channels )
+    {
+        current.audio.i_channels = p_dst->audio.i_channels;
+        current.audio.i_physical_channels = p_dst->audio.i_physical_channels;
+        current.audio.i_original_channels = p_dst->audio.i_original_channels;
+
+        if( ( !current.audio.i_physical_channels || !current.audio.i_original_channels ) &&
+            current.audio.i_channels < 6 )
+            current.audio.i_physical_channels =
+            current.audio.i_original_channels = pi_channels_maps[current.audio.i_channels];
+
+        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
+        {
+            msg_Err( p_stream, "Failed to find conversion filter for channel mixing" );
+            return VLC_EGENERIC;
+        }
+        current = *filter_chain_GetFmtOut( p_chain );
+    }
+
+    /* And last step, convert to the requested codec */
+    if( current.i_codec != p_dst->i_codec )
+    {
+        current.i_codec = p_dst->i_codec;
+        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
+        {
+            msg_Err( p_stream, "Failed to find conversion filter to %4.4s",
+                     (const char*)&p_dst->i_codec);
+            return VLC_EGENERIC;
+        }
+        current = *filter_chain_GetFmtOut( p_chain );
+    }
+
+    if( transcode_audio_filter_needed( p_dst, &current ) )
+    {
+        /* Weird case, a filter has side effects, doomed */
+        msg_Err( p_stream, "Failed to create a valid audio filter chain" );
+        return VLC_EGENERIC;
+    }
+
+    msg_Dbg( p_stream, "Got complete audio filter chain" );
+    return VLC_SUCCESS;
+}
+
 static int transcode_audio_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_last;
-    int i;
 
     /*
      * Open decoder
@@ -1122,7 +1163,7 @@ static int transcode_audio_new( sout_stream_t *p_stream,
     /* id->p_decoder->p_cfg = p_sys->p_audio_cfg; */
 
     id->p_decoder->p_module =
-        module_Need( id->p_decoder, "decoder", "$codec", 0 );
+        module_need( id->p_decoder, "decoder", "$codec", false );
     if( !id->p_decoder->p_module )
     {
         msg_Err( p_stream, "cannot find audio decoder" );
@@ -1132,7 +1173,7 @@ static int transcode_audio_new( sout_stream_t *p_stream,
         aout_BitsPerSample( id->p_decoder->fmt_out.i_codec );
     fmt_last = id->p_decoder->fmt_out;
     /* Fix AAC SBR changing number of channels and sampling rate */
-    if( !(id->p_decoder->fmt_in.i_codec == VLC_FOURCC('m','p','4','a') &&
+    if( !(id->p_decoder->fmt_in.i_codec == VLC_CODEC_MP4A &&
         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;
@@ -1158,13 +1199,13 @@ static int transcode_audio_new( sout_stream_t *p_stream,
 
     id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg;
     id->p_encoder->p_module =
-        module_Need( id->p_encoder, "encoder", p_sys->psz_aenc, true );
+        module_need( id->p_encoder, "encoder", p_sys->psz_aenc, true );
     if( !id->p_encoder->p_module )
     {
         msg_Err( p_stream, "cannot find audio encoder (module:%s fourcc:%4.4s)",
                  p_sys->psz_aenc ? p_sys->psz_aenc : "any",
                  (char *)&p_sys->i_acodec );
-        module_Unneed( id->p_decoder, id->p_decoder->p_module );
+        module_unneed( id->p_decoder, id->p_decoder->p_module );
         id->p_decoder->p_module = NULL;
         return VLC_EGENERIC;
     }
@@ -1172,141 +1213,43 @@ static int transcode_audio_new( sout_stream_t *p_stream,
     id->p_encoder->fmt_in.audio.i_bitspersample =
         aout_BitsPerSample( id->p_encoder->fmt_in.i_codec );
 
-    /* Init filter chain */
-    id->p_f_chain = filter_chain_New( p_stream, "audio filter2", true,
-                    transcode_audio_filter_allocation_init, NULL, NULL );
-    filter_chain_Reset( id->p_f_chain, &fmt_last, &id->p_encoder->fmt_in );
-
-    /* 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 )
-    {
-        /* We'll have to go through fl32 first */
-        fmt_last.i_codec = fmt_last.audio.i_format = VLC_FOURCC('f','l','3','2');
-        fmt_last.audio.i_bitspersample = aout_BitsPerSample( fmt_last.i_codec );
-        filter_chain_AppendFilter( id->p_f_chain, NULL, NULL, NULL, &fmt_last );
-        fmt_last = *filter_chain_GetFmtOut( id->p_f_chain );
-    }
-
-    for( i = 0; i < 4; i++ )
-    {
-        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) ||
-            (fmt_last.i_codec != id->p_encoder->fmt_in.i_codec) )
-        {
-            msg_Dbg( p_stream, "Looking for filter "
-                     "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)",
-                 (char *)&fmt_last.i_codec,
-                 (char *)&id->p_encoder->fmt_in.i_codec,
-                 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 );
-            filter_chain_AppendFilter( id->p_f_chain, NULL, NULL,
-                                       &fmt_last, &id->p_encoder->fmt_in );
-            fmt_last = *filter_chain_GetFmtOut( id->p_f_chain );
-        }
-        else break;
-    }
-
-    /* Final checks to see if conversions were successful */
-    if( fmt_last.i_codec != id->p_encoder->fmt_in.i_codec )
-    {
-        msg_Err( p_stream, "no audio filter found "
-                           "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)",
-                 (char *)&fmt_last.i_codec,
-                 (char *)&id->p_encoder->fmt_in.i_codec,
-                 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 );
-        transcode_audio_close( id );
-        return VLC_EGENERIC;
-    }
-
-    /* Load user specified audio filters now */
+    /* Load user specified audio filters */
     if( p_sys->psz_af2 )
     {
-        id->p_uf_chain = filter_chain_New( p_stream, "audio filter2", false,
-                       transcode_audio_filter_allocation_init, NULL, NULL );
-        filter_chain_Reset( id->p_uf_chain, &fmt_last, &id->p_encoder->fmt_in );
-        filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_af2 );
-        fmt_last = *filter_chain_GetFmtOut( id->p_uf_chain );
-    }
-
-    if( fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels )
-    {
-#if 1
-        module_Unneed( id->p_encoder, id->p_encoder->p_module );
-        id->p_encoder->p_module = NULL;
-
-        /* This might work, but only if the encoder is restarted */
-        id->p_encoder->fmt_in.audio.i_channels = fmt_last.audio.i_channels;
-        id->p_encoder->fmt_out.audio.i_channels = fmt_last.audio.i_channels;
-
-        id->p_encoder->fmt_in.audio.i_physical_channels =
-            id->p_encoder->fmt_in.audio.i_original_channels =
-                fmt_last.audio.i_physical_channels;
-        id->p_encoder->fmt_out.audio.i_physical_channels =
-            id->p_encoder->fmt_out.audio.i_original_channels =
-                fmt_last.audio.i_physical_channels;
-
-        msg_Dbg( p_stream, "number of audio channels for mixing changed, "
-                 "trying to reopen the encoder for mixing %i to %i channels",
-                 fmt_last.audio.i_channels,
-                 id->p_encoder->fmt_in.audio.i_channels );
-
-        /* reload encoder */
-        id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg;
-        id->p_encoder->p_module =
-            module_Need( id->p_encoder, "encoder", p_sys->psz_aenc, true );
-        if( !id->p_encoder->p_module ||
-            fmt_last.audio.i_channels != id->p_encoder->fmt_in.audio.i_channels  ||
-            fmt_last.i_codec != id->p_encoder->fmt_in.i_codec )
+        es_format_t fmt_fl32 = fmt_last;
+        fmt_fl32.i_codec =
+        fmt_fl32.audio.i_format = VLC_CODEC_FL32;
+        if( transcode_audio_filter_chain_build( p_stream, id->p_uf_chain,
+                                                &fmt_fl32, &fmt_last ) )
         {
-            if( id->p_encoder->p_module )
-            {
-                module_Unneed( id->p_encoder, id->p_encoder->p_module );
-                id->p_encoder->p_module = NULL;
-            }
-            msg_Err( p_stream, "cannot find audio encoder (module:%s fourcc:%4.4s)",
-                     p_sys->psz_aenc ? p_sys->psz_aenc : "any",
-                     (char *)&p_sys->i_acodec );
             transcode_audio_close( id );
             return VLC_EGENERIC;
         }
-        id->p_encoder->fmt_in.audio.i_format = id->p_encoder->fmt_in.i_codec;
-        id->p_encoder->fmt_in.audio.i_bitspersample =
-            aout_BitsPerSample( id->p_encoder->fmt_in.i_codec );
-#else
-        msg_Err( p_stream, "no audio filter found for mixing from"
-                 " %i to %i channels", fmt_last.audio.i_channels,
-                 id->p_encoder->fmt_in.audio.i_channels );
+        fmt_last = fmt_fl32;
 
-        transcode_audio_close( id );
-        return VLC_EGENERIC;
-#endif
+        id->p_uf_chain = filter_chain_New( p_stream, "audio filter2", false,
+                                           transcode_audio_filter_allocation_init, NULL, NULL );
+        filter_chain_Reset( id->p_uf_chain, &fmt_last, &fmt_fl32 );
+        if( filter_chain_AppendFromString( id->p_uf_chain, p_sys->psz_af2 ) > 0 )
+            fmt_last = *filter_chain_GetFmtOut( id->p_uf_chain );
     }
 
-    if( fmt_last.audio.i_rate != id->p_encoder->fmt_in.audio.i_rate )
+    /* Load conversion filters */
+    id->p_f_chain = filter_chain_New( p_stream, "audio filter2", true,
+                    transcode_audio_filter_allocation_init, NULL, NULL );
+    filter_chain_Reset( id->p_f_chain, &fmt_last, &id->p_encoder->fmt_in );
+
+    if( transcode_audio_filter_chain_build( p_stream, id->p_f_chain,
+                                            &id->p_encoder->fmt_in, &fmt_last ) )
     {
-        msg_Err( p_stream, "no audio filter found for resampling from"
-                 " %iHz to %iHz", fmt_last.audio.i_rate,
-                 id->p_encoder->fmt_in.audio.i_rate );
-#if 0
-        /* FIXME : this might work, but only if the encoder is restarted */
-        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;
-#else
         transcode_audio_close( id );
         return VLC_EGENERIC;
-#endif
     }
+    fmt_last = id->p_encoder->fmt_in;
 
-    /* FIXME: Hack for mp3 transcoding support */
-    if( id->p_encoder->fmt_out.i_codec == VLC_FOURCC( 'm','p','3',' ' ) )
-        id->p_encoder->fmt_out.i_codec = VLC_FOURCC( 'm','p','g','a' );
+    /* */
+    id->p_encoder->fmt_out.i_codec =
+        vlc_fourcc_GetCodec( AUDIO_ES, id->p_encoder->fmt_out.i_codec );
 
     return VLC_SUCCESS;
 }
@@ -1317,19 +1260,23 @@ static void transcode_audio_close( sout_stream_id_t *id )
 
     /* Close decoder */
     if( id->p_decoder->p_module )
-        module_Unneed( id->p_decoder, id->p_decoder->p_module );
+        module_unneed( id->p_decoder, id->p_decoder->p_module );
     id->p_decoder->p_module = NULL;
 
+    if( id->p_decoder->p_description )
+        vlc_meta_Delete( id->p_decoder->p_description );
+    id->p_decoder->p_description = NULL;
+
     /* Close encoder */
     if( id->p_encoder->p_module )
-        module_Unneed( id->p_encoder, id->p_encoder->p_module );
+        module_unneed( id->p_encoder, id->p_encoder->p_module );
     id->p_encoder->p_module = NULL;
 
     /* Close filters */
-    if( id->p_f_chain )
-        filter_chain_Delete( id->p_f_chain );
     if( id->p_uf_chain )
         filter_chain_Delete( id->p_uf_chain );
+    if( id->p_f_chain )
+        filter_chain_Delete( id->p_f_chain );
 }
 
 static int transcode_audio_process( sout_stream_t *p_stream,
@@ -1337,8 +1284,7 @@ static int transcode_audio_process( sout_stream_t *p_stream,
                                     block_t *in, block_t **out )
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
-    aout_buffer_t *p_audio_buf;
-    block_t *p_block, *p_audio_block;
+    block_t *p_block, *p_audio_buf;
     *out = NULL;
 
     while( (p_audio_buf = id->p_decoder->pf_decode_audio( id->p_decoder,
@@ -1348,60 +1294,48 @@ static int transcode_audio_process( sout_stream_t *p_stream,
         if( p_sys->b_master_sync )
         {
             mtime_t i_dts = date_Get( &id->interpolated_pts ) + 1;
-            if ( p_audio_buf->start_date - i_dts > MASTER_SYNC_MAX_DRIFT
-                  || p_audio_buf->start_date - i_dts < -MASTER_SYNC_MAX_DRIFT )
+            if ( p_audio_buf->i_pts - i_dts > MASTER_SYNC_MAX_DRIFT
+                  || p_audio_buf->i_pts - i_dts < -MASTER_SYNC_MAX_DRIFT )
             {
                 msg_Dbg( p_stream, "drift is too high, resetting master sync" );
-                date_Set( &id->interpolated_pts, p_audio_buf->start_date );
-                i_dts = p_audio_buf->start_date + 1;
+                date_Set( &id->interpolated_pts, p_audio_buf->i_pts );
+                i_dts = p_audio_buf->i_pts + 1;
             }
-            p_sys->i_master_drift = p_audio_buf->start_date - i_dts;
+            p_sys->i_master_drift = p_audio_buf->i_pts - i_dts;
             date_Increment( &id->interpolated_pts, p_audio_buf->i_nb_samples );
-            p_audio_buf->start_date -= p_sys->i_master_drift;
-            p_audio_buf->end_date -= p_sys->i_master_drift;
+            p_audio_buf->i_pts -= p_sys->i_master_drift;
         }
 
-        p_audio_block = p_audio_buf->p_sys;
-        p_audio_block->i_buffer = p_audio_buf->i_nb_bytes;
-        p_audio_block->i_dts = p_audio_block->i_pts =
-            p_audio_buf->start_date;
-        p_audio_block->i_length = p_audio_buf->end_date -
-            p_audio_buf->start_date;
-        p_audio_block->i_samples = p_audio_buf->i_nb_samples;
+        p_audio_buf->i_dts = p_audio_buf->i_pts;
 
         /* Run filter chain */
-        p_audio_block = filter_chain_AudioFilter( id->p_f_chain, p_audio_block );
         if( id->p_uf_chain )
-            p_audio_block = filter_chain_AudioFilter( id->p_uf_chain, p_audio_block );
-        assert( p_audio_block );
+        {
+            p_audio_buf = filter_chain_AudioFilter( id->p_uf_chain,
+                                                    p_audio_buf );
+            if( !p_audio_buf )
+                abort();
+        }
+
+        p_audio_buf = filter_chain_AudioFilter( id->p_f_chain, p_audio_buf );
+        if( !p_audio_buf )
+            abort();
 
-        p_audio_buf->p_buffer = p_audio_block->p_buffer;
-        p_audio_buf->i_nb_bytes = p_audio_block->i_buffer;
-        p_audio_buf->i_nb_samples = p_audio_block->i_samples;
-        p_audio_buf->start_date = p_audio_block->i_dts;
-        p_audio_buf->end_date = p_audio_block->i_dts + p_audio_block->i_length;
+        p_audio_buf->i_pts = p_audio_buf->i_dts;
 
         audio_timer_start( id->p_encoder );
         p_block = id->p_encoder->pf_encode_audio( id->p_encoder, p_audio_buf );
         audio_timer_stop( id->p_encoder );
 
         block_ChainAppend( out, p_block );
-        block_Release( p_audio_block );
-        free( p_audio_buf );
+        block_Release( p_audio_buf );
     }
 
     return VLC_SUCCESS;
 }
 
-static void audio_release_buffer( aout_buffer_t *p_buffer )
-{
-    if( p_buffer && p_buffer->p_sys ) block_Release( p_buffer->p_sys );
-    free( p_buffer );
-}
-
 static aout_buffer_t *audio_new_buffer( decoder_t *p_dec, int i_samples )
 {
-    aout_buffer_t *p_buffer;
     block_t *p_block;
     int i_size;
 
@@ -1421,69 +1355,52 @@ static aout_buffer_t *audio_new_buffer( decoder_t *p_dec, int i_samples )
         i_size = i_samples * 4 * p_dec->fmt_out.audio.i_channels;
     }
 
-    p_buffer = malloc( sizeof(aout_buffer_t) );
-    if( !p_buffer ) return NULL;
-    p_buffer->b_discontinuity = false;
-    p_buffer->pf_release = audio_release_buffer;
-    p_buffer->p_sys = p_block = block_New( p_dec, i_size );
-
-    p_buffer->p_buffer = p_block->p_buffer;
-    p_buffer->i_size = p_buffer->i_nb_bytes = p_block->i_buffer;
-    p_buffer->i_nb_samples = i_samples;
-    p_block->i_samples = i_samples;
-
-    return p_buffer;
+    p_block = block_New( p_dec, i_size );
+    p_block->i_nb_samples = i_samples;
+    return p_block;
 }
 
 static void audio_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer )
 {
     VLC_UNUSED(p_dec);
-    if( p_buffer && p_buffer->p_sys ) block_Release( p_buffer->p_sys );
-    free( p_buffer );
+    block_Release( p_buffer );
 }
 
 /*
  * video
  */
 
+static picture_t *transcode_video_filter_buffer_new( filter_t *p_filter )
+{
+    p_filter->fmt_out.video.i_chroma = p_filter->fmt_out.i_codec;
+    return picture_New( p_filter->fmt_out.video.i_chroma,
+                        p_filter->fmt_out.video.i_width,
+                        p_filter->fmt_out.video.i_height,
+                        p_filter->fmt_out.video.i_aspect );
+}
+static void transcode_video_filter_buffer_del( filter_t *p_filter, picture_t *p_pic )
+{
+    VLC_UNUSED(p_filter);
+    picture_Release( p_pic );
+}
+
 static int transcode_video_filter_allocation_init( filter_t *p_filter,
                                                    void *p_data )
 {
-    sout_stream_sys_t *p_sys = (sout_stream_sys_t*)p_data;
-    int i;
-
-    p_filter->pf_vout_buffer_new = video_new_buffer_filter;
-    p_filter->pf_vout_buffer_del = video_del_buffer_filter;
-
-    p_filter->p_owner = malloc( sizeof(filter_owner_sys_t) );
-    if( !p_filter->p_owner )
-        return VLC_EGENERIC;
-
-    for( i = 0; i < PICTURE_RING_SIZE; i++ )
-        p_filter->p_owner->pp_pics[i] = 0;
-    p_filter->p_owner->p_sys = p_sys;
-
+    VLC_UNUSED(p_data);
+    p_filter->pf_vout_buffer_new = transcode_video_filter_buffer_new;
+    p_filter->pf_vout_buffer_del = transcode_video_filter_buffer_del;
     return VLC_SUCCESS;
 }
 
 static void transcode_video_filter_allocation_clear( filter_t *p_filter )
 {
-    int j;
-
-    /* Clean-up pictures ring buffer */
-    for( j = 0; j < PICTURE_RING_SIZE; j++ )
-    {
-        if( p_filter->p_owner->pp_pics[j] )
-            video_del_buffer( VLC_OBJECT(p_filter),
-                              p_filter->p_owner->pp_pics[j] );
-    }
-    free( p_filter->p_owner );
+    VLC_UNUSED(p_filter);
 }
 
 static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
-    int i;
 
     /* Open decoder
      * Initialization of decoder structures
@@ -1502,13 +1419,11 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
     if( !id->p_decoder->p_owner )
         return VLC_EGENERIC;
 
-    for( i = 0; i < PICTURE_RING_SIZE; i++ )
-        id->p_decoder->p_owner->pp_pics[i] = 0;
     id->p_decoder->p_owner->p_sys = p_sys;
     /* id->p_decoder->p_cfg = p_sys->p_video_cfg; */
 
     id->p_decoder->p_module =
-        module_Need( id->p_decoder, "decoder", "$codec", 0 );
+        module_need( id->p_decoder, "decoder", "$codec", false );
 
     if( !id->p_decoder->p_module )
     {
@@ -1532,11 +1447,15 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
     /* The dimensions will be set properly later on.
      * Just put sensible values so we can test an encoder is available. */
     id->p_encoder->fmt_in.video.i_width =
-        id->p_encoder->fmt_out.video.i_width ?:
-        id->p_decoder->fmt_in.video.i_width ?: 16;
+        id->p_encoder->fmt_out.video.i_width
+          ? id->p_encoder->fmt_out.video.i_width
+          : id->p_decoder->fmt_in.video.i_width
+            ? id->p_decoder->fmt_in.video.i_width : 16;
     id->p_encoder->fmt_in.video.i_height =
-        id->p_encoder->fmt_out.video.i_height ?:
-        id->p_decoder->fmt_in.video.i_height ?: 16;
+        id->p_encoder->fmt_out.video.i_height
+          ? id->p_encoder->fmt_out.video.i_height
+          : id->p_decoder->fmt_in.video.i_height
+            ? id->p_decoder->fmt_in.video.i_height : 16;
     id->p_encoder->fmt_in.video.i_frame_rate = ENC_FRAMERATE;
     id->p_encoder->fmt_in.video.i_frame_rate_base = ENC_FRAMERATE_BASE;
 
@@ -1544,13 +1463,13 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
     id->p_encoder->p_cfg = p_sys->p_video_cfg;
 
     id->p_encoder->p_module =
-        module_Need( id->p_encoder, "encoder", p_sys->psz_venc, true );
+        module_need( id->p_encoder, "encoder", p_sys->psz_venc, true );
     if( !id->p_encoder->p_module )
     {
         msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s)",
                  p_sys->psz_venc ? p_sys->psz_venc : "any",
                  (char *)&p_sys->i_vcodec );
-        module_Unneed( id->p_decoder, id->p_decoder->p_module );
+        module_unneed( id->p_decoder, id->p_decoder->p_module );
         id->p_decoder->p_module = 0;
         free( id->p_decoder->p_owner );
         return VLC_EGENERIC;
@@ -1558,7 +1477,7 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
 
     /* Close the encoder.
      * We'll open it only when we have the first frame. */
-    module_Unneed( id->p_encoder, id->p_encoder->p_module );
+    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 );
@@ -1573,17 +1492,16 @@ static int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_t *id )
                            VLC_THREAD_PRIORITY_VIDEO;
         p_sys->id_video = id;
         vlc_mutex_init( &p_sys->lock_out );
-        vlc_cond_init( p_stream, &p_sys->cond );
+        vlc_cond_init( &p_sys->cond );
         memset( p_sys->pp_pics, 0, sizeof(p_sys->pp_pics) );
         p_sys->i_first_pic = 0;
         p_sys->i_last_pic = 0;
         p_sys->p_buffers = NULL;
         p_sys->b_die = p_sys->b_error = 0;
-        if( vlc_thread_create( p_sys, "encoder", EncoderThread, i_priority,
-                               false ) )
+        if( vlc_thread_create( p_sys, "encoder", EncoderThread, i_priority ) )
         {
             msg_Err( p_stream, "cannot spawn encoder thread" );
-            module_Unneed( id->p_decoder, id->p_decoder->p_module );
+            module_unneed( id->p_decoder, id->p_decoder->p_module );
             id->p_decoder->p_module = 0;
             free( id->p_decoder->p_owner );
             return VLC_EGENERIC;
@@ -1765,7 +1683,7 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream,
              id->p_encoder->fmt_in.video.i_height );
 
     id->p_encoder->p_module =
-        module_Need( id->p_encoder, "encoder", p_sys->psz_venc, true );
+        module_need( id->p_encoder, "encoder", p_sys->psz_venc, true );
     if( !id->p_encoder->p_module )
     {
         msg_Err( p_stream, "cannot find video encoder (module:%s fourcc:%4.4s)",
@@ -1776,15 +1694,12 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream,
 
     id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec;
 
-    /* Hack for mp2v/mp1v transcoding support */
-    if( id->p_encoder->fmt_out.i_codec == VLC_FOURCC('m','p','1','v') ||
-        id->p_encoder->fmt_out.i_codec == VLC_FOURCC('m','p','2','v') )
-    {
-        id->p_encoder->fmt_out.i_codec = VLC_FOURCC('m','p','g','v');
-    }
+    /*  */
+    id->p_encoder->fmt_out.i_codec =
+        vlc_fourcc_GetCodec( VIDEO_ES, id->p_encoder->fmt_out.i_codec );
 
-    id->id = p_stream->p_sys->p_out->pf_add( p_stream->p_sys->p_out,
-                                             &id->p_encoder->fmt_out );
+    id->id = sout_StreamIdAdd( p_stream->p_sys->p_out,
+                               &id->p_encoder->fmt_out );
     if( !id->id )
     {
         msg_Err( p_stream, "cannot add this stream" );
@@ -1797,8 +1712,6 @@ static int transcode_video_encoder_open( sout_stream_t *p_stream,
 static void transcode_video_close( sout_stream_t *p_stream,
                                    sout_stream_id_t *id )
 {
-    int i;
-
     if( p_stream->p_sys->i_threads >= 1 )
     {
         vlc_mutex_lock( &p_stream->p_sys->lock_out );
@@ -1814,23 +1727,15 @@ static void transcode_video_close( sout_stream_t *p_stream,
 
     /* Close decoder */
     if( id->p_decoder->p_module )
-        module_Unneed( id->p_decoder, id->p_decoder->p_module );
+        module_unneed( id->p_decoder, id->p_decoder->p_module );
+    if( id->p_decoder->p_description )
+        vlc_meta_Delete( id->p_decoder->p_description );
 
-    if( id->p_decoder->p_owner )
-    {
-        /* Clean-up pictures ring buffer */
-        for( i = 0; i < PICTURE_RING_SIZE; i++ )
-        {
-            if( id->p_decoder->p_owner->pp_pics[i] )
-                video_del_buffer( VLC_OBJECT(id->p_decoder),
-                                  id->p_decoder->p_owner->pp_pics[i] );
-        }
-        free( id->p_decoder->p_owner );
-    }
+    free( id->p_decoder->p_owner );
 
     /* Close encoder */
     if( id->p_encoder->p_module )
-        module_Unneed( id->p_encoder, id->p_encoder->p_module );
+        module_unneed( id->p_encoder, id->p_encoder->p_module );
 
     /* Close filters */
     if( id->p_f_chain )
@@ -1861,7 +1766,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
             {
                 msg_Dbg( p_stream, "late picture skipped (%"PRId64")",
                          current_date + 50000 - p_pic->date );
-                p_pic->pf_release( p_pic );
+                picture_Release( p_pic );
                 continue;
             }
         }
@@ -1892,7 +1797,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
                 msg_Dbg( p_stream, "dropping frame (%i)",
                          (int)(i_video_drift - i_master_drift) );
 #endif
-                p_pic->pf_release( p_pic );
+                picture_Release( p_pic );
                 continue;
             }
             else if( i_video_drift > (i_master_drift + 50000) )
@@ -1962,7 +1867,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
 
             if( transcode_video_encoder_open( p_stream, id ) != VLC_SUCCESS )
             {
-                p_pic->pf_release( p_pic );
+                picture_Release( p_pic );
                 transcode_video_close( p_stream, id );
                 id->b_transcode = false;
                 return VLC_EGENERIC;
@@ -1980,30 +1885,23 @@ static int transcode_video_process( sout_stream_t *p_stream,
         /* Check if we have a subpicture to overlay */
         if( p_sys->p_spu )
         {
-            p_subpic = spu_SortSubpictures( p_sys->p_spu, p_pic->date,
-                       false /* Fixme: check if stream is paused */ );
+            p_subpic = spu_SortSubpictures( p_sys->p_spu, p_pic->date, false );
             /* TODO: get another pic */
         }
 
         /* Overlay subpicture */
         if( p_subpic )
         {
-            int i_scale_width, i_scale_height;
             video_format_t fmt;
 
-            i_scale_width = id->p_encoder->fmt_in.video.i_width * 1000 /
-                id->p_decoder->fmt_out.video.i_width;
-            i_scale_height = id->p_encoder->fmt_in.video.i_height * 1000 /
-                id->p_decoder->fmt_out.video.i_height;
-
-            if( p_pic->i_refcount && !filter_chain_GetLength( id->p_f_chain ) )
+            if( picture_IsReferenced( p_pic ) && !filter_chain_GetLength( id->p_f_chain ) )
             {
                 /* We can't modify the picture, we need to duplicate it */
                 picture_t *p_tmp = video_new_buffer_decoder( id->p_decoder );
                 if( p_tmp )
                 {
-                    vout_CopyPicture( p_stream, p_tmp, p_pic );
-                    p_pic->pf_release( p_pic );
+                    picture_Copy( p_tmp, p_pic );
+                    picture_Release( p_pic );
                     p_pic = p_tmp;
                 }
             }
@@ -2017,8 +1915,9 @@ static int transcode_video_process( sout_stream_t *p_stream,
             fmt.i_sar_num = fmt.i_aspect * fmt.i_height / fmt.i_width;
             fmt.i_sar_den = VOUT_ASPECT_FACTOR;
 
-            spu_RenderSubpictures( p_sys->p_spu, &fmt, p_pic, p_subpic,
-                                   i_scale_width, i_scale_height );
+            /* FIXME the mdate() seems highly suspicious */
+            spu_RenderSubpictures( p_sys->p_spu, p_pic, &fmt,
+                                   p_subpic, &id->p_decoder->fmt_out.video, mdate() );
         }
 
         /* Run user specified filter chain */
@@ -2067,7 +1966,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
                 p_pic2 = video_new_buffer_decoder( id->p_decoder );
                 if( p_pic2 != NULL )
                 {
-                    vout_CopyPicture( p_stream, p_pic2, p_pic );
+                    picture_Copy( p_pic2, p_pic );
                     p_pic2->date = i_pts;
                 }
             }
@@ -2084,7 +1983,7 @@ static int transcode_video_process( sout_stream_t *p_stream,
 
         if( p_sys->i_threads == 0 )
         {
-            p_pic->pf_release( p_pic );
+            picture_Release( p_pic );
         }
         else
         {
@@ -2141,14 +2040,14 @@ static void* EncoderThread( vlc_object_t* p_this )
         block_ChainAppend( &p_sys->p_buffers, p_block );
 
         vlc_mutex_unlock( &p_sys->lock_out );
-        p_pic->pf_release( p_pic );
+        picture_Release( p_pic );
     }
 
     while( p_sys->i_last_pic != p_sys->i_first_pic )
     {
         p_pic = p_sys->pp_pics[p_sys->i_first_pic++];
         p_sys->i_first_pic %= PICTURE_RING_SIZE;
-        p_pic->pf_release( p_pic );
+        picture_Release( p_pic );
     }
     block_ChainRelease( p_sys->p_buffers );
 
@@ -2156,161 +2055,48 @@ static void* EncoderThread( vlc_object_t* p_this )
     return NULL;
 }
 
-struct picture_sys_t
-{
-    vlc_object_t *p_owner;
-};
-
-static void video_release_buffer( picture_t *p_pic )
-{
-    if( p_pic && !p_pic->i_refcount && p_pic->pf_release && p_pic->p_sys )
-    {
-        video_del_buffer_decoder( (decoder_t *)p_pic->p_sys->p_owner, p_pic );
-    }
-    else if( p_pic && p_pic->i_refcount > 0 ) p_pic->i_refcount--;
-}
-
-static picture_t *video_new_buffer( vlc_object_t *p_this, picture_t **pp_ring,
-                                    sout_stream_sys_t *p_sys )
+static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
 {
-    decoder_t *p_dec = (decoder_t *)p_this;
-    picture_t *p_pic;
-    int i;
-
-    /* Find an empty space in the picture ring buffer */
-    for( i = 0; i < PICTURE_RING_SIZE; i++ )
-    {
-        if( pp_ring[i] != 0 && pp_ring[i]->i_status == DESTROYED_PICTURE )
-        {
-            pp_ring[i]->i_status = RESERVED_PICTURE;
-            return pp_ring[i];
-        }
-    }
-    for( i = 0; i < PICTURE_RING_SIZE; i++ )
-    {
-        if( pp_ring[i] == 0 ) break;
-    }
-
-    if( i == PICTURE_RING_SIZE && p_sys->i_threads >= 1 )
+    sout_stream_sys_t *p_ssys = p_dec->p_owner->p_sys;
+    if( p_ssys->i_threads >= 1 )
     {
-        int i_first_pic = p_sys->i_first_pic;
+        int i_first_pic = p_ssys->i_first_pic;
 
-        if( p_sys->i_first_pic != p_sys->i_last_pic )
+        if( p_ssys->i_first_pic != p_ssys->i_last_pic )
         {
             /* Encoder still has stuff to encode, wait to clear-up the list */
-            while( p_sys->i_first_pic == i_first_pic )
-                msleep( 100000 );
-        }
-
-        /* Find an empty space in the picture ring buffer */
-        for( i = 0; i < PICTURE_RING_SIZE; i++ )
-        {
-            if( pp_ring[i] != 0 && pp_ring[i]->i_status == DESTROYED_PICTURE )
+            while( p_ssys->i_first_pic == i_first_pic )
             {
-                pp_ring[i]->i_status = RESERVED_PICTURE;
-                return pp_ring[i];
+#warning THERE IS A DEFINITELY BUG! LOCKING IS INSUFFICIENT!
+                msleep( 10000 );
+                barrier ();
             }
         }
-        for( i = 0; i < PICTURE_RING_SIZE; i++ )
-        {
-            if( pp_ring[i] == 0 ) break;
-        }
-    }
-
-    if( i == PICTURE_RING_SIZE )
-    {
-        msg_Err( p_this, "decoder/filter is leaking pictures, "
-                 "resetting its ring buffer" );
-
-        for( i = 0; i < PICTURE_RING_SIZE; i++ )
-        {
-            pp_ring[i]->pf_release( pp_ring[i] );
-        }
-
-        i = 0;
     }
 
-    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,
-                          p_dec->fmt_out.video.i_width,
-                          p_dec->fmt_out.video.i_height,
-                          p_dec->fmt_out.video.i_aspect );
-
-    if( !p_pic->i_planes )
-    {
-        free( p_pic );
-        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;
-
-    pp_ring[i] = p_pic;
-    return p_pic;
-}
-
-static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
-{
-    return video_new_buffer( VLC_OBJECT(p_dec),
-                             p_dec->p_owner->pp_pics, p_dec->p_owner->p_sys );
-}
-
-static picture_t *video_new_buffer_filter( filter_t *p_filter )
-{
-    return video_new_buffer( VLC_OBJECT(p_filter),
-                             p_filter->p_owner->pp_pics,
-                             p_filter->p_owner->p_sys );
-}
-
-static void video_del_buffer( vlc_object_t *p_this, picture_t *p_pic )
-{
-    VLC_UNUSED(p_this);
-    if( p_pic )
-    {
-        free( p_pic->p_q );
-        free( p_pic->p_data_orig );
-        free( p_pic->p_sys );
-        free( p_pic );
-    }
+    return picture_New( p_dec->fmt_out.video.i_chroma,
+                        p_dec->fmt_out.video.i_width,
+                        p_dec->fmt_out.video.i_height,
+                        p_dec->fmt_out.video.i_aspect );
 }
 
 static void video_del_buffer_decoder( decoder_t *p_decoder, picture_t *p_pic )
 {
     VLC_UNUSED(p_decoder);
-    p_pic->i_refcount = 0;
-    p_pic->i_status = DESTROYED_PICTURE;
-    picture_CleanupQuant( p_pic );
-}
-
-static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic )
-{
-    VLC_UNUSED(p_filter);
-    p_pic->i_refcount = 0;
-    p_pic->i_status = DESTROYED_PICTURE;
-    picture_CleanupQuant( p_pic );
+    picture_Release( p_pic );
 }
 
 static void video_link_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
 {
     VLC_UNUSED(p_dec);
-    p_pic->i_refcount++;
+    picture_Hold( p_pic );
 }
 
 static void video_unlink_picture_decoder( decoder_t *p_dec, picture_t *p_pic )
 {
     VLC_UNUSED(p_dec);
-    video_release_buffer( p_pic );
+    picture_Release( p_pic );
 }
 
 /*
@@ -2335,7 +2121,7 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id )
     /* id->p_decoder->p_cfg = p_sys->p_spu_cfg; */
 
     id->p_decoder->p_module =
-        module_Need( id->p_decoder, "decoder", "$codec", 0 );
+        module_need( id->p_decoder, "decoder", "$codec", false );
 
     if( !id->p_decoder->p_module )
     {
@@ -2353,11 +2139,11 @@ static int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_t *id )
         id->p_encoder->p_cfg = p_sys->p_spu_cfg;
 
         id->p_encoder->p_module =
-            module_Need( id->p_encoder, "encoder", p_sys->psz_senc, true );
+            module_need( id->p_encoder, "encoder", p_sys->psz_senc, true );
 
         if( !id->p_encoder->p_module )
         {
-            module_Unneed( id->p_decoder, id->p_decoder->p_module );
+            module_unneed( id->p_decoder, id->p_decoder->p_module );
             msg_Err( p_stream, "cannot find spu encoder (%s)", p_sys->psz_senc );
             return VLC_EGENERIC;
         }
@@ -2376,11 +2162,13 @@ static void transcode_spu_close( sout_stream_id_t *id)
 {
     /* Close decoder */
     if( id->p_decoder->p_module )
-        module_Unneed( id->p_decoder, id->p_decoder->p_module );
+        module_unneed( id->p_decoder, id->p_decoder->p_module );
+    if( id->p_decoder->p_description )
+        vlc_meta_Delete( id->p_decoder->p_description );
 
     /* Close encoder */
     if( id->p_encoder->p_module )
-        module_Unneed( id->p_encoder, id->p_encoder->p_module );
+        module_unneed( id->p_encoder, id->p_encoder->p_module );
 }
 
 static int transcode_spu_process( sout_stream_t *p_stream,
@@ -2425,14 +2213,14 @@ static int transcode_spu_process( sout_stream_t *p_stream,
 
 static subpicture_t *spu_new_buffer( decoder_t *p_dec )
 {
-    sout_stream_t *p_stream = (sout_stream_t *)p_dec->p_owner;
-    return spu_CreateSubpicture( p_stream->p_sys->p_spu );
+    VLC_UNUSED( p_dec );
+    return subpicture_New();
 }
 
 static void spu_del_buffer( decoder_t *p_dec, subpicture_t *p_subpic )
 {
-    sout_stream_t *p_stream = (sout_stream_t *)p_dec->p_owner;
-    spu_DestroySubpicture( p_stream->p_sys->p_spu, p_subpic );
+    VLC_UNUSED( p_dec );
+    subpicture_Delete( p_subpic );
 }
 
 /*
@@ -2456,13 +2244,13 @@ static int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_t *id )
 
         /* Open encoder */
         es_format_Init( &id->p_encoder->fmt_in, id->p_decoder->fmt_in.i_cat,
-                        VLC_FOURCC('Y','U','V','A') );
+                        VLC_CODEC_YUVA );
         id->p_encoder->fmt_in.psz_language = strdup( "osd" );
 
         id->p_encoder->p_cfg = p_sys->p_osd_cfg;
 
         id->p_encoder->p_module =
-            module_Need( id->p_encoder, "encoder", p_sys->psz_osdenc, true );
+            module_need( id->p_encoder, "encoder", p_sys->psz_osdenc, true );
 
         if( !id->p_encoder->p_module )
         {
@@ -2471,7 +2259,7 @@ static int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_t *id )
         }
 
         /* open output stream */
-        id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->p_encoder->fmt_out );
+        id->id = sout_StreamIdAdd( p_sys->p_out, &id->p_encoder->fmt_out );
         id->b_transcode = true;
 
         if( !id->id ) goto error;
@@ -2480,7 +2268,7 @@ static int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_t *id )
     {
         msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
                  (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->id = sout_StreamIdAdd( p_sys->p_out, &id->p_decoder->fmt_out );
         id->b_transcode = false;
 
         if( !id->id ) goto error;
@@ -2497,7 +2285,7 @@ static int transcode_osd_new( sout_stream_t *p_stream, sout_stream_id_t *id )
  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 );
+            module_unneed( id->p_encoder, id->p_encoder->p_module );
     p_sys->b_osd = false;
     return VLC_EGENERIC;
 }
@@ -2510,7 +2298,7 @@ static void transcode_osd_close( sout_stream_t *p_stream, sout_stream_id_t *id)
     if( id )
     {
         if( id->p_encoder->p_module )
-            module_Unneed( id->p_encoder, id->p_encoder->p_module );
+            module_unneed( id->p_encoder, id->p_encoder->p_module );
     }
     p_sys->b_osd = false;
 }
@@ -2548,7 +2336,7 @@ static int transcode_osd_process( sout_stream_t *p_stream,
         }
 
         p_block = id->p_encoder->pf_encode_sub( id->p_encoder, p_subpic );
-        spu_DestroySubpicture( p_sys->p_spu, p_subpic );
+        subpicture_Delete( p_subpic );
         if( p_block )
         {
             p_block->i_dts = p_block->i_pts = in->i_dts;