]> git.sesse.net Git - vlc/blobdiff - modules/stream_out/transcode.c
Rename audio filter2 capability back to audio filter
[vlc] / modules / stream_out / transcode.c
index ce71eb8ef999ab6d87343b6d001c6ee3c4e78436..a5d60af2a9f4c9ba952bb6cc0610f7752a9fdb76 100644 (file)
 #define ARATE_TEXT N_("Audio sample rate")
 #define ARATE_LONGTEXT N_( \
  "Sample rate of the transcoded audio stream (11250, 22500, 44100 or 48000).")
+#define ALANG_TEXT N_("Audio Language")
+#define ALANG_LONGTEXT N_( \
+    "This is the language of the audio stream.")
 #define ACHANS_TEXT N_("Audio channels")
 #define ACHANS_LONGTEXT N_( \
     "Number of audio channels in the transcoded streams." )
@@ -171,7 +174,7 @@ vlc_module_begin ()
                 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,
+    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 )
@@ -179,7 +182,7 @@ vlc_module_begin ()
                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,
+    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,
@@ -204,13 +207,15 @@ vlc_module_begin ()
                 ACODEC_LONGTEXT, false )
     add_integer( SOUT_CFG_PREFIX "ab", 0, NULL, AB_TEXT,
                  AB_LONGTEXT, false )
+    add_string( SOUT_CFG_PREFIX "alang", NULL, NULL, ALANG_TEXT,
+                ALANG_LONGTEXT, true )
     add_integer( SOUT_CFG_PREFIX "channels", 0, NULL, ACHANS_TEXT,
                  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,
+    add_bool( SOUT_CFG_PREFIX "audio-sync", false, NULL, ASYNC_TEXT,
               ASYNC_LONGTEXT, false )
-    add_module_list( SOUT_CFG_PREFIX "afilter",  "audio filter2",
+    add_module_list( SOUT_CFG_PREFIX "afilter",  "audio filter",
                      NULL, NULL,
                      AFILTER_TEXT, AFILTER_LONGTEXT, false )
 
@@ -219,20 +224,20 @@ vlc_module_begin ()
                 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,
+    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 )
 
     set_section( N_("On Screen Display"), NULL )
-    add_bool( SOUT_CFG_PREFIX "osd", 0, NULL, OSD_TEXT,
+    add_bool( SOUT_CFG_PREFIX "osd", false, NULL, OSD_TEXT,
               OSD_LONGTEXT, false )
 
     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,
+    add_bool( SOUT_CFG_PREFIX "high-priority", false, NULL, HP_TEXT, HP_LONGTEXT,
               true )
 
 vlc_module_end ()
@@ -240,7 +245,7 @@ vlc_module_end ()
 static const char *const ppsz_sout_options[] = {
     "venc", "vcodec", "vb",
     "scale", "fps", "width", "height", "vfilter", "deinterlace",
-    "deinterlace-module", "threads", "hurry-up", "aenc", "acodec", "ab",
+    "deinterlace-module", "threads", "hurry-up", "aenc", "acodec", "ab", "alang",
     "afilter", "samplerate", "channels", "senc", "scodec", "soverlay",
     "sfilter", "osd", "audio-sync", "high-priority", "maxwidth", "maxheight",
     NULL
@@ -268,13 +273,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 * );
@@ -320,6 +322,7 @@ struct sout_stream_sys_t
     /* Audio */
     vlc_fourcc_t    i_acodec;   /* codec audio (0 if not transcode) */
     char            *psz_aenc;
+    char            *psz_alang;
     config_chain_t  *p_audio_cfg;
     uint32_t        i_sample_rate;
     uint32_t        i_channels;
@@ -365,12 +368,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;
 };
 
@@ -421,6 +418,8 @@ static int Open( vlc_object_t *p_this )
     }
     free( val.psz_string );
 
+    p_sys->psz_alang = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "alang" );
+
     var_Get( p_stream, SOUT_CFG_PREFIX "ab", &val );
     p_sys->i_abitrate = val.i_int;
     if( p_sys->i_abitrate < 4000 ) p_sys->i_abitrate *= 1000;
@@ -646,6 +645,7 @@ static void Close( vlc_object_t * p_this )
 
     config_ChainDestroy( p_sys->p_audio_cfg );
     free( p_sys->psz_aenc );
+    free( p_sys->psz_alang );
 
     free( p_sys->psz_vf2 );
 
@@ -721,7 +721,10 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
     es_format_Init( &id->p_encoder->fmt_out, p_fmt->i_cat, 0 );
     id->p_encoder->fmt_out.i_id    = p_fmt->i_id;
     id->p_encoder->fmt_out.i_group = p_fmt->i_group;
