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