From 48d852cb08d1e118937f9796518f27698693223a Mon Sep 17 00:00:00 2001 From: Josh Coalson Date: Tue, 6 Aug 2002 05:31:17 +0000 Subject: [PATCH] initial import, still more work to be done... --- src/libOggFLAC/Makefile.am | 42 + src/libOggFLAC/Makefile.lite | 44 + src/libOggFLAC/Makefile.vc | 44 + src/libOggFLAC/file_decoder.c | 631 +++++++++++ src/libOggFLAC/include/Makefile.am | 19 + src/libOggFLAC/include/protected/Makefile.am | 24 + src/libOggFLAC/include/protected/all.h | 28 + .../include/protected/file_decoder.h | 29 + .../protected/seekable_stream_decoder.h | 29 + .../include/protected/stream_decoder.h | 29 + .../include/protected/stream_encoder.h | 29 + src/libOggFLAC/libOggFLAC.m4 | 104 ++ src/libOggFLAC/seekable_stream_decoder.c | 990 ++++++++++++++++++ src/libOggFLAC/stream_decoder.c | 597 +++++++++++ src/libOggFLAC/stream_encoder.c | 641 ++++++++++++ 15 files changed, 3280 insertions(+) create mode 100644 src/libOggFLAC/Makefile.am create mode 100644 src/libOggFLAC/Makefile.lite create mode 100644 src/libOggFLAC/Makefile.vc create mode 100644 src/libOggFLAC/file_decoder.c create mode 100644 src/libOggFLAC/include/Makefile.am create mode 100644 src/libOggFLAC/include/protected/Makefile.am create mode 100644 src/libOggFLAC/include/protected/all.h create mode 100644 src/libOggFLAC/include/protected/file_decoder.h create mode 100644 src/libOggFLAC/include/protected/seekable_stream_decoder.h create mode 100644 src/libOggFLAC/include/protected/stream_decoder.h create mode 100644 src/libOggFLAC/include/protected/stream_encoder.h create mode 100644 src/libOggFLAC/libOggFLAC.m4 create mode 100644 src/libOggFLAC/seekable_stream_decoder.c create mode 100644 src/libOggFLAC/stream_decoder.c create mode 100644 src/libOggFLAC/stream_encoder.c diff --git a/src/libOggFLAC/Makefile.am b/src/libOggFLAC/Makefile.am new file mode 100644 index 00000000..5ae939e5 --- /dev/null +++ b/src/libOggFLAC/Makefile.am @@ -0,0 +1,42 @@ +# libOggFLAC - Free Lossless Audio Codec + Ogg library +# Copyright (C) 2002 Josh Coalson +# +# 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. + +lib_LTLIBRARIES = libOggFLAC.la +if DEBUG +DEBUGCFLAGS = +endif +CFLAGS = @CFLAGS@ $(DEBUGCFLAGS) + +SUBDIRS = $(ARCH_SUBDIRS) include . + +m4datadir = $(datadir)/aclocal +m4data_DATA = libOggFLAC.m4 + +EXTRA_DIST = \ + Makefile.lite \ + Makefile.vc \ + libOggFLAC.m4 + +# see 'http://www.gnu.org/software/libtool/manual.html#Versioning' for numbering convention +libOggFLAC_la_LDFLAGS = -version-info 0:0:0 + +libOggFLAC_la_SOURCES = \ + file_decoder.c \ + seekable_stream_decoder.c \ + stream_decoder.c \ + stream_encoder.c diff --git a/src/libOggFLAC/Makefile.lite b/src/libOggFLAC/Makefile.lite new file mode 100644 index 00000000..22d09f00 --- /dev/null +++ b/src/libOggFLAC/Makefile.lite @@ -0,0 +1,44 @@ +# libOggFLAC - Free Lossless Audio Codec + Ogg library +# Copyright (C) 2002 Josh Coalson +# +# 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. + +# +# GNU makefile +# + +LIB_NAME = libOggFLAC +ifeq ($(DARWIN_BUILD),yes) +DEFINES = +else +ifeq ($(SOLARIS_BUILD),yes) +DEFINES = +else +DEFINES = +endif +endif +INCLUDES = -I./include -I../../include +DEBUG_CFLAGS = + +OBJS = \ + file_decoder.o \ + seekable_stream_decoder.o \ + stream_decoder.o \ + stream_encoder.o + +include ../../build/lib.mk + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/src/libOggFLAC/Makefile.vc b/src/libOggFLAC/Makefile.vc new file mode 100644 index 00000000..d6c92a97 --- /dev/null +++ b/src/libOggFLAC/Makefile.vc @@ -0,0 +1,44 @@ +# libOggFLAC - Free Lossless Audio Codec + Ogg library +# Copyright (C) 2002 Josh Coalson +# +# 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 + +!IFDEF DEBUG +.c.obj: + $(cc) /D "_LIB" /GX $(cdebug) $(cflags) /I ".\include" /I "..\..\include" -DSTRICT -YX /Od /D "_DEBUG" $< +!else +.c.obj: + $(cc) /D "_LIB" /O2 $(crelease) $(cflags) /I ".\include" /I "..\..\include" -DSTRICT -YX -DNODEBUG $< +!endif + +C_FILES= \ + file_decoder.c \ + seekable_stream_decoder.c \ + stream_decoder.c \ + stream_encoder.c + +OBJS= $(C_FILES:.c=.obj) + +all: libOggFLAC.lib + +libOggFLAC.lib: $(OBJS) + link.exe -lib /nodefaultlib -out:../../obj/lib/$*.lib $(OBJS) + +clean: + -del *.obj ia32\*.obj *.pch + -del ..\..\obj\lib\libOggFLAC.lib ..\..\obj\lib\libOggFLAC.pdb diff --git a/src/libOggFLAC/file_decoder.c b/src/libOggFLAC/file_decoder.c new file mode 100644 index 00000000..0c5c71c1 --- /dev/null +++ b/src/libOggFLAC/file_decoder.c @@ -0,0 +1,631 @@ +/* libOggFLAC - Free Lossless Audio Codec + Ogg library + * Copyright (C) 2002 Josh Coalson + * + * 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 +#include /* for malloc() */ +#include /* for strcmp() */ +#include /* for stat() */ +#if defined _MSC_VER || defined __MINGW32__ +#include /* for _setmode() */ +#include /* for _O_BINARY */ +#elif defined __CYGWIN__ +#include /* for _setmode(), O_BINARY */ +#endif +#include "FLAC/assert.h" +#include "protected/file_decoder.h" +#include "protected/seekable_stream_decoder.h" +#include "private/md5.h" + +/*********************************************************************** + * + * Private class method prototypes + * + ***********************************************************************/ + +static void set_defaults_(FLAC__FileDecoder *decoder); +static FILE *get_binary_stdin_(); +static FLAC__SeekableStreamDecoderReadStatus read_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data); +static FLAC__SeekableStreamDecoderSeekStatus seek_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); +static FLAC__SeekableStreamDecoderTellStatus tell_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); +static FLAC__SeekableStreamDecoderLengthStatus length_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); +static FLAC__bool eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data); +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +static void metadata_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static void error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + +/*********************************************************************** + * + * Private class data + * + ***********************************************************************/ + +typedef struct FLAC__FileDecoderPrivate { + FLAC__FileDecoderWriteCallback write_callback; + FLAC__FileDecoderMetadataCallback metadata_callback; + FLAC__FileDecoderErrorCallback error_callback; + void *client_data; + FILE *file; + char *filename; /* == NULL if stdin */ + FLAC__SeekableStreamDecoder *seekable_stream_decoder; +} FLAC__FileDecoderPrivate; + +/*********************************************************************** + * + * Public static class data + * + ***********************************************************************/ + +const char * const FLAC__FileDecoderStateString[] = { + "FLAC__FILE_DECODER_OK", + "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_SEEKABLE_STREAM_DECODER_DECODER_ERROR", + "FLAC__FILE_DECODER_ALREADY_INITIALIZED", + "FLAC__FILE_DECODER_INVALID_CALLBACK", + "FLAC__FILE_DECODER_UNINITIALIZED" +}; + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +FLAC__FileDecoder *FLAC__file_decoder_new() +{ + FLAC__FileDecoder *decoder; + + FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ + + decoder = (FLAC__FileDecoder*)malloc(sizeof(FLAC__FileDecoder)); + if(decoder == 0) { + return 0; + } + memset(decoder, 0, sizeof(FLAC__FileDecoder)); + + decoder->protected_ = (FLAC__FileDecoderProtected*)malloc(sizeof(FLAC__FileDecoderProtected)); + if(decoder->protected_ == 0) { + free(decoder); + return 0; + } + memset(decoder->protected_, 0, sizeof(FLAC__FileDecoderProtected)); + + decoder->private_ = (FLAC__FileDecoderPrivate*)malloc(sizeof(FLAC__FileDecoderPrivate)); + if(decoder->private_ == 0) { + free(decoder->protected_); + free(decoder); + return 0; + } + memset(decoder->private_, 0, sizeof(FLAC__FileDecoderPrivate)); + + decoder->private_->seekable_stream_decoder = FLAC__seekable_stream_decoder_new(); + if(0 == decoder->private_->seekable_stream_decoder) { + free(decoder->private_); + free(decoder->protected_); + free(decoder); + return 0; + } + + decoder->private_->file = 0; + + set_defaults_(decoder); + + decoder->protected_->state = FLAC__FILE_DECODER_UNINITIALIZED; + + return decoder; +} + +void FLAC__file_decoder_delete(FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); + + (void)FLAC__file_decoder_finish(decoder); + + FLAC__seekable_stream_decoder_delete(decoder->private_->seekable_stream_decoder); + + free(decoder->private_); + free(decoder->protected_); + free(decoder); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__FileDecoderState FLAC__file_decoder_init(FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return decoder->protected_->state = FLAC__FILE_DECODER_ALREADY_INITIALIZED; + + if(0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback) + return decoder->protected_->state = FLAC__FILE_DECODER_INVALID_CALLBACK; + + if(0 == decoder->private_->filename) + decoder->private_->file = get_binary_stdin_(); + else + decoder->private_->file = fopen(decoder->private_->filename, "rb"); + + if(decoder->private_->file == 0) + return decoder->protected_->state = FLAC__FILE_DECODER_ERROR_OPENING_FILE; + + FLAC__seekable_stream_decoder_set_read_callback(decoder->private_->seekable_stream_decoder, read_callback_); + FLAC__seekable_stream_decoder_set_seek_callback(decoder->private_->seekable_stream_decoder, seek_callback_); + FLAC__seekable_stream_decoder_set_tell_callback(decoder->private_->seekable_stream_decoder, tell_callback_); + FLAC__seekable_stream_decoder_set_length_callback(decoder->private_->seekable_stream_decoder, length_callback_); + FLAC__seekable_stream_decoder_set_eof_callback(decoder->private_->seekable_stream_decoder, eof_callback_); + FLAC__seekable_stream_decoder_set_write_callback(decoder->private_->seekable_stream_decoder, write_callback_); + FLAC__seekable_stream_decoder_set_metadata_callback(decoder->private_->seekable_stream_decoder, metadata_callback_); + FLAC__seekable_stream_decoder_set_error_callback(decoder->private_->seekable_stream_decoder, error_callback_); + FLAC__seekable_stream_decoder_set_client_data(decoder->private_->seekable_stream_decoder, decoder); + + if(FLAC__seekable_stream_decoder_init(decoder->private_->seekable_stream_decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) + return decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR; + + return decoder->protected_->state = FLAC__FILE_DECODER_OK; +} + +FLAC__bool FLAC__file_decoder_finish(FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + + if(decoder->protected_->state == FLAC__FILE_DECODER_UNINITIALIZED) + return true; + + FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); + + if(0 != decoder->private_->file && decoder->private_->file != stdin) { + fclose(decoder->private_->file); + decoder->private_->file = 0; + } + + if(0 != decoder->private_->filename) { + free(decoder->private_->filename); + decoder->private_->filename = 0; + } + + set_defaults_(decoder); + + decoder->protected_->state = FLAC__FILE_DECODER_UNINITIALIZED; + + return FLAC__seekable_stream_decoder_finish(decoder->private_->seekable_stream_decoder); +} + +FLAC__bool FLAC__file_decoder_set_md5_checking(FLAC__FileDecoder *decoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + return FLAC__seekable_stream_decoder_set_md5_checking(decoder->private_->seekable_stream_decoder, value); +} + +FLAC__bool FLAC__file_decoder_set_filename(FLAC__FileDecoder *decoder, const char *value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != value); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + if(0 != decoder->private_->filename) { + free(decoder->private_->filename); + decoder->private_->filename = 0; + } + if(0 != strcmp(value, "-")) { + if(0 == (decoder->private_->filename = (char*)malloc(strlen(value)+1))) { + decoder->protected_->state = FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + strcpy(decoder->private_->filename, value); + } + return true; +} + +FLAC__bool FLAC__file_decoder_set_write_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderWriteCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + decoder->private_->write_callback = value; + return true; +} + +FLAC__bool FLAC__file_decoder_set_metadata_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderMetadataCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + decoder->private_->metadata_callback = value; + return true; +} + +FLAC__bool FLAC__file_decoder_set_error_callback(FLAC__FileDecoder *decoder, FLAC__FileDecoderErrorCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + decoder->private_->error_callback = value; + return true; +} + +FLAC__bool FLAC__file_decoder_set_client_data(FLAC__FileDecoder *decoder, void *value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + decoder->private_->client_data = value; + return true; +} + +FLAC__bool FLAC__file_decoder_set_metadata_respond(FLAC__FileDecoder *decoder, FLAC__MetadataType type) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + return FLAC__seekable_stream_decoder_set_metadata_respond(decoder->private_->seekable_stream_decoder, type); +} + +FLAC__bool FLAC__file_decoder_set_metadata_respond_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4]) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + return FLAC__seekable_stream_decoder_set_metadata_respond_application(decoder->private_->seekable_stream_decoder, id); +} + +FLAC__bool FLAC__file_decoder_set_metadata_respond_all(FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + return FLAC__seekable_stream_decoder_set_metadata_respond_all(decoder->private_->seekable_stream_decoder); +} + +FLAC__bool FLAC__file_decoder_set_metadata_ignore(FLAC__FileDecoder *decoder, FLAC__MetadataType type) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + return FLAC__seekable_stream_decoder_set_metadata_ignore(decoder->private_->seekable_stream_decoder, type); +} + +FLAC__bool FLAC__file_decoder_set_metadata_ignore_application(FLAC__FileDecoder *decoder, const FLAC__byte id[4]) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + return FLAC__seekable_stream_decoder_set_metadata_ignore_application(decoder->private_->seekable_stream_decoder, id); +} + +FLAC__bool FLAC__file_decoder_set_metadata_ignore_all(FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->seekable_stream_decoder); + if(decoder->protected_->state != FLAC__FILE_DECODER_UNINITIALIZED) + return false; + return FLAC__seekable_stream_decoder_set_metadata_ignore_all(decoder->private_->seekable_stream_decoder); +} + + +FLAC__FileDecoderState FLAC__file_decoder_get_state(const FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->state; +} + +FLAC__SeekableStreamDecoderState FLAC__file_decoder_get_seekable_stream_decoder_state(const FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__seekable_stream_decoder_get_state(decoder->private_->seekable_stream_decoder); +} + +FLAC__StreamDecoderState FLAC__file_decoder_get_stream_decoder_state(const FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__seekable_stream_decoder_get_stream_decoder_state(decoder->private_->seekable_stream_decoder); +} + +FLAC__bool FLAC__file_decoder_get_md5_checking(const FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__seekable_stream_decoder_get_md5_checking(decoder->private_->seekable_stream_decoder); +} + +unsigned FLAC__file_decoder_get_channels(const FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__seekable_stream_decoder_get_channels(decoder->private_->seekable_stream_decoder); +} + +FLAC__ChannelAssignment FLAC__file_decoder_get_channel_assignment(const FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__seekable_stream_decoder_get_channel_assignment(decoder->private_->seekable_stream_decoder); +} + +unsigned FLAC__file_decoder_get_bits_per_sample(const FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__seekable_stream_decoder_get_bits_per_sample(decoder->private_->seekable_stream_decoder); +} + +unsigned FLAC__file_decoder_get_sample_rate(const FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__seekable_stream_decoder_get_sample_rate(decoder->private_->seekable_stream_decoder); +} + +unsigned FLAC__file_decoder_get_blocksize(const FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__seekable_stream_decoder_get_blocksize(decoder->private_->seekable_stream_decoder); +} + +FLAC__bool FLAC__file_decoder_process_single(FLAC__FileDecoder *decoder) +{ + FLAC__bool ret; + FLAC__ASSERT(0 != decoder); + + if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) + decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; + + if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) + return true; + + FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); + + ret = FLAC__seekable_stream_decoder_process_single(decoder->private_->seekable_stream_decoder); + if(!ret) + decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR; + + return ret; +} + +FLAC__bool FLAC__file_decoder_process_until_end_of_metadata(FLAC__FileDecoder *decoder) +{ + FLAC__bool ret; + FLAC__ASSERT(0 != decoder); + + if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) + decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; + + if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) + return true; + + FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); + + ret = FLAC__seekable_stream_decoder_process_until_end_of_metadata(decoder->private_->seekable_stream_decoder); + if(!ret) + decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR; + + return ret; +} + +FLAC__bool FLAC__file_decoder_process_until_end_of_file(FLAC__FileDecoder *decoder) +{ + FLAC__bool ret; + FLAC__ASSERT(0 != decoder); + + if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) + decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE; + + if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE) + return true; + + FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK); + + ret = FLAC__seekable_stream_decoder_process_until_end_of_stream(decoder->private_->seekable_stream_decoder); + if(!ret) + decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR; + + return ret; +} + +FLAC__bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, FLAC__uint64 sample) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK || decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE); + + if(decoder->private_->filename == 0) { /* means the file is stdin... */ + decoder->protected_->state = FLAC__FILE_DECODER_SEEK_ERROR; + return false; + } + + if(!FLAC__seekable_stream_decoder_seek_absolute(decoder->private_->seekable_stream_decoder, sample)) { + decoder->protected_->state = FLAC__FILE_DECODER_SEEK_ERROR; + return false; + } + else { + decoder->protected_->state = FLAC__FILE_DECODER_OK; + return true; + } +} + + +/*********************************************************************** + * + * Private class methods + * + ***********************************************************************/ + +void set_defaults_(FLAC__FileDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + + decoder->private_->filename = 0; + decoder->private_->write_callback = 0; + decoder->private_->metadata_callback = 0; + decoder->private_->error_callback = 0; + decoder->private_->client_data = 0; +} + +/* + * This will forcibly set stdin to binary mode (for OSes that require it) + */ +FILE *get_binary_stdin_() +{ + /* if something breaks here it is probably due to the presence or + * absence of an underscore before the identifiers 'setmode', + * 'fileno', and/or 'O_BINARY'; check your system header files. + */ +#if defined _MSC_VER || defined __MINGW32__ + _setmode(_fileno(stdin), _O_BINARY); +#elif defined __CYGWIN__ + /* almost certainly not needed for any modern Cygwin, but let's be safe... */ + setmode(_fileno(stdin), _O_BINARY); +#endif + + return stdin; +} + +FLAC__SeekableStreamDecoderReadStatus read_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + (void)decoder; + + if(*bytes > 0) { + size_t bytes_read = fread(buffer, sizeof(FLAC__byte), *bytes, file_decoder->private_->file); + if(bytes_read == 0 && !feof(file_decoder->private_->file)) { + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; + } + else { + *bytes = (unsigned)bytes_read; + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; + } + } + else + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; /* abort to avoid a deadlock */ +} + +FLAC__SeekableStreamDecoderSeekStatus seek_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + (void)decoder; + + if(fseek(file_decoder->private_->file, (long)absolute_byte_offset, SEEK_SET) < 0) + return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; + else + return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; +} + +FLAC__SeekableStreamDecoderTellStatus tell_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + long pos; + (void)decoder; + + if((pos = ftell(file_decoder->private_->file)) < 0) + return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR; + else { + *absolute_byte_offset = (FLAC__uint64)pos; + return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; + } +} + +FLAC__SeekableStreamDecoderLengthStatus length_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + struct stat filestats; + (void)decoder; + + if(0 == file_decoder->private_->filename || stat(file_decoder->private_->filename, &filestats) != 0) + return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR; + else { + *stream_length = (FLAC__uint64)filestats.st_size; + return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; + } +} + +FLAC__bool eof_callback_(const FLAC__SeekableStreamDecoder *decoder, void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + (void)decoder; + + return feof(file_decoder->private_->file); +} + +FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + (void)decoder; + + return file_decoder->private_->write_callback(file_decoder, frame, buffer, file_decoder->private_->client_data); +} + +void metadata_callback_(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + (void)decoder; + + file_decoder->private_->metadata_callback(file_decoder, metadata, file_decoder->private_->client_data); +} + +void error_callback_(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + FLAC__FileDecoder *file_decoder = (FLAC__FileDecoder *)client_data; + (void)decoder; + + file_decoder->private_->error_callback(file_decoder, status, file_decoder->private_->client_data); +} diff --git a/src/libOggFLAC/include/Makefile.am b/src/libOggFLAC/include/Makefile.am new file mode 100644 index 00000000..c6ad8fa8 --- /dev/null +++ b/src/libOggFLAC/include/Makefile.am @@ -0,0 +1,19 @@ +# libOggFLAC - Free Lossless Audio Codec + Ogg library +# Copyright (C) 2002 Josh Coalson +# +# 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. + +SUBDIRS = private diff --git a/src/libOggFLAC/include/protected/Makefile.am b/src/libOggFLAC/include/protected/Makefile.am new file mode 100644 index 00000000..1b6c88b1 --- /dev/null +++ b/src/libOggFLAC/include/protected/Makefile.am @@ -0,0 +1,24 @@ +# libOggFLAC - Free Lossless Audio Codec + Ogg library +# Copyright (C) 2002 Josh Coalson +# +# 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. + +noinst_HEADERS = \ + all.h \ + file_decoder.h \ + seekable_stream_decoder.h \ + stream_decoder.h \ + stream_encoder.h diff --git a/src/libOggFLAC/include/protected/all.h b/src/libOggFLAC/include/protected/all.h new file mode 100644 index 00000000..c6d6cc64 --- /dev/null +++ b/src/libOggFLAC/include/protected/all.h @@ -0,0 +1,28 @@ +/* libOggFLAC - Free Lossless Audio Codec + Ogg library + * Copyright (C) 2002 Josh Coalson + * + * 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. + */ + +#ifndef OggFLAC__PROTECTED__ALL_H +#define OggFLAC__PROTECTED__ALL_H + +#include "file_decoder.h" +#include "seekable_stream_decoder.h" +#include "stream_decoder.h" +#include "stream_encoder.h" + +#endif diff --git a/src/libOggFLAC/include/protected/file_decoder.h b/src/libOggFLAC/include/protected/file_decoder.h new file mode 100644 index 00000000..92c42cbd --- /dev/null +++ b/src/libOggFLAC/include/protected/file_decoder.h @@ -0,0 +1,29 @@ +/* libOggFLAC - Free Lossless Audio Codec + Ogg library + * Copyright (C) 2002 Josh Coalson + * + * 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. + */ + +#ifndef OggFLAC__PROTECTED__FILE_DECODER_H +#define OggFLAC__PROTECTED__FILE_DECODER_H + +#include "OggFLAC/file_decoder.h" + +typedef struct OggFLAC__FileDecoderProtected { + OggFLAC__FileDecoderState state; +} OggFLAC__FileDecoderProtected; + +#endif diff --git a/src/libOggFLAC/include/protected/seekable_stream_decoder.h b/src/libOggFLAC/include/protected/seekable_stream_decoder.h new file mode 100644 index 00000000..9ba53006 --- /dev/null +++ b/src/libOggFLAC/include/protected/seekable_stream_decoder.h @@ -0,0 +1,29 @@ +/* libOggFLAC - Free Lossless Audio Codec + Ogg library + * Copyright (C) 2002 Josh Coalson + * + * 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. + */ + +#ifndef OggFLAC__PROTECTED__SEEKABLE_STREAM_DECODER_H +#define OggFLAC__PROTECTED__SEEKABLE_STREAM_DECODER_H + +#include "OggFLAC/seekable_stream_decoder.h" + +typedef struct OggFLAC__SeekableStreamDecoderProtected { + OggFLAC__SeekableStreamDecoderState state; +} OggFLAC__SeekableStreamDecoderProtected; + +#endif diff --git a/src/libOggFLAC/include/protected/stream_decoder.h b/src/libOggFLAC/include/protected/stream_decoder.h new file mode 100644 index 00000000..833fa513 --- /dev/null +++ b/src/libOggFLAC/include/protected/stream_decoder.h @@ -0,0 +1,29 @@ +/* libOggFLAC - Free Lossless Audio Codec + Ogg library + * Copyright (C) 2002 Josh Coalson + * + * 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. + */ + +#ifndef OggFLAC__PROTECTED__STREAM_DECODER_H +#define OggFLAC__PROTECTED__STREAM_DECODER_H + +#include "OggFLAC/stream_decoder.h" + +typedef struct OggFLAC__StreamDecoderProtected { + OggFLAC__StreamDecoderState state; +} OggFLAC__StreamDecoderProtected; + +#endif diff --git a/src/libOggFLAC/include/protected/stream_encoder.h b/src/libOggFLAC/include/protected/stream_encoder.h new file mode 100644 index 00000000..aaa7d1da --- /dev/null +++ b/src/libOggFLAC/include/protected/stream_encoder.h @@ -0,0 +1,29 @@ +/* libOggFLAC - Free Lossless Audio Codec + Ogg library + * Copyright (C) 2002 Josh Coalson + * + * 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. + */ + +#ifndef OggFLAC__PROTECTED__STREAM_ENCODER_H +#define OggFLAC__PROTECTED__STREAM_ENCODER_H + +#include "OggFLAC/stream_encoder.h" + +typedef struct OggFLAC__StreamEncoderProtected { + OggFLAC__StreamEncoderState state; +} OggFLAC__StreamEncoderProtected; + +#endif diff --git a/src/libOggFLAC/libOggFLAC.m4 b/src/libOggFLAC/libOggFLAC.m4 new file mode 100644 index 00000000..5ce8bda3 --- /dev/null +++ b/src/libOggFLAC/libOggFLAC.m4 @@ -0,0 +1,104 @@ +# Configure paths for libOggFLAC +# "Inspired" by ogg.m4 + +dnl AM_PATH_LIBOGGFLAC([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for libOggFLAC, and define LIBOGGFLAC_CFLAGS and LIBOGGFLAC_LIBS +dnl +AC_DEFUN(AM_PATH_LIBOGGFLAC, +[dnl +dnl Get the cflags and libraries +dnl +AC_ARG_WITH(libOggFLAC,[ --with-libOggFLAC=PFX Prefix where libOggFLAC is installed (optional)], libOggFLAC_prefix="$withval", libOggFLAC_prefix="") +AC_ARG_WITH(libOggFLAC-libraries,[ --with-libOggFLAC-libraries=DIR Directory where libOggFLAC library is installed (optional)], libOggFLAC_libraries="$withval", libOggFLAC_libraries="") +AC_ARG_WITH(libOggFLAC-includes,[ --with-libOggFLAC-includes=DIR Directory where libOggFLAC header files are installed (optional)], libOggFLAC_includes="$withval", libOggFLAC_includes="") +AC_ARG_ENABLE(libOggFLACtest, [ --disable-libOggFLACtest Do not try to compile and run a test libOggFLAC program],, enable_libOggFLACtest=yes) + + if test "x$libOggFLAC_libraries" != "x" ; then + LIBOGGFLAC_LIBS="-L$libOggFLAC_libraries" + elif test "x$libOggFLAC_prefix" != "x" ; then + LIBOGGFLAC_LIBS="-L$libOggFLAC_prefix/lib" + elif test "x$prefix" != "xNONE" ; then + LIBOGGFLAC_LIBS="-L$prefix/lib" + fi + + LIBOGGFLAC_LIBS="$LIBOGGFLAC_LIBS -lOggFLAC -lFLAC -lm" + + if test "x$libOggFLAC_includes" != "x" ; then + LIBOGGFLAC_CFLAGS="-I$libOggFLAC_includes" + elif test "x$libOggFLAC_prefix" != "x" ; then + LIBOGGFLAC_CFLAGS="-I$libOggFLAC_prefix/include" + elif test "$prefix" != "xNONE"; then + LIBOGGFLAC_CFLAGS="-I$prefix/include" + fi + + AC_MSG_CHECKING(for libOggFLAC) + no_libOggFLAC="" + + + if test "x$enable_libOggFLACtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_CXXFLAGS="$CXXFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $LIBOGGFLAC_CFLAGS" + CXXFLAGS="$CXXFLAGS $LIBOGGFLAC_CFLAGS" + LIBS="$LIBS $LIBOGGFLAC_LIBS" +dnl +dnl Now check if the installed libOggFLAC is sufficiently new. +dnl + rm -f conf.libOggFLACtest + AC_TRY_RUN([ +#include +#include +#include +#include + +int main () +{ + system("touch conf.libOggFLACtest"); + return 0; +} + +],, no_libOggFLAC=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + + if test "x$no_libOggFLAC" = "x" ; then + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + AC_MSG_RESULT(no) + if test -f conf.libOggFLACtest ; then + : + else + echo "*** Could not run libOggFLAC test program, checking why..." + CFLAGS="$CFLAGS $LIBOGGFLAC_CFLAGS" + LIBS="$LIBS $LIBOGGFLAC_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return 0; ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding libOggFLAC or finding the wrong" + echo "*** version of libOggFLAC. If it is not finding libOggFLAC, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means libOggFLAC was incorrectly installed" + echo "*** or that you have moved libOggFLAC since it was installed. In the latter case, you" + echo "*** may want to edit the libOggFLAC-config script: $LIBOGGFLAC_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + LIBOGGFLAC_CFLAGS="" + LIBOGGFLAC_LIBS="" + ifelse([$2], , :, [$2]) + fi + AC_SUBST(LIBOGGFLAC_CFLAGS) + AC_SUBST(LIBOGGFLAC_LIBS) + rm -f conf.libOggFLACtest +]) diff --git a/src/libOggFLAC/seekable_stream_decoder.c b/src/libOggFLAC/seekable_stream_decoder.c new file mode 100644 index 00000000..e42f576a --- /dev/null +++ b/src/libOggFLAC/seekable_stream_decoder.c @@ -0,0 +1,990 @@ +/* libOggFLAC - Free Lossless Audio Codec + Ogg library + * Copyright (C) 2002 Josh Coalson + * + * 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 +#include /* for malloc() */ +#include /* for memcpy()/memcmp() */ +#include "FLAC/assert.h" +#include "protected/seekable_stream_decoder.h" +#include "protected/stream_decoder.h" +#include "private/md5.h" + +/*********************************************************************** + * + * Private class method prototypes + * + ***********************************************************************/ + +static void set_defaults_(FLAC__SeekableStreamDecoder *decoder); +static FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data); +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +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 FLAC__bool seek_to_absolute_sample_(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample); + +/*********************************************************************** + * + * Private class data + * + ***********************************************************************/ + +typedef struct FLAC__SeekableStreamDecoderPrivate { + FLAC__SeekableStreamDecoderReadCallback read_callback; + FLAC__SeekableStreamDecoderSeekCallback seek_callback; + FLAC__SeekableStreamDecoderTellCallback tell_callback; + FLAC__SeekableStreamDecoderLengthCallback length_callback; + FLAC__SeekableStreamDecoderEofCallback eof_callback; + FLAC__SeekableStreamDecoderWriteCallback write_callback; + FLAC__SeekableStreamDecoderMetadataCallback metadata_callback; + FLAC__SeekableStreamDecoderErrorCallback error_callback; + void *client_data; + FLAC__StreamDecoder *stream_decoder; + FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek */ + struct MD5Context md5context; + FLAC__byte stored_md5sum[16]; /* this is what is stored in the metadata */ + FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */ + /* the rest of these are only used for seeking: */ + FLAC__StreamMetadata_StreamInfo stream_info; /* we keep this around so we can figure out how to seek quickly */ + const FLAC__StreamMetadata_SeekTable *seek_table; /* we hold a pointer to the stream decoder's seek table for the same reason */ + /* Since we always want to see the STREAMINFO and SEEK_TABLE blocks at this level, we need some extra flags to keep track of whether they should be passed on up through the metadata_callback */ + FLAC__bool ignore_stream_info_block; + FLAC__bool ignore_seek_table_block; + FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */ + FLAC__uint64 target_sample; +} FLAC__SeekableStreamDecoderPrivate; + +/*********************************************************************** + * + * Public static class data + * + ***********************************************************************/ + +const char * const FLAC__SeekableStreamDecoderStateString[] = { + "FLAC__SEEKABLE_STREAM_DECODER_OK", + "FLAC__SEEKABLE_STREAM_DECODER_SEEKING", + "FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM", + "FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR", + "FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR", + "FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR", + "FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR", + "FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED", + "FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK", + "FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED" +}; + +const char * const FLAC__SeekableStreamDecoderReadStatusString[] = { + "FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK", + "FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR" +}; + +const char * const FLAC__SeekableStreamDecoderSeekStatusString[] = { + "FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK", + "FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR" +}; + +const char * const FLAC__SeekableStreamDecoderTellStatusString[] = { + "FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK", + "FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR" +}; + +const char * const FLAC__SeekableStreamDecoderLengthStatusString[] = { + "FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK", + "FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR" +}; + + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ + +FLAC__SeekableStreamDecoder *FLAC__seekable_stream_decoder_new() +{ + FLAC__SeekableStreamDecoder *decoder; + + FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ + + decoder = (FLAC__SeekableStreamDecoder*)malloc(sizeof(FLAC__SeekableStreamDecoder)); + if(decoder == 0) { + return 0; + } + memset(decoder, 0, sizeof(FLAC__SeekableStreamDecoder)); + + decoder->protected_ = (FLAC__SeekableStreamDecoderProtected*)malloc(sizeof(FLAC__SeekableStreamDecoderProtected)); + if(decoder->protected_ == 0) { + free(decoder); + return 0; + } + memset(decoder->protected_, 0, sizeof(FLAC__SeekableStreamDecoderProtected)); + + decoder->private_ = (FLAC__SeekableStreamDecoderPrivate*)malloc(sizeof(FLAC__SeekableStreamDecoderPrivate)); + if(decoder->private_ == 0) { + free(decoder->protected_); + free(decoder); + return 0; + } + memset(decoder->private_, 0, sizeof(FLAC__SeekableStreamDecoderPrivate)); + + decoder->private_->stream_decoder = FLAC__stream_decoder_new(); + if(0 == decoder->private_->stream_decoder) { + free(decoder->private_); + free(decoder->protected_); + free(decoder); + return 0; + } + + set_defaults_(decoder); + + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED; + + return decoder; +} + +void FLAC__seekable_stream_decoder_delete(FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->private_->stream_decoder); + + (void)FLAC__seekable_stream_decoder_finish(decoder); + + FLAC__stream_decoder_delete(decoder->private_->stream_decoder); + + free(decoder->private_); + free(decoder->protected_); + free(decoder); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_init(FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_ALREADY_INITIALIZED; + + if(0 == decoder->private_->read_callback || 0 == decoder->private_->seek_callback || 0 == decoder->private_->tell_callback || 0 == decoder->private_->length_callback || 0 == decoder->private_->eof_callback) + return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK; + + if(0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback) + return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_INVALID_CALLBACK; + + decoder->private_->seek_table = 0; + + decoder->private_->do_md5_checking = decoder->protected_->md5_checking; + + /* We initialize the MD5Context even though we may never use it. This is + * because md5 checking 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__seekable_stream_decoder_finish() to make sure things are always + * cleaned up properly. + */ + MD5Init(&decoder->private_->md5context); + + FLAC__stream_decoder_set_read_callback(decoder->private_->stream_decoder, read_callback_); + FLAC__stream_decoder_set_write_callback(decoder->private_->stream_decoder, write_callback_); + FLAC__stream_decoder_set_metadata_callback(decoder->private_->stream_decoder, metadata_callback_); + FLAC__stream_decoder_set_error_callback(decoder->private_->stream_decoder, error_callback_); + FLAC__stream_decoder_set_client_data(decoder->private_->stream_decoder, decoder); + + /* We always want to see these blocks. Whether or not we pass them up + * through the metadata callback will be determined by flags set in our + * implementation of ..._set_metadata_respond/ignore...() + */ + FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_STREAMINFO); + FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, FLAC__METADATA_TYPE_SEEKTABLE); + + if(FLAC__stream_decoder_init(decoder->private_->stream_decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA) + return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; + + return decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK; +} + +FLAC__bool FLAC__seekable_stream_decoder_finish(FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__bool md5_failed = false; + + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + + if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return true; + + FLAC__ASSERT(0 != decoder->private_->stream_decoder); + + /* see the comment in FLAC__seekable_stream_decoder_init() as to why we + * always call MD5Final() + */ + MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); + + FLAC__stream_decoder_finish(decoder->private_->stream_decoder); + + if(decoder->private_->do_md5_checking) { + if(memcmp(decoder->private_->stored_md5sum, decoder->private_->computed_md5sum, 16)) + md5_failed = true; + } + + set_defaults_(decoder); + + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED; + + return !md5_failed; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_md5_checking(FLAC__SeekableStreamDecoder *decoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->protected_->md5_checking = value; + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_read_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderReadCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->read_callback = value; + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_seek_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderSeekCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->seek_callback = value; + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_tell_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderTellCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->tell_callback = value; + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_length_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderLengthCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->length_callback = value; + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_eof_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderEofCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->eof_callback = value; + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_write_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderWriteCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->write_callback = value; + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_metadata_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderMetadataCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->metadata_callback = value; + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_error_callback(FLAC__SeekableStreamDecoder *decoder, FLAC__SeekableStreamDecoderErrorCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->error_callback = value; + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_client_data(FLAC__SeekableStreamDecoder *decoder, void *value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->client_data = value; + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->stream_decoder); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + if(type == FLAC__METADATA_TYPE_STREAMINFO) + decoder->private_->ignore_stream_info_block = false; + else if(type == FLAC__METADATA_TYPE_SEEKTABLE) + decoder->private_->ignore_seek_table_block = false; + return FLAC__stream_decoder_set_metadata_respond(decoder->private_->stream_decoder, type); +} + +FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4]) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->stream_decoder); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + return FLAC__stream_decoder_set_metadata_respond_application(decoder->private_->stream_decoder, id); +} + +FLAC__bool FLAC__seekable_stream_decoder_set_metadata_respond_all(FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->stream_decoder); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->ignore_stream_info_block = false; + decoder->private_->ignore_seek_table_block = false; + return FLAC__stream_decoder_set_metadata_respond_all(decoder->private_->stream_decoder); +} + +FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore(FLAC__SeekableStreamDecoder *decoder, FLAC__MetadataType type) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->stream_decoder); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + if(type == FLAC__METADATA_TYPE_STREAMINFO) + decoder->private_->ignore_stream_info_block = true; + else if(type == FLAC__METADATA_TYPE_SEEKTABLE) + decoder->private_->ignore_seek_table_block = true; + return FLAC__stream_decoder_set_metadata_ignore(decoder->private_->stream_decoder, type); +} + +FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_application(FLAC__SeekableStreamDecoder *decoder, const FLAC__byte id[4]) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->stream_decoder); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + return FLAC__stream_decoder_set_metadata_ignore_application(decoder->private_->stream_decoder, id); +} + +FLAC__bool FLAC__seekable_stream_decoder_set_metadata_ignore_all(FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_->stream_decoder); + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->ignore_stream_info_block = true; + decoder->private_->ignore_seek_table_block = true; + return FLAC__stream_decoder_set_metadata_ignore_all(decoder->private_->stream_decoder); +} + +FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_get_state(const FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->state; +} + +FLAC__SeekableStreamDecoderState FLAC__seekable_stream_decoder_get_stream_decoder_state(const FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__stream_decoder_get_state(decoder->private_->stream_decoder); +} + +FLAC__bool FLAC__seekable_stream_decoder_get_md5_checking(const FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->md5_checking; +} + +unsigned FLAC__seekable_stream_decoder_get_channels(const FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__stream_decoder_get_channels(decoder->private_->stream_decoder); +} + +FLAC__ChannelAssignment FLAC__seekable_stream_decoder_get_channel_assignment(const FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__stream_decoder_get_channel_assignment(decoder->private_->stream_decoder); +} + +unsigned FLAC__seekable_stream_decoder_get_bits_per_sample(const FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__stream_decoder_get_bits_per_sample(decoder->private_->stream_decoder); +} + +unsigned FLAC__seekable_stream_decoder_get_sample_rate(const FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__stream_decoder_get_sample_rate(decoder->private_->stream_decoder); +} + +unsigned FLAC__seekable_stream_decoder_get_blocksize(const FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + return FLAC__stream_decoder_get_blocksize(decoder->private_->stream_decoder); +} + +FLAC__bool FLAC__seekable_stream_decoder_flush(FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + + decoder->private_->do_md5_checking = false; + + if(!FLAC__stream_decoder_flush(decoder->private_->stream_decoder)) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; + return false; + } + + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK; + + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_reset(FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + + if(!FLAC__seekable_stream_decoder_flush(decoder)) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; + return false; + } + + if(!FLAC__stream_decoder_reset(decoder->private_->stream_decoder)) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; + return false; + } + + decoder->private_->seek_table = 0; + + decoder->private_->do_md5_checking = decoder->protected_->md5_checking; + + /* We initialize the MD5Context even though we may never use it. This is + * because md5 checking 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__seekable_stream_decoder_finish() to make sure things are always + * cleaned up properly. + */ + MD5Init(&decoder->private_->md5context); + + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK; + + return true; +} + +FLAC__bool FLAC__seekable_stream_decoder_process_single(FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__bool ret; + FLAC__ASSERT(0 != decoder); + + if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; + + if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) + return true; + + FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK); + + ret = FLAC__stream_decoder_process_single(decoder->private_->stream_decoder); + if(!ret) + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; + + return ret; +} + +FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_metadata(FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__bool ret; + FLAC__ASSERT(0 != decoder); + + if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; + + if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) + return true; + + FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK); + + ret = FLAC__stream_decoder_process_until_end_of_metadata(decoder->private_->stream_decoder); + if(!ret) + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; + + return ret; +} + +FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_stream(FLAC__SeekableStreamDecoder *decoder) +{ + FLAC__bool ret; + FLAC__ASSERT(0 != decoder); + + if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; + + if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) + return true; + + FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK); + + ret = FLAC__stream_decoder_process_until_end_of_stream(decoder->private_->stream_decoder); + if(!ret) + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; + + return ret; +} + +FLAC__bool FLAC__seekable_stream_decoder_seek_absolute(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 sample) +{ + FLAC__uint64 length; + + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK || decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM); + + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEKING; + + /* turn off md5 checking if a seek is attempted */ + decoder->private_->do_md5_checking = false; + + if(!FLAC__stream_decoder_reset(decoder->private_->stream_decoder)) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; + return false; + } + /* get the file length */ + if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; + return false; + } + /* rewind */ + if(decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; + return false; + } + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder->private_->stream_decoder)) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; + return false; + } + if(decoder->private_->stream_info.total_samples > 0 && sample > decoder->private_->stream_info.total_samples) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; + return false; + } + + return seek_to_absolute_sample_(decoder, length, sample); +} + +/*********************************************************************** + * + * Private class methods + * + ***********************************************************************/ + +void set_defaults_(FLAC__SeekableStreamDecoder *decoder) +{ + decoder->private_->read_callback = 0; + decoder->private_->seek_callback = 0; + decoder->private_->tell_callback = 0; + decoder->private_->length_callback = 0; + decoder->private_->eof_callback = 0; + decoder->private_->write_callback = 0; + decoder->private_->metadata_callback = 0; + decoder->private_->error_callback = 0; + decoder->private_->client_data = 0; + /* WATCHOUT: these should match the default behavior of FLAC__StreamDecoder */ + decoder->private_->ignore_stream_info_block = false; + decoder->private_->ignore_seek_table_block = true; + + decoder->protected_->md5_checking = false; +} + +FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) +{ + FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data; + (void)decoder; + if(seekable_stream_decoder->private_->eof_callback(seekable_stream_decoder, seekable_stream_decoder->private_->client_data)) { + seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + } + else if(*bytes > 0) { + unsigned bytes_read = *bytes; + if(seekable_stream_decoder->private_->read_callback(seekable_stream_decoder, buffer, &bytes_read, seekable_stream_decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK) { + seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_READ_ERROR; + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } + if(bytes_read == 0) { + if(seekable_stream_decoder->private_->eof_callback(seekable_stream_decoder, seekable_stream_decoder->private_->client_data)) { + seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM; + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + } + else + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + else { + *bytes = bytes_read; + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + } + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ +} + +FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data; + (void)decoder; + + if(seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_SEEKING) { + FLAC__uint64 this_frame_sample = frame->header.number.sample_number; + FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize; + FLAC__uint64 target_sample = seekable_stream_decoder->private_->target_sample; + + FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + + seekable_stream_decoder->private_->last_frame = *frame; /* save the frame */ + 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 */ + seekable_stream_decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_OK; + /* shift out the samples before target_sample */ + if(delta > 0) { + unsigned channel; + const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS]; + for(channel = 0; channel < frame->header.channels; channel++) + newbuffer[channel] = buffer[channel] + delta; + seekable_stream_decoder->private_->last_frame.header.blocksize -= delta; + seekable_stream_decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta; + /* write the relevant samples */ + return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, &seekable_stream_decoder->private_->last_frame, newbuffer, seekable_stream_decoder->private_->client_data); + } + else { + /* write the relevant samples */ + return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, frame, buffer, seekable_stream_decoder->private_->client_data); + } + } + else { + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + } + } + else { + if(seekable_stream_decoder->private_->do_md5_checking) { + if(!FLAC__MD5Accumulate(&seekable_stream_decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8)) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + return seekable_stream_decoder->private_->write_callback(seekable_stream_decoder, frame, buffer, seekable_stream_decoder->private_->client_data); + } +} + +void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data; + (void)decoder; + + if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + seekable_stream_decoder->private_->stream_info = metadata->data.stream_info; + /* save the MD5 signature for comparison later */ + memcpy(seekable_stream_decoder->private_->stored_md5sum, metadata->data.stream_info.md5sum, 16); + if(0 == memcmp(seekable_stream_decoder->private_->stored_md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) + seekable_stream_decoder->private_->do_md5_checking = false; + } + else if(metadata->type == FLAC__METADATA_TYPE_SEEKTABLE) { + seekable_stream_decoder->private_->seek_table = &metadata->data.seek_table; + } + + if(seekable_stream_decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING) { + FLAC__bool ignore_block = false; + if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO && seekable_stream_decoder->private_->ignore_stream_info_block) + ignore_block = true; + else if(metadata->type == FLAC__METADATA_TYPE_SEEKTABLE && seekable_stream_decoder->private_->ignore_seek_table_block) + ignore_block = true; + if(!ignore_block) + seekable_stream_decoder->private_->metadata_callback(seekable_stream_decoder, metadata, seekable_stream_decoder->private_->client_data); + } +} + +void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + FLAC__SeekableStreamDecoder *seekable_stream_decoder = (FLAC__SeekableStreamDecoder *)client_data; + (void)decoder; + + if(seekable_stream_decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING) + seekable_stream_decoder->private_->error_callback(seekable_stream_decoder, status, seekable_stream_decoder->private_->client_data); +} + +FLAC__bool seek_to_absolute_sample_(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) +{ + FLAC__uint64 first_frame_offset, lower_bound, upper_bound; + FLAC__int64 pos = -1, last_pos = -1; + int i, lower_seek_point = -1, upper_seek_point = -1; + unsigned approx_bytes_per_frame; + FLAC__uint64 last_frame_sample = 0xffffffffffffffff; + FLAC__bool needs_seek; + const FLAC__uint64 total_samples = decoder->private_->stream_info.total_samples; + const unsigned min_blocksize = decoder->private_->stream_info.min_blocksize; + const unsigned max_blocksize = decoder->private_->stream_info.max_blocksize; + const unsigned max_framesize = decoder->private_->stream_info.max_framesize; + const unsigned channels = FLAC__seekable_stream_decoder_get_channels(decoder); + const unsigned bps = FLAC__seekable_stream_decoder_get_bits_per_sample(decoder); + + /* we are just guessing here, but we want to guess high, not low */ + if(max_framesize > 0) { + approx_bytes_per_frame = max_framesize; + } + /* + * Check if it's a known fixed-blocksize stream. Note that though + * the spec doesn't allow zeroes in the STREAMINFO block, we may + * never get a STREAMINFO block when decoding so the value of + * min_blocksize might be zero. + */ + else if(min_blocksize == max_blocksize && min_blocksize > 0) { + /* note there are no () around 'bps/8' to keep precision up since it's an integer calulation */ + approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64; + } + else + approx_bytes_per_frame = 4608 * channels * bps/8 + 64; + + /* + * The stream position is currently at the first frame plus any read + * ahead data, so first we get the stream position, then subtract + * uncomsumed bytes to get the position of the first frame in the + * stream. + */ + if(decoder->private_->tell_callback(decoder, &first_frame_offset, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; + return false; + } + FLAC__ASSERT(first_frame_offset >= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder->private_->stream_decoder)); + first_frame_offset -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder->private_->stream_decoder); + + /* + * First, we set an upper and lower bound on where in the + * stream we will search. For now we assume the worst case + * scenario, which is our best guess at the beginning of + * the first and last frames. + */ + lower_bound = first_frame_offset; + + /* calc the upper_bound, beyond which we never want to seek */ + if(max_framesize > 0) + upper_bound = stream_length - (max_framesize + 128 + 2); /* 128 for a possible ID3V1 tag, 2 for indexing differences */ + else + upper_bound = stream_length - ((channels * bps * FLAC__MAX_BLOCK_SIZE) / 8 + 128 + 2); + + /* + * Now we refine the bounds if we have a seektable with + * suitable points. Note that according to the spec they + * must be ordered by ascending sample number. + */ + if(0 != decoder->private_->seek_table) { + /* find the closest seek point <= target_sample, if it exists */ + for(i = (int)decoder->private_->seek_table->num_points - 1; i >= 0; i--) { + if(decoder->private_->seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && decoder->private_->seek_table->points[i].sample_number <= target_sample) + break; + } + if(i >= 0) { /* i.e. we found a suitable seek point... */ + lower_bound = first_frame_offset + decoder->private_->seek_table->points[i].stream_offset; + lower_seek_point = i; + } + + /* find the closest seek point > target_sample, if it exists */ + for(i = 0; i < (int)decoder->private_->seek_table->num_points; i++) { + if(decoder->private_->seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && decoder->private_->seek_table->points[i].sample_number > target_sample) + break; + } + if(i < (int)decoder->private_->seek_table->num_points) { /* i.e. we found a suitable seek point... */ + upper_bound = first_frame_offset + decoder->private_->seek_table->points[i].stream_offset; + upper_seek_point = i; + } + } + + /* + * Now guess at where within those bounds our target + * sample will be. + */ + if(lower_seek_point >= 0) { + /* first see if our sample is within a few frames of the lower seekpoint */ + if(decoder->private_->seek_table->points[lower_seek_point].sample_number <= target_sample && target_sample < decoder->private_->seek_table->points[lower_seek_point].sample_number + (decoder->private_->seek_table->points[lower_seek_point].frame_samples * 4)) { + pos = (FLAC__int64)lower_bound; + } + else if(upper_seek_point >= 0) { + const FLAC__uint64 target_offset = target_sample - decoder->private_->seek_table->points[lower_seek_point].sample_number; + const FLAC__uint64 range_samples = decoder->private_->seek_table->points[upper_seek_point].sample_number - decoder->private_->seek_table->points[lower_seek_point].sample_number; + const FLAC__uint64 range_bytes = upper_bound - lower_bound; +#if defined _MSC_VER || defined __MINGW32__ + /* with VC++ you have to spoon feed it the casting */ + pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)(FLAC__int64)target_offset / (double)(FLAC__int64)range_samples * (double)(FLAC__int64)(range_bytes-1)) - approx_bytes_per_frame; +#else + pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)target_offset / (double)range_samples * (double)(range_bytes-1)) - approx_bytes_per_frame; +#endif + } + } + + /* + * If there's no seek table, we need to use the metadata (if we + * have it) and the filelength to estimate the position of the + * frame with the correct sample. + */ + if(pos < 0 && total_samples > 0) { +#if defined _MSC_VER || defined __MINGW32__ + /* with VC++ you have to spoon feed it the casting */ + pos = (FLAC__int64)first_frame_offset + (FLAC__int64)((double)(FLAC__int64)target_sample / (double)(FLAC__int64)total_samples * (double)(FLAC__int64)(stream_length-first_frame_offset-1)) - approx_bytes_per_frame; +#else + pos = (FLAC__int64)first_frame_offset + (FLAC__int64)((double)target_sample / (double)total_samples * (double)(stream_length-first_frame_offset-1)) - approx_bytes_per_frame; +#endif + } + + /* + * If there's no seek table and total_samples is unknown, we + * don't even bother trying to figure out a target, we just use + * our current position. + */ + if(pos < 0) { + FLAC__uint64 upos; + if(decoder->private_->tell_callback(decoder, &upos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; + return false; + } + pos = (FLAC__int32)upos; + needs_seek = false; + } + else + needs_seek = true; + + /* clip the position to the bounds, lower bound takes precedence */ + if(pos >= (FLAC__int64)upper_bound) { + pos = (FLAC__int64)upper_bound-1; + needs_seek = true; + } + if(pos < (FLAC__int64)lower_bound) { + pos = (FLAC__int64)lower_bound; + needs_seek = true; + } + + decoder->private_->target_sample = target_sample; + while(1) { + if(needs_seek) { + if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; + return false; + } + if(!FLAC__stream_decoder_flush(decoder->private_->stream_decoder)) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR; + return false; + } + } + if(!FLAC__stream_decoder_process_single(decoder->private_->stream_decoder)) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; + return false; + } + /* our write callback will change the state when it gets to the target frame */ + if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING) { + break; + } + else { /* we need to narrow the search */ + FLAC__uint64 this_frame_sample = decoder->private_->last_frame.header.number.sample_number; + FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); + 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->private_->last_frame.header.blocksize * channels * bps/8 + 64; + pos -= approx_bytes_per_frame; + needs_seek = true; + } + else { /* target_sample >= this_frame_sample + this frame's blocksize */ + FLAC__uint64 upos; + if(decoder->private_->tell_callback(decoder, &upos, decoder->private_->client_data) != FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK) { + decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_SEEK_ERROR; + return false; + } + last_pos = pos; + pos = (FLAC__int32)upos; + pos -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder->private_->stream_decoder); + needs_seek = false; + } + } + if(pos < (FLAC__int64)lower_bound) + pos = (FLAC__int64)lower_bound; + last_frame_sample = this_frame_sample; + } + } + + return true; +} diff --git a/src/libOggFLAC/stream_decoder.c b/src/libOggFLAC/stream_decoder.c new file mode 100644 index 00000000..19f03559 --- /dev/null +++ b/src/libOggFLAC/stream_decoder.c @@ -0,0 +1,597 @@ +/* libOggFLAC - Free Lossless Audio Codec + Ogg library + * Copyright (C) 2002 Josh Coalson + * + * 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 +#include "FLAC/assert.h" +#include "protected/stream_decoder.h" + +/*********************************************************************** + * + * Private class method prototypes + * + ***********************************************************************/ + +static void set_defaults_(FLAC__StreamDecoder *decoder); + + +/*********************************************************************** + * + * Private class data + * + ***********************************************************************/ + +typedef struct FLAC__StreamDecoderPrivate { + FLAC__StreamDecoderReadCallback read_callback; + FLAC__StreamDecoderWriteCallback write_callback; + FLAC__StreamDecoderMetadataCallback metadata_callback; + FLAC__StreamDecoderErrorCallback error_callback; + void *client_data; +} FLAC__StreamDecoderPrivate; + +/*********************************************************************** + * + * Public static class data + * + ***********************************************************************/ + +const char * const FLAC__StreamDecoderStateString[] = { + "OggFLAC__STREAM_DECODER_OK", + "OggFLAC__STREAM_DECODER_FLAC_STREAM_DECODER_ERROR", + "OggFLAC__STREAM_DECODER_INVALID_CALLBACK", + "OggFLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR", + "OggFLAC__STREAM_DECODER_ALREADY_INITIALIZED", + "OggFLAC__STREAM_DECODER_UNINITIALIZED" +}; + + +/*********************************************************************** + * + * Class constructor/destructor + * + ***********************************************************************/ +FLAC__StreamDecoder *FLAC__stream_decoder_new() +{ + FLAC__StreamDecoder *decoder; + unsigned i; + + FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ + + decoder = (FLAC__StreamDecoder*)malloc(sizeof(FLAC__StreamDecoder)); + if(decoder == 0) { + return 0; + } + memset(decoder, 0, sizeof(FLAC__StreamDecoder)); + + decoder->protected_ = (FLAC__StreamDecoderProtected*)malloc(sizeof(FLAC__StreamDecoderProtected)); + if(decoder->protected_ == 0) { + free(decoder); + return 0; + } + memset(decoder->protected_, 0, sizeof(FLAC__StreamDecoderProtected)); + + decoder->private_ = (FLAC__StreamDecoderPrivate*)malloc(sizeof(FLAC__StreamDecoderPrivate)); + if(decoder->private_ == 0) { + free(decoder->protected_); + free(decoder); + return 0; + } + memset(decoder->private_, 0, sizeof(FLAC__StreamDecoderPrivate)); + + decoder->private_->input = FLAC__bitbuffer_new(); + if(decoder->private_->input == 0) { + free(decoder->private_); + free(decoder->protected_); + free(decoder); + return 0; + } + + decoder->private_->metadata_filter_ids_capacity = 16; + if(0 == (decoder->private_->metadata_filter_ids = malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) { + FLAC__bitbuffer_delete(decoder->private_->input); + free(decoder->private_); + free(decoder->protected_); + free(decoder); + return 0; + } + + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + decoder->private_->output[i] = 0; + decoder->private_->residual[i] = 0; + } + + decoder->private_->output_capacity = 0; + decoder->private_->output_channels = 0; + decoder->private_->has_seek_table = false; + + set_defaults_(decoder); + + decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; + + return decoder; +} + +void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->private_->input); + + FLAC__stream_decoder_finish(decoder); + + if(0 != decoder->private_->metadata_filter_ids) + free(decoder->private_->metadata_filter_ids); + + FLAC__bitbuffer_delete(decoder->private_->input); + free(decoder->private_); + free(decoder->protected_); + free(decoder); +} + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +FLAC__StreamDecoderState FLAC__stream_decoder_init(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return decoder->protected_->state = FLAC__STREAM_DECODER_ALREADY_INITIALIZED; + + if(0 == decoder->private_->read_callback || 0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback) + return decoder->protected_->state = FLAC__STREAM_DECODER_INVALID_CALLBACK; + + if(!FLAC__bitbuffer_init(decoder->private_->input)) + return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + + decoder->private_->last_frame_number = 0; + decoder->private_->samples_decoded = 0; + decoder->private_->has_stream_info = false; + decoder->private_->cached = false; + + /* + * get the CPU info and set the function pointers + */ + FLAC__cpu_info(&decoder->private_->cpuinfo); + /* first default to the non-asm routines */ + decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal; + decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal; + /* now override with asm where appropriate */ +#ifndef FLAC__NO_ASM + if(decoder->private_->cpuinfo.use_asm) { +#ifdef FLAC__CPU_IA32 + FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32); +#ifdef FLAC__HAS_NASM + if(decoder->private_->cpuinfo.data.ia32.mmx) { + decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32; + decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32_mmx; + } + else { + decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32; + decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32; + } +#endif +#endif + } +#endif + + if(!FLAC__stream_decoder_reset(decoder)) + return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + + return decoder->protected_->state; +} + +void FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder) +{ + unsigned i; + FLAC__ASSERT(0 != decoder); + if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) + return; + if(decoder->private_->has_seek_table) { + FLAC__ASSERT(0 != decoder->private_->seek_table.data.seek_table.points); + free(decoder->private_->seek_table.data.seek_table.points); + decoder->private_->seek_table.data.seek_table.points = 0; + decoder->private_->has_seek_table = false; + } + FLAC__bitbuffer_free(decoder->private_->input); + for(i = 0; i < FLAC__MAX_CHANNELS; i++) { + /* WATCHOUT: FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the output arrays have a buffer of up to 3 zeroes in front (at negative indices) for alignment purposes; we use 4 to keep the data well-aligned. */ + if(0 != decoder->private_->output[i]) { + free(decoder->private_->output[i]-4); + decoder->private_->output[i] = 0; + } + if(0 != decoder->private_->residual[i]) { + free(decoder->private_->residual[i]); + decoder->private_->residual[i] = 0; + } + } + decoder->private_->output_capacity = 0; + decoder->private_->output_channels = 0; + + set_defaults_(decoder); + + decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; +} + +FLAC__bool FLAC__stream_decoder_set_read_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->read_callback = value; + return true; +} + +FLAC__bool FLAC__stream_decoder_set_write_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderWriteCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->write_callback = value; + return true; +} + +FLAC__bool FLAC__stream_decoder_set_metadata_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderMetadataCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->metadata_callback = value; + return true; +} + +FLAC__bool FLAC__stream_decoder_set_error_callback(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorCallback value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->error_callback = value; + return true; +} + +FLAC__bool FLAC__stream_decoder_set_client_data(FLAC__StreamDecoder *decoder, void *value) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->client_data = value; + return true; +} + +FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(type <= FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->metadata_filter[type] = true; + if(type == FLAC__METADATA_TYPE_APPLICATION) + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != id); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + + if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION]) + return true; + + FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids); + + if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) { + if(0 == (decoder->private_->metadata_filter_ids = realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2))) + return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + decoder->private_->metadata_filter_ids_capacity *= 2; + } + + memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); + decoder->private_->metadata_filter_ids_count++; + + return true; +} + +FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder) +{ + unsigned i; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++) + decoder->private_->metadata_filter[i] = true; + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(type <= FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + decoder->private_->metadata_filter[type] = false; + if(type == FLAC__METADATA_TYPE_APPLICATION) + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + FLAC__ASSERT(0 != id); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + + if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION]) + return true; + + FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids); + + if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) { + if(0 == (decoder->private_->metadata_filter_ids = realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2))) + return decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + decoder->private_->metadata_filter_ids_capacity *= 2; + } + + memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); + decoder->private_->metadata_filter_ids_count++; + + return true; +} + +FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) + return false; + memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter)); + decoder->private_->metadata_filter_ids_count = 0; + return true; +} + +FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->state; +} + +unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->channels; +} + +FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->channel_assignment; +} + +unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->bits_per_sample; +} + +unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->sample_rate; +} + +unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + return decoder->protected_->blocksize; +} + +FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + + if(!FLAC__bitbuffer_clear(decoder->private_->input)) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; + + return true; +} + +FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->private_); + FLAC__ASSERT(0 != decoder->protected_); + + if(!FLAC__stream_decoder_flush(decoder)) { + decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; + return false; + } + decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA; + + decoder->private_->samples_decoded = 0; + + return true; +} + +FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder) +{ + FLAC__bool got_a_frame; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!read_metadata_(decoder)) + return false; /* above function sets the status for us */ + else + return true; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!read_frame_(decoder, &got_a_frame)) + return false; /* above function sets the status for us */ + if(got_a_frame) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + FLAC__ASSERT(0); + return false; + } + } +} + +FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!read_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + case FLAC__STREAM_DECODER_READ_FRAME: + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + FLAC__ASSERT(0); + return false; + } + } +} + +FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder) +{ + FLAC__bool dummy; + FLAC__ASSERT(0 != decoder); + FLAC__ASSERT(0 != decoder->protected_); + + while(1) { + switch(decoder->protected_->state) { + case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: + if(!find_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_METADATA: + if(!read_metadata_(decoder)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: + if(!frame_sync_(decoder)) + return true; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_READ_FRAME: + if(!read_frame_(decoder, &dummy)) + return false; /* above function sets the status for us */ + break; + case FLAC__STREAM_DECODER_END_OF_STREAM: + case FLAC__STREAM_DECODER_ABORTED: + return true; + default: + FLAC__ASSERT(0); + return false; + } + } +} + +/*********************************************************************** + * + * Protected class methods + * + ***********************************************************************/ + +unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder) +{ + FLAC__ASSERT(0 != decoder); + return FLAC__bitbuffer_get_input_bytes_unconsumed(decoder->private_->input); +} + +/*********************************************************************** + * + * Private class methods + * + ***********************************************************************/ + +void set_defaults_(FLAC__StreamDecoder *decoder) +{ + decoder->private_->read_callback = 0; + decoder->private_->write_callback = 0; + decoder->private_->metadata_callback = 0; + decoder->private_->error_callback = 0; + decoder->private_->client_data = 0; + + memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter)); + decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true; + decoder->private_->metadata_filter_ids_count = 0; +} diff --git a/src/libOggFLAC/stream_encoder.c b/src/libOggFLAC/stream_encoder.c new file mode 100644 index 00000000..20beee5e --- /dev/null +++ b/src/libOggFLAC/stream_encoder.c @@ -0,0 +1,641 @@ +/* libOggFLAC - Free Lossless Audio Codec + Ogg library + * Copyright (C) 2002 Josh Coalson + * + * 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 +#include /* for malloc() */ +#include /* for memcpy() */ +#include "ogg/ogg.h" +#include "FLAC/assert.h" +#include "OggFLAC/stream_decoder.h" +#include "protected/stream_encoder.h" + +/*********************************************************************** + * + * Private class method prototypes + * + ***********************************************************************/ + +static void set_defaults_(FLAC__StreamEncoder *encoder); +static FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data); +static void metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data); + + +/*********************************************************************** + * + * Private class data + * + ***********************************************************************/ + +typedef struct FLAC__StreamEncoderPrivate { + OggFLAC__StreamEncoderWriteCallback write_callback; + void *client_data; + FLAC__StreamEncoder *stream_encoder; + /* internal vars (all the above are class settings) */ + FLAC__bool is_first_packet; + FLAC__uint64 samples_written; + struct { + ogg_stream_state stream_state; + ogg_page page; + } ogg; +} FLAC__StreamEncoderPrivate; + + +/*********************************************************************** + * + * Public static class data + * + ***********************************************************************/ + +const char * const OggFLAC__StreamEncoderStateString[] = { + "OggFLAC__STREAM_ENCODER_OK", + "OggFLAC__STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR", + "OggFLAC__STREAM_ENCODER_INVALID_CALLBACK", + "OggFLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR", + "OggFLAC__STREAM_ENCODER_ALREADY_INITIALIZED", + "OggFLAC__STREAM_ENCODER_UNINITIALIZED" +}; + + +/*********************************************************************** + * + * Class constructor/destructor + * + */ +OggFLAC__StreamEncoder *OggFLAC__stream_encoder_new() +{ + OggFLAC__StreamEncoder *encoder; + + encoder = (OggFLAC__StreamEncoder*)malloc(sizeof(OggFLAC__StreamEncoder)); + if(encoder == 0) { + return 0; + } + memset(encoder, 0, sizeof(OggFLAC__StreamEncoder)); + + encoder->protected_ = (OggFLAC__StreamEncoderProtected*)malloc(sizeof(OggFLAC__StreamEncoderProtected)); + if(encoder->protected_ == 0) { + free(encoder); + return 0; + } + memset(encoder->protected_, 0, sizeof(OggFLAC__StreamEncoderProtected)); + + encoder->private_ = (OggFLAC__StreamEncoderPrivate*)malloc(sizeof(OggFLAC__StreamEncoderPrivate)); + if(encoder->private_ == 0) { + free(encoder->protected_); + free(encoder); + return 0; + } + memset(encoder->private_, 0, sizeof(OggFLAC__StreamEncoderPrivate)); + + encoder->private_->stream_encoder = FLAC__stream_encoder_new(); + if(0 == encoder->private_->stream_encoder) { + free(encoder->private_); + free(encoder->protected_); + free(encoder); + return 0; + } + + set_defaults_(encoder); + + encoder->protected_->state = OggFLAC__STREAM_ENCODER_UNINITIALIZED; + + return encoder; +} + +void OggFLAC__stream_encoder_delete(OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + + (void)OggFLAC__stream_encoder_finish(encoder); + + FLAC__stream_encoder_delete(encoder->private_->stream_encoder); + + free(encoder->private_); + free(encoder->protected_); + free(encoder); +} + + +/*********************************************************************** + * + * Public class methods + * + ***********************************************************************/ + +OggFLAC__StreamEncoderState OggFLAC__stream_encoder_init(FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + + if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED) + return encoder->protected_->state = OggFLAC__STREAM_ENCODER_ALREADY_INITIALIZED; + + if(0 == encoder->private_->write_callback) + return encoder->protected_->state = OggFLAC__STREAM_ENCODER_INVALID_CALLBACK; + + FLAC__stream_encoder_set_write_callback(encoder->private_->stream_encoder, write_callback_); + FLAC__stream_encoder_set_metadata_callback(encoder->private_->stream_encoder, metadata_callback_); + FLAC__stream_encoder_set_client_data(encoder->private_->stream_encoder, encoder); + + if(FLAC__stream_encoder_init(encoder->private_->stream_encoder) != FLAC__STREAM_ENCODER_OK) + return encoder->protected_->state = OggFLAC__STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR; + + encoder->private_->is_first_packet = true; + encoder->private_->samples_written = 0; + + return encoder->protected_->state = OggFLAC__STREAM_ENCODER_OK; +} + +void OggFLAC__stream_encoder_finish(OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + + if(encoder->protected_->state == OggFLAC__STREAM_ENCODER_UNINITIALIZED) + return; + + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + + FLAC__stream_encoder_finish(encoder->private_->stream_encoder); + + set_defaults_(encoder); + + encoder->protected_->state = OggFLAC__STREAM_ENCODER_UNINITIALIZED; +} + +FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_verify(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_streamable_subset(OggFLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_streamable_subset(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_do_mid_side_stereo(OggFLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_do_mid_side_stereo(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_loose_mid_side_stereo(OggFLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_loose_mid_side_stereo(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_channels(OggFLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_channels(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_bits_per_sample(OggFLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_bits_per_sample(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_sample_rate(OggFLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_sample_rate(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_blocksize(OggFLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_blocksize(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_max_lpc_order(OggFLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_max_lpc_order(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_qlp_coeff_precision(OggFLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_qlp_coeff_precision(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_do_qlp_coeff_prec_search(OggFLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_do_escape_coding(OggFLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_do_escape_coding(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_do_exhaustive_model_search(OggFLAC__StreamEncoder *encoder, FLAC__bool value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_do_exhaustive_model_search(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_min_residual_partition_order(OggFLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_min_residual_partition_order(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_max_residual_partition_order(OggFLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_max_residual_partition_order(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_rice_parameter_search_dist(OggFLAC__StreamEncoder *encoder, unsigned value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_rice_parameter_search_dist(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_total_samples_estimate(OggFLAC__StreamEncoder *encoder, FLAC__uint64 value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_total_samples_estimate(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_metadata(OggFLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != encoder->private_->stream_encoder); + if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + return FLAC__stream_encoder_set_metadata(encoder->private_->stream_encoder, value); +} + +FLAC__bool OggFLAC__stream_encoder_set_write_callback(OggFLAC__StreamEncoder *encoder, OggFLAC__StreamEncoderWriteCallback value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + FLAC__ASSERT(0 != value); + if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->private_->write_callback = value; + return true; +} + +FLAC__bool OggFLAC__stream_encoder_set_client_data(OggFLAC__StreamEncoder *encoder, void *value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != OggFLAC__STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->private_->client_data = value; + return true; +} + +OggFLAC__StreamEncoderState OggFLAC__stream_encoder_get_state(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return encoder->protected_->state; +} + +FLAC__StreamEncoderState OggFLAC__stream_encoder_get_FLAC_stream_encoder_state(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_state(encoder->private_->encoder); +} + +FLAC__StreamDecoderState OggFLAC__stream_encoder_get_verify_decoder_state(const OggFLAC__StreamEncoder *encoder); +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_verify_decoder_state(encoder->private_->encoder); +} + +FLAC__bool OggFLAC__stream_encoder_get_verify(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_verify(encoder->private_->encoder); +} + +FLAC__bool OggFLAC__stream_encoder_get_streamable_subset(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_streamable_subset(encoder->private_->encoder); +} + +FLAC__bool OggFLAC__stream_encoder_get_do_mid_side_stereo(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_do_mid_side_stereo(encoder->private_->encoder); +} + +FLAC__bool OggFLAC__stream_encoder_get_loose_mid_side_stereo(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_loose_mid_side_stereo(encoder->private_->encoder); +} + +unsigned OggFLAC__stream_encoder_get_channels(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_channels(encoder->private_->encoder); +} + +unsigned OggFLAC__stream_encoder_get_bits_per_sample(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_bits_per_sample(encoder->private_->encoder); +} + +unsigned OggFLAC__stream_encoder_get_sample_rate(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_sample_rate(encoder->private_->encoder); +} + +unsigned OggFLAC__stream_encoder_get_blocksize(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_blocksize(encoder->private_->encoder); +} + +unsigned OggFLAC__stream_encoder_get_max_lpc_order(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_max_lpc_order(encoder->private_->encoder); +} + +unsigned OggFLAC__stream_encoder_get_qlp_coeff_precision(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_qlp_coeff_precision(encoder->private_->encoder); +} + +FLAC__bool OggFLAC__stream_encoder_get_do_qlp_coeff_prec_search(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder->private_->encoder); +} + +FLAC__bool OggFLAC__stream_encoder_get_do_escape_coding(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_do_escape_coding(encoder->private_->encoder); +} + +FLAC__bool OggFLAC__stream_encoder_get_do_exhaustive_model_search(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_do_exhaustive_model_search(encoder->private_->encoder); +} + +unsigned OggFLAC__stream_encoder_get_min_residual_partition_order(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_min_residual_partition_order(encoder->private_->encoder); +} + +unsigned OggFLAC__stream_encoder_get_max_residual_partition_order(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_max_residual_partition_order(encoder->private_->encoder); +} + +unsigned OggFLAC__stream_encoder_get_rice_parameter_search_dist(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_rice_parameter_search_dist(encoder->private_->encoder); +} + +FLAC__uint64 OggFLAC__stream_encoder_get_total_samples_estimate(const OggFLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_get_total_samples_estimate(encoder->private_->encoder); +} + +FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_process(encoder->private_->encoder, buffer, samples); +} + +FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + return FLAC__stream_encoder_process_interleaved(encoder->private_->encoder, buffer, samples); +} + +/*********************************************************************** + * + * Private class methods + * + ***********************************************************************/ + +void set_defaults_(FLAC__StreamEncoder *encoder) +{ + FLAC__ASSERT(0 != encoder); + + encoder->private_->write_callback = 0; + encoder->private_->client_data = 0; +} + +FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data) +{ + ogg_packet packet; + + encoder->private_->samples_written += samples; + + memset(&packet, 0, sizeof(packet)); + packet.packet = (unsigned char *)buffer; + packet.granulepos = encoder->private_->samples_written - 1; + /*@@@ WATCHOUT: + * This depends on the behavior of FLAC__StreamEncoder that 'samples' + * will be 0 for metadata writes. + */ + packet.packetno = (samples == 0? -1 : (int)current_frame); + packet.bytes = bytes; + + if(encoder->private_->is_first_packet) { + packet.b_o_s = 1; + encoder->private_->is_first_packet = false; + } + + if(encoder->private_->total_samples_to_encode > 0 && encoder->private_->total_samples_to_encode == encoder->private_->samples_written) + packet.e_o_s = 1; + + ogg_stream_packetin(&encoder->private_->ogg.stream_state, &packet); + + while(ogg_stream_pageout(&encoder->private_->ogg.stream_state, &encoder->private_->ogg.page) != 0) { + if(encoder->private_->write_callback(encoder, encoder->private_->ogg.page.header, encoder->private_->ogg.page.header_len) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + + if(encoder->private_->write_callback(encoder, encoder->private_->ogg.page.body, encoder->private_->ogg.page.body_len) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + } + + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; +} + +void metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + /* + * We don't try to go back an update metadata blocks by mucking + * around inside the Ogg layer. Maybe someday we will care to + * and an OggFLAC__SeekableStreamEncoder and OggFLAC__FileEncoder + * will be possible but it may just never be useful. + */ + (void)encoder, (void)metadata, (void)client_data; +}