lpcm.c 26.9 KB
Newer Older
1
/*****************************************************************************
gbazin's avatar
   
gbazin committed
2
 * lpcm.c: lpcm decoder/packetizer module
3
 *****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
4
 * Copyright (C) 1999-2008 the VideoLAN team
zorglub's avatar
zorglub committed
5
 * $Id$
6
7
8
 *
 * Authors: Samuel Hocevar <sam@zoy.org>
 *          Henri Fallon <henri@videolan.org>
9
 *          Christophe Massiot <massiot@via.ecp.fr>
10
 *          Gildas Bazin <gbazin@videolan.org>
11
 *          Lauren Aimar <fenrir _AT_ videolan _DOT_ org >
12
13
14
15
16
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
17
 *
18
19
20
21
22
23
24
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26
27
28
29
30
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
31
32
33
34
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

35
#include <vlc_common.h>
36
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
37
38
#include <vlc_codec.h>
#include <vlc_aout.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
39
#include <assert.h>
40

Laurent Aimar's avatar
Laurent Aimar committed
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  OpenDecoder   ( vlc_object_t * );
static int  OpenPacketizer( vlc_object_t * );
static void CloseCommon   ( vlc_object_t * );

vlc_module_begin ()

    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_ACODEC )
    set_description( N_("Linear PCM audio decoder") )
    set_capability( "decoder", 100 )
    set_callbacks( OpenDecoder, CloseCommon )

    add_submodule ()
    set_description( N_("Linear PCM audio packetizer") )
    set_capability( "packetizer", 100 )
    set_callbacks( OpenPacketizer, CloseCommon )

vlc_module_end ()


64
/*****************************************************************************
gbazin's avatar
   
gbazin committed
65
 * decoder_sys_t : lpcm decoder descriptor
66
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
67
struct decoder_sys_t
68
{
gbazin's avatar
   
gbazin committed
69
    /* Module mode */
70
    bool b_packetizer;
71
72
73
74

    /*
     * Output properties
     */
75
    date_t   end_date;
gbazin's avatar
   
gbazin committed
76

Laurent Aimar's avatar
Laurent Aimar committed
77
    /* */
78
    unsigned i_header_size;
79
    int      i_type;
gbazin's avatar
   
gbazin committed
80
};
81

82
/*
Laurent Aimar's avatar
Laurent Aimar committed
83
 * LPCM DVD header :
84
85
86
87
88
89
90
91
92
 * - frame number (8 bits)
 * - unknown (16 bits) == 0x0003 ?
 * - unknown (4 bits)
 * - current frame (4 bits)
 * - unknown (2 bits)
 * - frequency (2 bits) 0 == 48 kHz, 1 == 32 kHz, 2 == ?, 3 == ?
 * - unknown (1 bit)
 * - number of channels - 1 (3 bits) 1 == 2 channels
 * - start code (8 bits) == 0x80
93
 *
94
95
96
97
98
99
100
101
102
103
104
105
 * LPCM DVD-A header (http://dvd-audio.sourceforge.net/spec/aob.shtml)
 * - continuity counter (8 bits, clipped to 0x00-0x1f)
 * - header size (16 bits)
 * - byte pointer to start of first audio frame.
 * - unknown (8bits, 0x10 for stereo, 0x00 for surround)
 * - sample size (4+4 bits)
 * - samplerate (4+4 bits)
 * - unknown (8 bits)
 * - group assignment (8 bits)
 * - unknown (8 bits)
 * - padding(variable)
 *
106
107
108
109
110
111
 * LPCM BD header :
 * - unkown (16 bits)
 * - number of channels (4 bits)
 * - frequency (4 bits)
 * - bits per sample (2 bits)
 * - unknown (6 bits)
112
113
 */

114
115
#define LPCM_VOB_HEADER_LEN (6)
#define LPCM_AOB_HEADER_LEN (11)
116
#define LPCM_BD_HEADER_LEN (4)
117

118
119
120
121
122
123
124
125
126
127
128
129
130
131
enum
{
    LPCM_VOB,
    LPCM_AOB,
    LPCM_BD,
};

typedef struct
{
    unsigned i_channels;
    bool     b_used;
    unsigned pi_position[6];
} aob_group_t;

132
133
134
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
135
static void *DecodeFrame  ( decoder_t *, block_t ** );
136
137
138

