X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Fmpeg_audio.c;h=4267f0916922a214c3cbbb2fb3e9e67dc1928e58;hb=f5b8f4a13fe40151abd54a009049e5d9a6e6780c;hp=fbecce291de351af48eb30f8c79a55be6103c165;hpb=0bbce5b50d4f6acab7899231b3d4b649dc718d71;p=vlc diff --git a/modules/codec/mpeg_audio.c b/modules/codec/mpeg_audio.c index fbecce291d..4267f09169 100644 --- a/modules/codec/mpeg_audio.c +++ b/modules/codec/mpeg_audio.c @@ -1,12 +1,13 @@ /***************************************************************************** * mpeg_audio.c: parse MPEG audio sync info and packetize the stream ***************************************************************************** - * Copyright (C) 2001-2003 VideoLAN - * $Id: mpeg_audio.c,v 1.5 2003/01/16 14:08:39 massiot Exp $ + * Copyright (C) 2001-2003 the VideoLAN team + * $Id$ * * Authors: Laurent Aimar * Eric Petit * Christophe Massiot + * Gildas Bazin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,404 +21,584 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include /* malloc(), free() */ -#include /* strdup() */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include -#include -#include +#include +#include +#include +#include +#include + +#include /***************************************************************************** - * dec_thread_t : decoder thread descriptor + * decoder_sys_t : decoder descriptor *****************************************************************************/ -typedef struct dec_thread_t +struct decoder_sys_t { - /* - * Thread properties - */ - vlc_thread_t thread_id; /* id for thread functions */ + /* Module mode */ + bool b_packetizer; /* * Input properties */ - decoder_fifo_t * p_fifo; /* stores the PES stream data */ - bit_stream_t bit_stream; + int i_state; + + block_bytestream_t bytestream; /* - * Output properties + * Common properties */ - aout_instance_t * p_aout; /* opaque */ - aout_input_t * p_aout_input; /* opaque */ - audio_sample_format_t output_format; -} dec_thread_t; + date_t end_date; + unsigned int i_current_layer; + + mtime_t i_pts; + + int i_frame_size, i_free_frame_size; + unsigned int i_channels_conf, i_channels; + unsigned int i_rate, i_max_frame_size, i_frame_length; + unsigned int i_layer, i_bit_rate; + + bool b_discontinuity; +}; + +enum { + + STATE_NOSYNC, + STATE_SYNC, + STATE_HEADER, + STATE_NEXT_SYNC, + STATE_GET_DATA, + STATE_SEND_DATA +}; -#define MAX_FRAME_SIZE (511 + 2048) /* This isn't the place to put mad-specific stuff. However, it makes the * mad plug-in's life much easier if we put 8 extra bytes at the end of the * buffer, because that way it doesn't have to copy the aout_buffer_t to a * bigger buffer. This has no implication on other plug-ins, and we only * lose 8 bytes per frame. --Meuuh */ #define MAD_BUFFER_GUARD 8 - +#define MPGA_HEADER_SIZE 4 /**************************************************************************** * Local prototypes ****************************************************************************/ -static int Open ( vlc_object_t * ); -static int RunDecoder ( decoder_fifo_t * ); +static int OpenDecoder ( vlc_object_t * ); +static int OpenPacketizer( vlc_object_t * ); +static void CloseDecoder ( vlc_object_t * ); +static void *DecodeBlock ( decoder_t *, block_t ** ); -static void EndThread ( dec_thread_t * ); +static uint8_t *GetOutBuffer ( decoder_t *, block_t ** ); +static aout_buffer_t *GetAoutBuffer( decoder_t * ); +static block_t *GetSoutBuffer( decoder_t * ); static int SyncInfo( uint32_t i_header, unsigned int * pi_channels, + unsigned int * pi_channels_conf, unsigned int * pi_sample_rate, unsigned int * pi_bit_rate, unsigned int * pi_frame_length, - unsigned int * pi_current_frame_length, + unsigned int * pi_max_frame_size, unsigned int * pi_layer ); /***************************************************************************** * Module descriptor *****************************************************************************/ -vlc_module_begin(); - set_description( _("MPEG audio layer I/II/III parser") ); - set_capability( "decoder", 100 ); - set_callbacks( Open, NULL ); -vlc_module_end(); +vlc_module_begin () + set_description( N_("MPEG audio layer I/II/III decoder") ) + set_category( CAT_INPUT ) + set_subcategory( SUBCAT_INPUT_ACODEC ) +#if defined(UNDER_CE) + set_capability( "decoder", 5 ) +#else + set_capability( "decoder", 100 ) +#endif + set_callbacks( OpenDecoder, CloseDecoder ) + + add_submodule () + set_description( N_("MPEG audio layer I/II/III packetizer") ) + set_capability( "packetizer", 10 ) + set_callbacks( OpenPacketizer, CloseDecoder ) +vlc_module_end () /***************************************************************************** - * OpenDecoder: probe the decoder and return score + * Open: probe the decoder and return score *****************************************************************************/ static int Open( vlc_object_t *p_this ) { - decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; + decoder_t *p_dec = (decoder_t*)p_this; + decoder_sys_t *p_sys; - if( p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', 'a') ) + if( p_dec->fmt_in.i_codec != VLC_CODEC_MPGA ) { return VLC_EGENERIC; } - p_fifo->pf_run = RunDecoder; + /* Allocate the memory needed to store the decoder's structure */ + if( ( p_dec->p_sys = p_sys = + (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL ) + return VLC_ENOMEM; + + /* Misc init */ + p_sys->b_packetizer = false; + p_sys->i_state = STATE_NOSYNC; + date_Set( &p_sys->end_date, 0 ); + p_sys->bytestream = block_BytestreamInit(); + p_sys->i_pts = VLC_TS_INVALID; + p_sys->b_discontinuity = false; + + /* Set output properties */ + p_dec->fmt_out.i_cat = AUDIO_ES; + p_dec->fmt_out.i_codec = VLC_CODEC_MPGA; + p_dec->fmt_out.audio.i_rate = 0; /* So end_date gets initialized */ + + /* Set callback */ + p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **)) + DecodeBlock; + p_dec->pf_packetize = (block_t *(*)(decoder_t *, block_t **)) + DecodeBlock; + + /* Start with the minimum size for a free bitrate frame */ + p_sys->i_free_frame_size = MPGA_HEADER_SIZE; + return VLC_SUCCESS; } -/***************************************************************************** - * RunDecoder: this function is called just after the thread is created - *****************************************************************************/ -static int RunDecoder( decoder_fifo_t *p_fifo ) +static int OpenDecoder( vlc_object_t *p_this ) { - dec_thread_t * p_dec; - audio_date_t end_date; - unsigned int i_layer = 0; - byte_t p_sync[MAD_BUFFER_GUARD]; - mtime_t pts; - int i_free_frame_size = 0; - - /* Allocate the memory needed to store the thread's structure */ - p_dec = malloc( sizeof(dec_thread_t) ); - if( p_dec == NULL ) - { - msg_Err( p_fifo, "out of memory" ); - DecoderError( p_fifo ); - return -1; - } + /* HACK: Don't use this codec if we don't have an mpga audio filter */ + if( !module_exists( "mpgatofixed32" ) ) + return VLC_EGENERIC; - /* Initialize the thread properties */ - p_dec->p_aout = NULL; - p_dec->p_aout_input = NULL; - p_dec->p_fifo = p_fifo; + return Open( p_this ); +} + +static int OpenPacketizer( vlc_object_t *p_this ) +{ + decoder_t *p_dec = (decoder_t*)p_this; - aout_DateSet( &end_date, 0 ); + int i_ret = Open( p_this ); - /* Init the bitstream */ - if( InitBitstream( &p_dec->bit_stream, p_dec->p_fifo, - NULL, NULL ) != VLC_SUCCESS ) + if( i_ret == VLC_SUCCESS ) p_dec->p_sys->b_packetizer = true; + + return i_ret; +} + +/**************************************************************************** + * DecodeBlock: the whole thing + **************************************************************************** + * This function is called just after the thread is launched. + ****************************************************************************/ +static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + uint8_t p_header[MAD_BUFFER_GUARD]; + uint32_t i_header; + uint8_t *p_buf; + block_t *p_out_buffer; + + if( !pp_block || !*pp_block ) return NULL; + + if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { - msg_Err( p_fifo, "cannot initialize bitstream" ); - DecoderError( p_fifo ); - free( p_dec ); - return -1; + if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) + { + p_sys->i_state = STATE_NOSYNC; + block_BytestreamEmpty( &p_sys->bytestream ); + } + date_Set( &p_sys->end_date, 0 ); + block_Release( *pp_block ); + p_sys->b_discontinuity = true; + return NULL; } - /* Init sync buffer. */ - NextPTS( &p_dec->bit_stream, &pts, NULL ); - GetChunk( &p_dec->bit_stream, p_sync, MAD_BUFFER_GUARD ); + if( !date_Get( &p_sys->end_date ) && (*pp_block)->i_pts <= VLC_TS_INVALID ) + { + /* We've just started the stream, wait for the first PTS. */ + msg_Dbg( p_dec, "waiting for PTS" ); + block_Release( *pp_block ); + return NULL; + } - /* Decoder thread's main loop */ - while ( !p_dec->p_fifo->b_die && !p_dec->p_fifo->b_error ) + block_BytestreamPush( &p_sys->bytestream, *pp_block ); + + while( 1 ) { - int i_current_frame_size; - unsigned int i_rate, i_original_channels, i_frame_size, i_frame_length; - unsigned int i_new_layer, i_bit_rate; - uint32_t i_header; - aout_buffer_t * p_buffer; - int i; - - /* Look for sync word - should be 0xffe */ - if ( (p_sync[0] != 0xff) || ((p_sync[1] & 0xe0) != 0xe0) ) + switch( p_sys->i_state ) { - msg_Warn( p_dec->p_fifo, "no sync - skipping" ); - /* Look inside the sync buffer. */ - for ( i = 1; i < MAD_BUFFER_GUARD - 1; i++ ) + + case STATE_NOSYNC: + while( block_PeekBytes( &p_sys->bytestream, p_header, 2 ) + == VLC_SUCCESS ) { - if ( (p_sync[i] == 0xff) && ((p_sync[i + 1] & 0xe0) != 0xe0) ) + /* Look for sync word - should be 0xffe */ + if( p_header[0] == 0xff && (p_header[1] & 0xe0) == 0xe0 ) + { + p_sys->i_state = STATE_SYNC; break; + } + block_SkipByte( &p_sys->bytestream ); } - if ( i < MAD_BUFFER_GUARD - 1 ) + if( p_sys->i_state != STATE_SYNC ) { - /* Found it ! */ - memmove( p_sync, &p_sync[i], MAD_BUFFER_GUARD - i ); - GetChunk( &p_dec->bit_stream, &p_sync[MAD_BUFFER_GUARD - i], - i ); + block_BytestreamFlush( &p_sys->bytestream ); + + /* Need more data */ + return NULL; } - else + + case STATE_SYNC: + /* New frame, set the Presentation Time Stamp */ + p_sys->i_pts = p_sys->bytestream.p_block->i_pts; + if( p_sys->i_pts > VLC_TS_INVALID && + p_sys->i_pts != date_Get( &p_sys->end_date ) ) { - if ( p_sync[MAD_BUFFER_GUARD - 1] == 0xff - && ShowBits( &p_dec->bit_stream, 3 ) == 0x3 ) - { - /* Found it ! */ - p_sync[0] = p_sync[MAD_BUFFER_GUARD - 1]; - GetChunk( &p_dec->bit_stream, - &p_sync[1], MAD_BUFFER_GUARD - 1 ); - } - else - { - /* Scan the stream. */ - while ( ShowBits( &p_dec->bit_stream, 11 ) != 0x07ff && - (!p_dec->p_fifo->b_die) && - (!p_dec->p_fifo->b_error) ) - { - RemoveBits( &p_dec->bit_stream, 8 ); - } - if ( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error ) - break; - NextPTS( &p_dec->bit_stream, &pts, NULL ); - GetChunk( &p_dec->bit_stream,p_sync, MAD_BUFFER_GUARD ); - } + date_Set( &p_sys->end_date, p_sys->i_pts ); } - } - if ( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error ) break; + p_sys->i_state = STATE_HEADER; - /* Set the Presentation Time Stamp */ - if ( pts != 0 && pts != aout_DateGet( &end_date ) ) - { - aout_DateSet( &end_date, pts ); - } - - /* Get frame header */ - i_header = (p_sync[0] << 24) | (p_sync[1] << 16) | (p_sync[2] << 8) - | p_sync[3]; + case STATE_HEADER: + /* Get MPGA frame header (MPGA_HEADER_SIZE bytes) */ + if( block_PeekBytes( &p_sys->bytestream, p_header, + MPGA_HEADER_SIZE ) != VLC_SUCCESS ) + { + /* Need more data */ + return NULL; + } - /* Check if frame is valid and get frame info */ - i_current_frame_size = SyncInfo( i_header, - &i_original_channels, &i_rate, - &i_bit_rate, &i_frame_length, - &i_frame_size, &i_new_layer ); - if ( !i_current_frame_size ) - i_current_frame_size = i_free_frame_size; + /* Build frame header */ + i_header = (p_header[0]<<24)|(p_header[1]<<16)|(p_header[2]<<8) + |p_header[3]; - if ( i_current_frame_size == -1 ) - { - msg_Warn( p_dec->p_fifo, "syncinfo failed" ); - /* This is probably an emulated startcode, drop the first byte - * to force looking for the next startcode. */ - memmove( p_sync, &p_sync[1], MAD_BUFFER_GUARD - 1 ); - p_sync[MAD_BUFFER_GUARD - 1] = GetBits( &p_dec->bit_stream, 8 ); - continue; - } - if ( (unsigned int)i_current_frame_size > i_frame_size ) - { - msg_Warn( p_dec->p_fifo, "frame too big %d > %d", - i_current_frame_size, i_frame_size ); - memmove( p_sync, &p_sync[1], MAD_BUFFER_GUARD - 1 ); - p_sync[MAD_BUFFER_GUARD - 1] = GetBits( &p_dec->bit_stream, 8 ); - continue; - } + /* Check if frame is valid and get frame info */ + p_sys->i_frame_size = SyncInfo( i_header, + &p_sys->i_channels, + &p_sys->i_channels_conf, + &p_sys->i_rate, + &p_sys->i_bit_rate, + &p_sys->i_frame_length, + &p_sys->i_max_frame_size, + &p_sys->i_layer ); - if( (p_dec->p_aout_input != NULL) && - ( (p_dec->output_format.i_rate != i_rate) - || (p_dec->output_format.i_original_channels - != i_original_channels) - || (p_dec->output_format.i_bytes_per_frame - != i_frame_size + MAD_BUFFER_GUARD) - || (p_dec->output_format.i_frame_length != i_frame_length) - || (i_layer != i_new_layer) ) ) - { - /* Parameters changed - this should not happen. */ - aout_DecDelete( p_dec->p_aout, p_dec->p_aout_input ); - p_dec->p_aout_input = NULL; - } + p_dec->fmt_in.i_profile = p_sys->i_layer; - /* Creating the audio input if not created yet. */ - if( p_dec->p_aout_input == NULL ) - { - i_layer = i_new_layer; - if ( i_layer == 3 ) + if( p_sys->i_frame_size == -1 ) { - p_dec->output_format.i_format = VLC_FOURCC('m','p','g','3'); - } - else - { - p_dec->output_format.i_format = VLC_FOURCC('m','p','g','a'); + msg_Dbg( p_dec, "emulated startcode" ); + block_SkipByte( &p_sys->bytestream ); + p_sys->i_state = STATE_NOSYNC; + p_sys->b_discontinuity = true; + break; } - p_dec->output_format.i_rate = i_rate; - p_dec->output_format.i_original_channels = i_original_channels; - p_dec->output_format.i_physical_channels - = i_original_channels & AOUT_CHAN_PHYSMASK; - p_dec->output_format.i_bytes_per_frame = i_frame_size - + MAD_BUFFER_GUARD; - p_dec->output_format.i_frame_length = i_frame_length; - aout_DateInit( &end_date, i_rate ); - p_dec->p_aout_input = aout_DecNew( p_dec->p_fifo, - &p_dec->p_aout, - &p_dec->output_format ); - - if ( p_dec->p_aout_input == NULL ) + + if( p_sys->i_bit_rate == 0 ) { - p_dec->p_fifo->b_error = 1; - break; + /* Free bitrate, but 99% emulated startcode :( */ + if( p_dec->p_sys->i_free_frame_size == MPGA_HEADER_SIZE ) + { + msg_Dbg( p_dec, "free bitrate mode"); + } + /* The -1 below is to account for the frame padding */ + p_sys->i_frame_size = p_sys->i_free_frame_size - 1; } - } - if ( !aout_DateGet( &end_date ) ) - { - byte_t p_junk[MAX_FRAME_SIZE]; - - /* We've just started the stream, wait for the first PTS. */ - GetChunk( &p_dec->bit_stream, p_junk, i_current_frame_size - - MAD_BUFFER_GUARD ); - NextPTS( &p_dec->bit_stream, &pts, NULL ); - GetChunk( &p_dec->bit_stream, p_sync, MAD_BUFFER_GUARD ); - continue; - } + p_sys->i_state = STATE_NEXT_SYNC; - p_buffer = aout_DecNewBuffer( p_dec->p_aout, p_dec->p_aout_input, - i_frame_length ); - if ( p_buffer == NULL ) - { - p_dec->p_fifo->b_error = 1; - break; - } - p_buffer->start_date = aout_DateGet( &end_date ); - p_buffer->end_date = aout_DateIncrement( &end_date, - i_frame_length ); + case STATE_NEXT_SYNC: + /* TODO: If p_block == NULL, flush the buffer without checking the + * next sync word */ - /* Get the whole frame. */ - memcpy( p_buffer->p_buffer, p_sync, MAD_BUFFER_GUARD ); - if ( i_current_frame_size ) - { - GetChunk( &p_dec->bit_stream, p_buffer->p_buffer + MAD_BUFFER_GUARD, - i_current_frame_size - MAD_BUFFER_GUARD ); - } - else - { - /* Free bit-rate stream. Peek at next frame header. */ - i = MAD_BUFFER_GUARD; - for ( ; ; ) + /* Check if next expected frame contains the sync word */ + if( block_PeekOffsetBytes( &p_sys->bytestream, + p_sys->i_frame_size, p_header, + MAD_BUFFER_GUARD ) != VLC_SUCCESS ) { - int i_next_real_frame_size; - unsigned int i_next_channels, i_next_rate, i_next_bit_rate; - unsigned int i_next_frame_length, i_next_frame_size; + /* Need more data */ + return NULL; + } + + if( p_header[0] == 0xff && (p_header[1] & 0xe0) == 0xe0 ) + { + /* Startcode is fine, let's try the header as an extra check */ + int i_next_frame_size; + unsigned int i_next_channels, i_next_channels_conf; + unsigned int i_next_rate, i_next_bit_rate; + unsigned int i_next_frame_length, i_next_max_frame_size; unsigned int i_next_layer; - while ( ShowBits( &p_dec->bit_stream, 11 ) != 0x07ff && - (!p_dec->p_fifo->b_die) && - (!p_dec->p_fifo->b_error) && - i < (int)i_frame_size + MAD_BUFFER_GUARD ) + + /* Build frame header */ + i_header = (p_header[0]<<24)|(p_header[1]<<16)|(p_header[2]<<8) + |p_header[3]; + + i_next_frame_size = SyncInfo( i_header, + &i_next_channels, + &i_next_channels_conf, + &i_next_rate, + &i_next_bit_rate, + &i_next_frame_length, + &i_next_max_frame_size, + &i_next_layer ); + + /* Free bitrate only */ + if( p_sys->i_bit_rate == 0 && i_next_frame_size == -1 ) + { + if( (unsigned int)p_sys->i_frame_size > + p_sys->i_max_frame_size ) + { + msg_Dbg( p_dec, "frame too big %d > %d " + "(emulated startcode ?)", p_sys->i_frame_size, + p_sys->i_max_frame_size ); + block_SkipByte( &p_sys->bytestream ); + p_sys->i_state = STATE_NOSYNC; + p_sys->i_free_frame_size = MPGA_HEADER_SIZE; + break; + } + + p_sys->i_frame_size++; + break; + } + + if( i_next_frame_size == -1 ) { - ((uint8_t *)p_buffer->p_buffer)[i++] = - GetBits( &p_dec->bit_stream, 8 ); + msg_Dbg( p_dec, "emulated startcode on next frame" ); + block_SkipByte( &p_sys->bytestream ); + p_sys->i_state = STATE_NOSYNC; + p_sys->b_discontinuity = true; + break; } - if ( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error - || i == (int)i_frame_size + MAD_BUFFER_GUARD ) + + /* Check info is in sync with previous one */ + if( i_next_channels_conf != p_sys->i_channels_conf || + i_next_rate != p_sys->i_rate || + i_next_layer != p_sys->i_layer || + i_next_frame_length != p_sys->i_frame_length ) + { + /* Free bitrate only */ + if( p_sys->i_bit_rate == 0 ) + { + p_sys->i_frame_size++; + break; + } + + msg_Dbg( p_dec, "parameters changed unexpectedly " + "(emulated startcode ?)" ); + block_SkipByte( &p_sys->bytestream ); + p_sys->i_state = STATE_NOSYNC; break; - i_header = ShowBits( &p_dec->bit_stream, 8 ); - i_next_real_frame_size = SyncInfo( i_header, - &i_next_channels, &i_next_rate, - &i_next_bit_rate, &i_next_frame_length, - &i_next_frame_size, &i_next_layer ); - if ( i_next_real_frame_size != 0 || - i_next_channels != i_original_channels || - i_next_rate != i_rate || - i_next_bit_rate != i_bit_rate || - i_next_frame_length != i_frame_length || - i_next_frame_size != i_frame_size || - i_next_layer != i_new_layer ) + } + + /* Free bitrate only */ + if( p_sys->i_bit_rate == 0 ) { - /* This is an emulated start code, try again. */ - continue; + if( i_next_bit_rate != 0 ) + { + p_sys->i_frame_size++; + break; + } } - i_free_frame_size = i; - break; + } - if ( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error ) - break; - if ( i == (int)i_frame_size + MAD_BUFFER_GUARD ) + else { - /* Couldn't find the next start-code. This is sooo - * embarassing. */ - aout_DecDeleteBuffer( p_dec->p_aout, p_dec->p_aout_input, - p_buffer ); - NextPTS( &p_dec->bit_stream, &pts, NULL ); - GetChunk( &p_dec->bit_stream, p_sync, MAD_BUFFER_GUARD ); - continue; + /* Free bitrate only */ + if( p_sys->i_bit_rate == 0 ) + { + if( (unsigned int)p_sys->i_frame_size > + p_sys->i_max_frame_size ) + { + msg_Dbg( p_dec, "frame too big %d > %d " + "(emulated startcode ?)", p_sys->i_frame_size, + p_sys->i_max_frame_size ); + block_SkipByte( &p_sys->bytestream ); + p_sys->i_state = STATE_NOSYNC; + p_sys->i_free_frame_size = MPGA_HEADER_SIZE; + break; + } + + p_sys->i_frame_size++; + break; + } + + msg_Dbg( p_dec, "emulated startcode " + "(no startcode on following frame)" ); + p_sys->i_state = STATE_NOSYNC; + block_SkipByte( &p_sys->bytestream ); + break; } - } - if( p_dec->p_fifo->b_die ) - { - aout_DecDeleteBuffer( p_dec->p_aout, p_dec->p_aout_input, - p_buffer ); + + p_sys->i_state = STATE_SEND_DATA; break; + + case STATE_GET_DATA: + /* Make sure we have enough data. + * (Not useful if we went through NEXT_SYNC) */ + if( block_WaitBytes( &p_sys->bytestream, + p_sys->i_frame_size ) != VLC_SUCCESS ) + { + /* Need more data */ + return NULL; + } + p_sys->i_state = STATE_SEND_DATA; + + case STATE_SEND_DATA: + if( !(p_buf = GetOutBuffer( p_dec, &p_out_buffer )) ) + { + //p_dec->b_error = true; + return NULL; + } + + /* Free bitrate only */ + if( p_sys->i_bit_rate == 0 ) + { + p_sys->i_free_frame_size = p_sys->i_frame_size; + } + + /* Copy the whole frame into the buffer. When we reach this point + * we already know we have enough data available. */ + block_GetBytes( &p_sys->bytestream, + p_buf, __MIN( (unsigned)p_sys->i_frame_size, p_out_buffer->i_buffer ) ); + + /* Get beginning of next frame for libmad */ + if( !p_sys->b_packetizer ) + { + assert( p_out_buffer->i_buffer >= (unsigned)p_sys->i_frame_size + MAD_BUFFER_GUARD ); + memcpy( p_buf + p_sys->i_frame_size, + p_header, MAD_BUFFER_GUARD ); + } + + p_sys->i_state = STATE_NOSYNC; + + /* Make sure we don't reuse the same pts twice */ + if( p_sys->i_pts == p_sys->bytestream.p_block->i_pts ) + p_sys->i_pts = p_sys->bytestream.p_block->i_pts = VLC_TS_INVALID; + + /* So p_block doesn't get re-added several times */ + *pp_block = block_BytestreamPop( &p_sys->bytestream ); + + return p_out_buffer; } - /* Get beginning of next frame. */ - NextPTS( &p_dec->bit_stream, &pts, NULL ); - GetChunk( &p_dec->bit_stream, p_buffer->p_buffer + i_current_frame_size, - MAD_BUFFER_GUARD ); - memcpy( p_sync, p_buffer->p_buffer + i_current_frame_size, - MAD_BUFFER_GUARD ); + } + + return NULL; +} + +/***************************************************************************** + * GetOutBuffer: + *****************************************************************************/ +static uint8_t *GetOutBuffer( decoder_t *p_dec, block_t **pp_out_buffer ) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + uint8_t *p_buf; - p_buffer->i_nb_bytes = i_current_frame_size + MAD_BUFFER_GUARD; + if( p_dec->fmt_out.audio.i_rate != p_sys->i_rate ) + { + msg_Dbg( p_dec, "MPGA channels:%d samplerate:%d bitrate:%d", + p_sys->i_channels, p_sys->i_rate, p_sys->i_bit_rate ); - /* Send the buffer to the aout core. */ - aout_DecPlay( p_dec->p_aout, p_dec->p_aout_input, p_buffer ); + date_Init( &p_sys->end_date, p_sys->i_rate, 1 ); + date_Set( &p_sys->end_date, p_sys->i_pts ); } - if( p_dec->p_fifo->b_error ) + p_dec->fmt_out.audio.i_rate = p_sys->i_rate; + p_dec->fmt_out.audio.i_channels = p_sys->i_channels; + p_dec->fmt_out.audio.i_frame_length = p_sys->i_frame_length; + p_dec->fmt_out.audio.i_bytes_per_frame = + p_sys->i_max_frame_size + MAD_BUFFER_GUARD; + + p_dec->fmt_out.audio.i_original_channels = p_sys->i_channels_conf; + p_dec->fmt_out.audio.i_physical_channels = + p_sys->i_channels_conf & AOUT_CHAN_PHYSMASK; + + p_dec->fmt_out.i_bitrate = p_sys->i_bit_rate * 1000; + + if( p_sys->b_packetizer ) { - DecoderError( p_dec->p_fifo ); + block_t *p_sout_buffer = GetSoutBuffer( p_dec ); + p_buf = p_sout_buffer ? p_sout_buffer->p_buffer : NULL; + *pp_out_buffer = p_sout_buffer; + } + else + { + aout_buffer_t *p_aout_buffer = GetAoutBuffer( p_dec ); + p_buf = p_aout_buffer ? p_aout_buffer->p_buffer : NULL; + *pp_out_buffer = p_aout_buffer; } - EndThread( p_dec ); + return p_buf; +} - return 0; +/***************************************************************************** + * GetAoutBuffer: + *****************************************************************************/ +static aout_buffer_t *GetAoutBuffer( decoder_t *p_dec ) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + aout_buffer_t *p_buf; + + p_buf = decoder_NewAudioBuffer( p_dec, p_sys->i_frame_length ); + if( p_buf == NULL ) return NULL; + + p_buf->i_pts = date_Get( &p_sys->end_date ); + p_buf->i_length = date_Increment( &p_sys->end_date, p_sys->i_frame_length ) + - p_buf->i_pts; + if( p_sys->b_discontinuity ) + p_buf->i_flags |= BLOCK_FLAG_DISCONTINUITY; + p_sys->b_discontinuity = false; + + /* Hack for libmad filter */ + p_buf = block_Realloc( p_buf, 0, p_sys->i_frame_size + MAD_BUFFER_GUARD ); + + return p_buf; } /***************************************************************************** - * EndThread : thread destruction + * GetSoutBuffer: *****************************************************************************/ -static void EndThread( dec_thread_t * p_dec ) +static block_t *GetSoutBuffer( decoder_t *p_dec ) { - if ( p_dec->p_aout_input != NULL ) - { - aout_DecDelete( p_dec->p_aout, p_dec->p_aout_input ); - } + decoder_sys_t *p_sys = p_dec->p_sys; + block_t *p_block; + + p_block = block_New( p_dec, p_sys->i_frame_size ); + if( p_block == NULL ) return NULL; + + p_block->i_pts = p_block->i_dts = date_Get( &p_sys->end_date ); - CloseBitstream( &p_dec->bit_stream ); - free( p_dec ); + p_block->i_length = + date_Increment( &p_sys->end_date, p_sys->i_frame_length ) - p_block->i_pts; + + return p_block; +} + +/***************************************************************************** + * CloseDecoder: clean up the decoder + *****************************************************************************/ +static void CloseDecoder( vlc_object_t *p_this ) +{ + decoder_t *p_dec = (decoder_t *)p_this; + decoder_sys_t *p_sys = p_dec->p_sys; + + block_BytestreamRelease( &p_sys->bytestream ); + + free( p_sys ); } /***************************************************************************** * SyncInfo: parse MPEG audio sync info *****************************************************************************/ static int SyncInfo( uint32_t i_header, unsigned int * pi_channels, + unsigned int * pi_channels_conf, unsigned int * pi_sample_rate, unsigned int * pi_bit_rate, unsigned int * pi_frame_length, - unsigned int * pi_frame_size, unsigned int * pi_layer ) + unsigned int * pi_max_frame_size, unsigned int * pi_layer) { - static const int pppi_mpegaudio_bitrate[2][3][16] = + static const int ppi_bitrate[2][3][16] = { { /* v1 l1 */ @@ -428,7 +609,7 @@ static int SyncInfo( uint32_t i_header, unsigned int * pi_channels, 320, 384, 0}, /* v1 l3 */ { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, - 256, 320, 0} + 256, 320, 0} }, { @@ -440,26 +621,26 @@ static int SyncInfo( uint32_t i_header, unsigned int * pi_channels, 144, 160, 0}, /* v2 l3 */ { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, - 144, 160, 0} + 144, 160, 0} } }; - static const int ppi_mpegaudio_samplerate[2][4] = /* version 1 then 2 */ + static const int ppi_samplerate[2][4] = /* version 1 then 2 */ { { 44100, 48000, 32000, 0 }, { 22050, 24000, 16000, 0 } }; int i_version, i_mode, i_emphasis; - vlc_bool_t b_padding, b_mpeg_2_5; - int i_current_frame_size = 0; + bool b_padding, b_mpeg_2_5, b_crc; + int i_frame_size = 0; int i_bitrate_index, i_samplerate_index; int i_max_bit_rate; b_mpeg_2_5 = 1 - ((i_header & 0x100000) >> 20); i_version = 1 - ((i_header & 0x80000) >> 19); *pi_layer = 4 - ((i_header & 0x60000) >> 17); - /* CRC */ + b_crc = !((i_header >> 16) & 0x01); i_bitrate_index = (i_header & 0xf000) >> 12; i_samplerate_index = (i_header & 0xc00) >> 10; b_padding = (i_header & 0x200) >> 9; @@ -477,19 +658,22 @@ static int SyncInfo( uint32_t i_header, unsigned int * pi_channels, { case 0: /* stereo */ case 1: /* joint stereo */ - *pi_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; + *pi_channels = 2; + *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; break; case 2: /* dual-mono */ - *pi_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT - | AOUT_CHAN_DUALMONO; + *pi_channels = 2; + *pi_channels_conf = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT + | AOUT_CHAN_DUALMONO; break; case 3: /* mono */ - *pi_channels = AOUT_CHAN_CENTER; + *pi_channels = 1; + *pi_channels_conf = AOUT_CHAN_CENTER; break; } - *pi_bit_rate = pppi_mpegaudio_bitrate[i_version][*pi_layer-1][i_bitrate_index]; - i_max_bit_rate = pppi_mpegaudio_bitrate[i_version][*pi_layer-1][14]; - *pi_sample_rate = ppi_mpegaudio_samplerate[i_version][i_samplerate_index]; + *pi_bit_rate = ppi_bitrate[i_version][*pi_layer-1][i_bitrate_index]; + i_max_bit_rate = ppi_bitrate[i_version][*pi_layer-1][14]; + *pi_sample_rate = ppi_samplerate[i_version][i_samplerate_index]; if ( b_mpeg_2_5 ) { @@ -499,40 +683,38 @@ static int SyncInfo( uint32_t i_header, unsigned int * pi_channels, switch( *pi_layer ) { case 1: - i_current_frame_size = ( ( i_version ? 6000 : 12000 ) * - *pi_bit_rate / *pi_sample_rate - + b_padding ) * 4; - *pi_frame_size = ( ( i_version ? 6000 : 12000 ) * - i_max_bit_rate / *pi_sample_rate + 1 ) * 4; + i_frame_size = ( 12000 * *pi_bit_rate / *pi_sample_rate + + b_padding ) * 4; + *pi_max_frame_size = ( 12000 * i_max_bit_rate / + *pi_sample_rate + 1 ) * 4; *pi_frame_length = 384; break; case 2: - i_current_frame_size = ( i_version ? 72000 : 144000 ) * - *pi_bit_rate / *pi_sample_rate - + b_padding; - *pi_frame_size = ( i_version ? 72000 : 144000 ) * - i_max_bit_rate / *pi_sample_rate + 1; + i_frame_size = 144000 * *pi_bit_rate / *pi_sample_rate + b_padding; + *pi_max_frame_size = 144000 * i_max_bit_rate / *pi_sample_rate + 1; *pi_frame_length = 1152; break; case 3: - i_current_frame_size = ( i_version ? 72000 : 144000 ) * - *pi_bit_rate / *pi_sample_rate - + b_padding; - *pi_frame_size = ( i_version ? 72000 : 144000 ) * - i_max_bit_rate / *pi_sample_rate + 1; + i_frame_size = ( i_version ? 72000 : 144000 ) * + *pi_bit_rate / *pi_sample_rate + b_padding; + *pi_max_frame_size = ( i_version ? 72000 : 144000 ) * + i_max_bit_rate / *pi_sample_rate + 1; *pi_frame_length = i_version ? 576 : 1152; break; default: + break; } + + /* Free bitrate mode can support higher bitrates */ + if( !*pi_bit_rate ) *pi_max_frame_size *= 2; } else { return -1; } - - return i_current_frame_size; -} + return i_frame_size; +}