Coverage Report

Created: 2026-09-01 07:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/packetizer/mlp.c
Line
Count
Source
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
170
vlc_module_begin ()
47
85
    set_subcategory( SUBCAT_SOUT_PACKETIZER )
48
85
    set_description( N_("MLP/TrueHD parser") )
49
85
    set_capability( "audio packetizer", 50 )
50
170
    set_callbacks( Open, Close )
51
85
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
    enum vlc_packetizer_state 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
38.8M
#define MLP_MAX_SUBSTREAMS (16)
94
39.7M
#define MLP_HEADER_SYNC (28)
95
38.8M
#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
830k
{
106
830k
    static const uint8_t pu_thd[13] =
107
830k
    {
108
830k
         2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1
109
830k
    };
110
830k
    int i_count = 0;
111
112
11.6M
    for( int i = 0; i < 13; i++ )
113
10.8M
    {
114
10.8M
        if( i_map & (1<<i) )
115
6.11M
            i_count += pu_thd[i];
116
10.8M
    }
117
830k
    return i_count;
118
830k
}
119
120
static int MlpParse( mlp_header_t *p_mlp, const uint8_t p_hdr[MLP_HEADER_SYNC] )
121
886k
{
122
886k
    bs_t s;
123
124
886k
    assert( !memcmp( p_hdr, pu_start_code, 3 ) );
125
126
    /* TODO Checksum ? */
127
128
    /* */
129
886k
    bs_init( &s, &p_hdr[3], MLP_HEADER_SYNC - 3 );
130
131
    /* Stream type */
132
886k
    p_mlp->i_type = bs_read( &s, 8 );
133
886k
    int i_rate_idx1;
134
135
886k
    if( p_mlp->i_type == 0xbb )        /* MLP */
136
34.6k
    {
137
34.6k
        static const unsigned pu_channels[32] = {
138
34.6k
            1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4,
139
34.6k
            5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
140
34.6k
        };
141
142
34.6k
        bs_skip( &s, 4 + 4 );
143
144
34.6k
        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
34.6k
        bs_skip( &s, 4 );
149
150
34.6k
        bs_skip( &s, 11 );
151
152
34.6k
        const int i_channel_idx = bs_read( &s, 5 );
153
34.6k
        p_mlp->i_channels = pu_channels[i_channel_idx];
154
34.6k
    }
155
851k
    else if( p_mlp->i_type == 0xba )   /* True HD */
156
830k
    {
157
830k
        i_rate_idx1 = bs_read( &s, 4 );
158
159
830k
        bs_skip( &s, 8 );
160
161
830k
        const int i_channel1 = bs_read( &s, 5 );
162
163
830k
        bs_skip( &s, 2 );
164
165
830k
        const int i_channel2 = bs_read( &s, 13 );
166
830k
        if( i_channel2 )
167
751k
            p_mlp->i_channels = TrueHdChannels( i_channel2 );
168
79.3k
        else
169
79.3k
            p_mlp->i_channels = TrueHdChannels( i_channel1 );
170
830k
    }
171
20.7k
    else
172
20.7k
    {
173
20.7k
        return VLC_EGENERIC;
174
20.7k
    }
175
176
865k
    if( i_rate_idx1 == 0x0f )
177
729k
        p_mlp->i_rate = 0;
178
136k
    else
179
136k
        p_mlp->i_rate = ( ( i_rate_idx1 & 0x8 ) ? 44100 : 48000 ) << (i_rate_idx1 & 0x7);
180
865k
    p_mlp->i_channels_conf = 0; /* TODO ? */
181
182
865k
    p_mlp->i_samples = 40 << ( i_rate_idx1 & 0x07 );
183
184
865k
    bs_skip( &s, 48 );
185
186
865k
    p_mlp->b_vbr = bs_read( &s, 1 );
187
865k
    p_mlp->i_bitrate = ( bs_read( &s, 15 ) * p_mlp->i_rate + 8) / 16;
188
189
865k
    p_mlp->i_substreams = bs_read( &s, 4 );
190
865k
    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
865k
    return VLC_SUCCESS;
195
886k
}
196
197
static int SyncInfo( const uint8_t *p_hdr, bool *pb_mlp, mlp_header_t *p_mlp )
198
19.5M
{
199
    /* Check major sync presence */
200
19.5M
    const bool b_has_sync = !memcmp( &p_hdr[4], pu_start_code, 3 );
201
202
    /* Wait for a major sync */
203
19.5M
    if( !b_has_sync && !*pb_mlp )
204
16.1M
        return 0;
205
206
    /* Parse major sync if present */
207
3.36M
    if( b_has_sync )
208
886k
    {
209
886k
        *pb_mlp = !MlpParse( p_mlp, &p_hdr[4] );
210
211
886k
        if( !*pb_mlp )
212
20.7k
            return 0;
213
886k
    }
214
215
3.34M
    if( !b_has_sync )
216
2.47M
    {
217
2.47M
        int i_tmp = 0 ^ p_hdr[0] ^ p_hdr[1] ^ p_hdr[2] ^ p_hdr[3];
218
2.47M
        const uint8_t *p = &p_hdr[4];
219
220
4.28M
        for( unsigned i = 0; i < p_mlp->i_substreams; i++ )
221
1.80M
        {
222
1.80M
            i_tmp ^= *p++;
223
1.80M
            i_tmp ^= *p++;
224
1.80M
            if( p[-2] & 0x80 )
225
486k
            {
226
486k
                i_tmp ^= *p++;
227
486k
                i_tmp ^= *p++;
228
486k
            }
229
1.80M
        }
230
2.47M
        i_tmp = ( i_tmp >> 4 ) ^ i_tmp;
231
232
2.47M
        if( ( i_tmp & 0x0f ) != 0x0f )
233
1.75M
            return 0;
234
2.47M
    }
235
236
    /* */
237
1.59M
    const int i_word = ( ( p_hdr[0] << 8 ) | p_hdr[1] ) & 0xfff;
238
1.59M
    return i_word * 2;
239
3.34M
}
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
19.0M
{
246
19.0M
    vlc_a52_header_t a52;
247
19.0M
    if( vlc_a52_header_Parse( &a52, p_buf, MLP_HEADER_SIZE ) == VLC_SUCCESS )
248
71.0k
        return a52.i_size;
249
18.9M
    else
250
18.9M
        return 0;
251
19.0M
}
252
253
static void Flush( decoder_t *p_dec )
254
5.81k
{
255
5.81k
    decoder_sys_t *p_sys = p_dec->p_sys;
256
257
5.81k
    p_sys->b_mlp = false;
258
5.81k
    p_sys->i_state = STATE_NOSYNC;
259
5.81k
    p_sys->b_discontinuity = true;
260
5.81k
    block_BytestreamEmpty( &p_sys->bytestream );
261
5.81k
    date_Set( &p_sys->end_date, VLC_TICK_INVALID );
262
5.81k
}
263
264
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
265
574k
{
266
574k
    decoder_sys_t *p_sys = p_dec->p_sys;
267
574k
    uint8_t p_header[MLP_HEADER_SIZE];
268
574k
    block_t *p_out_buffer;
269
270
574k
    block_t *p_block = pp_block ? *pp_block : NULL;
271
272
574k
    if ( p_block )
273
564k
    {
274
564k
        if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
275
7.42k
        {
276
            /* First always drain complete blocks before discontinuity */
277
7.42k
            block_t *p_drain = Packetize( p_dec, NULL );
278
7.42k
            if( p_drain )
279
1.60k
                return p_drain;
280
281
5.81k
            Flush( p_dec );
282
283
5.81k
            if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
284
0
            {
285
0
                block_Release( p_block );
286
0
                return NULL;
287
0
            }
288
5.81k
        }
289
290
562k
        if( p_block->i_pts == VLC_TICK_INVALID &&
291
185k
            date_Get( &p_sys->end_date ) == VLC_TICK_INVALID )
292
10.4k
        {
293
            /* We've just started the stream, wait for the first PTS. */
294
10.4k
            msg_Dbg( p_dec, "waiting for PTS" );
295
10.4k
            block_Release( p_block );
296
10.4k
            return NULL;
297
10.4k
        }
298
299
552k
        block_BytestreamPush( &p_sys->bytestream, p_block );
300
552k
    }
301
302
562k
    for( ;; )
303
1.16M
    {
304
1.16M
        switch( p_sys->i_state )
305
1.16M
        {
306
644k
        case STATE_NOSYNC:
307
18.4M
            while( !block_PeekBytes( &p_sys->bytestream, p_header, MLP_HEADER_SIZE ) )
308
18.3M
            {
309
18.3M
                if( SyncInfo( p_header, &p_sys->b_mlp, &p_sys->mlp ) > 0 )
310
562k
                {
311
562k
                    p_sys->i_state = STATE_SYNC;
312
562k
                    break;
313
562k
                }
314
17.8M
                else if( SyncInfoDolby( p_header ) > 0 )
315
33.2k
                {
316
33.2k
                    p_sys->i_state = STATE_SYNC;
317
33.2k
                    break;
318
33.2k
                }
319
17.7M
                (void) block_SkipByte( &p_sys->bytestream );
320
17.7M
            }
321
644k
            if( p_sys->i_state != STATE_SYNC )
322
48.6k
            {
323
48.6k
                block_BytestreamFlush( &p_sys->bytestream );
324
325
                /* Need more data */
326
48.6k
                return NULL;
327
48.6k
            }
328
            /* fallthrough */
329
330
595k
        case STATE_SYNC:
331
            /* New frame, set the Presentation Time Stamp */
332
595k
            p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
333
595k
            if( p_sys->i_pts != VLC_TICK_INVALID &&
334
170k
                p_sys->i_pts != date_Get( &p_sys->end_date ) )
335
25.5k
            {
336
25.5k
                date_Set( &p_sys->end_date, p_sys->i_pts );
337
25.5k
            }
338
595k
            p_sys->i_state = STATE_HEADER;
339
            /* fallthrough */
340
341
595k
        case STATE_HEADER:
342
            /* Get a MLP header */
343
595k
            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
595k
            p_sys->i_frame_size = SyncInfoDolby( p_header );
351
595k
            if( p_sys->i_frame_size <= 0 )
352
562k
                p_sys->i_frame_size = SyncInfo( p_header, &p_sys->b_mlp, &p_sys->mlp );
353
595k
            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
595k
            p_sys->i_state = STATE_NEXT_SYNC;
362
            /* fallthrough */
363
364
784k
        case STATE_NEXT_SYNC:
365
            /* Check if next expected frame contains the sync word */
366
784k
            if( block_PeekOffsetBytes( &p_sys->bytestream,
367
784k
                                       p_sys->i_frame_size, p_header, MLP_HEADER_SIZE ) )
368
192k
            {
369
192k
                if( p_block == NULL ) /* drain */
370
3.47k
                {
371
3.47k
                    p_sys->i_state = STATE_GET_DATA;
372
3.47k
                    break;
373
3.47k
                }
374
                /* Need more data */
375
189k
                return NULL;
376
192k
            }
377
378
784k
            bool b_mlp = p_sys->b_mlp;
379
592k
            mlp_header_t mlp = p_sys->mlp;
380
592k
            if( SyncInfo( p_header, &b_mlp, &mlp ) <= 0 && SyncInfoDolby( p_header ) <= 0 )
381
268k
            {
382
268k
                msg_Dbg( p_dec, "emulated sync word "
383
268k
                         "(no sync on following frame)" );
384
268k
                p_sys->b_mlp = false;
385
268k
                p_sys->i_state = STATE_NOSYNC;
386
268k
                block_SkipByte( &p_sys->bytestream );
387
268k
                break;
388
268k
            }
389
323k
            p_sys->i_state = STATE_GET_DATA;
390
323k
            break;
391
392
327k
        case STATE_GET_DATA:
393
            /* Make sure we have enough data. */
394
327k
            if( block_WaitBytes( &p_sys->bytestream, p_sys->i_frame_size ) )
395
1.40k
            {
396
                /* Need more data */
397
1.40k
                return NULL;
398
1.40k
            }
399
325k
            p_sys->i_state = STATE_SEND_DATA;
400
            /* fallthrough */
401
402
325k
        case STATE_SEND_DATA:
403
            /* When we reach this point we already know we have enough
404
             * data available. */
405
325k
            p_out_buffer = block_Alloc( p_sys->i_frame_size );
406
325k
            if( !p_out_buffer )
407
0
                return NULL;
408
409
            /* Copy the whole frame into the buffer */
410
325k
            block_GetBytes( &p_sys->bytestream,
411
325k
                            p_out_buffer->p_buffer, p_out_buffer->i_buffer );
412
413
            /* Just ignore (E)AC3 frames */
414
325k
            if( SyncInfoDolby( p_out_buffer->p_buffer ) > 0 )
415
2.18k
            {
416
2.18k
                block_Release( p_out_buffer );
417
2.18k
                p_sys->i_state = STATE_NOSYNC;
418
2.18k
                break;
419
2.18k
            }
420
421
            /* Setup output */
422
323k
            if( p_dec->fmt_out.audio.i_rate != p_sys->mlp.i_rate )
423
15.7k
            {
424
15.7k
                msg_Info( p_dec, "MLP channels: %d samplerate: %d",
425
15.7k
                          p_sys->mlp.i_channels, p_sys->mlp.i_rate );
426
427
15.7k
                if( p_sys->mlp.i_rate > 0 )
428
9.51k
                    date_Change( &p_sys->end_date, p_sys->mlp.i_rate, 1 );
429
15.7k
            }
430
431
323k
            p_dec->fmt_out.audio.i_rate     = p_sys->mlp.i_rate;
432
323k
            p_dec->fmt_out.audio.i_channels = p_sys->mlp.i_channels;
433
323k
            p_dec->fmt_out.audio.i_physical_channels = p_sys->mlp.i_channels_conf;
434
323k
            p_dec->fmt_out.audio.i_bytes_per_frame = p_sys->i_frame_size;
435
323k
            p_dec->fmt_out.audio.i_frame_length = p_sys->mlp.i_samples;
436
437
323k
            p_out_buffer->i_pts = p_out_buffer->i_dts = date_Get( &p_sys->end_date );
438
323k
            p_out_buffer->i_nb_samples = p_sys->mlp.i_samples;
439
440
323k
            p_out_buffer->i_length =
441
323k
                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
323k
            if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
445
322k
                p_sys->i_pts = p_sys->bytestream.p_block->i_pts = VLC_TICK_INVALID;
446
447
323k
            if( p_sys->b_discontinuity )
448
2.79k
            {
449
2.79k
                p_out_buffer->i_flags |= BLOCK_FLAG_DISCONTINUITY;
450
2.79k
                p_sys->b_discontinuity = false;
451
2.79k
            }
452
453
            /* So p_block doesn't get re-added several times */
454
323k
            if( pp_block )
455
321k
                *pp_block = block_BytestreamPop( &p_sys->bytestream );
456
457
323k
            p_sys->i_state = STATE_NOSYNC;
458
459
323k
            return p_out_buffer;
460
461
0
        case STATE_CUSTOM_FIRST:
462
0
            break; // do nothing
463
1.16M
        }
464
1.16M
    }
465
466
0
    return NULL;
467
562k
}
468
469
static int Open( vlc_object_t *p_this )
470
192k
{
471
192k
    decoder_t *p_dec = (decoder_t*)p_this;
472
192k
    decoder_sys_t *p_sys;
473
474
192k
    if( p_dec->fmt_in->i_codec != VLC_CODEC_MLP &&
475
192k
        p_dec->fmt_in->i_codec != VLC_CODEC_TRUEHD )
476
189k
        return VLC_EGENERIC;
477
478
    /* */
479
2.98k
    p_dec->p_sys = p_sys = malloc( sizeof(*p_sys) );
480
2.98k
    if( !p_sys )
481
0
        return VLC_ENOMEM;
482
483
    /* */
484
2.98k
    p_sys->i_state = STATE_NOSYNC;
485
2.98k
    date_Init( &p_sys->end_date, 1, 1 );
486
487
2.98k
    block_BytestreamInit( &p_sys->bytestream );
488
2.98k
    p_sys->b_mlp = false;
489
2.98k
    p_sys->b_discontinuity = false;
490
491
    /* Set output properties (Passthrough only) */
492
2.98k
    p_dec->fmt_out.i_codec = p_dec->fmt_in->i_codec;
493
2.98k
    p_dec->fmt_out.audio.i_rate = 0;
494
495
    /* Set callback */
496
2.98k
    p_dec->pf_packetize = Packetize;
497
2.98k
    p_dec->pf_flush     = Flush;
498
2.98k
    p_dec->pf_get_cc    = NULL;
499
2.98k
    return VLC_SUCCESS;
500
2.98k
}
501
502
static void Close( vlc_object_t *p_this )
503
2.98k
{
504
2.98k
    decoder_t *p_dec = (decoder_t*)p_this;
505
2.98k
    decoder_sys_t *p_sys = p_dec->p_sys;
506
507
2.98k
    block_BytestreamRelease( &p_sys->bytestream );
508
509
2.98k
    free( p_sys );
510
2.98k
}