/* */
static int VobHeader( unsigned *pi_rate,
139
140
141
                      unsigned *pi_channels, unsigned *pi_original_channels,
                      unsigned *pi_bits,
                      const uint8_t *p_header );
142
143
144
145
146
147
148
149
150
151
static void VobExtract( aout_buffer_t *, block_t *, unsigned i_bits );
/* */
static int AobHeader( unsigned *pi_rate,
                      unsigned *pi_channels, unsigned *pi_layout,
                      unsigned *pi_bits,
                      unsigned *pi_padding,
                      aob_group_t g[2],
                      const uint8_t *p_header );
static void AobExtract( aout_buffer_t *, block_t *, unsigned i_bits, aob_group_t p_group[2] );
/* */
152
153
154
155
156
157
static int BdHeader( unsigned *pi_rate,
                     unsigned *pi_channels, unsigned *pi_original_channels,
                     unsigned *pi_bits,
                     const uint8_t *p_header );
static void BdExtract( aout_buffer_t *, block_t * );

158
159

/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
160
 * OpenCommon:
161
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
162
static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
163
{
gbazin's avatar
   
gbazin committed
164
    decoder_t *p_dec = (decoder_t*)p_this;
gbazin's avatar
   
gbazin committed
165
    decoder_sys_t *p_sys;
166
167
    int i_type;
    int i_header_size;
168

Laurent Aimar's avatar
Laurent Aimar committed
169
    switch( p_dec->fmt_in.i_codec )
170
    {
171
    /* DVD LPCM */
172
    case VLC_CODEC_DVD_LPCM:
173
174
175
176
177
178
179
        i_type = LPCM_VOB;
        i_header_size = LPCM_VOB_HEADER_LEN;
        break;
    /* DVD-Audio LPCM */
    case VLC_CODEC_DVDA_LPCM:
        i_type = LPCM_AOB;
        i_header_size = LPCM_AOB_HEADER_LEN;
180
181
        break;
    /* BD LPCM */
182
    case VLC_CODEC_BD_LPCM:
183
184
        i_type = LPCM_BD;
        i_header_size = LPCM_BD_HEADER_LEN;
Laurent Aimar's avatar
Laurent Aimar committed
185
186
        break;
    default:
187
188
189
        return VLC_EGENERIC;
    }

gbazin's avatar
   
gbazin committed
190
    /* Allocate the memory needed to store the decoder's structure */
Laurent Aimar's avatar
Laurent Aimar committed
191
    if( ( p_dec->p_sys = p_sys = malloc(sizeof(decoder_sys_t)) ) == NULL )
192
        return VLC_ENOMEM;
193

gbazin's avatar
   
gbazin committed
194
    /* Misc init */
Laurent Aimar's avatar
Laurent Aimar committed
195
    p_sys->b_packetizer = b_packetizer;
196
    date_Set( &p_sys->end_date, 0 );
197
198
    p_sys->i_type = i_type;
    p_sys->i_header_size = i_header_size;
199

gbazin's avatar
   
gbazin committed
200
201
    /* Set output properties */
    p_dec->fmt_out.i_cat = AUDIO_ES;
202

Laurent Aimar's avatar
Laurent Aimar committed
203
    if( b_packetizer )
204
    {
205
206
207
208
209
210
211
212
213
214
215
216
217
218
        switch( i_type )
        {
        case LPCM_VOB:
            p_dec->fmt_out.i_codec = VLC_CODEC_DVD_LPCM;
            break;
        case LPCM_AOB:
            p_dec->fmt_out.i_codec = VLC_CODEC_DVDA_LPCM;
            break;
        default:
            assert(0);
        case LPCM_BD:
            p_dec->fmt_out.i_codec = VLC_CODEC_BD_LPCM;
            break;
        }
219
220
221
    }
    else
    {
Laurent Aimar's avatar
Laurent Aimar committed
222
223
224
225
        switch( p_dec->fmt_out.audio.i_bitspersample )
        {
        case 24:
        case 20:
226
            p_dec->fmt_out.i_codec = VLC_CODEC_S24B;
227
            p_dec->fmt_out.audio.i_bitspersample = 24;
Laurent Aimar's avatar
Laurent Aimar committed
228
229
            break;
        default:
230
            p_dec->fmt_out.i_codec = VLC_CODEC_S16B;
Laurent Aimar's avatar
Laurent Aimar committed
231
232
233
            p_dec->fmt_out.audio.i_bitspersample = 16;
            break;
        }
234
    }
235

gbazin's avatar
   
gbazin committed
236
237
238
239
240
    /* Set callback */
    p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))
        DecodeFrame;
    p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
        DecodeFrame;
