You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

444 lines
14 KiB

/*****************************************************************************
* dts_header.c: parse DTS audio headers info
*****************************************************************************
* Copyright (C) 2004-2009 VLC authors and VideoLAN
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
* Laurent Aimar
*
* 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
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_bits.h>
#include <vlc_aout.h>
#include "dts_header.h"
#include <assert.h>
static void BufLeToBe( uint8_t *p_out, const uint8_t *p_in, int i_in )
{
int i;
for( i = 0; i < i_in/2; i++ )
{
p_out[i*2] = p_in[i*2+1];
p_out[i*2+1] = p_in[i*2];
}
}
static int Buf14To16( uint8_t *p_out, const uint8_t *p_in, int i_in, int i_le,
int i_out_le )
{
unsigned char tmp, cur = 0;
int bits_in, bits_out = 0;
int i, i_out = 0;
for( i = 0; i < i_in; i++ )
{
if( i%2 )
{
tmp = p_in[i-i_le];
bits_in = 8;
}
else
{
tmp = p_in[i+i_le] & 0x3F;
bits_in = 8 - 2;
}
if( bits_out < 8 )
{
int need = __MIN( 8 - bits_out, bits_in );
cur <<= need;
cur |= ( tmp >> (bits_in - need) );
tmp <<= (8 - bits_in + need);
tmp >>= (8 - bits_in + need);
bits_in -= need;
bits_out += need;
}
if( bits_out == 8 )
{
if( i_out % 2 )
p_out[i_out - i_out_le] = cur;
else
p_out[i_out + i_out_le] = cur;
cur = 0;
bits_out = 0;
i_out++;
}
bits_out += bits_in;
cur <<= bits_in;
cur |= tmp;
}
return i_out;
}
static enum vlc_dts_syncword_e dts_header_getSyncword( const uint8_t *p_buf )
{
if( memcmp( p_buf, "\x7F\xFE\x80\x01", 4 ) == 0 )
return DTS_SYNC_CORE_BE;
else
if( memcmp( p_buf, "\xFE\x7F\x01\x80", 4 ) == 0 )
return DTS_SYNC_CORE_LE;
else
if( memcmp( p_buf, "\x64\x58\x20\x25", 4 ) == 0 )
return DTS_SYNC_SUBSTREAM;
else
if( memcmp( p_buf, "\x1F\xFF\xE8\x00", 4 ) == 0
&& p_buf[4] == 0x07 && (p_buf[5] & 0xf0) == 0xf0 )
return DTS_SYNC_CORE_14BITS_BE;
else
if( memcmp( p_buf, "\xFF\x1F\x00\xE8", 4 ) == 0
&& (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;
}
bool vlc_dts_header_IsSync( const void *p_buf, size_t i_buf )
{
return i_buf >= 6
&& dts_header_getSyncword( p_buf ) != DTS_SYNC_NONE;
}
static unsigned int dca_get_samplerate( uint8_t i_sfreq )
{
/* See ETSI TS 102 114, table 5-5 */
const unsigned int p_dca_samplerates[16] = {
0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0,
12000, 24000, 48000, 96000, 192000
};
if( i_sfreq >= 16 )
return 0;
return p_dca_samplerates[i_sfreq];
}
static unsigned int dca_get_bitrate( uint8_t i_rate )
{
/* See ETSI TS 102 114, table 5-7 */
const unsigned int p_dca_bitrates[32] = {
32000, 56000, 64000, 96000, 112000,
128000, 192000, 224000, 256000, 320000,
384000, 448000, 512000, 576000, 640000,
768000, 896000, 1024000, 1152000, 1280000,
1344000, 1408000, 1411200, 1472000, 1536000,
1920000, 2048000, 3072000, 3840000,
/* FIXME: The following can't be put in a VLC audio_format_t:
* 1: open, 2: variable, 3: lossless */
0, 0, 0
};
if( i_rate >= 32 )
return 0;
return p_dca_bitrates[i_rate];
}
static uint16_t dca_get_channels( uint8_t i_amode, bool b_lfe,
uint16_t *p_chan_mode )
{
/* See ETSI TS 102 114, table 5-4
* 00: A
* 01: A + B (dual mono)
* 02: L + R (stereo)
* 03: (L+R) + (L-R) (sum and difference)
* 04: LT + RT (left and right total)
* 05: C + L + R
* 06: L + R + S
* 07: C + L + R + S
* 08: L + R + SL + SR
* 09: C + L + R + SL + SR
* 0A: CL + CR + L + R + SL + SR
* 0B: C + L + R + LR + RR + OV
* 0C: CF + CR + LF + RF + LR + RR
* 0D: CL + C + CR + L + R + SL + SR
* 0E: CL + CR + L + R + SL1 + SL2 + SR1 + SR2
* 0F: CL + C + CR + L + R + SL + S + SR
* 10-3F: user defined */
uint16_t i_physical_channels;
switch( i_amode )
{
case 0x0:
i_physical_channels = AOUT_CHAN_CENTER;
break;
case 0x1:
i_physical_channels = AOUT_CHANS_FRONT;
*p_chan_mode = AOUT_CHANMODE_DUALMONO;
break;
case 0x2:
case 0x3:
case 0x4:
i_physical_channels = AOUT_CHANS_FRONT;
break;
case 0x5:
i_physical_channels = AOUT_CHANS_3_0;
break;
case 0x6:
i_physical_channels = AOUT_CHANS_FRONT | AOUT_CHAN_REARCENTER;
break;
case 0x7:
i_physical_channels = AOUT_CHANS_4_CENTER_REAR;
break;
case 0x8:
i_physical_channels = AOUT_CHANS_4_0;
break;
case 0x9:
i_physical_channels = AOUT_CHANS_5_0;
break;
case 0xA:
case 0xB:
i_physical_channels = AOUT_CHANS_6_0;
break;
case 0xC:
i_physical_channels = AOUT_CHANS_CENTER | AOUT_CHANS_FRONT
| AOUT_CHANS_REAR;
break;
case 0xD:
i_physical_channels = AOUT_CHANS_7_0;
break;
case 0xE:
case 0xF:
/* FIXME: AOUT_CHANS_8_0 */
i_physical_channels = AOUT_CHANS_7_0;
break;
default:
return 0;
}
if (b_lfe)
i_physical_channels |= AOUT_CHAN_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 )
{
bs_t s;
bs_init( &s, p_buffer, VLC_DTS_HEADER_SIZE );
bs_skip( &s, 32 /*SYNCEXTSSH*/ + 8 /*UserDefinedBits*/ + 2 /*nExtSSIndex*/ );
uint8_t bHeaderSizeType = bs_read1( &s );
uint32_t nuBits4ExSSFsize;
uint16_t nuExtSSHeaderSize;
if( bHeaderSizeType == 0 )
{
nuExtSSHeaderSize = bs_read( &s, 8 /*nuBits4Header*/ );
nuBits4ExSSFsize = bs_read( &s, 16 );
}
else
{
nuExtSSHeaderSize = bs_read( &s, 12 /*nuBits4Header*/ );
nuBits4ExSSFsize = bs_read( &s, 20 );
}
memset( p_header, 0, sizeof(*p_header) );
p_header->syncword = DTS_SYNC_SUBSTREAM;
p_header->i_substream_header_size = nuExtSSHeaderSize + 1;
p_header->i_frame_size = nuBits4ExSSFsize + 1;
return VLC_SUCCESS;
}
static int dts_header_ParseLBRExtSubstream( vlc_dts_header_t *p_header,
const void *p_buffer )
{
bs_t s;
bs_init( &s, p_buffer, VLC_DTS_HEADER_SIZE );
bs_skip( &s, 32 /*SYNCEXTSSH*/ );
uint8_t ucFmtInfoCode = bs_read( &s, 8 );
if( ucFmtInfoCode != 0x02 /*LBR_HDRCODE_DECODERINIT*/ )
return VLC_EGENERIC;
p_header->i_rate = bs_read( &s, 8 );
/* See ETSI TS 102 114, table 9-3 */
const unsigned int LBRsamplerates[] = {
8000, 16000, 32000,
0, 0,
22050, 44100,
0, 0, 0,
12000, 24000, 48000,
};
if(p_header->i_rate >= ARRAY_SIZE(LBRsamplerates))
return VLC_EGENERIC;
p_header->i_rate = LBRsamplerates[p_header->i_rate];
if( p_header->i_rate < 16000 )
p_header->i_frame_length = 1024;
else if( p_header->i_rate < 32000 )
p_header->i_frame_length = 2048;
else
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 );
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);
p_header->i_frame_size = 0;
return VLC_SUCCESS;
}
static int dts_header_ParseCore( vlc_dts_header_t *p_header,
const void *p_buffer)
{
bs_t s;
bs_init( &s, p_buffer, VLC_DTS_HEADER_SIZE );
bs_skip( &s, 32 /*SYNC*/ + 1 /*FTYPE*/ + 5 /*SHORT*/ + 1 /*CPF*/ );
uint8_t i_nblks = bs_read( &s, 7 );
if( i_nblks < 5 )
return VLC_EGENERIC;
uint16_t i_fsize = bs_read( &s, 14 );
if( i_fsize < 95 )
return VLC_EGENERIC;
uint8_t i_amode = bs_read( &s, 6 );
uint8_t i_sfreq = bs_read( &s, 4 );
uint8_t i_rate = bs_read( &s, 5 );
bs_skip( &s, 1 /*FixedBit*/ + 1 /*DYNF*/ + 1 /*TIMEF*/ + 1 /*AUXF*/ +
1 /*HDCD*/ + 3 /*EXT_AUDIO_ID*/ + 1 /*EXT_AUDIO */ + 1 /*ASPF*/ );
uint8_t i_lff = bs_read( &s, 2 );
bool b_lfe = i_lff == 1 || i_lff == 2;
p_header->i_rate = dca_get_samplerate( i_sfreq );
p_header->i_bitrate = dca_get_bitrate( i_rate );
p_header->i_frame_size = i_fsize + 1;
if( p_header->syncword == DTS_SYNC_CORE_14BITS_LE ||
p_header->syncword == DTS_SYNC_CORE_14BITS_BE )
p_header->i_frame_size = p_header->i_frame_size * 16 / 14;
/* See ETSI TS 102 114, table 5-2 */
p_header->i_frame_length = (i_nblks + 1) * 32;
p_header->i_chan_mode = 0;
p_header->i_physical_channels =
dca_get_channels( i_amode, b_lfe, &p_header->i_chan_mode );
if( !p_header->i_rate || !p_header->i_frame_size ||
!p_header->i_frame_length || !p_header->i_physical_channels )
return VLC_EGENERIC;
return VLC_SUCCESS;
}
ssize_t vlc_dts_header_Convert14b16b( void *p_dst, size_t i_dst,
const void *p_src, size_t i_src,
bool b_out_le )
{
size_t i_size = i_src * 14 / 16;
if( i_src <= VLC_DTS_HEADER_SIZE || i_size > i_dst )
return -1;
enum vlc_dts_syncword_e syncword = dts_header_getSyncword( p_src );
if( syncword == DTS_SYNC_NONE )
return -1;
if( syncword != DTS_SYNC_CORE_14BITS_BE
&& syncword != DTS_SYNC_CORE_14BITS_LE )
return -1;
int i_ret = Buf14To16( p_dst, p_src, i_src,
syncword == DTS_SYNC_CORE_14BITS_LE, b_out_le );
return i_ret;
}
int vlc_dts_header_Parse( vlc_dts_header_t *p_header,
const void *p_buffer, size_t i_buffer)
{
if( i_buffer < VLC_DTS_HEADER_SIZE )
return VLC_EGENERIC;
p_header->syncword = dts_header_getSyncword( p_buffer );
if( p_header->syncword == DTS_SYNC_NONE )
return VLC_EGENERIC;
switch( p_header->syncword )
{
case DTS_SYNC_CORE_LE:
{
uint8_t conv_buf[VLC_DTS_HEADER_SIZE];
BufLeToBe( conv_buf, p_buffer, VLC_DTS_HEADER_SIZE );
return dts_header_ParseCore( p_header, conv_buf );
}
case DTS_SYNC_CORE_BE:
return dts_header_ParseCore( p_header, p_buffer );
case DTS_SYNC_CORE_14BITS_BE:
case DTS_SYNC_CORE_14BITS_LE:
{
uint8_t conv_buf[VLC_DTS_HEADER_SIZE];
Buf14To16( conv_buf, p_buffer, VLC_DTS_HEADER_SIZE,
p_header->syncword == DTS_SYNC_CORE_14BITS_LE, 0 );
return dts_header_ParseCore( p_header, conv_buf );
}
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();
}
}