X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Fflac.c;h=c77f9dcc3ac69db518f3f106224d18db2d75b784;hb=694be9ad65fbf123bea29a9e338231de2122569c;hp=1b31aabb7daf30a00fe86a60090d4e865a87c4b6;hpb=de81c25db345fcad4ac8106f52845dc2fd11cf50;p=vlc diff --git a/modules/codec/flac.c b/modules/codec/flac.c index 1b31aabb7d..c77f9dcc3a 100644 --- a/modules/codec/flac.c +++ b/modules/codec/flac.c @@ -1,11 +1,11 @@ /***************************************************************************** * flac.c: flac decoder/packetizer/encoder module making use of libflac ***************************************************************************** - * Copyright (C) 1999-2001 VideoLAN - * $Id: flac.c,v 1.9 2004/02/25 17:48:52 fenrir Exp $ + * Copyright (C) 1999-2001 the VideoLAN team + * $Id$ * - * Authors: Gildas Bazin - * Sigmund Augdal + * Authors: Gildas Bazin + * Sigmund Augdal Helberg * * 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 @@ -19,7 +19,7 @@ * * 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. *****************************************************************************/ /***************************************************************************** @@ -27,15 +27,24 @@ *****************************************************************************/ #include -#include +#include +#include -#include -#include +#ifdef HAVE_FLAC_STREAM_DECODER_H +# include +# include +# define USE_LIBFLAC +#endif -#include "vlc_block_helper.h" +#include +#include #define MAX_FLAC_HEADER_SIZE 16 +#if defined(FLAC_API_VERSION_CURRENT) && FLAC_API_VERSION_CURRENT >= 8 +# define USE_NEW_FLAC_API +#endif + /***************************************************************************** * decoder_sys_t : FLAC decoder descriptor *****************************************************************************/ @@ -57,10 +66,21 @@ struct decoder_sys_t /* * FLAC properties */ +#ifdef USE_LIBFLAC FLAC__StreamDecoder *p_flac; - - vlc_bool_t b_stream_info; FLAC__StreamMetadata_StreamInfo stream_info; +#else + struct + { + unsigned min_blocksize, max_blocksize; + unsigned min_framesize, max_framesize; + unsigned sample_rate; + unsigned channels; + unsigned bits_per_sample; + + } stream_info; +#endif + vlc_bool_t b_stream_info; /* * Common properties @@ -82,7 +102,7 @@ enum { STATE_SEND_DATA }; -static int pi_channels_maps[6] = +static int pi_channels_maps[7] = { 0, AOUT_CHAN_CENTER, @@ -91,7 +111,9 @@ static int pi_channels_maps[6] = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT, AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER - | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT + | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT, + AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER + | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE }; /***************************************************************************** @@ -101,15 +123,21 @@ static int OpenDecoder ( vlc_object_t * ); static int OpenPacketizer( vlc_object_t * ); static void CloseDecoder ( vlc_object_t * ); +#ifdef USE_LIBFLAC static int OpenEncoder ( vlc_object_t * ); static void CloseEncoder ( vlc_object_t * ); +#endif +#ifdef USE_LIBFLAC static aout_buffer_t *DecodeBlock( decoder_t *, block_t ** ); +#endif static block_t *PacketizeBlock( decoder_t *, block_t ** ); -static int SyncInfo( decoder_t *, uint8_t *, int *, int *, int *,int * ); +static int SyncInfo( decoder_t *, uint8_t *, unsigned int *, unsigned int *, + unsigned int *,int * ); +#ifdef USE_LIBFLAC static FLAC__StreamDecoderReadStatus DecoderReadCallback( const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data ); @@ -133,6 +161,7 @@ static void Interleave16( int16_t *p_out, const int32_t * const *pp_in, static void decoder_state_error( decoder_t *p_dec, FLAC__StreamDecoderState state ); +#endif static uint64_t read_utf8( const uint8_t *p_buf, int *pi_read ); static uint8_t flac_crc8( const uint8_t *data, unsigned len ); @@ -142,20 +171,26 @@ static uint8_t flac_crc8( const uint8_t *data, unsigned len ); *****************************************************************************/ vlc_module_begin(); + set_category( CAT_INPUT ); + set_subcategory( SUBCAT_INPUT_ACODEC ); + add_shortcut( "flac" ); + +#ifdef USE_LIBFLAC set_description( _("Flac audio decoder") ); set_capability( "decoder", 100 ); set_callbacks( OpenDecoder, CloseDecoder ); - add_submodule(); - set_description( _("Flac audio packetizer") ); - set_capability( "packetizer", 100 ); - set_callbacks( OpenPacketizer, CloseDecoder ); - add_submodule(); set_description( _("Flac audio encoder") ); set_capability( "encoder", 100 ); set_callbacks( OpenEncoder, CloseEncoder ); + add_submodule(); +#endif + set_description( _("Flac audio packetizer") ); + set_capability( "packetizer", 100 ); + set_callbacks( OpenPacketizer, CloseDecoder ); + vlc_module_end(); /***************************************************************************** @@ -183,9 +218,10 @@ static int OpenDecoder( vlc_object_t *p_this ) aout_DateSet( &p_sys->end_date, 0 ); p_sys->i_state = STATE_NOSYNC; p_sys->b_stream_info = VLC_FALSE; - + p_sys->p_block=NULL; p_sys->bytestream = block_BytestreamInit( p_dec ); +#ifdef USE_LIBFLAC /* Take care of flac init */ if( !(p_sys->p_flac = FLAC__stream_decoder_new()) ) { @@ -194,6 +230,25 @@ static int OpenDecoder( vlc_object_t *p_this ) return VLC_EGENERIC; } +#ifdef USE_NEW_FLAC_API + if( FLAC__stream_decoder_init_stream( p_sys->p_flac, + DecoderReadCallback, + NULL, + NULL, + NULL, + NULL, + DecoderWriteCallback, + DecoderMetadataCallback, + DecoderErrorCallback, + p_dec ) + != FLAC__STREAM_DECODER_INIT_STATUS_OK ) + { + msg_Err( p_dec, "FLAC__stream_decoder_init_stream() failed" ); + FLAC__stream_decoder_delete( p_sys->p_flac ); + free( p_sys ); + return VLC_EGENERIC; + } +#else FLAC__stream_decoder_set_read_callback( p_sys->p_flac, DecoderReadCallback ); FLAC__stream_decoder_set_write_callback( p_sys->p_flac, @@ -205,15 +260,72 @@ static int OpenDecoder( vlc_object_t *p_this ) FLAC__stream_decoder_set_client_data( p_sys->p_flac, p_dec ); FLAC__stream_decoder_init( p_sys->p_flac ); +#endif +#endif /* Set output properties */ p_dec->fmt_out.i_cat = AUDIO_ES; p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','3','2'); /* Set callbacks */ +#ifdef USE_LIBFLAC p_dec->pf_decode_audio = DecodeBlock; +#endif + + return VLC_SUCCESS; +} + +static int OpenPacketizer( vlc_object_t *p_this ) +{ + decoder_t *p_dec = (decoder_t*)p_this; + es_format_t es_save = p_dec->fmt_out; + int i_ret; + + /* */ + es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); + + i_ret = OpenDecoder( p_this ); + p_dec->pf_decode_audio = NULL; p_dec->pf_packetize = PacketizeBlock; + /* Set output properties */ + p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','a','c'); + + if( i_ret != VLC_SUCCESS ) + { + es_format_Clean( &p_dec->fmt_out ); + p_dec->fmt_out = es_save; + } + return i_ret; +} + +/***************************************************************************** + * CloseDecoder: flac decoder destruction + *****************************************************************************/ +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; + +#ifdef USE_LIBFLAC + FLAC__stream_decoder_finish( p_sys->p_flac ); + FLAC__stream_decoder_delete( p_sys->p_flac ); +#endif + + if( p_sys->p_block ) free( p_sys->p_block ); + free( p_sys ); +} + +/***************************************************************************** + * ProcessHeader: process Flac header. + *****************************************************************************/ +static void ProcessHeader( decoder_t *p_dec ) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + +#ifdef USE_LIBFLAC + if( !p_dec->fmt_in.i_extra ) return; + /* Decode STREAMINFO */ msg_Dbg( p_dec, "decode STREAMINFO" ); p_sys->p_block = block_New( p_dec, p_dec->fmt_in.i_extra ); @@ -222,20 +334,34 @@ static int OpenDecoder( vlc_object_t *p_this ) FLAC__stream_decoder_process_until_end_of_metadata( p_sys->p_flac ); msg_Dbg( p_dec, "STREAMINFO decoded" ); - return VLC_SUCCESS; -} +#else + bs_t bs; -static int OpenPacketizer( vlc_object_t *p_this ) -{ - decoder_t *p_dec = (decoder_t*)p_this; + if( !p_dec->fmt_in.i_extra ) return; - int i_ret = OpenDecoder( p_this ); + bs_init( &bs, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); - if( i_ret != VLC_SUCCESS ) return i_ret; + p_sys->stream_info.min_blocksize = bs_read( &bs, 16 ); + p_sys->stream_info.max_blocksize = bs_read( &bs, 16 ); - es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); + p_sys->stream_info.min_framesize = bs_read( &bs, 24 ); + p_sys->stream_info.max_framesize = bs_read( &bs, 24 ); - return i_ret; + p_sys->stream_info.sample_rate = bs_read( &bs, 20 ); + p_sys->stream_info.channels = bs_read( &bs, 3 ) + 1; + p_sys->stream_info.bits_per_sample = bs_read( &bs, 5 ) + 1; +#endif + + if( !p_sys->b_stream_info ) return; + + if( p_dec->fmt_out.i_codec == VLC_FOURCC('f','l','a','c') ) + { + p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; + p_dec->fmt_out.p_extra = + realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); + memcpy( p_dec->fmt_out.p_extra, + p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra ); + } } /**************************************************************************** @@ -251,16 +377,36 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) if( !pp_block || !*pp_block ) return NULL; + if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) + { + if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) + { + p_sys->i_state = STATE_NOSYNC; + block_BytestreamFlush( &p_sys->bytestream ); + } +// aout_DateSet( &p_sys->end_date, 0 ); + block_Release( *pp_block ); + return NULL; + } + + if( !p_sys->b_stream_info ) ProcessHeader( p_dec ); + + if( p_sys->stream_info.channels > 6 ) + { + msg_Err( p_dec, "This stream uses too many audio channels" ); + return NULL; + } + if( !aout_DateGet( &p_sys->end_date ) && !(*pp_block)->i_pts ) { /* We've just started the stream, wait for the first PTS. */ block_Release( *pp_block ); return NULL; } - - if( (*pp_block)->i_flags&BLOCK_FLAG_DISCONTINUITY ) + else if( !aout_DateGet( &p_sys->end_date ) ) { - p_sys->i_state = STATE_NOSYNC; + /* The first PTS is as good as anything else. */ + aout_DateSet( &p_sys->end_date, (*pp_block)->i_pts ); } block_BytestreamPush( &p_sys->bytestream, *pp_block ); @@ -324,7 +470,6 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) { p_dec->fmt_out.audio.i_rate = p_sys->i_rate; aout_DateInit( &p_sys->end_date, p_sys->i_rate ); - p_dec->fmt_out.audio.i_rate = p_sys->i_rate; } p_sys->i_state = STATE_NEXT_SYNC; p_sys->i_frame_size = 1; @@ -363,7 +508,6 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) /* Need more data */ return NULL; } - break; case STATE_SEND_DATA: p_sout_block = block_New( p_dec, p_sys->i_frame_size ); @@ -396,6 +540,7 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) return NULL; } +#ifdef USE_LIBFLAC /**************************************************************************** * DecodeBlock: the whole thing ****************************************************************************/ @@ -430,20 +575,6 @@ static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) return p_sys->p_aout_buffer; } -/***************************************************************************** - * CloseDecoder: flac decoder destruction - *****************************************************************************/ -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; - - FLAC__stream_decoder_finish( p_sys->p_flac ); - FLAC__stream_decoder_delete( p_sys->p_flac ); - if( p_sys->p_block ) free( p_sys->p_block ); - free( p_sys ); -} - /***************************************************************************** * DecoderReadCallback: called by libflac when it needs more data *****************************************************************************/ @@ -516,19 +647,22 @@ static void DecoderMetadataCallback( const FLAC__StreamDecoder *decoder, decoder_t *p_dec = (decoder_t *)client_data; decoder_sys_t *p_sys = p_dec->p_sys; - switch( metadata->data.stream_info.bits_per_sample ) + if( p_dec->pf_decode_audio ) { - case 8: - p_dec->fmt_out.i_codec = VLC_FOURCC('s','8',' ',' '); - break; - case 16: - p_dec->fmt_out.i_codec = AOUT_FMT_S16_NE; - break; - default: - msg_Dbg( p_dec, "strange bit/sample value: %d", - metadata->data.stream_info.bits_per_sample ); - p_dec->fmt_out.i_codec = VLC_FOURCC('f','i','3','2'); - break; + switch( metadata->data.stream_info.bits_per_sample ) + { + case 8: + p_dec->fmt_out.i_codec = VLC_FOURCC('s','8',' ',' '); + break; + case 16: + p_dec->fmt_out.i_codec = AOUT_FMT_S16_NE; + break; + default: + msg_Dbg( p_dec, "strange bit/sample value: %d", + metadata->data.stream_info.bits_per_sample ); + p_dec->fmt_out.i_codec = VLC_FOURCC('f','i','3','2'); + break; + } } /* Setup the format */ @@ -564,7 +698,7 @@ static void DecoderErrorCallback( const FLAC__StreamDecoder *decoder, switch( status ) { case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC: - msg_Err( p_dec, "an error in the stream caused the decoder to " + msg_Warn( p_dec, "an error in the stream caused the decoder to " "lose synchronization." ); break; case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER: @@ -619,33 +753,44 @@ static void decoder_state_error( decoder_t *p_dec, switch ( state ) { case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: - msg_Err( p_dec, "the decoder is ready to search for metadata." ); + msg_Dbg( p_dec, "the decoder is ready to search for metadata." ); break; case FLAC__STREAM_DECODER_READ_METADATA: - msg_Err( p_dec, "the decoder is ready to or is in the process of " + msg_Dbg( p_dec, "the decoder is ready to or is in the process of " "reading metadata." ); break; case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - msg_Err( p_dec, "the decoder is ready to or is in the process of " + msg_Dbg( p_dec, "the decoder is ready to or is in the process of " "searching for the frame sync code." ); break; case FLAC__STREAM_DECODER_READ_FRAME: - msg_Err( p_dec, "the decoder is ready to or is in the process of " + msg_Dbg( p_dec, "the decoder is ready to or is in the process of " "reading a frame." ); break; case FLAC__STREAM_DECODER_END_OF_STREAM: - msg_Err( p_dec, "the decoder has reached the end of the stream." ); + msg_Dbg( p_dec, "the decoder has reached the end of the stream." ); + break; +#ifdef USE_NEW_FLAC_API + case FLAC__STREAM_DECODER_OGG_ERROR: + msg_Err( p_dec, "error occurred in the Ogg layer." ); break; + case FLAC__STREAM_DECODER_SEEK_ERROR: + msg_Err( p_dec, "error occurred while seeking." ); + break; +#endif case FLAC__STREAM_DECODER_ABORTED: - msg_Err( p_dec, "the decoder was aborted by the read callback." ); + msg_Warn( p_dec, "the decoder was aborted by the read callback." ); break; +#ifndef USE_NEW_FLAC_API case FLAC__STREAM_DECODER_UNPARSEABLE_STREAM: - msg_Err( p_dec, "the decoder encountered reserved fields in use " + msg_Warn( p_dec, "the decoder encountered reserved fields in use " "in the stream." ); break; +#endif case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR: msg_Err( p_dec, "error when allocating memory." ); break; +#ifndef USE_NEW_FLAC_API case FLAC__STREAM_DECODER_ALREADY_INITIALIZED: msg_Err( p_dec, "FLAC__stream_decoder_init() was called when the " "decoder was already initialized, usually because " @@ -655,20 +800,24 @@ static void decoder_state_error( decoder_t *p_dec, msg_Err( p_dec, "FLAC__stream_decoder_init() was called without " "all callbacks being set." ); break; +#endif case FLAC__STREAM_DECODER_UNINITIALIZED: msg_Err( p_dec, "decoder in uninitialized state." ); break; default: - msg_Err(p_dec, "unknown error" ); + msg_Warn(p_dec, "unknown error" ); } } +#endif /***************************************************************************** * SyncInfo: parse FLAC sync info *****************************************************************************/ static int SyncInfo( decoder_t *p_dec, uint8_t *p_buf, - int * pi_channels, int * pi_channels_conf, - int * pi_sample_rate, int * pi_bits_per_sample ) + unsigned int * pi_channels, + unsigned int * pi_channels_conf, + unsigned int * pi_sample_rate, + int * pi_bits_per_sample ) { decoder_sys_t *p_sys = p_dec->p_sys; int i_header, i_temp, i_read; @@ -784,9 +933,9 @@ static int SyncInfo( decoder_t *p_dec, uint8_t *p_buf, i_temp = (unsigned)(p_buf[3] >> 4); if( i_temp & 8 ) { +#ifdef USE_LIBFLAC int i_channel_assignment; /* ??? */ - *pi_channels = 2; switch( i_temp & 7 ) { case 0: @@ -802,6 +951,9 @@ static int SyncInfo( decoder_t *p_dec, uint8_t *p_buf, return 0; break; } +#endif + + *pi_channels = 2; } else { @@ -1008,6 +1160,7 @@ static uint8_t flac_crc8( const uint8_t *data, unsigned len ) return crc; } +#ifdef USE_LIBFLAC /***************************************************************************** * encoder_sys_t : flac encoder descriptor *****************************************************************************/ @@ -1022,7 +1175,7 @@ struct encoder_sys_t int i_channels; FLAC__int32 *p_buffer; - int i_buffer; + unsigned int i_buffer; block_t *p_chain; @@ -1060,7 +1213,8 @@ static int OpenEncoder( vlc_object_t *p_this ) encoder_t *p_enc = (encoder_t *)p_this; encoder_sys_t *p_sys; - if( p_enc->fmt_out.i_codec != VLC_FOURCC('f','l','a','c') ) + if( p_enc->fmt_out.i_codec != VLC_FOURCC('f','l','a','c') && + !p_enc->b_force ) { return VLC_EGENERIC; } @@ -1073,13 +1227,20 @@ static int OpenEncoder( vlc_object_t *p_this ) } p_enc->p_sys = p_sys; p_enc->pf_encode_audio = Encode; + p_enc->fmt_out.i_codec = VLC_FOURCC('f','l','a','c'); + p_sys->i_headers = 0; p_sys->p_buffer = 0; p_sys->i_buffer = 0; p_sys->i_samples_delay = 0; /* Create flac encoder */ - p_sys->p_flac = FLAC__stream_encoder_new(); + if( !(p_sys->p_flac = FLAC__stream_encoder_new()) ) + { + msg_Err( p_enc, "FLAC__stream_encoder_new() failed" ); + free( p_sys ); + return VLC_EGENERIC; + } FLAC__stream_encoder_set_streamable_subset( p_sys->p_flac, 1 ); FLAC__stream_encoder_set_channels( p_sys->p_flac, @@ -1089,15 +1250,32 @@ static int OpenEncoder( vlc_object_t *p_this ) FLAC__stream_encoder_set_bits_per_sample( p_sys->p_flac, 16 ); p_enc->fmt_in.i_codec = AOUT_FMT_S16_NE; + /* Get and store the STREAMINFO metadata block as a p_extra */ + p_sys->p_chain = 0; + +#ifdef USE_NEW_FLAC_API + if( FLAC__stream_encoder_init_stream( p_sys->p_flac, + EncoderWriteCallback, + NULL, + NULL, + EncoderMetadataCallback, + p_enc ) + != FLAC__STREAM_ENCODER_INIT_STATUS_OK ) + { + msg_Err( p_enc, "FLAC__stream_encoder_init_stream() failed" ); + FLAC__stream_encoder_delete( p_sys->p_flac ); + free( p_sys ); + return VLC_EGENERIC; + } +#else FLAC__stream_encoder_set_write_callback( p_sys->p_flac, EncoderWriteCallback ); FLAC__stream_encoder_set_metadata_callback( p_sys->p_flac, EncoderMetadataCallback ); FLAC__stream_encoder_set_client_data( p_sys->p_flac, p_enc ); - /* Get and store the STREAMINFO metadata block as a p_extra */ - p_sys->p_chain = 0; FLAC__stream_encoder_init( p_sys->p_flac ); +#endif return VLC_SUCCESS; } @@ -1111,7 +1289,7 @@ static block_t *Encode( encoder_t *p_enc, aout_buffer_t *p_aout_buf ) { encoder_sys_t *p_sys = p_enc->p_sys; block_t *p_chain; - int i; + unsigned int i; p_sys->i_pts = p_aout_buf->start_date - (mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay / @@ -1218,3 +1396,4 @@ EncoderWriteCallback( const FLAC__StreamEncoder *encoder, return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } +#endif