id3: Remember id3v2 Header Info. Do Call mpeg_decode() Twice.

This commit is contained in:
Arthur Taylor 2021-03-22 11:05:57 -07:00
parent b00db8b15c
commit f97fa5e6ba
5 changed files with 46 additions and 32 deletions

View File

@ -1136,6 +1136,10 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...)
byte_count += count ;
break ;
case '!' : /* Clear buffer, forcing re-read. */
psf->header.end = psf->header.indx = 0 ;
break ;
default :
psf_log_printf (psf, "*** Invalid format specifier `%c'\n", c) ;
psf->error = SFE_INTERNAL ;

View File

@ -296,6 +296,12 @@ typedef SF_BROADCAST_INFO_VAR (16 * 1024) SF_BROADCAST_INFO_16K ;
typedef SF_CART_INFO_VAR (16 * 1024) SF_CART_INFO_16K ;
typedef struct
{ sf_count_t offset ;
sf_count_t len ;
unsigned minor_version ;
} ID3V2_HEADER_INFO ;
#if SIZEOF_WCHAR_T == 2
typedef wchar_t sfwchar_t ;
#else
@ -516,6 +522,8 @@ typedef struct sf_private_tag
int (*get_chunk_data) (struct sf_private_tag*, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ;
int cpu_flags ;
ID3V2_HEADER_INFO id3_header ;
} SF_PRIVATE ;

View File

@ -63,31 +63,39 @@ id3_lookup_v1_genre (int UNUSED (number))
#endif
int
id3_skip (SF_PRIVATE * psf)
{ unsigned char buf [10] ;
int offset ;
memset (buf, 0, sizeof (buf)) ;
psf_binheader_readf (psf, "pb", 0, buf, 10) ;
if (buf [0] == 'I' && buf [1] == 'D' && buf [2] == '3')
{ int offset = buf [6] & 0x7f ;
{ psf->id3_header.minor_version = buf [3] ;
offset = buf [6] & 0x7f ;
offset = (offset << 7) | (buf [7] & 0x7f) ;
offset = (offset << 7) | (buf [8] & 0x7f) ;
offset = (offset << 7) | (buf [9] & 0x7f) ;
psf_log_printf (psf, "ID3 length : %d\n--------------------\n", offset) ;
/*
** ID3 count field is how many bytes of ID3v2 header FOLLOW the ten
** bytes of header magic and offset, NOT the total ID3v2 header len.
*/
psf->id3_header.len = offset + 10 ;
psf->id3_header.offset = psf->fileoffset ;
psf_log_printf (psf, " ID3v2.%d header length : %d\n----------------------------------------\n",
psf->id3_header.minor_version, psf->id3_header.len) ;
/* Never want to jump backwards in a file. */
if (offset < 0)
return 0 ;
/* Calculate new file offset and position ourselves there. */
offset += 10 ;
if (psf->fileoffset + offset < psf->filelength)
{ psf_binheader_readf (psf, "p", offset) ;
psf->fileoffset += offset ;
/* Position ourselves at the new file offset. */
if (psf->fileoffset + psf->id3_header.len < psf->filelength)
{ psf_binheader_readf (psf, "p!", psf->id3_header.len) ;
psf->fileoffset += psf->id3_header.len ;
return 1 ;
} ;
} ;

View File

@ -526,17 +526,6 @@ mpeg_decoder_init (SF_PRIVATE *psf)
if (! (psf->file.mode & SFM_READ))
return SFE_INTERNAL ;
/*
** Check to see if we have already successfully opened the file when we
** guessed it was an MP3 based on seeing an ID3 header.
*/
if (psf->codec_data != NULL &&
(SF_CODEC (psf->sf.format) == SF_FORMAT_MPEG_LAYER_I
|| SF_CODEC (psf->sf.format) == SF_FORMAT_MPEG_LAYER_II
|| SF_CODEC (psf->sf.format) == SF_FORMAT_MPEG_LAYER_III)
&& ((MPEG_DEC_PRIVATE *) psf->codec_data)->unique_id == psf->unique_id)
return 0 ;
/*
** *** FIXME - Threading issues ***
**
@ -580,15 +569,31 @@ mpeg_decoder_init (SF_PRIVATE *psf)
#endif
psf->dataoffset = 0 ;
/*
** Need to pass the first MPEG frame to libmpg123, but that frame was read
** into psf->binheader in order that we could identify the stream.
*/
if (psf->is_pipe)
{ // Need to read data in the binheader buffer. Avoid a file seek.
{ /*
** Can't seek, so setup our libmpg123 io callbacks to read the binheader
** buffer first.
*/
psf_binheader_readf (psf, "p", 0) ;
pmp3d->header_remaining = psf_binheader_readf (psf, NULL) ;
/* Tell libmpg123 we can't seek the file. */
mpg123_param (pmp3d->pmh, MPG123_ADD_FLAGS, MPG123_NO_PEEK_END, 1.0) ;
}
else
{ /*
** libmpg123 can parse the ID3v2 header. Undo the embedded file offset if the
** enclosing file data is the ID3v2 header.
*/
if (psf->id3_header.len > 0 && psf->id3_header.len + psf->id3_header.offset == psf->fileoffset)
psf->fileoffset = psf->id3_header.offset ;
psf_fseek (psf, 0, SEEK_SET) ;
} ;
error = mpg123_open_handle (pmp3d->pmh, psf) ;
if (error != MPG123_OK)

View File

@ -967,7 +967,6 @@ sf_format_check (const SF_INFO *info)
return 0 ;
if (endian != SF_ENDIAN_FILE)
return 0 ;
/* TODO */
if (subformat == SF_FORMAT_MPEG_LAYER_I || subformat == SF_FORMAT_MPEG_LAYER_II || subformat == SF_FORMAT_MPEG_LAYER_III)
return 1 ;
break ;
@ -2881,16 +2880,6 @@ retry:
if (buffer [0] == MAKE_MARKER ('I', 'D', '3', 2) || buffer [0] == MAKE_MARKER ('I', 'D', '3', 3)
|| buffer [0] == MAKE_MARKER ('I', 'D', '3', 4))
{ psf_log_printf (psf, "Found 'ID3' marker.\n") ;
/* Guess MP3, try and open it as such. Allows libmpg123 to parse the ID3v2 headers */
if (psf->file.mode == SFM_READ)
{ if (mpeg_open (psf) == 0)
return SF_FORMAT_MPEG | ((~SF_FORMAT_TYPEMASK) & psf->sf.format) ;
else if (psf->codec_close)
psf->codec_close (psf) ;
} ;
/* Otherwise, seek to after the ID3 header */
if (id3_skip (psf))
goto retry ;
return 0 ;