]> git.sesse.net Git - vlc/blob - modules/codec/dts.c
Made es_format_t member i_bitrate unsigned int, because I cannot imagine it ever...
[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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <vlc/vlc.h>
29 #include <vlc/decoder.h>
30
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, NULL );
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( !aout_DateGet( &p_sys->end_date ) && !(*pp_block)->i_pts )
174     {
175         /* We've just started the stream, wait for the first PTS. */
176         block_Release( *pp_block );
177         return NULL;
178     }
179
180     if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
181     {
182         p_sys->i_state = STATE_NOSYNC;
183     }
184
185     block_BytestreamPush( &p_sys->bytestream, *pp_block );
186
187     while( 1 )
188     {
189         switch( p_sys->i_state )
190         {
191         case STATE_NOSYNC:
192             /* Look for sync code - should be 0x7ffe8001 */
193             while( block_PeekBytes( &p_sys->bytestream, p_header, 6 )
194                    == VLC_SUCCESS )
195             {
196                 if( SyncCode( p_header ) == VLC_SUCCESS )
197                 {
198                     p_sys->i_state = STATE_SYNC;
199                     break;
200                 }
201                 block_SkipByte( &p_sys->bytestream );
202             }
203             if( p_sys->i_state != STATE_SYNC )
204             {
205                 block_BytestreamFlush( &p_sys->bytestream );
206
207                 /* Need more data */
208                 return NULL;
209             }
210
211         case STATE_SYNC:
212             /* New frame, set the Presentation Time Stamp */
213             p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
214             if( p_sys->i_pts != 0 &&
215                 p_sys->i_pts != aout_DateGet( &p_sys->end_date ) )
216             {
217                 aout_DateSet( &p_sys->end_date, p_sys->i_pts );
218             }
219             p_sys->i_state = STATE_HEADER;
220
221         case STATE_HEADER:
222             /* Get DTS frame header (DTS_HEADER_SIZE bytes) */
223             if( block_PeekBytes( &p_sys->bytestream, p_header,
224                                  DTS_HEADER_SIZE ) != VLC_SUCCESS )
225             {
226                 /* Need more data */
227                 return NULL;
228             }
229
230             /* Check if frame is valid and get frame info */
231             p_sys->i_frame_size = SyncInfo( p_header,
232                                             &p_sys->i_channels,
233                                             &p_sys->i_channels_conf,
234                                             &p_sys->i_rate,
235                                             &p_sys->i_bit_rate,
236                                             &p_sys->i_frame_length );
237             if( !p_sys->i_frame_size )
238             {
239                 msg_Dbg( p_dec, "emulated sync word" );
240                 block_SkipByte( &p_sys->bytestream );
241                 p_sys->i_state = STATE_NOSYNC;
242                 break;
243             }
244             p_sys->i_state = STATE_NEXT_SYNC;
245
246         case STATE_NEXT_SYNC:
247             /* TODO: If pp_block == NULL, flush the buffer without checking the
248              * next sync word */
249
250             /* Check if next expected frame contains the sync word */
251             if( block_PeekOffsetBytes( &p_sys->bytestream,
252                                        p_sys->i_frame_size, p_header, 6 )
253                 != VLC_SUCCESS )
254             {
255                 /* Need more data */
256                 return NULL;
257             }
258
259             if( SyncCode( p_header ) != VLC_SUCCESS )
260             {
261                 msg_Dbg( p_dec, "emulated sync word "
262                          "(no sync on following frame): %2.2x%2.2x%2.2x%2.2x",
263                          (int)p_header[0], (int)p_header[1],
264                          (int)p_header[2], (int)p_header[3] );
265                 p_sys->i_state = STATE_NOSYNC;
266                 block_SkipByte( &p_sys->bytestream );
267                 break;
268             }
269             p_sys->i_state = STATE_SEND_DATA;
270             break;
271
272         case STATE_GET_DATA:
273             /* Make sure we have enough data.
274              * (Not useful if we went through NEXT_SYNC) */
275             if( block_WaitBytes( &p_sys->bytestream,
276                                  p_sys->i_frame_size ) != VLC_SUCCESS )
277             {
278                 /* Need more data */
279                 return NULL;
280             }
281             p_sys->i_state = STATE_SEND_DATA;
282
283         case STATE_SEND_DATA:
284             if( !(p_buf = GetOutBuffer( p_dec, &p_out_buffer )) )
285             {
286                 //p_dec->b_error = VLC_TRUE;
287                 return NULL;
288             }
289
290             /* Copy the whole frame into the buffer. When we reach this point
291              * we already know we have enough data available. */
292             block_GetBytes( &p_sys->bytestream, p_buf, p_sys->i_frame_size );
293
294             /* Make sure we don't reuse the same pts twice */
295             if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
296                 p_sys->i_pts = p_sys->bytestream.p_block->i_pts = 0;
297
298             p_sys->i_state = STATE_NOSYNC;
299
300             /* So p_block doesn't get re-added several times */
301             *pp_block = block_BytestreamPop( &p_sys->bytestream );
302
303             return p_out_buffer;
304         }
305     }
306
307     return NULL;
308 }
309
310 /*****************************************************************************
311  * CloseDecoder: clean up the decoder
312  *****************************************************************************/
313 static void CloseDecoder( vlc_object_t *p_this )
314 {
315     decoder_t *p_dec = (decoder_t*)p_this;
316     decoder_sys_t *p_sys = p_dec->p_sys;
317
318     block_BytestreamRelease( &p_sys->bytestream );
319
320     free( p_sys );
321 }
322
323 /*****************************************************************************
324  * GetOutBuffer:
325  *****************************************************************************/
326 static uint8_t *GetOutBuffer( decoder_t *p_dec, void **pp_out_buffer )
327 {
328     decoder_sys_t *p_sys = p_dec->p_sys;
329     uint8_t *p_buf;
330
331     if( p_dec->fmt_out.audio.i_rate != p_sys->i_rate )
332     {
333         msg_Info( p_dec, "DTS channels:%d samplerate:%d bitrate:%d",
334                   p_sys->i_channels, p_sys->i_rate, p_sys->i_bit_rate );
335
336         aout_DateInit( &p_sys->end_date, p_sys->i_rate );
337         aout_DateSet( &p_sys->end_date, p_sys->i_pts );
338     }
339
340     p_dec->fmt_out.audio.i_rate     = p_sys->i_rate;
341     p_dec->fmt_out.audio.i_channels = p_sys->i_channels;
342     /* Hack for DTS S/PDIF filter which needs to pad the DTS frames */
343     p_dec->fmt_out.audio.i_bytes_per_frame =
344         __MAX( p_sys->i_frame_size, p_sys->i_frame_length * 4 );
345     p_dec->fmt_out.audio.i_frame_length = p_sys->i_frame_length;
346
347     p_dec->fmt_out.audio.i_original_channels = p_sys->i_channels_conf;
348     p_dec->fmt_out.audio.i_physical_channels =
349         p_sys->i_channels_conf & AOUT_CHAN_PHYSMASK;
350
351     p_dec->fmt_out.i_bitrate = p_sys->i_bit_rate;
352
353     if( p_sys->b_packetizer )
354     {
355         block_t *p_sout_buffer = GetSoutBuffer( p_dec );
356         p_buf = p_sout_buffer ? p_sout_buffer->p_buffer : NULL;
357         *pp_out_buffer = p_sout_buffer;
358     }
359     else
360     {
361         aout_buffer_t *p_aout_buffer = GetAoutBuffer( p_dec );
362         p_buf = p_aout_buffer ? p_aout_buffer->p_buffer : NULL;
363         *pp_out_buffer = p_aout_buffer;
364     }
365
366     return p_buf;
367 }
368
369 /*****************************************************************************
370  * GetAoutBuffer:
371  *****************************************************************************/
372 static aout_buffer_t *GetAoutBuffer( decoder_t *p_dec )
373 {
374     decoder_sys_t *p_sys = p_dec->p_sys;
375     aout_buffer_t *p_buf;
376
377     /* Hack for DTS S/PDIF filter which needs to send 3 frames at a time
378      * (plus a few header bytes) */
379     p_buf = p_dec->pf_aout_buffer_new( p_dec, p_sys->i_frame_length * 4 );
380     if( p_buf == NULL ) return NULL;
381     p_buf->i_nb_samples = p_sys->i_frame_length;
382     p_buf->i_nb_bytes = p_sys->i_frame_size;
383
384     p_buf->start_date = aout_DateGet( &p_sys->end_date );
385     p_buf->end_date =
386         aout_DateIncrement( &p_sys->end_date, p_sys->i_frame_length );
387
388     return p_buf;
389 }
390
391 /*****************************************************************************
392  * GetSoutBuffer:
393  *****************************************************************************/
394 static block_t *GetSoutBuffer( decoder_t *p_dec )
395 {
396     decoder_sys_t *p_sys = p_dec->p_sys;
397     block_t *p_block;
398
399     p_block = block_New( p_dec, p_sys->i_frame_size );
400     if( p_block == NULL ) return NULL;
401
402     p_block->i_pts = p_block->i_dts = aout_DateGet( &p_sys->end_date );
403
404     p_block->i_length = aout_DateIncrement( &p_sys->end_date,
405         p_sys->i_frame_length ) - p_block->i_pts;
406
407     return p_block;
408 }
409
410 /*****************************************************************************
411  * SyncInfo: parse DTS sync info
412  *****************************************************************************/
413 static const unsigned int ppi_dts_samplerate[] =
414 {
415     0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0,
416     12000, 24000, 48000, 96000, 192000
417 };
418
419 static const unsigned int ppi_dts_bitrate[] =
420 {
421     32000, 56000, 64000, 96000, 112000, 128000,
422     192000, 224000, 256000, 320000, 384000,
423     448000, 512000, 576000, 640000, 768000,
424     896000, 1024000, 1152000, 1280000, 1344000,
425     1408000, 1411200, 1472000, 1536000, 1920000,
426     2048000, 3072000, 3840000, 1/*open*/, 2/*variable*/, 3/*lossless*/
427 };
428
429 static int SyncInfo16be( const uint8_t *p_buf,
430                          unsigned int *pi_audio_mode,
431                          unsigned int *pi_sample_rate,
432                          unsigned int *pi_bit_rate,
433                          unsigned int *pi_frame_length )
434 {
435     unsigned int i_frame_size;
436     unsigned int i_lfe;
437
438     *pi_frame_length = (p_buf[4] & 0x01) << 6 | (p_buf[5] >> 2);
439     i_frame_size = (p_buf[5] & 0x03) << 12 | (p_buf[6] << 4) |
440                    (p_buf[7] >> 4);
441
442     *pi_audio_mode = (p_buf[7] & 0x0f) << 2 | (p_buf[8] >> 6);
443     *pi_sample_rate = (p_buf[8] >> 2) & 0x0f;
444     *pi_bit_rate = (p_buf[8] & 0x03) << 3 | ((p_buf[9] >> 5) & 0x07);
445
446     i_lfe = (p_buf[10] >> 1) & 0x03;
447     if( i_lfe ) *pi_audio_mode |= 0x10000;
448
449     return i_frame_size + 1;
450 }
451
452 static void BufLeToBe( uint8_t *p_out, const uint8_t *p_in, int i_in )
453 {
454     int i;
455
456     for( i = 0; i < i_in/2; i++  )
457     {
458         p_out[i*2] = p_in[i*2+1];
459         p_out[i*2+1] = p_in[i*2];
460     }
461 }
462
463 static int Buf14To16( uint8_t *p_out, const uint8_t *p_in, int i_in, int i_le )
464 {
465     unsigned char tmp, cur = 0;
466     int bits_in, bits_out = 0;
467     int i, i_out = 0;
468
469     for( i = 0; i < i_in; i++  )
470     {
471         if( i%2 )
472         {
473             tmp = p_in[i-i_le];
474             bits_in = 8;
475         }
476         else
477         {
478             tmp = p_in[i+i_le] & 0x3F;
479             bits_in = 8 - 2;
480         }
481
482         if( bits_out < 8 )
483         {
484             int need = __MIN( 8 - bits_out, bits_in );
485             cur <<= need;
486             cur |= ( tmp >> (bits_in - need) );
487             tmp <<= (8 - bits_in + need);
488             tmp >>= (8 - bits_in + need);
489             bits_in -= need;
490             bits_out += need;
491         }
492
493         if( bits_out == 8 )
494         {
495             p_out[i_out] = cur;
496             cur = 0;
497             bits_out = 0;
498             i_out++;
499         }
500
501         bits_out += bits_in;
502         cur <<= bits_in;
503         cur |= tmp;
504     }
505
506     return i_out;
507 }
508
509 static inline int SyncCode( const uint8_t *p_buf )
510 {
511     /* 14 bits, little endian version of the bitstream */
512     if( p_buf[0] == 0xff && p_buf[1] == 0x1f &&
513         p_buf[2] == 0x00 && p_buf[3] == 0xe8 &&
514         (p_buf[4] & 0xf0) == 0xf0 && p_buf[5] == 0x07 )
515     {
516         return VLC_SUCCESS;
517     }
518     /* 14 bits, big endian version of the bitstream */
519     else if( p_buf[0] == 0x1f && p_buf[1] == 0xff &&
520              p_buf[2] == 0xe8 && p_buf[3] == 0x00 &&
521              p_buf[4] == 0x07 && (p_buf[5] & 0xf0) == 0xf0 )
522     {
523         return VLC_SUCCESS;
524     }
525     /* 16 bits, big endian version of the bitstream */
526     else if( p_buf[0] == 0x7f && p_buf[1] == 0xfe &&
527              p_buf[2] == 0x80 && p_buf[3] == 0x01 )
528     {
529         return VLC_SUCCESS;
530     }
531     /* 16 bits, little endian version of the bitstream */
532     else if( p_buf[0] == 0xfe && p_buf[1] == 0x7f &&
533              p_buf[2] == 0x01 && p_buf[3] == 0x80 )
534     {
535         return VLC_SUCCESS;
536     }
537     else return VLC_EGENERIC;
538 }
539
540 static int SyncInfo( const uint8_t *p_buf,
541                      unsigned int *pi_channels,
542                      unsigned int *pi_channels_conf,
543                      unsigned int *pi_sample_rate,
544                      unsigned int *pi_bit_rate,
545                      unsigned int *pi_frame_length )
546 {
547     unsigned int i_audio_mode;
548     unsigned int i_frame_size;
549
550     /* 14 bits, little endian version of the bitstream */
551     if( p_buf[0] == 0xff && p_buf[1] == 0x1f &&
552         p_buf[2] == 0x00 && p_buf[3] == 0xe8 &&
553         (p_buf[4] & 0xf0) == 0xf0 && p_buf[5] == 0x07 )
554     {
555         uint8_t conv_buf[DTS_HEADER_SIZE];
556         Buf14To16( conv_buf, p_buf, DTS_HEADER_SIZE, 1 );
557         i_frame_size = SyncInfo16be( conv_buf, &i_audio_mode, pi_sample_rate,
558                                      pi_bit_rate, pi_frame_length );
559         i_frame_size = i_frame_size * 8 / 14 * 2;
560     }
561     /* 14 bits, big endian version of the bitstream */
562     else if( p_buf[0] == 0x1f && p_buf[1] == 0xff &&
563              p_buf[2] == 0xe8 && p_buf[3] == 0x00 &&
564              p_buf[4] == 0x07 && (p_buf[5] & 0xf0) == 0xf0 )
565     {
566         uint8_t conv_buf[DTS_HEADER_SIZE];
567         Buf14To16( conv_buf, p_buf, DTS_HEADER_SIZE, 0 );
568         i_frame_size = SyncInfo16be( conv_buf, &i_audio_mode, pi_sample_rate,
569                                      pi_bit_rate, pi_frame_length );
570         i_frame_size = i_frame_size * 8 / 14 * 2;
571     }
572     /* 16 bits, big endian version of the bitstream */
573     else if( p_buf[0] == 0x7f && p_buf[1] == 0xfe &&
574              p_buf[2] == 0x80 && p_buf[3] == 0x01 )
575     {
576         i_frame_size = SyncInfo16be( p_buf, &i_audio_mode, pi_sample_rate,
577                                      pi_bit_rate, pi_frame_length );
578     }
579     /* 16 bits, little endian version of the bitstream */
580     else if( p_buf[0] == 0xfe && p_buf[1] == 0x7f &&
581              p_buf[2] == 0x01 && p_buf[3] == 0x80 )
582     {
583         uint8_t conv_buf[DTS_HEADER_SIZE];
584         BufLeToBe( conv_buf, p_buf, DTS_HEADER_SIZE );
585         i_frame_size = SyncInfo16be( p_buf, &i_audio_mode, pi_sample_rate,
586                                      pi_bit_rate, pi_frame_length );
587     }
588     else return 0;
589
590     switch( i_audio_mode & 0xFFFF )
591     {
592         case 0x0:
593             /* Mono */
594             *pi_channels_conf = AOUT_CHAN_CENTER;
595             break;
596         case 0x1:
597             /* Dual-mono = stereo + dual-mono */
598             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
599                            AOUT_CHAN_DUALMONO;
600             break;
601         case 0x2:
602         case 0x3:
603         case 0x4:
604             /* Stereo */
605             *pi_channels = 2;
606             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
607             break;
608         case 0x5:
609             /* 3F */
610             *pi_channels = 3;
611             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
612                                 AOUT_CHAN_CENTER;
613             break;
614         case 0x6:
615             /* 2F/1R */
616             *pi_channels = 3;
617             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
618                                 AOUT_CHAN_REARCENTER;
619             break;
620         case 0x7:
621             /* 3F/1R */
622             *pi_channels = 4;
623             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
624                                 AOUT_CHAN_CENTER | AOUT_CHAN_REARCENTER;
625             break;
626         case 0x8:
627             /* 2F2R */
628             *pi_channels = 4;
629             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
630                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
631             break;
632         case 0x9:
633             /* 3F2R */
634             *pi_channels = 5;
635             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
636                                 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
637                                 AOUT_CHAN_REARRIGHT;
638             break;
639         case 0xA:
640         case 0xB:
641             /* 2F2M2R */
642             *pi_channels = 6;
643             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
644                                 AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
645                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
646             break;
647         case 0xC:
648             /* 3F2M2R */
649             *pi_channels = 7;
650             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
651                                 AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT |
652                                 AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT |
653                                 AOUT_CHAN_REARRIGHT;
654             break;
655         case 0xD:
656         case 0xE:
657             /* 3F2M2R/LFE */
658             *pi_channels = 8;
659             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
660                                 AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT |
661                                 AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT |
662                                 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
663             break;
664
665         default:
666             if( i_audio_mode <= 63 )
667             {
668                 /* User defined */
669                 *pi_channels = 0;
670                 *pi_channels_conf = 0;
671             }
672             else return 0;
673             break;
674     }
675
676     if( i_audio_mode & 0x10000 )
677     {
678         (*pi_channels)++;
679         *pi_channels_conf |= AOUT_CHAN_LFE;
680     }
681
682     if( *pi_sample_rate >= sizeof( ppi_dts_samplerate ) /
683                            sizeof( ppi_dts_samplerate[0] ) )
684     {
685         return 0;
686     }
687     *pi_sample_rate = ppi_dts_samplerate[ *pi_sample_rate ];
688     if( !*pi_sample_rate ) return 0;
689
690     if( *pi_bit_rate >= sizeof( ppi_dts_bitrate ) /
691                         sizeof( ppi_dts_bitrate[0] ) )
692     {
693         return 0;
694     }
695     *pi_bit_rate = ppi_dts_bitrate[ *pi_bit_rate ];
696     if( !*pi_bit_rate ) return 0;
697
698     *pi_frame_length = (*pi_frame_length + 1) * 32;
699
700     return i_frame_size;
701 }