Mercurial > SDL_sound_CoreAudio
diff decoders/ogg.c @ 433:f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Sat, 21 Dec 2002 11:32:14 +0000 |
parents | cbb15ecf423a |
children | 30f96c853462 |
line wrap: on
line diff
--- a/decoders/ogg.c Tue Dec 10 02:15:32 2002 +0000 +++ b/decoders/ogg.c Sat Dec 21 11:32:14 2002 +0000 @@ -238,14 +238,24 @@ free(vf); } /* OGG_close */ - +/* Note: According to the Vorbis documentation: + * "ov_read() will decode at most one vorbis packet per invocation, + * so the value returned will generally be less than length." + * Due to this, for buffer sizes like 16384, SDL_Sound was always getting + * an underfilled buffer and always setting the EAGAIN flag. + * Since the SDL_Sound API implies that the entire buffer + * should be filled unless EOF, additional code has been added + * to this function to call ov_read() until the buffer is filled. + * However, there may still be some corner cases where the buffer + * cannot be entirely filled. So be aware. + */ static Uint32 OGG_read(Sound_Sample *sample) { int rc; int bitstream; - Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private; - + rc = ov_read(vf, internal->buffer, internal->buffer_size, ((sample->actual.format & 0x1000) ? 1 : 0), /* bigendian? */ ((sample->actual.format & 0xFF) / 8), /* bytes per sample point */ @@ -255,13 +265,85 @@ /* Make sure the read went smoothly... */ if (rc == 0) sample->flags |= SOUND_SAMPLEFLAG_EOF; - + else if (rc < 0) sample->flags |= SOUND_SAMPLEFLAG_ERROR; - /* (next call this EAGAIN may turn into an EOF or error.) */ + /* If the buffer isn't filled, keep trying to fill it + * until no more data can be grabbed */ else if ((Uint32) rc < internal->buffer_size) - sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; + { + /* Creating a pointer to the buffer that denotes where to start + * writing new data. */ + Uint8* buffer_start_point = NULL; + int total_bytes_read = rc; + int bytes_remaining = internal->buffer_size - rc; + + /* Keep grabbing data until something prevents + * us from getting more. (Could be EOF, + * packets are too large to fit in remaining + * space, or an error.) + */ + while( (rc > 0) && (bytes_remaining > 0) ) + { + /* Set buffer pointer to end of last write */ + /* All the messiness is to get rid of the warning for + * dereferencing a void* + */ + buffer_start_point = &(((Uint8*)internal->buffer)[total_bytes_read]); + rc = ov_read(vf, buffer_start_point, bytes_remaining, + ((sample->actual.format & 0x1000) ? 1 : 0), /* bigendian? */ + ((sample->actual.format & 0xFF) / 8), /* bytes per sample point */ + ((sample->actual.format & 0x8000) ? 1 : 0), /* signed data? */ + &bitstream); + /* Make sure rc > 0 because we don't accidently want + * to change the counters if there was an error + */ + if(rc > 0) + { + total_bytes_read += rc; + bytes_remaining = bytes_remaining - rc; + } + } + /* I think the minimum read size is 2, though I'm + * not sure about this. (I've hit cases where I + * couldn't read less than 4.) What I don't want to do is + * accidently claim we hit EOF when the reason rc == 0 + * is because the requested amount of data was smaller + * than the minimum packet size. + * For now, I will be conservative + * and not set the EOF flag, and let the next call to + * this function figure it out. + * I think the ERROR flag is safe to set because + * it looks like OGG simply returns 0 if the + * read size is too small. + * And in most cases for sensible buffer sizes, + * this fix will fill the buffer, + * so we can set the EAGAIN flag without worrying + * that it will always be set. + */ + if(rc < 0) + { + sample->flags |= SOUND_SAMPLEFLAG_ERROR; + } + else if(rc == 0) + { + /* Do nothing for now until there is a better solution */ + /* sample->flags |= SOUND_SAMPLEFLAG_EOF; */ + } + + /* Test for a buffer underrun. It should occur less frequently + * now, but it still may happen and not necessarily mean + * anything useful. */ + if ((Uint32) total_bytes_read < internal->buffer_size) + { + sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; + } + /* change rc to the total bytes read so function + * can return the correct value. + */ + rc = total_bytes_read; + } return((Uint32) rc); } /* OGG_read */