]> git.sesse.net Git - vlc/blob - modules/codec/dts.c
Improved BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED handling in packetizers.
[vlc] / modules / codec / dts.c
1 /*****************************************************************************
2  * dts.c: parse DTS audio sync info and packetize the stream
3  *****************************************************************************
4  * Copyright (C) 2003-2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Gildas Bazin <gbazin@netcourrier.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <vlc/vlc.h>
29 #include <vlc_codec.h>
30 #include <vlc_aout.h>
31 #include <vlc_block_helper.h>
32
33 #define DTS_HEADER_SIZE 14
34
35 /*****************************************************************************
36  * decoder_sys_t : decoder descriptor
37  *****************************************************************************/
38 struct decoder_sys_t
39 {
40     /* Module mode */
41     vlc_bool_t b_packetizer;
42
43     /*
44      * Input properties
45      */
46     int i_state;
47
48     block_bytestream_t bytestream;
49
50     /*
51      * Common properties
52      */
53     audio_date_t   end_date;
54
55     mtime_t i_pts;
56
57     unsigned int i_bit_rate;
58     unsigned int i_frame_size;
59     unsigned int i_frame_length;
60     unsigned int i_rate;
61     unsigned int i_channels;
62     unsigned int i_channels_conf;
63 };
64
65 enum {
66
67     STATE_NOSYNC,
68     STATE_SYNC,
69     STATE_HEADER,
70     STATE_NEXT_SYNC,
71     STATE_GET_DATA,
72     STATE_SEND_DATA
73 };
74
75 /****************************************************************************
76  * Local prototypes
77  ****************************************************************************/
78 static int  OpenDecoder   ( vlc_object_t * );
79 static int  OpenPacketizer( vlc_object_t * );
80 static void CloseDecoder  ( vlc_object_t * );
81 static void *DecodeBlock  ( decoder_t *, block_t ** );
82
83 static inline int SyncCode( const uint8_t * );
84 static int  SyncInfo      ( const uint8_t *, unsigned int *, unsigned int *,
85                             unsigned int *, unsigned int *, unsigned int * );
86
87 static uint8_t       *GetOutBuffer ( decoder_t *, void ** );
88 static aout_buffer_t *GetAoutBuffer( decoder_t * );
89 static block_t       *GetSoutBuffer( decoder_t * );
90
91 /*****************************************************************************
92  * Module descriptor
93  *****************************************************************************/
94 vlc_module_begin();
95     set_description( _("DTS parser") );
96     set_capability( "decoder", 100 );
97     set_callbacks( OpenDecoder, CloseDecoder );
98
99     add_submodule();
100     set_description( _("DTS audio packetizer") );
101     set_capability( "packetizer", 10 );
102     set_callbacks( OpenPacketizer, CloseDecoder );
103 vlc_module_end();
104
105 /*****************************************************************************
106  * OpenDecoder: probe the decoder and return score
107  *****************************************************************************/
108 static int OpenDecoder( vlc_object_t *p_this )
109 {
110     decoder_t *p_dec = (decoder_t*)p_this;
111     decoder_sys_t *p_sys;
112
113     if( p_dec->fmt_in.i_codec != VLC_FOURCC('d','t','s',' ')
114          && p_dec->fmt_in.i_codec != VLC_FOURCC('d','t','s','b') )
115     {
116         return VLC_EGENERIC;
117     }
118
119     /* Allocate the memory needed to store the decoder's structure */
120     if( ( p_dec->p_sys = p_sys =
121           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
122     {
123         msg_Err( p_dec, "out of memory" );
124         return VLC_EGENERIC;
125     }
126
127     /* Misc init */
128     p_sys->b_packetizer = VLC_FALSE;
129     p_sys->i_state = STATE_NOSYNC;
130     aout_DateSet( &p_sys->end_date, 0 );
131
132     p_sys->bytestream = block_BytestreamInit( p_dec );
133
134     /* Set output properties */
135     p_dec->fmt_out.i_cat = AUDIO_ES;
136     p_dec->fmt_out.i_codec = VLC_FOURCC('d','t','s',' ');
137     p_dec->fmt_out.audio.i_rate = 0; /* So end_date gets initialized */
138
139     /* Set callback */
140     p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))
141         DecodeBlock;
142     p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
143         DecodeBlock;
144
145     return VLC_SUCCESS;
146 }
147
148 static int OpenPacketizer( vlc_object_t *p_this )
149 {
150     decoder_t *p_dec = (decoder_t*)p_this;
151
152     int i_ret = OpenDecoder( p_this );
153
154     if( i_ret == VLC_SUCCESS ) p_dec->p_sys->b_packetizer = VLC_TRUE;
155
156     return i_ret;
157 }
158
159 /****************************************************************************
160  * DecodeBlock: the whole thing
161  ****************************************************************************
162  * This function is called just after the thread is launched.
163  ****************************************************************************/
164 static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
165 {
166     decoder_sys_t *p_sys = p_dec->p_sys;
167     uint8_t p_header[DTS_HEADER_SIZE];
168     uint8_t *p_buf;
169     void *p_out_buffer;
170
171     if( !pp_block || !*pp_block ) return NULL;
172
173     if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
174     {
175         if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED )
176         {
177             p_sys->i_state = STATE_NOSYNC;
178             block_BytestreamFlush( &p_sys->bytestream );
179         }
180 //        aout_DateSet( &p_sys->end_date, 0 );
181         block_Release( *pp_block );
182         return NULL;
183     }
184
185     if( !aout_DateGet( &p_sys->end_date ) && !(*pp_block)->i_pts )
186     {
187         /* We've just started the stream, wait for the first PTS. */
188         block_Release( *pp_block );
189         return NULL;
190     }
191
192     block_BytestreamPush( &p_sys->bytestream, *pp_block );
193
194     while( 1 )
195     {
196         switch( p_sys->i_state )
197         {
198         case STATE_NOSYNC:
199             /* Look for sync code - should be 0x7ffe8001 */
200             while( block_PeekBytes( &p_sys->bytestream, p_header, 6 )
201                    == VLC_SUCCESS )
202             {
203                 if( SyncCode( p_header ) == VLC_SUCCESS )
204                 {
205                     p_sys->i_state = STATE_SYNC;
206                     break;
207                 }
208                 block_SkipByte( &p_sys->bytestream );
209             }
210             if( p_sys->i_state != STATE_SYNC )
211             {
212                 block_BytestreamFlush( &p_sys->bytestream );
213
214                 /* Need more data */
215                 return NULL;
216             }
217
218         case STATE_SYNC:
219             /* New frame, set the Presentation Time Stamp */
220             p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
221             if( p_sys->i_pts != 0 &&
222                 p_sys->i_pts != aout_DateGet( &p_sys->end_date ) )
223             {
224                 aout_DateSet( &p_sys->end_date, p_sys->i_pts );
225             }
226             p_sys->i_state = STATE_HEADER;
227
228         case STATE_HEADER:
229             /* Get DTS frame header (DTS_HEADER_SIZE bytes) */
230             if( block_PeekBytes( &p_sys->bytestream, p_header,
231                                  DTS_HEADER_SIZE ) != VLC_SUCCESS )
232             {
233                 /* Need more data */
234                 return NULL;
235             }
236
237             /* Check if frame is valid and get frame info */
238             p_sys->i_frame_size = SyncInfo( p_header,
239                                             &p_sys->i_channels,
240                                             &p_sys->i_channels_conf,
241                                             &p_sys->i_rate,
242                                             &p_sys->i_bit_rate,
243                                             &p_sys->i_frame_length );
244             if( !p_sys->i_frame_size )
245             {
246                 msg_Dbg( p_dec, "emulated sync word" );
247                 block_SkipByte( &p_sys->bytestream );
248                 p_sys->i_state = STATE_NOSYNC;
249                 break;
250             }
251             p_sys->i_state = STATE_NEXT_SYNC;
252
253         case STATE_NEXT_SYNC:
254             /* TODO: If pp_block == NULL, flush the buffer without checking the
255              * next sync word */
256
257             /* Check if next expected frame contains the sync word */
258             if( block_PeekOffsetBytes( &p_sys->bytestream,
259                                        p_sys->i_frame_size, p_header, 6 )
260                 != VLC_SUCCESS )
261             {
262                 /* Need more data */
263                 return NULL;
264             }
265
266             if( SyncCode( p_header ) != VLC_SUCCESS )
267             {
268                 msg_Dbg( p_dec, "emulated sync word "
269                          "(no sync on following frame): %2.2x%2.2x%2.2x%2.2x",
270                          (int)p_header[0], (int)p_header[1],
271                          (int)p_header[2], (int)p_header[3] );
272                 p_sys->i_state = STATE_NOSYNC;
273                 block_SkipByte( &p_sys->bytestream );
274                 break;
275             }
276             p_sys->i_state = STATE_SEND_DATA;
277             break;
278
279         case STATE_GET_DATA:
280             /* Make sure we have enough data.
281              * (Not useful if we went through NEXT_SYNC) */
282             if( block_WaitBytes( &p_sys->bytestream,
283                                  p_sys->i_frame_size ) != VLC_SUCCESS )
284             {
285                 /* Need more data */
286                 return NULL;
287             }
288             p_sys->i_state = STATE_SEND_DATA;
289
290         case STATE_SEND_DATA:
291             if( !(p_buf = GetOutBuffer( p_dec, &p_out_buffer )) )
292             {
293                 //p_dec->b_error = VLC_TRUE;
294                 return NULL;
295             }
296
297             /* Copy the whole frame into the buffer. When we reach this point
298              * we already know we have enough data available. */
299             block_GetBytes( &p_sys->bytestream, p_buf, p_sys->i_frame_size );
300
301             /* Make sure we don't reuse the same pts twice */
302             if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
303                 p_sys->i_pts = p_sys->bytestream.p_block->i_pts = 0;
304
305             p_sys->i_state = STATE_NOSYNC;
306
307             /* So p_block doesn't get re-added several times */
308             *pp_block = block_BytestreamPop( &p_sys->bytestream );
309
310             return p_out_buffer;
311         }
312     }
313
314     return NULL;
315 }
316
317 /*****************************************************************************
318  * CloseDecoder: clean up the decoder
319  *****************************************************************************/
320 static void CloseDecoder( vlc_object_t *p_this )
321 {
322     decoder_t *p_dec = (decoder_t*)p_this;
323     decoder_sys_t *p_sys = p_dec->p_sys;
324
325     block_BytestreamRelease( &p_sys->bytestream );
326
327     free( p_sys );
328 }
329
330 /*****************************************************************************
331  * GetOutBuffer:
332  *****************************************************************************/
333 static uint8_t *GetOutBuffer( decoder_t *p_dec, void **pp_out_buffer )
334 {
335     decoder_sys_t *p_sys = p_dec->p_sys;
336     uint8_t *p_buf;
337
338     if( p_dec->fmt_out.audio.i_rate != p_sys->i_rate )
339     {
340         msg_Info( p_dec, "DTS channels:%d samplerate:%d bitrate:%d",
341                   p_sys->i_channels, p_sys->i_rate, p_sys->i_bit_rate );
342
343         aout_DateInit( &p_sys->end_date, p_sys->i_rate );
344         aout_DateSet( &p_sys->end_date, p_sys->i_pts );
345     }
346
347     p_dec->fmt_out.audio.i_rate     = p_sys->i_rate;
348     p_dec->fmt_out.audio.i_channels = p_sys->i_channels;
349     /* Hack for DTS S/PDIF filter which needs to pad the DTS frames */
350     p_dec->fmt_out.audio.i_bytes_per_frame =
351         __MAX( p_sys->i_frame_size, p_sys->i_frame_length * 4 );
352     p_dec->fmt_out.audio.i_frame_length = p_sys->i_frame_length;
353
354     p_dec->fmt_out.audio.i_original_channels = p_sys->i_channels_conf;
355     p_dec->fmt_out.audio.i_physical_channels =
356         p_sys->i_channels_conf & AOUT_CHAN_PHYSMASK;
357
358     p_dec->fmt_out.i_bitrate = p_sys->i_bit_rate;
359
360     if( p_sys->b_packetizer )
361     {
362         block_t *p_sout_buffer = GetSoutBuffer( p_dec );
363         p_buf = p_sout_buffer ? p_sout_buffer->p_buffer : NULL;
364         *pp_out_buffer = p_sout_buffer;
365     }
366     else
367     {
368         aout_buffer_t *p_aout_buffer = GetAoutBuffer( p_dec );
369         p_buf = p_aout_buffer ? p_aout_buffer->p_buffer : NULL;
370         *pp_out_buffer = p_aout_buffer;
371     }
372
373     return p_buf;
374 }
375
376 /*****************************************************************************
377  * GetAoutBuffer:
378  *****************************************************************************/
379 static aout_buffer_t *GetAoutBuffer( decoder_t *p_dec )
380 {
381     decoder_sys_t *p_sys = p_dec->p_sys;
382     aout_buffer_t *p_buf;
383
384     /* Hack for DTS S/PDIF filter which needs to send 3 frames at a time
385      * (plus a few header bytes) */
386     p_buf = p_dec->pf_aout_buffer_new( p_dec, p_sys->i_frame_length * 4 );
387     if( p_buf == NULL ) return NULL;
388     p_buf->i_nb_samples = p_sys->i_frame_length;
389     p_buf->i_nb_bytes = p_sys->i_frame_size;
390
391     p_buf->start_date = aout_DateGet( &p_sys->end_date );
392     p_buf->end_date =
393         aout_DateIncrement( &p_sys->end_date, p_sys->i_frame_length );
394
395     return p_buf;
396 }
397
398 /*****************************************************************************
399  * GetSoutBuffer:
400  *****************************************************************************/
401 static block_t *GetSoutBuffer( decoder_t *p_dec )
402 {
403     decoder_sys_t *p_sys = p_dec->p_sys;
404     block_t *p_block;
405
406     p_block = block_New( p_dec, p_sys->i_frame_size );
407     if( p_block == NULL ) return NULL;
408
409     p_block->i_pts = p_block->i_dts = aout_DateGet( &p_sys->end_date );
410
411     p_block->i_length = aout_DateIncrement( &p_sys->end_date,
412         p_sys->i_frame_length ) - p_block->i_pts;
413
414     return p_block;
415 }
416
417 /*****************************************************************************
418  * SyncInfo: parse DTS sync info
419  *****************************************************************************/
420 static const unsigned int ppi_dts_samplerate[] =
421 {
422     0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0,
423     12000, 24000, 48000, 96000, 192000
424 };
425
426 static const unsigned int ppi_dts_bitrate[] =
427 {
428     32000, 56000, 64000, 96000, 112000, 128000,
429     192000, 224000, 256000, 320000, 384000,
430     448000, 512000, 576000, 640000, 768000,
431     896000, 1024000, 1152000, 1280000, 1344000,
432     1408000, 1411200, 1472000, 1536000, 1920000,
433     2048000, 3072000, 3840000, 1/*open*/, 2/*variable*/, 3/*lossless*/
434 };
435
436 static int SyncInfo16be( const uint8_t *p_buf,
437                          unsigned int *pi_audio_mode,
438                          unsigned int *pi_sample_rate,
439                          unsigned int *pi_bit_rate,
440                          unsigned int *pi_frame_length )
441 {
442     unsigned int i_frame_size;
443     unsigned int i_lfe;
444
445     *pi_frame_length = (p_buf[4] & 0x01) << 6 | (p_buf[5] >> 2);
446     i_frame_size = (p_buf[5] & 0x03) << 12 | (p_buf[6] << 4) |
447                    (p_buf[7] >> 4);
448
449     *pi_audio_mode = (p_buf[7] & 0x0f) << 2 | (p_buf[8] >> 6);
450     *pi_sample_rate = (p_buf[8] >> 2) & 0x0f;
451     *pi_bit_rate = (p_buf[8] & 0x03) << 3 | ((p_buf[9] >> 5) & 0x07);
452
453     i_lfe = (p_buf[10] >> 1) & 0x03;
454     if( i_lfe ) *pi_audio_mode |= 0x10000;
455
456     return i_frame_size + 1;
457 }
458
459 static void BufLeToBe( uint8_t *p_out, const uint8_t *p_in, int i_in )
460 {
461     int i;
462
463     for( i = 0; i < i_in/2; i++  )
464     {
465         p_out[i*2] = p_in[i*2+1];
466         p_out[i*2+1] = p_in[i*2];
467     }
468 }
469
470 static int Buf14To16( uint8_t *p_out, const uint8_t *p_in, int i_in, int i_le )
471 {
472     unsigned char tmp, cur = 0;
473     int bits_in, bits_out = 0;
474     int i, i_out = 0;
475
476     for( i = 0; i < i_in; i++  )
477     {
478         if( i%2 )
479         {
480             tmp = p_in[i-i_le];
481             bits_in = 8;
482         }
483         else
484         {
485             tmp = p_in[i+i_le] & 0x3F;
486             bits_in = 8 - 2;
487         }
488
489         if( bits_out < 8 )
490         {
491             int need = __MIN( 8 - bits_out, bits_in );
492             cur <<= need;
493             cur |= ( tmp >> (bits_in - need) );
494             tmp <<= (8 - bits_in + need);
495             tmp >>= (8 - bits_in + need);
496             bits_in -= need;
497             bits_out += need;
498         }
499
500         if( bits_out == 8 )
501         {
502             p_out[i_out] = cur;
503             cur = 0;
504             bits_out = 0;
505             i_out++;
506         }
507
508         bits_out += bits_in;
509         cur <<= bits_in;
510         cur |= tmp;
511     }
512
513     return i_out;
514 }
515
516 static inline int SyncCode( const uint8_t *p_buf )
517 {
518     /* 14 bits, little endian version of the bitstream */
519     if( p_buf[0] == 0xff && p_buf[1] == 0x1f &&
520         p_buf[2] == 0x00 && p_buf[3] == 0xe8 &&
521         (p_buf[4] & 0xf0) == 0xf0 && p_buf[5] == 0x07 )
522     {
523         return VLC_SUCCESS;
524     }
525     /* 14 bits, big endian version of the bitstream */
526     else if( p_buf[0] == 0x1f && p_buf[1] == 0xff &&
527              p_buf[2] == 0xe8 && p_buf[3] == 0x00 &&
528              p_buf[4] == 0x07 && (p_buf[5] & 0xf0) == 0xf0 )
529     {
530         return VLC_SUCCESS;
531     }
532     /* 16 bits, big endian version of the bitstream */
533     else if( p_buf[0] == 0x7f && p_buf[1] == 0xfe &&
534              p_buf[2] == 0x80 && p_buf[3] == 0x01 )
535     {
536         return VLC_SUCCESS;
537     }
538     /* 16 bits, little endian version of the bitstream */
539     else if( p_buf[0] == 0xfe && p_buf[1] == 0x7f &&
540              p_buf[2] == 0x01 && p_buf[3] == 0x80 )
541     {
542         return VLC_SUCCESS;
543     }
544     else return VLC_EGENERIC;
545 }
546
547 static int SyncInfo( const uint8_t *p_buf,
548                      unsigned int *pi_channels,
549                      unsigned int *pi_channels_conf,
550                      unsigned int *pi_sample_rate,
551                      unsigned int *pi_bit_rate,
552                      unsigned int *pi_frame_length )
553 {
554     unsigned int i_audio_mode;
555     unsigned int i_frame_size;
556
557     /* 14 bits, little endian version of the bitstream */
558     if( p_buf[0] == 0xff && p_buf[1] == 0x1f &&
559         p_buf[2] == 0x00 && p_buf[3] == 0xe8 &&
560         (p_buf[4] & 0xf0) == 0xf0 && p_buf[5] == 0x07 )
561     {
562         uint8_t conv_buf[DTS_HEADER_SIZE];
563         Buf14To16( conv_buf, p_buf, DTS_HEADER_SIZE, 1 );
564         i_frame_size = SyncInfo16be( conv_buf, &i_audio_mode, pi_sample_rate,
565                                      pi_bit_rate, pi_frame_length );
566         i_frame_size = i_frame_size * 8 / 14 * 2;
567     }
568     /* 14 bits, big endian version of the bitstream */
569     else if( p_buf[0] == 0x1f && p_buf[1] == 0xff &&
570              p_buf[2] == 0xe8 && p_buf[3] == 0x00 &&
571              p_buf[4] == 0x07 && (p_buf[5] & 0xf0) == 0xf0 )
572     {
573         uint8_t conv_buf[DTS_HEADER_SIZE];
574         Buf14To16( conv_buf, p_buf, DTS_HEADER_SIZE, 0 );
575         i_frame_size = SyncInfo16be( conv_buf, &i_audio_mode, pi_sample_rate,
576                                      pi_bit_rate, pi_frame_length );
577         i_frame_size = i_frame_size * 8 / 14 * 2;
578     }
579     /* 16 bits, big endian version of the bitstream */
580     else if( p_buf[0] == 0x7f && p_buf[1] == 0xfe &&
581              p_buf[2] == 0x80 && p_buf[3] == 0x01 )
582     {
583         i_frame_size = SyncInfo16be( p_buf, &i_audio_mode, pi_sample_rate,
584                                      pi_bit_rate, pi_frame_length );
585     }
586     /* 16 bits, little endian version of the bitstream */
587     else if( p_buf[0] == 0xfe && p_buf[1] == 0x7f &&
588              p_buf[2] == 0x01 && p_buf[3] == 0x80 )
589     {
590         uint8_t conv_buf[DTS_HEADER_SIZE];
591         BufLeToBe( conv_buf, p_buf, DTS_HEADER_SIZE );
592         i_frame_size = SyncInfo16be( p_buf, &i_audio_mode, pi_sample_rate,
593                                      pi_bit_rate, pi_frame_length );
594     }
595     else return 0;
596
597     switch( i_audio_mode & 0xFFFF )
598     {
599         case 0x0:
600             /* Mono */
601             *pi_channels_conf = AOUT_CHAN_CENTER;
602             break;
603         case 0x1:
604             /* Dual-mono = stereo + dual-mono */
605             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
606                            AOUT_CHAN_DUALMONO;
607             break;
608         case 0x2:
609         case 0x3:
610         case 0x4:
611             /* Stereo */
612             *pi_channels = 2;
613             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
614             break;
615         case 0x5:
616             /* 3F */
617             *pi_channels = 3;
618             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
619                                 AOUT_CHAN_CENTER;
620             break;
621         case 0x6:
622             /* 2F/1R */
623             *pi_channels = 3;
624             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
625                                 AOUT_CHAN_REARCENTER;
626             break;
627         case 0x7:
628             /* 3F/1R */
629             *pi_channels = 4;
630             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
631                                 AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER;
632             break;
633         case 0x8:
634             /* 2F2R */
635             *pi_channels = 4;
636             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
637                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
638             break;
639         case 0x9:
640             /* 3F2R */
641             *pi_channels = 5;
642             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
643                                 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
644                                 AOUT_CHAN_REARRIGHT;
645             break;
646         case 0xA:
647         case 0xB:
648             /* 2F2M2R */
649             *pi_channels = 6;
650             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
651                                 AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
652                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
653             break;
654         case 0xC:
655             /* 3F2M2R */
656             *pi_channels = 7;
657             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
658                                 AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT |
659                                 AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT |
660                                 AOUT_CHAN_REARRIGHT;
661             break;
662         case 0xD:
663         case 0xE:
664             /* 3F2M2R/LFE */
665             *pi_channels = 8;
666             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
667                                 AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT |
668                                 AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT |
669                                 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
670             break;
671
672         default:
673             if( i_audio_mode <= 63 )
674             {
675                 /* User defined */
676                 *pi_channels = 0;
677                 *pi_channels_conf = 0;
678             }
679             else return 0;
680             break;
681     }
682
683     if( i_audio_mode & 0x10000 )
684     {
685         (*pi_channels)++;
686         *pi_channels_conf |= AOUT_CHAN_LFE;
687     }
688
689     if( *pi_sample_rate >= sizeof( ppi_dts_samplerate ) /
690                            sizeof( ppi_dts_samplerate[0] ) )
691     {
692         return 0;
693     }
694     *pi_sample_rate = ppi_dts_samplerate[ *pi_sample_rate ];
695     if( !*pi_sample_rate ) return 0;
696
697     if( *pi_bit_rate >= sizeof( ppi_dts_bitrate ) /
698                         sizeof( ppi_dts_bitrate[0] ) )
699     {
700         return 0;
701     }
702     *pi_bit_rate = ppi_dts_bitrate[ *pi_bit_rate ];
703     if( !*pi_bit_rate ) return 0;
704
705     *pi_frame_length = (*pi_frame_length + 1) * 32;
706
707     return i_frame_size;
708 }