[vlc-commits] packetizer: dts: handle LBR (fix #21973)

Francois Cartegnie git at videolan.org
Mon Mar 11 19:39:17 CET 2019


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Mon Mar 11 18:28:54 2019 +0100| [ddf8716a0d749e9af01b6d1a32f6f99ab7aed340] | committer: Francois Cartegnie

packetizer: dts: handle LBR (fix #21973)

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=ddf8716a0d749e9af01b6d1a32f6f99ab7aed340
---

 modules/packetizer/dts.c        | 75 ++++++++++++++++++++++++++++++++---------
 modules/packetizer/dts_header.c | 55 ++++++++++++++++++++++++++++--
 modules/packetizer/dts_header.h |  3 ++
 3 files changed, 114 insertions(+), 19 deletions(-)

diff --git a/modules/packetizer/dts.c b/modules/packetizer/dts.c
index b5bb4f09ce..0500009d57 100644
--- a/modules/packetizer/dts.c
+++ b/modules/packetizer/dts.c
@@ -222,14 +222,47 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block )
             break;
 
         case STATE_SYNC_SUBSTREAM_EXTENSIONS:
+            /* Peek into the substream extension (sync + header size < frame_size) */
+            if( block_PeekOffsetBytes( &p_sys->bytestream,
+                                       p_sys->first.i_substream_header_size,
+                                       p_header,
+                                       VLC_DTS_HEADER_SIZE ) != VLC_SUCCESS )
             {
-                msg_Warn( p_dec, "substream without the paired core stream, "
-                          "skip it" );
+                /* Need more data */
+                return NULL;
+            }
+
+            vlc_dts_header_t xssheader;
+            if( vlc_dts_header_Parse( &xssheader, p_header,
+                                      VLC_DTS_HEADER_SIZE ) != VLC_SUCCESS )
+            {
+                msg_Dbg( p_dec, "emulated substream sync word, can't find extension" );
+                block_SkipByte( &p_sys->bytestream );
                 p_sys->i_state = STATE_NOSYNC;
-                if( block_SkipBytes( &p_sys->bytestream,
-                                     p_sys->first.i_frame_size ) != VLC_SUCCESS )
-                    return NULL;
+                break;
+            }
+
+            if( xssheader.syncword == DTS_SYNC_SUBSTREAM_LBR )
+            {
+                /*
+                 * LBR exists as independant SUBSTREAM. It is seen valid
+                 * only when SUBSTREAM[LBR]..SUBTREAM.
+                 * CORE...SUBSTREAM is regular extension.
+                 * SUBSTREAM...CORE is sync issue.
+                 */
+                p_dec->fmt_out.i_profile = PROFILE_DTS_EXPRESS;
+                p_sys->first.i_rate = xssheader.i_rate;
+                p_sys->first.i_frame_length = xssheader.i_frame_length;
+                p_sys->i_state = STATE_NEXT_SYNC;
+                break;
             }
+
+            msg_Warn( p_dec, "substream without the paired core stream, skip it" );
+            p_sys->i_state = STATE_NOSYNC;
+            p_dec->fmt_out.i_profile = PROFILE_DTS;
+            if( block_SkipBytes( &p_sys->bytestream,
+                                 p_sys->first.i_frame_size ) != VLC_SUCCESS )
+                return NULL;
             break;
 
         case STATE_NEXT_SYNC:
@@ -279,24 +312,34 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block )
 
                 /* Check if a DTS substream packet is located just after
                  * the core packet */
-                if( p_sys->i_next_offset == p_sys->first.i_frame_size )
+                if( p_sys->i_next_offset == p_sys->first.i_frame_size &&
+                    vlc_dts_header_Parse( &p_sys->second,
+                                          p_header, VLC_DTS_HEADER_SIZE ) == VLC_SUCCESS &&
+                    p_sys->second.syncword == DTS_SYNC_SUBSTREAM )
                 {
-                    if( vlc_dts_header_Parse( &p_sys->second, p_header,
-                                              VLC_DTS_HEADER_SIZE )
-                        == VLC_SUCCESS && p_sys->second.syncword == DTS_SYNC_SUBSTREAM )
-                    {
-                        p_sys->i_state = STATE_NEXT_SYNC_SUBSTREAM_EXTENSIONS;
-                        break;
-                    }
+                    p_sys->i_state = STATE_NEXT_SYNC_SUBSTREAM_EXTENSIONS;
+                }
+                else
+                {
+                    p_dec->fmt_out.i_profile = PROFILE_DTS;
+                    p_sys->i_state = STATE_GET_DATA;
                 }
-                p_sys->i_state = STATE_GET_DATA;
             }
             break;
 
         case STATE_NEXT_SYNC_SUBSTREAM_EXTENSIONS:
-            p_dec->fmt_out.i_profile = PROFILE_DTS_HD;
+            assert(p_sys->second.syncword == DTS_SYNC_SUBSTREAM);
+            if( p_sys->first.syncword == DTS_SYNC_SUBSTREAM )
+            {
+                /* First substream must have been LBR */
+                p_dec->fmt_out.i_profile = PROFILE_DTS_EXPRESS;
+            }
+            else /* Otherwise that's core + extensions, we need to output both */
+            {
+                p_dec->fmt_out.i_profile = PROFILE_DTS_HD;
+                p_sys->i_input_size += p_sys->second.i_frame_size;
+            }
             p_sys->i_state = STATE_GET_DATA;
