[vlc-devel] [RFC PATCH 7/9] a52: split decoder and packetizer

Thomas Guillem thomas at gllm.fr
Sat Jul 9 12:20:15 CEST 2016


The A52 decoder need the A52 packetizer, it queries it via
decoder_RequestPacketizer(). All the block parsing is done on the packetizer
side.

When the A52 packetizer find a valid fmt_out, the core will reload the decoder
module: the A52 decoder will be closed and opened again. The A52 decoder will
be able to know if an audio output can handle SPDIF in the open function: if
decoder_UpdateAudioFormat() doesn't fail. If decoder_UpdateAudioFormat() fails,
the A52 decoder will abort and an other decoder will be used to output PCM
(avcodec, and the future a52tofloat32 that will be moved to decoder).

The same thing can be done for DTS, or every other passthrough format.  Maybe
this can be done if the same module.
---
 modules/codec/a52.c | 159 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 90 insertions(+), 69 deletions(-)

diff --git a/modules/codec/a52.c b/modules/codec/a52.c
index 044905b..934cc75 100644
--- a/modules/codec/a52.c
+++ b/modules/codec/a52.c
@@ -45,19 +45,20 @@
  *****************************************************************************/
 static int  OpenDecoder   ( vlc_object_t * );
 static int  OpenPacketizer( vlc_object_t * );
-static void CloseCommon   ( vlc_object_t * );
+static void CloseDecoder  ( vlc_object_t * );
+static void ClosePacketizer   ( vlc_object_t * );
 
 vlc_module_begin ()
     set_description( N_("A/52 parser") )
     set_capability( "decoder", 100 )
-    set_callbacks( OpenDecoder, CloseCommon )
+    set_callbacks( OpenDecoder, CloseDecoder )
     set_category( CAT_INPUT )
     set_subcategory( SUBCAT_INPUT_ACODEC )
 
     add_submodule ()
     set_description( N_("A/52 audio packetizer") )
     set_capability( "packetizer", 10 )
-    set_callbacks( OpenPacketizer, CloseCommon )
+    set_callbacks( OpenPacketizer, ClosePacketizer )
 vlc_module_end ()
 
 /*****************************************************************************
@@ -66,9 +67,6 @@ vlc_module_end ()
 
 struct decoder_sys_t
 {
-    /* Module mode */
-    bool b_packetizer;
-
     /*
      * Input properties
      */
@@ -80,6 +78,7 @@ struct decoder_sys_t
      * Common properties
      */
     date_t  end_date;
+    bool    b_date_set;
 
     mtime_t i_pts;
 
@@ -89,33 +88,26 @@ struct decoder_sys_t
 /****************************************************************************
  * Local prototypes
  ****************************************************************************/
+static block_t *PacketizeBlock  ( decoder_t *, block_t ** );
 static block_t *DecodeBlock  ( decoder_t *, block_t ** );
 static void Flush( decoder_t * );
 
 static uint8_t *GetOutBuffer ( decoder_t *, block_t ** );
-static block_t *GetAoutBuffer( decoder_t * );
 static block_t *GetSoutBuffer( decoder_t * );
 
 /*****************************************************************************
- * OpenCommon: probe the decoder/packetizer and return score
+ * OpenPacketizer: probe the decoder/packetizer and return score
  *****************************************************************************/
