[vlc-devel] [PATCH 4/8] decoder: refactor pf_decode_* callbacks

Thomas Guillem thomas at gllm.fr
Wed Feb 8 19:53:51 CET 2017


Use only one callback for every decoder types:

int (*pf_decode)(decoder_t *, block_t *p_block);

There is now only one way to send output frames/blocks from a decoder module:
using decoder_QueueVideo(), decoder_QueueAudio() and decoder_QueueSub()
functions.

This fixes transcoding not receiving any output when a decoder used
decoder_Queue*() function.

The pf_packetize callback is kept unchanged. A packetizer shouldn't be
asynchronous at all (and this simplify the locking for decoder core).

The pf_decode callback returns, for now, only one value: SUCCESS. This will
allow a module to send more status.

TODO: fix some spu decoders that send a queue of spu (they should call
decoder_QueueSub() for each spu).
---
 include/vlc_codec.h                      |  50 ++++---
 include/vlc_image.h                      |   3 +
 modules/codec/a52.c                      |  21 +--
 modules/codec/adpcm.c                    |  19 ++-
 modules/codec/aes3.c                     |  37 ++---
 modules/codec/aom.c                      |  28 ++--
 modules/codec/araw.c                     |  22 ++-
 modules/codec/arib/aribsub.c             |  22 ++-
 modules/codec/avcodec/audio.c            |  18 ++-
 modules/codec/avcodec/subtitle.c         |  17 ++-
 modules/codec/avcodec/video.c            |  19 ++-
 modules/codec/bpg.c                      |  20 +--
 modules/codec/cc.c                       |  19 ++-
 modules/codec/cdg.c                      |  19 ++-
 modules/codec/crystalhd.c                |  27 ++--
 modules/codec/cvdsub.c                   |  24 ++--
 modules/codec/daala.c                    |  46 ++++---
 modules/codec/dca.c                      |  16 +--
 modules/codec/ddummy.c                   |  18 +--
 modules/codec/dmo/dmo.c                  |  94 +++++--------
 modules/codec/dvbsub.c                   |  33 ++---
 modules/codec/faad.c                     |  34 +++--
 modules/codec/flac.c                     |  28 ++--
 modules/codec/fluidsynth.c               |  23 ++--
 modules/codec/g711.c                     |  29 ++--
 modules/codec/gstreamer/gstdecode.c      |  24 ++--
 modules/codec/jpeg.c                     |  23 ++--
 modules/codec/kate.c                     |  65 +++++----
 modules/codec/libass.c                   |  29 ++--
 modules/codec/libmpeg2.c                 |  18 ++-
 modules/codec/lpcm.c                     |  19 ++-
 modules/codec/mad.c                      |  14 +-
 modules/codec/mft.c                      |  71 +++-------
 modules/codec/mpg123.c                   |  17 ++-
 modules/codec/oggspots.c                 |  50 ++++---
 modules/codec/omxil/mediacodec.c         |  75 ++++------
 modules/codec/omxil/omxil.c              |  94 ++++++-------
 modules/codec/opus.c                     |  54 +++++---
 modules/codec/png.c                      |  36 ++---
 modules/codec/rawvideo.c                 |  36 +++--
 modules/codec/schroedinger.c             |  33 ++---
 modules/codec/scte18.c                   |  15 +-
 modules/codec/scte27.c                   |  13 +-
 modules/codec/sdl_image.c                |  23 ++--
 modules/codec/spdif.c                    |  20 +--
 modules/codec/speex.c                    |  63 +++++----
 modules/codec/spudec/spudec.c            |  35 +++--
 modules/codec/stl.c                      |  17 ++-
 modules/codec/subsdec.c                  |  20 ++-
 modules/codec/substx3g.c                 |  30 ++--
 modules/codec/subsusf.c                  |  19 ++-
 modules/codec/svcdsub.c                  |  24 ++--
 modules/codec/svg.c                      |  19 ++-
 modules/codec/telx.c                     |  19 ++-
 modules/codec/textst.c                   |  49 +++----
 modules/codec/theora.c                   |  51 ++++---
 modules/codec/ttml/substtml.c            |  14 +-
 modules/codec/uleaddvaudio.c             |  19 ++-
 modules/codec/videotoolbox.m             |  38 +++---
 modules/codec/vorbis.c                   |  35 +++--
 modules/codec/vpx.c                      |  28 ++--
 modules/codec/wmafixed/wma.c             |  58 +++-----
 modules/codec/xwd.c                      |  18 +--
 modules/codec/zvbi.c                     |  20 ++-
 modules/hw/mmal/codec.c                  |  28 ++--
 modules/misc/stats.c                     |  15 +-
 modules/packetizer/flac.c                |   6 +-
 modules/stream_out/mosaic_bridge.c       | 180 ++++++++++++------------
 modules/stream_out/transcode/audio.c     |  82 ++++++++---
 modules/stream_out/transcode/spu.c       |  90 ++++++++----
 modules/stream_out/transcode/transcode.c |   3 +
 modules/stream_out/transcode/transcode.h |  22 +++
 modules/stream_out/transcode/video.c     |  55 +++++++-
 src/input/decoder.c                      | 226 ++++++++-----------------------
 src/input/demux.c                        |   4 +-
 src/misc/image.c                         |  44 +++++-
 76 files changed, 1407 insertions(+), 1339 deletions(-)

diff --git a/include/vlc_codec.h b/include/vlc_codec.h
index eb4a5c3f41..2f8facc18f 100644
--- a/include/vlc_codec.h
+++ b/include/vlc_codec.h
@@ -67,11 +67,23 @@ struct decoder_t
     /* Tell the decoder if it is allowed to drop frames */
     bool                b_frame_drop_allowed;
 
-    /* All pf_decode_* and pf_packetize functions have the same behavior.
+#   define VLCDEC_SUCCESS   VLC_SUCCESS
+    /* This function is called to decode one packetized block.
      *
-     * These functions are called in a loop with the same pp_block argument
-     * until they return NULL. This allows a module implementation to return
-     * more than one frames/samples for one input block.
+     * The module implementation will own the input block (p_block) and should
+     * process and release it. Depending of the decoder type, the module should
+     * send output frames/blocks via decoder_QueueVideo(), decoder_QueueAudio()
+     * or decoder_QueueSub().
+     *
+     * If p_block is NULL, the decoder asks the module to drain itself. The
+     * module should return all available output frames/block via the queue
+     * functions.
+     */
+    int                 ( * pf_decode )   ( decoder_t *, block_t *p_block );
+
+    /* This function is called in a loop with the same pp_block argument until
+     * it returns NULL. This allows a module implementation to return more than
+     * one output blocks for one input block.
      *
      * pp_block or *pp_block can be NULL.
      *
@@ -79,32 +91,31 @@ struct decoder_t
      * own the input block (*pp_block) and should process and release it. The
      * module can also process a part of the block. In that case, it should
      * modify (*pp_block)->p_buffer/i_buffer accordingly and return a valid
-     * frame/samples. The module can also set *pp_block to NULL when the input
+     * output block. The module can also set *pp_block to NULL when the input
      * block is consumed.
      *
      * If pp_block is not NULL but *pp_block is NULL, a previous call of the pf
      * function has set the *pp_block to NULL. Here, the module can return new
-     * frames/samples for the same, already processed, input block (the pf
-     * function will be called as long as the module return a frame/samples).
+     * output block for the same, already processed, input block (the
+     * pf_packetize function will be called as long as the module return an
+     * output block).
      *
      * When the pf function returns NULL, the next call to this function will
-     * have a new a valid pp_block (if the decoder is not drained).
+     * have a new a valid pp_block (if the packetizer is not drained).
      *
-     * If pp_block is NULL, the decoder asks the module to drain itself. In
-     * that case, the module has to return all frames/samples available (the pf
-     * function will be called as long as the module return a frame/samples).
+     * If pp_block is NULL, the packetizer asks the module to drain itself. In
+     * that case, the module has to return all output frames available (the
+     * pf_packetize function will be called as long as the module return an
+     * output block).
      */
-    picture_t *         ( * pf_decode_video )( decoder_t *, block_t **pp_block );
-    block_t *           ( * pf_decode_audio )( decoder_t *, block_t **pp_block );
-    subpicture_t *      ( * pf_decode_sub)   ( decoder_t *, block_t **pp_block );
-    block_t *           ( * pf_packetize )   ( decoder_t *, block_t **pp_block );
+    block_t *           ( * pf_packetize )( decoder_t *, block_t **pp_block );
     /* */
     void                ( * pf_flush ) ( decoder_t * );
 
     /* Closed Caption (CEA 608/708) extraction.
-     * If set, it *may* be called after pf_decode_video/pf_packetize
+     * If set, it *may* be called after pf_decode/pf_packetize
      * returned data. It should return CC for the pictures returned by the
-     * last pf_packetize/pf_decode_video call only,
+     * last pf_packetize/pf_decode call only,
      * pb_present will be used to known which cc channel are present (but
      * globaly, not necessary for the current packet */
     block_t *           ( * pf_get_cc )      ( decoder_t *, bool pb_present[4] );
@@ -156,6 +167,7 @@ struct decoder_t
     int             (*pf_queue_audio)( decoder_t *, block_t * );
     /* XXX use decoder_QueueSub */
     int             (*pf_queue_sub)( decoder_t *, subpicture_t *);
+    void             *p_queue_ctx;
 
     /* Private structure for the owner of the decoder */
     decoder_owner_sys_t *p_owner;
@@ -325,14 +337,14 @@ static inline int decoder_UpdateAudioFormat( decoder_t *dec )
 /**
  * This function will return a new audio buffer usable by a decoder as an
  * output buffer. It must be released with block_Release() or returned it to
- * the caller as a pf_decode_audio return value.
+ * the caller as a decoder_QueueAudio parameter.
  */
 VLC_API block_t * decoder_NewAudioBuffer( decoder_t *, int i_size ) VLC_USED;
 
 /**
  * This function will return a new subpicture usable by a decoder as an output
  * buffer. You have to release it using subpicture_Delete() or by returning
- * it to the caller as a pf_decode_sub return value.
+ * it to the caller as a decoder_QueueSub parameter.
  */
 VLC_API subpicture_t * decoder_NewSubpicture( decoder_t *, const subpicture_updater_t * ) VLC_USED;
 
diff --git a/include/vlc_image.h b/include/vlc_image.h
index 0b9ab9e8ce..41aab308f6 100644
--- a/include/vlc_image.h
+++ b/include/vlc_image.h
@@ -25,6 +25,7 @@
 #define VLC_IMAGE_H 1
 
 # include <vlc_picture.h>
+# include <vlc_picture_fifo.h>
 
 /**
  * \file
@@ -55,6 +56,8 @@ struct image_handler_t
     decoder_t *p_dec;
     encoder_t *p_enc;
     filter_t  *p_filter;
+
+    picture_fifo_t *outfifo;
 };
 
 VLC_API image_handler_t * image_HandlerCreate( vlc_object_t * ) VLC_USED;
diff --git a/modules/codec/a52.c b/modules/codec/a52.c
index 967ad20d79..f9f48cfb31 100644
--- a/modules/codec/a52.c
+++ b/modules/codec/a52.c
@@ -154,13 +154,12 @@ static void Exchange( sample_t *restrict p_out, const sample_t *restrict p_in )
     }
 }
 
-static block_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_in_buf )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if (pp_block == NULL || *pp_block == NULL)
-        return NULL;
-    block_t *p_in_buf = *pp_block;
+    if (p_in_buf == NULL) /* No drain */
+        return VLCDEC_SUCCESS;
 
 #ifdef LIBA52_FIXED
     sample_t i_sample_level = (1 << 24);
@@ -175,7 +174,10 @@ static block_t *Decode( decoder_t *p_dec, block_t **pp_block )
      * samples for each channel. */
     block_t *p_out_buf = block_Alloc( 6 * i_bytes_per_block );
     if( unlikely(p_out_buf == NULL) )
-        goto out;
+    {
+        block_Release( p_in_buf );
+        return VLCDEC_SUCCESS;
+    }
 
     /* Do the actual decoding now. */
     a52_frame( p_sys->p_liba52, p_in_buf->p_buffer,
@@ -231,10 +233,9 @@ static block_t *Decode( decoder_t *p_dec, block_t **pp_block )
     p_out_buf->i_dts = p_in_buf->i_dts;
     p_out_buf->i_pts = p_in_buf->i_pts;
     p_out_buf->i_length = p_in_buf->i_length;
-out:
     block_Release( p_in_buf );
-    *pp_block = NULL;
-    return p_out_buf;
+    decoder_QueueAudio( p_dec, p_out_buf );
+    return VLCDEC_SUCCESS;
 }
 
 static int channels_vlc2a52( const audio_format_t *p_audio, int *p_flags )
@@ -369,8 +370,8 @@ static int Open( vlc_object_t *p_this )
         return VLC_EGENERIC;
     }
 
-    p_dec->pf_decode_audio = Decode;
-    p_dec->pf_flush        = NULL;
+    p_dec->pf_decode = Decode;
+    p_dec->pf_flush  = NULL;
     return VLC_SUCCESS;
 }
 
diff --git a/modules/codec/adpcm.c b/modules/codec/adpcm.c
index 1128f5a7a9..457f2fc0c1 100644
--- a/modules/codec/adpcm.c
+++ b/modules/codec/adpcm.c
@@ -41,7 +41,7 @@
 static int  OpenDecoder( vlc_object_t * );
 static void CloseDecoder( vlc_object_t * );
 
-static block_t *DecodeBlock( decoder_t *, block_t ** );
+static int DecodeAudio( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 
 vlc_module_begin ()
@@ -290,8 +290,8 @@ static int OpenDecoder( vlc_object_t *p_this )
     date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 );
     date_Set( &p_sys->end_date, 0 );
 
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeAudio;
+    p_dec->pf_flush  = Flush;
 
     return VLC_SUCCESS;
 }
@@ -314,7 +314,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     decoder_sys_t *p_sys  = p_dec->p_sys;
     block_t *p_block;
 
-    if( !pp_block || !*pp_block ) return NULL;
+    if( !*pp_block ) return NULL;
 
     p_block = *pp_block;
 
@@ -390,6 +390,17 @@ drop:
     return NULL;
 }
 
+static int DecodeAudio( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    block_t **pp_block = &p_block, *p_out;
+    while( ( p_out = DecodeBlock( p_dec, pp_block ) ) != NULL )
+        decoder_QueueAudio( p_dec, p_out );
+    return VLCDEC_SUCCESS;
+}
+
 /*****************************************************************************
  * CloseDecoder:
  *****************************************************************************/
diff --git a/modules/codec/aes3.c b/modules/codec/aes3.c
index ce7f20d3ad..019e242601 100644
--- a/modules/codec/aes3.c
+++ b/modules/codec/aes3.c
@@ -74,7 +74,7 @@ struct decoder_sys_t
 static int Open( decoder_t *p_dec, bool b_packetizer );
 
 static block_t *Parse( decoder_t *p_dec, int *pi_frame_length, int *pi_bits,
-                       block_t **pp_block, bool b_packetizer );
+                       block_t *p_block, bool b_packetizer );
 
 /*****************************************************************************
  * OpenDecoder:
@@ -135,16 +135,15 @@ static const uint8_t reverse[256] = {
  ****************************************************************************
  * Beware, this function must be fed with complete frames (PES packet).
  *****************************************************************************/
-static block_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t       *p_block;
     block_t       *p_aout_buffer;
     int            i_frame_length, i_bits;
 
-    p_block = Parse( p_dec, &i_frame_length, &i_bits, pp_block, false );
+    p_block = Parse( p_dec, &i_frame_length, &i_bits, p_block, false );
     if( !p_block )
-        return NULL;
+        return VLCDEC_SUCCESS;
 
     if( decoder_UpdateAudioFormat( p_dec ) )
     {
@@ -220,7 +219,9 @@ static block_t *Decode( decoder_t *p_dec, block_t **pp_block )
 
 exit:
     block_Release( p_block );
-    return p_aout_buffer;
+    if( p_aout_buffer != NULL )
+        decoder_QueueAudio( p_dec, p_aout_buffer );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -244,7 +245,12 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
     block_t       *p_block;
     int           i_frame_length, i_bits;
 
-    p_block = Parse( p_dec, &i_frame_length, &i_bits, pp_block, true );
+    if( !pp_block ) /* No Drain */
+        return NULL;
+    p_block = *pp_block;
+    *pp_block = NULL; /* So the packet doesn't get re-sent */
+
+    p_block = Parse( p_dec, &i_frame_length, &i_bits, p_block, true );
     if( !p_block )
         return NULL;
 
@@ -284,7 +290,7 @@ static int Open( decoder_t *p_dec, bool b_packetizer )
     {
         p_dec->fmt_out.i_codec = VLC_CODEC_302M;
 
-        p_dec->pf_decode_audio = NULL;
+        p_dec->pf_decode       = NULL;
         p_dec->pf_packetize    = Packetize;
     }
     else
@@ -292,8 +298,8 @@ static int Open( decoder_t *p_dec, bool b_packetizer )
         p_dec->fmt_out.i_codec = VLC_CODEC_S16N;
         p_dec->fmt_out.audio.i_bitspersample = 16;
 
-        p_dec->pf_decode_audio = Decode;
-        p_dec->pf_packetize    = NULL;
+        p_dec->pf_decode    = Decode;
+        p_dec->pf_packetize = NULL;
     }
     p_dec->pf_flush            = Flush;
     return VLC_SUCCESS;
@@ -312,20 +318,17 @@ static const unsigned int pi_original_channels[4] = {
         AOUT_CHAN_CENTER | AOUT_CHAN_LFE,
 };
 
-static block_t *Parse( decoder_t *p_dec, int *pi_frame_length, int *pi_bits,
-                       block_t **pp_block, bool b_packetizer )
+static block_t * Parse( decoder_t *p_dec, int *pi_frame_length, int *pi_bits,
+                        block_t *p_block, bool b_packetizer )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t       *p_block;
     uint32_t h;
     unsigned int i_size;
     int i_channels;
     int i_bits;
 
-    if( !pp_block || !*pp_block ) return NULL;
-
-    p_block = *pp_block;
-    *pp_block = NULL; /* So the packet doesn't get re-sent */
+    if( !p_block ) /* No drain */
+        return NULL;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
diff --git a/modules/codec/aom.c b/modules/codec/aom.c
index fb818f1243..2770b6deb0 100644
--- a/modules/codec/aom.c
+++ b/modules/codec/aom.c
@@ -132,25 +132,23 @@ static vlc_fourcc_t FindVlcChroma( struct aom_image *img )
 /****************************************************************************
  * Decode: the whole thing
  ****************************************************************************/
-static picture_t *Decode(decoder_t *dec, block_t **pp_block)
+static int Decode(decoder_t *dec, block_t *block)
 {
     aom_codec_ctx_t *ctx = &dec->p_sys->ctx;
 
-    if( !pp_block || !*pp_block )
-        return NULL;
-    block_t *block = *pp_block;
+    if (!block) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if (block->i_flags & (BLOCK_FLAG_CORRUPTED)) {
         block_Release(block);
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* Associate packet PTS with decoded frame */
     mtime_t *pkt_pts = malloc(sizeof(*pkt_pts));
     if (!pkt_pts) {
         block_Release(block);
-        *pp_block = NULL;
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     *pkt_pts = block->i_pts;
@@ -159,19 +157,18 @@ static picture_t *Decode(decoder_t *dec, block_t **pp_block)
     err = aom_codec_decode(ctx, block->p_buffer, block->i_buffer, pkt_pts, 0);
 
     block_Release(block);
-    *pp_block = NULL;
 
     if (err != AOM_CODEC_OK) {
         free(pkt_pts);
         AOM_ERR(dec, ctx, "Failed to decode frame");
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     const void *iter = NULL;
     struct aom_image *img = aom_codec_get_frame(ctx, &iter);
     if (!img) {
         free(pkt_pts);
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* fetches back the PTS */
@@ -182,7 +179,7 @@ static picture_t *Decode(decoder_t *dec, block_t **pp_block)
     dec->fmt_out.i_codec = FindVlcChroma(img);
     if (dec->fmt_out.i_codec == 0) {
         msg_Err(dec, "Unsupported output colorspace %d", img->fmt);
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     video_format_t *v = &dec->fmt_out.video;
@@ -219,10 +216,10 @@ static picture_t *Decode(decoder_t *dec, block_t **pp_block)
     }
 
     if (decoder_UpdateVideoFormat(dec))
-        return NULL;
+        return VLCDEC_SUCCESS;
     picture_t *pic = decoder_NewPicture(dec);
     if (!pic)
-        return NULL;
+        return VLCDEC_SUCCESS;
 
     for (int plane = 0; plane < pic->i_planes; plane++ ) {
         uint8_t *src = img->planes[plane];
@@ -241,7 +238,8 @@ static picture_t *Decode(decoder_t *dec, block_t **pp_block)
     pic->b_progressive = true; /* codec does not support interlacing */
     pic->date = pts;
 
-    return pic;
+    decoder_QueueVideo(dec, pic);
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -281,7 +279,7 @@ static int OpenDecoder(vlc_object_t *p_this)
         return VLC_EGENERIC;;
     }
 
-    dec->pf_decode_video = Decode;
+    dec->pf_decode = Decode;
 
     dec->fmt_out.i_cat = VIDEO_ES;
     dec->fmt_out.video.i_width = dec->fmt_in.video.i_width;
diff --git a/modules/codec/araw.c b/modules/codec/araw.c
index 5e323f69e4..28add6fe39 100644
--- a/modules/codec/araw.c
+++ b/modules/codec/araw.c
@@ -66,7 +66,7 @@ vlc_module_end ()
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static block_t *DecodeBlock( decoder_t *, block_t ** );
+static int DecodeBlock( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 
 struct decoder_sys_t
@@ -293,8 +293,8 @@ static int DecoderOpen( vlc_object_t *p_this )
     date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 );
     date_Set( &p_sys->end_date, 0 );
 
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = Flush;
     p_dec->p_sys = p_sys;
 
     return VLC_SUCCESS;
@@ -315,16 +315,11 @@ static void Flush( decoder_t *p_dec )
  ****************************************************************************
  * This function must be fed with whole samples (see nBlockAlign).
  ****************************************************************************/
-static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    if( pp_block == NULL )
-        return NULL;
-
-    block_t *p_block = *pp_block;
-    if( p_block == NULL )
-        return NULL;
-    *pp_block = NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
         goto skip;
@@ -368,10 +363,11 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     p_block->i_pts = date_Get( &p_sys->end_date );
     p_block->i_length = date_Increment( &p_sys->end_date, samples )
                       - p_block->i_pts;
-    return p_block;
+    decoder_QueueAudio( p_dec, p_block );
+    return VLCDEC_SUCCESS;
 skip:
     block_Release( p_block );
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 static void S8Decode( void *outp, const uint8_t *in, unsigned samples )
diff --git a/modules/codec/arib/aribsub.c b/modules/codec/arib/aribsub.c
index 84f54d3ffa..cf1ea3e3b3 100644
--- a/modules/codec/arib/aribsub.c
+++ b/modules/codec/arib/aribsub.c
@@ -41,7 +41,7 @@
  *****************************************************************************/
 static int  Open( vlc_object_t * );
 static void Close( vlc_object_t * );
-static subpicture_t *Decode( decoder_t *, block_t ** );
+static int Decode( decoder_t *, block_t * );
 
 #define IGNORE_RUBY_TEXT N_("Ignore ruby(furigana)")
 #define IGNORE_RUBY_LONGTEXT N_("Ignore ruby(furigana) in the subtitle.")
@@ -117,7 +117,7 @@ static int Open( vlc_object_t *p_this )
     }
 
     p_dec->p_sys = p_sys;
-    p_dec->pf_decode_sub = Decode;
+    p_dec->pf_decode = Decode;
     p_dec->fmt_out.i_cat = SPU_ES;
     p_dec->fmt_out.i_codec = 0;
 
@@ -161,22 +161,18 @@ static void Close( vlc_object_t *p_this )
 /*****************************************************************************
  * Decode:
  *****************************************************************************/
-static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t       *p_block;
     subpicture_t  *p_spu = NULL;
 
-    if( ( pp_block == NULL ) || ( *pp_block == NULL ) )
-    {
-        return NULL;
-    }
-    p_block = *pp_block;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     arib_parser_t *p_parser = arib_get_parser( p_sys->p_arib_instance );
@@ -185,12 +181,12 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
     {
         arib_parse_pes( p_parser, p_block->p_buffer, p_block->i_buffer );
         p_spu = render( p_dec, p_parser, p_decoder, p_block );
+        if( p_spu != NULL )
+            decoder_QueueSub( p_dec, p_spu );
     }
 
     block_Release( p_block );
-    *pp_block = NULL;
-
-    return p_spu;
+    return VLCDEC_SUCCESS;
 }
 
 /* following functions are local */
diff --git a/modules/codec/avcodec/audio.c b/modules/codec/avcodec/audio.c
index 35cd258289..0700963745 100644
--- a/modules/codec/avcodec/audio.c
+++ b/modules/codec/avcodec/audio.c
@@ -74,7 +74,7 @@ struct decoder_sys_t
 
 static void SetupOutputFormat( decoder_t *p_dec, bool b_trust );
 static block_t * ConvertAVFrame( decoder_t *p_dec, AVFrame *frame );
-static block_t *DecodeAudio( decoder_t *, block_t ** );
+static int  DecodeAudio( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 
 static void InitDecoderConfig( decoder_t *p_dec, AVCodecContext *p_context )
@@ -270,8 +270,8 @@ int InitAudioDec( decoder_t *p_dec, AVCodecContext *p_context,
     if( p_dec->fmt_out.audio.i_rate )
         date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 );
 
-    p_dec->pf_decode_audio = DecodeAudio;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeAudio;
+    p_dec->pf_flush  = Flush;
     return VLC_SUCCESS;
 }
 
@@ -299,9 +299,9 @@ static void Flush( decoder_t *p_dec )
 }
 
 /*****************************************************************************
- * DecodeAudio: Called to decode one frame
+ * DecodeBlock: Called to decode one frame
  *****************************************************************************/
-static block_t *DecodeAudio( decoder_t *p_dec, block_t **pp_block )
+static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     AVCodecContext *ctx = p_sys->p_context;
@@ -466,6 +466,14 @@ drop:
     return NULL;
 }
 
+static int DecodeAudio( decoder_t *p_dec, block_t *p_block )
+{
+    block_t **pp_block = p_block ? &p_block : NULL, *p_out;
+    while( ( p_out = DecodeBlock( p_dec, pp_block ) ) != NULL )
+        decoder_QueueAudio( p_dec, p_out );
+    return VLCDEC_SUCCESS;
+}
+
 static block_t * ConvertAVFrame( decoder_t *p_dec, AVFrame *frame )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
diff --git a/modules/codec/avcodec/subtitle.c b/modules/codec/avcodec/subtitle.c
index 26d87547f6..b48dea381b 100644
--- a/modules/codec/avcodec/subtitle.c
+++ b/modules/codec/avcodec/subtitle.c
@@ -45,7 +45,7 @@ struct decoder_sys_t {
 
 static subpicture_t *ConvertSubtitle(decoder_t *, AVSubtitle *, mtime_t pts,
                                      AVCodecContext *avctx);
-static subpicture_t *DecodeSubtitle(decoder_t *, block_t **);
+static int  DecodeSubtitle(decoder_t *, block_t *);
 static void Flush(decoder_t *);
 
 /**
@@ -113,8 +113,8 @@ int InitSubtitleDec(decoder_t *dec, AVCodecContext *context,
     /* */
     msg_Dbg(dec, "libavcodec codec (%s) started", codec->name);
     dec->fmt_out.i_cat = SPU_ES;
-    dec->pf_decode_sub = DecodeSubtitle;
-    dec->pf_flush      = Flush;
+    dec->pf_decode = DecodeSubtitle;
+    dec->pf_flush  = Flush;
 
     return VLC_SUCCESS;
 }
@@ -132,7 +132,7 @@ static void Flush(decoder_t *dec)
 /**
  * Decode one subtitle
  */
-static subpicture_t *DecodeSubtitle(decoder_t *dec, block_t **block_ptr)
+static subpicture_t *DecodeBlock(decoder_t *dec, block_t **block_ptr)
 {
     decoder_sys_t *sys = dec->p_sys;
 
@@ -203,6 +203,15 @@ static subpicture_t *DecodeSubtitle(decoder_t *dec, block_t **block_ptr)
     return spu;
 }
 
+static int DecodeSubtitle(decoder_t *dec, block_t *block)
+{
+    block_t **block_ptr = block ? &block : NULL;
+    subpicture_t *spu;
+    while ((spu = DecodeBlock(dec, block_ptr)) != NULL)
+        decoder_QueueSub(dec, spu);
+    return VLCDEC_SUCCESS;
+}
+
 /**
  * Convert a RGBA libavcodec region to our format.
  */
diff --git a/modules/codec/avcodec/video.c b/modules/codec/avcodec/video.c
index dc477f823e..b2ab47878a 100644
--- a/modules/codec/avcodec/video.c
+++ b/modules/codec/avcodec/video.c
@@ -98,7 +98,7 @@ static void ffmpeg_InitCodec      ( decoder_t * );
 static int lavc_GetFrame(struct AVCodecContext *, AVFrame *, int);
 static enum PixelFormat ffmpeg_GetFormat( AVCodecContext *,
                                           const enum PixelFormat * );
-static picture_t *DecodeVideo( decoder_t *, block_t ** );
+static int  DecodeVideo( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 
 static uint32_t ffmpeg_CodecTag( vlc_fourcc_t fcc )
@@ -554,8 +554,8 @@ int InitVideoDec( decoder_t *p_dec, AVCodecContext *p_context,
         return VLC_EGENERIC;
     }
 
-    p_dec->pf_decode_video = DecodeVideo;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeVideo;
+    p_dec->pf_flush  = Flush;
 
     return VLC_SUCCESS;
 }
@@ -706,9 +706,9 @@ static void update_late_frame_count( decoder_t *p_dec, block_t *p_block, mtime_t
 
 
 /*****************************************************************************
- * DecodeVideo: Called to decode one or more frames
+ * DecodeBlock: Called to decode one or more frames
  *****************************************************************************/
-static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
+static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     AVCodecContext *p_context = p_sys->p_context;
@@ -1018,6 +1018,15 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
     return NULL;
 }
 
+static int DecodeVideo( decoder_t *p_dec, block_t *p_block )
+{
+    block_t **pp_block = p_block ? &p_block : NULL;
+    picture_t *p_pic;
+    while( ( p_pic = DecodeBlock( p_dec, pp_block ) ) != NULL )
+        decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
+}
+
 /*****************************************************************************
  * EndVideo: decoder destruction
  *****************************************************************************
diff --git a/modules/codec/bpg.c b/modules/codec/bpg.c
index 8c41fa75ff..757c0c696f 100644
--- a/modules/codec/bpg.c
+++ b/modules/codec/bpg.c
@@ -37,7 +37,7 @@ struct decoder_sys_t
 static int  OpenDecoder(vlc_object_t *);
 static void CloseDecoder(vlc_object_t *);
 
-static picture_t *DecodeBlock(decoder_t *, block_t **);
+static int DecodeBlock(decoder_t *, block_t *);
 
 /*
  * Module descriptor
@@ -80,7 +80,7 @@ static int OpenDecoder(vlc_object_t *p_this)
     p_dec->fmt_out.i_cat = VIDEO_ES;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
 
     return VLC_SUCCESS;
 }
@@ -88,18 +88,14 @@ static int OpenDecoder(vlc_object_t *p_this)
 /*
  * This function must be fed with a complete compressed frame.
  */
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block;
     picture_t *p_pic = 0;
     BPGImageInfo img_info;
 
-    if( !pp_block || !*pp_block )
-        return NULL;
-
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
         goto error;
@@ -158,12 +154,10 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 
     p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts;
 
-    block_Release( p_block );
-    return p_pic;
-
+    decoder_QueueVideo( p_dec, p_pic );
 error:
     block_Release( p_block );
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 static void CloseDecoder( vlc_object_t *p_this )
diff --git a/modules/codec/cc.c b/modules/codec/cc.c
index eacc3d29b3..b62adda31f 100644
--- a/modules/codec/cc.c
+++ b/modules/codec/cc.c
@@ -225,7 +225,7 @@ struct decoder_sys_t
     bool b_opaque;
 };
 
