Coverage Report

Created: 2025-08-29 07:30

/src/vlc/modules/packetizer/mlp.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * mlp.c: packetize MLP/TrueHD audio
3
 *****************************************************************************
4
 * Copyright (C) 2008 Laurent Aimar
5
 *
6
 * Authors: Laurent Aimar < fenrir _AT videolan _DOT_ org >
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program; if not, write to the Free Software Foundation,
20
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21
 *****************************************************************************/
22
23
/*****************************************************************************
24
 * Preamble
25
 *****************************************************************************/
26
#ifdef HAVE_CONFIG_H
27
# include "config.h"
28
#endif
29
30
#include <vlc_common.h>
31
#include <vlc_plugin.h>
32
#include <vlc_codec.h>
33
#include <vlc_block_helper.h>
34
#include <vlc_bits.h>
35
#include <assert.h>
36
37
#include "packetizer_helper.h"
38
#include "a52.h"
39
40
/*****************************************************************************
41
 * Module descriptor
42
 *****************************************************************************/
43
static int  Open ( vlc_object_t * );
44
static void Close( vlc_object_t * );
45
46
104
vlc_module_begin ()
47
52
    set_subcategory( SUBCAT_SOUT_PACKETIZER )
48
52
    set_description( N_("MLP/TrueHD parser") )
49
52
    set_capability( "audio packetizer", 50 )
50
104
    set_callbacks( Open, Close )
51
52
vlc_module_end ()
52
53
/*****************************************************************************
54
 *
55
 *****************************************************************************/
56
typedef struct
57
{
58
    int i_type;
59
    unsigned i_rate;
60
    unsigned i_channels;
61
    int i_channels_conf;
62
    unsigned i_samples;
63
64
    bool b_vbr;
65
    unsigned  i_bitrate;
66
67
    unsigned  i_substreams;
68
69
} mlp_header_t;
70
71
typedef struct
72
{
73
    /*
74
     * Input properties
75
     */
76
    int i_state;
77
78
    block_bytestream_t bytestream;
79
80
    /*
81
     * Common properties
82
     */
83
    date_t  end_date;
84
    bool    b_discontinuity;
85
86
    vlc_tick_t i_pts;
87
    int i_frame_size;
88
89
    bool         b_mlp;
90
    mlp_header_t mlp;
91
} decoder_sys_t;
92
93
33.2M
#define MLP_MAX_SUBSTREAMS (16)
94
33.7M
#define MLP_HEADER_SYNC (28)
95
33.2M
#define MLP_HEADER_SIZE (4 + MLP_HEADER_SYNC + 4 * MLP_MAX_SUBSTREAMS)
96
97
static const uint8_t pu_start_code[3] = { 0xf8, 0x72, 0x6f };
98
99
/**
100
 * It parse MLP sync info.
101
 *
102
 * TODO handle CRC (at offset 26)
103
 */
