]> git.sesse.net Git - vlc/blob - modules/codec/a52.c
* modules/codec/a52.c: fixes and simplifications.
[vlc] / modules / codec / a52.c
1 /*****************************************************************************
2  * a52.c: A/52 basic parser
3  *****************************************************************************
4  * Copyright (C) 2001-2002 VideoLAN
5  * $Id: a52.c,v 1.26 2003/10/01 18:32:13 gbazin Exp $
6  *
7  * Authors: Stéphane Borel <stef@via.ecp.fr>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *          Gildas Bazin <gbazin@netcourrier.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>                                              /* memcpy() */
32 #include <fcntl.h>
33
34 #include <vlc/vlc.h>
35 #include <vlc/decoder.h>
36 #include <vlc/input.h>
37 #include <vlc/aout.h>
38 #include <vlc/sout.h>
39
40 #ifdef HAVE_UNISTD_H
41 #   include <unistd.h>
42 #endif
43
44 #include "vlc_block_helper.h"
45
46 #define A52_HEADER_SIZE 7
47
48 /*****************************************************************************
49  * decoder_sys_t : decoder descriptor
50  *****************************************************************************/
51 struct decoder_sys_t
52 {
53     /* Module mode */
54     vlc_bool_t b_packetizer;
55
56     /*
57      * Input properties
58      */
59     int        i_state;
60     vlc_bool_t b_synchro;
61
62     block_t *p_chain;
63     block_bytestream_t bytestream;
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
73     /*
74      * Packetizer output properties
75      */
76     sout_packetizer_input_t *p_sout_input;
77     sout_format_t           sout_format;
78     sout_buffer_t *         p_sout_buffer;            /* current sout buffer */
79
80     /*
81      * Common properties
82      */
83     uint8_t               *p_out_buffer;                    /* output buffer */
84     audio_date_t          end_date;
85
86     mtime_t pts;
87     int i_frame_size, i_bit_rate;
88     unsigned int i_rate, i_channels, i_channels_conf;
89
90 };
91
92 enum {
93
94     STATE_NOSYNC,
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 *, int *, int *, int *,int * );
111
112 static int GetOutBuffer ( decoder_t *, uint8_t ** );
113 static int GetAoutBuffer( decoder_t *, aout_buffer_t ** );
114 static int GetSoutBuffer( decoder_t *, sout_buffer_t ** );
115 static int SendOutBuffer( decoder_t * );
116
117 /*****************************************************************************
118  * Module descriptor
119  *****************************************************************************/
120 vlc_module_begin();
121     set_description( _("A/52 parser") );
122     set_capability( "decoder", 100 );
123     set_callbacks( OpenDecoder, NULL );
124
125     add_submodule();
126     set_description( _("A/52 audio packetizer") );
127     set_capability( "packetizer", 10 );
128     set_callbacks( OpenPacketizer, NULL );
129 vlc_module_end();
130
131 /*****************************************************************************
132  * OpenDecoder: probe the decoder and return score
133  *****************************************************************************/
134 static int OpenDecoder( vlc_object_t *p_this )
135 {
136     decoder_t *p_dec = (decoder_t*)p_this;
137
138     if( p_dec->p_fifo->i_fourcc != VLC_FOURCC('a','5','2',' ')
139          && p_dec->p_fifo->i_fourcc != VLC_FOURCC('a','5','2','b') )
140     {
141         return VLC_EGENERIC;
142     }
143
144     p_dec->pf_init = InitDecoder;
145     p_dec->pf_decode = RunDecoder;
146     p_dec->pf_end = EndDecoder;
147
148     /* Allocate the memory needed to store the decoder's structure */
149     if( ( p_dec->p_sys =
150           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
151     {
152         msg_Err( p_dec, "out of memory" );
153         return VLC_EGENERIC;
154     }
155     p_dec->p_sys->b_packetizer = VLC_FALSE;
156
157     return VLC_SUCCESS;
158 }
159
160 static int OpenPacketizer( vlc_object_t *p_this )
161 {
162     decoder_t *p_dec = (decoder_t*)p_this;
163
164     int i_ret = OpenDecoder( p_this );
165
166     if( i_ret == VLC_SUCCESS ) p_dec->p_sys->b_packetizer = VLC_TRUE;
167
168     return i_ret;
169 }
170
171 /*****************************************************************************
172  * InitDecoder: Initalize the decoder
173  *****************************************************************************/
174 static int InitDecoder( decoder_t *p_dec )
175 {
176     p_dec->p_sys->i_state = STATE_NOSYNC;
177     p_dec->p_sys->b_synchro = VLC_FALSE;
178
179     p_dec->p_sys->p_out_buffer = NULL;
180     aout_DateSet( &p_dec->p_sys->end_date, 0 );
181
182     p_dec->p_sys->p_aout = NULL;
183     p_dec->p_sys->p_aout_input = NULL;
184     p_dec->p_sys->p_aout_buffer = NULL;
185     p_dec->p_sys->aout_format.i_format = VLC_FOURCC('a','5','2',' ');
186
187     p_dec->p_sys->p_sout_input = NULL;
188     p_dec->p_sys->p_sout_buffer = NULL;
189     p_dec->p_sys->sout_format.i_cat = AUDIO_ES;
190     p_dec->p_sys->sout_format.i_fourcc = VLC_FOURCC( 'a', '5', '2', ' ' );
191
192     p_dec->p_sys->p_chain = NULL;
193
194     return VLC_SUCCESS;
195 }
196
197 /****************************************************************************
198  * RunDecoder: the whole thing
199  ****************************************************************************
200  * This function is called just after the thread is launched.
201  ****************************************************************************/
202 static int RunDecoder( decoder_t *p_dec, block_t *p_block )
203 {
204     decoder_sys_t *p_sys = p_dec->p_sys;
205     uint8_t p_header[A52_HEADER_SIZE];
206
207     if( !aout_DateGet( &p_sys->end_date ) && !p_block->i_pts )
208     {
209         /* We've just started the stream, wait for the first PTS. */
210         block_Release( p_block );
211         return VLC_SUCCESS;
212     }
213
214     if( p_sys->p_chain )
215     {
216         block_ChainAppend( &p_sys->p_chain, p_block );
217     }
218     else
219     {
220         block_ChainAppend( &p_sys->p_chain, p_block );
221         p_sys->bytestream = block_BytestreamInit( p_dec, p_sys->p_chain, 0 );
222     }
223
224     while( 1 )
225     {
226         switch( p_sys->i_state )
227         {
228
229         case STATE_NOSYNC:
230             while( block_PeekBytes( &p_sys->bytestream, p_header, 2 )
231                    == VLC_SUCCESS )
232             {
233                 if( p_header[0] == 0x0b && p_header[1] == 0x77 )
234                 {
235                     p_sys->i_state = STATE_SYNC;
236                     break;
237                 }
238                 block_SkipByte( &p_sys->bytestream );
239                 p_sys->b_synchro = VLC_FALSE;
240             }
241             if( p_sys->i_state != STATE_SYNC )
242             {
243                 block_ChainRelease( p_sys->p_chain );
244                 p_sys->p_chain = NULL;
245
246                 /* Need more data */
247                 return VLC_SUCCESS;
248             }
249
250         case STATE_SYNC:
251             /* New frame, set the Presentation Time Stamp */
252             p_sys->pts = p_sys->bytestream.p_block->i_pts;
253             if( p_sys->pts != 0 &&
254                 p_sys->pts != aout_DateGet( &p_sys->end_date ) )
255             {
256                 aout_DateSet( &p_sys->end_date, p_sys->pts );
257             }
258             p_sys->i_state = STATE_HEADER;
259             break;
260
261         case STATE_HEADER:
262             /* Get A/52 frame header (A52_HEADER_SIZE bytes) */
263             if( block_PeekBytes( &p_sys->bytestream, p_header,
264                                  A52_HEADER_SIZE ) != VLC_SUCCESS )
265             {
266                 /* Need more data */
267                 return VLC_SUCCESS;
268             }
269
270             /* Check if frame is valid and get frame info */
271             p_sys->i_frame_size = SyncInfo( p_header,
272                                             &p_sys->i_channels,
273                                             &p_sys->i_channels_conf,
274                                             &p_sys->i_rate,
275                                             &p_sys->i_bit_rate );
276             if( !p_sys->i_frame_size )
277             {
278                 msg_Dbg( p_dec, "emulated sync word" );
279                 block_SkipByte( &p_sys->bytestream );
280                 p_sys->i_state = STATE_NOSYNC;
281                 p_sys->b_synchro = VLC_FALSE;
282                 break;
283             }
284             p_sys->i_state = STATE_DATA;
285
286         case STATE_DATA:
287             /* TODO: If p_block == NULL, flush the buffer without checking the
288              * next sync word */
289
290             if( !p_sys->b_synchro )
291             {
292                 /* Check if next expected frame contains the sync word */
293                 if( block_PeekOffsetBytes( &p_sys->bytestream,
294                                            p_sys->i_frame_size, p_header, 2 )
295                     != VLC_SUCCESS )
296                 {
297                     /* Need more data */
298                     return VLC_SUCCESS;
299                 }
300
301                 if( p_header[0] != 0x0b || p_header[1] != 0x77 )
302                 {
303                     msg_Dbg( p_dec, "emulated sync word "
304                              "(no sync on following frame)" );
305                     p_sys->i_state = STATE_NOSYNC;
306                     block_SkipByte( &p_sys->bytestream );
307                     p_sys->b_synchro = VLC_FALSE;
308                     break;
309                 }
310             }
311
312             if( !p_sys->p_out_buffer )
313             if( GetOutBuffer( p_dec, &p_sys->p_out_buffer ) != VLC_SUCCESS )
314             {
315                 return VLC_EGENERIC;
316             }
317
318             /* Copy the whole frame into the buffer */
319             if( block_GetBytes( &p_sys->bytestream, p_sys->p_out_buffer,
320                                 p_sys->i_frame_size ) != VLC_SUCCESS )
321             {
322                 /* Need more data */
323                 return VLC_SUCCESS;
324             }
325
326             p_sys->p_chain = block_BytestreamFlush( &p_sys->bytestream );
327
328             SendOutBuffer( p_dec );
329             p_sys->i_state = STATE_NOSYNC;
330             p_sys->b_synchro = VLC_TRUE;
331
332             /* Make sure we don't reuse the same pts twice */
333             if( p_sys->pts == p_sys->bytestream.p_block->i_pts )
334                 p_sys->pts = p_sys->bytestream.p_block->i_pts = 0;
335         }
336     }
337
338     return VLC_SUCCESS;
339 }
340
341 /*****************************************************************************
342  * EndDecoder: clean up the decoder
343  *****************************************************************************/
344 static int EndDecoder( decoder_t *p_dec )
345 {
346     if( p_dec->p_sys->p_aout_input != NULL )
347     {
348         if( p_dec->p_sys->p_aout_buffer )
349         {
350             aout_DecDeleteBuffer( p_dec->p_sys->p_aout,
351                                   p_dec->p_sys->p_aout_input,
352                                   p_dec->p_sys->p_aout_buffer );
353         }
354
355         aout_DecDelete( p_dec->p_sys->p_aout, p_dec->p_sys->p_aout_input );
356     }
357
358     if( p_dec->p_sys->p_sout_input != NULL )
359     {
360         if( p_dec->p_sys->p_sout_buffer )
361         {
362             sout_BufferDelete( p_dec->p_sys->p_sout_input->p_sout,
363                                p_dec->p_sys->p_sout_buffer );
364         }
365
366         sout_InputDelete( p_dec->p_sys->p_sout_input );
367     }
368
369     if( p_dec->p_sys->p_chain ) block_ChainRelease( p_dec->p_sys->p_chain );
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         *pp_out_buffer =
394             p_sys->p_aout_buffer ? p_sys->p_aout_buffer->p_buffer : NULL;
395     }
396
397     return i_ret;
398 }
399
400 /*****************************************************************************
401  * GetAoutBuffer:
402  *****************************************************************************/
403 static int GetAoutBuffer( decoder_t *p_dec, aout_buffer_t **pp_buffer )
404 {
405     decoder_sys_t *p_sys = p_dec->p_sys;
406
407     if( p_sys->p_aout_input != NULL &&
408         ( p_sys->aout_format.i_rate != p_sys->i_rate
409         || p_sys->aout_format.i_original_channels != p_sys->i_channels_conf
410         || (int)p_sys->aout_format.i_bytes_per_frame != p_sys->i_frame_size ) )
411     {
412         /* Parameters changed - this should not happen. */
413         aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
414         p_sys->p_aout_input = NULL;
415     }
416
417     /* Creating the audio input if not created yet. */
418     if( p_sys->p_aout_input == NULL )
419     {
420         p_sys->aout_format.i_rate = p_sys->i_rate;
421         p_sys->aout_format.i_original_channels = p_sys->i_channels_conf;
422         p_sys->aout_format.i_physical_channels
423             = p_sys->i_channels_conf & AOUT_CHAN_PHYSMASK;
424         p_sys->aout_format.i_bytes_per_frame = p_sys->i_frame_size;
425         p_sys->aout_format.i_frame_length = A52_FRAME_NB;
426         aout_DateInit( &p_sys->end_date, p_sys->i_rate );
427         aout_DateSet( &p_sys->end_date, p_sys->pts );
428         p_sys->p_aout_input = aout_DecNew( p_dec,
429                                            &p_sys->p_aout,
430                                            &p_sys->aout_format );
431         if( p_sys->p_aout_input == NULL )
432         {
433             *pp_buffer = NULL;
434             return VLC_EGENERIC;
435         }
436     }
437
438     *pp_buffer = aout_DecNewBuffer( p_sys->p_aout, p_sys->p_aout_input,
439                                     A52_FRAME_NB );
440     if( *pp_buffer == NULL )
441     {
442         return VLC_EGENERIC;
443     }
444
445     (*pp_buffer)->start_date = aout_DateGet( &p_sys->end_date );
446     (*pp_buffer)->end_date =
447          aout_DateIncrement( &p_sys->end_date, A52_FRAME_NB );
448
449     return VLC_SUCCESS;
450 }
451
452 /*****************************************************************************
453  * GetSoutBuffer:
454  *****************************************************************************/
455 static int GetSoutBuffer( decoder_t *p_dec, sout_buffer_t **pp_buffer )
456 {
457     decoder_sys_t *p_sys = p_dec->p_sys;
458
459     if( p_sys->p_sout_input != NULL &&
460         ( p_sys->sout_format.i_sample_rate != (int)p_sys->i_rate
461           || p_sys->sout_format.i_channels != (int)p_sys->i_channels ) )
462     {
463         /* Parameters changed - this should not happen. */
464     }
465
466     /* Creating the sout input if not created yet. */
467     if( p_sys->p_sout_input == NULL )
468     {
469         p_sys->sout_format.i_sample_rate = p_sys->i_rate;
470         p_sys->sout_format.i_channels    = p_sys->i_channels;
471         p_sys->sout_format.i_block_align = 0;
472         p_sys->sout_format.i_bitrate     = p_sys->i_bit_rate;
473         p_sys->sout_format.i_extra_data  = 0;
474         p_sys->sout_format.p_extra_data  = NULL;
475
476         aout_DateInit( &p_sys->end_date, p_sys->i_rate );
477         aout_DateSet( &p_sys->end_date, p_sys->pts );
478
479         p_sys->p_sout_input = sout_InputNew( p_dec, &p_sys->sout_format );
480         if( p_sys->p_sout_input == NULL )
481         {
482             msg_Err( p_dec, "cannot add a new stream" );
483             *pp_buffer = NULL;
484             return VLC_EGENERIC;
485         }
486         msg_Info( p_dec, "A/52 channels:%d samplerate:%d bitrate:%d",
487                   p_sys->i_channels, p_sys->i_rate, p_sys->i_bit_rate );
488     }
489
490     *pp_buffer = sout_BufferNew( p_sys->p_sout_input->p_sout,
491                                  p_sys->i_frame_size );
492     if( *pp_buffer == NULL )
493     {
494         return VLC_EGENERIC;
495     }
496
497     (*pp_buffer)->i_pts =
498         (*pp_buffer)->i_dts = aout_DateGet( &p_sys->end_date );
499
500     (*pp_buffer)->i_length =
501         aout_DateIncrement( &p_sys->end_date, A52_FRAME_NB )
502         - (*pp_buffer)->i_pts;
503
504     return VLC_SUCCESS;
505 }
506
507 /*****************************************************************************
508  * SendOutBuffer:
509  *****************************************************************************/
510 static int SendOutBuffer( decoder_t *p_dec )
511 {
512     decoder_sys_t *p_sys = p_dec->p_sys;
513
514     if( p_sys->b_packetizer )
515     {
516         sout_InputSendBuffer( p_sys->p_sout_input, p_sys->p_sout_buffer );
517         p_sys->p_sout_buffer = NULL;
518     }
519     else
520     {
521         /* We have all we need, send the buffer to the aout core. */
522         aout_DecPlay( p_sys->p_aout, p_sys->p_aout_input,
523                       p_sys->p_aout_buffer );
524         p_sys->p_aout_buffer = NULL;
525     }
526
527     p_sys->p_out_buffer = NULL;
528
529     return VLC_SUCCESS;
530 }
531
532 /*****************************************************************************
533  * SyncInfo: parse A/52 sync info
534  *****************************************************************************
535  * This code is borrowed from liba52 by Aaron Holtzman & Michel Lespinasse,
536  * since we don't want to oblige S/PDIF people to use liba52 just to get
537  * their SyncInfo...
538  *****************************************************************************/
539 static int SyncInfo( const byte_t * p_buf,
540                      int * pi_channels, int * pi_channels_conf,
541                      int * pi_sample_rate, int * pi_bit_rate )
542 {
543     static const uint8_t halfrate[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 };
544     static const int rate[] = { 32,  40,  48,  56,  64,  80,  96, 112,
545                                 128, 160, 192, 224, 256, 320, 384, 448,
546                                 512, 576, 640 };
547     static const uint8_t lfeon[8] = { 0x10, 0x10, 0x04, 0x04,
548                                       0x04, 0x01, 0x04, 0x01 };
549     int frmsizecod;
550     int bitrate;
551     int half;
552     int acmod;
553
554     if ((p_buf[0] != 0x0b) || (p_buf[1] != 0x77))        /* syncword */
555         return 0;
556
557     if (p_buf[5] >= 0x60)                /* bsid >= 12 */
558         return 0;
559     half = halfrate[p_buf[5] >> 3];
560
561     /* acmod, dsurmod and lfeon */
562     acmod = p_buf[6] >> 5;
563     if ( (p_buf[6] & 0xf8) == 0x50 )
564     {
565         /* Dolby surround = stereo + Dolby */
566         *pi_channels = 2;
567         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
568                             | AOUT_CHAN_DOLBYSTEREO;
569     }
570     else switch ( acmod )
571     {
572     case 0x0:
573         /* Dual-mono = stereo + dual-mono */
574         *pi_channels = 2;
575         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
576                             | AOUT_CHAN_DUALMONO;
577         break;
578     case 0x1:
579         /* Mono */
580         *pi_channels = 1;
581         *pi_channels_conf = AOUT_CHAN_CENTER;
582         break;
583     case 0x2:
584         /* Stereo */
585         *pi_channels = 2;
586         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
587         break;
588     case 0x3:
589         /* 3F */
590         *pi_channels = 3;
591         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
592                             | AOUT_CHAN_CENTER;
593         break;
594     case 0x4:
595         /* 2F1R */
596         *pi_channels = 3;
597         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
598                             | AOUT_CHAN_REARCENTER;
599         break;
600     case 0x5:
601         /* 3F1R */
602         *pi_channels = 4;
603         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
604                             | AOUT_CHAN_REARCENTER;
605         break;
606     case 0x6:
607         /* 2F2R */
608         *pi_channels = 4;
609         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
610                             | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
611         break;
612     case 0x7:
613         /* 3F2R */
614         *pi_channels = 5;
615         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
616                             | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
617         break;
618     default:
619         return 0;
620     }
621
622     if ( p_buf[6] & lfeon[acmod] )
623     {
624         (*pi_channels)++;
625         *pi_channels_conf |= AOUT_CHAN_LFE;
626     }
627
628     frmsizecod = p_buf[4] & 63;
629     if (frmsizecod >= 38)
630         return 0;
631     bitrate = rate [frmsizecod >> 1];
632     *pi_bit_rate = (bitrate * 1000) >> half;
633
634     switch (p_buf[4] & 0xc0) {
635     case 0:
636         *pi_sample_rate = 48000 >> half;
637         return 4 * bitrate;
638     case 0x40:
639         *pi_sample_rate = 44100 >> half;
640         return 2 * (320 * bitrate / 147 + (frmsizecod & 1));
641     case 0x80:
642         *pi_sample_rate = 32000 >> half;
643         return 6 * bitrate;
644     default:
645         return 0;
646     }
647 }