[vlc-devel] [PATCH 5/9] packetizer/a52: rewrite header parser
Thomas Guillem
thomas at gllm.fr
Thu Sep 1 10:54:12 CEST 2016
Rewrite with bit stream helpers using the AC3/EAC3 spec. Add
i_blocks_per_sync_frame, eac3.strmtyp, eac3.i_substreamid that will be used by
the S/PDIF converter.
---
modules/packetizer/a52.h | 221 +++++++++++++++++++++++++++++------------------
1 file changed, 138 insertions(+), 83 deletions(-)
diff --git a/modules/packetizer/a52.h b/modules/packetizer/a52.h
index 3b7315c..73370c5 100644
--- a/modules/packetizer/a52.h
+++ b/modules/packetizer/a52.h
@@ -1,13 +1,14 @@
/*****************************************************************************
* a52.h
*****************************************************************************
- * Copyright (C) 2001-2009 Laurent Aimar
+ * Copyright (C) 2001-2016 Laurent Aimar
* $Id$
*
* Authors: Stéphane Borel <stef at via.ecp.fr>
* Christophe Massiot <massiot at via.ecp.fr>
* Gildas Bazin <gbazin at videolan.org>
* Laurent Aimar <fenrir at via.ecp.fr>
+ * Thomas Guillem <thomas at gllm.fr>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
@@ -49,66 +50,125 @@ typedef struct
unsigned int i_size;
unsigned int i_samples;
+ union {
+ struct {
+ enum {
+ EAC3_STRMTYP_INDEPENDENT = 0,
+ EAC3_STRMTYP_DEPENDENT = 1,
+ EAC3_STRMTYP_AC3_CONVERT = 2,
+ EAC3_STRMTYP_RESERVED,
+ } strmtyp;
+ uint8_t i_substreamid;
+ } eac3;
+ };
+ uint8_t i_blocks_per_sync_frame;
} vlc_a52_header_t;
/**
* It parse AC3 sync info.
*
- * This code is borrowed from liba52 by Aaron Holtzman & Michel Lespinasse,
- * since we don't want to oblige S/PDIF people to use liba52 just to get
- * their SyncInfo...
+ * cf. AC3 spec
*/
static inline int vlc_a52_header_ParseAc3( vlc_a52_header_t *p_header,
const uint8_t *p_buf,
- const uint32_t *p_acmod )
+ const uint32_t *p_acmod,
+ const unsigned *pi_fscod_samplerates )
{
- static const uint8_t pi_halfrate[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 };
- static const unsigned int pi_bitrate[] = { 32, 40, 48, 56, 64, 80, 96, 112,
- 128, 160, 192, 224, 256, 320, 384, 448,
- 512, 576, 640 };
- static const uint8_t pi_lfeon[8] = { 0x10, 0x10, 0x04, 0x04,
- 0x04, 0x01, 0x04, 0x01 };
-
- /* */
- const unsigned i_rate_shift = pi_halfrate[p_buf[5] >> 3];
-
- /* acmod, dsurmod and lfeon */
- const unsigned i_acmod = p_buf[6] >> 5;
- if( (p_buf[6] & 0xf8) == 0x50 )
- /* Dolby surround = stereo + Dolby */
- p_header->i_channels_conf = AOUT_CHANS_STEREO | AOUT_CHAN_DOLBYSTEREO;
- else
- p_header->i_channels_conf = p_acmod[i_acmod];
- if( p_buf[6] & pi_lfeon[i_acmod] )
- p_header->i_channels_conf |= AOUT_CHAN_LFE;
+ /* cf. Table 5.18 Frame Size Code Table */
+ static const uint16_t ppi_frmsizcod_fscod_sizes[][3] = {
+ /* 32K, 44.1K, 48K */
+ { 96, 69, 64 },
+ { 96, 70, 64 },
+ { 120, 87, 80 },
+ { 120, 88, 80 },
+ { 144, 104, 96 },
+ { 144, 105, 96 },
+ { 168, 121, 112 },
+ { 168, 122, 112 },
+ { 192, 139, 128 },
+ { 192, 140, 128 },
+ { 240, 174, 160 },
+ { 240, 175, 160 },
+ { 288, 208, 192 },
+ { 288, 209, 192 },
+ { 336, 243, 224 },
+ { 336, 244, 224 },
+ { 384, 278, 256 },
+ { 384, 279, 256 },
+ { 480, 348, 320 },
+ { 480, 349, 320 },
+ { 576, 417, 384 },
+ { 576, 418, 384 },
+ { 672, 487, 448 },
+ { 672, 488, 448 },
+ { 768, 557, 512 },
+ { 768, 558, 512 },
+ { 960, 696, 640 },
+ { 960, 697, 640 },
+ { 1152, 835, 768 },
+ { 1152, 836, 768 },
+ { 1344, 975, 896 },
+ { 1344, 976, 896 },
+ { 1536, 1114, 1024 },
+ { 1536, 1115, 1024 },
+ { 1728, 1253, 1152 },
+ { 1728, 1254, 1152 },
+ { 1920, 1393, 1280 },
+ { 1920, 1394, 1280 }
+ };
+ static const uint16_t pi_frmsizcod_bitrates[] = {
+ 32, 40, 48, 56,
+ 64, 80, 96, 112,
+ 128, 160, 192, 224,
+ 256, 320, 384, 448,
+ 512, 576, 640
+ };
- p_header->i_channels = popcount(p_header->i_channels_conf
- & AOUT_CHAN_PHYSMASK);
+ bs_t s;
+ bs_init( &s, (void*)p_buf, VLC_A52_HEADER_SIZE );
+ bs_skip( &s, 32 ); /* start code + CRC */
- const unsigned i_frmsizecod = p_buf[4] & 63;
- if( i_frmsizecod >= 38 )
+ /* cf. 5.3.2 */
+ const uint8_t i_fscod = bs_read( &s, 2 );
+ if( i_fscod == 3 )
return VLC_EGENERIC;
- const unsigned i_bitrate_base = pi_bitrate[i_frmsizecod >> 1];
- p_header->i_bitrate = (i_bitrate_base * 1000) >> i_rate_shift;
-
- switch( p_buf[4] & 0xc0 )
- {
- case 0:
- p_header->i_rate = 48000 >> i_rate_shift;
- p_header->i_size = 4 * i_bitrate_base;
- break;
- case 0x40:
- p_header->i_rate = 44100 >> i_rate_shift;
- p_header->i_size = 2 * (320 * i_bitrate_base / 147 + (i_frmsizecod & 1));
- break;
- case 0x80:
- p_header->i_rate = 32000 >> i_rate_shift;
- p_header->i_size = 6 * i_bitrate_base;
- break;
- default:
+ const uint8_t i_frmsizcod = bs_read( &s, 6 );
+ if( i_frmsizcod >= 38 )
return VLC_EGENERIC;
+ const uint8_t i_bsid = bs_read( &s, 5 );
+ bs_skip( &s, 3 ); /* i_bsmod */
+ const uint8_t i_acmod = bs_read( &s, 3 );
+ if( ( i_acmod & 0x1 ) && ( i_acmod != 0x1 ) )
+ {
+ /* if 3 front channels */
+ bs_skip( &s, 2 ); /* i_cmixlev */
+ }
+ if( i_acmod & 0x4 )
+ {
+ /* if a surround channel exists */
+ bs_skip( &s, 2 ); /* i_surmixlev */
}
- p_header->i_samples = 6*256;
+ /* if in 2/0 mode */
+ const uint8_t i_dsurmod = i_acmod == 0x2 ? bs_read( &s, 2 ) : 0;
+ const uint8_t i_lfeon = bs_read( &s, 1 );
+
+ p_header->i_channels_conf = p_acmod[i_acmod];
+ if( i_dsurmod == 2 )
+ p_header->i_channels_conf |= AOUT_CHAN_DOLBYSTEREO;
+ if( i_lfeon )
+ p_header->i_channels_conf |= AOUT_CHAN_LFE;
+
+ p_header->i_channels = popcount(p_header->i_channels_conf
+ & AOUT_CHAN_PHYSMASK);
+
+ const unsigned i_rate_shift = __MAX(i_bsid, 8) - 8;
+ p_header->i_bitrate = (pi_frmsizcod_bitrates[i_frmsizcod >> 1] * 1000)
+ >> i_rate_shift;
+ p_header->i_rate = pi_fscod_samplerates[i_fscod] >> i_rate_shift;
+
+ p_header->i_size = ppi_frmsizcod_fscod_sizes[i_frmsizcod][2 - i_fscod] * 2;
+ p_header->i_blocks_per_sync_frame = 6;
+ p_header->i_samples = p_header->i_blocks_per_sync_frame * 256;
p_header->b_eac3 = false;
return VLC_SUCCESS;
@@ -119,37 +179,35 @@ static inline int vlc_a52_header_ParseAc3( vlc_a52_header_t *p_header,
*/
static inline int vlc_a52_header_ParseEac3( vlc_a52_header_t *p_header,
const uint8_t *p_buf,
- const uint32_t *p_acmod )
+ const uint32_t *p_acmod,
+ const unsigned *pi_fscod_samplerates )
{
- static const unsigned pi_samplerate[3] = { 48000, 44100, 32000 };
- unsigned i_numblkscod;
bs_t s;
-
-
bs_init( &s, (void*)p_buf, VLC_A52_HEADER_SIZE );
- bs_skip( &s, 16 + /* start code */
- 2 + /* stream type */
- 3 ); /* substream id */
- const unsigned i_frame_size = bs_read( &s, 11 );
- if( i_frame_size < 2 )
+ bs_skip( &s, 16 ); /* start code */
+ p_header->eac3.strmtyp = bs_read( &s, 2 ); /* Stream Type */
+ p_header->eac3.i_substreamid = bs_read( &s, 3 );/* Substream Identification */
+
+ const uint16_t i_frmsiz = bs_read( &s, 11 );
+ if( i_frmsiz < 2 )
return VLC_EGENERIC;
- p_header->i_size = 2 * ( i_frame_size + 1 );
+ p_header->i_size = 2 * (i_frmsiz + 1 );
- const unsigned i_fscod = bs_read( &s, 2 );
+ const uint8_t i_fscod = bs_read( &s, 2 );
if( i_fscod == 0x03 )
{
- const unsigned i_fscod2 = bs_read( &s, 2 );
- if( i_fscod2 == 0X03 )
+ const uint8_t i_fscod2 = bs_read( &s, 2 );
+ if( i_fscod2 == 0x03 )
return VLC_EGENERIC;
- p_header->i_rate = pi_samplerate[i_fscod2] / 2;
- i_numblkscod = 6;
+ p_header->i_rate = pi_fscod_samplerates[i_fscod2] / 2;
+ p_header->i_blocks_per_sync_frame = 6;
}
else
{
- static const int pi_blocks[4] = { 1, 2, 3, 6 };
+ static const int pi_numblkscod [4] = { 1, 2, 3, 6 };
- p_header->i_rate = pi_samplerate[i_fscod];
- i_numblkscod = pi_blocks[bs_read( &s, 2 )];
+ p_header->i_rate = pi_fscod_samplerates[i_fscod];
+ p_header->i_blocks_per_sync_frame = pi_numblkscod[bs_read( &s, 2 )];
}
const unsigned i_acmod = bs_read( &s, 3 );
@@ -158,11 +216,11 @@ static inline int vlc_a52_header_ParseEac3( vlc_a52_header_t *p_header,
p_header->i_channels_conf = p_acmod[i_acmod];
if( i_lfeon )
p_header->i_channels_conf |= AOUT_CHAN_LFE;
- p_header->i_channels = popcount(p_header->i_channels_conf
- & AOUT_CHAN_PHYSMASK);
- p_header->i_bitrate = 8 * p_header->i_size * (p_header->i_rate)
- / (i_numblkscod * 256);
- p_header->i_samples = i_numblkscod * 256;
+ p_header->i_channels = popcount( p_header->i_channels_conf
+ & AOUT_CHAN_PHYSMASK );
+ p_header->i_bitrate = 8 * p_header->i_size * p_header->i_rate
+ / (p_header->i_blocks_per_sync_frame * 256);
+ p_header->i_samples = p_header->i_blocks_per_sync_frame * 256;
p_header->b_eac3 = true;
return VLC_SUCCESS;
@@ -187,6 +245,9 @@ static inline int vlc_a52_header_Parse( vlc_a52_header_t *p_header,
AOUT_CHANS_4_0,
AOUT_CHANS_5_0,
};
+ static const unsigned pi_fscod_samplerates[] = {
+ 48000, 44100, 32000
+ };
if( i_buffer < VLC_A52_HEADER_SIZE )
return VLC_EGENERIC;
@@ -197,20 +258,14 @@ static inline int vlc_a52_header_Parse( vlc_a52_header_t *p_header,
/* Check bsid */
const int bsid = p_buffer[5] >> 3;
- if( bsid > 16 )
- return VLC_EGENERIC;
- if( bsid <= 10 )
- {
- if( vlc_a52_header_ParseAc3( p_header, p_buffer, p_acmod ) )
- return VLC_EGENERIC;
- }
+ /* cf. Annex E 2.3.1.6 of AC3 spec */
+ if( bsid > 10 && bsid <= 16 )
+ return vlc_a52_header_ParseEac3( p_header, p_buffer,
+ p_acmod, pi_fscod_samplerates );
else
- {
- if( vlc_a52_header_ParseEac3( p_header, p_buffer, p_acmod ) )
- return VLC_EGENERIC;
- }
- return VLC_SUCCESS;
+ return vlc_a52_header_ParseAc3( p_header, p_buffer,
+ p_acmod, pi_fscod_samplerates );
}
#endif
--
2.9.3
More information about the vlc-devel
mailing list