104
static int TrueHdChannels( int i_map )
105
440k
{
106
440k
    static const uint8_t pu_thd[13] =
107
440k
    {
108
440k
         2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1
109
440k
    };
110
440k
    int i_count = 0;
111
112
6.16M
    for( int i = 0; i < 13; i++ )
113
5.72M
    {
114
5.72M
        if( i_map & (1<<i) )
115
2.60M
            i_count += pu_thd[i];
116
5.72M
    }
117
440k
    return i_count;
118
440k
}
119
120
static int MlpParse( mlp_header_t *p_mlp, const uint8_t p_hdr[MLP_HEADER_SYNC] )
121
502k
{
122
502k
    bs_t s;
123
124
502k
    assert( !memcmp( p_hdr, pu_start_code, 3 ) );
125
126
    /* TODO Checksum ? */
127
128
    /* */
129
502k
    bs_init( &s, &p_hdr[3], MLP_HEADER_SYNC - 3 );
130
131
    /* Stream type */
132
502k
    p_mlp->i_type = bs_read( &s, 8 );
133
502k
    int i_rate_idx1;
134
135
502k
    if( p_mlp->i_type == 0xbb )        /* MLP */
136
57.1k
    {
137
57.1k
        static const unsigned pu_channels[32] = {
138
57.1k
            1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4,
139
57.1k
            5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
140
57.1k
        };
141
142
57.1k
        bs_skip( &s, 4 + 4 );
143
144
57.1k
        i_rate_idx1 = bs_read( &s, 4 );
145
146
        // Just skip the 4 following, since we don't use it
147
        // const int i_rate_idx2 = bs_read( &s, 4 );
148
57.1k
        bs_skip( &s, 4 );
149
150
57.1k
        bs_skip( &s, 11 );
151
152
57.1k
        const int i_channel_idx = bs_read( &s, 5 );
153
57.1k
        p_mlp->i_channels = pu_channels[i_channel_idx];
154
57.1k
    }
155
445k
    else if( p_mlp->i_type == 0xba )   /* True HD */
156
440k
    {
157
440k
        i_rate_idx1 = bs_read( &s, 4 );
158
159
440k
        bs_skip( &s, 8 );
160
161
440k
        const int i_channel1 = bs_read( &s, 5 );
162
163
440k
        bs_skip( &s, 2 );
164
165
440k
        const int i_channel2 = bs_read( &s, 13 );
166
440k
        if( i_channel2 )
167
330k
            p_mlp->i_channels = TrueHdChannels( i_channel2 );
168
109k
        else
169
109k
            p_mlp->i_channels = TrueHdChannels( i_channel1 );
170
440k
    }
171
4.81k
    else
172
4.81k
    {
173
4.81k
        return VLC_EGENERIC;
174
4.81k
    }
175
176
497k
    if( i_rate_idx1 == 0x0f )
177
299k
        p_mlp->i_rate = 0;
178
198k
    else
179
198k
        p_mlp->i_rate = ( ( i_rate_idx1 & 0x8 ) ? 44100 : 48000 ) << (i_rate_idx1 & 0x7);
180
497k
    p_mlp->i_channels_conf = 0; /* TODO ? */
181
182
497k
    p_mlp->i_samples = 40 << ( i_rate_idx1 & 0x07 );
183
184
497k
    bs_skip( &s, 48 );
185
186
497k
    p_mlp->b_vbr = bs_read( &s, 1 );
187
497k
    p_mlp->i_bitrate = ( bs_read( &s, 15 ) * p_mlp->i_rate + 8) / 16;
188
189
497k
    p_mlp->i_substreams = bs_read( &s, 4 );
190
497k
    bs_skip( &s, 4 + 11 * 8 );
191
192
    //fprintf( stderr, "i_samples = %d channels:%d rate:%d bitsrate=%d substreams=%d\n",
193
    //        p_mlp->i_samples, p_mlp->i_channels, p_mlp->i_rate, p_mlp->i_bitrate, p_mlp->i_substreams );
194
497k
    return VLC_SUCCESS;
195
502k
}
196
197
static int SyncInfo( const uint8_t *p_hdr, bool *pb_mlp, mlp_header_t *p_mlp )
198
16.7M
{
199
    /* Check major sync presence */
200
16.7M
    const bool b_has_sync = !memcmp( &p_hdr[4], pu_start_code, 3 );
201
202
    /* Wait for a major sync */
203
16.7M
    if( !b_has_sync && !*pb_mlp )
204
15.4M
        return 0;
205
206
    /* Parse major sync if present */
207
1.36M
    if( b_has_sync )
208
502k
    {
209
502k
        *pb_mlp = !MlpParse( p_mlp, &p_hdr[4] );
210
211
502k
        if( !*pb_mlp )
212
4.81k
            return 0;
213
502k
    }
214
215
1.35M
    if( !b_has_sync )
216
857k
    {
217
857k
        int i_tmp = 0 ^ p_hdr[0] ^ p_hdr[1] ^ p_hdr[2] ^ p_hdr[3];
218
857k
        const uint8_t *p = &p_hdr[4];
219
220
2.00M
        for( unsigned i = 0; i < p_mlp->i_substreams; i++ )
221
1.15M
        {
222
1.15M
            i_tmp ^= *p++;
223
1.15M
            i_tmp ^= *p++;
224
1.15M
            if( p[-2] & 0x80 )
225
464k
            {
226
464k
                i_tmp ^= *p++;
227
464k
                i_tmp ^= *p++;
228
464k
            }
229
1.15M
        }
230
857k
        i_tmp = ( i_tmp >> 4 ) ^ i_tmp;
231
232
857k
        if( ( i_tmp & 0x0f ) != 0x0f )
233
393k
            return 0;
234
857k
    }
235
236
    /* */
237
961k
    const int i_word = ( ( p_hdr[0] << 8 ) | p_hdr[1] ) & 0xfff;
238
961k
    return i_word * 2;
239
1.35M
}
240
241
/**
242
 * It returns the size of an AC3/EAC3 frame (or 0 if invalid)
243
 */