-static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
+static int OpenPacketizer( vlc_object_t *p_this )
 {
     decoder_t *p_dec = (decoder_t*)p_this;
     decoder_sys_t *p_sys;
-    vlc_fourcc_t i_codec;
 
     switch( p_dec->fmt_in.i_codec )
     {
     case VLC_CODEC_A52:
-        i_codec = VLC_CODEC_A52;
         break;
     case VLC_CODEC_EAC3:
-        /* XXX ugly hack, a52 does not support eac3 so no eac3 pass-through
-         * support */
-        if( !b_packetizer )
-            return VLC_EGENERIC;
-        i_codec = VLC_CODEC_EAC3;
         break;
     default:
         return VLC_EGENERIC;
@@ -127,39 +119,75 @@ static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
         return VLC_ENOMEM;
 
     /* Misc init */
-    p_sys->b_packetizer = b_packetizer;
     p_sys->i_state = STATE_NOSYNC;
     date_Set( &p_sys->end_date, 0 );
     p_sys->i_pts = VLC_TS_INVALID;
+    p_sys->b_date_set = false;
 
     block_BytestreamInit( &p_sys->bytestream );
 
     /* Set output properties */
     p_dec->fmt_out.i_cat = AUDIO_ES;
-    p_dec->fmt_out.i_codec = i_codec;
-    p_dec->fmt_out.audio.i_rate = 0; /* So end_date gets initialized */
-    p_dec->fmt_out.audio.i_bytes_per_frame = 0;
+    p_dec->fmt_out.i_codec = p_dec->fmt_in.i_codec;
+    p_dec->fmt_out.audio = p_dec->fmt_in.audio;
+
+    p_sys->frame.i_rate = p_dec->fmt_out.audio.i_rate;
+    p_sys->frame.i_channels = p_dec->fmt_out.audio.i_channels;
+    p_sys->frame.i_size = p_dec->fmt_out.audio.i_bytes_per_frame;
+    p_sys->frame.i_samples = p_dec->fmt_out.audio.i_frame_length;
+    p_sys->frame.i_channels_conf = p_dec->fmt_out.audio.i_original_channels;
+    p_sys->frame.i_bitrate = p_dec->fmt_out.i_bitrate;
 
     /* Set callback */
-    if( b_packetizer )
-        p_dec->pf_packetize    = DecodeBlock;
-    else
-        p_dec->pf_decode_audio = DecodeBlock;
-    p_dec->pf_flush            = Flush;
+    p_dec->pf_packetize = PacketizeBlock;
+    p_dec->pf_flush     = Flush;
     return VLC_SUCCESS;
 }
 
 static int OpenDecoder( vlc_object_t *p_this )
 {
-    /* HACK: Don't use this codec if we don't have an a52 audio filter */
-    if( !module_exists( "a52tofloat32" ) )
+    decoder_t *p_dec = (decoder_t*)p_this;
+
+    switch( p_dec->fmt_in.i_codec )
+    {
+    case VLC_CODEC_A52:
+        break;
+    case VLC_CODEC_EAC3:
+        break;
+    default:
         return VLC_EGENERIC;
-    return OpenCommon( p_this, false );
-}
+    }
 
-static int OpenPacketizer( vlc_object_t *p_this )
-{
-    return OpenCommon( p_this, true );
+    if( !var_InheritBool( p_dec, "spdif" ) )
+        return VLC_EGENERIC;
+
+    if( decoder_RequestPacketizer( p_dec, "a52" ) != VLC_SUCCESS )
+        return VLC_EGENERIC;
+
+    /* Set output properties */
+    p_dec->fmt_out.i_cat = AUDIO_ES;
+    p_dec->fmt_out.i_codec = p_dec->fmt_in.i_codec;
+    p_dec->fmt_out.audio = p_dec->fmt_in.audio;
+    p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
+
+    /* If fmt_out is not complete, the a52 packetizer didn't parse any blocks
+     * yet. We shouldn't fail in that case in order to let the packetizer parse
+     * the first blocks that will trigger a module reload with a valid fmt_in.
+     * */
+    if( p_dec->fmt_out.audio.i_physical_channels != 0
+     && p_dec->fmt_out.audio.i_original_channels != 0
+     && p_dec->fmt_out.audio.i_bytes_per_frame != 0
+     && p_dec->fmt_out.audio.i_frame_length != 0
+     && decoder_UpdateAudioFormat( p_dec ) )
+    {
+        decoder_RequestPacketizer( p_dec, NULL );
+        return VLC_EGENERIC;
+    }
+
+    p_dec->pf_decode_audio = DecodeBlock;
+    p_dec->pf_flush        = NULL;
+
+    return VLC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -175,11 +203,11 @@ static void Flush( decoder_t *p_dec )
 }
 
 /****************************************************************************
- * DecodeBlock: the whole thing
+ * PacketizeBlock: the whole thing
  ****************************************************************************
  * This function is called just after the thread is launched.
  ****************************************************************************/
-static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     uint8_t p_header[VLC_A52_HEADER_SIZE];
@@ -278,8 +306,7 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
                 return NULL;
             }
 