-static subpicture_t *Decode( decoder_t *, block_t ** );
+static int Decode( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 
 /*****************************************************************************
@@ -260,8 +260,8 @@ static int Open( vlc_object_t *p_this )
             return VLC_EGENERIC;
     }
 
-    p_dec->pf_decode_sub = Decode;
-    p_dec->pf_flush      = Flush;
+    p_dec->pf_decode = Decode;
+    p_dec->pf_flush  = Flush;
 
     /* Allocate the memory needed to store the decoder's structure */
     p_dec->p_sys = p_sys = calloc( 1, sizeof( *p_sys ) );
@@ -301,15 +301,12 @@ static void     Push( decoder_t *, block_t * );
 static block_t *Pop( decoder_t * );
 static subpicture_t *Convert( decoder_t *, block_t ** );
 
-static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if( pp_block && *pp_block )
-    {
-        Push( p_dec, *pp_block );
-        *pp_block = NULL;
-    }
+    if( p_block )
+        Push( p_dec, p_block );
 
     for( ;; )
     {
@@ -331,9 +328,9 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
 
         subpicture_t *p_spu = Convert( p_dec, &p_sys->p_block );
         if( p_spu )
-            return p_spu;
+            decoder_QueueSub( p_dec, p_spu );
     }
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/cdg.c b/modules/codec/cdg.c
index b0e8ad65c2..3bb0c3141d 100644
--- a/modules/codec/cdg.c
+++ b/modules/codec/cdg.c
@@ -73,7 +73,7 @@ struct decoder_sys_t
 static int  Open ( vlc_object_t * );
 static void Close( vlc_object_t * );
 
-static picture_t *Decode( decoder_t *, block_t ** );
+static int Decode( decoder_t *, block_t * );
 
 static int DecodePacket( decoder_sys_t *p_cdg, uint8_t *p_buffer, int i_buffer );
 static void Flush( decoder_t * );
@@ -124,8 +124,8 @@ static int Open( vlc_object_t *p_this )
     p_dec->fmt_out.video.i_bmask = 0xff << CDG_COLOR_B_SHIFT;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = Decode;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = Decode;
+    p_dec->pf_flush  = Flush;
 
     return VLC_SUCCESS;
 }
@@ -145,15 +145,13 @@ static void Flush( decoder_t *p_dec )
  ****************************************************************************
  * This function must be fed with a complete compressed frame.
  ****************************************************************************/
-static picture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block;
     picture_t *p_pic = NULL;
 
-    if( !pp_block || !*pp_block )
-        return NULL;
-    p_block = *pp_block;
+    if( !p_block ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
@@ -185,8 +183,9 @@ static picture_t *Decode( decoder_t *p_dec, block_t **pp_block )
 
 exit:
     block_Release( p_block );
-    *pp_block = NULL;
-    return p_pic;
+    if( p_pic != NULL )
+        decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/crystalhd.c b/modules/codec/crystalhd.c
index f0c15877c6..9a8d2e7acc 100644
--- a/modules/codec/crystalhd.c
+++ b/modules/codec/crystalhd.c
@@ -96,7 +96,7 @@ vlc_module_end ()
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static picture_t *DecodeBlock   ( decoder_t *p_dec, block_t **pp_block );
+static int DecodeBlock   ( decoder_t *p_dec, block_t *p_block );
 // static void crystal_CopyPicture ( picture_t *, BC_DTS_PROC_OUT* );
 static int crystal_insert_sps_pps(decoder_t *, uint8_t *, uint32_t);
 
@@ -350,7 +350,7 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->fmt_out.video.i_height = p_dec->fmt_in.video.i_height;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
 
     msg_Info( p_dec, "Opened CrystalHD hardware with success" );
     return VLC_SUCCESS;
@@ -431,20 +431,19 @@ static BC_STATUS ourCallback(void *shnd, uint32_t width, uint32_t height, uint32
 /****************************************************************************
  * DecodeBlock: the whole thing
  ****************************************************************************/
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block = NULL;
 
     BC_DTS_PROC_OUT proc_out;
     BC_DTS_STATUS driver_stat;
 
     /* First check the status of the decode to produce pictures */
     if( BC_FUNC_PSYS(DtsGetDriverStatus)( p_sys->bcm_handle, &driver_stat ) != BC_STS_SUCCESS )
-        return NULL;
-
-    if( pp_block )
-        p_block = *pp_block;
+    {
+        block_Release( p_block );
+        return VLCDEC_SUCCESS;
+    }
 
     if( p_block )
     {
@@ -457,10 +456,9 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                                             p_block->i_pts >= VLC_TS_INVALID ? TO_BC_PTS(p_block->i_pts) : 0, false );
 
             block_Release( p_block );
-            *pp_block = NULL;
 
             if( status != BC_STS_SUCCESS )
-                return NULL;
+                return VLCDEC_SUCCESS;
         }
     }
 #ifdef DEBUG_CRYSTALHD
@@ -472,7 +470,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 #endif
 
     if( driver_stat.ReadyListCount == 0 )
-        return NULL;
+        return VLCDEC_SUCCESS;
 
     /* Prepare the Output structure */
     /* We always expect and use YUY2 */
@@ -508,7 +506,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             /* In interlaced mode, do not push the first field in the pipeline */
             if( (proc_out.PicInfo.flags & VDEC_FLAG_INTERLACED_SRC) &&
                !(proc_out.PicInfo.flags & VDEC_FLAG_FIELDPAIR) )
-                return NULL;
+                return VLCDEC_SUCCESS;
 
             //  crystal_CopyPicture( p_pic, &proc_out );
             p_pic->date = proc_out.PicInfo.timeStamp > 0 ?
@@ -517,7 +515,8 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 #ifdef DEBUG_CRYSTALHD
             msg_Dbg( p_dec, "TS Output is %"PRIu64, p_pic->date);
 #endif
-            return p_pic;
+            decoder_QueueVideo( p_dec, p_pic );
+            return VLCDEC_SUCCESS;
 
         case BC_STS_DEC_NOT_OPEN:
         case BC_STS_DEC_NOT_STARTED:
@@ -585,7 +584,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     }
     if( p_pic )
         picture_Release( p_pic );
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 #if 0
diff --git a/modules/codec/cvdsub.c b/modules/codec/cvdsub.c
index 44269e3b45..29fdae2507 100644
--- a/modules/codec/cvdsub.c
+++ b/modules/codec/cvdsub.c
@@ -60,7 +60,7 @@ vlc_module_end ()
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static subpicture_t *Decode( decoder_t *, block_t ** );
+static int Decode( decoder_t *, block_t * );
 static block_t *Packetize  ( decoder_t *, block_t ** );
 static block_t *Reassemble ( decoder_t *, block_t * );
 static void ParseMetaInfo  ( decoder_t *, block_t * );
@@ -122,7 +122,7 @@ static int DecoderOpen( vlc_object_t *p_this )
     p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
     p_sys->p_spu   = NULL;
 
-    p_dec->pf_decode_sub = Decode;
+    p_dec->pf_decode     = Decode;
     p_dec->pf_packetize  = Packetize;
 
     p_dec->fmt_out.i_cat = SPU_ES;
@@ -160,25 +160,27 @@ void DecoderClose( vlc_object_t *p_this )
 /*****************************************************************************
  * Decode:
  *****************************************************************************/
-static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
-    block_t *p_block, *p_spu;
+    block_t *p_data;
 
-    if( pp_block == NULL || *pp_block == NULL ) return NULL;
-
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
-    if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
+    if( !(p_data = Reassemble( p_dec, p_block )) )
+        return VLCDEC_SUCCESS;
 
     /* Parse and decode */
-    return DecodePacket( p_dec, p_spu );
+    subpicture_t *p_spu = DecodePacket( p_dec, p_data );
+    if( p_spu != NULL )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/daala.c b/modules/codec/daala.c
index 7bcf7c7f5f..ca94b67107 100644
--- a/modules/codec/daala.c
+++ b/modules/codec/daala.c
@@ -80,9 +80,10 @@ static int  OpenDecoder   ( vlc_object_t * );
 static int  OpenPacketizer( vlc_object_t * );
 static void CloseDecoder  ( vlc_object_t * );
 
-static void *DecodeBlock  ( decoder_t *, block_t ** );
+static int DecodeVideo( decoder_t *p_dec, block_t *p_block );
+static block_t *Packetize ( decoder_t *, block_t ** );
 static int  ProcessHeaders( decoder_t * );
-static void *ProcessPacket ( decoder_t *, daala_packet *, block_t ** );
+static void *ProcessPacket ( decoder_t *, daala_packet *, block_t * );
 
 static picture_t *DecodePacket( decoder_t *, daala_packet * );
 
@@ -183,10 +184,8 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->fmt_out.i_codec = VLC_CODEC_I420;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
-    p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
+    p_dec->pf_decode    = DecodeVideo;
+    p_dec->pf_packetize = Packetize;
 
     /* Init supporting Daala structures needed in header parsing */
     daala_comment_init( &p_sys->dc );
@@ -215,16 +214,11 @@ static int OpenPacketizer( vlc_object_t *p_this )
  ****************************************************************************
  * This function must be fed with Daala packets.
  ****************************************************************************/
-static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static void *DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block;
     daala_packet dpacket;
 
-    if( !pp_block || !*pp_block ) return NULL;
-
-    p_block = *pp_block;
-
     /* Block to Daala packet */
     dpacket.packet = p_block->p_buffer;
     dpacket.bytes = p_block->i_buffer;
@@ -252,7 +246,28 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     if( !p_sys->b_decoded_first_keyframe )
         p_block->i_flags |= BLOCK_FLAG_PREROLL; /* Wait until we've decoded the first keyframe */
 
-    return ProcessPacket( p_dec, &dpacket, pp_block );
+    return ProcessPacket( p_dec, &dpacket, p_block );
+}
+
+static int DecodeVideo( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    picture_t *p_pic = DecodeBlock( p_dec, p_block );
+    if( p_pic != NULL )
+        decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
+}
+
+static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
+{
+    if( pp_block == NULL ) /* No Drain */
+        return NULL;
+    block_t *p_block = *pp_block; *pp_block = NULL;
+    if( p_block == NULL )
+        return NULL;
+    return DecodeBlock( p_dec, p_block );
 }
 
 /*****************************************************************************
@@ -402,10 +417,9 @@ cleanup:
  * ProcessPacket: processes a daala packet.
  *****************************************************************************/
 static void *ProcessPacket( decoder_t *p_dec, daala_packet *p_dpacket,
-                            block_t **pp_block )
+                            block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block = *pp_block;
     void *p_buf;
 
     if( ( p_block->i_flags&(BLOCK_FLAG_CORRUPTED) ) != 0 )
@@ -423,8 +437,6 @@ static void *ProcessPacket( decoder_t *p_dec, daala_packet *p_dpacket,
         p_sys->i_pts = p_block->i_pts;
     }
 
-    *pp_block = NULL; /* To avoid being fed the same packet again */
-
     if( p_sys->b_packetizer )
     {
         /* Date management */
diff --git a/modules/codec/dca.c b/modules/codec/dca.c
index d2f7e00e0f..78e55f23c9 100644
--- a/modules/codec/dca.c
+++ b/modules/codec/dca.c
@@ -122,14 +122,13 @@ static void Exchange( float * p_out, const float * p_in )
     }
 }
 
-static block_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_in_buf )
 {
     decoder_sys_t  *p_sys = p_dec->p_sys;
 
-    if (pp_block == NULL || *pp_block == NULL)
-        return NULL;
+    if (p_in_buf == NULL) /* No Drain */
+        return VLCDEC_SUCCESS;
 
-    block_t *p_in_buf = *pp_block;
     sample_t i_sample_level = 1;
     int  i_flags = p_sys->i_flags;
     size_t i_bytes_per_block = 256 * p_sys->i_nb_channels * sizeof(float);
@@ -212,9 +211,10 @@ static block_t *Decode( decoder_t *p_dec, block_t **pp_block )
     p_out_buf->i_pts = p_in_buf->i_pts;
     p_out_buf->i_length = p_in_buf->i_length;
 out:
+    if (p_out_buf != NULL)
+        decoder_QueueAudio(p_dec, p_out_buf);
     block_Release( p_in_buf );
-    *pp_block = NULL;
-    return p_out_buf;
+    return VLCDEC_SUCCESS;
 }
 
 static int channels_vlc2dca( const audio_format_t *p_audio, int *p_flags )
@@ -341,8 +341,8 @@ static int Open( vlc_object_t *p_this )
         return VLC_EGENERIC;
     }
 
-    p_dec->pf_decode_audio = Decode;
-    p_dec->pf_flush        = NULL;
+    p_dec->pf_decode = Decode;
+    p_dec->pf_flush  = NULL;
     return VLC_SUCCESS;
 }
 
diff --git a/modules/codec/ddummy.c b/modules/codec/ddummy.c
index 2e88bbcdff..28f18c84c0 100644
--- a/modules/codec/ddummy.c
+++ b/modules/codec/ddummy.c
@@ -64,7 +64,7 @@ vlc_module_end ()
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block );
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block );
 
 /*****************************************************************************
  * OpenDecoder: Open the decoder
@@ -93,12 +93,7 @@ static int OpenDecoderCommon( vlc_object_t *p_this, bool b_force_dump )
         p_dec->p_sys = NULL;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
-    p_dec->pf_decode_audio = (block_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
-    p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
 
     es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
 
@@ -120,14 +115,11 @@ static int  OpenDecoderDump( vlc_object_t *p_this )
  ****************************************************************************
  * This function must be fed with ogg packets.
  ****************************************************************************/
-static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     FILE *stream = (void *)p_dec->p_sys;
-    block_t *p_block;
 
-    if( !pp_block || !*pp_block ) return NULL;
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( !p_block ) return VLCDEC_SUCCESS;
 
     if( stream != NULL
      && p_block->i_buffer > 0
@@ -138,7 +130,7 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     }
     block_Release( p_block );
 
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/dmo/dmo.c b/modules/codec/dmo/dmo.c
index 4559380a39..f76fa6ccc6 100644
--- a/modules/codec/dmo/dmo.c
+++ b/modules/codec/dmo/dmo.c
@@ -75,7 +75,7 @@ static const int pi_channels_maps[7] =
  *****************************************************************************/
 static int  DecoderOpen  ( vlc_object_t * );
 static void DecoderClose ( vlc_object_t * );
-static void *DecodeBlock ( decoder_t *, block_t ** );
+static int DecodeBlock ( decoder_t *, block_t * );
 static void *DecoderThread( void * );
 static int  EncoderOpen  ( vlc_object_t * );
 static void EncoderClose ( vlc_object_t * );
@@ -125,10 +125,7 @@ struct decoder_sys_t
     vlc_mutex_t  lock;
     vlc_cond_t   wait_input, wait_output;
     bool         b_ready, b_works;
-    block_t    **pp_input;
-
-    int          i_output;
-    void       **pp_output;
+    block_t     *p_input;
 };
 
 const GUID IID_IWMCodecPrivateData = {0x73f0be8e, 0x57f7, 0x4f01, {0xaa, 0x66, 0x9f, 0x57, 0x34, 0xc, 0xfe, 0xe}};
@@ -271,18 +268,14 @@ found:
         return VLC_ENOMEM;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
-    p_dec->pf_decode_audio = (block_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
 
     vlc_mutex_init( &p_sys->lock );
     vlc_cond_init( &p_sys->wait_input );
     vlc_cond_init( &p_sys->wait_output );
     p_sys->b_works =
     p_sys->b_ready = false;
-    p_sys->pp_input = NULL;
-    TAB_INIT( p_sys->i_output, p_sys->pp_output );
+    p_sys->p_input = NULL;
 
     if( vlc_clone( &p_sys->thread, DecoderThread, p_dec,
                    VLC_THREAD_PRIORITY_INPUT ) )
@@ -319,38 +312,27 @@ static void DecoderClose( vlc_object_t *p_this )
     vlc_mutex_unlock( &p_sys->lock );
 
     vlc_join( p_sys->thread, NULL );
-    TAB_CLEAN( p_sys->i_output, p_sys->pp_output );
     vlc_cond_destroy( &p_sys->wait_input );
     vlc_cond_destroy( &p_sys->wait_output );
     vlc_mutex_destroy( &p_sys->lock );
     free( p_sys );
 }
 
-static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    void *p_ret;
-
-    vlc_mutex_lock( &p_sys->lock );
-    if( p_sys->i_output <= 0 )
-    {
-        p_sys->pp_input = pp_block;
-        vlc_cond_signal( &p_sys->wait_input );
-
-        while( p_sys->pp_input )
-            vlc_cond_wait( &p_sys->wait_output, &p_sys->lock );
-    }
 
-    p_ret = NULL;
-    if( p_sys->i_output > 0 )
-    {
-        p_ret = p_sys->pp_output[0];
-        TAB_REMOVE( p_sys->i_output, p_sys->pp_output, p_ret );
-    }
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
+    vlc_mutex_lock( &p_sys->lock );
+    while( p_sys->p_input )
+        vlc_cond_wait( &p_sys->wait_output, &p_sys->lock );
+    p_sys->p_input = p_block;
+    vlc_cond_signal( &p_sys->wait_input );
     vlc_mutex_unlock( &p_sys->lock );
 
-    return p_ret;
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -836,7 +818,7 @@ static void DecClose( decoder_t *p_dec )
  ****************************************************************************
  * This function must be fed with packets.
  ****************************************************************************/
-static void *DecBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecBlock( decoder_t *p_dec, block_t **pp_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_block;
@@ -847,8 +829,6 @@ static void *DecBlock( decoder_t *p_dec, block_t **pp_block )
     block_t block_out;
     uint32_t i_status;
 
-    if( !pp_block ) return NULL;
-
     p_block = *pp_block;
 
     /* Won't work with streams with B-frames, but do we have any ? */
@@ -867,7 +847,7 @@ static void *DecBlock( decoder_t *p_dec, block_t **pp_block )
     {
         /* We've just started the stream, wait for the first PTS. */
         if( p_block ) block_Release( p_block );
-        return NULL;
+        return -1;
     }
 #endif
 
@@ -890,7 +870,7 @@ static void *DecBlock( decoder_t *p_dec, block_t **pp_block )
 #ifdef DMO_DEBUG
             msg_Dbg( p_dec, "ProcessInput(): no output generated" );
 #endif
-            return NULL;
+            return -1;
         }
         else if( i_result == (int)DMO_E_NOTACCEPTING )
         {
@@ -900,21 +880,17 @@ static void *DecBlock( decoder_t *p_dec, block_t **pp_block )
         else if( i_result != S_OK )
         {
             msg_Dbg( p_dec, "ProcessInput(): failed" );
-            return NULL;
+            return -1;
         }
         else
         {
 #ifdef DMO_DEBUG
             msg_Dbg( p_dec, "ProcessInput(): successful" );
 #endif
+            block_Release( p_block );
             *pp_block = NULL;
         }
     }
-    else if( p_block && !p_block->i_buffer )
-    {
-        block_Release( p_block );
-        *pp_block = NULL;
-    }
 
     /* Get output from the DMO */
     block_out.p_buffer = p_sys->p_buffer;
@@ -938,7 +914,7 @@ static void *DecBlock( decoder_t *p_dec, block_t **pp_block )
 #endif
 
         p_out->vt->Release( (IUnknown *)p_out );
-        return NULL;
+        return -1;
     }
 
 #ifdef DMO_DEBUG
@@ -951,16 +927,16 @@ static void *DecBlock( decoder_t *p_dec, block_t **pp_block )
         msg_Dbg( p_dec, "ProcessOutput(): no output (i_buffer_out == 0)" );
 #endif
         p_out->vt->Release( (IUnknown *)p_out );
-        return NULL;
+        return -1;
     }
 
     if( p_dec->fmt_out.i_cat == VIDEO_ES )
     {
         /* Get a new picture */
         if( decoder_UpdateVideoFormat( p_dec ) )
-            return NULL;
+            return -1;
         picture_t *p_pic = decoder_NewPicture( p_dec );
-        if( !p_pic ) return NULL;
+        if( !p_pic ) return -1;
 
         CopyPicture( p_pic, block_out.p_buffer );
 
@@ -970,14 +946,15 @@ static void *DecBlock( decoder_t *p_dec, block_t **pp_block )
 
         p_out->vt->Release( (IUnknown *)p_out );
 
-        return p_pic;
+        decoder_QueueVideo( p_dec, p_pic );
+        return 0;
     }
     else
     {
         if( decoder_UpdateAudioFormat( p_dec ) )
         {
             p_out->vt->Release( (IUnknown *)p_out );
-            return NULL;
+            return -1;
         }
 
         block_t *p_aout_buffer;
@@ -998,10 +975,9 @@ static void *DecBlock( decoder_t *p_dec, block_t **pp_block )
         }
         p_out->vt->Release( (IUnknown *)p_out );
 
-        return p_aout_buffer;
+        decoder_QueueAudio( p_dec, p_aout_buffer );
+        return 0;
     }
-
-    return NULL;
 }
 
 static void CopyPicture( picture_t *p_pic, uint8_t *p_in )
@@ -1043,19 +1019,17 @@ static void *DecoderThread( void *data )
     vlc_mutex_lock( &p_sys->lock );
     for( ;; )
     {
-        while( p_sys->b_ready && !p_sys->pp_input )
+        while( p_sys->b_ready && !p_sys->p_input )
             vlc_cond_wait( &p_sys->wait_input, &p_sys->lock );
         if( !p_sys->b_ready )
             break;
 
-        for( ;; )
-        {
-            void *p_output = DecBlock( p_dec, p_sys->pp_input );
-            if( !p_output )
-                break;
-            TAB_APPEND( p_sys->i_output, p_sys->pp_output, p_output );
-        }
-        p_sys->pp_input = NULL;
+        while( DecBlock( p_dec, &p_sys->p_input ) == 0 );
+
+        if( p_sys->p_input != NULL )
+            block_Release( p_sys->p_input );
+        p_sys->p_input = NULL;
+
         vlc_cond_signal( &p_sys->wait_output );
     }
     vlc_mutex_unlock( &p_sys->lock );
diff --git a/modules/codec/dvbsub.c b/modules/codec/dvbsub.c
index 85b8a6d520..00a31edb04 100644
--- a/modules/codec/dvbsub.c
+++ b/modules/codec/dvbsub.c
@@ -107,7 +107,7 @@ static const char *const ppsz_pos_descriptions[] =
  *****************************************************************************/
 static int  Open ( vlc_object_t * );
 static void Close( vlc_object_t * );
