1 /*****************************************************************************
2 * a52.c: A/52 basic parser
3 *****************************************************************************
4 * Copyright (C) 2001-2002 VideoLAN
5 * $Id: a52.c,v 1.23 2003/09/02 20:19:25 gbazin Exp $
7 * Authors: Stéphane Borel <stef@via.ecp.fr>
8 * Christophe Massiot <massiot@via.ecp.fr>
9 * Gildas Bazin <gbazin@netcourrier.com>
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.
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.
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 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
31 #include <string.h> /* memcpy() */
35 #include <vlc/decoder.h>
36 #include <vlc/input.h>
44 #define A52_HEADER_SIZE 7
46 /*****************************************************************************
47 * decoder_sys_t : decoder descriptor
48 *****************************************************************************/
52 vlc_bool_t b_packetizer;
59 uint8_t p_header[A52_HEADER_SIZE];
67 * Decoder output properties
69 aout_instance_t * p_aout; /* opaque */
70 aout_input_t * p_aout_input; /* opaque */
71 audio_sample_format_t aout_format;
73 aout_buffer_t * p_aout_buffer; /* current aout buffer being filled */
76 * Packetizer output properties
78 sout_packetizer_input_t *p_sout_input;
79 sout_format_t sout_format;
80 sout_buffer_t * p_sout_buffer; /* current sout buffer */
85 uint8_t *p_out_buffer; /* output buffer */
86 int i_out_buffer; /* position in output buffer */
87 audio_date_t end_date;
99 /****************************************************************************
101 ****************************************************************************/
102 static int OpenDecoder ( vlc_object_t * );
103 static int OpenPacketizer( vlc_object_t * );
105 static int InitDecoder ( decoder_t * );
106 static int RunDecoder ( decoder_t *, block_t * );
107 static int EndDecoder ( decoder_t * );
109 static int SyncInfo ( const byte_t *, int *, int *, int *,int * );
111 static int GetOutBuffer ( decoder_t *, uint8_t ** );
112 static int GetAoutBuffer( decoder_t *, aout_buffer_t ** );
113 static int GetSoutBuffer( decoder_t *, sout_buffer_t ** );
114 static int SendOutBuffer( decoder_t * );
116 /*****************************************************************************
118 *****************************************************************************/
120 set_description( _("A/52 parser") );
121 set_capability( "decoder", 100 );
122 set_callbacks( OpenDecoder, NULL );
125 set_description( _("A/52 audio packetizer") );
126 set_capability( "packetizer", 10 );
127 set_callbacks( OpenPacketizer, NULL );
130 /*****************************************************************************
131 * OpenDecoder: probe the decoder and return score
132 *****************************************************************************/
133 static int OpenDecoder( vlc_object_t *p_this )
135 decoder_t *p_dec = (decoder_t*)p_this;
137 if( p_dec->p_fifo->i_fourcc != VLC_FOURCC('a','5','2',' ')
138 && p_dec->p_fifo->i_fourcc != VLC_FOURCC('a','5','2','b') )
143 p_dec->pf_init = InitDecoder;
144 p_dec->pf_decode = RunDecoder;
145 p_dec->pf_end = EndDecoder;
147 /* Allocate the memory needed to store the decoder's structure */
149 (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
151 msg_Err( p_dec, "out of memory" );
154 p_dec->p_sys->b_packetizer = VLC_FALSE;
159 static int OpenPacketizer( vlc_object_t *p_this )
161 decoder_t *p_dec = (decoder_t*)p_this;
163 int i_ret = OpenDecoder( p_this );
165 if( i_ret == VLC_SUCCESS ) p_dec->p_sys->b_packetizer = VLC_TRUE;
170 /*****************************************************************************
171 * InitDecoder: Initalize the decoder
172 *****************************************************************************/
173 static int InitDecoder( decoder_t *p_dec )
175 p_dec->p_sys->i_state = STATE_NOSYNC;
177 p_dec->p_sys->p_out_buffer = NULL;
178 p_dec->p_sys->i_out_buffer = 0;
179 aout_DateSet( &p_dec->p_sys->end_date, 0 );
181 p_dec->p_sys->p_aout = NULL;
182 p_dec->p_sys->p_aout_input = NULL;
183 p_dec->p_sys->p_aout_buffer = NULL;
184 p_dec->p_sys->aout_format.i_format = VLC_FOURCC('a','5','2',' ');
186 p_dec->p_sys->p_sout_input = NULL;
187 p_dec->p_sys->p_sout_buffer = NULL;
188 p_dec->p_sys->sout_format.i_cat = AUDIO_ES;
189 p_dec->p_sys->sout_format.i_fourcc = VLC_FOURCC( 'a', '5', '2', ' ' );
194 /****************************************************************************
195 * RunDecoder: the whole thing
196 ****************************************************************************
197 * This function is called just after the thread is launched.
198 ****************************************************************************/
199 static int RunDecoder( decoder_t *p_dec, block_t *p_block )
201 decoder_sys_t *p_sys = p_dec->p_sys;
203 mtime_t i_pts = p_block->i_pts;
205 while( i_block_pos < p_block->i_buffer )
207 switch( p_sys->i_state )
210 /* Look for sync word - should be 0x0b77 */
211 while( i_block_pos < p_block->i_buffer &&
212 p_block->p_buffer[i_block_pos] != 0x0b )
217 if( i_block_pos < p_block->i_buffer )
219 p_sys->i_state = STATE_PARTIAL_SYNC;
221 p_sys->p_header[0] = 0x0b;
226 case STATE_PARTIAL_SYNC:
227 if( p_block->p_buffer[i_block_pos] == 0x77 )
229 p_sys->i_state = STATE_SYNC;
231 p_sys->p_header[1] = 0x77;
236 p_sys->i_state = STATE_NOSYNC;
241 /* New frame, set the Presentation Time Stamp */
242 p_sys->pts = i_pts; i_pts = 0;
243 if( p_sys->pts != 0 &&
244 p_sys->pts != aout_DateGet( &p_sys->end_date ) )
246 aout_DateSet( &p_sys->end_date, p_sys->pts );
248 p_sys->i_state = STATE_HEADER;
252 /* Get A/52 frame header (A52_HEADER_SIZE bytes) */
253 if( p_sys->i_header < A52_HEADER_SIZE )
255 int i_size = __MIN( A52_HEADER_SIZE - p_sys->i_header,
256 p_block->i_buffer - i_block_pos );
258 memcpy( p_sys->p_header + p_sys->i_header,
259 p_block->p_buffer + i_block_pos, i_size );
260 i_block_pos += i_size;
261 p_sys->i_header += i_size;
264 if( p_sys->i_header < A52_HEADER_SIZE )
267 if( GetOutBuffer( p_dec, &p_sys->p_out_buffer )
270 block_Release( p_block );
274 if( !p_sys->p_out_buffer )
276 p_sys->i_state = STATE_NOSYNC;
280 memcpy( p_sys->p_out_buffer, p_sys->p_header, A52_HEADER_SIZE );
281 p_sys->i_out_buffer = A52_HEADER_SIZE;
282 p_sys->i_state = STATE_DATA;
286 /* Copy the whole A52 frame into the aout buffer */
287 if( p_sys->i_out_buffer < p_sys->i_frame_size )
289 int i_size = __MIN( p_sys->i_frame_size - p_sys->i_out_buffer,
290 p_block->i_buffer - i_block_pos );
292 memcpy( p_sys->p_out_buffer + p_sys->i_out_buffer,
293 p_block->p_buffer + i_block_pos, i_size );
294 i_block_pos += i_size;
295 p_sys->i_out_buffer += i_size;
298 if( p_sys->i_out_buffer < p_sys->i_frame_size )
299 break; /* Need more data */
301 SendOutBuffer( p_dec );
303 p_sys->i_state = STATE_NOSYNC;
308 block_Release( p_block );
312 /*****************************************************************************
313 * EndDecoder: clean up the decoder
314 *****************************************************************************/
315 static int EndDecoder( decoder_t *p_dec )
317 if( p_dec->p_sys->p_aout_input != NULL )
319 if( p_dec->p_sys->p_aout_buffer )
321 aout_DecDeleteBuffer( p_dec->p_sys->p_aout,
322 p_dec->p_sys->p_aout_input,
323 p_dec->p_sys->p_aout_buffer );
326 aout_DecDelete( p_dec->p_sys->p_aout, p_dec->p_sys->p_aout_input );
329 if( p_dec->p_sys->p_sout_input != NULL )
331 if( p_dec->p_sys->p_sout_buffer )
333 sout_BufferDelete( p_dec->p_sys->p_sout_input->p_sout,
334 p_dec->p_sys->p_sout_buffer );
337 sout_InputDelete( p_dec->p_sys->p_sout_input );
340 free( p_dec->p_sys );
345 /*****************************************************************************
347 *****************************************************************************/
348 static int GetOutBuffer ( decoder_t *p_dec, uint8_t **pp_out_buffer )
350 decoder_sys_t *p_sys = p_dec->p_sys;
353 if( p_sys->b_packetizer )
355 i_ret= GetSoutBuffer( p_dec, &p_sys->p_sout_buffer );
357 p_sys->p_sout_buffer ? p_sys->p_sout_buffer->p_buffer : NULL;
361 i_ret = GetAoutBuffer( p_dec, &p_sys->p_aout_buffer );
363 p_sys->p_aout_buffer ? p_sys->p_aout_buffer->p_buffer : NULL;
369 /*****************************************************************************
371 *****************************************************************************/
372 static int GetAoutBuffer( decoder_t *p_dec, aout_buffer_t **pp_buffer )
375 unsigned int i_rate, i_channels, i_channels_conf;
377 decoder_sys_t *p_sys = p_dec->p_sys;
379 /* Check if frame is valid and get frame info */
380 p_sys->i_frame_size = SyncInfo( p_sys->p_header,
381 &i_channels, &i_channels_conf,
382 &i_rate, &i_bit_rate );
384 if( !p_sys->i_frame_size )
386 msg_Warn( p_dec, "a52 syncinfo failed" );
391 if( p_sys->p_aout_input != NULL && ( p_sys->aout_format.i_rate != i_rate
392 || p_sys->aout_format.i_original_channels != i_channels_conf
393 || (int)p_sys->aout_format.i_bytes_per_frame != p_sys->i_frame_size ) )
395 /* Parameters changed - this should not happen. */
396 aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
397 p_sys->p_aout_input = NULL;
400 /* Creating the audio input if not created yet. */
401 if( p_sys->p_aout_input == NULL )
403 p_sys->aout_format.i_rate = i_rate;
404 p_sys->aout_format.i_original_channels = i_channels_conf;
405 p_sys->aout_format.i_physical_channels
406 = i_channels_conf & AOUT_CHAN_PHYSMASK;
407 p_sys->aout_format.i_bytes_per_frame = p_sys->i_frame_size;
408 p_sys->aout_format.i_frame_length = A52_FRAME_NB;
409 aout_DateInit( &p_sys->end_date, i_rate );
410 aout_DateSet( &p_sys->end_date, p_sys->pts );
411 p_sys->p_aout_input = aout_DecNew( p_dec,
413 &p_sys->aout_format );
415 if ( p_sys->p_aout_input == NULL )
422 if( !aout_DateGet( &p_sys->end_date ) )
424 /* We've just started the stream, wait for the first PTS. */
429 *pp_buffer = aout_DecNewBuffer( p_sys->p_aout, p_sys->p_aout_input,
431 if( *pp_buffer == NULL )
436 (*pp_buffer)->start_date = aout_DateGet( &p_sys->end_date );
437 (*pp_buffer)->end_date =
438 aout_DateIncrement( &p_sys->end_date, A52_FRAME_NB );
443 /*****************************************************************************
445 *****************************************************************************/
446 static int GetSoutBuffer( decoder_t *p_dec, sout_buffer_t **pp_buffer )
449 unsigned int i_rate, i_channels, i_channels_conf;
451 decoder_sys_t *p_sys = p_dec->p_sys;
453 /* Check if frame is valid and get frame info */
454 p_sys->i_frame_size = SyncInfo( p_sys->p_header,
455 &i_channels, &i_channels_conf,
456 &i_rate, &i_bit_rate );
458 if( !p_sys->i_frame_size )
460 msg_Warn( p_dec, "a52 syncinfo failed" );
465 if( p_sys->p_sout_input != NULL &&
466 ( p_sys->sout_format.i_sample_rate != (int)i_rate
467 || p_sys->sout_format.i_channels != (int)i_channels ) )
469 /* Parameters changed - this should not happen. */
472 /* Creating the sout input if not created yet. */
473 if( p_sys->p_sout_input == NULL )
475 p_sys->sout_format.i_sample_rate = i_rate;
476 p_sys->sout_format.i_channels = i_channels;
477 p_sys->sout_format.i_block_align = 0;
478 p_sys->sout_format.i_bitrate = i_bit_rate;
479 p_sys->sout_format.i_extra_data = 0;
480 p_sys->sout_format.p_extra_data = NULL;
482 aout_DateInit( &p_sys->end_date, i_rate );
483 aout_DateSet( &p_sys->end_date, p_sys->pts );
485 p_sys->p_sout_input = sout_InputNew( p_dec,
486 &p_sys->sout_format );
488 if( p_sys->p_sout_input == NULL )
490 msg_Err( p_dec, "cannot add a new stream" );
494 msg_Info( p_dec, "A/52 channels:%d samplerate:%d bitrate:%d",
495 i_channels, i_rate, i_bit_rate );
498 if( !aout_DateGet( &p_sys->end_date ) )
500 /* We've just started the stream, wait for the first PTS. */
505 *pp_buffer = sout_BufferNew( p_sys->p_sout_input->p_sout,
506 p_sys->i_frame_size );
507 if( *pp_buffer == NULL )
512 (*pp_buffer)->i_pts =
513 (*pp_buffer)->i_dts = aout_DateGet( &p_sys->end_date );
515 (*pp_buffer)->i_length =
516 aout_DateIncrement( &p_sys->end_date, A52_FRAME_NB )
517 - (*pp_buffer)->i_pts;
522 /*****************************************************************************
524 *****************************************************************************/
525 static int SendOutBuffer( decoder_t *p_dec )
527 decoder_sys_t *p_sys = p_dec->p_sys;
529 if( p_sys->b_packetizer )
531 sout_InputSendBuffer( p_sys->p_sout_input, p_sys->p_sout_buffer );
532 p_sys->p_sout_buffer = NULL;
536 /* We have all we need, send the buffer to the aout core. */
537 aout_DecPlay( p_sys->p_aout, p_sys->p_aout_input,
538 p_sys->p_aout_buffer );
539 p_sys->p_aout_buffer = NULL;
545 /*****************************************************************************
546 * SyncInfo: parse A/52 sync info
547 *****************************************************************************
548 * This code is borrowed from liba52 by Aaron Holtzman & Michel Lespinasse,
549 * since we don't want to oblige S/PDIF people to use liba52 just to get
551 *****************************************************************************/
552 static int SyncInfo( const byte_t * p_buf,
553 int * pi_channels, int * pi_channels_conf,
554 int * pi_sample_rate, int * pi_bit_rate )
556 static const uint8_t halfrate[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 };
557 static const int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112,
558 128, 160, 192, 224, 256, 320, 384, 448,
560 static const uint8_t lfeon[8] = { 0x10, 0x10, 0x04, 0x04,
561 0x04, 0x01, 0x04, 0x01 };
567 if ((p_buf[0] != 0x0b) || (p_buf[1] != 0x77)) /* syncword */
570 if (p_buf[5] >= 0x60) /* bsid >= 12 */
572 half = halfrate[p_buf[5] >> 3];
574 /* acmod, dsurmod and lfeon */
575 acmod = p_buf[6] >> 5;
576 if ( (p_buf[6] & 0xf8) == 0x50 )
578 /* Dolby surround = stereo + Dolby */
580 *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
581 | AOUT_CHAN_DOLBYSTEREO;
583 else switch ( acmod )
586 /* Dual-mono = stereo + dual-mono */
588 *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
589 | AOUT_CHAN_DUALMONO;
594 *pi_channels_conf = AOUT_CHAN_CENTER;
599 *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
604 *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
610 *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
611 | AOUT_CHAN_REARCENTER;
616 *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
617 | AOUT_CHAN_REARCENTER;
622 *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
623 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
628 *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
629 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
635 if ( p_buf[6] & lfeon[acmod] )
638 *pi_channels_conf |= AOUT_CHAN_LFE;
641 frmsizecod = p_buf[4] & 63;
642 if (frmsizecod >= 38)
644 bitrate = rate [frmsizecod >> 1];
645 *pi_bit_rate = (bitrate * 1000) >> half;
647 switch (p_buf[4] & 0xc0) {
649 *pi_sample_rate = 48000 >> half;
652 *pi_sample_rate = 44100 >> half;
653 return 2 * (320 * bitrate / 147 + (frmsizecod & 1));
655 *pi_sample_rate = 32000 >> half;