Files
flac/src/libFLAC/file_decoder.c

489 lines
18 KiB
C
Raw Normal View History

2001-02-08 00:38:41 +00:00
/* libFLAC - Free Lossless Audio Codec library
2001-01-16 20:17:53 +00:00
* Copyright (C) 2000,2001 Josh Coalson
2000-12-10 04:09:52 +00:00
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h> /* for malloc() */
#include <string.h> /* for strcmp() */
#include <sys/stat.h> /* for stat() */
2000-12-10 04:09:52 +00:00
#include "FLAC/file_decoder.h"
#include "protected/stream_decoder.h"
2001-01-12 23:55:11 +00:00
#include "private/md5.h"
2000-12-10 04:09:52 +00:00
typedef struct FLAC__FileDecoderPrivate {
FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const int32 *buffer[], void *client_data);
2000-12-10 04:09:52 +00:00
void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
void (*error_callback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
void *client_data;
FILE *file;
char *filename; /* == NULL if stdin */
2000-12-10 04:09:52 +00:00
FLAC__StreamDecoder *stream;
2001-01-12 23:55:11 +00:00
struct MD5Context md5context;
byte stored_md5sum[16]; /* this is what is stored in the metadata */
byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */
2000-12-10 04:09:52 +00:00
/* the rest of these are only used for seeking: */
2001-02-23 21:03:21 +00:00
FLAC__StreamMetaData_StreamInfo stream_info; /* we keep this around so we can figure out how to seek quickly */
FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */
2000-12-10 04:09:52 +00:00
uint64 target_sample;
} FLAC__FileDecoderPrivate;
static FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data);
static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const int32 *buffer[], void *client_data);
2000-12-10 04:09:52 +00:00
static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
static bool seek_to_absolute_sample_(FLAC__FileDecoder *decoder, long filesize, uint64 target_sample);
2000-12-22 22:35:33 +00:00
const char *FLAC__FileDecoderStateString[] = {
"FLAC__FILE_DECODER_OK",
"FLAC__FILE_DECODER_SEEKING",
"FLAC__FILE_DECODER_END_OF_FILE",
"FLAC__FILE_DECODER_ERROR_OPENING_FILE",
"FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR",
"FLAC__FILE_DECODER_SEEK_ERROR",
"FLAC__FILE_DECODER_STREAM_ERROR",
"FLAC__FILE_DECODER_UNINITIALIZED"
};
2000-12-10 04:09:52 +00:00
FLAC__FileDecoder *FLAC__file_decoder_get_new_instance()
{
FLAC__FileDecoder *decoder = (FLAC__FileDecoder*)malloc(sizeof(FLAC__FileDecoder));
if(decoder != 0) {
decoder->state = FLAC__FILE_DECODER_UNINITIALIZED;
decoder->guts = 0;
}
return decoder;
}
void FLAC__file_decoder_free_instance(FLAC__FileDecoder *decoder)
{
free(decoder);
}
FLAC__FileDecoderState FLAC__file_decoder_init(
FLAC__FileDecoder *decoder,
const char *filename,
FLAC__StreamDecoderWriteStatus (*write_callback)(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const int32 *buffer[], void *client_data),
2000-12-10 04:09:52 +00:00
void (*metadata_callback)(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data),
void (*error_callback)(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data),
void *client_data
)
{
assert(sizeof(int) >= 4); /* we want to die right away if this is not true */
assert(decoder != 0);
assert(write_callback != 0);
assert(metadata_callback != 0);
assert(error_callback != 0);
assert(decoder->state == FLAC__FILE_DECODER_UNINITIALIZED);
assert(decoder->guts == 0);
decoder->state = FLAC__FILE_DECODER_OK;
decoder->guts = (FLAC__FileDecoderPrivate*)malloc(sizeof(FLAC__FileDecoderPrivate));
if(decoder->guts == 0)
return decoder->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR;
decoder->guts->write_callback = write_callback;
decoder->guts->metadata_callback = metadata_callback;
decoder->guts->error_callback = error_callback;
decoder->guts->client_data = client_data;
decoder->guts->stream = 0;
decoder->guts->file = 0;
decoder->guts->filename = 0;
2000-12-10 04:09:52 +00:00
if(0 == strcmp(filename, "-")) {
2000-12-10 04:09:52 +00:00
decoder->guts->file = stdin;
}
else {
if(0 == (decoder->guts->filename = (char*)malloc(strlen(filename)+1)))
return decoder->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR;
strcpy(decoder->guts->filename, filename);
2000-12-10 04:09:52 +00:00
decoder->guts->file = fopen(filename, "rb");
}
2000-12-10 04:09:52 +00:00
if(decoder->guts->file == 0)
return decoder->state = FLAC__FILE_DECODER_ERROR_OPENING_FILE;
2001-01-12 23:55:11 +00:00
/* We initialize the MD5Context even though we may never use it. This is
* because check_md5 may be turned on to start and then turned off if a
* seek occurs. So we always init the context here and finalize it in
* FLAC__file_decoder_finish() to make sure things are always cleaned up
* properly.
2001-01-12 23:55:11 +00:00
*/
MD5Init(&decoder->guts->md5context);
2000-12-10 04:09:52 +00:00
decoder->guts->stream = FLAC__stream_decoder_get_new_instance();
if(FLAC__stream_decoder_init(decoder->guts->stream, read_callback_, write_callback_, metadata_callback_, error_callback_, decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
return decoder->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR; /* this is based on internal knowledge of FLAC__stream_decoder_init() */
return decoder->state;
}
2001-01-12 23:55:11 +00:00
bool FLAC__file_decoder_finish(FLAC__FileDecoder *decoder)
2000-12-10 04:09:52 +00:00
{
2001-01-12 23:55:11 +00:00
bool md5_failed = false;
2000-12-10 04:09:52 +00:00
assert(decoder != 0);
if(decoder->state == FLAC__FILE_DECODER_UNINITIALIZED)
2001-01-12 23:55:11 +00:00
return true;
2000-12-10 04:09:52 +00:00
if(decoder->guts != 0) {
if(decoder->guts->file != 0 && decoder->guts->file != stdin)
fclose(decoder->guts->file);
if(0 != decoder->guts->filename)
free(decoder->guts->filename);
2001-01-12 23:55:11 +00:00
/* see the comment in FLAC__file_decoder_init() as to why we always
* call MD5Final()
*/
MD5Final(decoder->guts->computed_md5sum, &decoder->guts->md5context);
2000-12-10 04:09:52 +00:00
if(decoder->guts->stream != 0) {
FLAC__stream_decoder_finish(decoder->guts->stream);
FLAC__stream_decoder_free_instance(decoder->guts->stream);
}
2001-01-12 23:55:11 +00:00
if(decoder->check_md5) {
if(memcmp(decoder->guts->stored_md5sum, decoder->guts->computed_md5sum, 16))
md5_failed = true;
}
2000-12-10 04:09:52 +00:00
free(decoder->guts);
decoder->guts = 0;
}
decoder->state = FLAC__FILE_DECODER_UNINITIALIZED;
2001-01-12 23:55:11 +00:00
return !md5_failed;
2000-12-10 04:09:52 +00:00
}
bool FLAC__file_decoder_process_whole_file(FLAC__FileDecoder *decoder)
{
bool ret;
assert(decoder != 0);
2001-03-20 22:56:43 +00:00
if(decoder->guts->stream->state == FLAC__STREAM_DECODER_END_OF_STREAM)
decoder->state = FLAC__FILE_DECODER_END_OF_FILE;
2000-12-10 04:09:52 +00:00
if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE)
return true;
assert(decoder->state == FLAC__FILE_DECODER_OK);
ret = FLAC__stream_decoder_process_whole_stream(decoder->guts->stream);
if(!ret)
decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
return ret;
}
bool FLAC__file_decoder_process_metadata(FLAC__FileDecoder *decoder)
{
bool ret;
assert(decoder != 0);
2001-03-20 22:56:43 +00:00
if(decoder->guts->stream->state == FLAC__STREAM_DECODER_END_OF_STREAM)
decoder->state = FLAC__FILE_DECODER_END_OF_FILE;
2000-12-10 04:09:52 +00:00
if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE)
return true;
assert(decoder->state == FLAC__FILE_DECODER_OK);
ret = FLAC__stream_decoder_process_metadata(decoder->guts->stream);
if(!ret)
decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
return ret;
}
bool FLAC__file_decoder_process_one_frame(FLAC__FileDecoder *decoder)
{
bool ret;
assert(decoder != 0);
2001-03-20 22:56:43 +00:00
if(decoder->guts->stream->state == FLAC__STREAM_DECODER_END_OF_STREAM)
decoder->state = FLAC__FILE_DECODER_END_OF_FILE;
2000-12-10 04:09:52 +00:00
if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE)
return true;
assert(decoder->state == FLAC__FILE_DECODER_OK);
ret = FLAC__stream_decoder_process_one_frame(decoder->guts->stream);
if(!ret)
decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
return ret;
}
bool FLAC__file_decoder_process_remaining_frames(FLAC__FileDecoder *decoder)
{
bool ret;
assert(decoder != 0);
2001-03-20 22:56:43 +00:00
if(decoder->guts->stream->state == FLAC__STREAM_DECODER_END_OF_STREAM)
decoder->state = FLAC__FILE_DECODER_END_OF_FILE;
2000-12-10 04:09:52 +00:00
if(decoder->state == FLAC__FILE_DECODER_END_OF_FILE)
return true;
assert(decoder->state == FLAC__FILE_DECODER_OK);
ret = FLAC__stream_decoder_process_remaining_frames(decoder->guts->stream);
if(!ret)
decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
return ret;
}
bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, uint64 sample)
{
long filesize;
struct stat filestats;
2000-12-10 04:09:52 +00:00
assert(decoder != 0);
assert(decoder->state == FLAC__FILE_DECODER_OK);
if(decoder->guts->filename == 0) { /* means the file is stdin... */
decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
return false;
}
2000-12-10 04:09:52 +00:00
decoder->state = FLAC__FILE_DECODER_SEEKING;
2001-01-12 23:55:11 +00:00
/* turn off md5 checking if a seek is attempted */
decoder->check_md5 = false;
2000-12-10 04:09:52 +00:00
if(!FLAC__stream_decoder_reset(decoder->guts->stream)) {
decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
return false;
}
/* get the file length */
if(stat(decoder->guts->filename, &filestats) != 0) {
2000-12-10 04:09:52 +00:00
decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
return false;
}
filesize = filestats.st_size;
2000-12-10 04:09:52 +00:00
/* rewind */
if(0 != fseek(decoder->guts->file, 0, SEEK_SET)) {
decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
return false;
}
if(!FLAC__stream_decoder_process_metadata(decoder->guts->stream)) {
decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
return false;
}
2001-02-23 21:03:21 +00:00
if(sample > decoder->guts->stream_info.total_samples) {
2000-12-10 04:09:52 +00:00
decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
return false;
}
return seek_to_absolute_sample_(decoder, filesize, sample);
}
FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, byte buffer[], unsigned *bytes, void *client_data)
{
FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
(void)decoder;
if(feof(file_decoder->guts->file)) {
file_decoder->state = FLAC__FILE_DECODER_END_OF_FILE;
return FLAC__STREAM_DECODER_READ_END_OF_STREAM;
}
else if(*bytes > 0) {
size_t bytes_read = fread(buffer, sizeof(byte), *bytes, file_decoder->guts->file);
if(bytes_read == 0) {
if(feof(file_decoder->guts->file)) {
file_decoder->state = FLAC__FILE_DECODER_END_OF_FILE;
return FLAC__STREAM_DECODER_READ_END_OF_STREAM;
}
else
return FLAC__STREAM_DECODER_READ_ABORT;
}
else {
*bytes = (unsigned)bytes_read;
return FLAC__STREAM_DECODER_READ_CONTINUE;
}
}
else
return FLAC__STREAM_DECODER_READ_ABORT; /* abort to avoid a deadlock */
}
FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const int32 *buffer[], void *client_data)
2000-12-10 04:09:52 +00:00
{
FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
(void)decoder;
if(file_decoder->state == FLAC__FILE_DECODER_SEEKING) {
uint64 this_frame_sample = frame->header.number.sample_number;
uint64 next_frame_sample = this_frame_sample + (uint64)frame->header.blocksize;
2000-12-10 04:09:52 +00:00
uint64 target_sample = file_decoder->guts->target_sample;
file_decoder->guts->last_frame = *frame; /* save the frame in the guts */
2000-12-10 04:09:52 +00:00
if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */
unsigned delta = (unsigned)(target_sample - this_frame_sample);
/* kick out of seek mode */
file_decoder->state = FLAC__FILE_DECODER_OK;
/* shift out the samples before target_sample */
if(delta > 0) {
unsigned channel;
const int32 *newbuffer[FLAC__MAX_CHANNELS];
for(channel = 0; channel < frame->header.channels; channel++)
2000-12-10 04:09:52 +00:00
newbuffer[channel] = buffer[channel] + delta;
file_decoder->guts->last_frame.header.blocksize -= delta;
file_decoder->guts->last_frame.header.number.sample_number += (uint64)delta;
2000-12-10 04:09:52 +00:00
/* write the relevant samples */
return file_decoder->guts->write_callback(file_decoder, &file_decoder->guts->last_frame, newbuffer, file_decoder->guts->client_data);
2000-12-10 04:09:52 +00:00
}
else {
/* write the relevant samples */
return file_decoder->guts->write_callback(file_decoder, frame, buffer, file_decoder->guts->client_data);
2000-12-10 04:09:52 +00:00
}
}
else {
return FLAC__STREAM_DECODER_WRITE_CONTINUE;
}
}
else {
2001-01-12 23:55:11 +00:00
if(file_decoder->check_md5) {
if(!FLAC__MD5Accumulate(&file_decoder->guts->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8))
2001-01-12 23:55:11 +00:00
return FLAC__STREAM_DECODER_WRITE_ABORT;
}
return file_decoder->guts->write_callback(file_decoder, frame, buffer, file_decoder->guts->client_data);
2000-12-10 04:09:52 +00:00
}
}
void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
{
FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
(void)decoder;
2001-02-23 21:03:21 +00:00
if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
file_decoder->guts->stream_info = metadata->data.stream_info;
2001-01-12 23:55:11 +00:00
/* save the MD5 signature for comparison later */
2001-02-23 21:03:21 +00:00
memcpy(file_decoder->guts->stored_md5sum, metadata->data.stream_info.md5sum, 16);
2001-01-12 23:55:11 +00:00
if(0 == memcmp(file_decoder->guts->stored_md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
file_decoder->check_md5 = false;
}
2000-12-10 04:09:52 +00:00
if(file_decoder->state != FLAC__FILE_DECODER_SEEKING)
file_decoder->guts->metadata_callback(file_decoder, metadata, file_decoder->guts->client_data);
}
void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
{
FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data;
(void)decoder;
if(file_decoder->state != FLAC__FILE_DECODER_SEEKING)
file_decoder->guts->error_callback(file_decoder, status, file_decoder->guts->client_data);
}
bool seek_to_absolute_sample_(FLAC__FileDecoder *decoder, long filesize, uint64 target_sample)
{
long l, r, pos, last_pos = -1;
unsigned approx_bytes_per_frame;
uint64 last_frame_sample = 0xffffffffffffffff;
bool needs_seek;
2001-02-23 21:03:21 +00:00
const bool is_variable_blocksize_stream = (decoder->guts->stream_info.min_blocksize != decoder->guts->stream_info.max_blocksize);
2000-12-10 04:09:52 +00:00
/* we are just guessing here, but we want to guess high, not low */
if(decoder->guts->stream_info.max_framesize > 0) {
approx_bytes_per_frame = decoder->guts->stream_info.max_framesize + 64;
}
else if(!is_variable_blocksize_stream) {
2001-02-23 21:03:21 +00:00
/* note there are no () around 'decoder->guts->stream_info.bits_per_sample/8' to keep precision up since it's an integer calulation */
approx_bytes_per_frame = decoder->guts->stream_info.min_blocksize * decoder->guts->stream_info.channels * decoder->guts->stream_info.bits_per_sample/8 + 64;
2000-12-10 04:09:52 +00:00
}
else
2001-02-23 21:03:21 +00:00
approx_bytes_per_frame = 1152 * decoder->guts->stream_info.channels * decoder->guts->stream_info.bits_per_sample/8 + 64;
2000-12-10 04:09:52 +00:00
/* The file pointer is currently at the first frame plus any read
ahead data, so first we get the file pointer, then subtract
uncomsumed bytes to get the position (l) of the first frame
in the file */
2000-12-10 04:09:52 +00:00
if(-1 == (l = ftell(decoder->guts->file))) {
decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
return false;
}
l -= FLAC__stream_decoder_input_bytes_unconsumed(decoder->guts->stream) + 1;
if(l < 0)
l = 0;
/* Now we need to use the metadata and the filelength to search to the frame with the correct sample */
2000-12-10 04:09:52 +00:00
#ifdef _MSC_VER
/* with VC++ you have to spoon feed it the casting */
2001-02-23 21:03:21 +00:00
pos = l + (long)((double)(int64)target_sample / (double)(int64)decoder->guts->stream_info.total_samples * (double)(filesize-l+1)) - approx_bytes_per_frame;
2000-12-10 04:09:52 +00:00
#else
2001-02-23 21:03:21 +00:00
pos = l + (long)((double)target_sample / (double)decoder->guts->stream_info.total_samples * (double)(filesize-l+1)) - approx_bytes_per_frame;
2000-12-10 04:09:52 +00:00
#endif
if(decoder->guts->stream_info.max_framesize > 0)
r = filesize - decoder->guts->stream_info.max_framesize - 2;
else
r = filesize - ((decoder->guts->stream_info.channels * decoder->guts->stream_info.bits_per_sample * FLAC__MAX_BLOCK_SIZE) / 8 + 64);
2000-12-10 04:09:52 +00:00
if(pos >= r)
pos = r-1;
if(pos < l)
pos = l;
needs_seek = true;
decoder->guts->target_sample = target_sample;
while(1) {
if(needs_seek) {
if(-1 == fseek(decoder->guts->file, pos, SEEK_SET)) {
decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
return false;
}
if(!FLAC__stream_decoder_flush(decoder->guts->stream)) {
decoder->state = FLAC__FILE_DECODER_STREAM_ERROR;
return false;
}
}
if(!FLAC__stream_decoder_process_one_frame(decoder->guts->stream)) {
decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
return false;
}
/* our write callback will change the state when it gets to the target frame */
if(decoder->state != FLAC__FILE_DECODER_SEEKING) {
break;
}
else { /* we need to narrow the search */
uint64 this_frame_sample = decoder->guts->last_frame.header.number.sample_number;
2000-12-10 04:09:52 +00:00
if(this_frame_sample == last_frame_sample) {
/* our last move backwards wasn't big enough */
pos -= (last_pos - pos);
needs_seek = true;
}
else {
if(target_sample < this_frame_sample) {
last_pos = pos;
approx_bytes_per_frame = decoder->guts->last_frame.header.blocksize * decoder->guts->last_frame.header.channels * decoder->guts->last_frame.header.bits_per_sample/8 + 64;
2000-12-10 04:09:52 +00:00
pos -= approx_bytes_per_frame;
needs_seek = true;
}
else {
last_pos = pos;
if(-1 == (pos = ftell(decoder->guts->file))) {
decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
return false;
}
pos -= FLAC__stream_decoder_input_bytes_unconsumed(decoder->guts->stream);
needs_seek = false;
}
}
if(pos < l)
pos = l;
last_frame_sample = this_frame_sample;
}
}
return true;
}