@ -532,6 +532,14 @@ static void read_chapter(AVFormatContext *s, AVIOContext *pb, int len, char *tta
int taglen ;
char tag [ 5 ] ;
if ( ! s ) {
/* We should probably just put the chapter data to extra_meta here
* and do the AVFormatContext - needing part in a separate
* ff_id3v2_parse_apic ( ) - like function . */
av_log ( NULL , AV_LOG_DEBUG , " No AVFormatContext, skipped ID3 chapter data \n " ) ;
return ;
}
if ( decode_str ( s , pb , 0 , & dst , & len ) < 0 )
return ;
if ( len < 16 )
@ -650,16 +658,17 @@ static const ID3v2EMFunc *get_extra_meta_func(const char *tag, int isv34)
return NULL ;
}
static void id3v2_parse ( AVFormatContext * s , int len , uint8_t version ,
static void id3v2_parse ( AVIOContext * pb , AVDictionary * * metadata ,
AVFormatContext * s , int len , uint8_t version ,
uint8_t flags , ID3v2ExtraMeta * * extra_meta )
{
int isv34 , unsync ;
unsigned tlen ;
char tag [ 5 ] ;
int64_t next , end = avio_tell ( s - > pb ) + len ;
int64_t next , end = avio_tell ( pb ) + len ;
int taghdrlen ;
const char * reason = NULL ;
AVIOContext pb ;
AVIOContext pb_local ;
AVIOContext * pbx ;
unsigned char * buffer = NULL ;
int buffer_size = 0 ;
@ -693,7 +702,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
unsync = flags & 0x80 ;
if ( isv34 & & flags & 0x40 ) { /* Extended header present, just skip over it */
int extlen = get_size ( s - > pb , 4 ) ;
int extlen = get_size ( pb , 4 ) ;
if ( version = = 4 )
/* In v2.4 the length includes the length field we just read. */
extlen - = 4 ;
@ -702,7 +711,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
reason = " invalid extended header length " ;
goto error ;
}
avio_skip ( s - > pb , extlen ) ;
avio_skip ( pb , extlen ) ;
len - = extlen + 4 ;
if ( len < 0 ) {
reason = " extended header too long. " ;
@ -718,20 +727,20 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
unsigned long dlen ;
if ( isv34 ) {
if ( avio_read ( s - > pb , tag , 4 ) < 4 )
if ( avio_read ( pb , tag , 4 ) < 4 )
break ;
tag [ 4 ] = 0 ;
if ( version = = 3 ) {
tlen = avio_rb32 ( s - > pb ) ;
tlen = avio_rb32 ( pb ) ;
} else
tlen = get_size ( s - > pb , 4 ) ;
tflags = avio_rb16 ( s - > pb ) ;
tlen = get_size ( pb , 4 ) ;
tflags = avio_rb16 ( pb ) ;
tunsync = tflags & ID3v2_FLAG_UNSYNCH ;
} else {
if ( avio_read ( s - > pb , tag , 3 ) < 3 )
if ( avio_read ( pb , tag , 3 ) < 3 )
break ;
tag [ 3 ] = 0 ;
tlen = avio_rb24 ( s - > pb ) ;
tlen = avio_rb24 ( pb ) ;
}
if ( tlen > ( 1 < < 28 ) )
break ;
@ -740,7 +749,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
if ( len < 0 )
break ;
next = avio_tell ( s - > pb ) + tlen ;
next = avio_tell ( pb ) + tlen ;
if ( ! tlen ) {
if ( tag [ 0 ] )
@ -752,7 +761,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
if ( tflags & ID3v2_FLAG_DATALEN ) {
if ( tlen < 4 )
break ;
dlen = avio_rb32 ( s - > pb ) ;
dlen = avio_rb32 ( pb ) ;
tlen - = 4 ;
} else
dlen = tlen ;
@ -771,12 +780,12 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
type = " encrypted and compressed " ;
av_log ( s , AV_LOG_WARNING , " Skipping %s ID3v2 frame %s. \n " , type , tag ) ;
avio_skip ( s - > pb , tlen ) ;
avio_skip ( pb , tlen ) ;
/* check for text tag or supported special meta tag */
} else if ( tag [ 0 ] = = ' T ' | |
( extra_meta & &
( extra_func = get_extra_meta_func ( tag , isv34 ) ) ) ) {
pbx = s - > pb ;
pbx = pb ;
if ( unsync | | tunsync | | tcomp ) {
av_fast_malloc ( & buffer , & buffer_size , tlen ) ;
@ -786,23 +795,23 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
}
}
if ( unsync | | tunsync ) {
int64_t end = avio_tell ( s - > pb ) + tlen ;
int64_t end = avio_tell ( pb ) + tlen ;
uint8_t * b ;
b = buffer ;
while ( avio_tell ( s - > pb ) < end & & b - buffer < tlen & & ! s - > pb - > eof_reached ) {
* b + + = avio_r8 ( s - > pb ) ;
if ( * ( b - 1 ) = = 0xff & & avio_tell ( s - > pb ) < end - 1 & &
while ( avio_tell ( pb ) < end & & b - buffer < tlen & & ! pb - > eof_reached ) {
* b + + = avio_r8 ( pb ) ;
if ( * ( b - 1 ) = = 0xff & & avio_tell ( pb ) < end - 1 & &
b - buffer < tlen & &
! s - > pb - > eof_reached ) {
uint8_t val = avio_r8 ( s - > pb ) ;
* b + + = val ? val : avio_r8 ( s - > pb ) ;
! pb - > eof_reached ) {
uint8_t val = avio_r8 ( pb ) ;
* b + + = val ? val : avio_r8 ( pb ) ;
}
}
ffio_init_context ( & pb , buffer , b - buffer , 0 , NULL , NULL , NULL ,
ffio_init_context ( & pb_local , buffer , b - buffer , 0 , NULL , NULL , NULL ,
NULL ) ;
tlen = b - buffer ;
pbx = & pb ; // read from sync buffer
pbx = & pb_local ; // read from sync buffer
}
# if CONFIG_ZLIB
@ -818,7 +827,7 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
}
if ( ! ( unsync | | tunsync ) ) {
err = avio_read ( s - > pb , buffer , tlen ) ;
err = avio_read ( pb , buffer , tlen ) ;
if ( err < 0 ) {
av_log ( s , AV_LOG_ERROR , " Failed to read compressed tag \n " ) ;
goto seek ;
@ -831,26 +840,26 @@ static void id3v2_parse(AVFormatContext *s, int len, uint8_t version,
av_log ( s , AV_LOG_ERROR , " Failed to uncompress tag: %d \n " , err ) ;
goto seek ;
}
ffio_init_context ( & pb , uncompressed_buffer , dlen , 0 , NULL , NULL , NULL , NULL ) ;
ffio_init_context ( & pb_local , uncompressed_buffer , dlen , 0 , NULL , NULL , NULL , NULL ) ;
tlen = dlen ;
pbx = & pb ; // read from sync buffer
pbx = & pb_local ; // read from sync buffer
}
# endif
if ( tag [ 0 ] = = ' T ' )
/* parse text tag */
read_ttag ( s , pbx , tlen , & s - > metadata , tag ) ;
read_ttag ( s , pbx , tlen , metadata , tag ) ;
else
/* parse special meta tag */
extra_func - > read ( s , pbx , tlen , tag , extra_meta , isv34 ) ;
} else if ( ! tag [ 0 ] ) {
if ( tag [ 1 ] )
av_log ( s , AV_LOG_WARNING , " invalid frame id, assuming padding \n " ) ;
avio_skip ( s - > pb , tlen ) ;
avio_skip ( pb , tlen ) ;
break ;
}
/* Skip to end of tag */
seek :
avio_seek ( s - > pb , next , SEEK_SET ) ;
avio_seek ( pb , next , SEEK_SET ) ;
}
/* Footer preset, always 10 bytes, skip over it */
@ -861,14 +870,15 @@ error:
if ( reason )
av_log ( s , AV_LOG_INFO , " ID3v2.%d tag skipped, cannot handle %s \n " ,
version , reason ) ;
avio_seek ( s - > pb , end , SEEK_SET ) ;
avio_seek ( pb , end , SEEK_SET ) ;
av_free ( buffer ) ;
av_free ( uncompressed_buffer ) ;
return ;
}
void ff_id3v2_read ( AVFormatContext * s , const char * magic ,
ID3v2ExtraMeta * * extra_meta )
static void id3v2_read_internal ( AVIOContext * pb , AVDictionary * * metadata ,
AVFormatContext * s , const char * magic ,
ID3v2ExtraMeta * * extra_meta )
{
int len , ret ;
uint8_t buf [ ID3v2_HEADER_SIZE ] ;
@ -877,10 +887,10 @@ void ff_id3v2_read(AVFormatContext *s, const char *magic,
do {
/* save the current offset in case there's nothing to read/skip */
off = avio_tell ( s - > pb ) ;
ret = avio_read ( s - > pb , buf , ID3v2_HEADER_SIZE ) ;
off = avio_tell ( pb ) ;
ret = avio_read ( pb , buf , ID3v2_HEADER_SIZE ) ;
if ( ret ! = ID3v2_HEADER_SIZE ) {
avio_seek ( s - > pb , off , SEEK_SET ) ;
avio_seek ( pb , off , SEEK_SET ) ;
break ;
}
found_header = ff_id3v2_match ( buf , magic ) ;
@ -890,15 +900,27 @@ void ff_id3v2_read(AVFormatContext *s, const char *magic,
( ( buf [ 7 ] & 0x7f ) < < 14 ) |
( ( buf [ 8 ] & 0x7f ) < < 7 ) |
( buf [ 9 ] & 0x7f ) ;
id3v2_parse ( s , len , buf [ 3 ] , buf [ 5 ] , extra_meta ) ;
id3v2_parse ( pb , metadata , s , len , buf [ 3 ] , buf [ 5 ] , extra_meta ) ;
} else {
avio_seek ( s - > pb , off , SEEK_SET ) ;
avio_seek ( pb , off , SEEK_SET ) ;
}
} while ( found_header ) ;
ff_metadata_conv ( & s - > metadata , NULL , ff_id3v2_34_metadata_conv ) ;
ff_metadata_conv ( & s - > metadata , NULL , id3v2_2_metadata_conv ) ;
ff_metadata_conv ( & s - > metadata , NULL , ff_id3v2_4_metadata_conv ) ;
merge_date ( & s - > metadata ) ;
ff_metadata_conv ( metadata , NULL , ff_id3v2_34_metadata_conv ) ;
ff_metadata_conv ( metadata , NULL , id3v2_2_metadata_conv ) ;
ff_metadata_conv ( metadata , NULL , ff_id3v2_4_metadata_conv ) ;
merge_date ( metadata ) ;
}
void ff_id3v2_read_dict ( AVIOContext * pb , AVDictionary * * metadata ,
const char * magic , ID3v2ExtraMeta * * extra_meta )
{
id3v2_read_internal ( pb , metadata , NULL , magic , extra_meta ) ;
}
void ff_id3v2_read ( AVFormatContext * s , const char * magic ,
ID3v2ExtraMeta * * extra_meta )
{
id3v2_read_internal ( s - > pb , & s - > metadata , s , magic , extra_meta ) ;
}
void ff_id3v2_free_extra_meta ( ID3v2ExtraMeta * * extra_meta )