-            if( p_sys->b_packetizer &&
-                p_header[0] == 0 && p_header[1] == 0 )
+            if( p_header[0] == 0 && p_header[1] == 0 )
             {
                 /* A52 wav files and audio CD's use stuffing */
                 p_sys->i_state = STATE_GET_DATA;
@@ -334,10 +361,23 @@ static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
     }
 }
 
+static block_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
+{
+    (void) p_dec;
+    if( pp_block != NULL )
+    {
+        block_t *p_block = *pp_block;
+        *pp_block = NULL;
+        return p_block;
+    }
+    else
+        return NULL;
+}
+
 /*****************************************************************************
- * CloseCommon: clean up the decoder
+ * ClosePacketizer: clean up the decoder
  *****************************************************************************/
-static void CloseCommon( vlc_object_t *p_this )
+static void ClosePacketizer( vlc_object_t *p_this )
 {
     decoder_t *p_dec = (decoder_t*)p_this;
     decoder_sys_t *p_sys = p_dec->p_sys;
@@ -347,6 +387,12 @@ static void CloseCommon( vlc_object_t *p_this )
     free( p_sys );
 }
 
+static void CloseDecoder( vlc_object_t *p_this )
+{
+    decoder_t *p_dec = (decoder_t*)p_this;
+    decoder_RequestPacketizer( p_dec, NULL );
+}
+
 /*****************************************************************************
  * GetOutBuffer:
  *****************************************************************************/
@@ -355,13 +401,15 @@ static uint8_t *GetOutBuffer( decoder_t *p_dec, block_t **pp_out_buffer )
     decoder_sys_t *p_sys = p_dec->p_sys;
     uint8_t *p_buf;
 
-    if( p_dec->fmt_out.audio.i_rate != p_sys->frame.i_rate )
+    if( !p_sys->b_date_set
+     || p_dec->fmt_out.audio.i_rate != p_sys->frame.i_rate )
     {
         msg_Dbg( p_dec, "A/52 channels:%d samplerate:%d bitrate:%d",
                  p_sys->frame.i_channels, p_sys->frame.i_rate, p_sys->frame.i_bitrate );
 
         date_Init( &p_sys->end_date, p_sys->frame.i_rate, 1 );
         date_Set( &p_sys->end_date, p_sys->i_pts );
+        p_sys->b_date_set = true;
     }
 
     p_dec->fmt_out.audio.i_rate     = p_sys->frame.i_rate;
@@ -376,36 +424,9 @@ static uint8_t *GetOutBuffer( decoder_t *p_dec, block_t **pp_out_buffer )
 
     p_dec->fmt_out.i_bitrate = p_sys->frame.i_bitrate;
 
-    if( p_sys->b_packetizer )
-    {
-        block_t *p_sout_buffer = GetSoutBuffer( p_dec );
-        p_buf = p_sout_buffer ? p_sout_buffer->p_buffer : NULL;
-        *pp_out_buffer = p_sout_buffer;
-    }
-    else
-    {
-        block_t *p_aout_buffer = GetAoutBuffer( p_dec );
-        p_buf = p_aout_buffer ? p_aout_buffer->p_buffer : NULL;
-        *pp_out_buffer = p_aout_buffer;
-    }
-
-    return p_buf;
-}
-
-/*****************************************************************************
- * GetAoutBuffer:
- *****************************************************************************/
-static block_t *GetAoutBuffer( decoder_t *p_dec )
-{
-    decoder_sys_t *p_sys = p_dec->p_sys;
-
-    block_t *p_buf = decoder_NewAudioBuffer( p_dec, p_sys->frame.i_samples );
-    if( p_buf )
-    {
-        p_buf->i_pts = date_Get( &p_sys->end_date );
-        p_buf->i_length = date_Increment( &p_sys->end_date,
-                                          p_sys->frame.i_samples ) - p_buf->i_pts;
-    }
+    block_t *p_sout_buffer = GetSoutBuffer( p_dec );
+    p_buf = p_sout_buffer ? p_sout_buffer->p_buffer : NULL;
+    *pp_out_buffer = p_sout_buffer;
 
     return p_buf;
 }
-- 
2.8.1



More information about the vlc-devel mailing list