# HG changeset patch # User Ryan C. Gordon # Date 1006749175 0 # Node ID d8904267d23c2ab2f930ad2b4315f646b5fada23 # Parent 9b26ed9eaf04c69d42cc3be174069e4ce1a309e5 Cleanups, fixes and enhancements by Torbj�rn Andersson. diff -r 9b26ed9eaf04 -r d8904267d23c decoders/flac.c --- a/decoders/flac.c Mon Nov 19 16:44:10 2001 +0000 +++ b/decoders/flac.c Mon Nov 26 04:32:55 2001 +0000 @@ -79,10 +79,18 @@ SDL_RWops *rw; Sound_Sample *sample; Uint32 frame_size; - Uint8 metadata_found; + Uint8 is_flac; } flac_t; +static void free_flac(flac_t *f) +{ + FLAC__stream_decoder_finish(f->decoder); + FLAC__stream_decoder_delete(f->decoder); + free(f); +} /* free_flac */ + + static FLAC__StreamDecoderReadStatus FLAC_read_callback( const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned int *bytes, void *client_data) @@ -126,6 +134,7 @@ { flac_t *f = (flac_t *) client_data; Uint32 i, j; + Uint32 sample; Uint8 *dst; #if 0 @@ -140,19 +149,34 @@ dst = f->sample->buffer; - if (frame->header.bits_per_sample == 8) + /* If the sample is neither exactly 8-bit nor 16-bit, it will have to + * be converted. Unfortunately the buffer is read-only, so we either + * have to check for each sample, or make a copy of the buffer. I'm + * not sure which way is best, so I've arbitrarily picked the former. + */ + if (f->sample->actual.format == AUDIO_S8) { for (i = 0; i < frame->header.blocksize; i++) for (j = 0; j < frame->header.channels; j++) - *dst++ = buffer[j][i] & 0x000000ff; + { + sample = buffer[j][i]; + if (frame->header.bits_per_sample < 8) + sample <<= (8 - frame->header.bits_per_sample); + *dst++ = sample & 0x00ff; + } /* for */ } /* if */ else { for (i = 0; i < frame->header.blocksize; i++) for (j = 0; j < frame->header.channels; j++) { - *dst++ = (buffer[j][i] & 0x0000ff00) >> 8; - *dst++ = buffer[j][i] & 0x000000ff; + sample = buffer[j][i]; + if (frame->header.bits_per_sample < 16) + sample <<= (16 - frame->header.bits_per_sample); + else if (frame->header.bits_per_sample > 16) + sample >>= (frame->header.bits_per_sample - 16); + *dst++ = (sample & 0xff00) >> 8; + *dst++ = sample & 0x00ff; } /* for */ } /* else */ @@ -168,29 +192,21 @@ SNDDBG(("FLAC: Metadata callback.\n")); + /* There are several kinds of metadata, but STREAMINFO is the only + * one that always has to be there. + */ if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { SNDDBG(("FLAC: Metadata is streaminfo.\n")); - f->metadata_found = 1; + + f->is_flac = 1; f->sample->actual.channels = metadata->data.stream_info.channels; f->sample->actual.rate = metadata->data.stream_info.sample_rate; - /* !!! FIXME: I believe bits_per_sample may be anywhere between - * 4 and 24. We can only handle 8 and 16 at present. - */ - switch (metadata->data.stream_info.bits_per_sample) - { - case 8: - f->sample->actual.format = AUDIO_S8; - break; - case 16: - f->sample->actual.format = AUDIO_S16MSB; - break; - default: - Sound_SetError("FLAC: Unsupported sample width."); - f->sample->actual.format = 0; - break; - } /* switch */ + if (metadata->data.stream_info.bits_per_sample > 8) + f->sample->actual.format = AUDIO_S16MSB; + else + f->sample->actual.format = AUDIO_S8; } /* if */ } /* FLAC_metadata_callback */ @@ -201,6 +217,7 @@ { flac_t *f = (flac_t *) client_data; + /* !!! FIXME: Is every error really fatal? I don't know... */ Sound_SetError(FLAC__StreamDecoderErrorStatusString[status]); f->sample->flags |= SOUND_SAMPLEFLAG_ERROR; } /* FLAC_error_callback */ @@ -224,6 +241,7 @@ SDL_RWops *rw = internal->rw; FLAC__StreamDecoder *decoder; flac_t *f; + int i; f = (flac_t *) malloc(sizeof (flac_t)); BAIL_IF_MACRO(f == NULL, ERR_OUT_OF_MEMORY, 0); @@ -245,22 +263,47 @@ f->rw = internal->rw; f->sample = sample; f->decoder = decoder; - - FLAC__stream_decoder_init(decoder); - internal->decoder_private = f; - - f->metadata_found = 0; f->sample->actual.format = 0; - FLAC__stream_decoder_process_metadata(decoder); + f->is_flac = 0; - if (f->sample->actual.format == 0) +#if 0 + /* !!! FIXME: + * + * It should be possible to play a FLAC stream starting at any frame, + * but we can only do that if we know for sure that it is a FLAC + * stream. Otherwise we have to check for metadata, and then we need + * the entire stream, from the beginning. + * + * But getting this to work right seems to be an enormous pain in the + * butt for what is, at the moment, a very small gain. Maybe later. + */ + for (i = 0; extensions_flac[i] != NULL; i++) + if (__Sound_strcasecmp(ext, extensions_flac[i]) == 0) + { + f->is_flac = 1; + break; + } /* if */ +#endif + + internal->decoder_private = f; + FLAC__stream_decoder_init(decoder); + + /* If we are not sure this is a FLAC stream, check for the STREAMINFO + * metadata block. If not, we'd have to peek at the first audio frame + * and get the sound format from there but, as stated above, that is + * not yet implemented. + */ + if (!f->is_flac) { - if (f->metadata_found == 0) - Sound_SetError("FLAC: No metadata found."); - FLAC__stream_decoder_finish(decoder); - FLAC__stream_decoder_delete(decoder); - free(f); - return(0); + FLAC__stream_decoder_process_metadata(decoder); + + /* Still not FLAC? Give up. */ + if (!f->is_flac) + { + Sound_SetError("FLAC: No metadata found. Not a FLAC stream?"); + free_flac(f); + return(0); + } /* if */ } /* if */ SNDDBG(("FLAC: Accepting data stream.\n")); @@ -275,9 +318,7 @@ Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; flac_t *f = (flac_t *) internal->decoder_private; - FLAC__stream_decoder_finish(f->decoder); - FLAC__stream_decoder_delete(f->decoder); - free(f); + free_flac(f); } /* FLAC_close */