241

gbazin's avatar
   
gbazin committed
242
243
    return VLC_SUCCESS;
}
Laurent Aimar's avatar
Laurent Aimar committed
244
245
246
247
static int OpenDecoder( vlc_object_t *p_this )
{
    return OpenCommon( p_this, false );
}
gbazin's avatar
   
gbazin committed
248
249
static int OpenPacketizer( vlc_object_t *p_this )
{
Laurent Aimar's avatar
Laurent Aimar committed
250
    return OpenCommon( p_this, true );
251
252
253
}

/*****************************************************************************
gbazin's avatar
   
gbazin committed
254
255
256
 * DecodeFrame: decodes an lpcm frame.
 ****************************************************************************
 * Beware, this function must be fed with complete frames (PES packet).
257
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
258
static void *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
259
{
gbazin's avatar
   
gbazin committed
260
261
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t       *p_block;
262
263
    unsigned int  i_rate = 0, i_original_channels = 0, i_channels = 0, i_bits = 0;
    int           i_frame_length;
264

gbazin's avatar
   
gbazin committed
265
266
267
268
269
270
271
    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
    *pp_block = NULL; /* So the packet doesn't get re-sent */

    /* Date management */
    if( p_block->i_pts > 0 &&
272
        p_block->i_pts != date_Get( &p_sys->end_date ) )
273
    {
274
        date_Set( &p_sys->end_date, p_block->i_pts );
275
    }
276

277
    if( !date_Get( &p_sys->end_date ) )
278
    {
gbazin's avatar
   
gbazin committed
279
280
281
        /* We've just started the stream, wait for the first PTS. */
        block_Release( p_block );
        return NULL;
282
    }
283

Laurent Aimar's avatar
Laurent Aimar committed
284
    if( p_block->i_buffer <= p_sys->i_header_size )
285
    {
gbazin's avatar
   
gbazin committed
286
287
288
        msg_Err(p_dec, "frame is too short");
        block_Release( p_block );
        return NULL;
289
290
    }

291
    int i_ret;
292
    unsigned i_padding = 0;
293
294
295
296
297
    aob_group_t p_aob_group[2];
    switch( p_sys->i_type )
    {
    case LPCM_VOB:
        i_ret = VobHeader( &i_rate, &i_channels, &i_original_channels, &i_bits,
298
                           p_block->p_buffer );
299
300
301
302
303
304
305
        break;
    case LPCM_AOB:
        i_ret = AobHeader( &i_rate, &i_channels, &i_original_channels, &i_bits, &i_padding,
                           p_aob_group,
                           p_block->p_buffer );
        break;
    case LPCM_BD:
306
307
        i_ret = BdHeader( &i_rate, &i_channels, &i_original_channels, &i_bits,
                          p_block->p_buffer );
308
        break;
309
310
    default:
        assert(0);
311
    }
312

313
    if( i_ret || p_block->i_buffer <= p_sys->i_header_size + i_padding )
314
    {
315
        msg_Warn( p_dec, "no frame sync or too small frame" );
316
317
318
319
320
321
322
        block_Release( p_block );
        return NULL;
    }

    /* Set output properties */
    if( p_dec->fmt_out.audio.i_rate != i_rate )
    {
323
324
        date_Init( &p_sys->end_date, i_rate, 1 );
        date_Set( &p_sys->end_date, p_block->i_pts );
325
326
327
328
329
330
    }
    p_dec->fmt_out.audio.i_rate = i_rate;
    p_dec->fmt_out.audio.i_channels = i_channels;
    p_dec->fmt_out.audio.i_original_channels = i_original_channels;
    p_dec->fmt_out.audio.i_physical_channels = i_original_channels & AOUT_CHAN_PHYSMASK;

331
    i_frame_length = (p_block->i_buffer - p_sys->i_header_size - i_padding) / i_channels * 8 / i_bits;