-static subpicture_t *Decode( decoder_t *, block_t ** );
+static int Decode( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 
 #ifdef ENABLE_SOUT
@@ -334,8 +334,8 @@ static int Open( vlc_object_t *p_this )
         return VLC_EGENERIC;
     }
 
-    p_dec->pf_decode_sub = Decode;
-    p_dec->pf_flush      = Flush;
+    p_dec->pf_decode = Decode;
+    p_dec->pf_flush  = Flush;
     p_sys = p_dec->p_sys = calloc( 1, sizeof(decoder_sys_t) );
     if( !p_sys )
         return VLC_ENOMEM;
@@ -404,15 +404,12 @@ static void Flush( decoder_t *p_dec )
 /*****************************************************************************
  * Decode:
  *****************************************************************************/
-static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t       *p_block;
-    subpicture_t  *p_spu = NULL;
 
-    if( ( pp_block == NULL ) || ( *pp_block == NULL ) ) return NULL;
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) )
     {
@@ -420,7 +417,7 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
         if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
         {
             block_Release( p_block );
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
     }
 
@@ -438,7 +435,7 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
         msg_Warn( p_dec, "non dated subtitle" );
 #endif
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     bs_init( &p_sys->bs, p_block->p_buffer, p_block->i_buffer );
@@ -447,14 +444,14 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
     {
         msg_Dbg( p_dec, "invalid data identifier" );
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     if( bs_read( &p_sys->bs, 8 ) ) /* Subtitle stream id */
     {
         msg_Dbg( p_dec, "invalid subtitle stream id" );
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
 #ifdef DEBUG_DVBSUB
@@ -471,16 +468,20 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
     {
         msg_Warn( p_dec, "end marker not found (corrupted subtitle ?)" );
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* Check if the page is to be displayed */
     if( p_sys->p_page && p_sys->b_page )
-        p_spu = render( p_dec );
+    {
+        subpicture_t *p_spu = render( p_dec );
+        if( p_spu != NULL )
+            decoder_QueueSub( p_dec, p_spu );
+    }
 
     block_Release( p_block );
 
-    return p_spu;
+    return VLCDEC_SUCCESS;
 }
 
 /* following functions are local */
diff --git a/modules/codec/faad.c b/modules/codec/faad.c
index 137188c854..3443543470 100644
--- a/modules/codec/faad.c
+++ b/modules/codec/faad.c
@@ -59,7 +59,7 @@ vlc_module_end ()
 /****************************************************************************
  * Local prototypes
  ****************************************************************************/
-static block_t *DecodeBlock( decoder_t *, block_t ** );
+static int DecodeBlock( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 static void DoReordering( uint32_t *, uint32_t *, int, int, uint32_t * );
 
@@ -195,8 +195,8 @@ static int Open( vlc_object_t *p_this )
 
     p_sys->b_sbr = p_sys->b_ps = false;
 
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = Flush;
     return VLC_SUCCESS;
 }
 
@@ -213,15 +213,12 @@ static void Flush( decoder_t *p_dec )
 /*****************************************************************************
  * DecodeBlock:
  *****************************************************************************/
-static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block;
 
-    if( !pp_block || !*pp_block ) return NULL;
-
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( !p_block ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) )
     {
@@ -229,7 +226,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED) )
         {
             block_Release( p_block );
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
     }
 
@@ -305,7 +302,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                           &i_rate, &i_channels ) < 0 )
         {
             block_Release( p_block );
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
 
         p_dec->fmt_out.audio.i_rate = i_rate;
@@ -325,7 +322,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         /* We've just started the stream, wait for the first PTS. */
         block_Release( p_block );
         p_sys->i_buffer = 0;
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* Decode all data */
@@ -387,7 +384,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             /* Flush the buffer */
             p_sys->i_buffer = 0;
             block_Release( p_block );
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
 
         if( frame.channels <= 0 || frame.channels > 8 || frame.channels == 7 )
@@ -402,7 +399,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                          p_sys->i_buffer );
             }
             block_Release( p_block );
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
 
         if( frame.samples <= 0 )
@@ -422,7 +419,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                 p_sys->i_buffer = 0;
             }
             block_Release( p_block );
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
 
         /* We decoded a valid frame */
@@ -500,7 +497,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         {
             p_sys->i_buffer = 0;
             block_Release( p_block );
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
 
         p_out->i_pts = date_Get( &p_sys->date );
@@ -520,7 +517,8 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         }
 
         block_Release( p_block );
-        return p_out;
+        decoder_QueueAudio( p_dec, p_out );
+        return VLCDEC_SUCCESS;
     }
     else
     {
@@ -529,7 +527,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     }
 
     block_Release( p_block );
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/flac.c b/modules/codec/flac.c
index 504b0fac6d..92b7aa6146 100644
--- a/modules/codec/flac.c
+++ b/modules/codec/flac.c
@@ -102,7 +102,7 @@ static int OpenEncoder   ( vlc_object_t * );
 static void CloseEncoder ( vlc_object_t * );
 #endif
 
-static block_t *DecodeBlock( decoder_t *, block_t ** );
+static int DecodeBlock( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 
 /*****************************************************************************
@@ -361,8 +361,8 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->fmt_out.i_codec = VLC_CODEC_S32N;
 
     /* Set callbacks */
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = Flush;
 
     return VLC_SUCCESS;
 }
@@ -509,28 +509,26 @@ static void Flush( decoder_t *p_dec )
 /****************************************************************************
  * DecodeBlock: the whole thing
  ****************************************************************************/
-static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if( !pp_block || !*pp_block )
-        return NULL;
-    if( (*pp_block)->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) )
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+    if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY | BLOCK_FLAG_CORRUPTED) )
     {
         Flush( p_dec );
-        if( (*pp_block)->i_flags & BLOCK_FLAG_CORRUPTED )
+        if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
         {
-            block_Release( *pp_block );
-            *pp_block = NULL;
-            return NULL;
+            block_Release( p_block );
+            return VLCDEC_SUCCESS;
         }
     }
 
     if( !p_sys->b_stream_info )
         ProcessHeader( p_dec );
 
-    p_sys->p_block = *pp_block;
-    *pp_block = NULL;
+    p_sys->p_block = p_block;
 
     if( p_sys->p_block->i_pts > VLC_TS_INVALID &&
         p_sys->p_block->i_pts != date_Get( &p_sys->end_date ) )
@@ -562,7 +560,9 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     block_Release( p_sys->p_block );
     p_sys->p_block = NULL;
 
-    return p_sys->p_aout_buffer;
+    if( p_sys->p_aout_buffer != NULL )
+        decoder_QueueAudio( p_dec, p_sys->p_aout_buffer );
+    return VLCDEC_SUCCESS;
 }
 
 #ifdef ENABLE_SOUT
diff --git a/modules/codec/fluidsynth.c b/modules/codec/fluidsynth.c
index b7e43b348f..93c803a4b7 100644
--- a/modules/codec/fluidsynth.c
+++ b/modules/codec/fluidsynth.c
@@ -97,7 +97,7 @@ struct decoder_sys_t
 };
 
 
-static block_t *DecodeBlock (decoder_t *p_dec, block_t **pp_block);
+static int  DecodeBlock (decoder_t *p_dec, block_t *p_block);
 static void Flush (decoder_t *);
 
 static int Open (vlc_object_t *p_this)
@@ -181,8 +181,8 @@ static int Open (vlc_object_t *p_this)
     date_Set (&p_sys->end_date, 0);
 
     p_dec->p_sys = p_sys;
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = Flush;
     return VLC_SUCCESS;
 }
 
@@ -209,18 +209,13 @@ static void Flush (decoder_t *p_dec)
             fluid_synth_noteoff (p_sys->synth, channel, note);
 }
 
-static block_t *DecodeBlock (decoder_t *p_dec, block_t **pp_block)
+static int DecodeBlock (decoder_t *p_dec, block_t *p_block)
 {
-    block_t *p_block;
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_out = NULL;
 
-    if (pp_block == NULL)
-        return NULL;
-    p_block = *pp_block;
-    if (p_block == NULL)
-        return NULL;
-    *pp_block = NULL;
+    if (p_block == NULL) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
     {
@@ -228,7 +223,7 @@ static block_t *DecodeBlock (decoder_t *p_dec, block_t **pp_block)
         if (p_block->i_flags & BLOCK_FLAG_CORRUPTED)
         {
             block_Release(p_block);
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
     }
 
@@ -310,5 +305,7 @@ static block_t *DecodeBlock (decoder_t *p_dec, block_t **pp_block)
                              p_out->p_buffer, 1, 2);
 drop:
     block_Release (p_block);
-    return p_out;
+    if (p_out != NULL)
+        decoder_QueueAudio (p_dec, p_out);
+    return VLCDEC_SUCCESS;
 }
diff --git a/modules/codec/g711.c b/modules/codec/g711.c
index ec7292d481..6154e453e7 100644
--- a/modules/codec/g711.c
+++ b/modules/codec/g711.c
@@ -34,7 +34,7 @@
 
 static int  DecoderOpen ( vlc_object_t * );
 static void DecoderClose( vlc_object_t * );
-static block_t *DecodeBlock( decoder_t *, block_t ** );
+static int DecodeBlock( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 
 #ifdef ENABLE_SOUT
@@ -184,8 +184,8 @@ static int DecoderOpen( vlc_object_t *p_this )
         return VLC_ENOMEM;
 
     /* Set output properties */
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = Flush;
     p_dec->p_sys = p_sys;
 
     p_dec->fmt_out.i_cat = AUDIO_ES;
@@ -221,21 +221,17 @@ static void Flush( decoder_t *p_dec )
     date_Set( &p_sys->end_date, 0 );
 }
 
-static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if( pp_block == NULL )
-        return NULL;
-    block_t *p_block = *pp_block;
-    *pp_block = NULL;
-    if( p_block == NULL )
-        return NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
         block_Release( p_block);
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
@@ -250,7 +246,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     {
         /* We've just started the stream, wait for the first PTS. */
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* Don't re-use the same pts twice */
@@ -260,19 +256,19 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     if( samples == 0 )
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     if( decoder_UpdateAudioFormat( p_dec ) )
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
     block_t *p_out = decoder_NewAudioBuffer( p_dec, samples );
     if( p_out == NULL )
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     assert( p_out->i_nb_samples == samples );
@@ -291,7 +287,8 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
        *(dst++) = p_sys->table[*(src++)];
 
     block_Release( p_block );
-    return p_out;
+    decoder_QueueAudio( p_dec, p_out );
+    return VLCDEC_SUCCESS;
 }
 
 static void DecoderClose( vlc_object_t *p_this )
diff --git a/modules/codec/gstreamer/gstdecode.c b/modules/codec/gstreamer/gstdecode.c
index 3b069df4ae..89cc39bb73 100644
--- a/modules/codec/gstreamer/gstdecode.c
+++ b/modules/codec/gstreamer/gstdecode.c
@@ -70,7 +70,7 @@ typedef struct
  *****************************************************************************/
 static int  OpenDecoder( vlc_object_t* );
 static void CloseDecoder( vlc_object_t* );
-static picture_t *DecodeBlock( decoder_t*, block_t** );
+static int  DecodeBlock( decoder_t*, block_t* );
 static void Flush( decoder_t * );
 
 #define MODULE_DESCRIPTION N_( "Uses GStreamer framework's plugins " \
@@ -609,8 +609,8 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_sys->b_running = true;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = Flush;
 
     return VLC_SUCCESS;
 
@@ -648,21 +648,15 @@ static void Flush( decoder_t *p_dec )
 }
 
 /* Decode */
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
-    block_t *p_block;
     picture_t *p_pic = NULL;
     decoder_sys_t *p_sys = p_dec->p_sys;
     GstMessage *p_msg;
     GstBuffer *p_buf;
 
-    if( !pp_block )
-        return NULL;
-
-    p_block = *pp_block;
-
-    if( !p_block )
-        goto check_messages;
+    if( !p_block ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( unlikely( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY |
                     BLOCK_FLAG_CORRUPTED ) ) )
@@ -736,7 +730,6 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     else
         block_Release( p_block );
 
-check_messages:
     /* Poll for any messages, errors */
     p_msg = gst_bus_pop_filtered( p_sys->p_bus,
             GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR |
@@ -813,8 +806,9 @@ check_messages:
     }
 
 done:
-    *pp_block = NULL;
-    return p_pic;
+    if( p_pic != NULL )
+        decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
 }
 
 /* Close the decoder instance */
diff --git a/modules/codec/jpeg.c b/modules/codec/jpeg.c
index 60f60c343b..5c26d1fc69 100644
--- a/modules/codec/jpeg.c
+++ b/modules/codec/jpeg.c
@@ -76,7 +76,7 @@ struct decoder_sys_t
 static int  OpenDecoder(vlc_object_t *);
 static void CloseDecoder(vlc_object_t *);
 
-static picture_t *DecodeBlock(decoder_t *, block_t **);
+static int DecodeBlock(decoder_t *, block_t *);
 
 /*
  * jpeg encoder descriptor
@@ -178,7 +178,7 @@ static int OpenDecoder(vlc_object_t *p_this)
     p_dec->fmt_out.i_cat = VIDEO_ES;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
 
     return VLC_SUCCESS;
 }
@@ -493,26 +493,20 @@ jpeg_GetOrientation( j_decompress_ptr cinfo )
 /*
  * This function must be fed with a complete compressed frame.
  */
-static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
+static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block;
     picture_t *p_pic = 0;
 
     JSAMPARRAY p_row_pointers = NULL;
 
-    if (!pp_block || !*pp_block)
-    {
-        return NULL;
-    }
-
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if (!p_block) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if (p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
         block_Release(p_block);
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* libjpeg longjmp's there in case of error */
@@ -581,7 +575,8 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
     p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts;
 
     block_Release(p_block);
-    return p_pic;
+    decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
 
 error:
 
@@ -589,7 +584,7 @@ error:
     free(p_row_pointers);
 
     block_Release(p_block);
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 /*
diff --git a/modules/codec/kate.c b/modules/codec/kate.c
index 55678d67e7..d6bca7e650 100644
--- a/modules/codec/kate.c
+++ b/modules/codec/kate.c
@@ -156,11 +156,12 @@ static void CloseDecoder  ( vlc_object_t * );
 static int OpenPacketizer( vlc_object_t *p_this );
 #endif
 
-static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block );
+static int  DecodeSub( decoder_t *p_dec, block_t *p_block );
+static block_t * Packetize( decoder_t *p_dec, block_t **pp_block );
 static void Flush( decoder_t * );
 static int ProcessHeaders( decoder_t *p_dec );
-static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
-                            block_t **pp_block );
+static void         *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
+                            block_t *p_block );
 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp,
                             block_t *p_block );
 static void ParseKateComments( decoder_t * );
@@ -351,11 +352,9 @@ static int OpenDecoder( vlc_object_t *p_this )
     msg_Dbg( p_dec, "kate: OpenDecoder");
 
     /* Set callbacks */
-    p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
-    p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode    = DecodeSub;
+    p_dec->pf_packetize = Packetize;
+    p_dec->pf_flush     = Flush;
 
     /* Allocate the memory needed to store the decoder's structure */
     if( ( p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)) ) == NULL )
@@ -476,18 +475,11 @@ static void Flush( decoder_t *p_dec )
  ****************************************************************************
  * This function must be fed with kate packets.
  ****************************************************************************/
-static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static void *DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block;
     kate_packet kp;
 
-    if( !pp_block || !*pp_block )
-        return NULL;
-
-    p_block = *pp_block;
-    *pp_block = NULL;
-
     if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
     {
 #ifdef HAVE_TIGER
@@ -514,13 +506,34 @@ static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     {
         if( ProcessHeaders( p_dec ) )
         {
-            block_Release( *pp_block );
+            block_Release( p_block );
             return NULL;
         }
         p_sys->b_has_headers = true;
     }
 
-    return ProcessPacket( p_dec, &kp, pp_block );
+    return ProcessPacket( p_dec, &kp, p_block );
+}
+
+static int DecodeSub( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    subpicture_t *p_spu = DecodeBlock( p_dec, p_block );
+    if( p_spu != NULL )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
+}
+
+static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
+{
+    if( pp_block == NULL ) /* No Drain */
+        return NULL;
+    block_t *p_block = *pp_block; *pp_block = NULL;
+    if( p_block == NULL )
+        return NULL;
+    return DecodeBlock( p_dec, p_block );
 }
 
 /*****************************************************************************
@@ -611,12 +624,10 @@ static int ProcessHeaders( decoder_t *p_dec )
 /*****************************************************************************
  * ProcessPacket: processes a kate packet.
  *****************************************************************************/
-static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
-                            block_t **pp_block )
+static void *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
+                            block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block = *pp_block;
-    subpicture_t *p_buf = NULL;
 
     /* Date management */
     if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
@@ -624,8 +635,6 @@ static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
         p_sys->i_pts = p_block->i_pts;
     }
 
-    *pp_block = NULL; /* To avoid being fed the same packet again */
-
 #ifdef ENABLE_PACKETIZER
     if( p_sys->b_packetizer )
     {
@@ -636,19 +645,17 @@ static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
             p_block->i_length = p_sys->i_pts - p_block->i_pts;
         else
             p_block->i_length = 0;
-
-        p_buf = p_block;
+        return p_block;
     }
     else
 #endif
     {
-        p_buf = DecodePacket( p_dec, p_kp, p_block );
+        subpicture_t *p_buf = DecodePacket( p_dec, p_kp, p_block );
 
         if( p_block )
             block_Release( p_block );
+        return p_buf;
     }
-
-    return p_buf;
 }
 
 /* nicked off blend.c */
diff --git a/modules/codec/libass.c b/modules/codec/libass.c
index cf4dfe6505..7d7f265f58 100644
--- a/modules/codec/libass.c
+++ b/modules/codec/libass.c
@@ -64,7 +64,7 @@ vlc_module_end ()
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static subpicture_t *DecodeBlock( decoder_t *, block_t ** );
+static int DecodeBlock( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 
 /* */
@@ -132,8 +132,8 @@ static int Create( vlc_object_t *p_this )
     if( p_dec->fmt_in.i_codec != VLC_CODEC_SSA )
         return VLC_EGENERIC;
 
-    p_dec->pf_decode_sub = DecodeBlock;
-    p_dec->pf_flush      = Flush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = Flush;
 
     p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
     if( !p_sys )
@@ -310,37 +310,33 @@ static void Flush( decoder_t *p_dec )
 /****************************************************************************
  * DecodeBlock:
  ****************************************************************************/
-static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
     subpicture_t *p_spu = NULL;
-    block_t *p_block;
 
-    if( !pp_block || *pp_block == NULL )
-        return NULL;
-
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
         Flush( p_dec );
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     if( p_block->i_buffer == 0 || p_block->p_buffer[0] == '\0' )
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     subpicture_updater_sys_t *p_spu_sys = malloc( sizeof(*p_spu_sys) );
     if( !p_spu_sys )
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     subpicture_updater_t updater = {
@@ -355,7 +351,7 @@ static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         msg_Warn( p_dec, "can't get spu buffer" );
         free( p_spu_sys );
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     p_spu_sys->p_img = NULL;
@@ -367,7 +363,7 @@ static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     {
         subpicture_Delete( p_spu );
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
     memcpy( p_spu_sys->p_subs_data, p_block->p_buffer,
             p_block->i_buffer );
@@ -391,7 +387,8 @@ static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 
     block_Release( p_block );
 
-    return p_spu;
+    decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 }
 
 /****************************************************************************
diff --git a/modules/codec/libmpeg2.c b/modules/codec/libmpeg2.c
index ef994d40c7..120844d804 100644
--- a/modules/codec/libmpeg2.c
+++ b/modules/codec/libmpeg2.c
@@ -110,7 +110,7 @@ struct decoder_sys_t
 static int  OpenDecoder( vlc_object_t * );
 static void CloseDecoder( vlc_object_t * );
 
-static picture_t *DecodeBlock( decoder_t *, block_t ** );
+static int DecodeVideo( decoder_t *, block_t *);
 #if MPEG2_RELEASE >= MPEG2_VERSION (0, 5, 0)
 static block_t   *GetCc( decoder_t *p_dec, bool pb_present[4] );
 #endif
@@ -240,8 +240,8 @@ static int OpenDecoder( vlc_object_t *p_this )
 
     p_sys->p_info = mpeg2_info( p_sys->p_mpeg2dec );
 
-    p_dec->pf_decode_video = DecodeBlock;
-    p_dec->pf_flush        = Reset;
+    p_dec->pf_decode = DecodeVideo;
+    p_dec->pf_flush  = Reset;
     p_dec->fmt_out.i_cat = VIDEO_ES;
     p_dec->fmt_out.i_codec = 0;
 
@@ -596,6 +596,18 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     return NULL;
 }
 
+static int DecodeVideo( decoder_t *p_dec, block_t *p_block)
+{
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    block_t **pp_block = &p_block;
+    picture_t *p_pic;
+    while( ( p_pic = DecodeBlock( p_dec, pp_block ) ) != NULL )
+        decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
+}
+
 /*****************************************************************************
  * CloseDecoder: libmpeg2 decoder destruction
  *****************************************************************************/
diff --git a/modules/codec/lpcm.c b/modules/codec/lpcm.c
index 97b9a485b5..c48d10d1dd 100644
--- a/modules/codec/lpcm.c
+++ b/modules/codec/lpcm.c
@@ -178,7 +178,8 @@ typedef struct
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static block_t *DecodeFrame  ( decoder_t *, block_t ** );
+static int DecodeFrame    ( decoder_t *, block_t * );
+static block_t *Packetize ( decoder_t *, block_t ** );
 static void Flush( decoder_t * );
 
 /* */
@@ -297,9 +298,9 @@ static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
     }
 
     /* Set callback */
-    p_dec->pf_decode_audio = DecodeFrame;
-    p_dec->pf_packetize    = DecodeFrame;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode    = DecodeFrame;
+    p_dec->pf_packetize = Packetize;
+    p_dec->pf_flush     = Flush;
 
     return VLC_SUCCESS;
 }
@@ -327,7 +328,7 @@ static void Flush( decoder_t *p_dec )
  ****************************************************************************
  * Beware, this function must be fed with complete frames (PES packet).
  *****************************************************************************/
-static block_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
+static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t       *p_block;
@@ -511,6 +512,14 @@ static block_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
     }
 }
 
+static int DecodeFrame( decoder_t *p_dec, block_t *p_block )
+{
+    block_t *p_out = Packetize( p_dec, &p_block );
+    if( p_out != NULL )
+        decoder_QueueAudio( p_dec, p_out );
+    return VLCDEC_SUCCESS;
+}
+
 /*****************************************************************************
  * CloseCommon : lpcm decoder destruction
  *****************************************************************************/
diff --git a/modules/codec/mad.c b/modules/codec/mad.c
index 9a9772c7aa..635b2eadcd 100644
--- a/modules/codec/mad.c
+++ b/modules/codec/mad.c
@@ -81,7 +81,7 @@ vlc_module_begin ()
 vlc_module_end ()
 
 /*****************************************************************************
- * DecodeBLock: decode an MPEG audio frame.
+ * DecodeBlock: decode an MPEG audio frame.
  *****************************************************************************/
 static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 {
@@ -216,6 +216,14 @@ reject:
     goto end;
 }
 
+static int DecodeAudio( decoder_t *p_dec, block_t *p_block )
+{
+    block_t **pp_block = p_block ? &p_block : NULL, *p_out;
+    while( ( p_out = DecodeBlock( p_dec, pp_block ) ) != NULL )
+        decoder_QueueAudio( p_dec, p_out );
+    return VLCDEC_SUCCESS;
+}
+
 static void DecodeFlush( decoder_t *p_dec )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
@@ -270,8 +278,8 @@ static int Open( vlc_object_t *p_this )
         return VLC_EGENERIC;
     }
 
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_flush = DecodeFlush;
+    p_dec->pf_decode = DecodeAudio;
+    p_dec->pf_flush  = DecodeFlush;
 
     return VLC_SUCCESS;
 }
diff --git a/modules/codec/mft.c b/modules/codec/mft.c
index 25e9cfd193..fbd85d4bdc 100644
--- a/modules/codec/mft.c
+++ b/modules/codec/mft.c
@@ -640,15 +640,13 @@ static void CopyPackedBufferToPicture(picture_t *p_pic, const uint8_t *p_src)
     }
 }
 
-static int ProcessOutputStream(decoder_t *p_dec, DWORD stream_id, void **result)
+static int ProcessOutputStream(decoder_t *p_dec, DWORD stream_id)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     HRESULT hr;
     picture_t *picture = NULL;
     block_t *aout_buffer = NULL;
 
-    *result = NULL;
-
     DWORD output_status = 0;
     MFT_OUTPUT_DATA_BUFFER output_buffer = { stream_id, p_sys->output_sample, 0, NULL };
     hr = IMFTransform_ProcessOutput(p_sys->mft, 0, 1, &output_buffer, &output_status);
@@ -762,9 +760,9 @@ static int ProcessOutputStream(decoder_t *p_dec, DWORD stream_id, void **result)
     }
 
     if (p_dec->fmt_in.i_cat == VIDEO_ES)
-        *result = picture;
+        decoder_QueueVideo(p_dec, picture);
     else
-        *result = aout_buffer;
+        decoder_QueueAudio(p_dec, aout_buffer);
 
     return VLC_SUCCESS;
 
@@ -777,42 +775,32 @@ error:
     return VLC_EGENERIC;
 }
 
-static void *DecodeSync(decoder_t *p_dec, block_t **pp_block)
+static int DecodeSync(decoder_t *p_dec, block_t *p_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if (!pp_block || !*pp_block)
-        return NULL;
+    if (!p_block) /* No Drain */
+        return VLCDEC_SUCCESS;
 
-    block_t *p_block = *pp_block;
     if (p_block->i_flags & (BLOCK_FLAG_CORRUPTED))
     {
         block_Release(p_block);
-        *pp_block = NULL;
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* Drain the output stream before sending the input packet. */
-    void *result = NULL;
-    if (ProcessOutputStream(p_dec, p_sys->output_stream_id, &result))
+    if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
         goto error;
-    if (result)
-        return result;
-
     if (ProcessInputStream(p_dec, p_sys->input_stream_id, p_block))
         goto error;
-
     block_Release(p_block);
-    *pp_block = NULL;
 
-    return NULL;
+    return VLCDEC_SUCCESS;
 
 error:
     msg_Err(p_dec, "Error in DecodeSync()");
-    if (p_block)
-        block_Release(p_block);
-    *pp_block = NULL;
-    return NULL;
+    block_Release(p_block);
+    return VLCDEC_SUCCESS;
 }
 
 static HRESULT DequeueMediaEvent(decoder_t *p_dec)
@@ -840,20 +828,18 @@ static HRESULT DequeueMediaEvent(decoder_t *p_dec)
     return S_OK;
 }
 
