cleanups and fixes

This commit is contained in:
Glenn Maynard
2003-10-03 03:35:58 +00:00
parent 4dd503780a
commit b3474cd654
+83 -88
View File
@@ -213,11 +213,10 @@ struct madlib_t
/* Number of bytes of header data at the beginning; used for seeking. */
int header_bytes;
/* This is set to true once we get a frame that isn't a header. This
* is to keep us from accidentally double-counting a header. We do
* reset these to 0 when we rewind, but it's possible we could
* seek_stream_to_byte in the middle of them. */
int finished_header;
/* Whether we've decoded the first frame of real audio yet. If this
* is false, we're somewhere before the first frame; we might be in
* the middle of headers. */
int first_frame;
/* This data is filled in when the first frame is decoded. */
int has_xing; /* whether xingtag is valid */
@@ -256,24 +255,31 @@ static signed int scale(mad_fixed_t sample)
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
static int get_this_frame_byte( const madlib_t *mad )
{
int ret = mad->inbuf_filepos;
/* If we have a frame, adjust. */
if( mad->Stream.this_frame != NULL )
ret += mad->Stream.this_frame-mad->inbuf;
return ret;
}
/* Called on the first frame decoded. Returns true if this frame
* should be ignored. */
int RageSoundReader_MP3::handle_first_frame()
{
int ret = 0;
if( mad->finished_header )
return ret;
mad->finished_header = true;
/* Check for a XING tag. */
xing_init( &mad->xingtag );
if( xing_parse(&mad->xingtag, mad->Stream.anc_ptr, mad->Stream.anc_bitlen) == 0 )
{
mad_timer_t tm;
/* Add it to the header byte count. */
mad->header_bytes += mad->Stream.next_frame - mad->Stream.this_frame;
mad->header_bytes = min( mad->header_bytes, get_this_frame_byte(mad) );
mad->has_xing = true;
@@ -295,17 +301,6 @@ int RageSoundReader_MP3::handle_first_frame()
return ret;
}
static int get_this_frame_byte( const madlib_t *mad )
{
int ret = mad->inbuf_filepos;
/* If we have a frame, adjust. */
if( mad->Stream.this_frame != NULL )
ret += mad->Stream.this_frame-mad->inbuf;
return ret;
}
int RageSoundReader_MP3::fill_buffer()
{
@@ -362,21 +357,27 @@ int RageSoundReader_MP3::do_mad_frame_decode()
if( !mad_frame_decode(&mad->Frame,&mad->Stream) )
{
/* OK. */
if( mad_timer_compare(mad->Timer, mad_timer_zero) == 0 )
if( mad->first_frame )
{
/* We're at the beginning. */
/* We're at the beginning. Is this a Xing tag? */
if(handle_first_frame())
{
/* The first frame contained a header. Continue searching. */
continue;
}
/* We've decoded the first frame of data. */
mad->first_frame = false;
mad->Timer = mad_timer_zero;
mad->header_bytes = get_this_frame_byte(mad);
}
else
{
mad_timer_add( &mad->Timer,mad->Frame.header.duration );
}
/* Do this now, while Timer is the time of this frame, not the next frame. */
fill_frame_index_cache( mad );
/* Set Timer to the time of the next frame. */
mad_timer_add( &mad->Timer,mad->Frame.header.duration );
return 1;
}
@@ -384,19 +385,17 @@ int RageSoundReader_MP3::do_mad_frame_decode()
{
/* This might be an ID3V2 tag. */
const int tagsize = id3_tag_query(mad->Stream.this_frame,
mad->Stream.bufend - mad->Stream.this_frame);
mad->Stream.bufend - mad->Stream.this_frame);
if(tagsize && !mad_timer_compare(mad->Timer, mad_timer_zero))
if( tagsize )
{
if( !mad->finished_header )
mad->header_bytes += tagsize;
mad_stream_skip(&mad->Stream, tagsize);
/* Don't count the tagsize against the max-read-per-call figure. */
bytes_read -= tagsize;
}
continue;
continue;
}
}
if( mad->Stream.error == MAD_ERROR_BADCRC )
@@ -459,7 +458,7 @@ int RageSoundReader_MP3::FindOffsetFix()
mad_stream_buffer(&mad->Stream, NULL, 0);
mad->inbuf_filepos = 0;
mad->header_bytes = 0;
mad->finished_header = false;
mad->first_frame = true;
/* Read a couple frames, to make sure we're synced. */
for( i = 0; i < 5; ++i )
@@ -473,7 +472,6 @@ int RageSoundReader_MP3::FindOffsetFix()
if( ret == -1 )
return false; /* it set the error */
mad->outleft = 0;
synth_output();
}
@@ -507,7 +505,6 @@ int RageSoundReader_MP3::FindOffsetFix()
if( ret == -1 )
return false; /* it set the error */
mad->outleft = 0;
synth_output();
if( mad->outleft == size && !memcmp( cpy, mad->outbuf, mad->outleft ) )
{
@@ -515,7 +512,6 @@ int RageSoundReader_MP3::FindOffsetFix()
Actual = mad->Timer;
found = true;
break;
}
}
@@ -537,6 +533,8 @@ int RageSoundReader_MP3::FindOffsetFix()
void RageSoundReader_MP3::synth_output()
{
mad->outleft = 0;
if( MAD_NCHANNELS(&mad->Frame.header) != this->Channels )
{
/* This frame contains a different number of channels than the first.
@@ -580,6 +578,12 @@ int RageSoundReader_MP3::seek_stream_to_byte( int byte )
mad->inbytes = mad->outleft = mad->outpos = 0;
mad->inbuf_filepos = byte;
/* If the position is <= the position of the first audio sample, then
* we're at the beginning. */
if( mad->toc[0] != -1 )
mad->first_frame = ( byte <= mad->toc[0] );
return 1;
}
@@ -593,26 +597,17 @@ int RageSoundReader_MP3::resync()
/* Save the timer; decoding will change it, and we need to put it back. */
mad_timer_t orig = mad->Timer;
int reads = 0;
/* Seek backwards up to 4k. */
int origpos = mad->inbuf_filepos;
int seekpos = origpos - 1024*4;
if( seekpos < 0 )
seekpos = 0;
const int origpos = mad->inbuf_filepos;
const int seekpos = max( 0, origpos - 1024*4 );
seek_stream_to_byte( seekpos );
/* We're already synced if we're at the beginning. */
/* ... but we need to resync anyway; even if seekpos < 0, origpos might
* not have been. */
// if( mad->inbuf_filepos == 0 )
// return 1;
/* Agh. This is annoying. We want to decode enough so that the next frame
* read will be the first frame after the current file pointer. If we just
* read until the file pointer is >= what it was, we've passed it already.
* So, read until it's >= what it was, counting the number of times we had
* to read; then back up again and read n-1 times. Gross. */
int reads = 0;
do
{
if( do_mad_frame_decode() <= 0 ) /* XXX eof */
@@ -670,10 +665,10 @@ SoundReader_FileReader::OpenResult RageSoundReader_MP3::Open( CString filename_
mad->length = -1;
mad->inbuf_filepos = 0;
mad->header_bytes = 0;
mad->finished_header = false;
mad->has_xing = false;
mad->timer_accurate = 1;
mad->bitrate = -1;
mad->first_frame = true;
for(int i = 0; i < 200; ++i)
mad->toc[i] = -1;
@@ -699,8 +694,6 @@ SoundReader_FileReader::OpenResult RageSoundReader_MP3::Open( CString filename_
return OPEN_NO_MATCH;
}
LOG->Trace("Accepting MP3 stream.");
/* Store the bitrate of the frame we just got. */
if(mad->bitrate == -1)
mad->bitrate = mad->Frame.header.bitrate;
@@ -771,13 +764,13 @@ int RageSoundReader_MP3::Read( char *buf, unsigned len )
}
/* Decode more from the MP3 stream. */
mad->outpos = 0;
int ret = do_mad_frame_decode();
if( ret == 0 )
return bw;
if( ret == -1 )
return -1;
mad->outpos = 0;
synth_output();
}
@@ -802,21 +795,8 @@ bool RageSoundReader_MP3::MADLIB_rewind()
mad_stream_buffer(&mad->Stream, NULL, 0);
mad->inbuf_filepos = 0;
mad->header_bytes = 0;
mad->finished_header = false;
/* Decode and synth a frame, so we'll skip any id3/xing tags and the
* next_frame pointer will be valid--in case we seek immediately after
* this. */
int ret = do_mad_frame_decode();
if( ret == 0 )
{
SetError("Unexpected EOF");
return false;
}
if( ret == -1 )
return false; /* it set the error */
synth_output();
mad->first_frame = true;
mad->Stream.this_frame = NULL;
return true;
}
@@ -879,7 +859,7 @@ int RageSoundReader_MP3::SetPosition_toc( int ms, bool Xing )
{
seek_stream_to_byte( bytepos );
mad_timer_set( &mad->Timer, 0, percent * mad->length / 1000, 100 );
mad_timer_set( &mad->Timer, 0, percent * mad->length, 100 );
/* We've jumped across the file, so the decoder is currently desynced. */
resync();
@@ -896,30 +876,33 @@ int RageSoundReader_MP3::SetPosition_hard( int ms )
/* This seek doesn't change the accuracy of our timer. */
/* If we're already exactly at the requested position, OK. */
if( mad_timer_compare(mad->Timer, desired) == 0 )
return 0;
/* If we're already past the requested position, rewind. */
mad_timer_set(&desired, 0, ms, 1000);
if(mad_timer_compare(mad->Timer, desired) > 0)
MADLIB_rewind();
/* Decode frames until the current frame contains the desired offset. */
while(1)
{
/* If cur > desired, this frame contains the position. Since we've
if( do_mad_frame_decode() == -1 )
return -1; /* it set the error */
/* If desired < next_frame_timer, this frame contains the position. Since we've
* already decoded the frame, synth it, too. */
if( mad_timer_compare(mad->Timer, desired) > 0 )
mad_timer_t next_frame_timer = mad->Timer;
mad_timer_add( &next_frame_timer, mad->framelength );
if( mad_timer_compare(desired, next_frame_timer) < 0 )
{
mad->outleft = 0;
synth_output();
/* mad->Timer is the timestamp of the next frame. Subtract the frame length
* to find out the timestamp of the frame we just synthed. */
mad_timer_t ts = mad->Timer;
mad_timer_sub( &ts, mad->framelength );
/* We just synthed data starting at ts, containing the desired offset.
* Skip (desired - ts) worth of frames in the output to line up. */
/* We just synthed data starting at mad->Timer, containing the desired offset.
* Skip (desired - mad->Timer) worth of frames in the output to line up. */
mad_timer_t skip = desired;
mad_timer_sub( &skip, ts );
mad_timer_sub( &skip, mad->Timer );
int samples = mad_timer_count( skip, (mad_units) SampleRate );
@@ -930,8 +913,13 @@ int RageSoundReader_MP3::SetPosition_hard( int ms )
return ms;
}
if( do_mad_frame_decode() == -1 )
return -1; /* it set the error */
/* Otherwise, if the desired time will be in the *next* decode, then synth
* this one, too. */
mad_timer_t next_next_frame_timer = next_frame_timer;
mad_timer_add( &next_next_frame_timer, mad->framelength );
if( mad_timer_compare(desired, next_next_frame_timer) < 0 )
synth_output();
}
}
@@ -944,11 +932,10 @@ int RageSoundReader_MP3::SetPosition_estimate( int ms )
mad_timer_t seekamt;
mad_timer_set( &seekamt, 0, ms, 1000 );
{
/* We're going to skip ahead three samples below plus a little,
* as the decoder resyncs, so seek four frames earlier htan
/* We're going to skip ahead two samples below, so seek earlier than
* we were asked to. */
mad_timer_t back_len = mad->framelength;
mad_timer_multiply(&back_len, -4);
mad_timer_multiply(&back_len, -2);
mad_timer_add(&seekamt, back_len);
if( mad_timer_compare(seekamt, mad_timer_zero) < 0 )
seekamt = mad_timer_zero;
@@ -962,7 +949,10 @@ int RageSoundReader_MP3::SetPosition_estimate( int ms )
* Don't use resync(); it's slow. Just decode a few frames. */
if( do_mad_frame_decode() == -1 ) return -1;
if( do_mad_frame_decode() == -1 ) return -1;
if( do_mad_frame_decode() == -1 ) return -1;
/* Throw out one synth. */
synth_output();
mad->outleft = 0;
/* Find out where we really seeked to. */
ms = (get_this_frame_byte(mad) - mad->header_bytes) / (mad->bitrate / 8 / 1000);
@@ -1038,8 +1028,13 @@ int RageSoundReader_MP3::GetLengthInternal( bool fast )
break;
}
/* mad->Timer is the timestamp of the current frame; find the timestamp of
* the very end. */
mad_timer_t end = mad->Timer;
mad_timer_add( &end, mad->framelength );
/* Count milliseconds. */
return mad_timer_count( mad->Timer, MAD_UNITS_MILLISECONDS );
return mad_timer_count( end, MAD_UNITS_MILLISECONDS );
}
int RageSoundReader_MP3::GetLengthConst( bool fast ) const