332
333
334

    if( p_sys->b_packetizer )
    {
335
        p_block->i_pts = p_block->i_dts = date_Get( &p_sys->end_date );
336
        p_block->i_length =
337
            date_Increment( &p_sys->end_date, i_frame_length ) -
338
339
340
341
342
343
344
345
346
347
            p_block->i_pts;

        /* Just pass on the incoming frame */
        return p_block;
    }
    else
    {
        /* */
        if( i_bits == 16 )
        {
348
            p_dec->fmt_out.i_codec = VLC_CODEC_S16B;
349
350
351
352
            p_dec->fmt_out.audio.i_bitspersample = 16;
        }
        else
        {
353
            p_dec->fmt_out.i_codec = VLC_CODEC_S24B;
354
355
356
357
358
359
360
361
362
            p_dec->fmt_out.audio.i_bitspersample = 24;
        }

        /* */
        aout_buffer_t *p_aout_buffer;
        p_aout_buffer = decoder_NewAudioBuffer( p_dec, i_frame_length );
        if( !p_aout_buffer )
            return NULL;

363
        p_aout_buffer->start_date = date_Get( &p_sys->end_date );
364
        p_aout_buffer->end_date =
365
            date_Increment( &p_sys->end_date, i_frame_length );
366

367
368
        p_block->p_buffer += p_sys->i_header_size + i_padding;
        p_block->i_buffer -= p_sys->i_header_size + i_padding;
369

370
371
372
373
374
375
376
377
378
379
380
        switch( p_sys->i_type )
        {
        case LPCM_VOB:
            VobExtract( p_aout_buffer, p_block, i_bits );
            break;
        case LPCM_AOB:
            AobExtract( p_aout_buffer, p_block, i_bits, p_aob_group );
            break;
        default:
            assert(0);
        case LPCM_BD:
381
            BdExtract( p_aout_buffer, p_block );
382
383
            break;
        }
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401

        block_Release( p_block );
        return p_aout_buffer;
    }
}

/*****************************************************************************
 * CloseCommon : lpcm decoder destruction
 *****************************************************************************/
static void CloseCommon( vlc_object_t *p_this )
{
    decoder_t *p_dec = (decoder_t*)p_this;
    free( p_dec->p_sys );
}

/*****************************************************************************
 *
 *****************************************************************************/
402
static int VobHeader( unsigned *pi_rate,
403
404
405
406
407
408
409
                      unsigned *pi_channels, unsigned *pi_original_channels,
                      unsigned *pi_bits,
                      const uint8_t *p_header )
{
    const uint8_t i_header = p_header[4];

    switch( (i_header >> 4) & 0x3 )
410
    {
411
    case 0:
412
        *pi_rate = 48000;
413
414
        break;
    case 1:
415
        *pi_rate = 96000;
416
417
        break;
    case 2:
418
        *pi_rate = 44100;
419
420
        break;
    case 3:
421
        *pi_rate = 32000;
422
        break;
423
    }
424

425
426
    *pi_channels = (i_header & 0x7) + 1;
    switch( *pi_channels - 1 )
427
428
    {
    case 0:
429
        *pi_original_channels = AOUT_CHAN_CENTER;
430
431
        break;
    case 1:
432
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
433
434
435
        break;
    case 2:
        /* This is unsure. */
436
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_LFE;
437
438
        break;
    case 3:
439
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
440
                               | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
441
442
443
        break;
    case 4:
        /* This is unsure. */
444
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
445
446
                               | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
                               | AOUT_CHAN_LFE;
447
448
        break;
    case 5:
449
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
450
451
452
453
                               | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
                               | AOUT_CHAN_CENTER | AOUT_CHAN_LFE;
        break;
    case 6:
454
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
455
456
457
458
                               | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
                               | AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT
                               | AOUT_CHAN_MIDDLERIGHT;
        break;
459
    case 7:
460
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
461
462
463
464
                               | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
                               | AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT
                               | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE;
        break;
465
466
    }

467
    switch( (i_header >> 6) & 0x3 )
468
469
    {
    case 2:
470
        *pi_bits = 24;
471
472
        break;
    case 1:
473
        *pi_bits = 20;
474
475
476
        break;
    case 0:
    default:
477
        *pi_bits = 16;
478
479
480
        break;
    }

481
    /* Check frame sync and drop it. */
482
483
484
485
    if( p_header[5] != 0x80 )
        return -1;
    return 0;
}
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599