-static void *DecodeAsync(decoder_t *p_dec, block_t **pp_block)
+static int DecodeAsync(decoder_t *p_dec, block_t *p_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     HRESULT hr;
 
-    if (!pp_block || !*pp_block)
-        return NULL;
+    if (!p_block) /* No Drain */
+        return VLCDEC_SUCCESS;
 
-    block_t *p_block = *pp_block;
     if (p_block->i_flags & (BLOCK_FLAG_CORRUPTED))
     {
         block_Release(p_block);
-        *pp_block = NULL;
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* Dequeue all pending media events. */
@@ -866,10 +852,8 @@ static void *DecodeAsync(decoder_t *p_dec, block_t **pp_block)
     if (p_sys->pending_output_events > 0)
     {
         p_sys->pending_output_events -= 1;
-        void *result = NULL;
-        if (ProcessOutputStream(p_dec, p_sys->output_stream_id, &result))
+        if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
             goto error;
-        return result;
     }
 
     /* Poll the MFT and return decoded frames until the input stream is ready. */
@@ -888,10 +872,9 @@ static void *DecodeAsync(decoder_t *p_dec, block_t **pp_block)
         if (p_sys->pending_output_events > 0)
         {
             p_sys->pending_output_events -= 1;
-            void *result = NULL;
-            if (ProcessOutputStream(p_dec, p_sys->output_stream_id, &result))
+            if (ProcessOutputStream(p_dec, p_sys->output_stream_id))
                 goto error;
-            return result;
+            break;
         }
     }
 
@@ -900,15 +883,13 @@ static void *DecodeAsync(decoder_t *p_dec, block_t **pp_block)
         goto error;
 
     block_Release(p_block);
-    *pp_block = NULL;
 
-    return NULL;
+    return VLCDEC_SUCCESS;
 
 error:
     msg_Err(p_dec, "Error in DecodeAsync()");
     block_Release(p_block);
-    *pp_block = NULL;
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 static void DestroyMFT(decoder_t *p_dec);
@@ -1157,17 +1138,7 @@ int Open(vlc_object_t *p_this)
     if (AllocateOutputSample(p_dec, 0, &p_sys->output_sample))
         goto error;
 
-    if (p_sys->is_async)
-    {
-        p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))DecodeAsync;
-        p_dec->pf_decode_audio = (block_t   *(*)(decoder_t *, block_t **))DecodeAsync;
-    }
-    else
-    {
-        p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))DecodeSync;
-        p_dec->pf_decode_audio = (block_t   *(*)(decoder_t *, block_t **))DecodeSync;
-    }
-
+    p_dec->pf_decode = p_sys->is_async ? DecodeAsync : DecodeSync;
     p_dec->fmt_out.i_cat = p_dec->fmt_in.i_cat;
 
     return VLC_SUCCESS;
diff --git a/modules/codec/mpg123.c b/modules/codec/mpg123.c
index 559bf57266..90880f21bd 100644
--- a/modules/codec/mpg123.c
+++ b/modules/codec/mpg123.c
@@ -190,18 +190,15 @@ static int UpdateAudioFormat( decoder_t *p_dec )
 /****************************************************************************
  * DecodeBlock: the whole thing
  ****************************************************************************/
-static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     int i_err;
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_out = NULL;
 
-    block_t *p_block = pp_block ? *pp_block : NULL;
-
     /* Feed input block */
     if( p_block != NULL )
     {
-        *pp_block = NULL; /* avoid being fed the same packet again */
         if( !date_Get( &p_sys->end_date ) && p_block->i_pts <= VLC_TS_INVALID )
         {
             /* We've just started the stream, wait for the first PTS. */
@@ -240,7 +237,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         p_sys->p_out = block_Alloc( mpg123_outblock( p_sys->p_handle ) );
 
         if( unlikely( !p_sys->p_out ) )
-            return NULL;
+            return VLCDEC_SUCCESS;
     }
 
     /* Do the actual decoding now */
@@ -256,7 +253,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                      mpg123_plain_strerror( i_err ) );
             block_Release( p_sys->p_out );
             p_sys->p_out = NULL;
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
 
         i_err = mpg123_decode_frame( p_sys->p_handle, NULL, NULL, &i_bytes );
@@ -307,7 +304,9 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 end:
     if( p_block )
         block_Release( p_block );
-    return p_out;
+    if( p_out != NULL )
+        decoder_QueueAudio( p_dec, p_out );
+    return VLCDEC_SUCCESS;
 }
 
 
@@ -378,8 +377,8 @@ static int OpenDecoder( vlc_object_t *p_this )
 
     p_dec->fmt_out.audio.i_rate = 0; /* So end_date gets initialized */
     p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = Flush;
 
     msg_Dbg( p_this, "%4.4s->%4.4s, bits per sample: %i",
              (char *)&p_dec->fmt_in.i_codec,
diff --git a/modules/codec/oggspots.c b/modules/codec/oggspots.c
index 4fbd6e4b04..9db89c40e3 100644
--- a/modules/codec/oggspots.c
+++ b/modules/codec/oggspots.c
@@ -67,9 +67,10 @@ static int  OpenDecoder   (vlc_object_t*);
 static int  OpenPacketizer(vlc_object_t*);
 static void CloseDecoder  (vlc_object_t*);
 
-static void*      DecodeBlock  (decoder_t*, block_t**);
+static int        DecodeVideo  (decoder_t*, block_t*);
+static block_t*   Packetize  (decoder_t*, block_t**);
 static int        ProcessHeader(decoder_t*);
-static void*      ProcessPacket(decoder_t*, block_t**);
+static void*      ProcessPacket(decoder_t*, block_t*);
 static void       Flush        (decoder_t*);
 static picture_t* DecodePacket (decoder_t*, block_t*);
 
@@ -128,11 +129,9 @@ static int OpenDecoder(vlc_object_t* p_this)
     }
 
     /* Set callbacks */
-    p_dec->pf_decode_video = (picture_t*(*)(decoder_t*, block_t**))
-        DecodeBlock;
-    p_dec->pf_packetize    = (block_t*(*)(decoder_t*, block_t**))
-        DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode    = DecodeVideo;
+    p_dec->pf_packetize = Packetize;
+    p_dec->pf_flush     = Flush;
 
     return VLC_SUCCESS;
 }
@@ -156,22 +155,41 @@ static int OpenPacketizer(vlc_object_t* p_this)
  ****************************************************************************
  * This function must be fed with ogg packets.
  ****************************************************************************/
-static void* DecodeBlock(decoder_t* p_dec, block_t** pp_block)
+static void* DecodeBlock(decoder_t* p_dec, block_t* p_block)
 {
     decoder_sys_t* p_sys = p_dec->p_sys;
 
-    if (!pp_block || !*pp_block) return NULL;
-
     /* Check for headers */
     if (!p_sys->b_has_headers) {
         if (ProcessHeader(p_dec)) {
-            block_Release(*pp_block);
+            block_Release(p_block);
             return NULL;
         }
         p_sys->b_has_headers = true;
     }
 
-    return ProcessPacket(p_dec, pp_block);
+    return ProcessPacket(p_dec, p_block);
+}
+
+static int DecodeVideo( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    picture_t *p_pic = DecodeBlock( p_dec, p_block );
+    if( p_pic != NULL )
+        decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
+}
+
+static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
+{
+    if( pp_block == NULL ) /* No Drain */
+        return NULL;
+    block_t *p_block = *pp_block; *pp_block = NULL;
+    if( p_block == NULL )
+        return NULL;
+    return DecodeBlock( p_dec, p_block );
 }
 
 /*****************************************************************************
@@ -277,17 +295,11 @@ static void Flush(decoder_t* p_dec)
 /*****************************************************************************
  * ProcessPacket: processes an OggSpots packet.
  *****************************************************************************/
-static void* ProcessPacket(decoder_t* p_dec, block_t** pp_block)
+static void* ProcessPacket(decoder_t* p_dec, block_t* p_block)
 {
     decoder_sys_t* p_sys = p_dec->p_sys;
-    block_t* p_block = *pp_block;
     void* p_buf;
 
-    *pp_block = NULL; /* To avoid being fed the same packet again */
-
-    if (!p_block)
-        return NULL;
-
     if ( (p_block->i_flags & BLOCK_FLAG_DISCONTINUITY) != 0 ) {
         p_sys->i_pts = p_block->i_pts;
     }
diff --git a/modules/codec/omxil/mediacodec.c b/modules/codec/omxil/mediacodec.c
index a0879d771e..c42f9a1acb 100644
--- a/modules/codec/omxil/mediacodec.c
+++ b/modules/codec/omxil/mediacodec.c
@@ -61,7 +61,7 @@ struct csd
 #define DECODE_FLAG_RESTART (0x01)
 #define DECODE_FLASH_FLUSH (0x02)
 /**
- * Callback called when a new block is processed from DecodeCommon.
+ * Callback called when a new block is processed from DecodeBlock.
  * It returns -1 in case of error, 0 if block should be dropped, 1 otherwise.
  */
 typedef int (*dec_on_new_block_cb)(decoder_t *, block_t **);
@@ -72,7 +72,7 @@ typedef int (*dec_on_new_block_cb)(decoder_t *, block_t **);
 typedef void (*dec_on_flush_cb)(decoder_t *);
 
 /**
- * Callback called when DecodeCommon try to get an output buffer (pic or block).
+ * Callback called when DecodeBlock try to get an output buffer (pic or block).
  * It returns -1 in case of error, or the number of output buffer returned.
  */
 typedef int (*dec_process_output_cb)(decoder_t *, mc_api_out *, picture_t **,
@@ -82,7 +82,7 @@ struct decoder_sys_t
 {
     mc_api api;
 
-    /* Codec Specific Data buffer: sent in DecodeCommon after a start or a flush
+    /* Codec Specific Data buffer: sent in DecodeBlock after a start or a flush
      * with the BUFFER_FLAG_CODEC_CONFIG flag.*/
     block_t **pp_csd;
     size_t i_csd_count;
@@ -154,13 +154,12 @@ static int VideoVC1_OnNewBlock(decoder_t *, block_t **);
 static void Video_OnFlush(decoder_t *);
 static int Video_ProcessOutput(decoder_t *, mc_api_out *, picture_t **,
                                block_t **);
-static picture_t *DecodeVideo(decoder_t *, block_t **);
+static int DecodeBlock(decoder_t *, block_t *);
 
 static int Audio_OnNewBlock(decoder_t *, block_t **);
 static void Audio_OnFlush(decoder_t *);
 static int Audio_ProcessOutput(decoder_t *, mc_api_out *, picture_t **,
                                block_t **);
-static block_t *DecodeAudio(decoder_t *, block_t **);
 
 static void DecodeFlushLocked(decoder_t *);
 static void DecodeFlush(decoder_t *);
@@ -219,7 +218,7 @@ static void CSDFree(decoder_t *p_dec)
     p_sys->i_csd_count = 0;
 }
 
-/* Create the p_sys->p_csd that will be sent from DecodeCommon */
+/* Create the p_sys->p_csd that will be sent from DecodeBlock */
 static int CSDDup(decoder_t *p_dec, const struct csd *p_csd, size_t i_count)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
@@ -844,9 +843,8 @@ static int OpenDecoder(vlc_object_t *p_this, pf_MediaCodecApi_init pf_init)
         goto bailout;
     }
 
-    p_dec->pf_decode_video = DecodeVideo;
-    p_dec->pf_decode_audio = DecodeAudio;
-    p_dec->pf_flush        = DecodeFlush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = DecodeFlush;
 
     return VLC_SUCCESS;
 
@@ -1354,39 +1352,31 @@ static block_t *GetNextBlock(decoder_sys_t *p_sys, block_t *p_block)
         return p_block;
 }
 
-/**
- * DecodeCommon called from DecodeVideo or DecodeAudio.
- * It returns -1 in case of error, 0 otherwise.
- */
-static int DecodeCommon(decoder_t *p_dec, block_t **pp_block)
+static int DecodeBlock(decoder_t *p_dec, block_t *p_in_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     int i_ret;
     bool b_dequeue_timeout = false;
     bool b_draining;
 
-    if (pp_block != NULL && *pp_block == NULL)
-        return 0;
-
     vlc_mutex_lock(&p_sys->lock);
 
     if (p_sys->b_aborted)
         goto end;
 
-    if (pp_block != NULL)
+    if (p_in_block != NULL)
     {
-        block_t *p_block = *pp_block;
         b_draining = false;
-        if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
+        if (p_in_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
         {
             DecodeFlushLocked(p_dec);
             if (p_sys->b_aborted)
                 goto end;
-            if (p_block->i_flags & BLOCK_FLAG_CORRUPTED)
+            if (p_in_block->i_flags & BLOCK_FLAG_CORRUPTED)
                 goto end;
         }
 
-        if (p_block->i_flags & BLOCK_FLAG_INTERLACED_MASK
+        if (p_in_block->i_flags & BLOCK_FLAG_INTERLACED_MASK
          && !(p_sys->api.i_quirks & MC_API_VIDEO_QUIRKS_SUPPORT_INTERLACED))
         {
             /* Before Android 21 and depending on the vendor, MediaCodec can
@@ -1398,7 +1388,7 @@ static int DecodeCommon(decoder_t *p_dec, block_t **pp_block)
         }
 
         /* Parse input block */
-        if ((i_ret = p_sys->pf_on_new_block(p_dec, pp_block)) != 1)
+        if ((i_ret = p_sys->pf_on_new_block(p_dec, &p_in_block)) != 1)
         {
             if (i_ret != 0)
             {
@@ -1423,7 +1413,7 @@ static int DecodeCommon(decoder_t *p_dec, block_t **pp_block)
 
     if (p_sys->i_decode_flags & (DECODE_FLASH_FLUSH|DECODE_FLAG_RESTART))
     {
-        msg_Warn(p_dec, "Flushing from DecodeCommon");
+        msg_Warn(p_dec, "Flushing from DecodeBlock");
         const bool b_restart = p_sys->i_decode_flags & DECODE_FLAG_RESTART;
         p_sys->i_decode_flags = 0;
 
@@ -1448,7 +1438,7 @@ static int DecodeCommon(decoder_t *p_dec, block_t **pp_block)
             switch (i_ret)
             {
             case VLC_SUCCESS:
-                msg_Warn(p_dec, "Restarted from DecodeCommon");
+                msg_Warn(p_dec, "Restarted from DecodeBlock");
                 break;
             case VLC_ENOOBJ:
                 break;
@@ -1466,7 +1456,7 @@ static int DecodeCommon(decoder_t *p_dec, block_t **pp_block)
 
     /* Queue CSD blocks and input blocks */
     block_t *p_block = NULL;
-    while (b_draining || (p_block = GetNextBlock(p_sys, *pp_block)))
+    while (b_draining || (p_block = GetNextBlock(p_sys, p_in_block)))
     {
         int i_index;
 
@@ -1516,9 +1506,9 @@ static int DecodeCommon(decoder_t *p_dec, block_t **pp_block)
                     p_sys->b_output_ready = true;
                     vlc_cond_broadcast(&p_sys->cond);
 
-                    assert(p_block == *pp_block),
-                    block_Release(p_block);
-                    *pp_block = NULL;
+                    assert(p_block == p_in_block),
+                    block_Release(p_in_block);
+                    p_in_block = NULL;
                 }
                 b_dequeue_timeout = false;
                 if (b_draining)
@@ -1537,7 +1527,7 @@ static int DecodeCommon(decoder_t *p_dec, block_t **pp_block)
              * Vout is paused and when the Decoder is flushing. In that case,
              * the Vout won't release any output buffers, therefore MediaCodec
              * won't dequeue any input buffers. To work around this issue,
-             * release all output buffers if DecodeCommon is waiting more than
+             * release all output buffers if DecodeBlock is waiting more than
              * 1sec for a new input buffer. */
             if (!b_dequeue_timeout)
             {
@@ -1576,15 +1566,12 @@ static int DecodeCommon(decoder_t *p_dec, block_t **pp_block)
             msg_Err(p_dec, "OutThread timed out");
 
         vlc_mutex_unlock(&p_sys->lock);
-        return 0;
+        return VLCDEC_SUCCESS;
     }
 
 end:
-    if (pp_block && *pp_block)
-    {
-        block_Release(*pp_block);
-        *pp_block = NULL;
-    }
+    if (p_in_block)
+        block_Release(p_in_block);
     if (p_sys->b_aborted)
     {
         if (!p_sys->b_has_format)
@@ -1598,12 +1585,12 @@ end:
         else
             p_dec->b_error = true;
         vlc_mutex_unlock(&p_sys->lock);
-        return -1;
+        return VLCDEC_SUCCESS;
     }
     else
     {
         vlc_mutex_unlock(&p_sys->lock);
-        return 0;
+        return VLCDEC_SUCCESS;
     }
 }
 
@@ -1693,12 +1680,6 @@ static void Video_OnFlush(decoder_t *p_dec)
         InvalidateAllPictures(p_dec);
 }
 
-static picture_t *DecodeVideo(decoder_t *p_dec, block_t **pp_block)
-{
-    DecodeCommon(p_dec, pp_block);
-    return NULL;
-}
-
 static int Audio_OnNewBlock(decoder_t *p_dec, block_t **pp_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
@@ -1721,9 +1702,3 @@ static void Audio_OnFlush(decoder_t *p_dec)
 
     date_Set(&p_sys->audio.i_end_date, VLC_TS_INVALID);
 }
-
-static block_t *DecodeAudio(decoder_t *p_dec, block_t **pp_block)
-{
-    DecodeCommon(p_dec, pp_block);
-    return NULL;
-}
diff --git a/modules/codec/omxil/omxil.c b/modules/codec/omxil/omxil.c
index 8cc18d3005..2ae9bb1874 100644
--- a/modules/codec/omxil/omxil.c
+++ b/modules/codec/omxil/omxil.c
@@ -77,8 +77,8 @@ static int  OpenEncoder( vlc_object_t * );
 static int  OpenGeneric( vlc_object_t *, bool b_encode );
 static void CloseGeneric( vlc_object_t * );
 
-static picture_t *DecodeVideo( decoder_t *, block_t ** );
-static block_t *DecodeAudio ( decoder_t *, block_t ** );
+static int DecodeVideo( decoder_t *, block_t * );
+static int DecodeAudio ( decoder_t *, block_t * );
 static block_t *EncodeVideo( encoder_t *, picture_t * );
 static void Flush( decoder_t * );
 
@@ -1019,8 +1019,12 @@ static int OpenDecoder( vlc_object_t *p_this )
     status = OpenGeneric( p_this, false );
     if(status != VLC_SUCCESS) return status;
 
-    p_dec->pf_decode_video = DecodeVideo;
-    p_dec->pf_decode_audio = DecodeAudio;
+    switch( p_dec->fmt_in.i_cat )
+    {
+        case AUDIO_ES: p_dec->pf_decode = DecodeAudio; break;
+        case VIDEO_ES: p_dec->pf_decode = DecodeVideo; break;
+        default: vlc_assert_unreachable();
+    }
     p_dec->pf_flush        = Flush;
 
     return VLC_SUCCESS;
@@ -1538,32 +1542,28 @@ static void Flush( decoder_t *p_dec )
 /*****************************************************************************
  * DecodeVideo: Called to decode one frame
  *****************************************************************************/
-static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
+static int DecodeVideo( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    picture_t *p_pic = NULL;
     OMX_ERRORTYPE omx_error;
     unsigned int i;
-    block_t *p_block;
-
-    if( !pp_block || !*pp_block )
-        return NULL;
 
-    p_block = *pp_block;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     /* Check for errors from codec */
     if(p_sys->b_error)
     {
         msg_Dbg(p_dec, "error during decoding");
         block_Release( p_block );
-        return 0;
+        return VLCDEC_SUCCESS;
     }
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
         block_Release( p_block );
         Flush( p_dec );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* Use the aspect ratio provided by the input (ie read from packetizer).
@@ -1579,22 +1579,19 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
         p_dec->fmt_out.video.i_sar_den = p_dec->fmt_in.video.i_sar_den;
     }
 
-    /* Take care of decoded frames first */
-    if( DecodeVideoOutput( p_dec, &p_sys->out, &p_pic ) != 0 )
-        goto error;
-
     /* Loop as long as we haven't either got an input buffer (and cleared
      * *pp_block) or got an output picture */
     int max_polling_attempts = 100;
     int attempts = 0;
-    while( *pp_block && !p_pic ) {
+    while( p_block ) {
         bool b_reconfig = false;
 
-        if( DecodeVideoInput( p_dec, &p_sys->in, pp_block, 0, &b_reconfig ) != 0 )
+        if( DecodeVideoInput( p_dec, &p_sys->in, &p_block, 0, &b_reconfig ) != 0 )
             goto error;
 
+        picture_t *p_pic = NULL;
         /* If we don't have a p_pic from the first try. Try again */
-        if( !b_reconfig && !p_pic &&
+        if( !b_reconfig &&
             DecodeVideoOutput( p_dec, &p_sys->out, &p_pic ) != 0 )
             goto error;
 
@@ -1616,6 +1613,11 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
             }
         }
 
+        if( p_pic != NULL )
+        {
+            decoder_QueueVideo( p_dec, p_pic );
+            continue;
+        }
         attempts++;
         /* With opaque DR the output buffers are released by the
            vout therefore we implement a timeout for polling in
@@ -1631,46 +1633,44 @@ static picture_t *DecodeVideo( decoder_t *p_dec, block_t **pp_block )
                 picture_sys_t *p_picsys = invalid_picture->p_sys;
                 p_picsys->hw.p_dec = NULL;
                 p_picsys->hw.i_index = -1;
+                return VLCDEC_SUCCESS;
             } else {
                 /* If we cannot return a picture we must free the
                    block since the decoder will proceed with the
                    next block. */
                 block_Release(p_block);
-                *pp_block = NULL;
+                p_block = NULL;
+                return VLCDEC_SUCCESS;
             }
-            return invalid_picture;
 #endif
         }
     }
 
-    return p_pic;
+    return VLCDEC_SUCCESS;
 error:
     p_sys->b_error = true;
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
  * DecodeAudio: Called to decode one frame
  *****************************************************************************/
-block_t *DecodeAudio ( decoder_t *p_dec, block_t **pp_block )
+int DecodeAudio ( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_buffer = NULL;
     OMX_BUFFERHEADERTYPE *p_header;
     OMX_ERRORTYPE omx_error;
-    block_t *p_block;
     unsigned int i;
 
-    if( !pp_block || !*pp_block ) return NULL;
-
-    p_block = *pp_block;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     /* Check for errors from codec */
     if(p_sys->b_error)
     {
         msg_Dbg(p_dec, "error during decoding");
         block_Release( p_block );
-        return 0;
+        return VLCDEC_SUCCESS;
     }
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
@@ -1684,7 +1684,7 @@ block_t *DecodeAudio ( decoder_t *p_dec, block_t **pp_block )
                              p_sys->in.definition.nPortIndex, 0 );
         }
         p_sys->in.b_flushed = true;
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     if( !date_Get( &p_sys->end_date ) )
@@ -1693,13 +1693,13 @@ block_t *DecodeAudio ( decoder_t *p_dec, block_t **pp_block )
         {
             /* We've just started the stream, wait for the first PTS. */
             block_Release( p_block );
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
         date_Set( &p_sys->end_date, p_block->i_pts );
     }
 
     /* Take care of decoded frames first */
-    while(!p_buffer)
+    while (p_block != NULL)
     {
         unsigned int i_samples = 0;
 
@@ -1712,7 +1712,7 @@ block_t *DecodeAudio ( decoder_t *p_dec, block_t **pp_block )
         {
             if( decoder_UpdateAudioFormat( p_dec ) )
                 break;
-            p_buffer = decoder_NewAudioBuffer( p_dec, i_samples );
+            block_t *p_buffer = decoder_NewAudioBuffer( p_dec, i_samples );
             if( !p_buffer ) break; /* No audio buffer available */
 
             memcpy( p_buffer->p_buffer, p_header->pBuffer, p_buffer->i_buffer );
@@ -1726,25 +1726,25 @@ block_t *DecodeAudio ( decoder_t *p_dec, block_t **pp_block )
             p_buffer->i_pts = date_Get( &p_sys->end_date );
             p_buffer->i_length = date_Increment( &p_sys->end_date, i_samples ) -
                 p_buffer->i_pts;
+            decoder_QueueAudio( p_dec, p_buffer );
         }
 
         OMX_DBG( "FillThisBuffer %p, %p", (void *)p_header,
                  (void *)p_header->pBuffer );
         OMX_FIFO_GET(&p_sys->out.fifo, p_header);
         OMX_FillThisBuffer(p_sys->omx_handle, p_header);
-    }
 
+        /* Send the input buffer to the component */
+        OMX_FIFO_GET_TIMEOUT(&p_sys->in.fifo, p_header, 200000);
 
-    /* Send the input buffer to the component */
-    OMX_FIFO_GET_TIMEOUT(&p_sys->in.fifo, p_header, 200000);
+        if (p_header && p_header->nFlags & SENTINEL_FLAG) {
+            free(p_header);
+            goto reconfig;
+        }
 
-    if (p_header && p_header->nFlags & SENTINEL_FLAG) {
-        free(p_header);
-        goto reconfig;
-    }
+        if (!p_header)
+            continue;
 
-    if(p_header)
-    {
         p_header->nFilledLen = p_block->i_buffer;
         p_header->nOffset = 0;
         p_header->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
@@ -1775,7 +1775,7 @@ block_t *DecodeAudio ( decoder_t *p_dec, block_t **pp_block )
                  (void *)p_header->pBuffer, (unsigned)p_header->nFilledLen );
         OMX_EmptyThisBuffer(p_sys->omx_handle, p_header);
         p_sys->in.b_flushed = false;
-        *pp_block = NULL; /* Avoid being fed the same packet again */
+        p_block = NULL;
     }
 
 reconfig:
@@ -1789,10 +1789,10 @@ reconfig:
         CHECK_ERROR(omx_error, "PortReconfigure failed");
     }
 
-    return p_buffer;
+    return VLCDEC_SUCCESS;
 error:
     p_sys->b_error = true;
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/opus.c b/modules/codec/opus.c
index e7e238427f..68c479ca07 100644
--- a/modules/codec/opus.c
+++ b/modules/codec/opus.c
@@ -154,11 +154,12 @@ static const uint32_t pi_3channels_in[] =
  * Local prototypes
  ****************************************************************************/
 
-static block_t *DecodeBlock  ( decoder_t *, block_t ** );
+static block_t *Packetize ( decoder_t *, block_t ** );
+static int  DecodeAudio ( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 static int  ProcessHeaders( decoder_t * );
 static int  ProcessInitialHeader ( decoder_t *, ogg_packet * );
-static void *ProcessPacket( decoder_t *, ogg_packet *, block_t ** );
+static block_t *ProcessPacket( decoder_t *, ogg_packet *, block_t * );
 
 static block_t *DecodePacket( decoder_t *, ogg_packet *, int, int );
 
@@ -184,9 +185,9 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->fmt_out.i_cat = AUDIO_ES;
     p_dec->fmt_out.i_codec = VLC_CODEC_FL32;
 
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_packetize    = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode    = DecodeAudio;
+    p_dec->pf_packetize = Packetize;
+    p_dec->pf_flush     = Flush;
 
     p_sys->p_st = NULL;
 
@@ -198,17 +199,14 @@ static int OpenDecoder( vlc_object_t *p_this )
  ****************************************************************************
  * This function must be fed with ogg packets.
  ****************************************************************************/
-static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static block_t *DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     ogg_packet oggpacket;
 
-    if( !pp_block || !*pp_block)
-        return NULL;
-
     /* Block to Ogg packet */
-    oggpacket.packet = (*pp_block)->p_buffer;
-    oggpacket.bytes = (*pp_block)->i_buffer;
+    oggpacket.packet = p_block->p_buffer;
+    oggpacket.bytes = p_block->i_buffer;
 
     oggpacket.granulepos = -1;
     oggpacket.b_o_s = 0;
@@ -220,13 +218,34 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     {
         if( ProcessHeaders( p_dec ) )
         {
-            block_Release( *pp_block );
+            block_Release( p_block );
             return NULL;
         }
         p_sys->b_has_headers = true;
     }
 
-    return ProcessPacket( p_dec, &oggpacket, pp_block );
+    return ProcessPacket( p_dec, &oggpacket, p_block );
+}
+
+static int DecodeAudio( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    p_block = DecodeBlock( p_dec, p_block );
+    if( p_block != NULL )
+        decoder_QueueAudio( p_dec, p_block );
+    return VLCDEC_SUCCESS;
+}
+
+static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
+{
+    if( pp_block == NULL ) /* No Drain */
+        return NULL;
+    block_t *p_block = *pp_block; *pp_block = NULL;
+    if( p_block == NULL )
+        return NULL;
+    return DecodeBlock( p_dec, p_block );
 }
 
 /*****************************************************************************
@@ -374,15 +393,10 @@ static void Flush( decoder_t *p_dec )
 /*****************************************************************************
  * ProcessPacket: processes a Opus packet.
  *****************************************************************************/
-static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
-                            block_t **pp_block )
+static block_t *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
+                               block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block = *pp_block;
-    *pp_block = NULL; /* To avoid being fed the same packet again */
-
-    if( !p_block )
-        return NULL;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
diff --git a/modules/codec/png.c b/modules/codec/png.c
index 39f8b79435..dc91b775b5 100644
--- a/modules/codec/png.c
+++ b/modules/codec/png.c
@@ -66,7 +66,7 @@ struct decoder_sys_t
 static int  OpenDecoder   ( vlc_object_t * );
 static void CloseDecoder  ( vlc_object_t * );
 
-static picture_t *DecodeBlock  ( decoder_t *, block_t ** );
+static int DecodeBlock  ( decoder_t *, block_t * );
 
 /*
  * png encoder descriptor
@@ -127,7 +127,7 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->fmt_out.i_codec = VLC_CODEC_RGBA;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
 
     return VLC_SUCCESS;
 }
@@ -186,10 +186,9 @@ static void user_warning( png_structp p_png, png_const_charp warning_msg )
  ****************************************************************************
  * This function must be fed with a complete compressed frame.
  ****************************************************************************/
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block;
     picture_t *p_pic = 0;
 
     png_uint_32 i_width, i_height;
@@ -200,38 +199,38 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     png_infop p_info, p_end_info;
     png_bytep *volatile p_row_pointers = NULL;
 
-    if( !pp_block || !*pp_block ) return NULL;
+    if( !p_block ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
-    p_block = *pp_block;
     p_sys->b_error = false;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
-        block_Release( p_block ); *pp_block = NULL;
-        return NULL;
+        block_Release( p_block );
+        return VLCDEC_SUCCESS;
     }
 
     p_png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
     if( p_png == NULL )
     {
-        block_Release( p_block ); *pp_block = NULL;
-        return NULL;
+        block_Release( p_block );
+        return VLCDEC_SUCCESS;
     }
 
     p_info = png_create_info_struct( p_png );
     if( p_info == NULL )
     {
         png_destroy_read_struct( &p_png, NULL, NULL );
-        block_Release( p_block ); *pp_block = NULL;
-        return NULL;
+        block_Release( p_block );
+        return VLCDEC_SUCCESS;
     }
 
     p_end_info = png_create_info_struct( p_png );
     if( p_end_info == NULL )
     {
         png_destroy_read_struct( &p_png, &p_info, NULL );
-        block_Release( p_block ); *pp_block = NULL;
-        return NULL;
+        block_Release( p_block );
+        return VLCDEC_SUCCESS;
     }
 
     /* libpng longjmp's there in case of error */
@@ -298,15 +297,16 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 
     p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts;
 
-    block_Release( p_block ); *pp_block = NULL;
-    return p_pic;
+    block_Release( p_block );
+    decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
 
  error:
 
     free( p_row_pointers );
     png_destroy_read_struct( &p_png, &p_info, &p_end_info );
-    block_Release( p_block ); *pp_block = NULL;
-    return NULL;
+    block_Release( p_block );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/rawvideo.c b/modules/codec/rawvideo.c
index fabc4820c8..09ef1ba40c 100644
--- a/modules/codec/rawvideo.c
+++ b/modules/codec/rawvideo.c
@@ -144,15 +144,10 @@ static void Flush( decoder_t *p_dec )
  ****************************************************************************
  * This function must be fed with complete frames.
  ****************************************************************************/
-static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static block_t *DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if( pp_block == NULL || *pp_block == NULL )
-        return NULL;
-
-    block_t *p_block = *pp_block;
-
     if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
         date_Set( &p_sys->pts, p_block->i_dts );
 
@@ -187,7 +182,6 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         return NULL;
     }
 