-            p_sys->i_input_size += p_sys->second.i_frame_size;
             break;
 
         case STATE_GET_DATA:
diff --git a/modules/packetizer/dts_header.c b/modules/packetizer/dts_header.c
index 1d4ebd98a1..0eb64dfcfa 100644
--- a/modules/packetizer/dts_header.c
+++ b/modules/packetizer/dts_header.c
@@ -113,6 +113,9 @@ static enum vlc_dts_syncword_e dts_header_getSyncword( const uint8_t *p_buf )
      && (p_buf[4] & 0xf0) == 0xf0 && p_buf[5] == 0x07 )
         return DTS_SYNC_CORE_14BITS_LE;
     else
+    if( memcmp( p_buf, "\x0A\x80\x19\x21", 4 ) == 0 )
+        return DTS_SYNC_SUBSTREAM_LBR;
+    else
         return DTS_SYNC_NONE;
 }
 
@@ -233,6 +236,49 @@ static uint16_t dca_get_channels( uint8_t i_amode, bool b_lfe,
     return i_physical_channels;
 }
 
+static uint8_t dca_get_LBR_channels( uint16_t nuSpkrActivityMask,
+                                     uint16_t *pi_chans )
+{
+    uint16_t i_physical_channels = 0;
+    uint8_t i_channels = 0;
+
+    static const struct
+    {
+        int phy;
+        uint8_t nb;
+    } bitmask[16] = {
+         /* table 7-10 */
+        { AOUT_CHAN_CENTER,     1 },
+        { AOUT_CHANS_FRONT,     2 },
+        { AOUT_CHANS_MIDDLE,    2 },
+        { AOUT_CHAN_LFE,        1 },
+        { AOUT_CHAN_REARCENTER, 1 },
+        { 0,                    2 },
+        { AOUT_CHANS_REAR,      2 },
+        { 0,                    1 },
+        { 0,                    1 },
+        { 0,                    2 },
+        { AOUT_CHANS_FRONT,     2 },
+        { AOUT_CHANS_MIDDLE,    2 },
+        { 0,                    1 },
+        { 0,                    2 },
+        { 0,                    1 },
+        { 0,                    2 },
+    };
+
+    for( int i=0 ; nuSpkrActivityMask; nuSpkrActivityMask >>= 1 )
+    {
+        if( nuSpkrActivityMask & 1 )
+        {
+            i_physical_channels |= bitmask[i].phy;
+            i_channels += bitmask[i].nb;
+        }
+        ++i;
+    }
+    *pi_chans = i_physical_channels;
+    return i_channels;
+}
+
 static int dts_header_ParseSubstream( vlc_dts_header_t *p_header,
                                       const void *p_buffer )
 {
@@ -288,12 +334,13 @@ static int dts_header_ParseLBRExtSubstream( vlc_dts_header_t *p_header,
         p_header->i_frame_length = 4096;
 
     uint16_t i_spkrmask = bs_read( &s, 16 );
+    dca_get_LBR_channels( i_spkrmask, &p_header->i_physical_channels );
     bs_skip( &s, 16 );
     bs_skip( &s, 8 );
-    bs_skip( &s, 8 );
-    bs_skip( &s, 16 );
+    uint16_t nLBRBitRateMSnybbles = bs_read( &s, 8 );
     bs_skip( &s, 16 );
-
+    uint16_t nLBRScaledBitRate_LSW = bs_read( &s, 16 );
+    p_header->i_bitrate = nLBRScaledBitRate_LSW | ((nLBRBitRateMSnybbles & 0xF0) << 12);
     return VLC_SUCCESS;
 }
 
@@ -388,6 +435,8 @@ int vlc_dts_header_Parse( vlc_dts_header_t *p_header,
         }
         case DTS_SYNC_SUBSTREAM:
             return dts_header_ParseSubstream( p_header, p_buffer );
+        case DTS_SYNC_SUBSTREAM_LBR:
+            return dts_header_ParseLBRExtSubstream( p_header, p_buffer );
         default:
             vlc_assert_unreachable();
     }
diff --git a/modules/packetizer/dts_header.h b/modules/packetizer/dts_header.h
index 2ec623d934..255f0be770 100644
--- a/modules/packetizer/dts_header.h
+++ b/modules/packetizer/dts_header.h
@@ -26,6 +26,7 @@
 #define PROFILE_DTS_INVALID -1
 #define PROFILE_DTS 0
 #define PROFILE_DTS_HD 1
+#define PROFILE_DTS_EXPRESS 2
 
 enum vlc_dts_syncword_e
 {
@@ -35,6 +36,8 @@ enum vlc_dts_syncword_e
     DTS_SYNC_CORE_14BITS_BE,
     DTS_SYNC_CORE_14BITS_LE,
     DTS_SYNC_SUBSTREAM,
+    /* Substreams internal syncs */
+    DTS_SYNC_SUBSTREAM_LBR,
 };
 
 typedef struct



More information about the vlc-commits mailing list