static const unsigned p_aob_group1[21][6] = {
    { AOUT_CHAN_CENTER, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,   0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,   0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,   0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,   0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,   0 },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0  },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0  },
    { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0  },
};
static const unsigned p_aob_group2[21][6] = {
    { 0 },
    { 0 },
    { AOUT_CHAN_REARCENTER, 0 },
    { AOUT_CHAN_REARLEFT,   AOUT_CHAN_REARRIGHT,    0 },
    { AOUT_CHAN_LFE,        0 },
    { AOUT_CHAN_LFE,        AOUT_CHAN_REARCENTER,   0 },
    { AOUT_CHAN_LFE,        AOUT_CHAN_REARLEFT,     AOUT_CHAN_REARRIGHT,    0 },
    { AOUT_CHAN_CENTER,     0 },
    { AOUT_CHAN_CENTER,     AOUT_CHAN_REARCENTER, 0 },
    { AOUT_CHAN_CENTER,     AOUT_CHAN_REARLEFT,   AOUT_CHAN_REARRIGHT,    0 },
    { AOUT_CHAN_CENTER,     AOUT_CHAN_LFE,        0 },
    { AOUT_CHAN_CENTER,     AOUT_CHAN_LFE,        AOUT_CHAN_REARCENTER,   0 },
    { AOUT_CHAN_CENTER,     AOUT_CHAN_LFE,        AOUT_CHAN_REARLEFT,     AOUT_CHAN_REARRIGHT,    0 },
    { AOUT_CHAN_REARCENTER, 0 },
    { AOUT_CHAN_REARLEFT,   AOUT_CHAN_REARRIGHT,    0 },
    { AOUT_CHAN_LFE,        0 },
    { AOUT_CHAN_LFE,        AOUT_CHAN_REARCENTER,   0 },
    { AOUT_CHAN_LFE,        AOUT_CHAN_REARLEFT,     AOUT_CHAN_REARRIGHT,    0 },
    { AOUT_CHAN_LFE,        0 },
    { AOUT_CHAN_CENTER,     0 },
    { AOUT_CHAN_CENTER,     AOUT_CHAN_LFE,          0 },
};

static int AobHeader( unsigned *pi_rate,
                      unsigned *pi_channels, unsigned *pi_layout,
                      unsigned *pi_bits,
                      unsigned *pi_padding,
                      aob_group_t g[2],
                      const uint8_t *p_header )
{
    const unsigned i_header_size = GetWBE( &p_header[1] );
    if( i_header_size + 3 < LPCM_AOB_HEADER_LEN )
        return VLC_EGENERIC;

    *pi_padding = 3+i_header_size - LPCM_AOB_HEADER_LEN;

    const int i_index_size_g1 = (p_header[6] >> 4) & 0x0f;
    const int i_index_size_g2 = (p_header[6]     ) & 0x0f;
    const int i_index_rate_g1 = (p_header[7] >> 4) & 0x0f;
    const int i_index_rate_g2 = (p_header[7]     ) & 0x0f;
    const int i_assignment     = p_header[9];

    /* Validate */
    if( i_index_size_g1 > 0x02 ||
        ( i_index_size_g2 != 0x0f && i_index_size_g2 > 0x02 ) )
        return VLC_EGENERIC;
    if( (i_index_rate_g1 & 0x07) > 0x02 ||
        ( i_index_rate_g2 != 0x0f && (i_index_rate_g1 & 0x07) > 0x02 ) )
        return VLC_EGENERIC;
    if( i_assignment > 20 )
        return VLC_EGENERIC;

    /* */
    *pi_bits = 16 + 4 * i_index_size_g1;
    if( i_index_rate_g1 & 0x08 )
        *pi_rate = 44100 << (i_index_rate_g1 & 0x07);
    else
        *pi_rate = 48000 << (i_index_rate_g1 & 0x07);


    /* Group1 */
    unsigned i_channels1 = 0;
    unsigned i_layout1 = 0;
    for( int i = 0; p_aob_group1[i_assignment][i] != 0; i++ )
    {
        i_channels1++;
        i_layout1 |= p_aob_group1[i_assignment][i];
    }
    /* Group2 */
    unsigned i_channels2 = 0;
    unsigned i_layout2 = 0;
    if( i_index_size_g2 != 0x0f && i_index_rate_g2 != 0x0f )
    {
        for( int i = 0; p_aob_group2[i_assignment][i] != 0; i++ )
        {
            i_channels2++;
            i_layout2 |= p_aob_group2[i_assignment][i];
        }
        assert( (i_layout1 & i_layout2) == 0 );
    }
    /* It is enabled only when presents and compatible wih group1 */
    const bool b_group2_used = i_index_size_g1 == i_index_size_g2 &&
                               i_index_rate_g1 == i_index_rate_g2;

    /* */
    *pi_channels = i_channels1 + ( b_group2_used ? i_channels2 : 0 );
    *pi_layout   = i_layout1   | ( b_group2_used ? i_layout2   : 0 );

    /* */
600
    for( unsigned i = 0; i < 2; i++ )
601
602
603
604
605
606
607
608
609
    {
        const unsigned *p_aob = i == 0 ? p_aob_group1[i_assignment] :
                                         p_aob_group2[i_assignment];
        g[i].i_channels = i == 0 ? i_channels1 :
                                   i_channels2;

        g[i].b_used = i == 0 || b_group2_used;
        if( !g[i].b_used )
            continue;
610
        for( unsigned j = 0; j < g[i].i_channels; j++ )
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
        {
            g[i].pi_position[j] = 0;
            for( int k = 0; pi_vlc_chan_order_wg4[k] != 0; k++ )
            {
                const unsigned i_channel = pi_vlc_chan_order_wg4[k];
                if( i_channel == p_aob[j] )
                    break;
                if( (*pi_layout) & i_channel )
                    g[i].pi_position[j]++;
            }
        }
    }
    return VLC_SUCCESS;
}