-    *pp_block = NULL;
     return p_block;
 }
 
@@ -218,11 +212,14 @@ static void FillPicture( decoder_t *p_dec, block_t *p_block, picture_t *p_pic )
 /*****************************************************************************
  * DecodeFrame: decodes a video frame.
  *****************************************************************************/
-static picture_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
+static int DecodeFrame( decoder_t *p_dec, block_t *p_block )
 {
-    block_t *p_block = DecodeBlock( p_dec, pp_block );
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    p_block = DecodeBlock( p_dec, p_block );
     if( p_block == NULL )
-        return NULL;
+        return VLCDEC_SUCCESS;
 
     decoder_sys_t *p_sys = p_dec->p_sys;
 
@@ -233,7 +230,7 @@ static picture_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
     if( p_pic == NULL )
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     FillPicture( p_dec, p_block, p_pic );
@@ -255,7 +252,8 @@ static picture_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
         p_pic->b_progressive = true;
 
     block_Release( p_block );
-    return p_pic;
+    decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
 }
 
 static int OpenDecoder( vlc_object_t *p_this )
@@ -265,8 +263,8 @@ static int OpenDecoder( vlc_object_t *p_this )
     int ret = OpenCommon( p_dec );
     if( ret == VLC_SUCCESS )
     {
-        p_dec->pf_decode_video = DecodeFrame;
-        p_dec->pf_flush        = Flush;
+        p_dec->pf_decode = DecodeFrame;
+        p_dec->pf_flush  = Flush;
     }
     return ret;
 }
@@ -276,7 +274,15 @@ static int OpenDecoder( vlc_object_t *p_this )
  *****************************************************************************/
 static block_t *SendFrame( decoder_t *p_dec, block_t **pp_block )
 {
-    block_t *p_block = DecodeBlock( p_dec, pp_block );
+    if( pp_block == NULL ) /* No Drain */
+        return NULL;
+
+    block_t *p_block = *pp_block;
+    if( p_block == NULL )
+        return NULL;
+    *pp_block = NULL;
+
+    p_block = DecodeBlock( p_dec, p_block );
     if( p_block == NULL )
         return NULL;
 
diff --git a/modules/codec/schroedinger.c b/modules/codec/schroedinger.c
index 9febc22c11..77d8ae509e 100644
--- a/modules/codec/schroedinger.c
+++ b/modules/codec/schroedinger.c
@@ -524,7 +524,7 @@ vlc_module_end ()
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static picture_t *DecodeBlock  ( decoder_t *p_dec, block_t **pp_block );
+static int DecodeBlock  ( decoder_t *p_dec, block_t *p_block );
 static void Flush( decoder_t * );
 
 struct picture_free_t
@@ -588,8 +588,8 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->fmt_out.i_codec = VLC_CODEC_I420;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = Flush;
 
     return VLC_SUCCESS;
 }
@@ -758,20 +758,14 @@ static void Flush( decoder_t *p_dec )
  ****************************************************************************
  * Blocks need not be Dirac dataunit aligned.
  * If a block has a PTS signaled, it applies to the first picture at or after p_block
- *
- * If this function returns a picture (!NULL), it is called again and the
- * same block is resubmitted.  To avoid this, set *pp_block to NULL;
- * If this function returns NULL, the *pp_block is lost (and leaked).
- * This function must free all blocks when finished with them.
  ****************************************************************************/
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    if( !pp_block ) return NULL;
-
-    if ( *pp_block ) {
-        block_t *p_block = *pp_block;
+    if( !p_block ) /* No Drain */
+        return VLCDEC_SUCCESS;
+    else {
 
         /* reset the decoder when seeking as the decode in progress is invalid */
         /* discard the block as it is just a null magic block */
@@ -779,8 +773,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             Flush( p_dec );
 
             block_Release( p_block );
-            *pp_block = NULL;
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
 
         SchroBuffer *p_schrobuffer;
@@ -798,7 +791,6 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 
         /* this stops the same block being fed back into this function if
          * we were on the next iteration of this loop to output a picture */
-        *pp_block = NULL;
         schro_decoder_autoparse_push( p_sys->p_schro, p_schrobuffer );
         /* DO NOT refer to p_block after this point, it may have been freed */
     }
@@ -816,7 +808,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             break;
 
         case SCHRO_DECODER_NEED_BITS:
-            return NULL;
+            return VLCDEC_SUCCESS;
 
         case SCHRO_DECODER_NEED_FRAME:
             p_schroframe = CreateSchroFrameFromPic( p_dec );
@@ -824,7 +816,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             if( !p_schroframe )
             {
                 msg_Err( p_dec, "Could not allocate picture for decoder");
-                return NULL;
+                return VLCDEC_SUCCESS;
             }
 
             schro_decoder_add_output_picture( p_sys->p_schro, p_schroframe);
@@ -862,7 +854,8 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
             p_sys->i_lastpts = p_pic->date;
 
             schro_frame_unref( p_schroframe );
-            return p_pic;
+            decoder_QueueVideo( p_dec, p_pic );
+            return VLCDEC_SUCCESS;
         }
         case SCHRO_DECODER_EOS:
             /* NB, the new api will not emit _EOS, it handles the reset internally */
@@ -870,7 +863,7 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 
         case SCHRO_DECODER_ERROR:
             msg_Err( p_dec, "SCHRO_DECODER_ERROR");
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
     }
 }
diff --git a/modules/codec/scte18.c b/modules/codec/scte18.c
index 79954a8a92..2be6c9996e 100644
--- a/modules/codec/scte18.c
+++ b/modules/codec/scte18.c
@@ -169,12 +169,11 @@ error:
     return NULL;
 }
 
-static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
-    if ( pp_block == NULL || *pp_block == NULL )
-        return NULL;
-    block_t *p_block = *pp_block; *pp_block = NULL;
-    subpicture_t  *p_spu = NULL;
+    if ( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+    subpicture_t *p_spu = NULL;
 
     if (p_block->i_flags & (BLOCK_FLAG_CORRUPTED))
         goto exit;
@@ -213,7 +212,9 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
 
 exit:
     block_Release( p_block );
-    return p_spu;
+    if( p_spu != NULL )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 }
 
 static int Open( vlc_object_t *object )
@@ -235,7 +236,7 @@ static int Open( vlc_object_t *object )
     }
 
     dec->p_sys = p_sys;
-    dec->pf_decode_sub = Decode;
+    dec->pf_decode = Decode;
     es_format_Init( &dec->fmt_out, SPU_ES, 0 );
 
     return VLC_SUCCESS;
diff --git a/modules/codec/scte27.c b/modules/codec/scte27.c
index 03b7b2def7..bd959793c1 100644
--- a/modules/codec/scte27.c
+++ b/modules/codec/scte27.c
@@ -405,13 +405,12 @@ error:
     return NULL;
 }
 
-static subpicture_t *Decode(decoder_t *dec, block_t **block)
+static int Decode(decoder_t *dec, block_t *b)
 {
     decoder_sys_t *sys = dec->p_sys;
 
-    if (block == NULL || *block == NULL)
-        return NULL;
-    block_t *b = *block; *block = NULL;
+    if (b == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     subpicture_t *sub_first = NULL;
     subpicture_t **sub_last = &sub_first;
@@ -490,7 +489,9 @@ static subpicture_t *Decode(decoder_t *dec, block_t **block)
 
 exit:
     block_Release(b);
-    return sub_first;
+    if (sub_first != NULL)
+        decoder_QueueSub(dec, sub_first );
+    return VLCDEC_SUCCESS;
 }
 
 static int Open(vlc_object_t *object)
@@ -507,7 +508,7 @@ static int Open(vlc_object_t *object)
     sys->segment_size = 0;
     sys->segment_buffer = NULL;
 
-    dec->pf_decode_sub = Decode;
+    dec->pf_decode = Decode;
     es_format_Init(&dec->fmt_out, SPU_ES, VLC_CODEC_SPU);
     dec->fmt_out.video.i_chroma = VLC_CODEC_YUVP;
 
diff --git a/modules/codec/sdl_image.c b/modules/codec/sdl_image.c
index 40cce2c434..de7999ccec 100644
--- a/modules/codec/sdl_image.c
+++ b/modules/codec/sdl_image.c
@@ -49,7 +49,7 @@ struct decoder_sys_t
 static int  OpenDecoder   ( vlc_object_t * );
 static void CloseDecoder  ( vlc_object_t * );
 
-static picture_t *DecodeBlock  ( decoder_t *, block_t ** );
+static int DecodeBlock  ( decoder_t *, block_t * );
 
 /*****************************************************************************
  * Module descriptor
@@ -116,7 +116,7 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->fmt_out.i_codec = VLC_CODEC_RGB32;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
 
     return VLC_SUCCESS;
 }
@@ -126,21 +126,20 @@ static int OpenDecoder( vlc_object_t *p_this )
  ****************************************************************************
  * This function must be fed with a complete compressed frame.
  ****************************************************************************/
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block;
     picture_t *p_pic = NULL;
     SDL_Surface *p_surface;
     SDL_RWops *p_rw;
 
-    if( pp_block == NULL || *pp_block == NULL ) return NULL;
-    p_block = *pp_block;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
-        block_Release( p_block ); *pp_block = NULL;
-        return NULL;
+        block_Release( p_block );
+        return VLCDEC_SUCCESS;
     }
 
     p_rw = SDL_RWFromConstMem( p_block->p_buffer, p_block->i_buffer );
@@ -261,14 +260,12 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     p_pic->date = (p_block->i_pts > VLC_TS_INVALID) ?
         p_block->i_pts : p_block->i_dts;
 
-    SDL_FreeSurface( p_surface );
-    block_Release( p_block ); *pp_block = NULL;
-    return p_pic;
+    decoder_QueueVideo( p_dec, p_pic );
 
 error:
     if ( p_surface != NULL ) SDL_FreeSurface( p_surface );
-    block_Release( p_block ); *pp_block = NULL;
-    return NULL;
+    block_Release( p_block );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/spdif.c b/modules/codec/spdif.c
index 4fff770fc8..25e7c5616b 100644
--- a/modules/codec/spdif.c
+++ b/modules/codec/spdif.c
@@ -38,18 +38,12 @@ vlc_module_begin()
     set_callbacks(OpenDecoder, NULL)
 vlc_module_end()
 
-static block_t *
-DecodeBlock(decoder_t *p_dec, block_t **pp_block)
+static int
+DecodeBlock(decoder_t *p_dec, block_t *p_block)
 {
-    (void) p_dec;
-    if (pp_block != NULL)
-    {
-        block_t *p_block = *pp_block;
-        *pp_block = NULL;
-        return p_block;
-    }
-    else
-        return NULL;
+    if (p_block != NULL)
+        decoder_QueueAudio( p_dec, p_block );
+    return VLCDEC_SUCCESS;
 }
 
 static int
@@ -91,8 +85,8 @@ OpenDecoder(vlc_object_t *p_this)
         return VLC_EGENERIC;
     }
 
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_flush        = NULL;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = NULL;
 
     return VLC_SUCCESS;
 }
diff --git a/modules/codec/speex.c b/modules/codec/speex.c
index a3acad750d..dcea9a8de0 100644
--- a/modules/codec/speex.c
+++ b/modules/codec/speex.c
@@ -189,11 +189,12 @@ static const int pi_channels_maps[6] =
  * Local prototypes
  ****************************************************************************/
 
-static block_t *DecodeBlock  ( decoder_t *, block_t ** );
-static block_t *DecodeRtpSpeexPacket( decoder_t *, block_t **);
-static int  ProcessHeaders( decoder_t * );
-static int  ProcessInitialHeader ( decoder_t *, ogg_packet * );
-static void *ProcessPacket( decoder_t *, ogg_packet *, block_t ** );
+static block_t *Packetize  ( decoder_t *, block_t ** );
+static int      DecodeAudio  ( decoder_t *, block_t * );
+static int      DecodeRtpSpeexPacket( decoder_t *, block_t *);
+static int      ProcessHeaders( decoder_t * );
+static int      ProcessInitialHeader ( decoder_t *, ogg_packet * );
+static block_t *ProcessPacket( decoder_t *, ogg_packet *, block_t ** );
 static void Flush( decoder_t * );
 
 static block_t *DecodePacket( decoder_t *, ogg_packet * );
@@ -236,13 +237,13 @@ static int OpenDecoder( vlc_object_t *p_this )
     {
         msg_Dbg( p_dec, "Using RTP version of Speex decoder @ rate %d.",
         p_dec->fmt_in.audio.i_rate );
-        p_dec->pf_decode_audio = DecodeRtpSpeexPacket;
+        p_dec->pf_decode = DecodeRtpSpeexPacket;
     }
     else
     {
-        p_dec->pf_decode_audio = DecodeBlock;
+        p_dec->pf_decode = DecodeAudio;
     }
-    p_dec->pf_packetize    = DecodeBlock;
+    p_dec->pf_packetize    = Packetize;
     p_dec->pf_flush        = Flush;
 
     p_sys->p_state = NULL;
@@ -335,8 +336,6 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     decoder_sys_t *p_sys = p_dec->p_sys;
     ogg_packet oggpacket;
 
-    if( !pp_block ) return NULL;
-
     block_t *block = *pp_block;
 
     if( block != NULL )
@@ -385,6 +384,24 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     return ProcessPacket( p_dec, &oggpacket, pp_block );
 }
 
+static int DecodeAudio( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    block_t **pp_block = &p_block, *p_out;
+    while( ( p_out = DecodeBlock( p_dec, pp_block ) ) != NULL )
+        decoder_QueueAudio( p_dec, p_out );
+    return VLCDEC_SUCCESS;
+}
+
+static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
+{
+    if( pp_block == NULL ) /* No Drain */
+        return NULL;
+    return DecodeBlock( p_dec, pp_block );
+}
+
 /*****************************************************************************
  * ProcessHeaders: process Speex headers.
  *****************************************************************************/
@@ -545,8 +562,8 @@ static void Flush( decoder_t *p_dec )
 /*****************************************************************************
  * ProcessPacket: processes a Speex packet.
  *****************************************************************************/
-static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
-                            block_t **pp_block )
+static block_t *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
+                               block_t **pp_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_block = *pp_block;
@@ -651,16 +668,15 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
     }
 }
 
-static block_t *DecodeRtpSpeexPacket( decoder_t *p_dec, block_t **pp_block )
+static int DecodeRtpSpeexPacket( decoder_t *p_dec, block_t *p_speex_bit_block )
 {
-    block_t *p_speex_bit_block = *pp_block;
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_aout_buffer;
     int i_decode_ret;
     unsigned int i_speex_frame_size;
 
     if ( !p_speex_bit_block || p_speex_bit_block->i_pts <= VLC_TS_INVALID )
-        return NULL;
+        return VLCDEC_SUCCESS;
 
     /*
       If the SpeexBits buffer size is 0 (a default value),
@@ -672,7 +688,7 @@ static block_t *DecodeRtpSpeexPacket( decoder_t *p_dec, block_t **pp_block )
         if ( !p_sys->p_header )
         {
             msg_Err( p_dec, "Could not allocate a Speex header.");
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
 
         const SpeexMode *mode = speex_lib_get_mode((p_sys->rtp_rate / 8000) >> 1);
@@ -684,7 +700,7 @@ static block_t *DecodeRtpSpeexPacket( decoder_t *p_dec, block_t **pp_block )
         {
             msg_Err( p_dec, "Could not allocate a Speex decoder." );
             free( p_sys->p_header );
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
 
         /*
@@ -707,7 +723,7 @@ static block_t *DecodeRtpSpeexPacket( decoder_t *p_dec, block_t **pp_block )
             msg_Err( p_dec, "Could not determine the frame size." );
             speex_decoder_destroy( p_sys->p_state );
             free( p_sys->p_header );
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
         p_dec->fmt_out.audio.i_bytes_per_frame = i_speex_frame_size;
 
@@ -721,9 +737,8 @@ static block_t *DecodeRtpSpeexPacket( decoder_t *p_dec, block_t **pp_block )
     if ( !p_sys->p_header )
     {
         msg_Err( p_dec, "There is no valid Speex header found." );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
-    *pp_block = NULL;
 
     if ( !date_Get( &p_sys->end_date ) )
         date_Set( &p_sys->end_date, p_speex_bit_block->i_dts );
@@ -740,7 +755,7 @@ static block_t *DecodeRtpSpeexPacket( decoder_t *p_dec, block_t **pp_block )
     if ( !p_aout_buffer || p_aout_buffer->i_buffer == 0 )
     {
         msg_Err(p_dec, "Oops: No new buffer was returned!");
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /*
@@ -759,7 +774,7 @@ static block_t *DecodeRtpSpeexPacket( decoder_t *p_dec, block_t **pp_block )
     if ( i_decode_ret < 0 )
     {
         msg_Err( p_dec, "Decoding failed. Perhaps we have a bad stream?" );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /*
@@ -772,8 +787,8 @@ static block_t *DecodeRtpSpeexPacket( decoder_t *p_dec, block_t **pp_block )
 
     p_sys->i_frame_in_packet++;
     block_Release( p_speex_bit_block );
-
-    return p_aout_buffer;
+    decoder_QueueAudio( p_dec, p_aout_buffer );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/spudec/spudec.c b/modules/codec/spudec/spudec.c
index 4179e95c45..ae2a739f17 100644
--- a/modules/codec/spudec/spudec.c
+++ b/modules/codec/spudec/spudec.c
@@ -65,8 +65,8 @@ vlc_module_end ()
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static block_t *      Reassemble( decoder_t *, block_t ** );
-static subpicture_t * Decode    ( decoder_t *, block_t ** );
+static block_t *      Reassemble( decoder_t *, block_t * );
+static int            Decode    ( decoder_t *, block_t * );
 static block_t *      Packetize ( decoder_t *, block_t ** );
 
 /*****************************************************************************
@@ -93,8 +93,8 @@ static int DecoderOpen( vlc_object_t *p_this )
 
     es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_CODEC_SPU );
 
-    p_dec->pf_decode_sub = Decode;
-    p_dec->pf_packetize  = NULL;
+    p_dec->pf_decode    = Decode;
+    p_dec->pf_packetize = NULL;
 
     return VLC_SUCCESS;
 }
@@ -140,17 +140,19 @@ static void Close( vlc_object_t *p_this )
 /*****************************************************************************
  * Decode:
  *****************************************************************************/
-static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t       *p_spu_block;
     subpicture_t  *p_spu;
 
-    p_spu_block = Reassemble( p_dec, pp_block );
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+    p_spu_block = Reassemble( p_dec, p_block );
 
     if( ! p_spu_block )
     {
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* FIXME: what the, we shouldn’t need to allocate 64k of buffer --sam. */
@@ -167,7 +169,9 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
     p_sys->i_spu      = 0;
     p_sys->p_block    = NULL;
 
-    return p_spu;
+    if( p_spu != NULL )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -176,7 +180,13 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t       *p_spu = Reassemble( p_dec, pp_block );
+    if( pp_block == NULL ) /* No Drain */
+        return NULL;
+    block_t *p_block = *pp_block; *pp_block = NULL;
+    if( p_block == NULL )
+        return NULL;
+
+    block_t *p_spu = Reassemble( p_dec, p_block );
 
     if( ! p_spu )
     {
@@ -198,14 +208,9 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
 /*****************************************************************************
  * Reassemble:
  *****************************************************************************/
-static block_t *Reassemble( decoder_t *p_dec, block_t **pp_block )
+static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block;
-
-    if( pp_block == NULL || *pp_block == NULL ) return NULL;
-    p_block = *pp_block;
-    *pp_block = NULL;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
diff --git a/modules/codec/stl.c b/modules/codec/stl.c
index d51a52032e..71d89c059e 100644
--- a/modules/codec/stl.c
+++ b/modules/codec/stl.c
@@ -363,17 +363,14 @@ static void ResetGroups(decoder_sys_t *p_sys)
     memset(p_sys->groups, 0, sizeof(stl_sg_t) * (STL_GROUPS_MAX + 1));
 }
 
-static subpicture_t *Decode(decoder_t *p_dec, block_t **pp_block)
+static int Decode(decoder_t *p_dec, block_t *p_block)
 {
-    if (pp_block == NULL || *pp_block == NULL)
-        return NULL;
+    if (p_block == NULL) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     subpicture_t *p_sub_first = NULL;
     subpicture_t **pp_sub_last = &p_sub_first;
 
-    block_t *p_block = *pp_block;
-    *pp_block = NULL;
-
     if(p_block->i_buffer < STL_TTI_SIZE)
         p_block->i_flags |= BLOCK_FLAG_CORRUPTED;
 
@@ -384,7 +381,7 @@ static subpicture_t *Decode(decoder_t *p_dec, block_t **pp_block)
         if(p_block->i_flags & BLOCK_FLAG_CORRUPTED)
         {
             block_Release(p_block);
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
     }
 
@@ -422,7 +419,9 @@ static subpicture_t *Decode(decoder_t *p_dec, block_t **pp_block)
     }
 
     block_Release(p_block);
-    return p_sub_first;
+    if (p_sub_first != NULL)
+        decoder_QueueSub(p_dec, p_sub_first);
+    return VLCDEC_SUCCESS;
 }
 
 static int ExtractCCT(const decoder_t *dec, cct_number_value_t *cct_number)
@@ -472,7 +471,7 @@ static int Open(vlc_object_t *object)
         sys->groups[i].pp_segment_last = &sys->groups[i].p_segment;
 
     dec->p_sys = sys;
-    dec->pf_decode_sub = Decode;
+    dec->pf_decode = Decode;
     dec->fmt_out.i_cat = SPU_ES;
     dec->fmt_out.i_codec = 0;
     return VLC_SUCCESS;
diff --git a/modules/codec/subsdec.c b/modules/codec/subsdec.c
index f75a152372..e407c9adbf 100644
--- a/modules/codec/subsdec.c
+++ b/modules/codec/subsdec.c
@@ -209,7 +209,7 @@ struct decoder_sys_t
 };
 
 
-static subpicture_t   *DecodeBlock   ( decoder_t *, block_t ** );
+static int             DecodeBlock   ( decoder_t *, block_t * );
 static subpicture_t   *ParseText     ( decoder_t *, block_t * );
 static text_segment_t *ParseSubtitles(int *pi_align, const char * );
 
@@ -233,7 +233,7 @@ static int OpenDecoder( vlc_object_t *p_this )
             return VLC_EGENERIC;
     }
 
-    p_dec->pf_decode_sub = DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
     p_dec->fmt_out.i_cat = SPU_ES;
     p_dec->fmt_out.i_codec = 0;
 
@@ -320,27 +320,25 @@ static int OpenDecoder( vlc_object_t *p_this )
  ****************************************************************************
  * This function must be fed with complete subtitles units.
  ****************************************************************************/
-static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     subpicture_t *p_spu;
-    block_t *p_block;
 
