Coverage Report

Created: 2025-08-25 06:17

/src/vlc/modules/packetizer/dts_header.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * dts_header.c: parse DTS audio headers info
3
 *****************************************************************************
4
 * Copyright (C) 2004-2009 VLC authors and VideoLAN
5
 *
6
 * Authors: Gildas Bazin <gbazin@netcourrier.com>
7
 *          Laurent Aimar
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program; if not, write to the Free Software Foundation,
21
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23
24
#ifdef HAVE_CONFIG_H
25
# include "config.h"
26
#endif
27
28
#include <vlc_common.h>
29
#include <vlc_bits.h>
30
#include <vlc_aout.h>
31
32
#include "dts_header.h"
33
34
#include <assert.h>
35
36
static void BufLeToBe( uint8_t *p_out, const uint8_t *p_in, int i_in )
37
0
{
38
0
    int i;
39
40
0
    for( i = 0; i < i_in/2; i++  )
41
0
    {
42
0
        p_out[i*2] = p_in[i*2+1];
43
0
        p_out[i*2+1] = p_in[i*2];
44
0
    }
45
0
}
46
47
static int Buf14To16( uint8_t *p_out, const uint8_t *p_in, int i_in, int i_le,
48
                      int i_out_le )
49
0
{
50
0
    unsigned char tmp, cur = 0;
51
0
    int bits_in, bits_out = 0;
52
0
    int i, i_out = 0;
53
54
0
    for( i = 0; i < i_in; i++  )
55
0
    {
56
0
        if( i%2 )
57
0
        {
58
0
            tmp = p_in[i-i_le];
59
0
            bits_in = 8;
60
0
        }
61
0
        else
62
0
        {
63
0
            tmp = p_in[i+i_le] & 0x3F;
64
0
            bits_in = 8 - 2;
65
0
        }
66
67
0
        if( bits_out < 8 )
68
0
        {
69
0
            int need = __MIN( 8 - bits_out, bits_in );
70
0
            cur <<= need;
71
0
            cur |= ( tmp >> (bits_in - need) );
72
0
            tmp <<= (8 - bits_in + need);
73
0
            tmp >>= (8 - bits_in + need);
74
0
            bits_in -= need;
75
0
            bits_out += need;
76
0
        }
77
78
0
        if( bits_out == 8 )
79
0
        {
80
0
            if( i_out % 2 )
81
0
                p_out[i_out - i_out_le] = cur;
82
0
            else
83
0
                p_out[i_out + i_out_le] = cur;
84
0
            cur = 0;
85
0
            bits_out = 0;
86
0
            i_out++;
87
0
        }
88
89
0
        bits_out += bits_in;
90
0
        cur <<= bits_in;
91
0
        cur |= tmp;
92
0
    }
93
94
0
    return i_out;
95
0
}
96
97
static enum vlc_dts_syncword_e dts_header_getSyncword( const uint8_t *p_buf )
98
0
{
99
0
    if( memcmp( p_buf, "\x7F\xFE\x80\x01", 4 ) == 0 )
100
0
        return DTS_SYNC_CORE_BE;
101
0
    else
102
0
    if( memcmp( p_buf, "\xFE\x7F\x01\x80", 4 ) == 0 )
103
0
        return DTS_SYNC_CORE_LE;
104
0
    else
105
0
    if( memcmp( p_buf, "\x64\x58\x20\x25", 4 ) == 0 )
106
0
        return DTS_SYNC_SUBSTREAM;
107
0
    else
108
0
    if( memcmp( p_buf, "\x1F\xFF\xE8\x00", 4 ) == 0
109
0
     && p_buf[4] == 0x07 && (p_buf[5] & 0xf0) == 0xf0 )
110
0
        return DTS_SYNC_CORE_14BITS_BE;
111
0
    else
112
0
    if( memcmp( p_buf, "\xFF\x1F\x00\xE8", 4 ) == 0
113
0
     && (p_buf[4] & 0xf0) == 0xf0 && p_buf[5] == 0x07 )
114
0
        return DTS_SYNC_CORE_14BITS_LE;
115
0
    else
116
0
    if( memcmp( p_buf, "\x0A\x80\x19\x21", 4 ) == 0 )
117
0
        return DTS_SYNC_SUBSTREAM_LBR;
118
0
    else
119
0
        return DTS_SYNC_NONE;
120
0
}
121
122
bool vlc_dts_header_IsSync( const void *p_buf, size_t i_buf )
123
0
{
124
0
    return i_buf >= 6
125
0
        && dts_header_getSyncword( p_buf ) != DTS_SYNC_NONE;
126
0
}
127
128
static unsigned int dca_get_samplerate( uint8_t i_sfreq )
129
0
{
130
    /* See ETSI TS 102 114, table 5-5 */
131
0
    const unsigned int p_dca_samplerates[16] = {
132
0
        0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0,
133
0
        12000, 24000, 48000, 96000, 192000
134
0
    };
135
136
0
    if( i_sfreq >= 16 )
137
0
        return 0;
138
0
    return p_dca_samplerates[i_sfreq];
139
0
}
140
141
static unsigned int dca_get_bitrate( uint8_t i_rate )
142
0
{
143
    /* See ETSI TS 102 114, table 5-7 */
144
0
    const unsigned int p_dca_bitrates[32] = {
145
0
        32000,   56000,   64000,   96000,  112000,
146
0
        128000, 192000,  224000,  256000,  320000,
147
0
        384000, 448000,  512000,  576000,  640000,
148
0
        768000, 896000, 1024000, 1152000, 1280000,
149
0
        1344000, 1408000, 1411200, 1472000, 1536000,
150
0
        1920000, 2048000, 3072000, 3840000,
151
        /* FIXME: The following can't be put in a VLC audio_format_t:
152
         * 1: open, 2: variable, 3: lossless */
153
0
        0, 0, 0
154
0
    };
155
156
0
    if( i_rate >= 32 )
157
0
        return 0;
158
0
    return p_dca_bitrates[i_rate];
159
0
}
160
161
static uint16_t dca_get_channels( uint8_t i_amode, bool b_lfe,
162
                                  uint16_t *p_chan_mode )
