From 447327c6053e496b70a46e9075e10fa3454211ae Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Sat, 13 Feb 2010 13:26:03 +0100 Subject: [PATCH] Moved out the flac packetizer from the flac decoder. It simplify the flac decoder code. It fixes the build of the packetizer when flac is disabled. It makes the flac packetizer behaviour independant of the flac decoder presence. --- modules/codec/flac.c | 727 ++-------------------------------- modules/packetizer/Modules.am | 2 + modules/packetizer/flac.c | 701 ++++++++++++++++++++++++++++++++ 3 files changed, 735 insertions(+), 695 deletions(-) create mode 100644 modules/packetizer/flac.c diff --git a/modules/codec/flac.c b/modules/codec/flac.c index cc869da0bd..f35a1dbed0 100644 --- a/modules/codec/flac.c +++ b/modules/codec/flac.c @@ -1,5 +1,5 @@ /***************************************************************************** - * flac.c: flac decoder/packetizer/encoder module making use of libflac + * flac.c: flac decoder/encoder module making use of libflac ***************************************************************************** * Copyright (C) 1999-2001 the VideoLAN team * $Id$ @@ -35,17 +35,12 @@ #include #include -#ifdef HAVE_FLAC_STREAM_DECODER_H -# include -# include -# define USE_LIBFLAC -#endif +#include +#include #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 @@ -55,13 +50,6 @@ *****************************************************************************/ struct decoder_sys_t { - /* - * Input properties - */ - int i_state; - - block_bytestream_t bytestream; - /* * Input/Output properties */ @@ -71,40 +59,9 @@ 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 bool b_stream_info; - - /* - * Common properties - */ - date_t end_date; - mtime_t i_pts; - - int i_frame_size, i_frame_length, i_bits_per_sample; - unsigned int i_rate, i_channels, i_channels_conf; -}; - -enum { - - STATE_NOSYNC, - STATE_SYNC, - STATE_HEADER, - STATE_NEXT_SYNC, - STATE_GET_DATA, - STATE_SEND_DATA }; static const int pi_channels_maps[7] = @@ -125,24 +82,13 @@ static const int pi_channels_maps[7] = * Local prototypes *****************************************************************************/ 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 *, 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 ); @@ -168,10 +114,6 @@ 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 ); /***************************************************************************** * Module descriptor @@ -182,7 +124,6 @@ vlc_module_begin () set_subcategory( SUBCAT_INPUT_ACODEC ) add_shortcut( "flac" ) -#ifdef USE_LIBFLAC set_description( N_("Flac audio decoder") ) set_capability( "decoder", 100 ) set_callbacks( OpenDecoder, CloseDecoder ) @@ -193,13 +134,6 @@ vlc_module_begin () set_capability( "encoder", 100 ) set_callbacks( OpenEncoder, CloseEncoder ) - add_submodule () - add_shortcut( "flac" ) -#endif - set_description( N_("Flac audio packetizer") ) - set_capability( "packetizer", 100 ) - set_callbacks( OpenPacketizer, CloseDecoder ) - vlc_module_end () /***************************************************************************** @@ -220,14 +154,9 @@ static int OpenDecoder( vlc_object_t *p_this ) return VLC_ENOMEM; /* Misc init */ - date_Set( &p_sys->end_date, 0 ); - p_sys->i_state = STATE_NOSYNC; p_sys->b_stream_info = false; - p_sys->p_block=NULL; - p_sys->i_pts = VLC_TS_INVALID; - p_sys->bytestream = block_BytestreamInit(); + p_sys->p_block = NULL; -#ifdef USE_LIBFLAC /* Take care of flac init */ if( !(p_sys->p_flac = FLAC__stream_decoder_new()) ) { @@ -266,7 +195,6 @@ 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 */ @@ -274,35 +202,12 @@ static int OpenDecoder( vlc_object_t *p_this ) p_dec->fmt_out.i_codec = VLC_CODEC_FL32; /* 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; + p_dec->b_need_packetized = true; - /* Set output properties */ - p_dec->fmt_out.i_codec = VLC_CODEC_FLAC; - - if( i_ret != VLC_SUCCESS ) - { - es_format_Clean( &p_dec->fmt_out ); - p_dec->fmt_out = es_save; - } - return i_ret; + return VLC_SUCCESS; } /***************************************************************************** @@ -313,12 +218,11 @@ 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 - free( p_sys->p_block ); + if( p_sys->p_block ) + block_Release( p_sys->p_block ); free( p_sys ); } @@ -329,8 +233,8 @@ 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; + if( !p_dec->fmt_in.i_extra ) + return; /* Decode STREAMINFO */ msg_Dbg( p_dec, "decode STREAMINFO" ); @@ -339,248 +243,49 @@ static void ProcessHeader( decoder_t *p_dec ) p_dec->fmt_in.i_extra ); FLAC__stream_decoder_process_until_end_of_metadata( p_sys->p_flac ); msg_Dbg( p_dec, "STREAMINFO decoded" ); - -#else - bs_t bs; - - 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 - - if( !p_sys->b_stream_info ) return; - - if( p_dec->fmt_out.i_codec == VLC_CODEC_FLAC ) - { - p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; - p_dec->fmt_out.p_extra = xrealloc( 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 ); - } } /**************************************************************************** - * PacketizeBlock: the whole thing - **************************************************************************** - * This function is called just after the thread is launched. + * DecodeBlock: the whole thing ****************************************************************************/ -static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block ) +static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; - uint8_t p_header[MAX_FLAC_HEADER_SIZE]; - block_t *p_sout_block; - - if( !pp_block || !*pp_block ) return NULL; + 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_BytestreamEmpty( &p_sys->bytestream ); - } - date_Set( &p_sys->end_date, 0 ); block_Release( *pp_block ); return NULL; } - if( !p_sys->b_stream_info ) ProcessHeader( p_dec ); + 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; - } + p_sys->p_block = *pp_block; + *pp_block = NULL; - 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. */ - block_Release( *pp_block ); - return NULL; - } - else if( !date_Get( &p_sys->end_date ) ) - { - /* The first PTS is as good as anything else. */ - p_sys->i_rate = p_dec->fmt_out.audio.i_rate; - date_Init( &p_sys->end_date, p_sys->i_rate, 1 ); - date_Set( &p_sys->end_date, (*pp_block)->i_pts ); - } - - block_BytestreamPush( &p_sys->bytestream, *pp_block ); + p_sys->p_aout_buffer = 0; - while( 1 ) + if( !FLAC__stream_decoder_process_single( p_sys->p_flac ) ) { - switch( p_sys->i_state ) - { - case STATE_NOSYNC: - while( block_PeekBytes( &p_sys->bytestream, p_header, 2 ) - == VLC_SUCCESS ) - { - if( p_header[0] == 0xFF && p_header[1] == 0xF8 ) - { - p_sys->i_state = STATE_SYNC; - break; - } - block_SkipByte( &p_sys->bytestream ); - } - if( p_sys->i_state != STATE_SYNC ) - { - block_BytestreamFlush( &p_sys->bytestream ); - - /* Need more data */ - return NULL; - } - - 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 ) ) - { - date_Set( &p_sys->end_date, p_sys->i_pts ); - } - p_sys->i_state = STATE_HEADER; - - case STATE_HEADER: - /* Get FLAC frame header (MAX_FLAC_HEADER_SIZE bytes) */ - if( block_PeekBytes( &p_sys->bytestream, p_header, - MAX_FLAC_HEADER_SIZE ) != VLC_SUCCESS ) - { - /* Need more data */ - return NULL; - } - - /* Check if frame is valid and get frame info */ - p_sys->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 ) - { - msg_Dbg( p_dec, "emulated sync word" ); - block_SkipByte( &p_sys->bytestream ); - 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; - date_Init( &p_sys->end_date, p_sys->i_rate, 1 ); - date_Set( &p_sys->end_date, p_sys->i_pts ); - } - p_sys->i_state = STATE_NEXT_SYNC; - p_sys->i_frame_size = 1; - - case STATE_NEXT_SYNC: - /* TODO: If pp_block == NULL, flush the buffer without checking the - * next sync word */ - - /* Check if next expected frame contains the sync word */ - while( block_PeekOffsetBytes( &p_sys->bytestream, - p_sys->i_frame_size, p_header, - MAX_FLAC_HEADER_SIZE ) - == VLC_SUCCESS ) - { - if( p_header[0] == 0xFF && p_header[1] == 0xF8 ) - { - /* Check if frame is valid and get frame info */ - 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( i_frame_length ) - { - p_sys->i_state = STATE_SEND_DATA; - break; - } - } - p_sys->i_frame_size++; - } - - if( p_sys->i_state != STATE_SEND_DATA ) - { - /* Need more data */ - return NULL; - } - - case STATE_SEND_DATA: - p_sout_block = block_New( p_dec, 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_sout_block->p_buffer, - p_sys->i_frame_size ); - - /* 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 ); - - p_sys->i_state = STATE_NOSYNC; - - /* Date management */ - p_sout_block->i_pts = - p_sout_block->i_dts = date_Get( &p_sys->end_date ); - date_Increment( &p_sys->end_date, p_sys->i_frame_length ); - p_sout_block->i_length = - date_Get( &p_sys->end_date ) - p_sout_block->i_pts; - - return p_sout_block; - } + decoder_state_error( p_dec, + FLAC__stream_decoder_get_state( p_sys->p_flac ) ); + FLAC__stream_decoder_flush( p_dec->p_sys->p_flac ); } - return NULL; -} - -#ifdef USE_LIBFLAC -/**************************************************************************** - * DecodeBlock: the whole thing - ****************************************************************************/ -static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) -{ - decoder_sys_t *p_sys = p_dec->p_sys; - - if( !pp_block || !*pp_block ) return NULL; - - p_sys->p_aout_buffer = 0; - if( ( p_sys->p_block = PacketizeBlock( p_dec, pp_block ) ) ) + /* If the decoder is in the "aborted" state, + * FLAC__stream_decoder_process_single() won't return an error. */ + if( FLAC__stream_decoder_get_state(p_dec->p_sys->p_flac) + == FLAC__STREAM_DECODER_ABORTED ) { - if( !FLAC__stream_decoder_process_single( p_sys->p_flac ) ) - { - decoder_state_error( p_dec, - FLAC__stream_decoder_get_state( p_sys->p_flac ) ); - FLAC__stream_decoder_flush( p_dec->p_sys->p_flac ); - } - - /* If the decoder is in the "aborted" state, - * FLAC__stream_decoder_process_single() won't return an error. */ - if( FLAC__stream_decoder_get_state(p_dec->p_sys->p_flac) - == FLAC__STREAM_DECODER_ABORTED ) - { - FLAC__stream_decoder_flush( p_dec->p_sys->p_flac ); - } - - block_Release( p_sys->p_block ); - p_sys->p_block = NULL; + FLAC__stream_decoder_flush( p_dec->p_sys->p_flac ); } + block_Release( p_sys->p_block ); + p_sys->p_block = NULL; + return p_sys->p_aout_buffer; } @@ -711,8 +416,6 @@ static void DecoderMetadataCallback( const FLAC__StreamDecoder *decoder, p_dec->fmt_out.audio.i_bitspersample = metadata->data.stream_info.bits_per_sample; - date_Init( &p_sys->end_date, p_dec->fmt_out.audio.i_rate, 1 ); - msg_Dbg( p_dec, "channels:%d samplerate:%d bitspersamples:%d", p_dec->fmt_out.audio.i_channels, p_dec->fmt_out.audio.i_rate, p_dec->fmt_out.audio.i_bitspersample ); @@ -872,373 +575,7 @@ static void decoder_state_error( decoder_t *p_dec, msg_Warn(p_dec, "unknown error" ); } } -#endif -/***************************************************************************** - * SyncInfo: parse FLAC sync info - *****************************************************************************/ -static int SyncInfo( decoder_t *p_dec, uint8_t *p_buf, - 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; - unsigned i_blocksize = 0; - int i_blocksize_hint = 0, i_sample_rate_hint = 0; - uint64_t i_sample_number = 0; - - bool b_variable_blocksize = ( p_sys->b_stream_info && - p_sys->stream_info.min_blocksize != p_sys->stream_info.max_blocksize ); - bool b_fixed_blocksize = ( p_sys->b_stream_info && - p_sys->stream_info.min_blocksize == p_sys->stream_info.max_blocksize ); - - /* Check syncword */ - if( p_buf[0] != 0xFF || p_buf[1] != 0xF8 ) return 0; - - /* Check there is no emulated sync code in the rest of the header */ - if( p_buf[2] == 0xff || p_buf[3] == 0xFF ) return 0; - - /* Find blocksize (framelength) */ - switch( i_temp = p_buf[2] >> 4 ) - { - case 0: - if( b_fixed_blocksize ) - i_blocksize = p_sys->stream_info.min_blocksize; - else return 0; /* We can't do anything with this */ - break; - - case 1: - i_blocksize = 192; - break; - - case 2: - case 3: - case 4: - case 5: - i_blocksize = 576 << (i_temp - 2); - break; - - case 6: - case 7: - i_blocksize_hint = i_temp; - break; - - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - i_blocksize = 256 << (i_temp - 8); - break; - } - - /* Find samplerate */ - switch( i_temp = p_buf[2] & 0x0f ) - { - case 0: - if( p_sys->b_stream_info ) - *pi_sample_rate = p_sys->stream_info.sample_rate; - else return 0; /* We can't do anything with this */ - break; - - case 1: - *pi_sample_rate = 88200; - break; - - case 2: - *pi_sample_rate = 176400; - break; - - case 3: - *pi_sample_rate = 192000; - break; - - case 4: - *pi_sample_rate = 8000; - break; - - case 5: - *pi_sample_rate = 16000; - break; - - case 6: - *pi_sample_rate = 22050; - break; - - case 7: - *pi_sample_rate = 24000; - break; - - case 8: - *pi_sample_rate = 32000; - break; - - case 9: - *pi_sample_rate = 44100; - break; - - case 10: - *pi_sample_rate = 48000; - break; - - case 11: - *pi_sample_rate = 96000; - break; - - case 12: - case 13: - case 14: - i_sample_rate_hint = i_temp; - break; - - case 15: - return 0; - } - - /* Find channels */ - i_temp = (unsigned)(p_buf[3] >> 4); - if( i_temp & 8 ) - { -#ifdef USE_LIBFLAC - int i_channel_assignment; /* ??? */ - - switch( i_temp & 7 ) - { - case 0: - i_channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE; - break; - case 1: - i_channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE; - break; - case 2: - i_channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE; - break; - default: - return 0; - break; - } -#endif - - *pi_channels = 2; - } - else - { - *pi_channels = i_temp + 1; - *pi_channels_conf = pi_channels_maps[ *pi_channels ]; - } - - /* Find bits per sample */ - switch( i_temp = (unsigned)(p_buf[3] & 0x0e) >> 1 ) - { - case 0: - if( p_sys->b_stream_info ) - *pi_bits_per_sample = p_sys->stream_info.bits_per_sample; - else - return 0; - break; - - case 1: - *pi_bits_per_sample = 8; - break; - - case 2: - *pi_bits_per_sample = 12; - break; - - case 4: - *pi_bits_per_sample = 16; - break; - - case 5: - *pi_bits_per_sample = 20; - break; - - case 6: - *pi_bits_per_sample = 24; - break; - - case 3: - case 7: - return 0; - break; - } - - /* Zero padding bit */ - if( p_buf[3] & 0x01 ) return 0; - - /* End of fixed size header */ - i_header = 4; - - /* Find Sample/Frame number */ - if( i_blocksize_hint && b_variable_blocksize ) - { - i_sample_number = read_utf8( &p_buf[i_header++], &i_read ); - if( i_sample_number == INT64_C(0xffffffffffffffff) ) return 0; - } - else - { - i_sample_number = read_utf8( &p_buf[i_header++], &i_read ); - if( i_sample_number == INT64_C(0xffffffffffffffff) ) return 0; - - if( p_sys->b_stream_info ) - i_sample_number *= p_sys->stream_info.min_blocksize; - } - - i_header += i_read; - - /* Read blocksize */ - if( i_blocksize_hint ) - { - int i_val1 = p_buf[i_header++]; - if( i_blocksize_hint == 7 ) - { - int i_val2 = p_buf[i_header++]; - i_val1 = (i_val1 << 8) | i_val2; - } - i_blocksize = i_val1 + 1; - } - - /* Read sample rate */ - if( i_sample_rate_hint ) - { - int i_val1 = p_buf[i_header++]; - if( i_sample_rate_hint != 12 ) - { - int i_val2 = p_buf[i_header++]; - i_val1 = (i_val1 << 8) | i_val2; - } - if( i_sample_rate_hint == 12 ) *pi_sample_rate = i_val1 * 1000; - else if( i_sample_rate_hint == 13 ) *pi_sample_rate = i_val1; - else *pi_sample_rate = i_val1 * 10; - } - - /* Check the CRC-8 byte */ - if( flac_crc8( p_buf, i_header ) != p_buf[i_header] ) - { - return 0; - } - - /* Sanity check using stream info header when possible */ - if( p_sys->b_stream_info ) - { - if( i_blocksize < p_sys->stream_info.min_blocksize || - i_blocksize > p_sys->stream_info.max_blocksize ) - return 0; - } - return i_blocksize; -} - -/* Will return 0xffffffffffffffff for an invalid utf-8 sequence */ -static uint64_t read_utf8( const uint8_t *p_buf, int *pi_read ) -{ - uint64_t i_result = 0; - unsigned i, j; - - if( !(p_buf[0] & 0x80) ) /* 0xxxxxxx */ - { - i_result = p_buf[0]; - i = 0; - } - else if( p_buf[0] & 0xC0 && !(p_buf[0] & 0x20) ) /* 110xxxxx */ - { - i_result = p_buf[0] & 0x1F; - i = 1; - } - else if( p_buf[0] & 0xE0 && !(p_buf[0] & 0x10) ) /* 1110xxxx */ - { - i_result = p_buf[0] & 0x0F; - i = 2; - } - else if( p_buf[0] & 0xF0 && !(p_buf[0] & 0x08) ) /* 11110xxx */ - { - i_result = p_buf[0] & 0x07; - i = 3; - } - else if( p_buf[0] & 0xF8 && !(p_buf[0] & 0x04) ) /* 111110xx */ - { - i_result = p_buf[0] & 0x03; - i = 4; - } - else if( p_buf[0] & 0xFC && !(p_buf[0] & 0x02) ) /* 1111110x */ - { - i_result = p_buf[0] & 0x01; - i = 5; - } - else if( p_buf[0] & 0xFE && !(p_buf[0] & 0x01) ) /* 11111110 */ - { - i_result = 0; - i = 6; - } - else { - return INT64_C(0xffffffffffffffff); - } - - for( j = 1; j <= i; j++ ) - { - if( !(p_buf[j] & 0x80) || (p_buf[j] & 0x40) ) /* 10xxxxxx */ - { - return INT64_C(0xffffffffffffffff); - } - i_result <<= 6; - i_result |= (p_buf[j] & 0x3F); - } - - *pi_read = i; - return i_result; -} - -/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */ -static const uint8_t flac_crc8_table[256] = { - 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, - 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, - 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, - 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, - 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, - 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, - 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, - 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, - 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, - 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, - 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, - 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, - 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, - 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, - 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, - 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, - 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, - 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, - 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, - 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, - 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, - 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, - 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, - 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, - 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, - 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, - 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, - 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, - 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, - 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, - 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, - 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 -}; - -static uint8_t flac_crc8( const uint8_t *data, unsigned len ) -{ - uint8_t crc = 0; - - while(len--) - crc = flac_crc8_table[crc ^ *data++]; - - return crc; -} - -#ifdef USE_LIBFLAC /***************************************************************************** * encoder_sys_t : flac encoder descriptor *****************************************************************************/ @@ -1473,4 +810,4 @@ EncoderWriteCallback( const FLAC__StreamEncoder *encoder, return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } -#endif + diff --git a/modules/packetizer/Modules.am b/modules/packetizer/Modules.am index 26063f7549..dba35c6278 100644 --- a/modules/packetizer/Modules.am +++ b/modules/packetizer/Modules.am @@ -6,6 +6,7 @@ SOURCES_packetizer_h264 = h264.c SOURCES_packetizer_vc1 = vc1.c SOURCES_packetizer_mlp = mlp.c SOURCES_packetizer_dirac = dirac.c +SOURCES_packetizer_flac = flac.c noinst_HEADERS = packetizer_helper.h @@ -17,6 +18,7 @@ libvlc_LTLIBRARIES += \ libpacketizer_vc1_plugin.la \ libpacketizer_mlp_plugin.la \ libpacketizer_dirac_plugin.la \ + libpacketizer_flac_plugin.la \ $(NULL) if ENABLE_SOUT libvlc_LTLIBRARIES += libpacketizer_copy_plugin.la diff --git a/modules/packetizer/flac.c b/modules/packetizer/flac.c new file mode 100644 index 0000000000..053dbef298 --- /dev/null +++ b/modules/packetizer/flac.c @@ -0,0 +1,701 @@ +/***************************************************************************** + * flac.c: flac packetizer module. + ***************************************************************************** + * Copyright (C) 1999-2001 the VideoLAN team + * $Id$ + * + * 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 + * GNU General Public License for more details. + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include +#include + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); + +vlc_module_begin() + set_category( CAT_SOUT ) + set_subcategory( SUBCAT_SOUT_PACKETIZER ) + set_description( N_("Flac audio packetizer") ) + set_capability( "packetizer", 50 ) + set_callbacks( Open, Close ) +vlc_module_end() + +/***************************************************************************** + * decoder_sys_t : FLAC decoder descriptor + *****************************************************************************/ +#define MAX_FLAC_HEADER_SIZE 16 +struct decoder_sys_t +{ + /* + * Input properties + */ + int i_state; + + block_bytestream_t bytestream; + + /* + * FLAC properties + */ + struct + { + unsigned min_blocksize, max_blocksize; + unsigned min_framesize, max_framesize; + unsigned sample_rate; + unsigned channels; + unsigned bits_per_sample; + + } stream_info; + bool b_stream_info; + + /* + * Common properties + */ + date_t end_date; + mtime_t i_pts; + + int i_frame_size, i_frame_length, i_bits_per_sample; + unsigned int i_rate, i_channels; +}; + +enum +{ + STATE_NOSYNC, + STATE_SYNC, + STATE_HEADER, + STATE_NEXT_SYNC, + STATE_GET_DATA, + STATE_SEND_DATA +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static block_t *Packetize( decoder_t *, block_t ** ); + +static int SyncInfo( decoder_t *, uint8_t *, unsigned int *, + unsigned int *,int * ); + +static uint64_t read_utf8( const uint8_t *p_buf, int *pi_read ); +static uint8_t flac_crc8( const uint8_t *data, unsigned len ); + +static int Open( vlc_object_t *p_this ) +{ + decoder_t *p_dec = (decoder_t*)p_this; + decoder_sys_t *p_sys; + + if( p_dec->fmt_in.i_codec != VLC_CODEC_FLAC ) + return VLC_EGENERIC; + + /* */ + p_dec->p_sys = p_sys = malloc(sizeof(*p_sys)); + if( !p_sys ) + return VLC_ENOMEM; + + date_Set( &p_sys->end_date, 0 ); + p_sys->i_state = STATE_NOSYNC; + p_sys->b_stream_info = false; + p_sys->i_pts = VLC_TS_INVALID; + p_sys->bytestream = block_BytestreamInit(); + + /* */ + es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); + p_dec->fmt_out.i_cat = AUDIO_ES; + p_dec->fmt_out.i_codec = VLC_CODEC_FLAC; + + /* */ + p_dec->pf_decode_audio = NULL; + p_dec->pf_packetize = Packetize; + + return VLC_SUCCESS; +} + +static void Close( vlc_object_t *p_this ) +{ + decoder_t *p_dec = (decoder_t *)p_this; + decoder_sys_t *p_sys = p_dec->p_sys; + + free( p_sys ); +} + +/***************************************************************************** + * ProcessHeader: process Flac header. + *****************************************************************************/ +static void ProcessHeader( decoder_t *p_dec ) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + + bs_t bs; + + 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; + + p_sys->b_stream_info = true; + + p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; + p_dec->fmt_out.p_extra = xrealloc( 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 ); +} + +/* */ +static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + uint8_t p_header[MAX_FLAC_HEADER_SIZE]; + block_t *p_sout_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_BytestreamEmpty( &p_sys->bytestream ); + } + date_Set( &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( !date_Get( &p_sys->end_date ) && (*pp_block)->i_pts <= VLC_TS_INVALID ) + { + /* We've just started the stream, wait for the first PTS. */ + block_Release( *pp_block ); + return NULL; + } + else if( !date_Get( &p_sys->end_date ) ) + { + /* The first PTS is as good as anything else. */ + p_sys->i_rate = p_dec->fmt_out.audio.i_rate; + date_Init( &p_sys->end_date, p_sys->i_rate, 1 ); + date_Set( &p_sys->end_date, (*pp_block)->i_pts ); + } + + block_BytestreamPush( &p_sys->bytestream, *pp_block ); + + while( 1 ) + { + switch( p_sys->i_state ) + { + case STATE_NOSYNC: + while( block_PeekBytes( &p_sys->bytestream, p_header, 2 ) + == VLC_SUCCESS ) + { + if( p_header[0] == 0xFF && p_header[1] == 0xF8 ) + { + p_sys->i_state = STATE_SYNC; + break; + } + block_SkipByte( &p_sys->bytestream ); + } + if( p_sys->i_state != STATE_SYNC ) + { + block_BytestreamFlush( &p_sys->bytestream ); + + /* Need more data */ + return NULL; + } + + 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 ) ) + { + date_Set( &p_sys->end_date, p_sys->i_pts ); + } + p_sys->i_state = STATE_HEADER; + + case STATE_HEADER: + /* Get FLAC frame header (MAX_FLAC_HEADER_SIZE bytes) */ + if( block_PeekBytes( &p_sys->bytestream, p_header, + MAX_FLAC_HEADER_SIZE ) != VLC_SUCCESS ) + { + /* Need more data */ + return NULL; + } + + /* Check if frame is valid and get frame info */ + p_sys->i_frame_length = SyncInfo( p_dec, p_header, + &p_sys->i_channels, + &p_sys->i_rate, + &p_sys->i_bits_per_sample ); + if( !p_sys->i_frame_length ) + { + msg_Dbg( p_dec, "emulated sync word" ); + block_SkipByte( &p_sys->bytestream ); + 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; + date_Init( &p_sys->end_date, p_sys->i_rate, 1 ); + date_Set( &p_sys->end_date, p_sys->i_pts ); + } + p_sys->i_state = STATE_NEXT_SYNC; + p_sys->i_frame_size = 1; + + case STATE_NEXT_SYNC: + /* TODO: If pp_block == NULL, flush the buffer without checking the + * next sync word */ + + /* Check if next expected frame contains the sync word */ + while( block_PeekOffsetBytes( &p_sys->bytestream, + p_sys->i_frame_size, p_header, + MAX_FLAC_HEADER_SIZE ) + == VLC_SUCCESS ) + { + if( p_header[0] == 0xFF && p_header[1] == 0xF8 ) + { + /* Check if frame is valid and get frame info */ + int i_frame_length = + SyncInfo( p_dec, p_header, + &p_sys->i_channels, + &p_sys->i_rate, + &p_sys->i_bits_per_sample ); + + if( i_frame_length ) + { + p_sys->i_state = STATE_SEND_DATA; + break; + } + } + p_sys->i_frame_size++; + } + + if( p_sys->i_state != STATE_SEND_DATA ) + { + /* Need more data */ + return NULL; + } + + case STATE_SEND_DATA: + p_sout_block = block_New( p_dec, 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_sout_block->p_buffer, + p_sys->i_frame_size ); + + /* 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 ); + + p_sys->i_state = STATE_NOSYNC; + + /* Date management */ + p_sout_block->i_pts = + p_sout_block->i_dts = date_Get( &p_sys->end_date ); + date_Increment( &p_sys->end_date, p_sys->i_frame_length ); + p_sout_block->i_length = + date_Get( &p_sys->end_date ) - p_sout_block->i_pts; + + return p_sout_block; + } + } + + return NULL; +} + +/***************************************************************************** + * SyncInfo: parse FLAC sync info + *****************************************************************************/ +static int SyncInfo( decoder_t *p_dec, uint8_t *p_buf, + unsigned int * pi_channels, + 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; + unsigned i_blocksize = 0; + int i_blocksize_hint = 0, i_sample_rate_hint = 0; + uint64_t i_sample_number = 0; + + bool b_variable_blocksize = ( p_sys->b_stream_info && + p_sys->stream_info.min_blocksize != p_sys->stream_info.max_blocksize ); + bool b_fixed_blocksize = ( p_sys->b_stream_info && + p_sys->stream_info.min_blocksize == p_sys->stream_info.max_blocksize ); + + /* Check syncword */ + if( p_buf[0] != 0xFF || p_buf[1] != 0xF8 ) return 0; + + /* Check there is no emulated sync code in the rest of the header */ + if( p_buf[2] == 0xff || p_buf[3] == 0xFF ) return 0; + + /* Find blocksize (framelength) */ + switch( i_temp = p_buf[2] >> 4 ) + { + case 0: + if( b_fixed_blocksize ) + i_blocksize = p_sys->stream_info.min_blocksize; + else return 0; /* We can't do anything with this */ + break; + + case 1: + i_blocksize = 192; + break; + + case 2: + case 3: + case 4: + case 5: + i_blocksize = 576 << (i_temp - 2); + break; + + case 6: + case 7: + i_blocksize_hint = i_temp; + break; + + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + i_blocksize = 256 << (i_temp - 8); + break; + } + + /* Find samplerate */ + switch( i_temp = p_buf[2] & 0x0f ) + { + case 0: + if( p_sys->b_stream_info ) + *pi_sample_rate = p_sys->stream_info.sample_rate; + else return 0; /* We can't do anything with this */ + break; + + case 1: + *pi_sample_rate = 88200; + break; + + case 2: + *pi_sample_rate = 176400; + break; + + case 3: + *pi_sample_rate = 192000; + break; + + case 4: + *pi_sample_rate = 8000; + break; + + case 5: + *pi_sample_rate = 16000; + break; + + case 6: + *pi_sample_rate = 22050; + break; + + case 7: + *pi_sample_rate = 24000; + break; + + case 8: + *pi_sample_rate = 32000; + break; + + case 9: + *pi_sample_rate = 44100; + break; + + case 10: + *pi_sample_rate = 48000; + break; + + case 11: + *pi_sample_rate = 96000; + break; + + case 12: + case 13: + case 14: + i_sample_rate_hint = i_temp; + break; + + case 15: + return 0; + } + + /* Find channels */ + i_temp = (unsigned)(p_buf[3] >> 4); + if( i_temp & 8 ) + { + if( ( i_temp & 7 ) >= 3 ) + return 0; + *pi_channels = 2; + } + else + { + *pi_channels = i_temp + 1; + } + + /* Find bits per sample */ + switch( i_temp = (unsigned)(p_buf[3] & 0x0e) >> 1 ) + { + case 0: + if( p_sys->b_stream_info ) + *pi_bits_per_sample = p_sys->stream_info.bits_per_sample; + else + return 0; + break; + + case 1: + *pi_bits_per_sample = 8; + break; + + case 2: + *pi_bits_per_sample = 12; + break; + + case 4: + *pi_bits_per_sample = 16; + break; + + case 5: + *pi_bits_per_sample = 20; + break; + + case 6: + *pi_bits_per_sample = 24; + break; + + case 3: + case 7: + return 0; + break; + } + + /* Zero padding bit */ + if( p_buf[3] & 0x01 ) return 0; + + /* End of fixed size header */ + i_header = 4; + + /* Find Sample/Frame number */ + if( i_blocksize_hint && b_variable_blocksize ) + { + i_sample_number = read_utf8( &p_buf[i_header++], &i_read ); + if( i_sample_number == INT64_C(0xffffffffffffffff) ) return 0; + } + else + { + i_sample_number = read_utf8( &p_buf[i_header++], &i_read ); + if( i_sample_number == INT64_C(0xffffffffffffffff) ) return 0; + + if( p_sys->b_stream_info ) + i_sample_number *= p_sys->stream_info.min_blocksize; + } + + i_header += i_read; + + /* Read blocksize */ + if( i_blocksize_hint ) + { + int i_val1 = p_buf[i_header++]; + if( i_blocksize_hint == 7 ) + { + int i_val2 = p_buf[i_header++]; + i_val1 = (i_val1 << 8) | i_val2; + } + i_blocksize = i_val1 + 1; + } + + /* Read sample rate */ + if( i_sample_rate_hint ) + { + int i_val1 = p_buf[i_header++]; + if( i_sample_rate_hint != 12 ) + { + int i_val2 = p_buf[i_header++]; + i_val1 = (i_val1 << 8) | i_val2; + } + if( i_sample_rate_hint == 12 ) *pi_sample_rate = i_val1 * 1000; + else if( i_sample_rate_hint == 13 ) *pi_sample_rate = i_val1; + else *pi_sample_rate = i_val1 * 10; + } + + /* Check the CRC-8 byte */ + if( flac_crc8( p_buf, i_header ) != p_buf[i_header] ) + { + return 0; + } + + /* Sanity check using stream info header when possible */ + if( p_sys->b_stream_info ) + { + if( i_blocksize < p_sys->stream_info.min_blocksize || + i_blocksize > p_sys->stream_info.max_blocksize ) + return 0; + } + return i_blocksize; +} + +/* Will return 0xffffffffffffffff for an invalid utf-8 sequence */ +static uint64_t read_utf8( const uint8_t *p_buf, int *pi_read ) +{ + uint64_t i_result = 0; + unsigned i, j; + + if( !(p_buf[0] & 0x80) ) /* 0xxxxxxx */ + { + i_result = p_buf[0]; + i = 0; + } + else if( p_buf[0] & 0xC0 && !(p_buf[0] & 0x20) ) /* 110xxxxx */ + { + i_result = p_buf[0] & 0x1F; + i = 1; + } + else if( p_buf[0] & 0xE0 && !(p_buf[0] & 0x10) ) /* 1110xxxx */ + { + i_result = p_buf[0] & 0x0F; + i = 2; + } + else if( p_buf[0] & 0xF0 && !(p_buf[0] & 0x08) ) /* 11110xxx */ + { + i_result = p_buf[0] & 0x07; + i = 3; + } + else if( p_buf[0] & 0xF8 && !(p_buf[0] & 0x04) ) /* 111110xx */ + { + i_result = p_buf[0] & 0x03; + i = 4; + } + else if( p_buf[0] & 0xFC && !(p_buf[0] & 0x02) ) /* 1111110x */ + { + i_result = p_buf[0] & 0x01; + i = 5; + } + else if( p_buf[0] & 0xFE && !(p_buf[0] & 0x01) ) /* 11111110 */ + { + i_result = 0; + i = 6; + } + else { + return INT64_C(0xffffffffffffffff); + } + + for( j = 1; j <= i; j++ ) + { + if( !(p_buf[j] & 0x80) || (p_buf[j] & 0x40) ) /* 10xxxxxx */ + { + return INT64_C(0xffffffffffffffff); + } + i_result <<= 6; + i_result |= (p_buf[j] & 0x3F); + } + + *pi_read = i; + return i_result; +} + +/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */ +static const uint8_t flac_crc8_table[256] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, + 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, + 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, + 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, + 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, + 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, + 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, + 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, + 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, + 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, + 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, + 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 +}; + +static uint8_t flac_crc8( const uint8_t *data, unsigned len ) +{ + uint8_t crc = 0; + + while(len--) + crc = flac_crc8_table[crc ^ *data++]; + + return crc; +} + -- 2.39.5