]> git.sesse.net Git - vlc/blob - modules/codec/lpcm.c
Fix DVD LPCM format description in comments.
[vlc] / modules / codec / lpcm.c
1 /*****************************************************************************
2  * lpcm.c: lpcm decoder/packetizer module
3  *****************************************************************************
4  * Copyright (C) 1999-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *          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  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_codec.h>
38 #include <vlc_aout.h>
39 #include <assert.h>
40
41 /*****************************************************************************
42  * Module descriptor
43  *****************************************************************************/
44 static int  OpenDecoder   ( vlc_object_t * );
45 static int  OpenPacketizer( vlc_object_t * );
46 static void CloseCommon   ( vlc_object_t * );
47
48 vlc_module_begin ()
49
50     set_category( CAT_INPUT )
51     set_subcategory( SUBCAT_INPUT_ACODEC )
52     set_description( N_("Linear PCM audio decoder") )
53     set_capability( "decoder", 100 )
54     set_callbacks( OpenDecoder, CloseCommon )
55
56     add_submodule ()
57     set_description( N_("Linear PCM audio packetizer") )
58     set_capability( "packetizer", 100 )
59     set_callbacks( OpenPacketizer, CloseCommon )
60
61 vlc_module_end ()
62
63
64 /*****************************************************************************
65  * decoder_sys_t : lpcm decoder descriptor
66  *****************************************************************************/
67 struct decoder_sys_t
68 {
69     /* Module mode */
70     bool b_packetizer;
71
72     /*
73      * Output properties
74      */
75     date_t   end_date;
76
77     /* */
78     unsigned i_header_size;
79     int      i_type;
80 };
81
82 /*
83  * LPCM DVD header :
84  * - number of frames in this packet (8 bits)
85  * - first access unit (16 bits) == 0x0003 ?
86  * - emphasis (1 bit)
87  * - mute (1 bit)
88  * - reserved (1 bit)
89  * - current frame (5 bits)
90  * - quantisation (2 bits) 0 == 16bps, 1 == 20bps, 2 == 24bps, 3 == illegal
91  * - frequency (2 bits) 0 == 48 kHz, 1 == 96 kHz, 2 == 44.1 kHz, 3 == 32 kHz
92  * - reserved (1 bit)
93  * - number of channels - 1 (3 bits) 1 == 2 channels
94  * - dynamic range (8 bits) 0x80 == neutral
95  *
96  * LPCM DVD-A header (http://dvd-audio.sourceforge.net/spec/aob.shtml)
97  * - continuity counter (8 bits, clipped to 0x00-0x1f)
98  * - header size (16 bits)
99  * - byte pointer to start of first audio frame.
100  * - unknown (8bits, 0x10 for stereo, 0x00 for surround)
101  * - sample size (4+4 bits)
102  * - samplerate (4+4 bits)
103  * - unknown (8 bits)
104  * - group assignment (8 bits)
105  * - unknown (8 bits)
106  * - padding(variable)
107  *
108  * LPCM BD header :
109  * - unkown (16 bits)
110  * - number of channels (4 bits)
111  * - frequency (4 bits)
112  * - bits per sample (2 bits)
113  * - unknown (6 bits)
114  */
115
116 #define LPCM_VOB_HEADER_LEN (6)
117 #define LPCM_AOB_HEADER_LEN (11)
118 #define LPCM_BD_HEADER_LEN (4)
119
120 enum
121 {
122     LPCM_VOB,
123     LPCM_AOB,
124     LPCM_BD,
125 };
126
127 typedef struct
128 {
129     unsigned i_channels;
130     bool     b_used;
131     unsigned pi_position[6];
132 } aob_group_t;
133
134 /*****************************************************************************
135  * Local prototypes
136  *****************************************************************************/
137 static void *DecodeFrame  ( decoder_t *, block_t ** );
138
139 /* */
140 static int VobHeader( unsigned *pi_rate,
141                       unsigned *pi_channels, unsigned *pi_original_channels,
142                       unsigned *pi_bits,
143                       const uint8_t *p_header );
144 static void VobExtract( aout_buffer_t *, block_t *, unsigned i_bits );
145 /* */
146 static int AobHeader( unsigned *pi_rate,
147                       unsigned *pi_channels, unsigned *pi_layout,
148                       unsigned *pi_bits,
149                       unsigned *pi_padding,
150                       aob_group_t g[2],
151                       const uint8_t *p_header );
152 static void AobExtract( aout_buffer_t *, block_t *, unsigned i_bits, aob_group_t p_group[2] );
153 /* */
154 static int BdHeader( unsigned *pi_rate,
155                      unsigned *pi_channels, unsigned *pi_original_channels,
156                      unsigned *pi_bits,
157                      const uint8_t *p_header );
158 static void BdExtract( aout_buffer_t *, block_t * );
159
160
161 /*****************************************************************************
162  * OpenCommon:
163  *****************************************************************************/
164 static int OpenCommon( vlc_object_t *p_this, bool b_packetizer )
165 {
166     decoder_t *p_dec = (decoder_t*)p_this;
167     decoder_sys_t *p_sys;
168     int i_type;
169     int i_header_size;
170
171     switch( p_dec->fmt_in.i_codec )
172     {
173     /* DVD LPCM */
174     case VLC_CODEC_DVD_LPCM:
175         i_type = LPCM_VOB;
176         i_header_size = LPCM_VOB_HEADER_LEN;
177         break;
178     /* DVD-Audio LPCM */
179     case VLC_CODEC_DVDA_LPCM:
180         i_type = LPCM_AOB;
181         i_header_size = LPCM_AOB_HEADER_LEN;
182         break;
183     /* BD LPCM */
184     case VLC_CODEC_BD_LPCM:
185         i_type = LPCM_BD;
186         i_header_size = LPCM_BD_HEADER_LEN;
187         break;
188     default:
189         return VLC_EGENERIC;
190     }
191
192     /* Allocate the memory needed to store the decoder's structure */
193     if( ( p_dec->p_sys = p_sys = malloc(sizeof(decoder_sys_t)) ) == NULL )
194         return VLC_ENOMEM;
195
196     /* Misc init */
197     p_sys->b_packetizer = b_packetizer;
198     date_Set( &p_sys->end_date, 0 );
199     p_sys->i_type = i_type;
200     p_sys->i_header_size = i_header_size;
201
202     /* Set output properties */
203     p_dec->fmt_out.i_cat = AUDIO_ES;
204
205     if( b_packetizer )
206     {
207         switch( i_type )
208         {
209         case LPCM_VOB:
210             p_dec->fmt_out.i_codec = VLC_CODEC_DVD_LPCM;
211             break;
212         case LPCM_AOB:
213             p_dec->fmt_out.i_codec = VLC_CODEC_DVDA_LPCM;
214             break;
215         default:
216             assert(0);
217         case LPCM_BD:
218             p_dec->fmt_out.i_codec = VLC_CODEC_BD_LPCM;
219             break;
220         }
221     }
222     else
223     {
224         switch( p_dec->fmt_out.audio.i_bitspersample )
225         {
226         case 24:
227         case 20:
228             p_dec->fmt_out.i_codec = VLC_CODEC_S24B;
229             p_dec->fmt_out.audio.i_bitspersample = 24;
230             break;
231         default:
232             p_dec->fmt_out.i_codec = VLC_CODEC_S16B;
233             p_dec->fmt_out.audio.i_bitspersample = 16;
234             break;
235         }
236     }
237
238     /* Set callback */
239     p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))
240         DecodeFrame;
241     p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
242         DecodeFrame;
243
244     return VLC_SUCCESS;
245 }
246 static int OpenDecoder( vlc_object_t *p_this )
247 {
248     return OpenCommon( p_this, false );
249 }
250 static int OpenPacketizer( vlc_object_t *p_this )
251 {
252     return OpenCommon( p_this, true );
253 }
254
255 /*****************************************************************************
256  * DecodeFrame: decodes an lpcm frame.
257  ****************************************************************************
258  * Beware, this function must be fed with complete frames (PES packet).
259  *****************************************************************************/
260 static void *DecodeFrame( decoder_t *p_dec, block_t **pp_block )
261 {
262     decoder_sys_t *p_sys = p_dec->p_sys;
263     block_t       *p_block;
264     unsigned int  i_rate = 0, i_original_channels = 0, i_channels = 0, i_bits = 0;
265     int           i_frame_length;
266
267     if( !pp_block || !*pp_block ) return NULL;
268
269     p_block = *pp_block;
270     *pp_block = NULL; /* So the packet doesn't get re-sent */
271
272     /* Date management */
273     if( p_block->i_pts > VLC_TS_INVALID &&
274         p_block->i_pts != date_Get( &p_sys->end_date ) )
275     {
276         date_Set( &p_sys->end_date, p_block->i_pts );
277     }
278
279     if( !date_Get( &p_sys->end_date ) )
280     {
281         /* We've just started the stream, wait for the first PTS. */
282         block_Release( p_block );
283         return NULL;
284     }
285
286     if( p_block->i_buffer <= p_sys->i_header_size )
287     {
288         msg_Err(p_dec, "frame is too short");
289         block_Release( p_block );
290         return NULL;
291     }
292
293     int i_ret;
294     unsigned i_padding = 0;
295     aob_group_t p_aob_group[2];
296     switch( p_sys->i_type )
297     {
298     case LPCM_VOB:
299         i_ret = VobHeader( &i_rate, &i_channels, &i_original_channels, &i_bits,
300                            p_block->p_buffer );
301         break;
302     case LPCM_AOB:
303         i_ret = AobHeader( &i_rate, &i_channels, &i_original_channels, &i_bits, &i_padding,
304                            p_aob_group,
305                            p_block->p_buffer );
306         break;
307     case LPCM_BD:
308         i_ret = BdHeader( &i_rate, &i_channels, &i_original_channels, &i_bits,
309                           p_block->p_buffer );
310         break;
311     default:
312         abort();
313     }
314
315     if( i_ret || p_block->i_buffer <= p_sys->i_header_size + i_padding )
316     {
317         msg_Warn( p_dec, "no frame sync or too small frame" );
318         block_Release( p_block );
319         return NULL;
320     }
321
322     /* Set output properties */
323     if( p_dec->fmt_out.audio.i_rate != i_rate )
324     {
325         date_Init( &p_sys->end_date, i_rate, 1 );
326         date_Set( &p_sys->end_date, p_block->i_pts );
327     }
328     p_dec->fmt_out.audio.i_rate = i_rate;
329     p_dec->fmt_out.audio.i_channels = i_channels;
330     p_dec->fmt_out.audio.i_original_channels = i_original_channels;
331     p_dec->fmt_out.audio.i_physical_channels = i_original_channels & AOUT_CHAN_PHYSMASK;
332
333     i_frame_length = (p_block->i_buffer - p_sys->i_header_size - i_padding) / i_channels * 8 / i_bits;
334
335     if( p_sys->b_packetizer )
336     {
337         p_block->i_pts = p_block->i_dts = date_Get( &p_sys->end_date );
338         p_block->i_length =
339             date_Increment( &p_sys->end_date, i_frame_length ) -
340             p_block->i_pts;
341
342         /* Just pass on the incoming frame */
343         return p_block;
344     }
345     else
346     {
347         /* */
348         if( i_bits == 16 )
349         {
350             p_dec->fmt_out.i_codec = VLC_CODEC_S16B;
351             p_dec->fmt_out.audio.i_bitspersample = 16;
352         }
353         else
354         {
355             p_dec->fmt_out.i_codec = VLC_CODEC_S24B;
356             p_dec->fmt_out.audio.i_bitspersample = 24;
357         }
358
359         /* */
360         aout_buffer_t *p_aout_buffer;
361         p_aout_buffer = decoder_NewAudioBuffer( p_dec, i_frame_length );
362         if( !p_aout_buffer )
363             return NULL;
364
365         p_aout_buffer->i_pts = date_Get( &p_sys->end_date );
366         p_aout_buffer->i_length =
367             date_Increment( &p_sys->end_date, i_frame_length )
368             - p_aout_buffer->i_pts;
369
370         p_block->p_buffer += p_sys->i_header_size + i_padding;
371         p_block->i_buffer -= p_sys->i_header_size + i_padding;
372
373         switch( p_sys->i_type )
374         {
375         case LPCM_VOB:
376             VobExtract( p_aout_buffer, p_block, i_bits );
377             break;
378         case LPCM_AOB:
379             AobExtract( p_aout_buffer, p_block, i_bits, p_aob_group );
380             break;
381         default:
382             assert(0);
383         case LPCM_BD:
384             BdExtract( p_aout_buffer, p_block );
385             break;
386         }
387
388         block_Release( p_block );
389         return p_aout_buffer;
390     }
391 }
392
393 /*****************************************************************************
394  * CloseCommon : lpcm decoder destruction
395  *****************************************************************************/
396 static void CloseCommon( vlc_object_t *p_this )
397 {
398     decoder_t *p_dec = (decoder_t*)p_this;
399     free( p_dec->p_sys );
400 }
401
402 /*****************************************************************************
403  *
404  *****************************************************************************/
405 static int VobHeader( unsigned *pi_rate,
406                       unsigned *pi_channels, unsigned *pi_original_channels,
407                       unsigned *pi_bits,
408                       const uint8_t *p_header )
409 {
410     const uint8_t i_header = p_header[4];
411
412     switch( (i_header >> 4) & 0x3 )
413     {
414     case 0:
415         *pi_rate = 48000;
416         break;
417     case 1:
418         *pi_rate = 96000;
419         break;
420     case 2:
421         *pi_rate = 44100;
422         break;
423     case 3:
424         *pi_rate = 32000;
425         break;
426     }
427
428     *pi_channels = (i_header & 0x7) + 1;
429     switch( *pi_channels - 1 )
430     {
431     case 0:
432         *pi_original_channels = AOUT_CHAN_CENTER;
433         break;
434     case 1:
435         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
436         break;
437     case 2:
438         /* This is unsure. */
439         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_LFE;
440         break;
441     case 3:
442         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
443                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
444         break;
445     case 4:
446         /* This is unsure. */
447         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
448                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
449                                | AOUT_CHAN_LFE;
450         break;
451     case 5:
452         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
453                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
454                                | AOUT_CHAN_CENTER | AOUT_CHAN_LFE;
455         break;
456     case 6:
457         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
458                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
459                                | AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT
460                                | AOUT_CHAN_MIDDLERIGHT;
461         break;
462     case 7:
463         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
464                                | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
465                                | AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT
466                                | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_LFE;
467         break;
468     }
469
470     switch( (i_header >> 6) & 0x3 )
471     {
472     case 2:
473         *pi_bits = 24;
474         break;
475     case 1:
476         *pi_bits = 20;
477         break;
478     case 0:
479     default:
480         *pi_bits = 16;
481         break;
482     }
483
484     /* Check frame sync and drop it. */
485     if( p_header[5] != 0x80 )
486         return -1;
487     return 0;
488 }
489
490 static const unsigned p_aob_group1[21][6] = {
491     { AOUT_CHAN_CENTER, 0 },
492     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
493     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
494     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
495     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
496     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
497     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
498     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
499     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
500     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
501     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
502     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
503     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, 0 },
504     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,   0 },
505     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,   0 },
506     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,   0 },
507     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,   0 },
508     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,   0 },
509     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0  },
510     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0  },
511     { AOUT_CHAN_LEFT,   AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0  },
512 };
513 static const unsigned p_aob_group2[21][6] = {
514     { 0 },
515     { 0 },
516     { AOUT_CHAN_REARCENTER, 0 },
517     { AOUT_CHAN_REARLEFT,   AOUT_CHAN_REARRIGHT,    0 },
518     { AOUT_CHAN_LFE,        0 },
519     { AOUT_CHAN_LFE,        AOUT_CHAN_REARCENTER,   0 },
520     { AOUT_CHAN_LFE,        AOUT_CHAN_REARLEFT,     AOUT_CHAN_REARRIGHT,    0 },
521     { AOUT_CHAN_CENTER,     0 },
522     { AOUT_CHAN_CENTER,     AOUT_CHAN_REARCENTER, 0 },
523     { AOUT_CHAN_CENTER,     AOUT_CHAN_REARLEFT,   AOUT_CHAN_REARRIGHT,    0 },
524     { AOUT_CHAN_CENTER,     AOUT_CHAN_LFE,        0 },
525     { AOUT_CHAN_CENTER,     AOUT_CHAN_LFE,        AOUT_CHAN_REARCENTER,   0 },
526     { AOUT_CHAN_CENTER,     AOUT_CHAN_LFE,        AOUT_CHAN_REARLEFT,     AOUT_CHAN_REARRIGHT,    0 },
527     { AOUT_CHAN_REARCENTER, 0 },
528     { AOUT_CHAN_REARLEFT,   AOUT_CHAN_REARRIGHT,    0 },
529     { AOUT_CHAN_LFE,        0 },
530     { AOUT_CHAN_LFE,        AOUT_CHAN_REARCENTER,   0 },
531     { AOUT_CHAN_LFE,        AOUT_CHAN_REARLEFT,     AOUT_CHAN_REARRIGHT,    0 },
532     { AOUT_CHAN_LFE,        0 },
533     { AOUT_CHAN_CENTER,     0 },
534     { AOUT_CHAN_CENTER,     AOUT_CHAN_LFE,          0 },
535 };
536
537 static int AobHeader( unsigned *pi_rate,
538                       unsigned *pi_channels, unsigned *pi_layout,
539                       unsigned *pi_bits,
540                       unsigned *pi_padding,
541                       aob_group_t g[2],
542                       const uint8_t *p_header )
543 {
544     const unsigned i_header_size = GetWBE( &p_header[1] );
545     if( i_header_size + 3 < LPCM_AOB_HEADER_LEN )
546         return VLC_EGENERIC;
547
548     *pi_padding = 3+i_header_size - LPCM_AOB_HEADER_LEN;
549
550     const int i_index_size_g1 = (p_header[6] >> 4) & 0x0f;
551     const int i_index_size_g2 = (p_header[6]     ) & 0x0f;
552     const int i_index_rate_g1 = (p_header[7] >> 4) & 0x0f;
553     const int i_index_rate_g2 = (p_header[7]     ) & 0x0f;
554     const int i_assignment     = p_header[9];
555
556     /* Validate */
557     if( i_index_size_g1 > 0x02 ||
558         ( i_index_size_g2 != 0x0f && i_index_size_g2 > 0x02 ) )
559         return VLC_EGENERIC;
560     if( (i_index_rate_g1 & 0x07) > 0x02 ||
561         ( i_index_rate_g2 != 0x0f && (i_index_rate_g1 & 0x07) > 0x02 ) )
562         return VLC_EGENERIC;
563     if( i_assignment > 20 )
564         return VLC_EGENERIC;
565
566     /* */
567     *pi_bits = 16 + 4 * i_index_size_g1;
568     if( i_index_rate_g1 & 0x08 )
569         *pi_rate = 44100 << (i_index_rate_g1 & 0x07);
570     else
571         *pi_rate = 48000 << (i_index_rate_g1 & 0x07);
572
573
574     /* Group1 */
575     unsigned i_channels1 = 0;
576     unsigned i_layout1 = 0;
577     for( int i = 0; p_aob_group1[i_assignment][i] != 0; i++ )
578     {
579         i_channels1++;
580         i_layout1 |= p_aob_group1[i_assignment][i];
581     }
582     /* Group2 */
583     unsigned i_channels2 = 0;
584     unsigned i_layout2 = 0;
585     if( i_index_size_g2 != 0x0f && i_index_rate_g2 != 0x0f )
586     {
587         for( int i = 0; p_aob_group2[i_assignment][i] != 0; i++ )
588         {
589             i_channels2++;
590             i_layout2 |= p_aob_group2[i_assignment][i];
591         }
592         assert( (i_layout1 & i_layout2) == 0 );
593     }
594     /* It is enabled only when presents and compatible wih group1 */
595     const bool b_group2_used = i_index_size_g1 == i_index_size_g2 &&
596                                i_index_rate_g1 == i_index_rate_g2;
597
598     /* */
599     *pi_channels = i_channels1 + ( b_group2_used ? i_channels2 : 0 );
600     *pi_layout   = i_layout1   | ( b_group2_used ? i_layout2   : 0 );
601
602     /* */
603     for( unsigned i = 0; i < 2; i++ )
604     {
605         const unsigned *p_aob = i == 0 ? p_aob_group1[i_assignment] :
606                                          p_aob_group2[i_assignment];
607         g[i].i_channels = i == 0 ? i_channels1 :
608                                    i_channels2;
609
610         g[i].b_used = i == 0 || b_group2_used;
611         if( !g[i].b_used )
612             continue;
613         for( unsigned j = 0; j < g[i].i_channels; j++ )
614         {
615             g[i].pi_position[j] = 0;
616             for( int k = 0; pi_vlc_chan_order_wg4[k] != 0; k++ )
617             {
618                 const unsigned i_channel = pi_vlc_chan_order_wg4[k];
619                 if( i_channel == p_aob[j] )
620                     break;
621                 if( (*pi_layout) & i_channel )
622                     g[i].pi_position[j]++;
623             }
624         }
625     }
626     return VLC_SUCCESS;
627 }
628
629 static int BdHeader( unsigned *pi_rate,
630                      unsigned *pi_channels, unsigned *pi_original_channels,
631                      unsigned *pi_bits,
632                      const uint8_t *p_header )
633 {
634     const uint32_t h = GetDWBE( p_header );
635     switch( ( h & 0xf000) >> 12 )
636     {
637     case 1:
638         *pi_channels = 1;
639         *pi_original_channels = AOUT_CHAN_CENTER;
640         break;
641     case 3:
642         *pi_channels = 2;
643         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
644         break;
645     case 4:
646         *pi_channels = 3;
647         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER;
648         break;
649     case 5:
650         *pi_channels = 3;
651         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER;
652         break;
653     case 6:
654         *pi_channels = 4;
655         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
656                                 AOUT_CHAN_REARCENTER;
657         break;
658     case 7:
659         *pi_channels = 4;
660         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
661                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
662         break;
663     case 8:
664         *pi_channels = 5;
665         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
666                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
667         break;
668     case 9:
669         *pi_channels = 6;
670         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
671                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
672                                 AOUT_CHAN_LFE;
673         break;
674     case 10:
675         *pi_channels = 7;
676         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
677                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
678                                 AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT;
679         break;
680     case 11:
681         *pi_channels = 8;
682         *pi_original_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER |
683                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT |
684                                 AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
685                                 AOUT_CHAN_LFE;
686         break;
687
688     default:
689         return -1;
690     }
691     switch( (h >> 6) & 0x03 )
692     {
693     case 1:
694         *pi_bits = 16;
695         break;
696     case 2: /* 20 bits but samples are stored on 24 bits */
697     case 3: /* 24 bits */
698         *pi_bits = 24;
699         break;
700     default:
701         return -1;
702     }
703     switch( (h >> 8) & 0x0f ) 
704     {
705     case 1:
706         *pi_rate = 48000;
707         break;
708     case 4:
709         *pi_rate = 96000;
710         break;
711     case 5:
712         *pi_rate = 192000;
713         break;
714     default:
715         return -1;
716     }
717     return 0;
718 }
719
720 static void VobExtract( aout_buffer_t *p_aout_buffer, block_t *p_block,
721                         unsigned i_bits )
722 {
723     uint8_t *p_out = p_aout_buffer->p_buffer;
724
725     /* 20/24 bits LPCM use special packing */
726     if( i_bits == 24 )
727     {
728         while( p_block->i_buffer / 12 )
729         {
730             /* Sample 1 */
731             p_out[0] = p_block->p_buffer[0];
732             p_out[1] = p_block->p_buffer[1];
733             p_out[2] = p_block->p_buffer[8];
734             /* Sample 2 */
735             p_out[3] = p_block->p_buffer[2];
736             p_out[4] = p_block->p_buffer[3];
737             p_out[5] = p_block->p_buffer[9];
738             /* Sample 3 */
739             p_out[6] = p_block->p_buffer[4];
740             p_out[7] = p_block->p_buffer[5];
741             p_out[8] = p_block->p_buffer[10];
742             /* Sample 4 */
743             p_out[9] = p_block->p_buffer[6];
744             p_out[10] = p_block->p_buffer[7];
745             p_out[11] = p_block->p_buffer[11];
746
747             p_block->i_buffer -= 12;
748             p_block->p_buffer += 12;
749             p_out += 12;
750         }
751     }
752     else if( i_bits == 20 )
753     {
754         while( p_block->i_buffer / 10 )
755         {
756             /* Sample 1 */
757             p_out[0] = p_block->p_buffer[0];
758             p_out[1] = p_block->p_buffer[1];
759             p_out[2] = p_block->p_buffer[8] & 0xF0;
760             /* Sample 2 */
761             p_out[3] = p_block->p_buffer[2];
762             p_out[4] = p_block->p_buffer[3];
763             p_out[5] = p_block->p_buffer[8] << 4;
764             /* Sample 3 */
765             p_out[6] = p_block->p_buffer[4];
766             p_out[7] = p_block->p_buffer[5];
767             p_out[8] = p_block->p_buffer[9] & 0xF0;
768             /* Sample 4 */
769             p_out[9] = p_block->p_buffer[6];
770             p_out[10] = p_block->p_buffer[7];
771             p_out[11] = p_block->p_buffer[9] << 4;
772
773             p_block->i_buffer -= 10;
774             p_block->p_buffer += 10;
775             p_out += 12;
776         }
777     }
778     else
779     {
780         assert( i_bits == 16 );
781         memcpy( p_out, p_block->p_buffer, p_block->i_buffer );
782     }
783 }
784 static void AobExtract( aout_buffer_t *p_aout_buffer,
785                         block_t *p_block, unsigned i_bits, aob_group_t p_group[2] )
786 {
787     const unsigned i_channels = p_group[0].i_channels +
788                                 ( p_group[1].b_used ? p_group[1].i_channels : 0 );
789     uint8_t *p_out = p_aout_buffer->p_buffer;
790
791     while( p_block->i_buffer > 0 )
792     {
793         for( int i = 0; i < 2; i++ )
794         {
795             const aob_group_t *g = &p_group[1-i];
796             const unsigned int i_group_size = 2 * g->i_channels * i_bits / 8;
797
798             if( p_block->i_buffer < i_group_size )
799             {
800                 p_block->i_buffer = 0;
801                 break;
802             }
803             for( unsigned n = 0; n < 2; n++ )
804             {
805                 for( unsigned j = 0; j < g->i_channels && g->b_used; j++ )
806                 {
807                     const int i_src = n * g->i_channels + j;
808                     const int i_dst = n * i_channels + g->pi_position[j];
809
810                     if( i_bits == 24 )
811                     {
812                         p_out[3*i_dst+0] = p_block->p_buffer[2*i_src+0];
813                         p_out[3*i_dst+1] = p_block->p_buffer[2*i_src+1];
814                         p_out[3*i_dst+2] = p_block->p_buffer[4*g->i_channels+i_src];
815                     }
816                     else if( i_bits == 20 )
817                     {
818                         p_out[3*i_dst+0] = p_block->p_buffer[2*i_src+0];
819                         p_out[3*i_dst+1] = p_block->p_buffer[2*i_src+1];
820                         if( n == 0 )
821                             p_out[3*i_dst+2] = (p_block->p_buffer[4*g->i_channels+i_src]     ) & 0xf0;
822                         else
823                             p_out[3*i_dst+2] = (p_block->p_buffer[4*g->i_channels+i_src] << 4) & 0xf0;
824                     }
825                     else
826                     {
827                         assert( i_bits == 16 );
828                         p_out[2*i_dst+0] = p_block->p_buffer[2*i_src+0];
829                         p_out[2*i_dst+1] = p_block->p_buffer[2*i_src+1];
830                     }
831                 }
832             }
833
834             p_block->i_buffer -= i_group_size;
835             p_block->p_buffer += i_group_size;
836         }
837         /* */
838         p_out += (i_bits == 16 ? 2 : 3) * i_channels * 2;
839
840     }
841 }
842 static void BdExtract( aout_buffer_t *p_aout_buffer, block_t *p_block )
843 {
844     memcpy( p_aout_buffer->p_buffer, p_block->p_buffer, p_block->i_buffer );
845 }
846