163
0
{
164
    /* See ETSI TS 102 114, table 5-4
165
     * 00: A
166
     * 01: A + B (dual mono)
167
     * 02: L + R (stereo)
168
     * 03: (L+R) + (L-R) (sum and difference)
169
     * 04: LT + RT (left and right total)
170
     * 05: C + L + R
171
     * 06: L + R + S
172
     * 07: C + L + R + S
173
     * 08: L + R + SL + SR
174
     * 09: C + L + R + SL + SR
175
     * 0A: CL + CR + L + R + SL + SR
176
     * 0B: C + L + R + LR + RR + OV
177
     * 0C: CF + CR + LF + RF + LR + RR
178
     * 0D: CL + C + CR + L + R + SL + SR
179
     * 0E: CL + CR + L + R + SL1 + SL2 + SR1 + SR2
180
     * 0F: CL + C + CR + L + R + SL + S + SR
181
     * 10-3F: user defined */
182
183
0
    uint16_t i_physical_channels;
184
185
0
    switch( i_amode )
186
0
    {
187
0
        case 0x0:
188
0
            i_physical_channels = AOUT_CHAN_CENTER;
189
0
            break;
190
0
        case 0x1:
191
0
            i_physical_channels = AOUT_CHANS_FRONT;
192
0
            *p_chan_mode = AOUT_CHANMODE_DUALMONO;
193
0
            break;
194
0
        case 0x2:
195
0
        case 0x3:
196
0
        case 0x4:
197
0
            i_physical_channels = AOUT_CHANS_FRONT;
198
0
            break;
199
0
        case 0x5:
200
0
            i_physical_channels = AOUT_CHANS_3_0;
201
0
            break;
202
0
        case 0x6:
203
0
            i_physical_channels = AOUT_CHANS_FRONT | AOUT_CHAN_REARCENTER;
204
0
            break;
205
0
        case 0x7:
206
0
            i_physical_channels = AOUT_CHANS_4_CENTER_REAR;
207
0
            break;
208
0
        case 0x8:
209
0
            i_physical_channels = AOUT_CHANS_4_0;
210
0
            break;
211
0
        case 0x9:
212
0
            i_physical_channels = AOUT_CHANS_5_0;
213
0
            break;
214
0
        case 0xA:
215
0
        case 0xB:
216
0
            i_physical_channels = AOUT_CHANS_6_0;
217
0
            break;
218
0
        case 0xC:
219
0
            i_physical_channels = AOUT_CHANS_CENTER | AOUT_CHANS_FRONT
220
0
                                | AOUT_CHANS_REAR;
221
0
            break;
222
0
        case 0xD:
223
0
            i_physical_channels = AOUT_CHANS_7_0;
224
0
            break;
225
0
        case 0xE:
226
0
        case 0xF:
227
            /* FIXME: AOUT_CHANS_8_0 */
228
0
            i_physical_channels = AOUT_CHANS_7_0;
229
0
            break;
230
0
        default:
231
0
            return 0;
232
0
    }
233
0
    if (b_lfe)
234
0
        i_physical_channels |= AOUT_CHAN_LFE;
235
236
0
    return i_physical_channels;
237
0
}
238
239
static uint8_t dca_get_LBR_channels( uint16_t nuSpkrActivityMask,
240
                                     uint16_t *pi_chans )
