/* OggEnc ** ** This program is distributed under the GNU General Public License, version 2. ** A copy of this license is included with this source. ** ** Copyright 2002, Stan Seibert ** **/ #include #include #include #include #include #include #include "audio.h" #include "flac.h" #include "i18n.h" #include "platform.h" #include "resample.h" #define DEFAULT_FLAC_FRAME_SIZE 4608 FLAC__StreamDecoderReadStatus easyflac_read_callback(const EasyFLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data); FLAC__StreamDecoderWriteStatus easyflac_write_callback(const EasyFLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); void easyflac_metadata_callback(const EasyFLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); void easyflac_error_callback(const EasyFLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); void resize_buffer(flacfile *flac, int newchannels, int newsamples); void copy_comments (vorbis_comment *v_comments, FLAC__StreamMetadata_VorbisComment *f_comments); int flac_id(unsigned char *buf, int len) { if (len < 4) return 0; return memcmp(buf, "fLaC", 4) == 0; } int oggflac_id(unsigned char *buf, int len) { if (len < 32) return 0; return memcmp(buf, "OggS", 4) == 0 && flac_id(buf+28, len - 28); } int flac_open(FILE *in, oe_enc_opt *opt, unsigned char *oldbuf, int buflen) { flacfile *flac = malloc(sizeof(flacfile)); flac->decoder = NULL; flac->channels = 0; flac->rate = 0; flac->totalsamples = 0; flac->comments = NULL; flac->in = NULL; flac->eos = 0; /* Setup empty audio buffer that will be resized on first frame callback */ flac->buf = NULL; flac->buf_len = 0; flac->buf_start = 0; flac->buf_fill = 0; /* Copy old input data over */ flac->oldbuf = malloc(buflen); flac->oldbuf_len = buflen; memcpy(flac->oldbuf, oldbuf, buflen); flac->oldbuf_start = 0; /* Need to save FILE pointer for read callback */ flac->in = in; /* Setup FLAC decoder */ flac->decoder = EasyFLAC__stream_decoder_new(oggflac_id(oldbuf, buflen)); EasyFLAC__set_client_data(flac->decoder, flac); EasyFLAC__set_read_callback(flac->decoder, &easyflac_read_callback); EasyFLAC__set_write_callback(flac->decoder, &easyflac_write_callback); EasyFLAC__set_metadata_callback(flac->decoder, &easyflac_metadata_callback); EasyFLAC__set_error_callback(flac->decoder, &easyflac_error_callback); EasyFLAC__set_metadata_respond(flac->decoder, FLAC__METADATA_TYPE_STREAMINFO); EasyFLAC__set_metadata_respond(flac->decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); EasyFLAC__init(flac->decoder); /* Callback will set the total samples and sample rate */ EasyFLAC__process_until_end_of_metadata(flac->decoder); /* Callback will set the number of channels and resize the audio buffer */ EasyFLAC__process_single(flac->decoder); /* Copy format info for caller */ opt->rate = flac->rate; opt->channels = flac->channels; /* flac->total_samples_per_channel was already set by metadata callback when metadata was processed. */ opt->total_samples_per_channel = flac->totalsamples; /* Copy Vorbis-style comments from FLAC file (read in metadata callback)*/ if (flac->comments != NULL && opt->copy_comments) copy_comments(opt->comments, &flac->comments->data.vorbis_comment); opt->read_samples = flac_read; opt->readdata = (void *)flac; return 1; } long flac_read(void *in, float **buffer, int samples) { flacfile *flac = (flacfile *)in; long realsamples = 0; FLAC__bool ret; int i,j; while (realsamples < samples) { if (flac->buf_fill > 0) { int copy = flac->buf_fill < (samples - realsamples) ? flac->buf_fill : (samples - realsamples); for (i = 0; i < flac->channels; i++) for (j = 0; j < copy; j++) buffer[i][j+realsamples] = flac->buf[i][j+flac->buf_start]; flac->buf_start += copy; flac->buf_fill -= copy; realsamples += copy; } else if (!flac->eos) { ret = EasyFLAC__process_single(flac->decoder); if (!ret || EasyFLAC__get_state(flac->decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) flac->eos = 1; /* Bail out! */ } else break; } return realsamples; } void flac_close(void *info) { int i; flacfile *flac = (flacfile *) info; for (i = 0; i < flac->channels; i++) free(flac->buf[i]); free(flac->buf); free(flac->oldbuf); free(flac->comments); EasyFLAC__finish(flac->decoder); EasyFLAC__stream_decoder_delete(flac->decoder); free(flac); } FLAC__StreamDecoderReadStatus easyflac_read_callback(const EasyFLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) { flacfile *flac = (flacfile *) client_data; int i = 0; int oldbuf_fill = flac->oldbuf_len - flac->oldbuf_start; /* Immediately return if errors occured */ if(feof(flac->in)) { *bytes = 0; return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; } else if(ferror(flac->in)) { *bytes = 0; return FLAC__STREAM_DECODER_READ_STATUS_ABORT; } if(oldbuf_fill > 0) { int copy; copy = oldbuf_fill < (*bytes - i) ? oldbuf_fill : (*bytes - i); memcpy(buffer + i, flac->oldbuf, copy); i += copy; flac->oldbuf_start += copy; } if(i < *bytes) i += fread(buffer+i, sizeof(FLAC__byte), *bytes - i, flac->in); *bytes = i; return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } FLAC__StreamDecoderWriteStatus easyflac_write_callback(const EasyFLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) { flacfile *flac = (flacfile *) client_data; int samples = frame->header.blocksize; int channels = frame->header.channels; int bits_per_sample = frame->header.bits_per_sample; int i, j; resize_buffer(flac, channels, samples); for (i = 0; i < channels; i++) for (j = 0; j < samples; j++) flac->buf[i][j] = buffer[i][j] / (float) (1 << (bits_per_sample - 1)); flac->buf_start = 0; flac->buf_fill = samples; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } void easyflac_metadata_callback(const EasyFLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { flacfile *flac = (flacfile *) client_data; switch (metadata->type) { case FLAC__METADATA_TYPE_STREAMINFO: flac->totalsamples = metadata->data.stream_info.total_samples; flac->rate = metadata->data.stream_info.sample_rate; break; case FLAC__METADATA_TYPE_VORBIS_COMMENT: flac->comments = FLAC__metadata_object_clone(metadata); break; default: break; } } void easyflac_error_callback(const EasyFLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) { flacfile *flac = (flacfile *) client_data; } void resize_buffer(flacfile *flac, int newchannels, int newsamples) { int i; if (newchannels == flac->channels && newsamples == flac->buf_len) { flac->buf_start = 0; flac->buf_fill = 0; return; } /* Not the most efficient approach, but it is easy to follow */ if(newchannels != flac->channels) { /* Deallocate all of the sample vectors */ for (i = 0; i < flac->channels; i++) free(flac->buf[i]); flac->buf = realloc(flac->buf, sizeof(float*) * newchannels); flac->channels = newchannels; } for (i = 0; i < newchannels; i++) flac->buf[i] = malloc(sizeof(float) * newsamples); flac->buf_len = newsamples; flac->buf_start = 0; flac->buf_fill = 0; } void copy_comments (vorbis_comment *v_comments, FLAC__StreamMetadata_VorbisComment *f_comments) { int i; for (i = 0; i < f_comments->num_comments; i++) { char *comment = malloc(f_comments->comments[i].length + 1); memset(comment, '\0', f_comments->comments[i].length + 1); strncpy((char *)comment, (char *)f_comments->comments[i].entry, f_comments->comments[i].length); vorbis_comment_add(v_comments, comment); free(comment); } }