X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Fmpeg_audio.c;h=f7dbd4635d9d8b699860db972505be438db68a8f;hb=70ee5fbf988a94c0c2e394f3346a3dc6eeb18d72;hp=7966d7c0d1c379972231becd66d770a99e034529;hpb=c19154da5ff3cbba7809e839a2a58651cf7addea;p=vlc diff --git a/modules/codec/mpeg_audio.c b/modules/codec/mpeg_audio.c index 7966d7c0d1..f7dbd4635d 100644 --- a/modules/codec/mpeg_audio.c +++ b/modules/codec/mpeg_audio.c @@ -2,11 +2,12 @@ * mpeg_audio.c: parse MPEG audio sync info and packetize the stream ***************************************************************************** * Copyright (C) 2001-2003 VideoLAN - * $Id: mpeg_audio.c,v 1.15 2003/05/04 10:46:28 fenrir Exp $ + * $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 @@ -26,58 +27,76 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include /* malloc(), free() */ -#include /* strdup() */ - #include -#include #include +#include + +#include "vlc_block_helper.h" /***************************************************************************** - * 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 */ + vlc_bool_t 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; + audio_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; +}; + +enum { + + STATE_NOSYNC, + STATE_SYNC, + STATE_HEADER, + STATE_NEXT_SYNC, + STATE_GET_DATA, + STATE_SEND_DATA +}; -#define MAX_FRAME_SIZE 10000 /* 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 *, void ** ); +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 ); /***************************************************************************** @@ -85,351 +104,467 @@ static int SyncInfo( uint32_t i_header, unsigned int * pi_channels, *****************************************************************************/ vlc_module_begin(); set_description( _("MPEG audio layer I/II/III parser") ); + set_category( CAT_INPUT ); + set_subcategory( SUBCAT_INPUT_ACODEC ); +#if defined(SYS_DARWIN) || defined(UNDER_CE) + set_capability( "decoder", 5 ); +#else set_capability( "decoder", 100 ); - set_callbacks( Open, NULL ); +#endif + set_callbacks( OpenDecoder, CloseDecoder ); + + add_submodule(); + set_description( _("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 *****************************************************************************/ -static int Open( vlc_object_t *p_this ) +static int OpenDecoder( 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_dec->fmt_in.i_codec != VLC_FOURCC('m','p','g','a') ) + { + return VLC_EGENERIC; + } - if( p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', 'a') ) + /* 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 ) { + msg_Err( p_dec, "out of memory" ); return VLC_EGENERIC; } - p_fifo->pf_run = RunDecoder; + /* Misc init */ + p_sys->b_packetizer = VLC_FALSE; + p_sys->i_state = STATE_NOSYNC; + aout_DateSet( &p_sys->end_date, 0 ); + p_sys->bytestream = block_BytestreamInit( p_dec ); + + /* Set output properties */ + p_dec->fmt_out.i_cat = AUDIO_ES; + p_dec->fmt_out.i_codec = VLC_FOURCC('m','p','g','a'); + 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 OpenPacketizer( 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; - } + decoder_t *p_dec = (decoder_t*)p_this; + + int i_ret = OpenDecoder( p_this ); + + if( i_ret == VLC_SUCCESS ) p_dec->p_sys->b_packetizer = VLC_TRUE; - /* Initialize the thread properties */ - p_dec->p_aout = NULL; - p_dec->p_aout_input = NULL; - p_dec->p_fifo = p_fifo; + 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; + void *p_out_buffer; - aout_DateSet( &end_date, 0 ); + if( !pp_block || !*pp_block ) return NULL; - /* Init the bitstream */ - if( InitBitstream( &p_dec->bit_stream, p_dec->p_fifo, - NULL, NULL ) != VLC_SUCCESS ) + if( !aout_DateGet( &p_sys->end_date ) && !(*pp_block)->i_pts ) { - msg_Err( p_fifo, "cannot initialize bitstream" ); - DecoderError( p_fifo ); - free( p_dec ); - return -1; + /* We've just started the stream, wait for the first PTS. */ + block_Release( *pp_block ); + return NULL; } - /* Init sync buffer. */ - NextPTS( &p_dec->bit_stream, &pts, NULL ); - GetChunk( &p_dec->bit_stream, p_sync, MAD_BUFFER_GUARD ); + if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) + { + p_sys->i_state = STATE_NOSYNC; + } - /* 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 != 0 && + p_sys->i_pts != aout_DateGet( &p_sys->end_date ) ) { - if ( p_sync[MAD_BUFFER_GUARD - 1] == 0xff - && ShowBits( &p_dec->bit_stream, 3 ) == 0x3 ) + aout_DateSet( &p_sys->end_date, p_sys->i_pts ); + } + p_sys->i_state = STATE_HEADER; + + 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; + } + + /* Build frame header */ + i_header = (p_header[0]<<24)|(p_header[1]<<16)|(p_header[2]<<8) + |p_header[3]; + + /* 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_sys->i_frame_size == -1 ) + { + msg_Dbg( p_dec, "emulated startcode" ); + block_SkipByte( &p_sys->bytestream ); + p_sys->i_state = STATE_NOSYNC; + break; + } + + if( p_sys->i_bit_rate == 0 ) + { + /* Free birate, but 99% emulated startcode :( */ + if( p_dec->p_sys->i_free_frame_size == MPGA_HEADER_SIZE ) { - /* Found it ! */ - p_sync[0] = p_sync[MAD_BUFFER_GUARD - 1]; - GetChunk( &p_dec->bit_stream, - &p_sync[1], MAD_BUFFER_GUARD - 1 ); + msg_Dbg( p_dec, "free bitrate mode"); } - else + p_sys->i_frame_size = p_sys->i_free_frame_size; + } + + p_sys->i_state = STATE_NEXT_SYNC; + + case STATE_NEXT_SYNC: + /* TODO: If p_block == NULL, flush the buffer without checking the + * next sync word */ + + /* 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 ) + { + /* 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; + + /* 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 ) { - /* Scan the stream. */ - while ( ShowBits( &p_dec->bit_stream, 11 ) != 0x07ff && - (!p_dec->p_fifo->b_die) && - (!p_dec->p_fifo->b_error) ) + if( (unsigned int)p_sys->i_frame_size > + p_sys->i_max_frame_size ) { - RemoveBits( &p_dec->bit_stream, 8 ); - } - if ( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error ) + 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; - NextPTS( &p_dec->bit_stream, &pts, NULL ); - GetChunk( &p_dec->bit_stream,p_sync, MAD_BUFFER_GUARD ); - } - } - } - if ( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error ) break; + } - /* Set the Presentation Time Stamp */ - if ( pts != 0 && pts != aout_DateGet( &end_date ) ) - { - aout_DateSet( &end_date, pts ); - } + p_sys->i_frame_size++; + break; + } - /* Get frame header */ - i_header = (p_sync[0] << 24) | (p_sync[1] << 16) | (p_sync[2] << 8) - | p_sync[3]; + if( i_next_frame_size == -1 ) + { + msg_Dbg( p_dec, "emulated startcode on next frame" ); + block_SkipByte( &p_sys->bytestream ); + p_sys->i_state = STATE_NOSYNC; + break; + } - /* 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; + /* 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; + } - 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; - } + msg_Dbg( p_dec, "parameters changed unexpectedly " + "(emulated startcode ?)" ); + block_SkipByte( &p_sys->bytestream ); + p_sys->i_state = STATE_NOSYNC; + break; + } - 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; - } + /* Free bitrate only */ + if( p_sys->i_bit_rate == 0 ) + { + if( i_next_bit_rate != 0 ) + { + p_sys->i_frame_size++; + break; + } + } - /* Creating the audio input if not created yet. */ - if( p_dec->p_aout_input == NULL ) - { - i_layer = i_new_layer; - if ( i_layer == 3 ) - { - 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'); - } - 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 ); - aout_DateSet( &end_date, pts ); - 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 ) - { - p_dec->p_fifo->b_error = 1; + /* 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 ( !aout_DateGet( &end_date ) ) - { - byte_t p_junk[MAX_FRAME_SIZE]; - int i_skip = i_current_frame_size - MAD_BUFFER_GUARD; + p_sys->i_state = STATE_SEND_DATA; + break; - /* We've just started the stream, wait for the first PTS. */ - while( i_skip > 0 ) + 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 ) { - int i_read; - - i_read = __MIN( i_current_frame_size - MAD_BUFFER_GUARD, MAX_FRAME_SIZE ); - GetChunk( &p_dec->bit_stream, p_junk, i_read ); - - i_skip -= i_read; + /* Need more data */ + return NULL; } - NextPTS( &p_dec->bit_stream, &pts, NULL ); - GetChunk( &p_dec->bit_stream, p_sync, MAD_BUFFER_GUARD ); - continue; - } + p_sys->i_state = STATE_SEND_DATA; - 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_SEND_DATA: + if( !(p_buf = GetOutBuffer( p_dec, &p_out_buffer )) ) + { + //p_dec->b_error = VLC_TRUE; + return NULL; + } - /* 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 ( ; ; ) + /* Free bitrate only */ + if( p_sys->i_bit_rate == 0 ) { - 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; - 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 ) - { - ((uint8_t *)p_buffer->p_buffer)[i++] = - GetBits( &p_dec->bit_stream, 8 ); - } - if ( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error - || i == (int)i_frame_size + MAD_BUFFER_GUARD ) - 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 ) - { - /* This is an emulated start code, try again. */ - /* there is at least 1 byte free */ - ((uint8_t *)p_buffer->p_buffer)[i++] = - GetBits( &p_dec->bit_stream, 8 ); - continue; - } - i_free_frame_size = i; - break; + p_sys->i_free_frame_size = p_sys->i_frame_size; } - if ( p_dec->p_fifo->b_die || p_dec->p_fifo->b_error ) - break; - if ( i == (int)i_frame_size + MAD_BUFFER_GUARD ) + + /* 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, p_sys->i_frame_size ); + + /* Get beginning of next frame for libmad */ + if( !p_sys->b_packetizer ) { - /* 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; + 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 = 0; + + /* So p_block doesn't get re-added several times */ + *pp_block = block_BytestreamPop( &p_sys->bytestream ); + + return p_out_buffer; } - if( p_dec->p_fifo->b_die ) - { - aout_DecDeleteBuffer( p_dec->p_aout, p_dec->p_aout_input, - p_buffer ); - break; - } - /* 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 ); + } - p_buffer->i_nb_bytes = i_current_frame_size + MAD_BUFFER_GUARD; + return NULL; +} - /* Send the buffer to the aout core. */ - aout_DecPlay( p_dec->p_aout, p_dec->p_aout_input, p_buffer ); +/***************************************************************************** + * GetOutBuffer: + *****************************************************************************/ +static uint8_t *GetOutBuffer( decoder_t *p_dec, void **pp_out_buffer ) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + uint8_t *p_buf; + + if( p_dec->fmt_out.audio.i_rate != p_sys->i_rate ) + { + msg_Info( p_dec, "MPGA channels:%d samplerate:%d bitrate:%d", + p_sys->i_channels, p_sys->i_rate, p_sys->i_bit_rate ); + + aout_DateInit( &p_sys->end_date, p_sys->i_rate ); + aout_DateSet( &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 ) + { + 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 { - DecoderError( p_dec->p_fifo ); + 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; +} + +/***************************************************************************** + * 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 = p_dec->pf_aout_buffer_new( p_dec, p_sys->i_frame_length ); + if( p_buf == NULL ) return NULL; - return 0; + p_buf->start_date = aout_DateGet( &p_sys->end_date ); + p_buf->end_date = + aout_DateIncrement( &p_sys->end_date, p_sys->i_frame_length ); + + /* Hack for libmad filter */ + p_buf->i_nb_bytes = 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; - CloseBitstream( &p_dec->bit_stream ); - free( p_dec ); + p_block->i_pts = p_block->i_dts = aout_DateGet( &p_sys->end_date ); + + p_block->i_length = + aout_DateIncrement( &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 */ @@ -456,22 +591,22 @@ static int SyncInfo( uint32_t i_header, unsigned int * pi_channels, } }; - 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; + vlc_bool_t 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; @@ -489,19 +624,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 ) { @@ -511,26 +649,23 @@ static int SyncInfo( uint32_t i_header, unsigned int * pi_channels, switch( *pi_layer ) { case 1: - i_current_frame_size = ( 12000 * - *pi_bit_rate / *pi_sample_rate - + b_padding ) * 4; - *pi_frame_size = ( 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 = 144000 * - *pi_bit_rate / *pi_sample_rate - + b_padding; - *pi_frame_size = 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_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; @@ -544,6 +679,5 @@ static int SyncInfo( uint32_t i_header, unsigned int * pi_channels, return -1; } - return i_current_frame_size; + return i_frame_size; } -