241
0
{
242
0
    uint16_t i_physical_channels = 0;
243
0
    uint8_t i_channels = 0;
244
245
0
    static const struct
246
0
    {
247
0
        int phy;
248
0
        uint8_t nb;
249
0
    } bitmask[16] = {
250
         /* table 7-10 */
251
0
        { AOUT_CHAN_CENTER,     1 },
252
0
        { AOUT_CHANS_FRONT,     2 },
253
0
        { AOUT_CHANS_MIDDLE,    2 },
254
0
        { AOUT_CHAN_LFE,        1 },
255
0
        { AOUT_CHAN_REARCENTER, 1 },
256
0
        { 0,                    2 },
257
0
        { AOUT_CHANS_REAR,      2 },
258
0
        { 0,                    1 },
259
0
        { 0,                    1 },
260
0
        { 0,                    2 },
261
0
        { AOUT_CHANS_FRONT,     2 },
262
0
        { AOUT_CHANS_MIDDLE,    2 },
263
0
        { 0,                    1 },
264
0
        { 0,                    2 },
265
0
        { 0,                    1 },
266
0
        { 0,                    2 },
267
0
    };
268
269
0
    for( int i=0 ; nuSpkrActivityMask; nuSpkrActivityMask >>= 1 )
270
0
    {
271
0
        if( nuSpkrActivityMask & 1 )
272
0
        {
273
0
            i_physical_channels |= bitmask[i].phy;
274
0
            i_channels += bitmask[i].nb;
275
0
        }
276
0
        ++i;
277
0
    }
278
0
    *pi_chans = i_physical_channels;
279
0
    return i_channels;
280
0
}
281
282
static int dts_header_ParseSubstream( vlc_dts_header_t *p_header,
283
                                      const void *p_buffer )
284
0
{
285
0
    bs_t s;
286
0
    bs_init( &s, p_buffer, VLC_DTS_HEADER_SIZE );
287
0
    bs_skip( &s, 32 /*SYNCEXTSSH*/ + 8 /*UserDefinedBits*/ + 2 /*nExtSSIndex*/ );
288
0
    uint8_t bHeaderSizeType = bs_read1( &s );
289
0
    uint32_t nuBits4ExSSFsize;
290
0
    uint16_t nuExtSSHeaderSize;
291
0
    if( bHeaderSizeType == 0 )
292
0
    {
293
0
        nuExtSSHeaderSize = bs_read( &s, 8 /*nuBits4Header*/ );
294
0
        nuBits4ExSSFsize = bs_read( &s, 16 );
295
0
    }
296
0
    else
297
0
    {
298
0
        nuExtSSHeaderSize = bs_read( &s, 12 /*nuBits4Header*/ );
299
0
        nuBits4ExSSFsize = bs_read( &s, 20 );
300
0
    }
301
0
    memset( p_header, 0, sizeof(*p_header) );
302
0
    p_header->syncword = DTS_SYNC_SUBSTREAM;
303
0
    p_header->i_substream_header_size = nuExtSSHeaderSize + 1;
304
0
    p_header->i_frame_size = nuBits4ExSSFsize + 1;
305
0
    return VLC_SUCCESS;
306
0
}
307
308
static int dts_header_ParseLBRExtSubstream( vlc_dts_header_t *p_header,
309
                                             const void *p_buffer )