626
627
628
629
630
631
632
static int BdHeader( unsigned *pi_rate,
                     unsigned *pi_channels, unsigned *pi_original_channels,
                     unsigned *pi_bits,
                     const uint8_t *p_header )
{
    const uint32_t h = GetDWBE( p_header );
    switch( ( h & 0xf000) >> 12 )
633
    {
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
    case 1:
        *pi_channels = 1;
        *pi_original_channels = AOUT_CHAN_CENTER;
        break;
    case 3:
        *pi_channels = 2;
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
        break;
    case 4:
        *pi_channels = 3;
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER;
        break;
    case 5:
        *pi_channels = 3;
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER;
        break;
    case 6:
        *pi_channels = 4;
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
                                AOUT_CHAN_REARCENTER;
        break;
    case 7:
        *pi_channels = 4;
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
                                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
        break;
    case 8:
        *pi_channels = 5;
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
                                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
        break;
    case 9:
        *pi_channels = 6;
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
                                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
                                AOUT_CHAN_LFE;
        break;
    case 10:
        *pi_channels = 7;
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
                                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
                                AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT;
        break;
    case 11:
        *pi_channels = 8;
        *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
                                AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
                                AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
                                AOUT_CHAN_LFE;
        break;
684

685
686
    default:
        return -1;
687
    }
688
    switch( (h >> 6) & 0x03 )
689
    {
690
691
692
693
694
695
696
697
698
    case 1:
        *pi_bits = 16;
        break;
    case 2: /* 20 bits but samples are stored on 24 bits */
    case 3: /* 24 bits */
        *pi_bits = 24;
        break;
    default:
        return -1;
699
    }
700
    switch( (h >> 8) & 0x0f ) 
701
    {
702
703
704
705
706
707
708
709
710
711
712
713
714
715
    case 1:
        *pi_rate = 48000;
        break;
    case 4:
        *pi_rate = 96000;
        break;
    case 5:
        *pi_rate = 192000;
        break;
    default:
        return -1;
    }
    return 0;
}
gbazin's avatar
   
gbazin committed
716

