[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