-    if( !pp_block || *pp_block == NULL )
-        return NULL;
-
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     p_spu = ParseText( p_dec, p_block );
 
     block_Release( p_block );
-    return p_spu;
+    if( p_spu != NULL )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/substx3g.c b/modules/codec/substx3g.c
index cb7243aacb..79fa1030d8 100644
--- a/modules/codec/substx3g.c
+++ b/modules/codec/substx3g.c
@@ -33,8 +33,8 @@
 /*****************************************************************************
  * Module descriptor.
  *****************************************************************************/
-static int  Open ( vlc_object_t * );
-static subpicture_t *Decode( decoder_t *, block_t ** );
+static int Open ( vlc_object_t * );
+static int Decode( decoder_t *, block_t * );
 
 vlc_module_begin ()
     set_description( N_("tx3g subtitles decoder") )
@@ -59,7 +59,7 @@ static int Open( vlc_object_t *p_this )
     if( p_dec->fmt_in.i_codec != VLC_CODEC_TX3G )
         return VLC_EGENERIC;
 
-    p_dec->pf_decode_sub = Decode;
+    p_dec->pf_decode = Decode;
 
     p_dec->fmt_out.i_cat = SPU_ES;
     p_dec->fmt_out.i_codec = 0;
@@ -300,20 +300,18 @@ static void FontSizeConvert( const text_style_t *p_default_style, text_style_t *
 /*****************************************************************************
  * Decode:
  *****************************************************************************/
-static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
-    block_t       *p_block;
     subpicture_t  *p_spu = NULL;
 
-    if( ( pp_block == NULL ) || ( *pp_block == NULL ) ) return NULL;
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( ( p_block->i_flags & (BLOCK_FLAG_CORRUPTED) ) ||
           p_block->i_buffer < sizeof(uint16_t) )
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     uint8_t *p_buf = p_block->p_buffer;
@@ -327,12 +325,14 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
        )
     {
         psz_subtitle = FromCharset( "UTF-16", p_pszstart, i_psz_bytelength );
-        if ( !psz_subtitle ) return NULL;
+        if ( !psz_subtitle )
+            return VLCDEC_SUCCESS;
     }
     else
     {
         psz_subtitle = malloc( i_psz_bytelength + 1 );
-        if ( !psz_subtitle ) return NULL;
+        if ( !psz_subtitle )
+            return VLCDEC_SUCCESS;
         memcpy( psz_subtitle, p_pszstart, i_psz_bytelength );
         psz_subtitle[ i_psz_bytelength ] = '\0';
     }
@@ -352,7 +352,7 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
     {
         text_segment_Delete( p_segment3g->s );
         free( p_segment3g );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* Create the subpicture unit */
@@ -361,7 +361,7 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
     {
         text_segment_Delete( p_segment3g->s );
         free( p_segment3g );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
     subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
 
@@ -458,5 +458,7 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
 
     block_Release( p_block );
 
-    return p_spu;
+    if( p_spu != NULL )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 }
diff --git a/modules/codec/subsusf.c b/modules/codec/subsusf.c
index 361cae3e08..8360db61b8 100644
--- a/modules/codec/subsusf.c
+++ b/modules/codec/subsusf.c
@@ -99,7 +99,7 @@ struct decoder_sys_t
     int                 i_images;
 };
 
-static subpicture_t *DecodeBlock   ( decoder_t *, block_t ** );
+static int           DecodeBlock   ( decoder_t *, block_t * );
 static char         *CreatePlainText( char * );
 static int           ParseImageAttachments( decoder_t *p_dec );
 
@@ -126,7 +126,7 @@ static int OpenDecoder( vlc_object_t *p_this )
     if( ( p_dec->p_sys = p_sys = calloc(1, sizeof(decoder_sys_t)) ) == NULL )
         return VLC_ENOMEM;
 
-    p_dec->pf_decode_sub = DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
     p_dec->fmt_out.i_cat = SPU_ES;
     p_dec->fmt_out.i_codec = 0;
 
@@ -154,22 +154,19 @@ static int OpenDecoder( vlc_object_t *p_this )
  ****************************************************************************
  * This function must be fed with complete subtitles units.
  ****************************************************************************/
-static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     subpicture_t *p_spu;
-    block_t *p_block;
 
-    if( !pp_block || *pp_block == NULL )
-        return NULL;
-
-    p_block = *pp_block;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     p_spu = ParseText( p_dec, p_block );
 
     block_Release( p_block );
-    *pp_block = NULL;
-
-    return p_spu;
+    if( p_spu != NULL )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/svcdsub.c b/modules/codec/svcdsub.c
index 5cefa23a19..7961d94923 100644
--- a/modules/codec/svcdsub.c
+++ b/modules/codec/svcdsub.c
@@ -62,7 +62,7 @@ vlc_module_end ()
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static subpicture_t *Decode( decoder_t *, block_t ** );
+static int      Decode( decoder_t *, block_t * );
 static block_t *Packetize  ( decoder_t *, block_t ** );
 static block_t *Reassemble ( decoder_t *, block_t * );
 static void ParseHeader( decoder_t *, block_t * );
@@ -132,8 +132,8 @@ static int DecoderOpen( vlc_object_t *p_this )
 
     es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_CODEC_OGT );
 
-    p_dec->pf_decode_sub = Decode;
-    p_dec->pf_packetize  = Packetize;
+    p_dec->pf_decode    = Decode;
+    p_dec->pf_packetize = Packetize;
 
     return VLC_SUCCESS;
 }
@@ -163,23 +163,23 @@ void DecoderClose( vlc_object_t *p_this )
 /*****************************************************************************
  * Decode:
  *****************************************************************************/
-static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
-    block_t *p_block, *p_spu;
-
 #ifndef NDEBUG
     msg_Dbg( p_dec, "Decode" );
 #endif
 
-    if( pp_block == NULL || *pp_block == NULL ) return NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
-    p_block = *pp_block;
-    *pp_block = NULL;
-
-    if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
+    if( !(p_block = Reassemble( p_dec, p_block )) )
+        return VLCDEC_SUCCESS;
 
     /* Parse and decode */
-    return DecodePacket( p_dec, p_spu );
+    subpicture_t *p_spu = DecodePacket( p_dec, p_block );
+    if( p_spu != NULL )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/svg.c b/modules/codec/svg.c
index b2ea456df7..3da62ad9ae 100644
--- a/modules/codec/svg.c
+++ b/modules/codec/svg.c
@@ -45,7 +45,7 @@
 static int  OpenDecoder   ( vlc_object_t * );
 static void CloseDecoder  ( vlc_object_t * );
 
-static picture_t *DecodeBlock  ( decoder_t *, block_t ** );
+static int DecodeBlock  ( decoder_t *, block_t * );
 
 #define TEXT_WIDTH       N_("Image width")
 #define LONG_TEXT_WIDTH  N_("Specify the width to decode the image too")
@@ -112,7 +112,7 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->fmt_out.i_codec = VLC_CODEC_BGRA;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
 
     return VLC_SUCCESS;
 }
@@ -122,10 +122,9 @@ static int OpenDecoder( vlc_object_t *p_this )
  ****************************************************************************
  * This function must be fed with a complete image.
  ****************************************************************************/
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys  = (decoder_sys_t *) p_dec->p_sys;
-    block_t *p_block;
     picture_t *p_pic = NULL;
     int32_t i_width, i_height;
 
@@ -133,15 +132,13 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     cairo_surface_t *surface = NULL;
     cairo_t *cr = NULL;
 
-    if( !pp_block || !*pp_block ) return NULL;
-
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & BLOCK_FLAG_CORRUPTED)
     {
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     rsvg = rsvg_handle_new_from_data( p_block->p_buffer, p_block->i_buffer, NULL );
@@ -259,7 +256,9 @@ done:
         cairo_surface_destroy( surface );
 
     block_Release( p_block );
-    return p_pic;
+    if( p_pic != NULL )
+        decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/telx.c b/modules/codec/telx.c
index b0980c1b9f..07a2d7c68c 100644
--- a/modules/codec/telx.c
+++ b/modules/codec/telx.c
@@ -49,7 +49,7 @@
  *****************************************************************************/
 static int  Open ( vlc_object_t * );
 static void Close( vlc_object_t * );
-static subpicture_t *Decode( decoder_t *, block_t ** );
+static int  Decode( decoder_t *, block_t * );
 
 #define OVERRIDE_PAGE_TEXT N_("Override page")
 #define OVERRIDE_PAGE_LONGTEXT N_("Override the indicated page, try this if " \
@@ -179,7 +179,7 @@ static int Open( vlc_object_t *p_this )
         return VLC_EGENERIC;
     }
 
-    p_dec->pf_decode_sub = Decode;
+    p_dec->pf_decode = Decode;
     p_sys = p_dec->p_sys = calloc( 1, sizeof(*p_sys) );
     if( p_sys == NULL )
         return VLC_ENOMEM;
@@ -428,10 +428,9 @@ static void decode_string( char * res, int res_len,
 /*****************************************************************************
  * Decode:
  *****************************************************************************/
-static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t       *p_block;
     subpicture_t  *p_spu = NULL;
     video_format_t fmt;
     /* int erase = 0; */
@@ -446,10 +445,8 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
     char psz_line[256];
     int i, total;
 
-    if( pp_block == NULL || *pp_block == NULL )
-        return NULL;
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     dbg((p_dec, "start of telx packet with header %2x\n",
                 * (uint8_t *) p_block->p_buffer));
@@ -712,7 +709,9 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
     dbg((p_dec, "%ld --> %ld\n", (long int) p_block->i_pts/100000, (long int)p_block->i_length/100000));
 
     block_Release( p_block );
-    return p_spu;
+    if( p_spu != NULL )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 
 error:
     if ( p_spu != NULL )
@@ -722,5 +721,5 @@ error:
     }
 
     block_Release( p_block );
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
diff --git a/modules/codec/textst.c b/modules/codec/textst.c
index a948d1c57f..e233de7da2 100644
--- a/modules/codec/textst.c
+++ b/modules/codec/textst.c
@@ -222,41 +222,36 @@ static void textst_FillRegions(decoder_t *p_dec, const uint8_t *p_data, size_t i
     }
 }
 
-static subpicture_t *Decode(decoder_t *p_dec, block_t **pp_block)
+static int Decode(decoder_t *p_dec, block_t *p_block)
 {
     subpicture_t *p_sub = NULL;
-    if (pp_block == NULL || *pp_block == NULL)
-        return NULL;
+    if (p_block == NULL) /* No Drain */
+        return VLCDEC_SUCCESS;
 
-    block_t *p_block = *pp_block;
-    *pp_block = NULL;
-
-    if(p_block)
+    if (p_block->i_buffer > 18 &&
+        (p_block->i_flags & BLOCK_FLAG_CORRUPTED) == 0 &&
+        (p_sub = decoder_NewSubpictureText(p_dec)))
     {
-        if(p_block->i_buffer > 18 &&
-           (p_block->i_flags & BLOCK_FLAG_CORRUPTED) == 0 &&
-           (p_sub = decoder_NewSubpictureText(p_dec)))
+        p_sub->i_start = ((int64_t) (p_block->p_buffer[3] & 0x01) << 32) | GetDWBE(&p_block->p_buffer[4]);
+        p_sub->i_stop = ((int64_t) (p_block->p_buffer[8] & 0x01) << 32) | GetDWBE(&p_block->p_buffer[9]);
+        p_sub->i_start = VLC_TS_0 + p_sub->i_start * 100 / 9;
+        p_sub->i_stop = VLC_TS_0 + p_sub->i_stop * 100 / 9;
+        if (p_sub->i_start < p_block->i_dts)
         {
-            p_sub->i_start = ((int64_t) (p_block->p_buffer[3] & 0x01) << 32) | GetDWBE(&p_block->p_buffer[4]);
-            p_sub->i_stop = ((int64_t) (p_block->p_buffer[8] & 0x01) << 32) | GetDWBE(&p_block->p_buffer[9]);
-            p_sub->i_start = VLC_TS_0 + p_sub->i_start * 100 / 9;
-            p_sub->i_stop = VLC_TS_0 + p_sub->i_stop * 100 / 9;
-            if(p_sub->i_start < p_block->i_dts)
-            {
-                p_sub->i_stop += p_block->i_dts - p_sub->i_start;
-                p_sub->i_start = p_block->i_dts;
-            }
-
-            textst_FillRegions(p_dec, &p_block->p_buffer[13], p_block->i_buffer - 13,
-                               &p_sub->updater.p_sys->region);
-
-            p_sub->b_absolute = false;
+            p_sub->i_stop += p_block->i_dts - p_sub->i_start;
+            p_sub->i_start = p_block->i_dts;
         }
 
-        block_Release(p_block);
+        textst_FillRegions(p_dec, &p_block->p_buffer[13], p_block->i_buffer - 13,
+                           &p_sub->updater.p_sys->region);
+
+        p_sub->b_absolute = false;
     }
 
-    return p_sub;
+    block_Release(p_block);
+    if (p_sub != NULL)
+        decoder_QueueSub(p_dec, p_sub);
+    return VLCDEC_SUCCESS;
 }
 
 static void Close(vlc_object_t *object)
@@ -278,7 +273,7 @@ static int Open(vlc_object_t *object)
     memset(p_sys->palette, 0xFF, 256 * sizeof(uint32_t));
 
     p_dec->p_sys = p_sys;
-    p_dec->pf_decode_sub = Decode;
+    p_dec->pf_decode = Decode;
     p_dec->fmt_out.i_cat = SPU_ES;
     p_dec->fmt_out.i_codec = 0;
 
diff --git a/modules/codec/theora.c b/modules/codec/theora.c
index d50a63c2cc..8f364fe61e 100644
--- a/modules/codec/theora.c
+++ b/modules/codec/theora.c
@@ -82,9 +82,10 @@ static int  OpenDecoder   ( vlc_object_t * );
 static int  OpenPacketizer( vlc_object_t * );
 static void CloseDecoder  ( vlc_object_t * );
 
-static void *DecodeBlock  ( decoder_t *, block_t ** );
+static int DecodeVideo  ( decoder_t *, block_t * );
+static block_t *Packetize  ( decoder_t *, block_t ** );
 static int  ProcessHeaders( decoder_t * );
-static void *ProcessPacket ( decoder_t *, ogg_packet *, block_t ** );
+static void *ProcessPacket ( decoder_t *, ogg_packet *, block_t * );
 static void Flush( decoder_t * );
 
 static picture_t *DecodePacket( decoder_t *, ogg_packet * );
@@ -169,11 +170,9 @@ static int OpenDecoder( vlc_object_t *p_this )
     p_dec->fmt_out.i_codec = VLC_CODEC_I420;
 
     /* Set callbacks */
-    p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
-    p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
-        DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode    = DecodeVideo;
+    p_dec->pf_packetize = Packetize;
+    p_dec->pf_flush     = Flush;
 
     /* Init supporting Theora structures needed in header parsing */
     th_comment_init( &p_sys->tc );
@@ -202,16 +201,11 @@ static int OpenPacketizer( vlc_object_t *p_this )
  ****************************************************************************
  * This function must be fed with ogg packets.
  ****************************************************************************/
-static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static void *DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block;
     ogg_packet oggpacket;
 
-    if( !pp_block || !*pp_block ) return NULL;
-
-    p_block = *pp_block;
-
     /* Block to Ogg packet */
     oggpacket.packet = p_block->p_buffer;
     oggpacket.bytes = p_block->i_buffer;
@@ -231,7 +225,28 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
         p_sys->b_has_headers = true;
     }
 
-    return ProcessPacket( p_dec, &oggpacket, pp_block );
+    return ProcessPacket( p_dec, &oggpacket, p_block );
+}
+
+static int DecodeVideo( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    picture_t *p_pic = DecodeBlock( p_dec, p_block );
+    if( p_pic != NULL )
+        decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
+}
+
+static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
+{
+    if( pp_block == NULL ) /* No Drain */
+        return NULL;
+    block_t *p_block = *pp_block; *pp_block = NULL;
+    if( p_block == NULL )
+        return NULL;
+    return DecodeBlock( p_dec, p_block );
 }
 
 /*****************************************************************************
@@ -437,17 +452,11 @@ static void Flush( decoder_t *p_dec )
  * ProcessPacket: processes a theora packet.
  *****************************************************************************/
 static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
-                            block_t **pp_block )
+                            block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t *p_block = *pp_block;
     void *p_buf;
 
-    *pp_block = NULL; /* To avoid being fed the same packet again */
-
-    if( !p_block )
-        return NULL;
-
     if( ( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) != 0 )
         p_sys->i_pts = p_block->i_pts;
 
diff --git a/modules/codec/ttml/substtml.c b/modules/codec/ttml/substtml.c
index b01cf0d3b6..f0e4925c64 100644
--- a/modules/codec/ttml/substtml.c
+++ b/modules/codec/ttml/substtml.c
@@ -822,18 +822,18 @@ static subpicture_t *ParseBlock( decoder_t *p_dec, const block_t *p_block )
 /****************************************************************************
  * DecodeBlock: the whole thing
  ****************************************************************************/
-static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
-    if( !pp_block || *pp_block == NULL )
-        return NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
-    block_t* p_block = *pp_block;
     subpicture_t *p_spu = ParseBlock( p_dec, p_block );
 
     block_Release( p_block );
-    *pp_block = NULL;
 
-    return p_spu;
+    if( p_spu != NULL )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -852,7 +852,7 @@ int OpenDecoder( vlc_object_t *p_this )
     if( unlikely( p_sys == NULL ) )
         return VLC_ENOMEM;
 
-    p_dec->pf_decode_sub = DecodeBlock;
+    p_dec->pf_decode = DecodeBlock;
     p_dec->fmt_out.i_cat = SPU_ES;
     p_sys->i_align = var_InheritInteger( p_dec, "ttml-align" );
 
diff --git a/modules/codec/uleaddvaudio.c b/modules/codec/uleaddvaudio.c
index c578682e3d..cc1dcb9c2a 100644
--- a/modules/codec/uleaddvaudio.c
+++ b/modules/codec/uleaddvaudio.c
@@ -61,11 +61,11 @@ static void Flush(decoder_t *dec)
     date_Set(&sys->end_date, 0);
 }
 
-static block_t *Decode(decoder_t *dec, block_t **block_ptr)
+static block_t *DecodeBlock(decoder_t *dec, block_t **block_ptr)
 {
     decoder_sys_t *sys  = dec->p_sys;
 
-    if (!block_ptr || !*block_ptr)
+    if (!*block_ptr)
         return NULL;
 
     block_t *block = *block_ptr;
@@ -122,6 +122,17 @@ static block_t *Decode(decoder_t *dec, block_t **block_ptr)
     return NULL;
 }
 
+static int DecodeAudio(decoder_t *dec, block_t *block)
+{
+    if (block == NULL) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    block_t **block_ptr = &block, *out;
+    while ((out = DecodeBlock(dec, block_ptr)) != NULL)
+        decoder_QueueAudio(dec,out);
+    return VLCDEC_SUCCESS;
+}
+
 static int Open(vlc_object_t *object)
 {
     decoder_t *dec = (decoder_t*)object;
@@ -159,8 +170,8 @@ static int Open(vlc_object_t *object)
     dec->fmt_out.audio.i_physical_channels =
     dec->fmt_out.audio.i_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
 
-    dec->pf_decode_audio = Decode;
-    dec->pf_flush        = Flush;
+    dec->pf_decode = DecodeAudio;
+    dec->pf_flush  = Flush;
 
     return VLC_SUCCESS;
 }
diff --git a/modules/codec/videotoolbox.m b/modules/codec/videotoolbox.m
index 8c92d6d5bb..8c90f318c5 100644
--- a/modules/codec/videotoolbox.m
+++ b/modules/codec/videotoolbox.m
@@ -86,7 +86,7 @@ vlc_module_end()
 #pragma mark - local prototypes
 
 static CFDataRef ESDSCreate(decoder_t *, uint8_t *, uint32_t);
-static picture_t *DecodeBlock(decoder_t *, block_t **);
+static int DecodeBlock(decoder_t *, block_t *);
 static void PicReorder_pushSorted(decoder_t *, picture_t *);
 static picture_t *PicReorder_pop(decoder_t *, bool);
 static void PicReorder_flush(decoder_t *);
@@ -752,8 +752,8 @@ static int OpenDecoder(vlc_object_t *p_this)
         return i_ret;
     }
 
-    p_dec->pf_decode_video = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeBlock;
+    p_dec->pf_flush  = Flush;
 
     msg_Info(p_dec, "Using Video Toolbox to decode '%4.4s'", (char *)&p_dec->fmt_in.i_codec);
 
@@ -1028,7 +1028,7 @@ static void Flush(decoder_t *p_dec)
     p_sys->b_vt_flush = p_sys->b_vt_feed;
 }
 
-static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
+static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
@@ -1037,22 +1037,24 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
         p_sys->b_vt_flush = false;
     }
 
-    if (!pp_block)
+    if (!p_block)
     {
         /* draining: return last pictures of the reordered queue */
         if (p_sys->session)
             VTDecompressionSessionWaitForAsynchronousFrames(p_sys->session);
-        vlc_mutex_lock(&p_sys->lock);
-        picture_t *p_pic = PicReorder_pop(p_dec, true);
-        vlc_mutex_unlock(&p_sys->lock);
-        return p_pic;
-    }
-
-    block_t *p_block = *pp_block;
-    *pp_block = NULL;
+        for (;;)
+        {
+            vlc_mutex_lock(&p_sys->lock);
+            picture_t *p_pic = PicReorder_pop(p_dec, true);
+            vlc_mutex_unlock(&p_sys->lock);
 
-    if (p_block == NULL)
-        return NULL; /* no need to be called again, pics are queued asynchronously */
+            if (p_pic)
+                decoder_QueueVideo(p_dec, p_pic);
+            else
+                break;
+        }
+        return VLCDEC_SUCCESS;
+    }
 
     vlc_mutex_lock(&p_sys->lock);
     if (p_sys->b_abort) { /* abort from output thread (DecoderCallback) */
@@ -1089,7 +1091,7 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
     if (p_sys->codec == kCMVideoCodecType_H264) {
         p_block = H264ProcessBlock(p_dec, p_block);
         if (!p_block)
-            return NULL;
+            return VLCDEC_SUCCESS;
     }
 
     CMSampleBufferRef sampleBuffer =
@@ -1131,7 +1133,7 @@ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block)
 
 skip:
     block_Release(p_block);
-    return NULL;
+    return VLCDEC_SUCCESS;
 
 reload:
     /* Add an empty variable so that videotoolbox won't be loaded again for
@@ -1141,7 +1143,7 @@ reload:
     else
         p_dec->b_error = true;
     block_Release(p_block);
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 static int UpdateVideoFormat(decoder_t *p_dec, CVPixelBufferRef imageBuffer)
diff --git a/modules/codec/vorbis.c b/modules/codec/vorbis.c
index 0ce0e26338..a54b0cabab 100644
--- a/modules/codec/vorbis.c
+++ b/modules/codec/vorbis.c
@@ -147,11 +147,12 @@ static const uint32_t pi_3channels_in[] =
 static int  OpenDecoder   ( vlc_object_t * );
 static int  OpenPacketizer( vlc_object_t * );
 static void CloseDecoder  ( vlc_object_t * );
-static block_t *DecodeBlock  ( decoder_t *, block_t ** );
+static int  DecodeAudio  ( decoder_t *, block_t * );
+static block_t *Packetize  ( decoder_t *, block_t ** );
 static void Flush( decoder_t * );
 
 static int  ProcessHeaders( decoder_t * );
-static void *ProcessPacket ( decoder_t *, ogg_packet *, block_t ** );
+static block_t *ProcessPacket ( decoder_t *, ogg_packet *, block_t ** );
 
 static block_t *DecodePacket( decoder_t *, ogg_packet * );
 static block_t *SendPacket( decoder_t *, ogg_packet *, block_t * );
@@ -261,9 +262,9 @@ static int OpenDecoder( vlc_object_t *p_this )
 #endif
 
     /* Set callbacks */
-    p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_packetize    = DecodeBlock;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode     = DecodeAudio;
+    p_dec->pf_packetize  = Packetize;
+    p_dec->pf_flush      = Flush;
 
     return VLC_SUCCESS;
 }
@@ -293,8 +294,6 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     decoder_sys_t *p_sys = p_dec->p_sys;
     ogg_packet oggpacket;
 
-    if( !pp_block ) return NULL;
-
     if( *pp_block )
     {
         /* Block to Ogg packet */
@@ -330,6 +329,24 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     return ProcessPacket( p_dec, &oggpacket, pp_block );
 }
 
+static int DecodeAudio( decoder_t *p_dec, block_t *p_block )
+{
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
+
+    block_t **pp_block = &p_block, *p_out;
+    while( ( p_out = DecodeBlock( p_dec, pp_block ) ) != NULL )
+        decoder_QueueAudio( p_dec, p_out );
+    return VLCDEC_SUCCESS;
+}
+
+static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
+{
+    if( pp_block == NULL ) /* No Drain */
+        return NULL;
+    return DecodeBlock( p_dec, pp_block );
+}
+
 /*****************************************************************************
  * ProcessHeaders: process Vorbis headers.
  *****************************************************************************/
@@ -445,8 +462,8 @@ static void Flush( decoder_t *p_dec )
 /*****************************************************************************
  * ProcessPacket: processes a Vorbis packet.
  *****************************************************************************/
-static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
-                            block_t **pp_block )
+static block_t *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
+                               block_t **pp_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_block = *pp_block;
diff --git a/modules/codec/vpx.c b/modules/codec/vpx.c
index 86cb262119..a0db6c86c0 100644
--- a/modules/codec/vpx.c
+++ b/modules/codec/vpx.c
@@ -159,25 +159,23 @@ static vlc_fourcc_t FindVlcChroma( struct vpx_image *img )
 /****************************************************************************
  * Decode: the whole thing
  ****************************************************************************/