717
static void VobExtract( aout_buffer_t *p_aout_buffer, block_t *p_block,
718
719
720
                        unsigned i_bits )
{
    uint8_t *p_out = p_aout_buffer->p_buffer;
721

722
723
724
725
    /* 20/24 bits LPCM use special packing */
    if( i_bits == 24 )
    {
        while( p_block->i_buffer / 12 )
726
        {
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
            /* Sample 1 */
            p_out[0] = p_block->p_buffer[0];
            p_out[1] = p_block->p_buffer[1];
            p_out[2] = p_block->p_buffer[8];
            /* Sample 2 */
            p_out[3] = p_block->p_buffer[2];
            p_out[4] = p_block->p_buffer[3];
            p_out[5] = p_block->p_buffer[9];
            /* Sample 3 */
            p_out[6] = p_block->p_buffer[4];
            p_out[7] = p_block->p_buffer[5];
            p_out[8] = p_block->p_buffer[10];
            /* Sample 4 */
            p_out[9] = p_block->p_buffer[6];
            p_out[10] = p_block->p_buffer[7];
            p_out[11] = p_block->p_buffer[11];

            p_block->i_buffer -= 12;
            p_block->p_buffer += 12;
            p_out += 12;
747
        }
748
749
750
751
    }
    else if( i_bits == 20 )
    {
        while( p_block->i_buffer / 10 )
752
        {
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
            /* Sample 1 */
            p_out[0] = p_block->p_buffer[0];
            p_out[1] = p_block->p_buffer[1];
            p_out[2] = p_block->p_buffer[8] & 0xF0;
            /* Sample 2 */
            p_out[3] = p_block->p_buffer[2];
            p_out[4] = p_block->p_buffer[3];
            p_out[5] = p_block->p_buffer[8] << 4;
            /* Sample 3 */
            p_out[6] = p_block->p_buffer[4];
            p_out[7] = p_block->p_buffer[5];
            p_out[8] = p_block->p_buffer[9] & 0xF0;
            /* Sample 4 */
            p_out[9] = p_block->p_buffer[6];
            p_out[10] = p_block->p_buffer[7];
            p_out[11] = p_block->p_buffer[9] << 4;

            p_block->i_buffer -= 10;
            p_block->p_buffer += 10;
            p_out += 12;
773
        }
774
775
776
777
778
    }
    else
    {
        assert( i_bits == 16 );
        memcpy( p_out, p_block->p_buffer, p_block->i_buffer );
779
    }
780
}
781
782
783
784
785
786
787
788
789
790
791
792
static void AobExtract( aout_buffer_t *p_aout_buffer,
                        block_t *p_block, unsigned i_bits, aob_group_t p_group[2] )
{
    const unsigned i_channels = p_group[0].i_channels +
                                ( p_group[1].b_used ? p_group[1].i_channels : 0 );
    uint8_t *p_out = p_aout_buffer->p_buffer;

    while( p_block->i_buffer > 0 )
    {
        for( int i = 0; i < 2; i++ )
        {
            const aob_group_t *g = &p_group[1-i];
793
            const unsigned int i_group_size = 2 * g->i_channels * i_bits / 8;
794
795
796
797
798
799

            if( p_block->i_buffer < i_group_size )
            {
                p_block->i_buffer = 0;
                break;
            }
800
            for( unsigned n = 0; n < 2; n++ )
801
            {
802
                for( unsigned j = 0; j < g->i_channels && g->b_used; j++ )
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
                {
                    const int i_src = n * g->i_channels + j;
                    const int i_dst = n * i_channels + g->pi_position[j];

                    if( i_bits == 24 )
                    {
                        p_out[3*i_dst+0] = p_block->p_buffer[2*i_src+0];
                        p_out[3*i_dst+1] = p_block->p_buffer[2*i_src+1];
                        p_out[3*i_dst+2] = p_block->p_buffer[4*g->i_channels+i_src];
                    }
                    else if( i_bits == 20 )
                    {
                        p_out[3*i_dst+0] = p_block->p_buffer[2*i_src+0];
                        p_out[3*i_dst+1] = p_block->p_buffer[2*i_src+1];
                        if( n == 0 )
                            p_out[3*i_dst+2] = (p_block->p_buffer[4*g->i_channels+i_src]     ) & 0xf0;
                        else
                            p_out[3*i_dst+2] = (p_block->p_buffer[4*g->i_channels+i_src] << 4) & 0xf0;
                    }
                    else
                    {
                        assert( i_bits == 16 );
                        p_out[2*i_dst+0] = p_block->p_buffer[2*i_src+0];
                        p_out[2*i_dst+1] = p_block->p_buffer[2*i_src+1];
                    }
                }
            }

            p_block->i_buffer -= i_group_size;
            p_block->p_buffer += i_group_size;
        }
        /* */
        p_out += (i_bits == 16 ? 2 : 3) * i_channels * 2;

    }
}
839
static void BdExtract( aout_buffer_t *p_aout_buffer, block_t *p_block )
840
{
841
    memcpy( p_aout_buffer->p_buffer, p_block->p_buffer, p_block->i_buffer );
842
}
Laurent Aimar's avatar
Laurent Aimar committed
843