310
0
{
311
0
    bs_t s;
312
0
    bs_init( &s, p_buffer, VLC_DTS_HEADER_SIZE );
313
0
    bs_skip( &s, 32 /*SYNCEXTSSH*/ );
314
0
    uint8_t ucFmtInfoCode = bs_read( &s, 8 );
315
0
    if( ucFmtInfoCode != 0x02 /*LBR_HDRCODE_DECODERINIT*/ )
316
0
        return VLC_EGENERIC;
317
0
    p_header->i_rate = bs_read( &s, 8 );
318
    /* See ETSI TS 102 114, table 9-3 */
319
0
    const unsigned int LBRsamplerates[] = {
320
0
        8000, 16000, 32000,
321
0
        0, 0,
322
0
        22050, 44100,
323
0
        0, 0, 0,
324
0
        12000, 24000, 48000,
325
0
    };
326
0
    if(p_header->i_rate >= ARRAY_SIZE(LBRsamplerates))
327
0
        return VLC_EGENERIC;
328
0
    p_header->i_rate = LBRsamplerates[p_header->i_rate];
329
0
    if( p_header->i_rate < 16000 )
330
0
        p_header->i_frame_length = 1024;
331
0
    else if( p_header->i_rate < 32000 )
332
0
        p_header->i_frame_length = 2048;
333
0
    else
334
0
        p_header->i_frame_length = 4096;
335
336
0
    uint16_t i_spkrmask = bs_read( &s, 16 );
337
0
    dca_get_LBR_channels( i_spkrmask, &p_header->i_physical_channels );
338
0
    bs_skip( &s, 16 );
339
0
    bs_skip( &s, 8 );
340
0
    uint16_t nLBRBitRateMSnybbles = bs_read( &s, 8 );
341
0
    bs_skip( &s, 16 );
342
0
    uint16_t nLBRScaledBitRate_LSW = bs_read( &s, 16 );
343
0
    p_header->i_bitrate = nLBRScaledBitRate_LSW | ((nLBRBitRateMSnybbles & 0xF0) << 12);
344
0
    p_header->i_frame_size = 0;
345
0
    return VLC_SUCCESS;
346
0
}
347
348
static int dts_header_ParseCore( vlc_dts_header_t *p_header,
349
                                 const void *p_buffer)
350
0
{
351
0
    bs_t s;
352
0
    bs_init( &s, p_buffer, VLC_DTS_HEADER_SIZE );
353
0
    bs_skip( &s, 32 /*SYNC*/ + 1 /*FTYPE*/ + 5 /*SHORT*/ + 1 /*CPF*/ );
354
0
    uint8_t i_nblks = bs_read( &s, 7 );
355
0
    if( i_nblks < 5 )
356
0
        return VLC_EGENERIC;
357
0
    uint16_t i_fsize = bs_read( &s, 14 );
358
0
    if( i_fsize < 95 )
359
0
        return VLC_EGENERIC;
360
0
    uint8_t i_amode = bs_read( &s, 6 );
361
0
    uint8_t i_sfreq = bs_read( &s, 4 );
362
0
    uint8_t i_rate = bs_read( &s, 5 );
363
0
    bs_skip( &s, 1 /*FixedBit*/ + 1 /*DYNF*/ + 1 /*TIMEF*/ + 1 /*AUXF*/ +
364
0
             1 /*HDCD*/ + 3 /*EXT_AUDIO_ID*/ + 1 /*EXT_AUDIO */ + 1 /*ASPF*/ );
365
0
    uint8_t i_lff = bs_read( &s, 2 );
366
367
0
    bool b_lfe = i_lff == 1 || i_lff == 2;
368
369
0
    p_header->i_rate = dca_get_samplerate( i_sfreq );
370
0
    p_header->i_bitrate = dca_get_bitrate( i_rate );
371
0
    p_header->i_frame_size = i_fsize + 1;
372
0
    if( p_header->syncword == DTS_SYNC_CORE_14BITS_LE ||
373
0
        p_header->syncword == DTS_SYNC_CORE_14BITS_BE )
374
0
        p_header->i_frame_size = p_header->i_frame_size * 16 / 14;
375
    /* See ETSI TS 102 114, table 5-2 */
376
0
    p_header->i_frame_length = (i_nblks + 1) * 32;
377
0
    p_header->i_chan_mode = 0;
378
0
    p_header->i_physical_channels =
379
0
        dca_get_channels( i_amode, b_lfe, &p_header->i_chan_mode );
380
381
0
    if( !p_header->i_rate || !p_header->i_frame_size ||
382
0
        !p_header->i_frame_length || !p_header->i_physical_channels )
383
0
        return VLC_EGENERIC;
384
385
0
    return VLC_SUCCESS;
386
0
}
387
388
ssize_t vlc_dts_header_Convert14b16b( void *p_dst, size_t i_dst,
389
                                      const void *p_src, size_t i_src,
390
                                      bool b_out_le )