-    if( p_fmt->psz_language )
+
+    if( p_sys->psz_alang )
+        id->p_encoder->fmt_out.psz_language = strdup( p_sys->psz_alang );
+    else if( p_fmt->psz_language )
         id->p_encoder->fmt_out.psz_language = strdup( p_fmt->psz_language );
 
     if( p_fmt->i_cat == AUDIO_ES && (p_sys->i_acodec || p_sys->psz_aenc) )
@@ -1236,7 +1239,7 @@ static int transcode_audio_new( sout_stream_t *p_stream,
         }
         fmt_last = fmt_fl32;
 
-        id->p_uf_chain = filter_chain_New( p_stream, "audio filter2", false,
+        id->p_uf_chain = filter_chain_New( p_stream, "audio filter", 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 )
@@ -1244,7 +1247,7 @@ static int transcode_audio_new( sout_stream_t *p_stream,
     }
 
     /* Load conversion filters */
-    id->p_f_chain = filter_chain_New( p_stream, "audio filter2", true,
+    id->p_f_chain = filter_chain_New( p_stream, "audio filter", true,
                     transcode_audio_filter_allocation_init, NULL, NULL );
     filter_chain_Reset( id->p_f_chain, &fmt_last, &id->p_encoder->fmt_in );
 
@@ -1293,8 +1296,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,
@@ -1304,64 +1306,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 */
         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_block = filter_chain_AudioFilter( id->p_f_chain, p_audio_block );
-        assert( p_audio_block );
+        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;
 
@@ -1381,69 +1367,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
@@ -1462,8 +1431,6 @@ 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; */
 
@@ -1492,11 +1459,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;
 
@@ -1753,8 +1724,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 );
@@ -1774,17 +1743,7 @@ static void transcode_video_close( sout_stream_t *p_stream,
     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 )
@@ -1819,7 +1778,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;
             }
         }
@@ -1850,7 +1809,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) )
@@ -1920,7 +1879,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;
@@ -1938,8 +1897,7 @@ 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 */, false );
+            p_subpic = spu_SortSubpictures( p_sys->p_spu, p_pic->date, false );
             /* TODO: get another pic */
         }
 
@@ -1948,14 +1906,14 @@ static int transcode_video_process( sout_stream_t *p_stream,
         {
             video_format_t fmt;
 
-            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 )
                 {
                     picture_Copy( p_tmp, p_pic );
-                    p_pic->pf_release( p_pic );
+                    picture_Release( p_pic );
                     p_pic = p_tmp;
                 }
             }
@@ -1969,8 +1927,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;
 
+            /* FIXME the mdate() seems highly suspicious */
             spu_RenderSubpictures( p_sys->p_spu, p_pic, &fmt,
-                                   p_subpic, &id->p_decoder->fmt_out.video, false );
+                                   p_subpic, &id->p_decoder->fmt_out.video, mdate() );
         }
 
         /* Run user specified filter chain */
@@ -2036,7 +1995,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
         {
@@ -2093,14 +2052,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 );
 
@@ -2108,150 +2067,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 )
+static picture_t *video_new_buffer_decoder( decoder_t *p_dec )
 {
-    if( p_pic && !p_pic->i_refcount && p_pic->pf_release && p_pic->p_sys )
+    sout_stream_sys_t *p_ssys = p_dec->p_owner->p_sys;
+    if( p_ssys->i_threads >= 1 )
     {
-        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 )
-{
-    decoder_t *p_dec = (decoder_t *)p_this;
-    picture_t *p_pic;
-    int i;
+        int i_first_pic = p_ssys->i_first_pic;
 
-    /* Find an empty space in the picture ring buffer */
-    for( i = 0; i < PICTURE_RING_SIZE; i++ )
-    {
-        if( pp_ring[i] != NULL && 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] == NULL ) break;
-    }
-
-    if( i == PICTURE_RING_SIZE && p_sys->i_threads >= 1 )
-    {
-        int i_first_pic = p_sys->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] != NULL && 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 DEFINITELY A BUG! LOCKING IS INSUFFICIENT!
+                msleep( 10000 );
+                barrier ();
             }
         }
-        for( i = 0; i < PICTURE_RING_SIZE; i++ )
-        {
-            if( pp_ring[i] == NULL ) 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_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
-    p_pic = 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 );
-    if( !p_pic ) return NULL;
-    p_pic->p_sys = calloc( 1, sizeof(picture_sys_t) );
-    if( !p_pic->p_sys )
-    {
-        picture_Release( p_pic );
-        return NULL;
-    }
-    p_pic->pf_release = video_release_buffer;
-    p_pic->i_refcount = 0;
-
-    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 );
 }
 
 /*
@@ -2468,7 +2325,7 @@ static int transcode_osd_process( sout_stream_t *p_stream,
     /* Check if we have a subpicture to send */
     if( p_sys->p_spu && in->i_dts > 0)
     {
-        p_subpic = spu_SortSubpictures( p_sys->p_spu, in->i_dts, false, false );
+        p_subpic = spu_SortSubpictures( p_sys->p_spu, in->i_dts, false );
     }
     else
     {