-static picture_t *Decode(decoder_t *dec, block_t **pp_block)
+static int Decode(decoder_t *dec, block_t *block)
 {
     struct vpx_codec_ctx *ctx = &dec->p_sys->ctx;
 
-    if( !pp_block || !*pp_block )
-        return NULL;
-    block_t *block = *pp_block;
+    if (block == NULL) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if (block->i_flags & (BLOCK_FLAG_CORRUPTED)) {
         block_Release(block);
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* Associate packet PTS with decoded frame */
     mtime_t *pkt_pts = malloc(sizeof(*pkt_pts));
     if (!pkt_pts) {
         block_Release(block);
-        *pp_block = NULL;
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     *pkt_pts = block->i_pts ? block->i_pts : block->i_dts;
@@ -186,21 +184,20 @@ static picture_t *Decode(decoder_t *dec, block_t **pp_block)
     err = vpx_codec_decode(ctx, block->p_buffer, block->i_buffer, pkt_pts, 0);
 
     block_Release(block);
-    *pp_block = NULL;
 
     if (err != VPX_CODEC_OK) {
         free(pkt_pts);
         VPX_ERR(dec, ctx, "Failed to decode frame");
         if (err == VPX_CODEC_UNSUP_BITSTREAM)
             dec->b_error = true;
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     const void *iter = NULL;
     struct vpx_image *img = vpx_codec_get_frame(ctx, &iter);
     if (!img) {
         free(pkt_pts);
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* fetches back the PTS */
@@ -212,7 +209,7 @@ static picture_t *Decode(decoder_t *dec, block_t **pp_block)
 
     if( dec->fmt_out.i_codec == 0 ) {
         msg_Err(dec, "Unsupported output colorspace %d", img->fmt);
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     video_format_t *v = &dec->fmt_out.video;
@@ -252,10 +249,10 @@ static picture_t *Decode(decoder_t *dec, block_t **pp_block)
     dec->fmt_out.video.pose = dec->fmt_in.video.pose;
 
     if (decoder_UpdateVideoFormat(dec))
-        return NULL;
+        return VLCDEC_SUCCESS;
     picture_t *pic = decoder_NewPicture(dec);
     if (!pic)
-        return NULL;
+        return VLCDEC_SUCCESS;
 
     for (int plane = 0; plane < pic->i_planes; plane++ ) {
         uint8_t *src = img->planes[plane];
@@ -274,7 +271,8 @@ static picture_t *Decode(decoder_t *dec, block_t **pp_block)
     pic->b_progressive = true; /* codec does not support interlacing */
     pic->date = pts;
 
-    return pic;
+    decoder_QueueVideo(dec, pic);
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -322,7 +320,7 @@ static int OpenDecoder(vlc_object_t *p_this)
         return VLC_EGENERIC;;
     }
 
-    dec->pf_decode_video = Decode;
+    dec->pf_decode = Decode;
 
     dec->fmt_out.i_cat = VIDEO_ES;
     dec->fmt_out.video.i_width = dec->fmt_in.video.i_width;
diff --git a/modules/codec/wmafixed/wma.c b/modules/codec/wmafixed/wma.c
index f8a8b4c813..a7abfb27cb 100644
--- a/modules/codec/wmafixed/wma.c
+++ b/modules/codec/wmafixed/wma.c
@@ -71,7 +71,7 @@ static unsigned int pi_channels_maps[7] =
 static int  OpenDecoder   ( vlc_object_t * );
 static void CloseDecoder  ( vlc_object_t * );
 
-static block_t *DecodeFrame( decoder_t *, block_t ** );
+static int DecodeFrame( decoder_t *, block_t * );
 static void Flush( decoder_t * );
 
 /*****************************************************************************
@@ -186,8 +186,8 @@ static int OpenDecoder( vlc_object_t *p_this )
     }
 
     /* Set callback */
-    p_dec->pf_decode_audio = DecodeFrame;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode = DecodeFrame;
+    p_dec->pf_flush  = Flush;
 
     return VLC_SUCCESS;
 }
@@ -205,15 +205,13 @@ static void Flush( decoder_t *p_dec )
 /*****************************************************************************
  * DecodeFrame: decodes a wma frame.
  *****************************************************************************/
-static block_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
+static int DecodeFrame( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    block_t       *p_block;
     block_t       *p_aout_buffer = NULL;
 
-    if( !pp_block || !*pp_block ) return NULL;
-
-    p_block = *pp_block;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
     {
@@ -221,24 +219,8 @@ static block_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
         if( p_block->i_flags & BLOCK_FLAG_CORRUPTED)
         {
             block_Release( p_block );
-            *pp_block = NULL;
-            return NULL;
-        }
-    }
-
-    if( p_block->i_buffer <= 0 )
-    {
-        /* we already decoded the samples, just feed a few to aout */
-        if( p_sys->i_samples )
-            p_aout_buffer = SplitBuffer( p_dec );
-        if( !p_sys->i_samples )
-        {   /* we need to decode new samples now */
-            free( p_sys->p_output );
-            p_sys->p_output = NULL;
-            block_Release( p_block );
-            *pp_block = NULL;
+            return VLCDEC_SUCCESS;
         }
-        return p_aout_buffer;
     }
 
     /* Date management */
@@ -253,7 +235,7 @@ static block_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
     {
         /* We've just started the stream, wait for the first PTS. */
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     if( wma_decode_superframe_init( &p_sys->wmadec, p_block->p_buffer,
@@ -261,16 +243,14 @@ static block_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
     {
         msg_Err( p_dec, "failed initializing wmafixed decoder" );
         block_Release( p_block );
-        *pp_block = NULL;
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     if( p_sys->wmadec.nb_frames <= 0 )
     {
         msg_Err( p_dec, "can not decode, invalid ASF packet ?" );
         block_Release( p_block );
-        *pp_block = NULL;
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     /* worst case */
@@ -283,7 +263,7 @@ static block_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
     {
         /* OOM, will try a bit later if VLC hasn't been killed */
         block_Release( p_block );
-        return NULL;
+        return VLCDEC_SUCCESS;
     }
 
     p_sys->i_samples = 0;
@@ -302,20 +282,26 @@ static block_t *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
                 "wma_decode_superframe_frame() failed for frame %d", i );
             free( p_sys->p_output );
             p_sys->p_output = NULL;
-            return NULL;
+            return VLCDEC_SUCCESS;
         }
         p_sys->i_samples += i_samples; /* advance in the samples buffer */
     }
 
-    p_block->i_buffer = 0; /* this block has been decoded */
+    block_Release( p_block ); /* this block has been decoded */
 
     for( size_t s = 0 ; s < i_buffer; s++ )
         p_sys->p_output[s] <<= 2; /* Q30 -> Q32 translation */
 
-    p_aout_buffer = SplitBuffer( p_dec );
-    assert( p_aout_buffer );
+    while( ( p_aout_buffer = SplitBuffer( p_dec ) ) != NULL )
+        decoder_QueueAudio( p_dec, p_aout_buffer );
+
+    if( !p_sys->i_samples )
+    {   /* we need to decode new samples now */
+        free( p_sys->p_output );
+        p_sys->p_output = NULL;
+    }
 
-    return p_aout_buffer;
+    return VLCDEC_SUCCESS;
 }
 
 /*****************************************************************************
diff --git a/modules/codec/xwd.c b/modules/codec/xwd.c
index fe8fc18426..dd3c8af7cb 100644
--- a/modules/codec/xwd.c
+++ b/modules/codec/xwd.c
@@ -40,7 +40,7 @@ vlc_module_begin()
     set_callbacks(Open, NULL)
 vlc_module_end()
 
-static picture_t *Decode(decoder_t *, block_t **);
+static int Decode(decoder_t *, block_t *);
 
 static int Open(vlc_object_t *obj)
 {
@@ -49,24 +49,19 @@ static int Open(vlc_object_t *obj)
     if (dec->fmt_in.i_codec != VLC_CODEC_XWD)
         return VLC_EGENERIC;
 
-    dec->pf_decode_video = Decode;
+    dec->pf_decode = Decode;
     es_format_Copy(&dec->fmt_out, &dec->fmt_in);
     dec->fmt_out.i_codec = VLC_CODEC_RGB32;
     dec->fmt_out.i_cat = VIDEO_ES;
     return VLC_SUCCESS;
 }
 
-static picture_t *Decode (decoder_t *dec, block_t **pp)
+static int Decode (decoder_t *dec, block_t *block)
 {
     picture_t *pic = NULL;
 
-    if (pp == NULL)
-        return NULL;
-
-    block_t *block = *pp;
-    if (block == NULL)
-        return NULL;
-    *pp = NULL;
+    if (block == NULL) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if (block->i_pts <= VLC_TS_INVALID)
         goto drop; /* undated block, should never happen */
@@ -153,5 +148,6 @@ static picture_t *Decode (decoder_t *dec, block_t **pp)
 
 drop:
     block_Release(block);
-    return pic;
+    decoder_QueueVideo(dec, pic);
+    return VLCDEC_SUCCESS;
 }
diff --git a/modules/codec/zvbi.c b/modules/codec/zvbi.c
index ff3de7f0af..430a6ba42d 100644
--- a/modules/codec/zvbi.c
+++ b/modules/codec/zvbi.c
@@ -173,7 +173,7 @@ struct decoder_sys_t
     int               i_key[3];
 };
 
-static subpicture_t *Decode( decoder_t *, block_t ** );
+static int Decode( decoder_t *, block_t * );
 
 static subpicture_t *Subpicture( decoder_t *p_dec, video_format_t *p_fmt,
                                  bool b_text,
@@ -275,7 +275,7 @@ static int Open( vlc_object_t *p_this )
     else
         p_dec->fmt_out.video.i_chroma = VLC_CODEC_RGBA;
 
-    p_dec->pf_decode_sub = Decode;
+    p_dec->pf_decode = Decode;
     return VLC_SUCCESS;
 }
 
@@ -307,20 +307,16 @@ static void Close( vlc_object_t *p_this )
 /*****************************************************************************
  * Decode:
  *****************************************************************************/
-static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
+static int Decode( decoder_t *p_dec, block_t *p_block )
 {
     decoder_sys_t   *p_sys = p_dec->p_sys;
-    block_t         *p_block;
     subpicture_t    *p_spu = NULL;
     video_format_t  fmt;
     bool            b_cached = false;
     vbi_page        p_page;
 
-    if( (pp_block == NULL) || (*pp_block == NULL) )
-        return NULL;
-
-    p_block = *pp_block;
-    *pp_block = NULL;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( p_block->i_buffer > 0 &&
         ( ( p_block->p_buffer[0] >= 0x10 && p_block->p_buffer[0] <= 0x1f ) ||
@@ -498,12 +494,14 @@ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
 exit:
     vbi_unref_page( &p_page );
     block_Release( p_block );
-    return p_spu;
+    if( p_spu )
+        decoder_QueueSub( p_dec, p_spu );
+    return VLCDEC_SUCCESS;
 
 error:
     vbi_unref_page( &p_page );
     block_Release( p_block );
-    return NULL;
+    return VLCDEC_SUCCESS;
 }
 
 static subpicture_t *Subpicture( decoder_t *p_dec, video_format_t *p_fmt,
diff --git a/modules/hw/mmal/codec.c b/modules/hw/mmal/codec.c
index 98a001ed63..c01d1e4635 100644
--- a/modules/hw/mmal/codec.c
+++ b/modules/hw/mmal/codec.c
@@ -90,7 +90,7 @@ static int send_output_buffer(decoder_t *dec);
 static void fill_output_port(decoder_t *dec);
 
 /* VLC decoder callback */
-static picture_t *decode(decoder_t *dec, block_t **block);
+static int decode(decoder_t *dec, block_t *block);
 static void flush_decoder(decoder_t *dec);
 
 /* MMAL callbacks */
@@ -236,8 +236,8 @@ static int OpenDecoder(decoder_t *dec)
     }
 
     dec->fmt_out.i_cat = VIDEO_ES;
-    dec->pf_decode_video = decode;
-    dec->pf_flush        = flush_decoder;
+    dec->pf_decode = decode;
+    dec->pf_flush  = flush_decoder;
 
     vlc_mutex_init_recursive(&sys->mutex);
     vlc_sem_init(&sys->sem, 0);
@@ -593,16 +593,14 @@ static void flush_decoder(decoder_t *dec)
     msg_Dbg(dec, "Ports flushed, returning to normal operation");
 }
 
-static picture_t *decode(decoder_t *dec, block_t **pblock)
+static int decode(decoder_t *dec, block_t *block)
 {
     decoder_sys_t *sys = dec->p_sys;
-    block_t *block;
     MMAL_BUFFER_HEADER_T *buffer;
     bool need_flush = false;
     uint32_t len;
     uint32_t flags = 0;
     MMAL_STATUS_T status;
-    picture_t *ret = NULL;
 
     /*
      * Configure output port if necessary
@@ -612,23 +610,22 @@ static picture_t *decode(decoder_t *dec, block_t **pblock)
             msg_Err(dec, "Failed to change output port format");
     }
 
-    if (!pblock)
+    if (!block)
         goto out;
 
-    block = *pblock;
-
     /*
      * Check whether full flush is required
      */
     if (block && block->i_flags & BLOCK_FLAG_DISCONTINUITY) {
         flush_decoder(dec);
-        block_Release(*pblock);
-        return NULL;
+        block_Release(block);
+        return VLCDEC_SUCCESS;
     }
 
     /*
      * Send output buffers
      */
+    picture_t *ret = NULL;
     if (atomic_load(&sys->started)) {
         buffer = mmal_queue_get(sys->decoded_pictures);
         if (buffer) {
@@ -646,17 +643,12 @@ static picture_t *decode(decoder_t *dec, block_t **pblock)
 
         fill_output_port(dec);
     }
-
     if (ret)
-        goto out;
+        decoder_QueueVideo(dec, ret);
 
     /*
      * Process input
      */
-    if (!block)
-        goto out;
-
-    *pblock = NULL;
 
     if (block->i_flags & BLOCK_FLAG_CORRUPTED)
         flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED;
@@ -701,7 +693,7 @@ out:
     if (need_flush)
         flush_decoder(dec);
 
-    return ret;
+    return VLCDEC_SUCCESS;
 }
 
 static void control_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
diff --git a/modules/misc/stats.c b/modules/misc/stats.c
index 9a0f112457..6c3d4fdf6c 100644
--- a/modules/misc/stats.c
+++ b/modules/misc/stats.c
@@ -40,13 +40,12 @@
 #include <vlc_demux.h>
 
 /*** Decoder ***/
-static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static int DecodeBlock( decoder_t *p_dec, block_t *p_block )
 {
-    block_t *p_block;
     picture_t * p_pic = NULL;
 
-    if( !pp_block || !*pp_block ) return NULL;
-    p_block = *pp_block;
+    if( p_block == NULL ) /* No Drain */
+        return VLCDEC_SUCCESS;
 
     if( !decoder_UpdateVideoFormat( p_dec ) )
         p_pic = decoder_NewPicture( p_dec );
@@ -73,8 +72,8 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
 
 error:
     block_Release( p_block );
-    *pp_block = NULL;
-    return p_pic;
+    decoder_QueueVideo( p_dec, p_pic );
+    return VLCDEC_SUCCESS;
 }
 
 static int OpenDecoder ( vlc_object_t *p_this )
@@ -84,9 +83,7 @@ static int OpenDecoder ( vlc_object_t *p_this )
     msg_Dbg( p_this, "opening stats decoder" );
 
     /* Set callbacks */
-    p_dec->pf_decode_video = DecodeBlock;
-    p_dec->pf_decode_audio = NULL;
-    p_dec->pf_decode_sub = NULL;
+    p_dec->pf_decode = DecodeBlock;
 
     /* */
     es_format_Init( &p_dec->fmt_out, VIDEO_ES, VLC_CODEC_I420 );
diff --git a/modules/packetizer/flac.c b/modules/packetizer/flac.c
index fbe161ea1d..877b4868a5 100644
--- a/modules/packetizer/flac.c
+++ b/modules/packetizer/flac.c
@@ -800,9 +800,9 @@ static int Open(vlc_object_t *p_this)
     p_dec->fmt_out.i_codec = VLC_CODEC_FLAC;
 
     /* */
-    p_dec->pf_decode_audio = NULL;
-    p_dec->pf_packetize    = Packetize;
-    p_dec->pf_flush        = Flush;
+    p_dec->pf_decode    = NULL;
+    p_dec->pf_packetize = Packetize;
+    p_dec->pf_flush     = Flush;
 
     return VLC_SUCCESS;
 }
diff --git a/modules/stream_out/mosaic_bridge.c b/modules/stream_out/mosaic_bridge.c
index 1c313f04b6..3e87d5debb 100644
--- a/modules/stream_out/mosaic_bridge.c
+++ b/modules/stream_out/mosaic_bridge.c
@@ -77,6 +77,7 @@ static sout_stream_id_sys_t *Add( sout_stream_t *, const es_format_t * );
 static void              Del ( sout_stream_t *, sout_stream_id_sys_t * );
 static int               Send( sout_stream_t *, sout_stream_id_sys_t *, block_t * );
 
+static int decoder_queue_video( decoder_t *p_dec, picture_t *p_pic );
 inline static int video_update_format_decoder( decoder_t *p_dec );
 inline static picture_t *video_new_buffer_decoder( decoder_t * );
 inline static picture_t *video_new_buffer_filter( filter_t * );
@@ -290,7 +291,9 @@ static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, const es_format_t *p
     p_sys->p_decoder->fmt_out = p_sys->p_decoder->fmt_in;
     p_sys->p_decoder->fmt_out.i_extra = 0;
     p_sys->p_decoder->fmt_out.p_extra = 0;
-    p_sys->p_decoder->pf_decode_video = 0;
+    p_sys->p_decoder->pf_decode = NULL;
+    p_sys->p_decoder->pf_queue_video = decoder_queue_video;
+    p_sys->p_decoder->p_queue_ctx = p_stream;
     p_sys->p_decoder->pf_vout_format_update = video_update_format_decoder;
     p_sys->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
     p_sys->p_decoder->p_owner = malloc( sizeof(decoder_owner_sys_t) );
@@ -306,9 +309,9 @@ static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, const es_format_t *p
     p_sys->p_decoder->p_module =
         module_need( p_sys->p_decoder, "decoder", "$codec", false );
 
-    if( !p_sys->p_decoder->p_module || !p_sys->p_decoder->pf_decode_video )
+    if( !p_sys->p_decoder->p_module || p_sys->p_decoder->fmt_out.i_cat != VIDEO_ES )
     {
-        if( p_sys->p_decoder->p_module )
+        if( p_sys->p_decoder->fmt_out.i_cat != VIDEO_ES )
         {
             msg_Err( p_stream, "instanciated a non video decoder" );
             module_unneed( p_sys->p_decoder, p_sys->p_decoder->p_module );
@@ -481,28 +484,97 @@ static void Del( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
     p_sys->b_inited = false;
 }
 
-/*****************************************************************************
- * PushPicture : push a picture in the mosaic-struct structure
- *****************************************************************************/
-static void PushPicture( sout_stream_t *p_stream, picture_t *p_picture )
+static int decoder_queue_video( decoder_t *p_dec, picture_t *p_pic )
 {
+    sout_stream_t *p_stream = p_dec->p_queue_ctx;
     sout_stream_sys_t *p_sys = p_stream->p_sys;
-    bridged_es_t *p_es = p_sys->p_es;
+    picture_t *p_new_pic;
 
-    vlc_global_lock( VLC_MOSAIC_MUTEX );
+    if( p_sys->i_height || p_sys->i_width )
+    {
+        video_format_t fmt_out, fmt_in;
+
+        memset( &fmt_in, 0, sizeof(video_format_t) );
+        memset( &fmt_out, 0, sizeof(video_format_t) );
+        fmt_in = p_sys->p_decoder->fmt_out.video;
+
+
+        if( p_sys->i_chroma )
+            fmt_out.i_chroma = p_sys->i_chroma;
+        else
+            fmt_out.i_chroma = VLC_CODEC_I420;
+
+        const unsigned i_fmt_in_aspect =
+            (int64_t)VOUT_ASPECT_FACTOR *
+            fmt_in.i_sar_num * fmt_in.i_width /
+            (fmt_in.i_sar_den * fmt_in.i_height);
+        if ( !p_sys->i_height )
+        {
+            fmt_out.i_width = p_sys->i_width;
+            fmt_out.i_height = (p_sys->i_width * VOUT_ASPECT_FACTOR
+                * p_sys->i_sar_num / p_sys->i_sar_den / i_fmt_in_aspect)
+                  & ~0x1;
+        }
+        else if ( !p_sys->i_width )
+        {
+            fmt_out.i_height = p_sys->i_height;
+            fmt_out.i_width = (p_sys->i_height * i_fmt_in_aspect
+                * p_sys->i_sar_den / p_sys->i_sar_num / VOUT_ASPECT_FACTOR)
+                  & ~0x1;
+        }
+        else
+        {
+            fmt_out.i_width = p_sys->i_width;
+            fmt_out.i_height = p_sys->i_height;
+        }
+        fmt_out.i_visible_width = fmt_out.i_width;
+        fmt_out.i_visible_height = fmt_out.i_height;
+
+        p_new_pic = image_Convert( p_sys->p_image,
+                                   p_pic, &fmt_in, &fmt_out );
+        if( p_new_pic == NULL )
+        {
+            msg_Err( p_stream, "image conversion failed" );
+            picture_Release( p_pic );
+            return -1;
+        }
+    }
+    else
+    {
+        /* TODO: chroma conversion if needed */
+
+        p_new_pic = picture_New( p_pic->format.i_chroma,
+                                 p_pic->format.i_width, p_pic->format.i_height,
+                                 p_sys->p_decoder->fmt_out.video.i_sar_num,
+                                 p_sys->p_decoder->fmt_out.video.i_sar_den );
+        if( !p_new_pic )
+        {
+            picture_Release( p_pic );
+            msg_Err( p_stream, "image allocation failed" );
+            return -1;
+        }
+
+        picture_Copy( p_new_pic, p_pic );
+    }
+    picture_Release( p_pic );
 
-    *p_es->pp_last = p_picture;
-    p_picture->p_next = NULL;
-    p_es->pp_last = &p_picture->p_next;
+    if( p_sys->p_vf2 )
+        p_new_pic = filter_chain_VideoFilter( p_sys->p_vf2, p_new_pic );
 
+    /* push the picture in the mosaic-struct structure */
+    bridged_es_t *p_es = p_sys->p_es;
+    vlc_global_lock( VLC_MOSAIC_MUTEX );
+    *p_es->pp_last = p_new_pic;
+    p_new_pic->p_next = NULL;
+    p_es->pp_last = &p_new_pic->p_next;
     vlc_global_unlock( VLC_MOSAIC_MUTEX );
+    return 0;
 }
 
 static int Send( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
                  block_t *p_buffer )
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
-    picture_t *p_pic;
 
     if ( (sout_stream_sys_t *)id != p_sys )
     {
@@ -510,86 +582,8 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
         return VLC_SUCCESS;
     }
 
-    while ( (p_pic = p_sys->p_decoder->pf_decode_video( p_sys->p_decoder,
-                                                        &p_buffer )) )
-    {
-        picture_t *p_new_pic;
-
-        if( p_sys->i_height || p_sys->i_width )
-        {
-            video_format_t fmt_out, fmt_in;
-
-            memset( &fmt_in, 0, sizeof(video_format_t) );
-            memset( &fmt_out, 0, sizeof(video_format_t) );
-            fmt_in = p_sys->p_decoder->fmt_out.video;
-
-
-            if( p_sys->i_chroma )
-                fmt_out.i_chroma = p_sys->i_chroma;
-            else
-                fmt_out.i_chroma = VLC_CODEC_I420;
-
-            const unsigned i_fmt_in_aspect =
-                (int64_t)VOUT_ASPECT_FACTOR *
-                fmt_in.i_sar_num * fmt_in.i_width /
-                (fmt_in.i_sar_den * fmt_in.i_height);
-            if ( !p_sys->i_height )
-            {
-                fmt_out.i_width = p_sys->i_width;
-                fmt_out.i_height = (p_sys->i_width * VOUT_ASPECT_FACTOR
-                    * p_sys->i_sar_num / p_sys->i_sar_den / i_fmt_in_aspect)
-                      & ~0x1;
-            }
-            else if ( !p_sys->i_width )
-            {
-                fmt_out.i_height = p_sys->i_height;
-                fmt_out.i_width = (p_sys->i_height * i_fmt_in_aspect
-                    * p_sys->i_sar_den / p_sys->i_sar_num / VOUT_ASPECT_FACTOR)
-                      & ~0x1;
-            }
-            else
-            {
-                fmt_out.i_width = p_sys->i_width;
-                fmt_out.i_height = p_sys->i_height;
-            }
-            fmt_out.i_visible_width = fmt_out.i_width;
-            fmt_out.i_visible_height = fmt_out.i_height;
-
-            p_new_pic = image_Convert( p_sys->p_image,
-                                       p_pic, &fmt_in, &fmt_out );
-            if( p_new_pic == NULL )
-            {
-                msg_Err( p_stream, "image conversion failed" );
-                picture_Release( p_pic );
-                continue;
-            }
-        }
-        else
-        {
-            /* TODO: chroma conversion if needed */
-
-            p_new_pic = picture_New( p_pic->format.i_chroma,
-                                     p_pic->format.i_width, p_pic->format.i_height,
-                                     p_sys->p_decoder->fmt_out.video.i_sar_num,
-                                     p_sys->p_decoder->fmt_out.video.i_sar_den );
-            if( !p_new_pic )
-            {
-                picture_Release( p_pic );
-                msg_Err( p_stream, "image allocation failed" );
-                continue;
-            }
-
-            picture_Copy( p_new_pic, p_pic );
-        }
-        picture_Release( p_pic );
-
-        if( p_sys->p_vf2 )
-            p_new_pic = filter_chain_VideoFilter( p_sys->p_vf2, p_new_pic );
-
-        PushPicture( p_stream, p_new_pic );
-    }
-
-    return VLC_SUCCESS;
+    int ret = p_sys->p_decoder->pf_decode( p_sys->p_decoder, p_buffer );
+    return ret == VLCDEC_SUCCESS ? VLC_SUCCESS : VLC_EGENERIC;
 }
 
 inline static int video_update_format_decoder( decoder_t *p_dec )
diff --git a/modules/stream_out/transcode/audio.c b/modules/stream_out/transcode/audio.c
index 46e65a4f87..cc07ceeba9 100644
--- a/modules/stream_out/transcode/audio.c
+++ b/modules/stream_out/transcode/audio.c
@@ -133,6 +133,28 @@ static int transcode_audio_initialize_encoder( sout_stream_id_sys_t *id, sout_st
     return VLC_SUCCESS;
 }
 
+static int decoder_queue_audio( decoder_t *p_dec, block_t *p_audio )
+{
+    sout_stream_id_sys_t *id = p_dec->p_queue_ctx;
+
+    vlc_mutex_lock(&id->fifo.lock);
+    *id->fifo.audio.last = p_audio;
+    id->fifo.audio.last = &p_audio->p_next;
+    vlc_mutex_unlock(&id->fifo.lock);
+    return 0;
+}
+
+static block_t *transcode_dequeue_all_audios( sout_stream_id_sys_t *id )
+{
+    vlc_mutex_lock(&id->fifo.lock);
+    block_t *p_audio_bufs = id->fifo.audio.first;
+    id->fifo.audio.first = NULL;
+    id->fifo.audio.last = &id->fifo.audio.first;
+    vlc_mutex_unlock(&id->fifo.lock);
+
+    return p_audio_bufs;
+}
+
 int transcode_audio_new( sout_stream_t *p_stream,
                                 sout_stream_id_sys_t *id )
 {
@@ -147,7 +169,9 @@ 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 = NULL;
+    id->p_decoder->pf_decode = NULL;
+    id->p_decoder->pf_queue_audio = decoder_queue_audio;
+    id->p_decoder->p_queue_ctx = id;
     id->p_decoder->pf_aout_format_update = audio_update_format;
     /* id->p_decoder->p_cfg = p_sys->p_audio_cfg; */
     id->p_decoder->p_module =
@@ -206,8 +230,8 @@ 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;
-    block_t *p_block, *p_audio_buf;
     *out = NULL;
+    bool b_error = false;
 
     if( unlikely( in == NULL ) )
     {
@@ -219,9 +243,26 @@ int transcode_audio_process( sout_stream_t *p_stream,
         return VLC_SUCCESS;
     }
 
-    while( (p_audio_buf = id->p_decoder->pf_decode_audio( id->p_decoder,
-                                                          &in )) )
+    int ret = id->p_decoder->pf_decode( id->p_decoder, in );
+    if( ret != VLCDEC_SUCCESS )
+        return VLC_EGENERIC;
+
+    block_t *p_audio_bufs = transcode_dequeue_all_audios( id );
+    if( p_audio_bufs == NULL )
+        return VLC_SUCCESS;
+
+    do
     {
+        block_t *p_audio_buf = p_audio_bufs;
+        p_audio_bufs = p_audio_bufs->p_next;
+        p_audio_buf->p_next = NULL;
+
+        if( b_error )
+        {
+            block_Release( p_audio_buf );
+            continue;
+        }
+
         if( unlikely( !id->p_encoder->p_module ) )
         {
             /* Complete destination format */
@@ -245,20 +286,11 @@ int transcode_audio_process( sout_stream_t *p_stream,
             if( transcode_audio_initialize_encoder( id, p_stream ) )
             {
                 msg_Err( p_stream, "cannot create audio chain" );
-
-                block_Release( in );
-                block_Release( p_audio_buf );
-
-                return VLC_EGENERIC;
+                goto error;
             }
             if( unlikely( transcode_audio_initialize_filters( p_stream, id, p_sys,
                           &id->p_decoder->fmt_out.audio ) != VLC_SUCCESS ) )
-            {
-                block_Release( in );
-                block_Release( p_audio_buf );
-
-                return VLC_EGENERIC;
-            }
+                goto error;
             date_Init( &id->next_input_pts, id->p_decoder->fmt_out.audio.i_rate, 1 );
             date_Set( &id->next_input_pts, p_audio_buf->i_pts );
         }
@@ -277,7 +309,7 @@ int transcode_audio_process( sout_stream_t *p_stream,
 
             if( transcode_audio_initialize_filters( p_stream, id, p_sys,
                           &id->p_decoder->fmt_out.audio ) != VLC_SUCCESS )
-                return VLC_EGENERIC;
+                goto error;
 
             /* Set next_input_pts to run with new samplerate */
             date_Init( &id->next_input_pts, id->fmt_audio.i_rate, 1 );
@@ -313,17 +345,24 @@ int transcode_audio_process( sout_stream_t *p_stream,
         p_audio_buf = aout_FiltersPlay( id->p_af_chain, p_audio_buf,
                                         INPUT_RATE_DEFAULT );
         if( !p_audio_buf )
-            abort();
+        {
+            b_error = true;
+            continue;
+        }
 
         p_audio_buf->i_dts = p_audio_buf->i_pts;
 
-        p_block = id->p_encoder->pf_encode_audio( id->p_encoder, p_audio_buf );
+        block_t *p_block = id->p_encoder->pf_encode_audio( id->p_encoder, p_audio_buf );
 
         block_ChainAppend( out, p_block );
         block_Release( p_audio_buf );
-    }
+        continue;
+error:
+        block_Release( p_audio_buf );
+        b_error = true;
+    } while( p_audio_bufs );
 
-    return VLC_SUCCESS;
+    return b_error ? VLC_EGENERIC : VLC_SUCCESS;
 }
 
 bool transcode_audio_add( sout_stream_t *p_stream, const es_format_t *p_fmt,
@@ -335,6 +374,9 @@ bool transcode_audio_add( sout_stream_t *p_stream, const es_format_t *p_fmt,
              "creating audio transcoding from fcc=`%4.4s' to fcc=`%4.4s'",
              (char*)&p_fmt->i_codec, (char*)&p_sys->i_acodec );
 
+    id->fifo.audio.first = NULL;
+    id->fifo.audio.last = &id->fifo.audio.first;
+
     /* Complete destination format */
     id->p_encoder->fmt_out.i_codec = p_sys->i_acodec;
     id->p_encoder->fmt_out.audio.i_rate = p_sys->i_sample_rate > 0 ?
diff --git a/modules/stream_out/transcode/spu.c b/modules/stream_out/transcode/spu.c
index 6b9c3f858f..07ef82dec9 100644
--- a/modules/stream_out/transcode/spu.c
+++ b/modules/stream_out/transcode/spu.c
@@ -45,6 +45,28 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec,
     return p_subpicture;
 }
 
+static int decoder_queue_sub( decoder_t *p_dec, subpicture_t *p_spu )
+{
+    sout_stream_id_sys_t *id = p_dec->p_queue_ctx;
+
+    vlc_mutex_lock(&id->fifo.lock);
+    *id->fifo.spu.last = p_spu;
+    id->fifo.spu.last = &p_spu->p_next;
+    vlc_mutex_unlock(&id->fifo.lock);
+    return 0;
+}
+
+static subpicture_t *transcode_dequeue_all_subs( sout_stream_id_sys_t *id )
+{
+    vlc_mutex_lock(&id->fifo.lock);
+    subpicture_t *p_subpics = id->fifo.spu.first;
+    id->fifo.spu.first = NULL;
+    id->fifo.spu.last = &id->fifo.spu.first;
+    vlc_mutex_unlock(&id->fifo.lock);
+
+    return p_subpics;
+}
+
 int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
@@ -54,8 +76,10 @@ int transcode_spu_new( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
      */
 
     /* Initialization of decoder structures */
-    id->p_decoder->pf_decode_sub = NULL;
+    id->p_decoder->pf_decode = NULL;
     id->p_decoder->pf_spu_buffer_new = spu_new_buffer;
+    id->p_decoder->pf_queue_sub = decoder_queue_sub;
+    id->p_decoder->p_queue_ctx = id;
     id->p_decoder->p_owner = (decoder_owner_sys_t *)p_stream;
     /* id->p_decoder->p_cfg = p_sys->p_spu_cfg; */
 
@@ -119,41 +143,50 @@ int transcode_spu_process( sout_stream_t *p_stream,
                                   block_t *in, block_t **out )
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
-    subpicture_t *p_subpic;
     *out = NULL;
+    bool b_error = false;
 
-    p_subpic = id->p_decoder->pf_decode_sub( id->p_decoder, &in );
-    if( !p_subpic )
-    {
-        /* We just don't have anything to handle now, go own*/
-        return VLC_SUCCESS;
-    }
-
-    if( p_sys->b_master_sync && p_sys->i_master_drift )
-    {
-        p_subpic->i_start -= p_sys->i_master_drift;
-        if( p_subpic->i_stop ) p_subpic->i_stop -= p_sys->i_master_drift;
-    }
+    int ret = id->p_decoder->pf_decode( id->p_decoder, in );
+    if( ret != VLCDEC_SUCCESS )
+        return VLC_EGENERIC;
 
-    if( p_sys->b_soverlay )
-    {
-        spu_PutSubpicture( p_sys->p_spu, p_subpic );
+    subpicture_t *p_subpics = transcode_dequeue_all_subs( id );
+    if( p_subpics == NULL )
         return VLC_SUCCESS;
-    }
-    else
+    do
     {
-        block_t *p_block;
+        subpicture_t *p_subpic = p_subpics;
+        p_subpics = p_subpics->p_next;
+        p_subpic->p_next = NULL;
 
-        p_block = id->p_encoder->pf_encode_sub( id->p_encoder, p_subpic );
-        subpicture_Delete( p_subpic );
-        if( p_block )
+        if( b_error )
         {
-            block_ChainAppend( out, p_block );
-            return VLC_SUCCESS;
+            subpicture_Delete( p_subpic );
+            continue;
         }
-    }
 
-    return VLC_EGENERIC;
+        if( p_sys->b_master_sync && p_sys->i_master_drift )
+        {
+            p_subpic->i_start -= p_sys->i_master_drift;
+            if( p_subpic->i_stop ) p_subpic->i_stop -= p_sys->i_master_drift;
+        }
+
+        if( p_sys->b_soverlay )
+            spu_PutSubpicture( p_sys->p_spu, p_subpic );
+        else
+        {
+            block_t *p_block;
+
+            p_block = id->p_encoder->pf_encode_sub( id->p_encoder, p_subpic );
+            subpicture_Delete( p_subpic );
+            if( p_block )
+                block_ChainAppend( out, p_block );
+            else
+                b_error = true;
+        }
+    } while( p_subpics );
+
+    return b_error ? VLC_EGENERIC : VLC_SUCCESS;
 }
 
 bool transcode_spu_add( sout_stream_t *p_stream, const es_format_t *p_fmt,
@@ -161,6 +194,9 @@ bool transcode_spu_add( sout_stream_t *p_stream, const es_format_t *p_fmt,
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
 
+    id->fifo.spu.first = NULL;
+    id->fifo.spu.last = &id->fifo.spu.first;
+
     if( p_sys->i_scodec )
     {
         msg_Dbg( p_stream, "creating subtitle transcoding from fcc=`%4.4s' "
diff --git a/modules/stream_out/transcode/transcode.c b/modules/stream_out/transcode/transcode.c
index 3e5884cb48..ebfcf14ebe 100644
--- a/modules/stream_out/transcode/transcode.c
+++ b/modules/stream_out/transcode/transcode.c
@@ -509,6 +509,7 @@ static sout_stream_id_sys_t *Add( sout_stream_t *p_stream,
     if( !id )
         goto error;
 
+    vlc_mutex_init(&id->fifo.lock);
     id->id = NULL;
     id->p_decoder = NULL;
     id->p_encoder = NULL;
@@ -579,6 +580,7 @@ error:
             id->p_encoder = NULL;
         }
 
+        vlc_mutex_destroy(&id->fifo.lock);
         free( id );
     }
     return NULL;
@@ -623,6 +625,7 @@ static void Del( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
         vlc_object_release( id->p_encoder );
         id->p_encoder = NULL;
     }
+    vlc_mutex_destroy(&id->fifo.lock);
     free( id );
 }
 
diff --git a/modules/stream_out/transcode/transcode.h b/modules/stream_out/transcode/transcode.h
index ff36c0986b..0c3aae0868 100644
--- a/modules/stream_out/transcode/transcode.h
+++ b/modules/stream_out/transcode/transcode.h
@@ -86,6 +86,26 @@ struct sout_stream_id_sys_t
     /* Decoder */
     decoder_t       *p_decoder;
 
+    struct
+    {
+        vlc_mutex_t lock;
+        union
+        {
+            struct {
+                picture_t *first;
+                picture_t **last;
+            } pic;
+            struct {
+                subpicture_t *first;
+                subpicture_t **last;
+            } spu;
+            struct {
+                block_t *first;
+                block_t **last;
+            } audio;
+        };
+    } fifo;
+
     union
     {
          struct
@@ -110,6 +130,8 @@ struct sout_stream_id_sys_t
     date_t          next_output_pts; /**< output calculated PTS */
 
 };
+#define SOUT_ID_FROM_DEC(x) \
+    (void *) (((uintptr_t)x) - offsetof(sout_stream_id_sys_t, p_decoder))
 
 /* OSD */
 
diff --git a/modules/stream_out/transcode/video.c b/modules/stream_out/transcode/video.c
index 9a6f29594a..61f4c880ab 100644
--- a/modules/stream_out/transcode/video.c
+++ b/modules/stream_out/transcode/video.c
@@ -148,6 +148,28 @@ static void* EncoderThread( void *obj )
     return NULL;
 }
 
+static int decoder_queue_video( decoder_t *p_dec, picture_t *p_pic )
+{
+    sout_stream_id_sys_t *id = p_dec->p_queue_ctx;
+
+    vlc_mutex_lock(&id->fifo.lock);
+    *id->fifo.pic.last = p_pic;
+    id->fifo.pic.last = &p_pic->p_next;
+    vlc_mutex_unlock(&id->fifo.lock);
+    return 0;
+}
+
+static picture_t *transcode_dequeue_all_pics( sout_stream_id_sys_t *id )
+{
+    vlc_mutex_lock(&id->fifo.lock);
+    picture_t *p_pics = id->fifo.pic.first;
+    id->fifo.pic.first = NULL;
+    id->fifo.pic.last = &id->fifo.pic.first;
+    vlc_mutex_unlock(&id->fifo.lock);
+
+    return p_pics;
+}
+
 int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
 {
     sout_stream_sys_t *p_sys = p_stream->p_sys;
@@ -159,7 +181,9 @@ int transcode_video_new( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
     id->p_decoder->fmt_out.i_extra = 0;
     id->p_decoder->fmt_out.p_extra = NULL;
     id->p_decoder->fmt_out.psz_language = NULL;
-    id->p_decoder->pf_decode_video = NULL;
+    id->p_decoder->pf_decode = NULL;
+    id->p_decoder->pf_queue_video = decoder_queue_video;
+    id->p_decoder->p_queue_ctx = id;
     id->p_decoder->pf_get_cc = NULL;
     id->p_decoder->pf_vout_format_update = video_update_format_decoder;
     id->p_decoder->pf_vout_buffer_new = video_new_buffer_decoder;
@@ -753,6 +777,7 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
     sout_stream_sys_t *p_sys = p_stream->p_sys;
     picture_t *p_pic = NULL;
     *out = NULL;
+    bool b_error = false;
 
     if( unlikely( in == NULL ) )
     {
@@ -783,9 +808,24 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
         return VLC_SUCCESS;
     }
 
+    int ret = id->p_decoder->pf_decode( id->p_decoder, in );
+    if( ret != VLCDEC_SUCCESS )
+        return VLC_EGENERIC;
 
-    while( (p_pic = id->p_decoder->pf_decode_video( id->p_decoder, &in )) )
+    picture_t *p_pics = transcode_dequeue_all_pics( id );
+    if( p_pics == NULL )
+        return VLC_SUCCESS;
+    do
     {
+        picture_t *p_pic = p_pics;
+        p_pics = p_pics->p_next;
+        p_pic->p_next = NULL;
+
+        if( b_error )
+        {
+            picture_Release( p_pic );
+            continue;
+        }
 
         if( unlikely (
              id->p_encoder->p_module &&
@@ -833,10 +873,10 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
             if( transcode_video_encoder_open( p_stream, id ) != VLC_SUCCESS )
             {
                 picture_Release( p_pic );
-                block_Release( in );
                 transcode_video_close( p_stream, id );
                 id->b_transcode = false;
-                return VLC_EGENERIC;
+                b_error = true;
+                continue;
             }
         }
 
@@ -869,7 +909,7 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
 
             p_pic = NULL;
         }
-    }
+    } while( p_pics );
 
     if( p_sys->i_threads >= 1 )
     {
@@ -880,7 +920,7 @@ int transcode_video_process( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
         vlc_mutex_unlock( &p_sys->lock_out );
     }
 
-    return VLC_SUCCESS;
+    return b_error ? VLC_EGENERIC : VLC_SUCCESS;
 }
 
 bool transcode_video_add( sout_stream_t *p_stream, const es_format_t *p_fmt,
@@ -892,6 +932,9 @@ bool transcode_video_add( sout_stream_t *p_stream, const es_format_t *p_fmt,
              "creating video transcoding from fcc=`%4.4s' to fcc=`%4.4s'",
              (char*)&p_fmt->i_codec, (char*)&p_sys->i_vcodec );
 
+    id->fifo.audio.first = NULL;
+    id->fifo.audio.last = &id->fifo.audio.first;
+
     /* Complete destination format */
     id->p_encoder->fmt_out.i_codec = p_sys->i_vcodec;
     id->p_encoder->fmt_out.video.i_visible_width  = p_sys->i_width & ~1;
diff --git a/src/input/decoder.c b/src/input/decoder.c
index f9d14ae001..4ce0ff2b7a 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -156,9 +156,7 @@ static int LoadDecoder( decoder_t *p_dec, bool b_packetizer,
     p_dec->b_frame_drop_allowed = true;
     p_dec->i_extra_picture_buffers = 0;
 
-    p_dec->pf_decode_audio = NULL;
-    p_dec->pf_decode_video = NULL;
-    p_dec->pf_decode_sub = NULL;
+    p_dec->pf_decode = NULL;
     p_dec->pf_get_cc = NULL;
     p_dec->pf_packetize = NULL;
     p_dec->pf_flush = NULL;
@@ -1039,81 +1037,6 @@ static int DecoderQueueVideo( decoder_t *p_dec, picture_t *p_pic )
     return ret;
 }
 
-static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block )
-{
-    picture_t      *p_pic;
-    block_t **pp_block = p_block ? &p_block : NULL;
-    unsigned i_lost = 0, i_decoded = 0;
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
-    while( (p_pic = p_dec->pf_decode_video( p_dec, pp_block ) ) )
-    {
-        i_decoded++;
-
-        DecoderPlayVideo( p_dec, p_pic, &i_lost );
-    }
-
-    p_owner->pf_update_stat( p_owner, i_decoded, i_lost );
-}
-
-/* This function process a video block
- */
-static void DecoderProcessVideo( decoder_t *p_dec, block_t *p_block )
-{
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
-    if( p_owner->p_packetizer )
-    {
-        block_t *p_packetized_block;
-        block_t **pp_block = p_block ? &p_block : NULL;
-        decoder_t *p_packetizer = p_owner->p_packetizer;
-
-        while( (p_packetized_block =
-                p_packetizer->pf_packetize( p_packetizer, pp_block ) ) )
-        {
-            if( !es_format_IsSimilar( &p_dec->fmt_in, &p_packetizer->fmt_out ) )
-            {
-                msg_Dbg( p_dec, "restarting module due to input format change");
-
-                /* Drain the decoder module */
-                DecoderDecodeVideo( p_dec, NULL );
-
-                if( ReloadDecoder( p_dec, false, &p_packetizer->fmt_out,
-                                   RELOAD_DECODER ) != VLC_SUCCESS )
-                {
-                    block_ChainRelease( p_packetized_block );
-                    return;
-                }
-            }
-
-            if( p_packetizer->pf_get_cc )
-                DecoderGetCc( p_dec, p_packetizer );
-
-            while( p_packetized_block )
-            {
-                block_t *p_next = p_packetized_block->p_next;
-                p_packetized_block->p_next = NULL;
-
-                DecoderDecodeVideo( p_dec, p_packetized_block );
-                if( p_dec->b_error )
-                {
-                    block_ChainRelease( p_next );
-                    return;
-                }
-
-                p_packetized_block = p_next;
-            }
-        }
-        /* Drain the decoder after the packetizer is drained */
-        if( !pp_block )
-            DecoderDecodeVideo( p_dec, NULL );
-    }
-    else
-    {
-        DecoderDecodeVideo( p_dec, p_block );
-    }
-}
-
 static int DecoderPlayAudio( decoder_t *p_dec, block_t *p_audio,
                              unsigned *restrict pi_lost_sum )
 {
@@ -1234,78 +1157,6 @@ static int DecoderQueueAudio( decoder_t *p_dec, block_t *p_aout_buf )
     return ret;
 }
 
-static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block )
-{
-    block_t *p_aout_buf;
-    block_t **pp_block = p_block ? &p_block : NULL;
-    unsigned decoded = 0, lost = 0;
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
-    while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, pp_block ) ) )
-    {
-        decoded++;
-
-        DecoderPlayAudio( p_dec, p_aout_buf, &lost );
-    }
-
-    p_owner->pf_update_stat( p_owner, decoded, lost );
-}
-
-/* This function process a audio block
- */
-static void DecoderProcessAudio( decoder_t *p_dec, block_t *p_block )
-{
-    decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
-    if( p_owner->p_packetizer )
-    {
-        block_t *p_packetized_block;
-        block_t **pp_block = p_block ? &p_block : NULL;
-        decoder_t *p_packetizer = p_owner->p_packetizer;
-
-        while( (p_packetized_block =
-                p_packetizer->pf_packetize( p_packetizer, pp_block ) ) )
-        {
-            if( !es_format_IsSimilar( &p_dec->fmt_in, &p_packetizer->fmt_out ) )
-            {
-                msg_Dbg( p_dec, "restarting module due to input format change");
-
-                /* Drain the decoder module */
-                DecoderDecodeAudio( p_dec, NULL );
-
-                if( ReloadDecoder( p_dec, false, &p_packetizer->fmt_out,
-                                   RELOAD_DECODER ) != VLC_SUCCESS )
-                {
-                    block_ChainRelease( p_packetized_block );
-                    return;
-                }
-            }
-
-            while( p_packetized_block )
-            {
-                block_t *p_next = p_packetized_block->p_next;
-                p_packetized_block->p_next = NULL;
-
-                DecoderDecodeAudio( p_dec, p_packetized_block );
-                if( p_dec->b_error )
-                {
-                    block_ChainRelease( p_next );
-                    return;
-                }
-
-                p_packetized_block = p_next;
-            }
-        }
-        /* Drain the decoder after the packetizer is drained */
-        if( !pp_block )
-            DecoderDecodeAudio( p_dec, NULL );
-    }
-    else
-    {
-        DecoderDecodeAudio( p_dec, p_block );
-    }
-}
-
 static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic )
 {
     decoder_owner_sys_t *p_owner = p_dec->p_owner;
@@ -1391,22 +1242,19 @@ static int DecoderQueueSpu( decoder_t *p_dec, subpicture_t *p_spu )
     return i_ret;
 }
 
-/* This function process a subtitle block
- */
-static void DecoderProcessSpu( decoder_t *p_dec, block_t *p_block )
+
+static void DecoderDecode( decoder_t *p_dec, block_t *p_block )
 {
-    subpicture_t *p_spu;
-    block_t **pp_block = p_block ? &p_block : NULL;
+    decoder_owner_sys_t *p_owner = p_dec->p_owner;
 
-    while( (p_spu = p_dec->pf_decode_sub( p_dec, pp_block ) ) )
+    int ret = p_dec->pf_decode( p_dec, p_block );
+    switch( ret )
     {
-        do
-        {
-            subpicture_t *p = p_spu;
-            p_spu = p_spu->p_next;
-            p->p_next = NULL;
-            DecoderQueueSpu( p_dec, p );
-        } while( p_spu );
+        case VLCDEC_SUCCESS:
+            p_owner->pf_update_stat( p_owner, 1, 0 );
+            break;
+        default:
+            vlc_assert_unreachable();
     }
 }
 
@@ -1455,13 +1303,55 @@ static void DecoderProcess( decoder_t *p_dec, block_t *p_block )
     }
 #endif
 
-    switch( p_dec->fmt_out.i_cat )
+    if( p_owner->p_packetizer )
     {
-        case VIDEO_ES: DecoderProcessVideo( p_dec, p_block ); return;
-        case AUDIO_ES: DecoderProcessAudio( p_dec, p_block ); return;
-        case   SPU_ES: DecoderProcessSpu( p_dec, p_block ); return;
-        default:       vlc_assert_unreachable();
+        block_t *p_packetized_block;
+        block_t **pp_block = p_block ? &p_block : NULL;
+        decoder_t *p_packetizer = p_owner->p_packetizer;
+
+        while( (p_packetized_block =
+                p_packetizer->pf_packetize( p_packetizer, pp_block ) ) )
+        {
+            if( !es_format_IsSimilar( &p_dec->fmt_in, &p_packetizer->fmt_out ) )
+            {
+                msg_Dbg( p_dec, "restarting module due to input format change");
+
+                /* Drain the decoder module */
+                DecoderDecode( p_dec, NULL );
+
+                if( ReloadDecoder( p_dec, false, &p_packetizer->fmt_out,
+                                   RELOAD_DECODER ) != VLC_SUCCESS )
+                {
+                    block_ChainRelease( p_packetized_block );
+                    return;
+                }
+            }
+
+            if( p_packetizer->pf_get_cc )
+                DecoderGetCc( p_dec, p_packetizer );
+
+            while( p_packetized_block )
+            {
+                block_t *p_next = p_packetized_block->p_next;
+                p_packetized_block->p_next = NULL;
+
+                DecoderDecode( p_dec, p_packetized_block );
+                if( p_dec->b_error )
+                {
+                    block_ChainRelease( p_next );
+                    return;
+                }
+
+                p_packetized_block = p_next;
+            }
+        }
+        /* Drain the decoder after the packetizer is drained */
+        if( !pp_block )
+            DecoderDecode( p_dec, NULL );
     }
+    else
+        DecoderDecode( p_dec, p_block );
+    return;
 
 error:
     if( p_block )
diff --git a/src/input/demux.c b/src/input/demux.c
index f3b0495c75..58234724bc 100644
--- a/src/input/demux.c
+++ b/src/input/demux.c
@@ -504,9 +504,7 @@ decoder_t *demux_PacketizerNew( demux_t *p_demux, es_format_t *p_fmt, const char
     }
     p_fmt->b_packetized = false;
 
-    p_packetizer->pf_decode_audio = NULL;
-    p_packetizer->pf_decode_video = NULL;
-    p_packetizer->pf_decode_sub = NULL;
+    p_packetizer->pf_decode = NULL;
     p_packetizer->pf_packetize = NULL;
 
     p_packetizer->fmt_in = *p_fmt;
diff --git a/src/misc/image.c b/src/misc/image.c
index 9e0fd7102e..ec372303bc 100644
--- a/src/misc/image.c
+++ b/src/misc/image.c
@@ -93,6 +93,8 @@ image_handler_t *image_HandlerCreate( vlc_object_t *p_this )
     p_image->pf_write_url = ImageWriteUrl;
     p_image->pf_convert = ImageConvert;
 
+    p_image->outfifo = picture_fifo_New();
+
     return p_image;
 }
 
@@ -108,6 +110,8 @@ void image_HandlerDelete( image_handler_t *p_image )
     if( p_image->p_enc ) DeleteEncoder( p_image->p_enc );
     if( p_image->p_filter ) DeleteFilter( p_image->p_filter );
 
+    picture_fifo_Delete( p_image->outfifo );
+
     free( p_image );
     p_image = NULL;
 }
@@ -117,11 +121,18 @@ void image_HandlerDelete( image_handler_t *p_image )
  *
  */
 
+static int ImageQueueVideo( decoder_t *p_dec, picture_t *p_pic )
+{
+    image_handler_t *p_image = p_dec->p_queue_ctx;
+    picture_fifo_Push( p_image->outfifo, p_pic );
+    return 0;
+}
+
 static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
                              video_format_t *p_fmt_in,
                              video_format_t *p_fmt_out )
 {
-    picture_t *p_pic = NULL, *p_tmp;
+    picture_t *p_pic = NULL;
 
     /* Check if we can reuse the current decoder */
     if( p_image->p_dec &&
@@ -140,15 +151,36 @@ static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block,
             block_Release(p_block);
             return NULL;
         }
+        if( p_image->p_dec->fmt_out.i_cat != VIDEO_ES )
+        {
+            DeleteDecoder( p_image->p_dec );
+            p_image->p_dec = NULL;
+            block_Release(p_block);
+            return NULL;
+        }
+        p_image->p_dec->pf_queue_video = ImageQueueVideo;
+        p_image->p_dec->p_queue_ctx = p_image;
     }
 
     p_block->i_pts = p_block->i_dts = mdate();
-    while( (p_tmp = p_image->p_dec->pf_decode_video( p_image->p_dec, &p_block ))
-             != NULL )
+    int ret = p_image->p_dec->pf_decode( p_image->p_dec, p_block );
+    if( ret == VLCDEC_SUCCESS )
     {
-        if( p_pic != NULL )
-            picture_Release( p_pic );
-        p_pic = p_tmp;
+        /* Drain */
+        p_image->p_dec->pf_decode( p_image->p_dec, NULL );
+
+        p_pic = picture_fifo_Pop( p_image->outfifo );
+
+        unsigned lostcount = 0;
+        picture_t *lostpic;
+        while( ( lostpic = picture_fifo_Pop( p_image->outfifo ) ) != NULL )
+        {
+            picture_Release( lostpic );
+            lostcount++;
+        }
+        if( lostcount > 0 )
+            msg_Warn( p_image->p_parent, "Image decoder output more than one "
+                      "picture (%d)", lostcount );
     }
 
     if( p_pic == NULL )
-- 
2.11.0



More information about the vlc-devel mailing list