391
0
{
392
0
    size_t i_size = i_src * 14 / 16;
393
0
    if( i_src <= VLC_DTS_HEADER_SIZE || i_size > i_dst )
394
0
        return -1;
395
396
0
    enum vlc_dts_syncword_e syncword = dts_header_getSyncword( p_src );
397
0
    if( syncword == DTS_SYNC_NONE )
398
0
        return -1;
399
400
0
    if( syncword != DTS_SYNC_CORE_14BITS_BE
401
0
     && syncword != DTS_SYNC_CORE_14BITS_LE )
402
0
        return -1;
403
404
0
    int i_ret = Buf14To16( p_dst, p_src, i_src,
405
0
                           syncword == DTS_SYNC_CORE_14BITS_LE, b_out_le );
406
0
    return i_ret;
407
0
}
408
409
int vlc_dts_header_Parse( vlc_dts_header_t *p_header,
410
                          const void *p_buffer, size_t i_buffer)
411
0
{
412
0
    if( i_buffer < VLC_DTS_HEADER_SIZE )
413
0
        return VLC_EGENERIC;
414
415
0
    p_header->syncword = dts_header_getSyncword( p_buffer );
416
0
    if( p_header->syncword == DTS_SYNC_NONE )
417
0
        return VLC_EGENERIC;
418
419
0
    switch( p_header->syncword )
420
0
    {
421
0
        case DTS_SYNC_CORE_LE:
422
0
        {
423
0
            uint8_t conv_buf[VLC_DTS_HEADER_SIZE];
424
0
            BufLeToBe( conv_buf, p_buffer, VLC_DTS_HEADER_SIZE );
425
0
            return dts_header_ParseCore( p_header, conv_buf );
426
0
        }
427
0
        case DTS_SYNC_CORE_BE:
428
0
            return dts_header_ParseCore( p_header, p_buffer );
429
0
        case DTS_SYNC_CORE_14BITS_BE:
430
0
        case DTS_SYNC_CORE_14BITS_LE:
431
0
        {
432
0
            uint8_t conv_buf[VLC_DTS_HEADER_SIZE];
433
0
            Buf14To16( conv_buf, p_buffer, VLC_DTS_HEADER_SIZE,
434
0
                       p_header->syncword == DTS_SYNC_CORE_14BITS_LE, 0 );
435
0
            return dts_header_ParseCore( p_header, conv_buf );
436
0
        }
437
0
        case DTS_SYNC_SUBSTREAM:
438
0
            return dts_header_ParseSubstream( p_header, p_buffer );
439
0
        case DTS_SYNC_SUBSTREAM_LBR:
440
0
            return dts_header_ParseLBRExtSubstream( p_header, p_buffer );
441
0
        default:
442
0
            vlc_assert_unreachable();
443
0
    }
444
0
}