244
static int SyncInfoDolby( const uint8_t *p_buf )
245
16.4M
{
246
16.4M
    vlc_a52_header_t a52;
247
16.4M
    if( vlc_a52_header_Parse( &a52, p_buf, MLP_HEADER_SIZE ) == VLC_SUCCESS )
248
76.4k
        return a52.i_size;
249
16.3M
    else
250
16.3M
        return 0;
251
16.4M
}
252
253
static void Flush( decoder_t *p_dec )
254
0
{
255
0
    decoder_sys_t *p_sys = p_dec->p_sys;
256
257
0
    p_sys->b_mlp = false;
258
0
    p_sys->i_state = STATE_NOSYNC;
259
0
    p_sys->b_discontinuity = true;
260
0
    block_BytestreamEmpty( &p_sys->bytestream );
261
0
    date_Set( &p_sys->end_date, VLC_TICK_INVALID );
262
0
}
263
264
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
265
169k
{
266
169k
    decoder_sys_t *p_sys = p_dec->p_sys;
267
169k
    uint8_t p_header[MLP_HEADER_SIZE];
268
169k
    block_t *p_out_buffer;
269
270
169k
    block_t *p_block = pp_block ? *pp_block : NULL;
271
272
169k
    if ( p_block )
273
167k
    {
274
167k
        if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
275
0
        {
276
            /* First always drain complete blocks before discontinuity */
277
0
            block_t *p_drain = Packetize( p_dec, NULL );
278
0
            if( p_drain )
279
0
                return p_drain;
280
281
0
            Flush( p_dec );
282
283
0
            if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
284
0
            {
285
0
                block_Release( p_block );
286
0
                return NULL;
287
0
            }
288
0
        }
289
290
167k
        if( p_block->i_pts == VLC_TICK_INVALID &&
291
167k
            date_Get( &p_sys->end_date ) == VLC_TICK_INVALID )
292
196
        {
293
            /* We've just started the stream, wait for the first PTS. */
294
196
            msg_Dbg( p_dec, "waiting for PTS" );
295
196
            block_Release( p_block );
296
196
            return NULL;
297
196
        }
298
299
167k
        block_BytestreamPush( &p_sys->bytestream, p_block );
300
167k
    }
301
302
169k
    for( ;; )
303
594k
    {
304
594k
        switch( p_sys->i_state )
305
594k
        {
306
426k
        case STATE_NOSYNC:
307
15.9M
            while( !block_PeekBytes( &p_sys->bytestream, p_header, MLP_HEADER_SIZE ) )
308
15.9M
            {
309
15.9M
                if( SyncInfo( p_header, &p_sys->b_mlp, &p_sys->mlp ) > 0 )
310
387k
                {
311
387k
                    p_sys->i_state = STATE_SYNC;
312
387k
                    break;
313
387k
                }
314
15.6M
                else if( SyncInfoDolby( p_header ) > 0 )
315
37.4k
                {
316
37.4k
                    p_sys->i_state = STATE_SYNC;
317
37.4k
                    break;
318
37.4k
                }
319
15.5M
                block_SkipByte( &p_sys->bytestream );
320
15.5M
            }
321
426k
            if( p_sys->i_state != STATE_SYNC )
322
2.24k
            {
323
2.24k
                block_BytestreamFlush( &p_sys->bytestream );
324
325
                /* Need more data */
326
2.24k
                return NULL;
327
2.24k
            }
328
            /* fallthrough */
329
330
424k
        case STATE_SYNC:
331
            /* New frame, set the Presentation Time Stamp */
332
424k
            p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
333
424k
            if( p_sys->i_pts != VLC_TICK_INVALID &&
334
424k
                p_sys->i_pts != date_Get( &p_sys->end_date ) )
335
935
            {
336
935
                date_Set( &p_sys->end_date, p_sys->i_pts );
337
935
            }
338
424k
            p_sys->i_state = STATE_HEADER;
339
            /* fallthrough */
340
341
424k
        case STATE_HEADER:
342
            /* Get a MLP header */
343
424k
            if( block_PeekBytes( &p_sys->bytestream, p_header, MLP_HEADER_SIZE ) )
344
0
            {
345
                /* Need more data */
346
0
                return NULL;
347
0
            }
348
349
            /* Check if frame is valid and get frame info */
350
424k
            p_sys->i_frame_size = SyncInfoDolby( p_header );
351
424k
            if( p_sys->i_frame_size <= 0 )
352
387k
                p_sys->i_frame_size = SyncInfo( p_header, &p_sys->b_mlp, &p_sys->mlp );
353
424k
            if( p_sys->i_frame_size <= 0 )
354
0
            {
355
0
                msg_Dbg( p_dec, "emulated sync word" );
356
0
                block_SkipByte( &p_sys->bytestream );
357
0
                p_sys->b_mlp = false;
358
0
                p_sys->i_state = STATE_NOSYNC;
359
0
                break;
360
0
            }
361
424k
            p_sys->i_state = STATE_NEXT_SYNC;
362
            /* fallthrough */
363
364
429k
        case STATE_NEXT_SYNC:
365
            /* Check if next expected frame contains the sync word */
366
429k
            if( block_PeekOffsetBytes( &p_sys->bytestream,
367
429k
                                       p_sys->i_frame_size, p_header, MLP_HEADER_SIZE ) )
368
5.61k
            {
369
5.61k
                if( p_block == NULL ) /* drain */
370
705
                {
371
705
                    p_sys->i_state = STATE_GET_DATA;
372
705
                    break;
373
705
                }
374
                /* Need more data */
375
4.91k
                return NULL;
376
5.61k
            }
377
378
423k
            bool b_mlp = p_sys->b_mlp;
379
423k
            mlp_header_t mlp = p_sys->mlp;
380
423k
            if( SyncInfo( p_header, &b_mlp, &mlp ) <= 0 && SyncInfoDolby( p_header ) <= 0 )
381
261k
            {
382
261k
                msg_Dbg( p_dec, "emulated sync word "
383
261k
                         "(no sync on following frame)" );
384
261k
                p_sys->b_mlp = false;
385
261k
                p_sys->i_state = STATE_NOSYNC;
386
261k
                block_SkipByte( &p_sys->bytestream );
387
261k
                break;
388
261k
            }
389
161k
            p_sys->i_state = STATE_GET_DATA;
390
161k
            break;
391
392
162k
        case STATE_GET_DATA:
393
            /* Make sure we have enough data. */
394
162k
            if( block_WaitBytes( &p_sys->bytestream, p_sys->i_frame_size ) )
395
376
            {
396
                /* Need more data */
397
376
                return NULL;
398
376
            }
399
162k
            p_sys->i_state = STATE_SEND_DATA;
400
            /* fallthrough */
401
402
162k
        case STATE_SEND_DATA:
403
            /* When we reach this point we already know we have enough
404
             * data available. */
405
162k
            p_out_buffer = block_Alloc( p_sys->i_frame_size );
406
162k
            if( !p_out_buffer )
407
0
                return NULL;
408
409
            /* Copy the whole frame into the buffer */
410
162k
            block_GetBytes( &p_sys->bytestream,
411
162k
                            p_out_buffer->p_buffer, p_out_buffer->i_buffer );
412
413
            /* Just ignore (E)AC3 frames */
414
162k
            if( SyncInfoDolby( p_out_buffer->p_buffer ) > 0 )
415
457
            {
416
457
                block_Release( p_out_buffer );
417
457
                p_sys->i_state = STATE_NOSYNC;
418
457
                break;
419
457
            }
420
421
            /* Setup output */
422
161k
            if( p_dec->fmt_out.audio.i_rate != p_sys->mlp.i_rate )
423
6.95k
            {
424
6.95k
                msg_Info( p_dec, "MLP channels: %d samplerate: %d",
425
6.95k
                          p_sys->mlp.i_channels, p_sys->mlp.i_rate );
426
427
6.95k
                if( p_sys->mlp.i_rate > 0 )
428
4.27k
                    date_Change( &p_sys->end_date, p_sys->mlp.i_rate, 1 );
429
6.95k
            }
430
431
161k
            p_dec->fmt_out.audio.i_rate     = p_sys->mlp.i_rate;
432
161k
            p_dec->fmt_out.audio.i_channels = p_sys->mlp.i_channels;
433
161k
            p_dec->fmt_out.audio.i_physical_channels = p_sys->mlp.i_channels_conf;
434
161k
            p_dec->fmt_out.audio.i_bytes_per_frame = p_sys->i_frame_size;
435
161k
            p_dec->fmt_out.audio.i_frame_length = p_sys->mlp.i_samples;
436
437
161k
            p_out_buffer->i_pts = p_out_buffer->i_dts = date_Get( &p_sys->end_date );
438
161k
            p_out_buffer->i_nb_samples = p_sys->mlp.i_samples;
439
440
161k
            p_out_buffer->i_length =
441
161k
                date_Increment( &p_sys->end_date, p_sys->mlp.i_samples ) - p_out_buffer->i_pts;
442
443
            /* Make sure we don't reuse the same pts twice */
444
161k
            if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
445
161k
                p_sys->i_pts = p_sys->bytestream.p_block->i_pts = VLC_TICK_INVALID;
446
447
161k
            if( p_sys->b_discontinuity )
448
0
            {
449
0
                p_out_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
450
0
                p_sys->b_discontinuity = false;
451
0
            }
452
453
            /* So p_block doesn't get re-added several times */
454
161k
            if( pp_block )
455
161k
                *pp_block = block_BytestreamPop( &p_sys->bytestream );
456
457
161k
            p_sys->i_state = STATE_NOSYNC;
458
459
161k
            return p_out_buffer;
460
594k
        }
461
594k
    }
462
463
0
    return NULL;
464
169k
}
465
466
static int Open( vlc_object_t *p_this )
467
2.28M
{
468
2.28M
    decoder_t *p_dec = (decoder_t*)p_this;
469
2.28M
    decoder_sys_t *p_sys;
470
471
2.28M
    if( p_dec->fmt_in->i_codec != VLC_CODEC_MLP &&
472
2.28M
        p_dec->fmt_in->i_codec != VLC_CODEC_TRUEHD )
473
2.28M
        return VLC_EGENERIC;
474
475
    /* */
476
1.54k
    p_dec->p_sys = p_sys = malloc( sizeof(*p_sys) );
477
1.54k
    if( !p_sys )
478
0
        return VLC_ENOMEM;
479
480
    /* */
481
1.54k
    p_sys->i_state = STATE_NOSYNC;
482
1.54k
    date_Init( &p_sys->end_date, 1, 1 );
483
484
1.54k
    block_BytestreamInit( &p_sys->bytestream );
485
1.54k
    p_sys->b_mlp = false;
486
1.54k
    p_sys->b_discontinuity = false;
487
488
    /* Set output properties (Passthrough only) */
489
1.54k
    p_dec->fmt_out.i_codec = p_dec->fmt_in->i_codec;
490
1.54k
    p_dec->fmt_out.audio.i_rate = 0;
491
492
    /* Set callback */
493
1.54k
    p_dec->pf_packetize = Packetize;
494
1.54k
    p_dec->pf_flush     = Flush;
495
1.54k
    p_dec->pf_get_cc    = NULL;
496
1.54k
    return VLC_SUCCESS;
497
1.54k
}
498
499
static void Close( vlc_object_t *p_this )
500
1.54k
{
501
1.54k
    decoder_t *p_dec = (decoder_t*)p_this;
502
1.54k
    decoder_sys_t *p_sys = p_dec->p_sys;
503
504
1.54k
    block_BytestreamRelease( &p_sys->bytestream );
505
506
1.54k
    free( p_sys );
507
1.54k
}