Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

a52.c

00001 /*****************************************************************************
00002  * a52.c: parse A/52 audio sync info and packetize the stream
00003  *****************************************************************************
00004  * Copyright (C) 2001-2002 the VideoLAN team
00005  * $Id: a52.c 11709 2005-07-11 16:20:33Z massiot $
00006  *
00007  * Authors: Stéphane Borel <[email protected]>
00008  *          Christophe Massiot <[email protected]>
00009  *          Gildas Bazin <[email protected]>
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00024  *****************************************************************************/
00025 
00026 /*****************************************************************************
00027  * Preamble
00028  *****************************************************************************/
00029 #include <vlc/vlc.h>
00030 #include <vlc/decoder.h>
00031 
00032 #include "vlc_block_helper.h"
00033 
00034 #define A52_HEADER_SIZE 7
00035 
00036 /*****************************************************************************
00037  * decoder_sys_t : decoder descriptor
00038  *****************************************************************************/
00039 struct decoder_sys_t
00040 {
00041     /* Module mode */
00042     vlc_bool_t b_packetizer;
00043 
00044     /*
00045      * Input properties
00046      */
00047     int i_state;
00048 
00049     block_bytestream_t bytestream;
00050 
00051     /*
00052      * Common properties
00053      */
00054     audio_date_t   end_date;
00055 
00056     mtime_t i_pts;
00057     int i_frame_size, i_bit_rate;
00058     unsigned int i_rate, i_channels, i_channels_conf;
00059 
00060 };
00061 
00062 enum {
00063 
00064     STATE_NOSYNC,
00065     STATE_SYNC,
00066     STATE_HEADER,
00067     STATE_NEXT_SYNC,
00068     STATE_GET_DATA,
00069     STATE_SEND_DATA
00070 };
00071 
00072 /****************************************************************************
00073  * Local prototypes
00074  ****************************************************************************/
00075 static int  OpenDecoder   ( vlc_object_t * );
00076 static int  OpenPacketizer( vlc_object_t * );
00077 static void CloseDecoder  ( vlc_object_t * );
00078 static void *DecodeBlock  ( decoder_t *, block_t ** );
00079 
00080 static int  SyncInfo      ( const byte_t *, unsigned int *, unsigned int *,
00081                             unsigned int *, int * );
00082 
00083 static uint8_t       *GetOutBuffer ( decoder_t *, void ** );
00084 static aout_buffer_t *GetAoutBuffer( decoder_t * );
00085 static block_t       *GetSoutBuffer( decoder_t * );
00086 
00087 /*****************************************************************************
00088  * Module descriptor
00089  *****************************************************************************/
00090 vlc_module_begin();
00091     set_description( _("A/52 parser") );
00092     set_capability( "decoder", 100 );
00093     set_callbacks( OpenDecoder, CloseDecoder );
00094     set_category( CAT_INPUT );
00095     set_subcategory( SUBCAT_INPUT_ACODEC );
00096 
00097     add_submodule();
00098     set_description( _("A/52 audio packetizer") );
00099     set_capability( "packetizer", 10 );
00100     set_callbacks( OpenPacketizer, CloseDecoder );
00101 vlc_module_end();
00102 
00103 /*****************************************************************************
00104  * OpenDecoder: probe the decoder and return score
00105  *****************************************************************************/
00106 static int OpenDecoder( vlc_object_t *p_this )
00107 {
00108     decoder_t *p_dec = (decoder_t*)p_this;
00109     decoder_sys_t *p_sys;
00110 
00111     if( p_dec->fmt_in.i_codec != VLC_FOURCC('a','5','2',' ')
00112           && p_dec->fmt_in.i_codec != VLC_FOURCC('a','5','2','b') )
00113     {
00114         return VLC_EGENERIC;
00115     }
00116 
00117     /* Allocate the memory needed to store the decoder's structure */
00118     if( ( p_dec->p_sys = p_sys =
00119           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
00120     {
00121         msg_Err( p_dec, "out of memory" );
00122         return VLC_EGENERIC;
00123     }
00124 
00125     /* Misc init */
00126     p_sys->b_packetizer = VLC_FALSE;
00127     p_sys->i_state = STATE_NOSYNC;
00128     aout_DateSet( &p_sys->end_date, 0 );
00129 
00130     p_sys->bytestream = block_BytestreamInit( p_dec );
00131 
00132     /* Set output properties */
00133     p_dec->fmt_out.i_cat = AUDIO_ES;
00134     p_dec->fmt_out.i_codec = VLC_FOURCC('a','5','2',' ');
00135     p_dec->fmt_out.audio.i_rate = 0; /* So end_date gets initialized */
00136 
00137     /* Set callback */
00138     p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))
00139         DecodeBlock;
00140     p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
00141         DecodeBlock;
00142 
00143     return VLC_SUCCESS;
00144 }
00145 
00146 static int OpenPacketizer( vlc_object_t *p_this )
00147 {
00148     decoder_t *p_dec = (decoder_t*)p_this;
00149 
00150     int i_ret = OpenDecoder( p_this );
00151 
00152     if( i_ret == VLC_SUCCESS ) p_dec->p_sys->b_packetizer = VLC_TRUE;
00153 
00154     return i_ret;
00155 }
00156 
00157 /****************************************************************************
00158  * DecodeBlock: the whole thing
00159  ****************************************************************************
00160  * This function is called just after the thread is launched.
00161  ****************************************************************************/
00162 static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
00163 {
00164     decoder_sys_t *p_sys = p_dec->p_sys;
00165     uint8_t p_header[A52_HEADER_SIZE];
00166     uint8_t *p_buf;
00167     void *p_out_buffer;
00168 
00169     if( !pp_block || !*pp_block ) return NULL;
00170 
00171     if( !aout_DateGet( &p_sys->end_date ) && !(*pp_block)->i_pts )
00172     {
00173         /* We've just started the stream, wait for the first PTS. */
00174         block_Release( *pp_block );
00175         return NULL;
00176     }
00177 
00178     if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
00179     {
00180         p_sys->i_state = STATE_NOSYNC;
00181     }
00182 
00183     block_BytestreamPush( &p_sys->bytestream, *pp_block );
00184 
00185     while( 1 )
00186     {
00187         switch( p_sys->i_state )
00188         {
00189         case STATE_NOSYNC:
00190             while( block_PeekBytes( &p_sys->bytestream, p_header, 2 )
00191                    == VLC_SUCCESS )
00192             {
00193                 if( p_header[0] == 0x0b && p_header[1] == 0x77 )
00194                 {
00195                     p_sys->i_state = STATE_SYNC;
00196                     break;
00197                 }
00198                 block_SkipByte( &p_sys->bytestream );
00199             }
00200             if( p_sys->i_state != STATE_SYNC )
00201             {
00202                 block_BytestreamFlush( &p_sys->bytestream );
00203 
00204                 /* Need more data */
00205                 return NULL;
00206             }
00207 
00208         case STATE_SYNC:
00209             /* New frame, set the Presentation Time Stamp */
00210             p_sys->i_pts = p_sys->bytestream.p_block->i_pts;
00211             if( p_sys->i_pts != 0 &&
00212                 p_sys->i_pts != aout_DateGet( &p_sys->end_date ) )
00213             {
00214                 aout_DateSet( &p_sys->end_date, p_sys->i_pts );
00215             }
00216             p_sys->i_state = STATE_HEADER;
00217 
00218         case STATE_HEADER:
00219             /* Get A/52 frame header (A52_HEADER_SIZE bytes) */
00220             if( block_PeekBytes( &p_sys->bytestream, p_header,
00221                                  A52_HEADER_SIZE ) != VLC_SUCCESS )
00222             {
00223                 /* Need more data */
00224                 return NULL;
00225             }
00226 
00227             /* Check if frame is valid and get frame info */
00228             p_sys->i_frame_size = SyncInfo( p_header,
00229                                             &p_sys->i_channels,
00230                                             &p_sys->i_channels_conf,
00231                                             &p_sys->i_rate,
00232                                             &p_sys->i_bit_rate );
00233             if( !p_sys->i_frame_size )
00234             {
00235                 msg_Dbg( p_dec, "emulated sync word" );
00236                 block_SkipByte( &p_sys->bytestream );
00237                 p_sys->i_state = STATE_NOSYNC;
00238                 break;
00239             }
00240             p_sys->i_state = STATE_NEXT_SYNC;
00241 
00242         case STATE_NEXT_SYNC:
00243             /* TODO: If pp_block == NULL, flush the buffer without checking the
00244              * next sync word */
00245 
00246             /* Check if next expected frame contains the sync word */
00247             if( block_PeekOffsetBytes( &p_sys->bytestream,
00248                                        p_sys->i_frame_size, p_header, 2 )
00249                 != VLC_SUCCESS )
00250             {
00251                 /* Need more data */
00252                 return NULL;
00253             }
00254 
00255             if( p_sys->b_packetizer &&
00256                 p_header[0] == 0 && p_header[1] == 0 )
00257             {
00258                 /* A52 wav files and audio CD's use stuffing */
00259                 p_sys->i_state = STATE_GET_DATA;
00260                 break;
00261             }
00262 
00263             if( p_header[0] != 0x0b || p_header[1] != 0x77 )
00264             {
00265                 msg_Dbg( p_dec, "emulated sync word "
00266                          "(no sync on following frame)" );
00267                 p_sys->i_state = STATE_NOSYNC;
00268                 block_SkipByte( &p_sys->bytestream );
00269                 break;
00270             }
00271             p_sys->i_state = STATE_SEND_DATA;
00272             break;
00273 
00274         case STATE_GET_DATA:
00275             /* Make sure we have enough data.
00276              * (Not useful if we went through NEXT_SYNC) */
00277             if( block_WaitBytes( &p_sys->bytestream,
00278                                  p_sys->i_frame_size ) != VLC_SUCCESS )
00279             {
00280                 /* Need more data */
00281                 return NULL;
00282             }
00283             p_sys->i_state = STATE_SEND_DATA;
00284 
00285         case STATE_SEND_DATA:
00286             if( !(p_buf = GetOutBuffer( p_dec, &p_out_buffer )) )
00287             {
00288                 //p_dec->b_error = VLC_TRUE;
00289                 return NULL;
00290             }
00291 
00292             /* Copy the whole frame into the buffer. When we reach this point
00293              * we already know we have enough data available. */
00294             block_GetBytes( &p_sys->bytestream, p_buf, p_sys->i_frame_size );
00295 
00296             /* Make sure we don't reuse the same pts twice */
00297             if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts )
00298                 p_sys->i_pts = p_sys->bytestream.p_block->i_pts = 0;
00299 
00300             /* So p_block doesn't get re-added several times */
00301             *pp_block = block_BytestreamPop( &p_sys->bytestream );
00302 
00303             p_sys->i_state = STATE_NOSYNC;
00304 
00305             return p_out_buffer;
00306         }
00307     }
00308 
00309     return NULL;
00310 }
00311 
00312 /*****************************************************************************
00313  * CloseDecoder: clean up the decoder
00314  *****************************************************************************/
00315 static void CloseDecoder( vlc_object_t *p_this )
00316 {
00317     decoder_t *p_dec = (decoder_t*)p_this;
00318     decoder_sys_t *p_sys = p_dec->p_sys;
00319 
00320     block_BytestreamRelease( &p_sys->bytestream );
00321 
00322     free( p_sys );
00323 }
00324 
00325 /*****************************************************************************
00326  * GetOutBuffer:
00327  *****************************************************************************/
00328 static uint8_t *GetOutBuffer( decoder_t *p_dec, void **pp_out_buffer )
00329 {
00330     decoder_sys_t *p_sys = p_dec->p_sys;
00331     uint8_t *p_buf;
00332 
00333     if( p_dec->fmt_out.audio.i_rate != p_sys->i_rate )
00334     {
00335         msg_Info( p_dec, "A/52 channels:%d samplerate:%d bitrate:%d",
00336                   p_sys->i_channels, p_sys->i_rate, p_sys->i_bit_rate );
00337 
00338         aout_DateInit( &p_sys->end_date, p_sys->i_rate );
00339         aout_DateSet( &p_sys->end_date, p_sys->i_pts );
00340     }
00341 
00342     p_dec->fmt_out.audio.i_rate     = p_sys->i_rate;
00343     p_dec->fmt_out.audio.i_channels = p_sys->i_channels;
00344     p_dec->fmt_out.audio.i_bytes_per_frame = p_sys->i_frame_size;
00345     p_dec->fmt_out.audio.i_frame_length = A52_FRAME_NB;
00346 
00347     p_dec->fmt_out.audio.i_original_channels = p_sys->i_channels_conf;
00348     p_dec->fmt_out.audio.i_physical_channels =
00349         p_sys->i_channels_conf & AOUT_CHAN_PHYSMASK;
00350 
00351     p_dec->fmt_out.i_bitrate = p_sys->i_bit_rate;
00352 
00353     if( p_sys->b_packetizer )
00354     {
00355         block_t *p_sout_buffer = GetSoutBuffer( p_dec );
00356         p_buf = p_sout_buffer ? p_sout_buffer->p_buffer : NULL;
00357         *pp_out_buffer = p_sout_buffer;
00358     }
00359     else
00360     {
00361         aout_buffer_t *p_aout_buffer = GetAoutBuffer( p_dec );
00362         p_buf = p_aout_buffer ? p_aout_buffer->p_buffer : NULL;
00363         *pp_out_buffer = p_aout_buffer;
00364     }
00365 
00366     return p_buf;
00367 }
00368 
00369 /*****************************************************************************
00370  * GetAoutBuffer:
00371  *****************************************************************************/
00372 static aout_buffer_t *GetAoutBuffer( decoder_t *p_dec )
00373 {
00374     decoder_sys_t *p_sys = p_dec->p_sys;
00375     aout_buffer_t *p_buf;
00376 
00377     p_buf = p_dec->pf_aout_buffer_new( p_dec, A52_FRAME_NB  );
00378     if( p_buf == NULL ) return NULL;
00379 
00380     p_buf->start_date = aout_DateGet( &p_sys->end_date );
00381     p_buf->end_date = aout_DateIncrement( &p_sys->end_date, A52_FRAME_NB );
00382 
00383     return p_buf;
00384 }
00385 
00386 /*****************************************************************************
00387  * GetSoutBuffer:
00388  *****************************************************************************/
00389 static block_t *GetSoutBuffer( decoder_t *p_dec )
00390 {
00391     decoder_sys_t *p_sys = p_dec->p_sys;
00392     block_t *p_block;
00393 
00394     p_block = block_New( p_dec, p_sys->i_frame_size );
00395     if( p_block == NULL ) return NULL;
00396 
00397     p_block->i_pts = p_block->i_dts = aout_DateGet( &p_sys->end_date );
00398 
00399     p_block->i_length = aout_DateIncrement( &p_sys->end_date, A52_FRAME_NB ) -
00400         p_block->i_pts;
00401 
00402     return p_block;
00403 }
00404 
00405 /*****************************************************************************
00406  * SyncInfo: parse A/52 sync info
00407  *****************************************************************************
00408  * This code is borrowed from liba52 by Aaron Holtzman & Michel Lespinasse,
00409  * since we don't want to oblige S/PDIF people to use liba52 just to get
00410  * their SyncInfo...
00411  *****************************************************************************/
00412 static int SyncInfo( const byte_t * p_buf,
00413                      unsigned int * pi_channels,
00414                      unsigned int * pi_channels_conf,
00415                      unsigned int * pi_sample_rate, int * pi_bit_rate )
00416 {
00417     static const uint8_t halfrate[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 };
00418     static const int rate[] = { 32,  40,  48,  56,  64,  80,  96, 112,
00419                                 128, 160, 192, 224, 256, 320, 384, 448,
00420                                 512, 576, 640 };
00421     static const uint8_t lfeon[8] = { 0x10, 0x10, 0x04, 0x04,
00422                                       0x04, 0x01, 0x04, 0x01 };
00423     int frmsizecod;
00424     int bitrate;
00425     int half;
00426     int acmod;
00427 
00428     if ((p_buf[0] != 0x0b) || (p_buf[1] != 0x77))        /* syncword */
00429         return 0;
00430 
00431     if (p_buf[5] >= 0x60)                /* bsid >= 12 */
00432         return 0;
00433     half = halfrate[p_buf[5] >> 3];
00434 
00435     /* acmod, dsurmod and lfeon */
00436     acmod = p_buf[6] >> 5;
00437     if ( (p_buf[6] & 0xf8) == 0x50 )
00438     {
00439         /* Dolby surround = stereo + Dolby */
00440         *pi_channels = 2;
00441         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
00442                             | AOUT_CHAN_DOLBYSTEREO;
00443     }
00444     else switch ( acmod )
00445     {
00446     case 0x0:
00447         /* Dual-mono = stereo + dual-mono */
00448         *pi_channels = 2;
00449         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
00450                             | AOUT_CHAN_DUALMONO;
00451         break;
00452     case 0x1:
00453         /* Mono */
00454         *pi_channels = 1;
00455         *pi_channels_conf = AOUT_CHAN_CENTER;
00456         break;
00457     case 0x2:
00458         /* Stereo */
00459         *pi_channels = 2;
00460         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
00461         break;
00462     case 0x3:
00463         /* 3F */
00464         *pi_channels = 3;
00465         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
00466                             | AOUT_CHAN_CENTER;
00467         break;
00468     case 0x4:
00469         /* 2F1R */
00470         *pi_channels = 3;
00471         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
00472                             | AOUT_CHAN_REARCENTER;
00473         break;
00474     case 0x5:
00475         /* 3F1R */
00476         *pi_channels = 4;
00477         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00478                             | AOUT_CHAN_REARCENTER;
00479         break;
00480     case 0x6:
00481         /* 2F2R */
00482         *pi_channels = 4;
00483         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
00484                             | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
00485         break;
00486     case 0x7:
00487         /* 3F2R */
00488         *pi_channels = 5;
00489         *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00490                             | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT;
00491         break;
00492     default:
00493         return 0;
00494     }
00495 
00496     if ( p_buf[6] & lfeon[acmod] )
00497     {
00498         (*pi_channels)++;
00499         *pi_channels_conf |= AOUT_CHAN_LFE;
00500     }
00501 
00502     frmsizecod = p_buf[4] & 63;
00503     if (frmsizecod >= 38)
00504         return 0;
00505     bitrate = rate [frmsizecod >> 1];
00506     *pi_bit_rate = (bitrate * 1000) >> half;
00507 
00508     switch (p_buf[4] & 0xc0) {
00509     case 0:
00510         *pi_sample_rate = 48000 >> half;
00511         return 4 * bitrate;
00512     case 0x40:
00513         *pi_sample_rate = 44100 >> half;
00514         return 2 * (320 * bitrate / 147 + (frmsizecod & 1));
00515     case 0x80:
00516         *pi_sample_rate = 32000 >> half;
00517         return 6 * bitrate;
00518     default:
00519         return 0;
00520     }
00521 }

Generated on Tue Dec 20 10:14:28 2005 for vlc-0.8.4a by  doxygen 1.4.2