X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Fflac.c;h=8c9a4808acea2a44574fd61f58b3e51b4a4dbd69;hb=f60b4c79acaf0412280672f83677a96e74dacb65;hp=4d8689b2813df07cff4c4f2aabd4ef03b9c79938;hpb=09d997200c05de78bb05ea4e2219fec752aef5a9;p=vlc diff --git a/modules/codec/flac.c b/modules/codec/flac.c index 4d8689b281..8c9a4808ac 100644 --- a/modules/codec/flac.c +++ b/modules/codec/flac.c @@ -1,17 +1,17 @@ /***************************************************************************** * flac.c: flac decoder/packetizer/encoder module making use of libflac ***************************************************************************** - * Copyright (C) 1999-2001 VideoLAN - * $Id: flac.c,v 1.3 2003/11/21 20:49:13 gbazin 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -25,14 +25,18 @@ /***************************************************************************** * Preamble *****************************************************************************/ + #include #include -#include -#include -#include +#ifdef HAVE_FLAC_STREAM_DECODER_H +# include +# include +# define USE_LIBFLAC +#endif #include "vlc_block_helper.h" +#include "vlc_bits.h" #define MAX_FLAC_HEADER_SIZE 16 @@ -41,9 +45,6 @@ *****************************************************************************/ struct decoder_sys_t { - /* Module mode */ - vlc_bool_t b_packetizer; - /* * Input properties */ @@ -60,10 +61,21 @@ struct decoder_sys_t /* * FLAC properties */ +#ifdef USE_LIBFLAC FLAC__StreamDecoder *p_flac; + 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; - FLAC__StreamMetadata_StreamInfo stream_info; /* * Common properties @@ -104,15 +116,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 ); @@ -136,6 +154,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 ); @@ -145,20 +164,26 @@ static uint8_t flac_crc8( const uint8_t *data, unsigned len ); *****************************************************************************/ vlc_module_begin(); + set_category( CAT_INPUT ); + set_subcategory( SUBCAT_INPUT_ACODEC ); + +#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 ); + + add_shortcut( "flac" ); vlc_module_end(); /***************************************************************************** @@ -184,11 +209,12 @@ static int OpenDecoder( vlc_object_t *p_this ) /* Misc init */ aout_DateSet( &p_sys->end_date, 0 ); - p_sys->b_packetizer = VLC_FALSE; p_sys->i_state = STATE_NOSYNC; + p_sys->b_stream_info = VLC_FALSE; p_sys->bytestream = block_BytestreamInit( p_dec ); +#ifdef USE_LIBFLAC /* Take care of flac init */ if( !(p_sys->p_flac = FLAC__stream_decoder_new()) ) { @@ -208,15 +234,65 @@ 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 /* 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 p_dec->pf_packetize = PacketizeBlock; + return VLC_SUCCESS; +} + +static int OpenPacketizer( vlc_object_t *p_this ) +{ + decoder_t *p_dec = (decoder_t*)p_this; + int i_ret; + + /* Hmmm, mem leak ?*/ + es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); + + i_ret = OpenDecoder( p_this ); + + /* Set output properties */ + p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','a','c'); + + if( i_ret != VLC_SUCCESS ) return i_ret; + + 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: processe 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" ); @@ -226,22 +302,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; + + bs_init( &bs, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); + + p_sys->stream_info.min_blocksize = bs_read( &bs, 16 ); + p_sys->stream_info.max_blocksize = bs_read( &bs, 16 ); + + p_sys->stream_info.min_framesize = bs_read( &bs, 24 ); + p_sys->stream_info.max_framesize = bs_read( &bs, 24 ); + + 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 - int i_ret = OpenDecoder( p_this ); + if( !p_sys->b_stream_info ) return; - if( i_ret == VLC_SUCCESS ) + if( p_dec->fmt_out.i_codec == VLC_FOURCC('f','l','a','c') ) { - p_dec->p_sys->b_packetizer = VLC_TRUE; - es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); + 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 ); } - - return i_ret; } /**************************************************************************** @@ -257,12 +345,24 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) if( !pp_block || !*pp_block ) return NULL; -#if 0 - if( (*pp_block)->b_discontinuity ) + if( !p_sys->b_stream_info ) ProcessHeader( p_dec ); + + 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; + } + else if( !aout_DateGet( &p_sys->end_date ) ) + { + /* The first PTS is as good as anything else. */ + aout_DateSet( &p_sys->end_date, (*pp_block)->i_pts ); + } + + if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { p_sys->i_state = STATE_NOSYNC; } -#endif block_BytestreamPush( &p_sys->bytestream, *pp_block ); @@ -321,6 +421,11 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) p_sys->i_state = STATE_NOSYNC; break; } + if( p_sys->i_rate != p_dec->fmt_out.audio.i_rate ) + { + p_dec->fmt_out.audio.i_rate = p_sys->i_rate; + aout_DateInit( &p_sys->end_date, p_sys->i_rate ); + } p_sys->i_state = STATE_NEXT_SYNC; p_sys->i_frame_size = 1; @@ -337,14 +442,14 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) if( p_header[0] == 0xFF && p_header[1] == 0xF8 ) { /* Check if frame is valid and get frame info */ - p_sys->i_frame_length = + int i_frame_length = SyncInfo( p_dec, p_header, &p_sys->i_channels, &p_sys->i_channels_conf, &p_sys->i_rate, &p_sys->i_bits_per_sample ); - if( p_sys->i_frame_length ) + if( i_frame_length ) { p_sys->i_state = STATE_SEND_DATA; break; @@ -358,7 +463,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 ); @@ -378,9 +482,11 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) p_sys->i_state = STATE_NOSYNC; /* Date management */ - p_sout_block->i_pts = aout_DateGet( &p_sys->end_date ); + p_sout_block->i_pts = + p_sout_block->i_dts = aout_DateGet( &p_sys->end_date ); + aout_DateIncrement( &p_sys->end_date, p_sys->i_frame_length ); p_sout_block->i_length = - aout_DateIncrement( &p_sys->end_date, p_sys->i_frame_length ); + aout_DateGet( &p_sys->end_date ) - p_sout_block->i_pts; return p_sout_block; } @@ -389,6 +495,7 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) return NULL; } +#ifdef USE_LIBFLAC /**************************************************************************** * DecodeBlock: the whole thing ****************************************************************************/ @@ -398,13 +505,6 @@ static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) if( !pp_block || !*pp_block ) 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; - } - p_sys->p_aout_buffer = 0; if( ( p_sys->p_block = PacketizeBlock( p_dec, pp_block ) ) ) { @@ -424,24 +524,12 @@ static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) } block_Release( p_sys->p_block ); + p_sys->p_block = NULL; } 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 ); - free( p_sys ); -} - /***************************************************************************** * DecoderReadCallback: called by libflac when it needs more data *****************************************************************************/ @@ -479,18 +567,6 @@ DecoderWriteCallback( const FLAC__StreamDecoder *decoder, decoder_t *p_dec = (decoder_t *)client_data; decoder_sys_t *p_sys = p_dec->p_sys; - if( p_sys->p_block && p_sys->p_block->i_pts != 0 && - p_sys->p_block->i_pts != aout_DateGet( &p_sys->end_date ) ) - { - aout_DateSet( &p_sys->end_date, p_sys->p_block->i_pts ); - } - else if( !aout_DateGet( &p_sys->end_date ) ) - { - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; - } - - if( p_sys->p_block ) p_sys->p_block->i_pts = 0; - p_sys->p_aout_buffer = p_dec->pf_aout_buffer_new( p_dec, frame->header.blocksize ); @@ -508,10 +584,10 @@ DecoderWriteCallback( const FLAC__StreamDecoder *decoder, frame->header.channels, frame->header.blocksize ); } - /* Date management */ - p_sys->p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date ); + /* Date management (already done by packetizer) */ + p_sys->p_aout_buffer->start_date = p_sys->p_block->i_pts; p_sys->p_aout_buffer->end_date = - aout_DateIncrement( &p_sys->end_date, frame->header.blocksize ); + p_sys->p_block->i_pts + p_sys->p_block->i_length; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } @@ -535,7 +611,7 @@ static void DecoderMetadataCallback( const FLAC__StreamDecoder *decoder, p_dec->fmt_out.i_codec = AOUT_FMT_S16_NE; break; default: - msg_Dbg( p_dec, "strange bps %d", + 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; @@ -574,14 +650,14 @@ 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 " - "loose synchronization." ); + msg_Err( p_dec, "an error in the stream caused the decoder to " + "lose synchronization." ); break; case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER: - msg_Err( p_dec, "The decoder encountered a corrupted frame header." ); + msg_Err( p_dec, "the decoder encountered a corrupted frame header." ); break; case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH: - msg_Err( p_dec, "The frame's data did not match the CRC in the " + msg_Err( p_dec, "frame's data did not match the CRC in the " "footer." ); break; default: @@ -629,32 +705,32 @@ 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_Err( 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_Err( 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_Err( 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_Err( 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_Err( p_dec, "the decoder has reached the end of the stream." ); break; case FLAC__STREAM_DECODER_ABORTED: - msg_Err( p_dec, "The decoder was aborted by the read callback." ); + msg_Err( p_dec, "the decoder was aborted by the read callback." ); break; case FLAC__STREAM_DECODER_UNPARSEABLE_STREAM: - msg_Err( p_dec, "The decoder encountered reserved fields in use " + msg_Err( p_dec, "the decoder encountered reserved fields in use " "in the stream." ); break; case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR: - msg_Err( p_dec, "An error occurred allocating memory." ); + msg_Err( p_dec, "error when allocating memory." ); break; case FLAC__STREAM_DECODER_ALREADY_INITIALIZED: msg_Err( p_dec, "FLAC__stream_decoder_init() was called when the " @@ -666,19 +742,22 @@ static void decoder_state_error( decoder_t *p_dec, "all callbacks being set." ); break; case FLAC__STREAM_DECODER_UNINITIALIZED: - msg_Err( p_dec, "The decoder is in the uninitialized state." ); + msg_Err( p_dec, "decoder in uninitialized state." ); break; default: msg_Err(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; @@ -794,9 +873,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: @@ -812,6 +891,9 @@ static int SyncInfo( decoder_t *p_dec, uint8_t *p_buf, return 0; break; } +#endif + + *pi_channels = 2; } else { @@ -1018,6 +1100,7 @@ static uint8_t flac_crc8( const uint8_t *data, unsigned len ) return crc; } +#ifdef USE_LIBFLAC /***************************************************************************** * encoder_sys_t : flac encoder descriptor *****************************************************************************/ @@ -1070,7 +1153,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; } @@ -1083,9 +1167,12 @@ 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(); @@ -1190,18 +1277,18 @@ EncoderWriteCallback( const FLAC__StreamEncoder *encoder, encoder_sys_t *p_sys = p_enc->p_sys; block_t *p_block; - if( samples == 0 && p_sys->i_headers <= 1 ) + if( samples == 0 ) { if( p_sys->i_headers == 1 ) { - msg_Err( p_enc, "Writing STREAMINFO: %i", bytes ); + msg_Dbg( p_enc, "Writing STREAMINFO: %i", bytes ); /* Backup the STREAMINFO metadata block */ p_enc->fmt_out.i_extra = STREAMINFO_SIZE + 4; p_enc->fmt_out.p_extra = malloc( STREAMINFO_SIZE + 4 ); memcpy( p_enc->fmt_out.p_extra, "fLaC", 4 ); memcpy( ((uint8_t *)p_enc->fmt_out.p_extra) + 4, buffer, - STREAMINFO_SIZE + 4 ); + STREAMINFO_SIZE ); /* Fake this as the last metadata block */ ((uint8_t*)p_enc->fmt_out.p_extra)[4] |= 0x80; @@ -1213,9 +1300,18 @@ EncoderWriteCallback( const FLAC__StreamEncoder *encoder, p_block = block_New( p_enc, bytes ); memcpy( p_block->p_buffer, buffer, bytes ); - p_block->i_dts = p_block->i_pts = p_block->i_length = 0; + p_block->i_dts = p_block->i_pts = p_sys->i_pts; + + p_sys->i_samples_delay -= samples; + + p_block->i_length = (mtime_t)1000000 * + (mtime_t)samples / (mtime_t)p_enc->fmt_in.audio.i_rate; + + /* Update pts */ + p_sys->i_pts += p_block->i_length; block_ChainAppend( &p_sys->p_chain, p_block ); return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } +#endif