]> git.sesse.net Git - vlc/blob - modules/codec/dts.c
* ALL: Introduction of a new api for decoders.
[vlc] / modules / codec / dts.c
1 /*****************************************************************************
2  * dts.c: DTS basic parser
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: dts.c,v 1.4 2003/09/02 20:19:25 gbazin Exp $
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 <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>                                              /* memcpy() */
31 #include <fcntl.h>
32
33 #include <vlc/vlc.h>
34 #include <vlc/decoder.h>
35 #include <vlc/input.h>
36 #include <vlc/aout.h>
37 #include <vlc/sout.h>
38
39 #ifdef HAVE_UNISTD_H
40 #   include <unistd.h>
41 #endif
42
43 #define DTS_HEADER_SIZE 10
44
45 /*****************************************************************************
46  * decoder_sys_t : decoder descriptor
47  *****************************************************************************/
48 struct decoder_sys_t
49 {
50     /* Module mode */
51     vlc_bool_t b_packetizer;
52
53     /*
54      * Input properties
55      */
56     int     i_state;
57
58     uint8_t p_header[DTS_HEADER_SIZE];
59     int     i_header;
60
61     mtime_t pts;
62
63     int     i_frame_size;
64
65     /*
66      * Decoder output properties
67      */
68     aout_instance_t *     p_aout;                                  /* opaque */
69     aout_input_t *        p_aout_input;                            /* opaque */
70     audio_sample_format_t aout_format;
71     aout_buffer_t *       p_aout_buffer; /* current aout buffer being filled */
72     /* This is very hacky. For DTS over S/PDIF we apparently need to send
73      * 3 frames at a time. This should likely be moved to the output stage. */
74     int                   i_frames_in_buf;
75
76     /*
77      * Packetizer output properties
78      */
79     sout_packetizer_input_t *p_sout_input;
80     sout_format_t           sout_format;
81     sout_buffer_t *         p_sout_buffer;            /* current sout buffer */
82
83     /*
84      * Common properties
85      */
86     uint8_t               *p_out_buffer;                    /* output buffer */
87     int                   i_out_buffer;         /* position in output buffer */
88     audio_date_t          end_date;
89 };
90
91 enum {
92
93     STATE_NOSYNC,
94     STATE_PARTIAL_SYNC,
95     STATE_SYNC,
96     STATE_HEADER,
97     STATE_DATA
98 };
99
100 /****************************************************************************
101  * Local prototypes
102  ****************************************************************************/
103 static int  OpenDecoder   ( vlc_object_t * );
104 static int  OpenPacketizer( vlc_object_t * );
105
106 static int  InitDecoder   ( decoder_t * );
107 static int  RunDecoder    ( decoder_t *, block_t * );
108 static int  EndDecoder    ( decoder_t * );
109
110 static int  SyncInfo      ( const byte_t *, unsigned int *, unsigned int *,
111                             unsigned int *, unsigned int *, unsigned int * );
112
113 static int GetOutBuffer ( decoder_t *, uint8_t ** );
114 static int GetAoutBuffer( decoder_t *, aout_buffer_t ** );
115 static int GetSoutBuffer( decoder_t *, sout_buffer_t ** );
116 static int SendOutBuffer( decoder_t * );
117
118 /*****************************************************************************
119  * Module descriptor
120  *****************************************************************************/
121 vlc_module_begin();
122     set_description( _("DTS parser") );
123     set_capability( "decoder", 100 );
124     set_callbacks( OpenDecoder, NULL );
125
126     add_submodule();
127     set_description( _("DTS audio packetizer") );
128     set_capability( "packetizer", 10 );
129     set_callbacks( OpenPacketizer, NULL );
130 vlc_module_end();
131
132 /*****************************************************************************
133  * OpenDecoder: probe the decoder and return score
134  *****************************************************************************/
135 static int OpenDecoder( vlc_object_t *p_this )
136 {
137     decoder_t *p_dec = (decoder_t*)p_this;
138
139     if( p_dec->p_fifo->i_fourcc != VLC_FOURCC('d','t','s',' ')
140          && p_dec->p_fifo->i_fourcc != VLC_FOURCC('d','t','s','b') )
141     {
142         return VLC_EGENERIC;
143     }
144
145     p_dec->pf_init = InitDecoder;
146     p_dec->pf_decode = RunDecoder;
147     p_dec->pf_end = EndDecoder;
148
149     /* Allocate the memory needed to store the decoder's structure */
150     if( ( p_dec->p_sys =
151           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
152     {
153         msg_Err( p_dec, "out of memory" );
154         return VLC_EGENERIC;
155     }
156     p_dec->p_sys->b_packetizer = VLC_FALSE;
157
158     return VLC_SUCCESS;
159 }
160
161 static int OpenPacketizer( vlc_object_t *p_this )
162 {
163     decoder_t *p_dec = (decoder_t*)p_this;
164
165     int i_ret = OpenDecoder( p_this );
166
167     if( i_ret == VLC_SUCCESS ) p_dec->p_sys->b_packetizer = VLC_TRUE;
168
169     return i_ret;
170 }
171
172 /*****************************************************************************
173  * InitDecoder: Initalize the decoder
174  *****************************************************************************/
175 static int InitDecoder( decoder_t *p_dec )
176 {
177     p_dec->p_sys->i_state = STATE_NOSYNC;
178
179     p_dec->p_sys->p_out_buffer = NULL;
180     p_dec->p_sys->i_out_buffer = 0;
181     aout_DateSet( &p_dec->p_sys->end_date, 0 );
182
183     p_dec->p_sys->p_aout = NULL;
184     p_dec->p_sys->p_aout_input = NULL;
185     p_dec->p_sys->p_aout_buffer = NULL;
186     p_dec->p_sys->aout_format.i_format = VLC_FOURCC('d','t','s',' ');
187
188     p_dec->p_sys->p_sout_input = NULL;
189     p_dec->p_sys->p_sout_buffer = NULL;
190     p_dec->p_sys->sout_format.i_cat = AUDIO_ES;
191     p_dec->p_sys->sout_format.i_fourcc = VLC_FOURCC('d','t','s',' ');
192
193     return VLC_SUCCESS;
194 }
195
196 /****************************************************************************
197  * RunDecoder: the whole thing
198  ****************************************************************************
199  * This function is called just after the thread is launched.
200  ****************************************************************************/
201 static int RunDecoder( decoder_t *p_dec, block_t *p_block )
202 {
203     decoder_sys_t *p_sys = p_dec->p_sys;
204     int i, i_block_pos = 0;
205     mtime_t i_pts = p_block->i_pts;
206
207     while( i_block_pos < p_block->i_buffer )
208     {
209         switch( p_sys->i_state )
210         {
211         case STATE_NOSYNC:
212             /* Look for sync dword - should be 0x7ffe8001 */
213             while( i_block_pos < p_block->i_buffer &&
214                    p_block->p_buffer[i_block_pos] != 0x7f )
215             {
216                 i_block_pos++;
217             }
218
219             if( i_block_pos < p_block->i_buffer )
220             {
221                 p_sys->i_state = STATE_PARTIAL_SYNC;
222                 i_block_pos++;
223                 p_sys->p_header[0] = 0x7f;
224                 p_sys->i_header = 1;
225                 break;
226             }
227             break;
228
229         case STATE_PARTIAL_SYNC:
230             /* Get the full 4 sync bytes */
231             if( p_sys->i_header < 4 )
232             {
233                 int i_size = __MIN( 4 - p_sys->i_header,
234                                     p_block->i_buffer - i_block_pos );
235
236                 memcpy( p_sys->p_header + p_sys->i_header,
237                         p_block->p_buffer + i_block_pos, i_size );
238                 i_block_pos += i_size;
239                 p_sys->i_header += i_size;
240             }
241
242             if( p_sys->i_header < 4 )
243                 break;
244
245             if( p_sys->p_header[0] == 0x7f && p_sys->p_header[1] == 0xfe &&
246                 p_sys->p_header[2] == 0x80 && p_sys->p_header[3] == 0x01 )
247             {
248                 p_sys->i_state = STATE_SYNC;
249             }
250             else
251             {
252                 for( i = 1; i < 4; i++ )
253                 {
254                     if( p_sys->p_header[i] == 0x7f ) break;
255                 }
256
257                 if( p_sys->p_header[i] == 0x7f )
258                 {
259                     /* Potential new sync */
260                     p_sys->i_header -= i;
261                     memmove( p_sys->p_header, &p_sys->p_header[i],
262                              p_sys->i_header );
263                     break;
264                 }
265
266                 /* retry to sync*/
267                 p_sys->i_state = STATE_NOSYNC;
268             }
269             break;
270
271         case STATE_SYNC:
272             /* New frame, set the Presentation Time Stamp */
273             p_sys->pts = i_pts; i_pts = 0;
274             if( p_sys->pts != 0 &&
275                 p_sys->pts != aout_DateGet( &p_sys->end_date ) )
276             {
277                 aout_DateSet( &p_sys->end_date, p_sys->pts );
278             }
279             p_sys->i_state = STATE_HEADER;
280             break;
281
282         case STATE_HEADER:
283             /* Get DTS frame header (DTS_HEADER_SIZE bytes) */
284             if( p_sys->i_header < DTS_HEADER_SIZE )
285             {
286                 int i_size = __MIN( DTS_HEADER_SIZE - p_sys->i_header,
287                                     p_block->i_buffer - i_block_pos );
288
289                 memcpy( p_sys->p_header + p_sys->i_header,
290                         p_block->p_buffer + i_block_pos, i_size );
291                 i_block_pos += i_size;
292                 p_sys->i_header += i_size;
293             }
294
295             if( p_sys->i_header < DTS_HEADER_SIZE )
296                 break;
297
298             if( GetOutBuffer( p_dec, &p_sys->p_out_buffer )
299                 != VLC_SUCCESS )
300             {
301                 block_Release( p_block );
302                 return VLC_EGENERIC;
303             }
304
305             if( !p_sys->p_out_buffer )
306             {
307                 p_sys->i_state = STATE_NOSYNC;
308                 break;
309             }
310
311             memcpy( p_sys->p_out_buffer, p_sys->p_header, DTS_HEADER_SIZE );
312             p_sys->i_out_buffer = DTS_HEADER_SIZE;
313             p_sys->i_state = STATE_DATA;
314             break;
315
316         case STATE_DATA:
317             /* Copy the whole DTS frame into the aout buffer */
318             if( p_sys->i_out_buffer < p_sys->i_frame_size )
319             {
320                 int i_size = __MIN( p_sys->i_frame_size - p_sys->i_out_buffer,
321                                     p_block->i_buffer - i_block_pos );
322
323                 memcpy( p_sys->p_out_buffer + p_sys->i_out_buffer,
324                         p_block->p_buffer + i_block_pos, i_size );
325                 i_block_pos += i_size;
326                 p_sys->i_out_buffer += i_size;
327             }
328
329             if( p_sys->i_out_buffer < p_sys->i_frame_size )
330                 break; /* Need more data */
331
332             SendOutBuffer( p_dec );
333
334             p_sys->i_state = STATE_NOSYNC;
335             break;
336         }
337     }
338
339     block_Release( p_block );
340     return VLC_SUCCESS;
341 }
342
343 /*****************************************************************************
344  * EndDecoder: clean up the decoder
345  *****************************************************************************/
346 static int EndDecoder( decoder_t *p_dec )
347 {
348     if( p_dec->p_sys->p_aout_input != NULL )
349     {
350         if( p_dec->p_sys->p_aout_buffer )
351         {
352             aout_DecDeleteBuffer( p_dec->p_sys->p_aout,
353                                   p_dec->p_sys->p_aout_input,
354                                   p_dec->p_sys->p_aout_buffer );
355         }
356
357         aout_DecDelete( p_dec->p_sys->p_aout, p_dec->p_sys->p_aout_input );
358     }
359
360     if( p_dec->p_sys->p_sout_input != NULL )
361     {
362         if( p_dec->p_sys->p_sout_buffer )
363         {
364             sout_BufferDelete( p_dec->p_sys->p_sout_input->p_sout,
365                                p_dec->p_sys->p_sout_buffer );
366         }
367
368         sout_InputDelete( p_dec->p_sys->p_sout_input );
369     }
370
371     free( p_dec->p_sys );
372
373     return VLC_SUCCESS;
374 }
375
376 /*****************************************************************************
377  * GetOutBuffer:
378  *****************************************************************************/
379 static int GetOutBuffer ( decoder_t *p_dec, uint8_t **pp_out_buffer )
380 {
381     decoder_sys_t *p_sys = p_dec->p_sys;
382     int i_ret;
383
384     if( p_sys->b_packetizer )
385     {
386         i_ret= GetSoutBuffer( p_dec, &p_sys->p_sout_buffer );
387         *pp_out_buffer =
388             p_sys->p_sout_buffer ? p_sys->p_sout_buffer->p_buffer : NULL;
389     }
390     else
391     {
392         i_ret = GetAoutBuffer( p_dec, &p_sys->p_aout_buffer );
393         if( p_sys->i_frames_in_buf == 1 )
394             *pp_out_buffer = p_sys->p_aout_buffer ?
395                 p_sys->p_aout_buffer->p_buffer : NULL;
396         else
397             *pp_out_buffer = p_sys->p_aout_buffer ?
398                 p_sys->p_aout_buffer->p_buffer + p_sys->i_frame_size *
399                 (p_sys->i_frames_in_buf - 1) : NULL;
400     }
401
402     return i_ret;
403 }
404
405 /*****************************************************************************
406  * GetAoutBuffer:
407  *****************************************************************************/
408 static int GetAoutBuffer( decoder_t *p_dec, aout_buffer_t **pp_buffer )
409 {
410     int i_bit_rate;
411     unsigned int i_frame_length, i_rate, i_channels, i_channels_conf;
412
413     decoder_sys_t *p_sys = p_dec->p_sys;
414
415     /* Check if frame is valid and get frame info */
416     p_sys->i_frame_size = SyncInfo( p_sys->p_header,
417                                     &i_channels, &i_channels_conf,
418                                     &i_rate, &i_bit_rate, &i_frame_length );
419
420     if( !p_sys->i_frame_size )
421     {
422         msg_Warn( p_dec, "dts syncinfo failed" );
423         *pp_buffer = NULL;
424         return VLC_SUCCESS;
425     }
426
427     if( p_sys->p_aout_input != NULL && ( p_sys->aout_format.i_rate != i_rate
428         || p_sys->aout_format.i_original_channels != i_channels_conf
429         || (int)p_sys->aout_format.i_bytes_per_frame != p_sys->i_frame_size ) )
430     {
431         /* Parameters changed - this should not happen. */
432         aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
433         p_sys->p_aout_input = NULL;
434     }
435
436     /* Creating the audio input if not created yet. */
437     if( p_sys->p_aout_input == NULL )
438     {
439         p_sys->aout_format.i_rate = i_rate;
440         p_sys->aout_format.i_original_channels = i_channels_conf;
441         p_sys->aout_format.i_physical_channels
442             = i_channels_conf & AOUT_CHAN_PHYSMASK;
443         p_sys->aout_format.i_bytes_per_frame = p_sys->i_frame_size;
444         p_sys->aout_format.i_frame_length = i_frame_length;
445         aout_DateInit( &p_sys->end_date, i_rate );
446         aout_DateSet( &p_sys->end_date, p_sys->pts );
447         p_sys->i_frames_in_buf = 3;
448         p_sys->p_aout_input = aout_DecNew( p_dec,
449                                            &p_sys->p_aout,
450                                            &p_sys->aout_format );
451
452         if ( p_sys->p_aout_input == NULL )
453         {
454             *pp_buffer = NULL;
455             return VLC_SUCCESS;
456         }
457     }
458
459     if( !aout_DateGet( &p_sys->end_date ) )
460     {
461         /* We've just started the stream, wait for the first PTS. */
462         *pp_buffer = NULL;
463         return VLC_SUCCESS;
464     }
465
466     if( p_sys->i_frames_in_buf == 3 )
467     {
468         p_sys->i_frames_in_buf = 0;
469         *pp_buffer = aout_DecNewBuffer( p_sys->p_aout, p_sys->p_aout_input,
470                                         i_frame_length * 3 );
471         if( *pp_buffer == NULL )
472         {
473             return VLC_SUCCESS;
474         }
475
476         (*pp_buffer)->start_date = aout_DateGet( &p_sys->end_date );
477         (*pp_buffer)->end_date =
478              aout_DateIncrement( &p_sys->end_date, i_frame_length * 3 );
479     }
480
481     p_sys->i_frames_in_buf++;
482
483     return VLC_SUCCESS;
484 }
485
486 /*****************************************************************************
487  * GetSoutBuffer:
488  *****************************************************************************/
489 static int GetSoutBuffer( decoder_t *p_dec, sout_buffer_t **pp_buffer )
490 {
491     int i_bit_rate;
492     unsigned int i_frame_length, i_rate, i_channels, i_channels_conf;
493
494     decoder_sys_t *p_sys = p_dec->p_sys;
495
496     /* Check if frame is valid and get frame info */
497     p_sys->i_frame_size = SyncInfo( p_sys->p_header,
498                                     &i_channels, &i_channels_conf,
499                                     &i_rate, &i_bit_rate, &i_frame_length );
500
501     if( !p_sys->i_frame_size )
502     {
503         msg_Warn( p_dec, "dts syncinfo failed" );
504         *pp_buffer = NULL;
505         return VLC_SUCCESS;
506     }
507
508     if( p_sys->p_sout_input != NULL &&
509         ( p_sys->sout_format.i_sample_rate != (int)i_rate
510           || p_sys->sout_format.i_channels != (int)i_channels ) )
511     {
512         /* Parameters changed - this should not happen. */
513     }
514
515     /* Creating the sout input if not created yet. */
516     if( p_sys->p_sout_input == NULL )
517     {
518         p_sys->sout_format.i_sample_rate = i_rate;
519         p_sys->sout_format.i_channels    = i_channels;
520         p_sys->sout_format.i_block_align = 0;
521         p_sys->sout_format.i_bitrate     = i_bit_rate;
522         p_sys->sout_format.i_extra_data  = 0;
523         p_sys->sout_format.p_extra_data  = NULL;
524
525         aout_DateInit( &p_sys->end_date, i_rate );
526         aout_DateSet( &p_sys->end_date, p_sys->pts );
527
528         p_sys->p_sout_input = sout_InputNew( p_dec,
529                                              &p_sys->sout_format );
530
531         if( p_sys->p_sout_input == NULL )
532         {
533             msg_Err( p_dec, "cannot add a new stream" );
534             *pp_buffer = NULL;
535             return VLC_EGENERIC;
536         }
537         msg_Info( p_dec, "DTS channels:%d samplerate:%d bitrate:%d",
538                   i_channels, i_rate, i_bit_rate );
539     }
540
541     if( !aout_DateGet( &p_sys->end_date ) )
542     {
543         /* We've just started the stream, wait for the first PTS. */
544         *pp_buffer = NULL;
545         return VLC_SUCCESS;
546     }
547
548     *pp_buffer = sout_BufferNew( p_sys->p_sout_input->p_sout,
549                                  p_sys->i_frame_size );
550     if( *pp_buffer == NULL )
551     {
552         return VLC_SUCCESS;
553     }
554
555     (*pp_buffer)->i_pts =
556         (*pp_buffer)->i_dts = aout_DateGet( &p_sys->end_date );
557
558     (*pp_buffer)->i_length =
559         aout_DateIncrement( &p_sys->end_date, i_frame_length )
560         - (*pp_buffer)->i_pts;
561
562     return VLC_SUCCESS;
563 }
564
565 /*****************************************************************************
566  * SendOutBuffer:
567  *****************************************************************************/
568 static int SendOutBuffer( decoder_t *p_dec )
569 {
570     decoder_sys_t *p_sys = p_dec->p_sys;
571
572     if( p_sys->b_packetizer )
573     {
574         sout_InputSendBuffer( p_sys->p_sout_input, p_sys->p_sout_buffer );
575         p_sys->p_sout_buffer = NULL;
576     }
577     else if( p_sys->i_frames_in_buf == 3 )
578     {
579         /* We have all we need, send the buffer to the aout core. */
580         aout_DecPlay( p_sys->p_aout, p_sys->p_aout_input,
581                       p_sys->p_aout_buffer );
582         p_sys->p_aout_buffer = NULL;
583     }
584
585     return VLC_SUCCESS;
586 }
587
588 /*****************************************************************************
589  * SyncInfo: parse DTS sync info
590  *****************************************************************************/
591 static int SyncInfo( const byte_t * p_buf,
592                      unsigned int * pi_channels,
593                      unsigned int * pi_channels_conf,
594                      unsigned int * pi_sample_rate,
595                      unsigned int * pi_bit_rate,
596                      unsigned int * pi_frame_length )
597 {
598     unsigned int i_bit_rate;
599     unsigned int i_audio_mode;
600     unsigned int i_sample_rate;
601     unsigned int i_frame_size;
602     unsigned int i_frame_length;
603
604     static const unsigned int ppi_dts_samplerate[] =
605     {
606         0, 8000, 16000, 32000, 64000, 128000,
607         11025, 22050, 44010, 88020, 176400,
608         12000, 24000, 48000, 96000, 192000
609     };
610
611     static const unsigned int ppi_dts_bitrate[] =
612     {
613         32000, 56000, 64000, 96000, 112000, 128000,
614         192000, 224000, 256000, 320000, 384000,
615         448000, 512000, 576000, 640000, 768000,
616         896000, 1024000, 1152000, 1280000, 1344000,
617         1408000, 1411200, 1472000, 1536000, 1920000,
618         2048000, 3072000, 3840000, 4096000, 0, 0
619     };
620
621     if( (p_buf[0] != 0x7f) || (p_buf[1] != 0xfe) ||
622         (p_buf[2] != 0x80) || (p_buf[3] != 0x01) )
623     {
624         return( 0 );
625     }
626
627     i_frame_length = (p_buf[4] & 0x01) << 6 | (p_buf[5] >> 2);
628     i_frame_size = (p_buf[5] & 0x03) << 12 | (p_buf[6] << 4) |
629                    (p_buf[7] >> 4);
630
631     i_audio_mode = (p_buf[7] & 0x0f) << 2 | (p_buf[8] >> 6);
632     i_sample_rate = (p_buf[8] >> 2) & 0x0f;
633     i_bit_rate = (p_buf[8] & 0x03) << 3 | ((p_buf[9] >> 5) & 0x07);
634
635     switch( i_audio_mode )
636     {
637         case 0x0:
638             /* Mono */
639             *pi_channels_conf = AOUT_CHAN_CENTER;
640             break;
641         case 0x1:
642             /* Dual-mono = stereo + dual-mono */
643             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
644                            AOUT_CHAN_DUALMONO;
645             break;
646         case 0x2:
647         case 0x3:
648         case 0x4:
649             /* Stereo */
650             *pi_channels = 2;
651             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
652             break;
653         case 0x5:
654             /* 3F */
655             *pi_channels = 3;
656             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
657                                 AOUT_CHAN_CENTER;
658             break;
659         case 0x6:
660             /* 2F/LFE */
661             *pi_channels = 3;
662             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
663                                 AOUT_CHAN_LFE;
664             break;
665         case 0x7:
666             /* 3F/LFE */
667             *pi_channels = 4;
668             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
669                                 AOUT_CHAN_CENTER | AOUT_CHAN_LFE;
670             break;
671         case 0x8:
672             /* 2F2R */
673             *pi_channels = 4;
674             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
675                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
676             break;
677         case 0x9:
678             /* 3F2R */
679             *pi_channels = 5;
680             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
681                                 AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
682                                 AOUT_CHAN_REARRIGHT;
683             break;
684         case 0xA:
685         case 0xB:
686             /* 2F2M2R */
687             *pi_channels = 6;
688             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
689                                 AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT |
690                                 AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
691             break;
692         case 0xC:
693             /* 3F2M2R */
694             *pi_channels = 7;
695             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
696                                 AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT |
697                                 AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT |
698                                 AOUT_CHAN_REARRIGHT;
699             break;
700         case 0xD:
701         case 0xE:
702             /* 3F2M2R/LFE */
703             *pi_channels = 8;
704             *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
705                                 AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT |
706                                 AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT |
707                                 AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE;
708             break;
709
710         default:
711             if( i_audio_mode <= 63 )
712             {
713                 /* User defined */
714                 *pi_channels = 0;
715                 *pi_channels_conf = 0; 
716             }
717             else
718             {
719                 return( 0 );
720             }
721             break;
722     }
723
724     if( i_sample_rate >= sizeof( ppi_dts_samplerate ) /
725                          sizeof( ppi_dts_samplerate[0] ) )
726     {
727         return( 0 );
728     }
729
730     *pi_sample_rate = ppi_dts_samplerate[ i_sample_rate ];
731
732     if( i_bit_rate >= sizeof( ppi_dts_bitrate ) /
733                       sizeof( ppi_dts_bitrate[0] ) )
734     {
735         return( 0 );
736     }
737
738     *pi_bit_rate = ppi_dts_bitrate[ i_bit_rate ];
739
740     *pi_frame_length = (i_frame_length + 1) * 32;
741
742     return( i_frame_size + 1 );
743 }