Coverage Report

Created: 2026-03-31 07:49

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