X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Fflac.c;h=0405d2e978250b4622f1242e77b2017a746c29c5;hb=53d547df9cd7c65830fad4c15fae43f35523d484;hp=8b0ca384afa7e72a21e9c7d31e7ae50021bc10af;hpb=8dc5af515d36089f28483c4eca3dd9180eaae848;p=vlc diff --git a/modules/demux/flac.c b/modules/demux/flac.c index 8b0ca384af..0405d2e978 100644 --- a/modules/demux/flac.c +++ b/modules/demux/flac.c @@ -1,25 +1,25 @@ /***************************************************************************** * flac.c : FLAC demux module for vlc ***************************************************************************** - * Copyright (C) 2001-2007 the VideoLAN team + * Copyright (C) 2001-2008 VLC authors and VideoLAN * $Id$ * * Authors: Gildas Bazin * Laurent Aimar * - * 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 + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 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. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser 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. + * You should have received a copy of the GNU Lesser 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. *****************************************************************************/ /***************************************************************************** @@ -32,12 +32,13 @@ #include #include #include -#include -#include -#include +#include /* vlc_meta_* */ +#include /* vlc_input_attachment, vlc_seekpoint */ +#include /* decoder_t */ +#include /* EnsureUTF8 */ + #include -#include -#include "vorbis.h" +#include "xiph_metadata.h" /* vorbis comments */ /***************************************************************************** * Module descriptor @@ -71,11 +72,8 @@ struct demux_sys_t decoder_t *p_packetizer; vlc_meta_t *p_meta; - audio_replay_gain_t replay_gain; - int64_t i_time_offset; int64_t i_pts; - int64_t i_pts_start; int64_t i_length; /* Length from stream info */ int64_t i_data_pos; @@ -91,7 +89,7 @@ struct demux_sys_t int i_cover_score; }; -#define STREAMINFO_SIZE 38 +#define STREAMINFO_SIZE 34 #define FLAC_PACKET_SIZE 16384 /***************************************************************************** @@ -111,23 +109,33 @@ static int Open( vlc_object_t * p_this ) if( p_peek[0]!='f' || p_peek[1]!='L' || p_peek[2]!='a' || p_peek[3]!='C' ) { - if( !p_demux->b_force ) return VLC_EGENERIC; + if( !p_demux->b_force ) + { + char *psz_mime = stream_ContentType( p_demux->s ); + if ( !psz_mime || strcmp( psz_mime, "audio/flac" ) ) + { + free( psz_mime ); + return VLC_EGENERIC; + } + free( psz_mime ); + } /* User forced */ msg_Err( p_demux, "this doesn't look like a flac stream, " "continuing anyway" ); } + p_sys = malloc( sizeof( demux_sys_t ) ); + if( unlikely(p_sys == NULL) ) + return VLC_ENOMEM; + p_demux->pf_demux = Demux; p_demux->pf_control = Control; - p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); + p_demux->p_sys = p_sys; p_sys->b_start = true; p_sys->p_meta = NULL; - memset( &p_sys->replay_gain, 0, sizeof(p_sys->replay_gain) ); p_sys->i_length = 0; - p_sys->i_time_offset = 0; p_sys->i_pts = 0; - p_sys->i_pts_start = 0; p_sys->p_es = NULL; TAB_INIT( p_sys->i_seekpoint, p_sys->seekpoint ); TAB_INIT( p_sys->i_attachments, p_sys->attachments); @@ -143,7 +151,6 @@ static int Open( vlc_object_t * p_this ) /* Load the FLAC packetizer */ /* Store STREAMINFO for the decoder and packetizer */ - p_streaminfo[4] |= 0x80; /* Fake this as the last metadata block */ es_format_Init( &fmt, AUDIO_ES, VLC_CODEC_FLAC ); fmt.i_extra = i_streaminfo; fmt.p_extra = p_streaminfo; @@ -164,7 +171,6 @@ static int Open( vlc_object_t * p_this ) p_sys->attachments[p_sys->i_cover_idx]->psz_name ); vlc_meta_Set( p_sys->p_meta, vlc_meta_ArtworkURL, psz_url ); } - vlc_audio_replay_gain_MergeFromMeta( &p_sys->replay_gain, p_sys->p_meta ); return VLC_SUCCESS; } @@ -176,11 +182,12 @@ static void Close( vlc_object_t * p_this ) demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys = p_demux->p_sys; + for( int i = 0; i < p_sys->i_seekpoint; i++ ) + vlc_seekpoint_Delete(p_sys->seekpoint[i]); TAB_CLEAN( p_sys->i_seekpoint, p_sys->seekpoint ); - int i; - for( i = 0; i < p_sys->i_attachments; i++ ) - free( p_sys->attachments[i] ); + for( int i = 0; i < p_sys->i_attachments; i++ ) + vlc_input_attachment_Delete( p_sys->attachments[i] ); TAB_CLEAN( p_sys->i_attachments, p_sys->attachments); /* Delete the decoder */ @@ -201,14 +208,16 @@ static int Demux( demux_t *p_demux ) demux_sys_t *p_sys = p_demux->p_sys; block_t *p_block_in, *p_block_out; - if( !( p_block_in = stream_Block( p_demux->s, FLAC_PACKET_SIZE ) ) ) - return 0; + bool b_eof = !( p_block_in = stream_Block( p_demux->s, FLAC_PACKET_SIZE ) ); - p_block_in->i_pts = p_block_in->i_dts = p_sys->b_start ? 1 : 0; - p_sys->b_start = false; + if ( p_block_in ) + { + p_block_in->i_pts = p_block_in->i_dts = p_sys->b_start ? VLC_TS_0 : VLC_TS_INVALID; + p_sys->b_start = false; + } while( (p_block_out = p_sys->p_packetizer->pf_packetize( - p_sys->p_packetizer, &p_block_in )) ) + p_sys->p_packetizer, (p_block_in) ? &p_block_in : NULL )) ) { while( p_block_out ) { @@ -219,16 +228,11 @@ static int Demux( demux_t *p_demux ) if( p_sys->p_es == NULL ) { p_sys->p_packetizer->fmt_out.b_packetized = true; - p_sys->p_packetizer->fmt_out.audio_replay_gain = p_sys->replay_gain; p_sys->p_es = es_out_Add( p_demux->out, &p_sys->p_packetizer->fmt_out); } p_sys->i_pts = p_block_out->i_dts; - /* Correct timestamp */ - p_block_out->i_pts += p_sys->i_time_offset; - p_block_out->i_dts += p_sys->i_time_offset; - /* set PCR */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block_out->i_dts ); @@ -237,7 +241,7 @@ static int Demux( demux_t *p_demux ) p_block_out = p_next; } } - return 1; + return !b_eof; } /***************************************************************************** @@ -272,7 +276,7 @@ static int64_t ControlGetLength( demux_t *p_demux ) static int64_t ControlGetTime( demux_t *p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; - return __MAX(p_sys->i_pts, p_sys->i_pts_start) + p_sys->i_time_offset; + return p_sys->i_pts; } static int ControlSetTime( demux_t *p_demux, int64_t i_time ) @@ -297,20 +301,19 @@ static int ControlSetTime( demux_t *p_demux, int64_t i_time ) i_delta_time = i_time - p_sys->seekpoint[i]->i_time_offset; /* XXX We do exact seek if it's not too far away(45s) */ - if( i_delta_time < 45*INT64_C(1000000) ) + if( i_delta_time < CLOCK_FREQ * 45 ) { if( stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos ) ) return VLC_EGENERIC; - p_sys->i_time_offset = p_sys->seekpoint[i]->i_time_offset - p_sys->i_pts; - p_sys->i_pts_start = p_sys->i_pts+i_delta_time; - es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, p_sys->i_pts_start + p_sys->i_time_offset ); + es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_time ); } else { int64_t i_delta_offset; int64_t i_next_time; int64_t i_next_offset; + uint32_t i_time_align = 1; if( i+1 < p_sys->i_seekpoint ) { @@ -324,15 +327,16 @@ static int ControlSetTime( demux_t *p_demux, int64_t i_time ) } i_delta_offset = 0; + + if ( INT64_MAX / i_delta_time < (i_next_offset - p_sys->seekpoint[i]->i_byte_offset) ) + i_time_align = CLOCK_FREQ; + if( i_next_time-p_sys->seekpoint[i]->i_time_offset > 0 ) - i_delta_offset = (i_next_offset - p_sys->seekpoint[i]->i_byte_offset) * i_delta_time / - (i_next_time-p_sys->seekpoint[i]->i_time_offset); + i_delta_offset = (i_next_offset - p_sys->seekpoint[i]->i_byte_offset) * (i_delta_time / i_time_align) / + ((i_next_time-p_sys->seekpoint[i]->i_time_offset) / i_time_align); if( stream_Seek( p_demux->s, p_sys->seekpoint[i]->i_byte_offset+p_sys->i_data_pos + i_delta_offset ) ) return VLC_EGENERIC; - - p_sys->i_pts_start = p_sys->i_pts; - p_sys->i_time_offset = (p_sys->seekpoint[i]->i_time_offset+i_delta_time) - p_sys->i_pts; } return VLC_SUCCESS; } @@ -395,14 +399,13 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) input_attachment_t ***ppp_attach = (input_attachment_t***)va_arg( args, input_attachment_t*** ); int *pi_int = (int*)va_arg( args, int * ); - int i; if( p_sys->i_attachments <= 0 ) return VLC_EGENERIC; - *pi_int = p_sys->i_attachments;; - *ppp_attach = malloc( sizeof(input_attachment_t**) * p_sys->i_attachments ); - for( i = 0; i < p_sys->i_attachments; i++ ) + *pi_int = p_sys->i_attachments; + *ppp_attach = xmalloc( sizeof(input_attachment_t*) * p_sys->i_attachments ); + for( int i = 0; i < p_sys->i_attachments; i++ ) (*ppp_attach)[i] = vlc_input_attachment_Duplicate( p_sys->attachments[i] ); return VLC_SUCCESS; } @@ -436,47 +439,25 @@ static int ReadMeta( demux_t *p_demux, uint8_t **pp_streaminfo, int *pi_streami int i_peek; const uint8_t *p_peek; bool b_last; - int i_sample_rate; + int i_sample_rate = 0; int64_t i_sample_count; - seekpoint_t *s; - /* Read STREAMINFO */ - i_peek = stream_Peek( p_demux->s, &p_peek, 8 ); - if( (p_peek[4] & 0x7F) != META_STREAMINFO ) - { - msg_Err( p_demux, "this isn't a STREAMINFO metadata block" ); - return VLC_EGENERIC; - } - if( Get24bBE(&p_peek[5]) != (STREAMINFO_SIZE - 4) ) - { - msg_Err( p_demux, "invalid size for a STREAMINFO metadata block" ); - return VLC_EGENERIC; - } - - *pi_streaminfo = 4 + STREAMINFO_SIZE; - *pp_streaminfo = malloc( 4 + STREAMINFO_SIZE ); - if( *pp_streaminfo == NULL ) - return VLC_EGENERIC; - - if( stream_Read( p_demux->s, *pp_streaminfo, 4+STREAMINFO_SIZE ) != 4+STREAMINFO_SIZE ) - { - msg_Err( p_demux, "failed to read STREAMINFO metadata block" ); - free( *pp_streaminfo ); - return VLC_EGENERIC; - } - - /* */ - ParseStreamInfo( &i_sample_rate, &i_sample_count, *pp_streaminfo ); - if( i_sample_rate > 0 ) - p_sys->i_length = i_sample_count * INT64_C(1000000)/i_sample_rate; + *pp_streaminfo = NULL; /* Be sure we have seekpoint 0 */ - s = vlc_seekpoint_New(); + seekpoint_t *s = vlc_seekpoint_New(); s->i_time_offset = 0; s->i_byte_offset = 0; TAB_APPEND( p_sys->i_seekpoint, p_sys->seekpoint, s ); - b_last = (*pp_streaminfo)[4]&0x80; + uint8_t header[4]; + if( stream_Read( p_demux->s, header, 4) < 4) + return VLC_EGENERIC; + + if (memcmp(header, "fLaC", 4)) + return VLC_EGENERIC; + + b_last = 0; while( !b_last ) { int i_len; @@ -489,7 +470,37 @@ static int ReadMeta( demux_t *p_demux, uint8_t **pp_streaminfo, int *pi_streami i_type = p_peek[0]&0x7f; i_len = Get24bBE( &p_peek[1] ); - if( i_type == META_SEEKTABLE ) + if( i_type == META_STREAMINFO && !*pp_streaminfo ) + { + if( i_len != STREAMINFO_SIZE ) { + msg_Err( p_demux, "invalid size %d for a STREAMINFO metadata block", i_len ); + return VLC_EGENERIC; + } + + *pi_streaminfo = STREAMINFO_SIZE; + *pp_streaminfo = malloc( STREAMINFO_SIZE); + if( *pp_streaminfo == NULL ) + return VLC_EGENERIC; + + if( stream_Read( p_demux->s, NULL, 4) < 4) + { + free( *pp_streaminfo ); + return VLC_EGENERIC; + } + if( stream_Read( p_demux->s, *pp_streaminfo, STREAMINFO_SIZE ) != STREAMINFO_SIZE ) + { + msg_Err( p_demux, "failed to read STREAMINFO metadata block" ); + free( *pp_streaminfo ); + return VLC_EGENERIC; + } + + /* */ + ParseStreamInfo( &i_sample_rate, &i_sample_count, *pp_streaminfo ); + if( i_sample_rate > 0 ) + p_sys->i_length = i_sample_count * CLOCK_FREQ /i_sample_rate; + continue; + } + else if( i_type == META_SEEKTABLE ) { i_peek = stream_Peek( p_demux->s, &p_peek, 4+i_len ); if( i_peek == 4+i_len ) @@ -515,14 +526,15 @@ static int ReadMeta( demux_t *p_demux, uint8_t **pp_streaminfo, int *pi_streami /* */ p_sys->i_data_pos = stream_Tell( p_demux->s ); + if (!*pp_streaminfo) + return VLC_EGENERIC; + return VLC_SUCCESS; } static void ParseStreamInfo( int *pi_rate, int64_t *pi_count, uint8_t *p_data ) { - const int i_skip = 4+4; - - *pi_rate = GetDWBE(&p_data[i_skip+4+6]) >> 12; - *pi_count = GetQWBE(&p_data[i_skip+4+6]) & ((INT64_C(1)<<36)-1); + *pi_rate = GetDWBE(&p_data[4+6]) >> 12; + *pi_count = GetQWBE(&p_data[4+6]) & ((INT64_C(1)<<36)-1); } static void ParseSeekTable( demux_t *p_demux, const uint8_t *p_data, int i_data, @@ -545,7 +557,7 @@ static void ParseSeekTable( demux_t *p_demux, const uint8_t *p_data, int i_data, continue; s = vlc_seekpoint_New(); - s->i_time_offset = i_sample * INT64_C(1000000)/i_sample_rate; + s->i_time_offset = i_sample * CLOCK_FREQ / i_sample_rate; s->i_byte_offset = GetQWBE( &p_data[4+18*i+8] ); /* Check for duplicate entry */ @@ -567,7 +579,6 @@ static void ParseSeekTable( demux_t *p_demux, const uint8_t *p_data, int i_data, /* TODO sort it by size and remove wrong seek entry (time not increasing) */ } -#define RM(x) do { i_data -= (x); p_data += (x); } while(0) static void ParseComment( demux_t *p_demux, const uint8_t *p_data, int i_data ) { demux_sys_t *p_sys = p_demux->p_sys; @@ -575,74 +586,22 @@ static void ParseComment( demux_t *p_demux, const uint8_t *p_data, int i_data ) if( i_data < 4 ) return; - vorbis_ParseComment( &p_sys->p_meta, &p_data[4], i_data - 4 ); - + vorbis_ParseComment( NULL, &p_sys->p_meta, &p_data[4], i_data - 4, + &p_sys->i_attachments, &p_sys->attachments, + &p_sys->i_cover_score, &p_sys->i_cover_idx, NULL, NULL, NULL, NULL ); } static void ParsePicture( demux_t *p_demux, const uint8_t *p_data, int i_data ) { - static const int pi_cover_score[] = { - 0, /* other */ - 2, 1, /* icons */ - 10, /* front cover */ - 9, /* back cover */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 6, /* movie/video screen capture */ - 0, - 7, /* Illustration */ - 8, /* Band/Artist logotype */ - 0, /* Publisher/Studio */ - }; demux_sys_t *p_sys = p_demux->p_sys; - int i_type; - int i_len; - char *psz_mime = NULL; - char *psz_description = NULL; - input_attachment_t *p_attachment; - char psz_name[128]; - - if( i_data < 4 + 3*4 ) + + i_data -= 4; p_data += 4; + + input_attachment_t *p_attachment = ParseFlacPicture( p_data, i_data, + p_sys->i_attachments, &p_sys->i_cover_score, &p_sys->i_cover_idx ); + if( p_attachment == NULL ) return; -#define RM(x) do { i_data -= (x); p_data += (x); } while(0) - RM(4); - - i_type = GetDWBE( p_data ); RM(4); - i_len = GetDWBE( p_data ); RM(4); - if( i_len < 0 || i_data < i_len + 4 ) - goto error; - psz_mime = strndup( (const char*)p_data, i_len ); RM(i_len); - i_len = GetDWBE( p_data ); RM(4); - if( i_len < 0 || i_data < i_len + 4*4 + 4) - goto error; - psz_description = strndup( (const char*)p_data, i_len ); RM(i_len); - EnsureUTF8( psz_description ); - RM(4*4); - i_len = GetDWBE( p_data ); RM(4); - if( i_len < 0 || i_len > i_data ) - goto error; - - msg_Dbg( p_demux, "FLAC: Picture type=%d mime=%s description='%s' file length=%d", - i_type, psz_mime, psz_description, i_len ); - - snprintf( psz_name, sizeof(psz_name), "picture%d", p_sys->i_attachments ); - if( !strcasecmp( psz_mime, "image/jpeg" ) ) - strcat( psz_name, ".jpg" ); - else if( !strcasecmp( psz_mime, "image/png" ) ) - strcat( psz_name, ".png" ); - - p_attachment = vlc_input_attachment_New( psz_name, psz_mime, psz_description, - p_data, i_data ); - TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment ); - if( i_type >= 0 && (unsigned int)i_type < sizeof(pi_cover_score)/sizeof(pi_cover_score[0]) && - p_sys->i_cover_score < pi_cover_score[i_type] ) - { - p_sys->i_cover_idx = p_sys->i_attachments-1; - p_sys->i_cover_score = pi_cover_score[i_type]; - } -error: - free( psz_mime ); - free( psz_description ); + TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment ); } -#undef RM