add support for writing ogg streams
authorJosh Coalson <jcoalson@users.sourceforce.net>
Wed, 31 Oct 2001 18:31:36 +0000 (18:31 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Wed, 31 Oct 2001 18:31:36 +0000 (18:31 +0000)
configure.in
src/flac/Makefile.am
src/flac/Makefile.lite
src/flac/decode.c
src/flac/decode.h
src/flac/encode.c
src/flac/encode.h
src/flac/main.c

index 206b1ff..1c8ecc0 100644 (file)
@@ -76,6 +76,9 @@ if test x$sse_os = xtrue ; then
 AC_DEFINE(FLAC__SSE_OS)
 fi
 
+AM_PATH_OGG( , AC_MSG_WARN([*** Ogg development enviroment not installed - ogg support will not be built]))
+AM_CONDITIONAL(FLaC__HAS_OGG, test x$OGG_LIBS != x)
+
 AM_PATH_XMMS(0.9.5.1, , AC_MSG_WARN([*** XMMS >= 0.9.5.1 not installed - xmms support will not be built]))
 AM_CONDITIONAL(FLaC__HAS_XMMS, test x$XMMS_INPUT_PLUGIN_DIR != x)
 
index cefea82..21be192 100644 (file)
@@ -29,5 +29,10 @@ flac_SOURCES = \
        encode.h \
        file.h
 
+if FLaC__HAS_OGG
 flac_LDFLAGS = -lm
+else
+flac_LDFLAGS = -lm -logg
+endif
+
 flac_LDADD = $(top_builddir)/src/libFLAC/libFLAC.la
index 40b55fa..0414ae2 100644 (file)
 #
 
 PROGRAM_NAME = flac
-INCLUDES     = -I./include -I../../include
-LIBS         = -lFLAC -lm
+#@@@OGG
+INCLUDES     = -I./include -I../../include -I$(HOME)/local/include
+#@@@OGG conditionalize -logg
+LIBS         = -lFLAC -lm -L$(HOME)/local/lib -logg
 
 OBJS = \
        analyze.o \
index 79f738f..ed0972a 100644 (file)
 #include "FLAC/all.h"
 #include "decode.h"
 #include "file.h"
+#ifdef FLaC__HAS_OGG
+#include "ogg/ogg.h"
+#endif
+
+#ifdef FLaC__HAS_OGG
+typedef struct {
+       ogg_sync_state oy;
+       ogg_stream_state os;
+} ogg_info_struct;
+#endif
 
 typedef struct {
        const char *inbasefilename;
+#ifdef FLaC__HAS_OGG
+       FILE *fin;
+#endif
        FILE *fout;
        FLAC__bool abort_flag;
        FLAC__bool analysis_mode;
@@ -48,36 +61,57 @@ typedef struct {
        FLAC__bool skip_count_too_high;
        FLAC__uint64 samples_processed;
        unsigned frame_counter;
+#ifdef FLaC__HAS_OGG
+       FLAC__bool is_ogg;
+#endif
+       union {
+               FLAC__FileDecoder *file;
+               FLAC__StreamDecoder *stream;
+       } decoder;
+#ifdef FLaC__HAS_OGG
+       ogg_info_struct ogg;
+#endif
 } stream_info_struct;
 
-static FLAC__FileDecoder *decoder;
 static FLAC__bool is_big_endian_host;
 
 /* local routines */
 static FLAC__bool init(const char *infilename, stream_info_struct *stream_info);
 static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val);
 static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val);
-static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
-static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
-static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+#ifdef FLaC__HAS_OGG
+static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
+#endif
+/*
+ * We use 'void *' so that we can use the same callbacks for the
+ * FLAC__StreamDecoder and FLAC__FileDecoder.  The 'decoder' argument is
+ * actually never used in the callbacks.
+ */
+static FLAC__StreamDecoderWriteStatus write_callback(const void *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data);
+static void metadata_callback(const void *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
+static void error_callback(const void *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
 static void print_stats(const stream_info_struct *stream_info);
 
-int flac__decode_wav(const char *infile, const char *outfile, FLAC__bool analysis_mode, analysis_options aopts, FLAC__bool verbose, FLAC__uint64 skip)
+
+int flac__decode_wav(const char *infile, const char *outfile, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options)
 {
        FLAC__bool md5_failure = false;
        stream_info_struct stream_info;
 
-       decoder = 0;
        stream_info.abort_flag = false;
        stream_info.analysis_mode = analysis_mode;
        stream_info.aopts = aopts;
        stream_info.test_only = (outfile == 0);
        stream_info.is_wave_out = true;
-       stream_info.verbose = verbose;
-       stream_info.skip = skip;
+       stream_info.verbose = options.common.verbose;
+       stream_info.skip = options.common.skip;
        stream_info.skip_count_too_high = false;
        stream_info.samples_processed = 0;
        stream_info.frame_counter = 0;
+#ifdef FLaC__HAS_OGG
+       stream_info.is_ogg = options.common.is_ogg;
+#endif
+       stream_info.decoder.file = 0; /* this zeroes stream_info.decoder.stream also */
        stream_info.inbasefilename = flac__file_get_basename(infile);
        stream_info.fout = 0; /* initialized with an open file later if necessary */
 
@@ -95,100 +129,179 @@ int flac__decode_wav(const char *infile, const char *outfile, FLAC__bool analysi
                }
        }
 
+#ifdef FLaC__HAS_OGG
+       if(stream_info.is_ogg) {
+               if (0 == strcmp(infile, "-")) {
+                       stream_info.fin = stdin;
+               } else {
+                       if (0 == (stream_info.fin = fopen(infile, "rb"))) {
+                               fprintf(stderr, "%s: ERROR: can't open input file %s\n", stream_info.inbasefilename, infile);
+                               if(stream_info.fout != stdout)
+                                       fclose(stream_info.fout);
+                               return 1;
+                       }
+               }
+       }
+#endif
+
        if(analysis_mode)
                flac__analyze_init(aopts);
 
        if(!init(infile, &stream_info))
                goto wav_abort_;
 
-       if(skip > 0) {
-               if(!FLAC__file_decoder_process_metadata(decoder)) {
-                       fprintf(stderr, "%s: ERROR while decoding metadata, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
+       if(stream_info.skip > 0) {
+#ifdef FLaC__HAS_OGG
+               if(stream_info.is_ogg) { //@@@ (move this check into main.c)
+                       fprintf(stderr, "%s: ERROR, can't skip when decoding Ogg-FLAC yet; convert to native-FLAC first\n", stream_info.inbasefilename);
+                       goto wav_abort_;
+               }
+#endif
+               if(!FLAC__file_decoder_process_metadata(stream_info.decoder.file)) {
+                       fprintf(stderr, "%s: ERROR while decoding metadata, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
                        goto wav_abort_;
                }
                if(stream_info.skip_count_too_high) {
                        fprintf(stderr, "%s: ERROR trying to skip more samples than in stream\n", stream_info.inbasefilename);
                        goto wav_abort_;
                }
-               if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
-                       fprintf(stderr, "%s: ERROR seeking while skipping bytes, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
+               if(!FLAC__file_decoder_seek_absolute(stream_info.decoder.file, stream_info.skip)) {
+                       fprintf(stderr, "%s: ERROR seeking while skipping bytes, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
                        goto wav_abort_;
                }
-               if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
-                       if(verbose) fprintf(stderr, "\n");
-                       fprintf(stderr, "%s: ERROR while decoding frames, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
+               if(!FLAC__file_decoder_process_remaining_frames(stream_info.decoder.file)) {
+                       if(stream_info.verbose) fprintf(stderr, "\n");
+                       fprintf(stderr, "%s: ERROR while decoding frames, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
                        goto wav_abort_;
                }
-               if(FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_END_OF_FILE) {
-                       if(verbose) fprintf(stderr, "\n");
-                       fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
+               if(FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_END_OF_FILE) {
+                       if(stream_info.verbose) fprintf(stderr, "\n");
+                       fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
                        goto wav_abort_;
                }
        }
        else {
-               if(!FLAC__file_decoder_process_whole_file(decoder)) {
-                       if(verbose) fprintf(stderr, "\n");
-                       fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
-                       goto wav_abort_;
+#ifdef FLaC__HAS_OGG
+               if(stream_info.is_ogg) {
+                       if(!FLAC__stream_decoder_process_whole_stream(stream_info.decoder.stream)) {
+                               if(stream_info.verbose) fprintf(stderr, "\n");
+                               fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", stream_info.inbasefilename, FLAC__stream_decoder_get_state(stream_info.decoder.stream), FLAC__StreamDecoderStateString[FLAC__stream_decoder_get_state(stream_info.decoder.stream)]);
+                               goto wav_abort_;
+                       }
+                       if(FLAC__stream_decoder_get_state(stream_info.decoder.stream) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && FLAC__stream_decoder_get_state(stream_info.decoder.stream) != FLAC__STREAM_DECODER_END_OF_STREAM) {
+                               if(stream_info.verbose) fprintf(stderr, "\n");
+                               fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", stream_info.inbasefilename, FLAC__stream_decoder_get_state(stream_info.decoder.stream), FLAC__StreamDecoderStateString[FLAC__stream_decoder_get_state(stream_info.decoder.stream)]);
+                               goto wav_abort_;
+                       }
                }
-               if(FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_END_OF_FILE) {
-                       if(verbose) fprintf(stderr, "\n");
-                       fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
-                       goto wav_abort_;
+               else
+#endif
+               {
+                       if(!FLAC__file_decoder_process_whole_file(stream_info.decoder.file)) {
+                               if(stream_info.verbose) fprintf(stderr, "\n");
+                               fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
+                               goto wav_abort_;
+                       }
+                       if(FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_END_OF_FILE) {
+                               if(stream_info.verbose) fprintf(stderr, "\n");
+                               fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
+                               goto wav_abort_;
+                       }
                }
        }
 
-       if(decoder) {
-               if(FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_UNINITIALIZED)
-                       md5_failure = !FLAC__file_decoder_finish(decoder);
-               print_stats(&stream_info);
-               FLAC__file_decoder_delete(decoder);
+#ifdef FLaC__HAS_OGG
+       if(stream_info.is_ogg) {
+               if(stream_info.decoder.stream) {
+                       if(FLAC__stream_decoder_get_state(stream_info.decoder.stream) != FLAC__STREAM_DECODER_UNINITIALIZED)
+                               FLAC__stream_decoder_finish(stream_info.decoder.stream);
+                       md5_failure = false;
+                       print_stats(&stream_info);
+                       FLAC__stream_decoder_delete(stream_info.decoder.stream);
+               }
+       }
+       else
+#endif
+       {
+               if(stream_info.decoder.file) {
+                       if(FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_UNINITIALIZED)
+                               md5_failure = !FLAC__file_decoder_finish(stream_info.decoder.file);
+                       print_stats(&stream_info);
+                       FLAC__file_decoder_delete(stream_info.decoder.file);
+               }
        }
        if(0 != stream_info.fout && stream_info.fout != stdout)
                fclose(stream_info.fout);
+#ifdef FLaC__HAS_OGG
+       if(stream_info.is_ogg) {
+               if(0 != stream_info.fin && stream_info.fin != stdin)
+                       fclose(stream_info.fin);
+       }
+#endif
        if(analysis_mode)
                flac__analyze_finish(aopts);
        if(md5_failure) {
                fprintf(stderr, "\r%s: WARNING, MD5 signature mismatch\n", stream_info.inbasefilename);
        }
        else {
-               if(verbose)
+               if(stream_info.verbose)
                        fprintf(stderr, "\r%s: %s         \n", stream_info.inbasefilename, stream_info.test_only? "ok           ":analysis_mode?"done           ":"done");
        }
        return 0;
 wav_abort_:
-       if(decoder) {
-               if(FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_UNINITIALIZED)
-                       FLAC__file_decoder_finish(decoder);
-               FLAC__file_decoder_delete(decoder);
+#ifdef FLaC__HAS_OGG
+       if(stream_info.is_ogg) {
+               if(stream_info.decoder.stream) {
+                       if(FLAC__stream_decoder_get_state(stream_info.decoder.stream) != FLAC__STREAM_DECODER_UNINITIALIZED)
+                               FLAC__stream_decoder_finish(stream_info.decoder.stream);
+                       FLAC__stream_decoder_delete(stream_info.decoder.stream);
+               }
+       }
+       else
+#endif
+       {
+               if(stream_info.decoder.file) {
+                       if(FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_UNINITIALIZED)
+                               FLAC__file_decoder_finish(stream_info.decoder.file);
+                       FLAC__file_decoder_delete(stream_info.decoder.file);
+               }
        }
        if(0 != stream_info.fout && stream_info.fout != stdout) {
                fclose(stream_info.fout);
                unlink(outfile);
        }
+#ifdef FLaC__HAS_OGG
+       if(stream_info.is_ogg) {
+               if(0 != stream_info.fin && stream_info.fin != stdin)
+                       fclose(stream_info.fin);
+       }
+#endif
        if(analysis_mode)
                flac__analyze_finish(aopts);
        return 1;
 }
 
-int flac__decode_raw(const char *infile, const char *outfile, FLAC__bool analysis_mode, analysis_options aopts, FLAC__bool verbose, FLAC__uint64 skip, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples)
+int flac__decode_raw(const char *infile, const char *outfile, FLAC__bool analysis_mode, analysis_options aopts, raw_decode_options_t options)
 {
        FLAC__bool md5_failure = false;
        stream_info_struct stream_info;
 
-       decoder = 0;
        stream_info.abort_flag = false;
        stream_info.analysis_mode = analysis_mode;
        stream_info.aopts = aopts;
        stream_info.test_only = (outfile == 0);
        stream_info.is_wave_out = false;
-       stream_info.is_big_endian = is_big_endian;
-       stream_info.is_unsigned_samples = is_unsigned_samples;
-       stream_info.verbose = verbose;
-       stream_info.skip = skip;
+       stream_info.is_big_endian = options.is_big_endian;
+       stream_info.is_unsigned_samples = options.is_unsigned_samples;
+       stream_info.verbose = options.common.verbose;
+       stream_info.skip = options.common.skip;
        stream_info.skip_count_too_high = false;
        stream_info.samples_processed = 0;
        stream_info.frame_counter = 0;
+#ifdef FLaC__HAS_OGG
+       stream_info.is_ogg = is_ogg;
+#endif
+       stream_info.decoder.file = 0; /* this zeroes stream_info.decoder.stream also */
        stream_info.inbasefilename = flac__file_get_basename(infile);
        stream_info.fout = 0; /* initialized with an open file later if necessary */
 
@@ -206,77 +319,153 @@ int flac__decode_raw(const char *infile, const char *outfile, FLAC__bool analysi
                }
        }
 
+#ifdef FLaC__HAS_OGG
+       if(stream_info.is_ogg) {
+               if (0 == strcmp(infile, "-")) {
+                       stream_info.fin = stdin;
+               } else {
+                       if (0 == (stream_info.fin = fopen(infile, "rb"))) {
+                               fprintf(stderr, "%s: ERROR: can't open input file %s\n", stream_info.inbasefilename, infile);
+                               if(stream_info.fout != stdout)
+                                       fclose(stream_info.fout);
+                               return 1;
+                       }
+               }
+       }
+#endif
+
        if(analysis_mode)
                flac__analyze_init(aopts);
 
        if(!init(infile, &stream_info))
                goto raw_abort_;
 
-       if(skip > 0) {
-               if(!FLAC__file_decoder_process_metadata(decoder)) {
-                       fprintf(stderr, "%s: ERROR while decoding metadata, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
+       if(stream_info.skip > 0) {
+#ifdef FLaC__HAS_OGG
+               if(stream_info.is_ogg) { //@@@ (move this check into main.c)
+                       fprintf(stderr, "%s: ERROR, can't skip when decoding Ogg-FLAC yet; convert to native-FLAC first\n", stream_info.inbasefilename);
+                       goto raw_abort_;
+               }
+#endif
+               if(!FLAC__file_decoder_process_metadata(stream_info.decoder.file)) {
+                       fprintf(stderr, "%s: ERROR while decoding metadata, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
                        goto raw_abort_;
                }
                if(stream_info.skip_count_too_high) {
                        fprintf(stderr, "%s: ERROR trying to skip more samples than in stream\n", stream_info.inbasefilename);
                        goto raw_abort_;
                }
-               if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
-                       fprintf(stderr, "%s: ERROR seeking while skipping bytes, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
+               if(!FLAC__file_decoder_seek_absolute(stream_info.decoder.file, stream_info.skip)) {
+                       fprintf(stderr, "%s: ERROR seeking while skipping bytes, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
                        goto raw_abort_;
                }
-               if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
-                       if(verbose) fprintf(stderr, "\n");
-                       fprintf(stderr, "%s: ERROR while decoding frames, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
+               if(!FLAC__file_decoder_process_remaining_frames(stream_info.decoder.file)) {
+                       if(stream_info.verbose) fprintf(stderr, "\n");
+                       fprintf(stderr, "%s: ERROR while decoding frames, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
                        goto raw_abort_;
                }
-               if(FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_END_OF_FILE) {
-                       if(verbose) fprintf(stderr, "\n");
-                       fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
+               if(FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_END_OF_FILE) {
+                       if(stream_info.verbose) fprintf(stderr, "\n");
+                       fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
                        goto raw_abort_;
                }
        }
        else {
-               if(!FLAC__file_decoder_process_whole_file(decoder)) {
-                       if(verbose) fprintf(stderr, "\n");
-                       fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
-                       goto raw_abort_;
+#ifdef FLaC__HAS_OGG
+               if(stream_info.is_ogg) {
+                       if(!FLAC__stream_decoder_process_whole_stream(stream_info.decoder.stream)) {
+                               if(stream_info.verbose) fprintf(stderr, "\n");
+                               fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", stream_info.inbasefilename, FLAC__stream_decoder_get_state(stream_info.decoder.stream), FLAC__StreamDecoderStateString[FLAC__stream_decoder_get_state(stream_info.decoder.stream)]);
+                               goto raw_abort_;
+                       }
+                       if(FLAC__stream_decoder_get_state(stream_info.decoder.stream) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && FLAC__stream_decoder_get_state(stream_info.decoder.stream) != FLAC__STREAM_DECODER_END_OF_STREAM) {
+                               if(stream_info.verbose) fprintf(stderr, "\n");
+                               fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", stream_info.inbasefilename, FLAC__stream_decoder_get_state(stream_info.decoder.stream), FLAC__StreamDecoderStateString[FLAC__stream_decoder_get_state(stream_info.decoder.stream)]);
+                               goto raw_abort_;
+                       }
                }
-               if(FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_END_OF_FILE) {
-                       if(verbose) fprintf(stderr, "\n");
-                       fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
-                       goto raw_abort_;
+               else
+#endif
+               {
+                       if(!FLAC__file_decoder_process_whole_file(stream_info.decoder.file)) {
+                               if(stream_info.verbose) fprintf(stderr, "\n");
+                               fprintf(stderr, "%s: ERROR while decoding data, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
+                               goto raw_abort_;
+                       }
+                       if(FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_END_OF_FILE) {
+                               if(stream_info.verbose) fprintf(stderr, "\n");
+                               fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", stream_info.inbasefilename, FLAC__file_decoder_get_state(stream_info.decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info.decoder.file)]);
+                               goto raw_abort_;
+                       }
                }
        }
 
-       if(decoder) {
-               if(FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_UNINITIALIZED)
-                       md5_failure = !FLAC__file_decoder_finish(decoder);
-               print_stats(&stream_info);
-               FLAC__file_decoder_delete(decoder);
+#ifdef FLaC__HAS_OGG
+       if(stream_info.is_ogg) {
+               if(stream_info.decoder.stream) {
+                       if(FLAC__stream_decoder_get_state(stream_info.decoder.stream) != FLAC__STREAM_DECODER_UNINITIALIZED)
+                               FLAC__stream_decoder_finish(stream_info.decoder.stream);
+                       md5_failure = false;
+                       print_stats(&stream_info);
+                       FLAC__stream_decoder_delete(stream_info.decoder.stream);
+               }
+       }
+       else
+#endif
+       {
+               if(stream_info.decoder.file) {
+                       if(FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_UNINITIALIZED)
+                               md5_failure = !FLAC__file_decoder_finish(stream_info.decoder.file);
+                       print_stats(&stream_info);
+                       FLAC__file_decoder_delete(stream_info.decoder.file);
+               }
        }
        if(0 != stream_info.fout && stream_info.fout != stdout)
                fclose(stream_info.fout);
+#ifdef FLaC__HAS_OGG
+       if(stream_info.is_ogg) {
+               if(0 != stream_info.fin && stream_info.fin != stdin)
+                       fclose(stream_info.fin);
+       }
+#endif
        if(analysis_mode)
                flac__analyze_finish(aopts);
        if(md5_failure) {
                fprintf(stderr, "\r%s: WARNING, MD5 signature mismatch\n", stream_info.inbasefilename);
        }
        else {
-               if(verbose)
+               if(stream_info.verbose)
                        fprintf(stderr, "\r%s: %s         \n", stream_info.inbasefilename, stream_info.test_only? "ok           ":analysis_mode?"done           ":"done");
        }
        return 0;
 raw_abort_:
-       if(decoder) {
-               if(FLAC__file_decoder_get_state(decoder) != FLAC__FILE_DECODER_UNINITIALIZED)
-                       FLAC__file_decoder_finish(decoder);
-               FLAC__file_decoder_delete(decoder);
+#ifdef FLaC__HAS_OGG
+       if(stream_info.is_ogg) {
+               if(stream_info.decoder.stream) {
+                       if(FLAC__stream_decoder_get_state(stream_info.decoder.stream) != FLAC__STREAM_DECODER_UNINITIALIZED)
+                               FLAC__stream_decoder_finish(stream_info.decoder.stream);
+                       FLAC__stream_decoder_delete(stream_info.decoder.stream);
+               }
+       }
+       else
+#endif
+       {
+               if(stream_info.decoder.file) {
+                       if(FLAC__file_decoder_get_state(stream_info.decoder.file) != FLAC__FILE_DECODER_UNINITIALIZED)
+                               FLAC__file_decoder_finish(stream_info.decoder.file);
+                       FLAC__file_decoder_delete(stream_info.decoder.file);
+               }
        }
        if(0 != stream_info.fout && stream_info.fout != stdout) {
                fclose(stream_info.fout);
                unlink(outfile);
        }
+#ifdef FLaC__HAS_OGG
+       if(stream_info.is_ogg) {
+               if(0 != stream_info.fin && stream_info.fin != stdin)
+                       fclose(stream_info.fin);
+       }
+#endif
        if(analysis_mode)
                flac__analyze_finish(aopts);
        return 1;
@@ -288,22 +477,61 @@ FLAC__bool init(const char *infilename, stream_info_struct *stream_info)
 
        is_big_endian_host = (*((FLAC__byte*)(&test)))? false : true;
 
-       decoder = FLAC__file_decoder_new();
-       if(0 == decoder) {
-               fprintf(stderr, "%s: ERROR creating the decoder instance\n", stream_info->inbasefilename);
-               return false;
+#ifdef FLaC__HAS_OGG
+       if(stream_info->is_ogg) {
+               stream_info->decoder.stream = FLAC__stream_decoder_new();
+
+               if(0 == stream_info->decoder.stream) {
+                       fprintf(stderr, "%s: ERROR creating the decoder instance\n", stream_info->inbasefilename);
+                       return false;
+               }
+
+               FLAC__stream_decoder_set_read_callback(stream_info->decoder.stream, read_callback);
+................................................................................
+               /*
+                * The three ugly casts here are to 'downcast' the 'void *' argument of
+                * the callback down to 'FLAC__StreamDecoder *'.  In C++ this would be
+                * unnecessary but here the cast makes the C compiler happy.
+                */
+               FLAC__stream_decoder_set_write_callback(stream_info->decoder.stream, (FLAC__StreamDecoderWriteStatus (*)(const FLAC__StreamDecoder *, const FLAC__Frame *, const FLAC__int32 *[], void *))write_callback);
+               FLAC__stream_decoder_set_metadata_callback(stream_info->decoder.stream, (void (*)(const FLAC__StreamDecoder *, const FLAC__StreamMetaData *, void *))metadata_callback);
+               FLAC__stream_decoder_set_error_callback(stream_info->decoder.stream, (void (*)(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus, void *))error_callback);
+               FLAC__stream_decoder_set_client_data(stream_info->decoder.stream, stream_info);
+
+               if(FLAC__stream_decoder_init(stream_info->decoder.stream) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA) {
+                       fprintf(stderr, "%s: ERROR initializing decoder, state=%d:%s\n", stream_info->inbasefilename, FLAC__stream_decoder_get_state(stream_info->decoder.stream), FLAC__StreamDecoderStateString[FLAC__stream_decoder_get_state(stream_info->decoder.stream)]);
+                       return false;
+               }
+
+               ogg_stream_init(&stream_info->ogg.os, 0);
+               ogg_sync_init(&stream_info->ogg.oy);
        }
+       else
+#endif
+       {
+               stream_info->decoder.file = FLAC__file_decoder_new();
 
-       FLAC__file_decoder_set_md5_checking(decoder, true);
-       FLAC__file_decoder_set_filename(decoder, infilename);
-       FLAC__file_decoder_set_write_callback(decoder, write_callback);
-       FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback);
-       FLAC__file_decoder_set_error_callback(decoder, error_callback);
-       FLAC__file_decoder_set_client_data(decoder, stream_info);
+               if(0 == stream_info->decoder.file) {
+                       fprintf(stderr, "%s: ERROR creating the decoder instance\n", stream_info->inbasefilename);
+                       return false;
+               }
 
-       if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) {
-               fprintf(stderr, "%s: ERROR initializing decoder, state=%d:%s\n", stream_info->inbasefilename, FLAC__file_decoder_get_state(decoder), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(decoder)]);
-               return false;
+               FLAC__file_decoder_set_md5_checking(stream_info->decoder.file, true);
+               FLAC__file_decoder_set_filename(stream_info->decoder.file, infilename);
+               /*
+                * The three ugly casts here are to 'downcast' the 'void *' argument of
+                * the callback down to 'FLAC__FileDecoder *'.  In C++ this would be
+                * unnecessary but here the cast makes the C compiler happy.
+                */
+               FLAC__file_decoder_set_write_callback(stream_info->decoder.file, (FLAC__StreamDecoderWriteStatus (*)(const FLAC__FileDecoder *, const FLAC__Frame *, const FLAC__int32 *[], void *))write_callback);
+               FLAC__file_decoder_set_metadata_callback(stream_info->decoder.file, (void (*)(const FLAC__FileDecoder *, const FLAC__StreamMetaData *, void *))metadata_callback);
+               FLAC__file_decoder_set_error_callback(stream_info->decoder.file, (void (*)(const FLAC__FileDecoder *, FLAC__StreamDecoderErrorStatus, void *))error_callback);
+               FLAC__file_decoder_set_client_data(stream_info->decoder.file, stream_info);
+
+               if(FLAC__file_decoder_init(stream_info->decoder.file) != FLAC__FILE_DECODER_OK) {
+                       fprintf(stderr, "%s: ERROR initializing decoder, state=%d:%s\n", stream_info->inbasefilename, FLAC__file_decoder_get_state(stream_info->decoder.file), FLAC__FileDecoderStateString[FLAC__file_decoder_get_state(stream_info->decoder.file)]);
+                       return false;
+               }
        }
 
        return true;
@@ -330,7 +558,56 @@ FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val)
        return fwrite(b, 1, 4, f) == 4;
 }
 
-FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
+#ifdef FLaC__HAS_OGG
+#define OGG_READ_BUFFER_SIZE 4096
+FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
+{
+       stream_info_struct *stream_info = (stream_info_struct *)client_data;
+       FILE *fin = stream_info->fin;
+       size_t bytes_read;
+       ogg_page og;
+       char *oggbuf;
+       unsigned int offset = 0;
+
+       *bytes = 0;
+
+       if (stream_info->abort_flag)
+               return FLAC__STREAM_DECODER_READ_ABORT;
+
+       oggbuf = ogg_sync_buffer(&stream_info->ogg.oy, OGG_READ_BUFFER_SIZE);
+
+       (void)decoder; /* avoid compiler warning */
+
+       if (feof(fin))
+               return FLAC__STREAM_DECODER_READ_END_OF_STREAM;
+
+       bytes_read = fread(oggbuf, 1, OGG_READ_BUFFER_SIZE, fin);
+
+       if (ferror(fin))
+               return FLAC__STREAM_DECODER_READ_ABORT;
+
+       if (ogg_sync_wrote(&stream_info->ogg.oy, bytes_read) < 0)
+               return FLAC__STREAM_DECODER_READ_ABORT;
+
+       while (ogg_sync_pageout(&stream_info->ogg.oy, &og) == 1) {
+               if (ogg_stream_pagein(&stream_info->ogg.os, &og) == 0) {
+                       ogg_packet op;
+
+                       while (ogg_stream_packetout(&stream_info->ogg.os, &op) == 1) {
+                               memcpy(buffer + offset, op.packet, op.bytes);
+                               *bytes += op.bytes;
+                               offset += op.bytes;
+                       }
+               } else {
+                       return FLAC__STREAM_DECODER_READ_ABORT;
+               }
+       }
+
+       return FLAC__STREAM_DECODER_READ_CONTINUE;
+}
+#endif
+
+FLAC__StreamDecoderWriteStatus write_callback(const void *decoder, const FLAC__Frame *frame, const FLAC__int32 *buffer[], void *client_data)
 {
        stream_info_struct *stream_info = (stream_info_struct *)client_data;
        FILE *fout = stream_info->fout;
@@ -451,7 +728,7 @@ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder,
        return FLAC__STREAM_DECODER_WRITE_CONTINUE;
 }
 
-void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
+void metadata_callback(const void *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
 {
        stream_info_struct *stream_info = (stream_info_struct *)client_data;
        (void)decoder;
@@ -497,7 +774,7 @@ void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaD
        }
 }
 
-void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+void error_callback(const void *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
 {
        stream_info_struct *stream_info = (stream_info_struct *)client_data;
        (void)decoder;
index 7b9aee3..6aff550 100644 (file)
 
 #include "analyze.h"
 
+typedef struct {
+       FLAC__bool verbose;
+#ifdef FLaC__HAS_OGG
+       FLAC__bool is_ogg;
+#endif
+       FLAC__uint64 skip;
+} decode_options_t;
+
+typedef struct {
+       decode_options_t common;
+} wav_decode_options_t;
+
+typedef struct {
+       decode_options_t common;
+
+       FLAC__bool is_big_endian;
+       FLAC__bool is_unsigned_samples;
+} raw_decode_options_t;
+
 /* outfile == 0 => test only */
-int flac__decode_wav(const char *infile, const char *outfile, FLAC__bool analysis_mode, analysis_options aopts, FLAC__bool verbose, FLAC__uint64 skip);
-int flac__decode_raw(const char *infile, const char *outfile, FLAC__bool analysis_mode, analysis_options aopts, FLAC__bool verbose, FLAC__uint64 skip, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples);
+int flac__decode_wav(const char *infile, const char *outfile, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options);
+int flac__decode_raw(const char *infile, const char *outfile, FLAC__bool analysis_mode, analysis_options aopts, raw_decode_options_t options);
 
 #endif
index 33909b0..1f0dc7e 100644 (file)
@@ -29,6 +29,9 @@
 #include "FLAC/all.h"
 #include "encode.h"
 #include "file.h"
+#ifdef FLaC__HAS_OGG
+#include "ogg/ogg.h"
+#endif
 
 #ifdef min
 #undef min
@@ -62,6 +65,13 @@ typedef struct {
        FLAC__StreamDecoder *decoder;
 } verify_fifo_struct;
 
+#ifdef FLaC__HAS_OGG
+typedef struct {
+       ogg_stream_state os;
+       ogg_page og;
+} ogg_info_struct;
+#endif
+
 typedef struct {
        const char *inbasefilename;
        FILE *fout;
@@ -78,6 +88,10 @@ typedef struct {
        verify_fifo_struct verify_fifo;
        FLAC__StreamMetaData_SeekTable seek_table;
        unsigned first_seek_point_to_check;
+       FLAC__bool use_ogg;
+#ifdef FLaC__HAS_OGG
+       ogg_info_struct ogg;
+#endif
 } encoder_wrapper_struct;
 
 static FLAC__bool is_big_endian_host;
@@ -92,7 +106,7 @@ static FLAC__int32 *input[FLAC__MAX_CHANNELS];
 
 /* local routines */
 static FLAC__bool init(encoder_wrapper_struct *encoder_wrapper);
-static FLAC__bool init_encoder(FLAC__bool lax, FLAC__bool do_mid_side, FLAC__bool loose_mid_side, FLAC__bool do_exhaustive_model_search, FLAC__bool do_escape_coding, FLAC__bool do_qlp_coeff_prec_search, unsigned min_residual_partition_order, unsigned max_residual_partition_order, unsigned rice_parameter_search_dist, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned channels, unsigned bps, unsigned sample_rate, unsigned padding, char *requested_seek_points, int num_requested_seek_points, encoder_wrapper_struct *encoder_wrapper);
+static FLAC__bool init_encoder(encode_options_t options, unsigned channels, unsigned bps, unsigned sample_rate, encoder_wrapper_struct *encoder_wrapper);
 static FLAC__bool convert_to_seek_table(char *requested_seek_points, int num_requested_seek_points, FLAC__uint64 stream_samples, unsigned blocksize, FLAC__StreamMetaData_SeekTable *seek_table);
 static void append_point_to_seek_table(FLAC__StreamMetaData_SeekTable *seek_table, FLAC__uint64 sample, FLAC__uint64 stream_samples, FLAC__uint64 blocksize);
 static int seekpoint_compare(const FLAC__StreamMetaData_SeekPoint *l, const FLAC__StreamMetaData_SeekPoint *r);
@@ -110,7 +124,7 @@ static FLAC__bool read_little_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bo
 static FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 val);
 static FLAC__bool write_big_endian_uint64(FILE *f, FLAC__uint64 val);
 
-int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, FLAC__int32 *align_reservoir[], unsigned *align_reservoir_samples, FLAC__bool sector_align, FLAC__bool is_last_file, FLAC__bool verbose, FLAC__uint64 skip, FLAC__bool verify, FLAC__bool lax, FLAC__bool do_mid_side, FLAC__bool loose_mid_side, FLAC__bool do_exhaustive_model_search, FLAC__bool do_escape_coding, FLAC__bool do_qlp_coeff_prec_search, unsigned min_residual_partition_order, unsigned max_residual_partition_order, unsigned rice_parameter_search_dist, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned padding, char *requested_seek_points, int num_requested_seek_points)
+int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options)
 {
        encoder_wrapper_struct encoder_wrapper;
        FLAC__bool is_unsigned_samples = false;
@@ -122,11 +136,11 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
        unsigned align_remainder = 0;
        int info_align_carry = -1, info_align_zero = -1;
 
-       FLAC__ASSERT(!sector_align || skip == 0);
+       FLAC__ASSERT(!options.sector_align || options.common.skip == 0);
 
        encoder_wrapper.encoder = 0;
-       encoder_wrapper.verify = verify;
-       encoder_wrapper.verbose = verbose;
+       encoder_wrapper.verify = options.common.verify;
+       encoder_wrapper.verbose = options.common.verbose;
        encoder_wrapper.bytes_written = 0;
        encoder_wrapper.samples_written = 0;
        encoder_wrapper.stream_offset = 0;
@@ -134,6 +148,9 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
        encoder_wrapper.outfilename = outfilename;
        encoder_wrapper.seek_table.points = 0;
        encoder_wrapper.first_seek_point_to_check = 0;
+#ifdef FLaC__HAS_OGG
+       encoder_wrapper.use_ogg = options.common.use_ogg;
+#endif
        (void)infilesize;
        (void)lookahead;
        (void)lookahead_length;
@@ -190,7 +207,7 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                        fprintf(stderr, "%s: ERROR: unsupported number channels %u\n", encoder_wrapper.inbasefilename, (unsigned)x);
                                        goto wav_abort_;
                                }
-                               else if(sector_align && x != 2) {
+                               else if(options.sector_align && x != 2) {
                                        fprintf(stderr, "%s: ERROR: file has %u channels, must be 2 for --sector-align\n", encoder_wrapper.inbasefilename, (unsigned)x);
                                        goto wav_abort_;
                                }
@@ -202,7 +219,7 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                        fprintf(stderr, "%s: ERROR: unsupported sample rate %u\n", encoder_wrapper.inbasefilename, (unsigned)xx);
                                        goto wav_abort_;
                                }
-                               else if(sector_align && xx != 44100) {
+                               else if(options.sector_align && xx != 44100) {
                                        fprintf(stderr, "%s: ERROR: file's sample rate is %u, must be 44100 for --sector-align\n", encoder_wrapper.inbasefilename, (unsigned)xx);
                                        goto wav_abort_;
                                }
@@ -256,16 +273,16 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
 
                                bytes_per_wide_sample = channels * (bps >> 3);
 
-                               if(skip > 0) {
+                               if(options.common.skip > 0) {
                                        if(infile != stdin) {
-                                               if(-1 == fseek(infile, bytes_per_wide_sample * (unsigned)skip, SEEK_CUR)) {
+                                               if(-1 == fseek(infile, bytes_per_wide_sample * (unsigned)options.common.skip, SEEK_CUR)) {
                                                        fprintf(stderr, "%s: ERROR during seek while skipping samples\n", encoder_wrapper.inbasefilename);
                                                        goto wav_abort_;
                                                }
                                        }
                                        else {
                                                unsigned left, need;
-                                               for(left = (unsigned)skip; left > 0; ) { /*@@@ WATCHOUT: 4GB limit */
+                                               for(left = (unsigned)options.common.skip; left > 0; ) { /*@@@ WATCHOUT: 4GB limit */
                                                        need = min(left, CHUNK_OF_SAMPLES);
                                                        if(fread(ucbuffer, bytes_per_wide_sample, need, infile) < need) {
                                                                fprintf(stderr, "%s: ERROR during read while skipping samples\n", encoder_wrapper.inbasefilename);
@@ -276,11 +293,11 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                        }
                                }
 
-                               data_bytes -= (unsigned)skip * bytes_per_wide_sample; /*@@@ WATCHOUT: 4GB limit */
-                               encoder_wrapper.total_samples_to_encode = data_bytes / bytes_per_wide_sample + *align_reservoir_samples;
-                               if(sector_align) {
+                               data_bytes -= (unsigned)options.common.skip * bytes_per_wide_sample; /*@@@ WATCHOUT: 4GB limit */
+                               encoder_wrapper.total_samples_to_encode = data_bytes / bytes_per_wide_sample + *options.align_reservoir_samples;
+                               if(options.sector_align) {
                                        align_remainder = (unsigned)(encoder_wrapper.total_samples_to_encode % 588);
-                                       if(is_last_file)
+                                       if(options.is_last_file)
                                                encoder_wrapper.total_samples_to_encode += (588-align_remainder); /* will pad with zeroes */
                                        else
                                                encoder_wrapper.total_samples_to_encode -= align_remainder; /* will stop short and carry over to next file */
@@ -289,7 +306,7 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                /* +44 for the size of the WAV headers; this is just an estimate for the progress indicator and doesn't need to be exact */
                                encoder_wrapper.unencoded_size = encoder_wrapper.total_samples_to_encode * bytes_per_wide_sample + 44;
 
-                               if(!init_encoder(lax, do_mid_side, loose_mid_side, do_exhaustive_model_search, do_escape_coding, do_qlp_coeff_prec_search, min_residual_partition_order, max_residual_partition_order, rice_parameter_search_dist, max_lpc_order, blocksize, qlp_coeff_precision, channels, bps, sample_rate, padding, requested_seek_points, num_requested_seek_points, &encoder_wrapper))
+                               if(!init_encoder(options.common, channels, bps, sample_rate, &encoder_wrapper))
                                        goto wav_abort_;
 
                                encoder_wrapper.verify_fifo.into_frames = true;
@@ -297,12 +314,12 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                /*
                                 * first do any samples in the reservoir
                                 */
-                               if(sector_align && *align_reservoir_samples > 0) {
+                               if(options.sector_align && *options.align_reservoir_samples > 0) {
                                        /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
-                                       append_to_verify_fifo(&encoder_wrapper, align_reservoir, channels, *align_reservoir_samples);
+                                       append_to_verify_fifo(&encoder_wrapper, options.align_reservoir, channels, *options.align_reservoir_samples);
 
                                        /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
-                                       if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, align_reservoir, *align_reservoir_samples)) {
+                                       if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, options.align_reservoir, *options.align_reservoir_samples)) {
                                                fprintf(stderr, "%s: ERROR during encoding, state = %d:%s\n", encoder_wrapper.inbasefilename, FLAC__stream_encoder_get_state(encoder_wrapper.encoder), FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder_wrapper.encoder)]);
                                                goto wav_abort_;
                                        }
@@ -311,13 +328,13 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                /*
                                 * decrement the data_bytes counter if we need to align the file
                                 */
-                               if(sector_align) {
-                                       if(is_last_file) {
-                                               *align_reservoir_samples = 0;
+                               if(options.sector_align) {
+                                       if(options.is_last_file) {
+                                               *options.align_reservoir_samples = 0;
                                        }
                                        else {
-                                               *align_reservoir_samples = align_remainder;
-                                               data_bytes -= (*align_reservoir_samples) * bytes_per_wide_sample;
+                                               *options.align_reservoir_samples = align_remainder;
+                                               data_bytes -= (*options.align_reservoir_samples) * bytes_per_wide_sample;
                                        }
                                }
 
@@ -358,8 +375,8 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                /*
                                 * now read unaligned samples into reservoir or pad with zeroes if necessary
                                 */
-                               if(sector_align) {
-                                       if(is_last_file) {
+                               if(options.sector_align) {
+                                       if(options.is_last_file) {
                                                unsigned wide_samples = 588 - align_remainder;
                                                if(wide_samples < 588) {
                                                        unsigned channel;
@@ -379,20 +396,20 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                                }
                                        }
                                        else {
-                                               if(*align_reservoir_samples > 0) {
+                                               if(*options.align_reservoir_samples > 0) {
                                                        FLAC__ASSERT(CHUNK_OF_SAMPLES >= 588);
-                                                       bytes_read = fread(ucbuffer, sizeof(unsigned char), (*align_reservoir_samples) * bytes_per_wide_sample, infile);
+                                                       bytes_read = fread(ucbuffer, sizeof(unsigned char), (*options.align_reservoir_samples) * bytes_per_wide_sample, infile);
                                                        if(bytes_read == 0 && ferror(infile)) {
                                                                fprintf(stderr, "%s: ERROR during read\n", encoder_wrapper.inbasefilename);
                                                                goto wav_abort_;
                                                        }
-                                                       else if(bytes_read != (*align_reservoir_samples) * bytes_per_wide_sample) {
+                                                       else if(bytes_read != (*options.align_reservoir_samples) * bytes_per_wide_sample) {
                                                                fprintf(stderr, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_wrapper.inbasefilename, (unsigned)encoder_wrapper.total_samples_to_encode, (unsigned)encoder_wrapper.samples_written);
                                                                data_bytes = 0;
                                                        }
                                                        else {
-                                                               info_align_carry = *align_reservoir_samples;
-                                                               format_input(align_reservoir, *align_reservoir_samples, false, is_unsigned_samples, channels, bps, &encoder_wrapper);
+                                                               info_align_carry = *options.align_reservoir_samples;
+                                                               format_input(options.align_reservoir, *options.align_reservoir_samples, false, is_unsigned_samples, channels, bps, &encoder_wrapper);
                                                        }
                                                }
                                        }
@@ -431,6 +448,10 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                if(FLAC__stream_encoder_get_state(encoder_wrapper.encoder) == FLAC__STREAM_ENCODER_OK)
                        FLAC__stream_encoder_finish(encoder_wrapper.encoder);
                FLAC__stream_encoder_delete(encoder_wrapper.encoder);
+#ifdef FLaC__HAS_OGG
+               if(use_ogg)
+                       ogg_stream_clear(&encoder_wrapper.ogg.os);
+#endif
        }
        if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode > 0) {
                print_stats(&encoder_wrapper);
@@ -438,7 +459,7 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
        }
        if(0 != encoder_wrapper.seek_table.points)
                free(encoder_wrapper.seek_table.points);
-       if(verify) {
+       if(options.common.verify) {
                FLAC__stream_decoder_finish(encoder_wrapper.verify_fifo.decoder);
                FLAC__stream_decoder_delete(encoder_wrapper.verify_fifo.decoder);
                if(encoder_wrapper.verify_fifo.result != FLAC__VERIFY_OK) {
@@ -460,10 +481,14 @@ wav_abort_:
                if(FLAC__stream_encoder_get_state(encoder_wrapper.encoder) == FLAC__STREAM_ENCODER_OK)
                        FLAC__stream_encoder_finish(encoder_wrapper.encoder);
                FLAC__stream_encoder_delete(encoder_wrapper.encoder);
+#ifdef FLaC__HAS_OGG
+               if(use_ogg)
+                       ogg_stream_clear(&encoder_wrapper.ogg.os);
+#endif
        }
        if(0 != encoder_wrapper.seek_table.points)
                free(encoder_wrapper.seek_table.points);
-       if(verify) {
+       if(options.common.verify) {
                FLAC__stream_decoder_finish(encoder_wrapper.verify_fifo.decoder);
                FLAC__stream_decoder_delete(encoder_wrapper.verify_fifo.decoder);
                if(encoder_wrapper.verify_fifo.result != FLAC__VERIFY_OK) {
@@ -477,17 +502,15 @@ wav_abort_:
        return 1;
 }
 
-int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, FLAC__bool is_last_file, FLAC__bool verbose, FLAC__uint64 skip, FLAC__bool verify, FLAC__bool lax, FLAC__bool do_mid_side, FLAC__bool loose_mid_side, FLAC__bool do_exhaustive_model_search, FLAC__bool do_escape_coding, FLAC__bool do_qlp_coeff_prec_search, unsigned min_residual_partition_order, unsigned max_residual_partition_order, unsigned rice_parameter_search_dist, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned padding, char *requested_seek_points, int num_requested_seek_points, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, unsigned channels, unsigned bps, unsigned sample_rate)
+int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, raw_encode_options_t options)
 {
        encoder_wrapper_struct encoder_wrapper;
        size_t bytes_read;
-       const size_t bytes_per_wide_sample = channels * (bps >> 3);
-
-       (void)is_last_file;
+       const size_t bytes_per_wide_sample = options.channels * (options.bps >> 3);
 
        encoder_wrapper.encoder = 0;
-       encoder_wrapper.verify = verify;
-       encoder_wrapper.verbose = verbose;
+       encoder_wrapper.verify = options.common.verify;
+       encoder_wrapper.verbose = options.common.verbose;
        encoder_wrapper.bytes_written = 0;
        encoder_wrapper.samples_written = 0;
        encoder_wrapper.stream_offset = 0;
@@ -495,6 +518,9 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
        encoder_wrapper.outfilename = outfilename;
        encoder_wrapper.seek_table.points = 0;
        encoder_wrapper.first_seek_point_to_check = 0;
+#ifdef FLaC__HAS_OGG
+       encoder_wrapper.use_ogg = use_ogg;
+#endif
 
        if(0 == strcmp(outfilename, "-")) {
                encoder_wrapper.fout = stdout;
@@ -515,15 +541,15 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
                encoder_wrapper.total_samples_to_encode = encoder_wrapper.unencoded_size = 0;
        }
        else {
-               encoder_wrapper.total_samples_to_encode = (unsigned)infilesize / bytes_per_wide_sample - skip;
+               encoder_wrapper.total_samples_to_encode = (unsigned)infilesize / bytes_per_wide_sample - options.common.skip;
                encoder_wrapper.unencoded_size = encoder_wrapper.total_samples_to_encode * bytes_per_wide_sample;
        }
 
        if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode <= 0)
                fprintf(stderr, "(No runtime statistics possible; please wait for encoding to finish...)\n");
 
-       if(skip > 0) {
-               unsigned skip_bytes = bytes_per_wide_sample * (unsigned)skip;
+       if(options.common.skip > 0) {
+               unsigned skip_bytes = bytes_per_wide_sample * (unsigned)options.common.skip;
                if(skip_bytes > lookahead_length) {
                        skip_bytes -= lookahead_length;
                        lookahead_length = 0;
@@ -552,7 +578,7 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
                }
        }
 
-       if(!init_encoder(lax, do_mid_side, loose_mid_side, do_exhaustive_model_search, do_escape_coding, do_qlp_coeff_prec_search, min_residual_partition_order, max_residual_partition_order, rice_parameter_search_dist, max_lpc_order, blocksize, qlp_coeff_precision, channels, bps, sample_rate, padding, requested_seek_points, num_requested_seek_points, &encoder_wrapper))
+       if(!init_encoder(options.common, options.channels, options.bps, options.sample_rate, &encoder_wrapper))
                goto raw_abort_;
 
        encoder_wrapper.verify_fifo.into_frames = true;
@@ -583,7 +609,7 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
                }
                else {
                        unsigned wide_samples = bytes_read / bytes_per_wide_sample;
-                       format_input(input, wide_samples, is_big_endian, is_unsigned_samples, channels, bps, &encoder_wrapper);
+                       format_input(input, wide_samples, options.is_big_endian, options.is_unsigned_samples, options.channels, options.bps, &encoder_wrapper);
 
                        /* NOTE: some versions of GCC can't figure out const-ness right and will give you an 'incompatible pointer type' warning on arg 2 here: */
                        if(!FLAC__stream_encoder_process(encoder_wrapper.encoder, input, wide_samples)) {
@@ -597,6 +623,10 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
                if(FLAC__stream_encoder_get_state(encoder_wrapper.encoder) == FLAC__STREAM_ENCODER_OK)
                        FLAC__stream_encoder_finish(encoder_wrapper.encoder);
                FLAC__stream_encoder_delete(encoder_wrapper.encoder);
+#ifdef FLaC__HAS_OGG
+               if(use_ogg)
+                       ogg_stream_clear(&encoder_wrapper.ogg.os);
+#endif
        }
        if(encoder_wrapper.verbose && encoder_wrapper.total_samples_to_encode > 0) {
                print_stats(&encoder_wrapper);
@@ -604,7 +634,7 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
        }
        if(0 != encoder_wrapper.seek_table.points)
                free(encoder_wrapper.seek_table.points);
-       if(verify) {
+       if(options.common.verify) {
                FLAC__stream_decoder_finish(encoder_wrapper.verify_fifo.decoder);
                FLAC__stream_decoder_delete(encoder_wrapper.verify_fifo.decoder);
                if(encoder_wrapper.verify_fifo.result != FLAC__VERIFY_OK) {
@@ -622,10 +652,14 @@ raw_abort_:
                if(FLAC__stream_encoder_get_state(encoder_wrapper.encoder) == FLAC__STREAM_ENCODER_OK)
                        FLAC__stream_encoder_finish(encoder_wrapper.encoder);
                FLAC__stream_encoder_delete(encoder_wrapper.encoder);
+#ifdef FLaC__HAS_OGG
+               if(use_ogg)
+                       ogg_stream_clear(&encoder_wrapper.ogg.os);
+#endif
        }
        if(0 != encoder_wrapper.seek_table.points)
                free(encoder_wrapper.seek_table.points);
-       if(verify) {
+       if(options.common.verify) {
                FLAC__stream_decoder_finish(encoder_wrapper.verify_fifo.decoder);
                FLAC__stream_decoder_delete(encoder_wrapper.verify_fifo.decoder);
                if(encoder_wrapper.verify_fifo.result != FLAC__VERIFY_OK) {
@@ -655,19 +689,29 @@ FLAC__bool init(encoder_wrapper_struct *encoder_wrapper)
                return false;
        }
 
+#ifdef FLaC__HAS_OGG
+       if(encoder_wrapper->use_ogg) {
+               if(ogg_stream_init(&encoder_wrapper->ogg.os, 0) != 0) {
+                       fprintf(stderr, "%s: ERROR initializing the Ogg stream\n", encoder_wrapper->inbasefilename);
+                       FLAC__stream_encoder_delete(encoder_wrapper->encoder);
+                       return false;
+               }
+       }
+#endif
+
        return true;
 }
 
-FLAC__bool init_encoder(FLAC__bool lax, FLAC__bool do_mid_side, FLAC__bool loose_mid_side, FLAC__bool do_exhaustive_model_search, FLAC__bool do_escape_coding, FLAC__bool do_qlp_coeff_prec_search, unsigned min_residual_partition_order, unsigned max_residual_partition_order, unsigned rice_parameter_search_dist, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned channels, unsigned bps, unsigned sample_rate, unsigned padding, char *requested_seek_points, int num_requested_seek_points, encoder_wrapper_struct *encoder_wrapper)
+FLAC__bool init_encoder(encode_options_t options, unsigned channels, unsigned bps, unsigned sample_rate, encoder_wrapper_struct *encoder_wrapper)
 {
        unsigned i;
 
        if(channels != 2)
-               do_mid_side = loose_mid_side = false;
+               options.do_mid_side = options.loose_mid_side = false;
 
        if(encoder_wrapper->verify) {
                /* set up the fifo which will hold the original signal to compare against */
-               encoder_wrapper->verify_fifo.size = blocksize + CHUNK_OF_SAMPLES;
+               encoder_wrapper->verify_fifo.size = options.blocksize + CHUNK_OF_SAMPLES;
                for(i = 0; i < channels; i++) {
                        if(0 == (encoder_wrapper->verify_fifo.original[i] = (FLAC__int32*)malloc(sizeof(FLAC__int32) * encoder_wrapper->verify_fifo.size))) {
                                fprintf(stderr, "%s: ERROR allocating verify buffers\n", encoder_wrapper->inbasefilename);
@@ -695,29 +739,29 @@ FLAC__bool init_encoder(FLAC__bool lax, FLAC__bool do_mid_side, FLAC__bool loose
                }
        }
 
-       if(!convert_to_seek_table(requested_seek_points, num_requested_seek_points, encoder_wrapper->total_samples_to_encode, blocksize, &encoder_wrapper->seek_table)) {
+       if(!convert_to_seek_table(options.requested_seek_points, options.num_requested_seek_points, encoder_wrapper->total_samples_to_encode, options.blocksize, &encoder_wrapper->seek_table)) {
                fprintf(stderr, "%s: ERROR allocating seek table\n", encoder_wrapper->inbasefilename);
                return false;
        }
 
-       FLAC__stream_encoder_set_streamable_subset(encoder_wrapper->encoder, !lax);
-       FLAC__stream_encoder_set_do_mid_side_stereo(encoder_wrapper->encoder, do_mid_side);
-       FLAC__stream_encoder_set_loose_mid_side_stereo(encoder_wrapper->encoder, loose_mid_side);
+       FLAC__stream_encoder_set_streamable_subset(encoder_wrapper->encoder, !options.lax);
+       FLAC__stream_encoder_set_do_mid_side_stereo(encoder_wrapper->encoder, options.do_mid_side);
+       FLAC__stream_encoder_set_loose_mid_side_stereo(encoder_wrapper->encoder, options.loose_mid_side);
        FLAC__stream_encoder_set_channels(encoder_wrapper->encoder, channels);
        FLAC__stream_encoder_set_bits_per_sample(encoder_wrapper->encoder, bps);
        FLAC__stream_encoder_set_sample_rate(encoder_wrapper->encoder, sample_rate);
-       FLAC__stream_encoder_set_blocksize(encoder_wrapper->encoder, blocksize);
-       FLAC__stream_encoder_set_max_lpc_order(encoder_wrapper->encoder, max_lpc_order);
-       FLAC__stream_encoder_set_qlp_coeff_precision(encoder_wrapper->encoder, qlp_coeff_precision);
-       FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder_wrapper->encoder, do_qlp_coeff_prec_search);
-       FLAC__stream_encoder_set_do_escape_coding(encoder_wrapper->encoder, do_escape_coding);
-       FLAC__stream_encoder_set_do_exhaustive_model_search(encoder_wrapper->encoder, do_exhaustive_model_search);
-       FLAC__stream_encoder_set_min_residual_partition_order(encoder_wrapper->encoder, min_residual_partition_order);
-       FLAC__stream_encoder_set_max_residual_partition_order(encoder_wrapper->encoder, max_residual_partition_order);
-       FLAC__stream_encoder_set_rice_parameter_search_dist(encoder_wrapper->encoder, rice_parameter_search_dist);
+       FLAC__stream_encoder_set_blocksize(encoder_wrapper->encoder, options.blocksize);
+       FLAC__stream_encoder_set_max_lpc_order(encoder_wrapper->encoder, options.max_lpc_order);
+       FLAC__stream_encoder_set_qlp_coeff_precision(encoder_wrapper->encoder, options.qlp_coeff_precision);
+       FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder_wrapper->encoder, options.do_qlp_coeff_prec_search);
+       FLAC__stream_encoder_set_do_escape_coding(encoder_wrapper->encoder, options.do_escape_coding);
+       FLAC__stream_encoder_set_do_exhaustive_model_search(encoder_wrapper->encoder, options.do_exhaustive_model_search);
+       FLAC__stream_encoder_set_min_residual_partition_order(encoder_wrapper->encoder, options.min_residual_partition_order);
+       FLAC__stream_encoder_set_max_residual_partition_order(encoder_wrapper->encoder, options.max_residual_partition_order);
+       FLAC__stream_encoder_set_rice_parameter_search_dist(encoder_wrapper->encoder, options.rice_parameter_search_dist);
        FLAC__stream_encoder_set_total_samples_estimate(encoder_wrapper->encoder, encoder_wrapper->total_samples_to_encode);
        FLAC__stream_encoder_set_seek_table(encoder_wrapper->encoder, (encoder_wrapper->seek_table.num_points > 0)? &encoder_wrapper->seek_table : 0);
-       FLAC__stream_encoder_set_padding(encoder_wrapper->encoder, padding);
+       FLAC__stream_encoder_set_padding(encoder_wrapper->encoder, options.padding);
        FLAC__stream_encoder_set_last_metadata_is_last(encoder_wrapper->encoder, true);
        FLAC__stream_encoder_set_write_callback(encoder_wrapper->encoder, write_callback);
        FLAC__stream_encoder_set_metadata_callback(encoder_wrapper->encoder, metadata_callback);
@@ -983,10 +1027,44 @@ FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder
                }
        }
 
-       if(fwrite(buffer, sizeof(FLAC__byte), bytes, encoder_wrapper->fout) == bytes)
+#ifdef FLaC__HAS_OGG
+       if(encoder_wrapper->use_ogg) {
+               ogg_packet op;
+
+               memset(&op, 0, sizeof(op));
+               op.packet = (unsigned char *)buffer;
+               op.packetno = encoder_wrapper->current_frame;
+               op.bytes = bytes;
+
+               if (encoder_wrapper->bytes_written == bytes)
+                       op.b_o_s = 1;
+
+               if (encoder_wrapper->total_samples_to_encode == encoder_wrapper->samples_written)
+                       op.e_o_s = 1;
+
+               ogg_stream_packetin(&encoder_wrapper->ogg.os, &op);
+
+               while(ogg_stream_pageout(&encoder_wrapper->ogg.os, &encoder_wrapper->ogg.og) != 0) {
+                       int written;
+                       written = fwrite(encoder_wrapper->ogg.og.header, 1, encoder_wrapper->ogg.og.header_len, encoder_wrapper->fout);
+                       if (written != encoder_wrapper->ogg.og.header_len)
+                               return FLAC__STREAM_ENCODER_WRITE_FATAL_ERROR;
+
+                       written = fwrite(encoder_wrapper->ogg.og.body, 1, encoder_wrapper->ogg.og.body_len, encoder_wrapper->fout);
+                       if (written != encoder_wrapper->ogg.og.body_len)
+                               return FLAC__STREAM_ENCODER_WRITE_FATAL_ERROR;
+               }
+
                return FLAC__STREAM_ENCODER_WRITE_OK;
+       }
        else
-               return FLAC__STREAM_ENCODER_WRITE_FATAL_ERROR;
+#endif
+       {
+               if(fwrite(buffer, sizeof(FLAC__byte), bytes, encoder_wrapper->fout) == bytes)
+                       return FLAC__STREAM_ENCODER_WRITE_OK;
+               else
+                       return FLAC__STREAM_ENCODER_WRITE_FATAL_ERROR;
+       }
 }
 
 void metadata_callback(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetaData *metadata, void *client_data)
@@ -1001,6 +1079,15 @@ void metadata_callback(const FLAC__StreamEncoder *encoder, const FLAC__StreamMet
        FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
 
        /*
+        * If we are writing to an ogg stream, there is no need to go back
+        * and update the STREAMINFO or SEEKTABLE blocks; the values we would
+        * update are not necessary with Ogg as the transport.  We can't do
+        * it reliably anyway without knowing the Ogg structure.
+        */
+       if(encoder_wrapper->use_ogg)
+               return;
+
+       /*
         * we get called by the encoder when the encoding process has
         * finished so that we can update the STREAMINFO and SEEKTABLE
         * blocks.
index 72335e0..8ac26f8 100644 (file)
 
 #include "FLAC/ordinals.h"
 
-int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, FLAC__int32 *align_reservoir[], unsigned *align_reservoir_samples, FLAC__bool sector_align, FLAC__bool is_last_file, FLAC__bool verbose, FLAC__uint64 skip, FLAC__bool verify, FLAC__bool lax, FLAC__bool do_mid_side, FLAC__bool loose_mid_side, FLAC__bool do_exhaustive_model_search, FLAC__bool do_escape_coding, FLAC__bool do_qlp_coeff_prec_search, unsigned min_residual_partition_order, unsigned max_residual_partition_order, unsigned rice_parameter_search_dist, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned padding, char *requested_seek_points, int num_requested_seek_points);
-int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, FLAC__bool is_last_file, FLAC__bool verbose, FLAC__uint64 skip, FLAC__bool verify, FLAC__bool lax, FLAC__bool do_mid_side, FLAC__bool loose_mid_side, FLAC__bool do_exhaustive_model_search, FLAC__bool do_escape_coding, FLAC__bool do_qlp_coeff_prec_search, unsigned min_residual_partition_order, unsigned max_residual_partition_order, unsigned rice_parameter_search_dist, unsigned max_lpc_order, unsigned blocksize, unsigned qlp_coeff_precision, unsigned padding, char *requested_seek_points, int num_requested_seek_points, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, unsigned channels, unsigned bps, unsigned sample_rate);
+typedef struct {
+       FLAC__bool verbose;
+       FLAC__uint64 skip;
+       FLAC__bool verify;
+#ifdef FLaC__HAS_OGG
+       FLAC__bool use_ogg;
+#endif
+       FLAC__bool lax;
+       FLAC__bool do_mid_side;
+       FLAC__bool loose_mid_side;
+       FLAC__bool do_exhaustive_model_search;
+       FLAC__bool do_escape_coding;
+       FLAC__bool do_qlp_coeff_prec_search;
+       unsigned min_residual_partition_order;
+       unsigned max_residual_partition_order;
+       unsigned rice_parameter_search_dist;
+       unsigned max_lpc_order;
+       unsigned blocksize;
+       unsigned qlp_coeff_precision;
+       unsigned padding;
+       char *requested_seek_points;
+       int num_requested_seek_points;
+} encode_options_t;
+
+typedef struct {
+       encode_options_t common;
+
+       FLAC__bool is_last_file;
+       FLAC__int32 **align_reservoir;
+       unsigned *align_reservoir_samples;
+       FLAC__bool sector_align;
+} wav_encode_options_t;
+
+typedef struct {
+       encode_options_t common;
+
+       FLAC__bool is_big_endian;
+       FLAC__bool is_unsigned_samples;
+       unsigned channels;
+       unsigned bps;
+       unsigned sample_rate;
+} raw_encode_options_t;
+
+int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options);
+int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, raw_encode_options_t options);
 
 #endif
index fee9d9b..f284bba 100644 (file)
@@ -37,7 +37,7 @@ static int usage(const char *message, ...);
 static int encode_file(const char *infilename, const char *forced_outfilename, FLAC__bool is_last_file);
 static int decode_file(const char *infilename, const char *forced_outfilename);
 
-FLAC__bool verify = false, verbose = true, lax = false, test_only = false, analyze = false;
+FLAC__bool verify = false, verbose = true, lax = false, test_only = false, analyze = false, use_ogg = false;
 FLAC__bool do_mid_side = true, loose_mid_side = false, do_exhaustive_model_search = false, do_escape_coding = false, do_qlp_coeff_prec_search = false;
 FLAC__bool force_to_stdout = false, delete_input = false, sector_align = false;
 const char *cmdline_forced_outfilename = 0, *output_prefix = 0;
@@ -55,6 +55,8 @@ FLAC__int32 align_reservoir_0[588], align_reservoir_1[588]; /* for carrying over
 FLAC__int32 *align_reservoir[2] = { align_reservoir_0, align_reservoir_1 };
 unsigned align_reservoir_samples = 0; /* 0 .. 587 */
 
+static const char *flac_suffix = ".flac", *ogg_suffix = ".ogg";
+
 int main(int argc, char *argv[])
 {
        int i, retval = 0;
@@ -110,6 +112,12 @@ int main(int argc, char *argv[])
                        lax = true;
                else if(0 == strcmp(argv[i], "--lax-"))
                        lax = false;
+#ifdef FLaC__HAS_OGG
+               else if(0 == strcmp(argv[i], "--ogg"))
+                       use_ogg = true;
+               else if(0 == strcmp(argv[i], "--ogg-"))
+                       use_ogg = false;
+#endif
                else if(0 == strcmp(argv[i], "-b"))
                        blocksize = atoi(argv[++i]);
                else if(0 == strcmp(argv[i], "-e"))
@@ -371,8 +379,17 @@ int main(int argc, char *argv[])
                fprintf(stderr, "welcome to redistribute it under certain conditions.  Type `flac' for details.\n\n");
 
                if(!mode_decode) {
-                       fprintf(stderr, "options:%s%s%s -P %u -b %u%s -l %u%s%s%s -q %u -r %u,%u -R %u%s\n",
-                               delete_input?" --delete-input-file":"", sector_align?" --sector-align":"", lax?" --lax":"",
+                       fprintf(stderr,
+                               "options:%s%s"
+#ifdef FLaC__HAS_OGG
+                               "%s"
+#endif
+                               "%s -P %u -b %u%s -l %u%s%s%s -q %u -r %u,%u -R %u%s\n",
+                               delete_input?" --delete-input-file":"", sector_align?" --sector-align":"",
+#ifdef FLaC__HAS_OGG
+                               ogg?" --ogg":"",
+#endif
+                               lax?" --lax":"",
                                padding, (unsigned)blocksize, loose_mid_side?" -M":do_mid_side?" -m":"", max_lpc_order,
                                do_exhaustive_model_search?" -e":"", do_escape_coding?" -E":"", do_qlp_coeff_prec_search?" -p":"",
                                qlp_coeff_precision,
@@ -492,6 +509,9 @@ int usage(const char *message, ...)
        fprintf(stderr, "  --a-rtext : include residual signal in text output\n");
        fprintf(stderr, "  --a-rgp : generate gnuplot files of residual distribution of each subframe\n");
        fprintf(stderr, "encoding options:\n");
+#ifdef FLaC__HAS_OGG
+       fprintf(stderr, "  --ogg : output Ogg-FLAC stream instead of native FLAC\n");
+#endif
        fprintf(stderr, "  --lax : allow encoder to generate non-Subset files\n");
        fprintf(stderr, "  --sector-align : align encoding of multiple files on sector boundaries\n");
        fprintf(stderr, "  -S { # | X | #x } : include a point or points in a SEEKTABLE\n");
@@ -538,7 +558,13 @@ int usage(const char *message, ...)
        fprintf(stderr, "  -R # : Rice parameter search distance (# is 0..32; above 2 doesn't help much)\n");
        fprintf(stderr, "  -V   : verify a correct encoding by decoding the output in parallel and\n");
        fprintf(stderr, "         comparing to the original\n");
-       fprintf(stderr, "  -S-, -m-, -M-, -e-, -E-, -p-, -V-, --delete-input-file-, --lax-, --sector-align-\n");
+       fprintf(stderr, "  -S-, -m-, -M-, -e-, -E-, -p-, -V-, --delete-input-file-,%s --lax-, --sector-align-\n",
+#ifdef FLaC__HAS_OGG
+               " --ogg-,"
+#else
+               ""
+#endif
+       );
        fprintf(stderr, "  can all be used to turn off a particular option\n");
        fprintf(stderr, "format options:\n");
        fprintf(stderr, "  -fb | -fl : big-endian | little-endian byte order\n");
@@ -561,6 +587,7 @@ int encode_file(const char *infilename, const char *forced_outfilename, FLAC__bo
        unsigned lookahead_length = 0;
        int retval;
        long infilesize;
+       encode_options_t common_options;
 
        if(0 == strcmp(infilename, "-")) {
                infilesize = -1;
@@ -611,15 +638,18 @@ int encode_file(const char *infilename, const char *forced_outfilename, FLAC__bo
        if(encode_infile == stdin || force_to_stdout)
                strcpy(outfilename, "-");
        else {
+               const char *suffix = (use_ogg? ogg_suffix : flac_suffix);
                strcpy(outfilename, output_prefix? output_prefix : "");
                strcat(outfilename, infilename);
                if(0 == (p = strrchr(outfilename, '.')))
-                       strcat(outfilename, ".flac");
+                       strcat(outfilename, suffix);
                else {
-                       if(0 == strcmp(p, ".flac"))
-                               strcpy(p, "_new.flac");
+                       if(0 == strcmp(p, suffix)) {
+                               strcpy(p, "_new");
+                               strcat(p, suffix);
+                       }
                        else
-                               strcpy(p, ".flac");
+                               strcpy(p, suffix);
                }
        }
        if(0 == forced_outfilename)
@@ -627,10 +657,51 @@ int encode_file(const char *infilename, const char *forced_outfilename, FLAC__bo
        if(0 != cmdline_forced_outfilename)
                forced_outfilename = cmdline_forced_outfilename;
 
-       if(format_is_wave)
-               retval = flac__encode_wav(encode_infile, infilesize, infilename, forced_outfilename, lookahead, lookahead_length, align_reservoir, &align_reservoir_samples, sector_align, is_last_file, verbose, skip, verify, lax, do_mid_side, loose_mid_side, do_exhaustive_model_search, do_escape_coding, do_qlp_coeff_prec_search, min_residual_partition_order, max_residual_partition_order, rice_parameter_search_dist, max_lpc_order, (unsigned)blocksize, qlp_coeff_precision, padding, requested_seek_points, num_requested_seek_points);
-       else
-               retval = flac__encode_raw(encode_infile, infilesize, infilename, forced_outfilename, lookahead, lookahead_length, is_last_file, verbose, skip, verify, lax, do_mid_side, loose_mid_side, do_exhaustive_model_search, do_escape_coding, do_qlp_coeff_prec_search, min_residual_partition_order, max_residual_partition_order, rice_parameter_search_dist, max_lpc_order, (unsigned)blocksize, qlp_coeff_precision, padding, requested_seek_points, num_requested_seek_points, format_is_big_endian, format_is_unsigned_samples, format_channels, format_bps, format_sample_rate);
+       common_options.verbose = verbose;
+       common_options.skip = skip;
+       common_options.verify = verify;
+#ifdef FLaC__HAS_OGG
+       common_options.use_ogg = use_ogg;
+#endif
+       common_options.lax = lax;
+       common_options.do_mid_side = do_mid_side;
+       common_options.loose_mid_side = loose_mid_side;
+       common_options.do_exhaustive_model_search = do_exhaustive_model_search;
+       common_options.do_escape_coding = do_escape_coding;
+       common_options.do_qlp_coeff_prec_search = do_qlp_coeff_prec_search;
+       common_options.min_residual_partition_order = min_residual_partition_order;
+       common_options.max_residual_partition_order = max_residual_partition_order;
+       common_options.rice_parameter_search_dist = rice_parameter_search_dist;
+       common_options.max_lpc_order = max_lpc_order;
+       common_options.blocksize = (unsigned)blocksize;
+       common_options.qlp_coeff_precision = qlp_coeff_precision;
+       common_options.padding = padding;
+       common_options.requested_seek_points = requested_seek_points;
+       common_options.num_requested_seek_points = num_requested_seek_points;
+
+       if(format_is_wave) {
+               wav_encode_options_t options;
+
+               options.common = common_options;
+               options.is_last_file = is_last_file;
+               options.align_reservoir = align_reservoir;
+               options.align_reservoir_samples = &align_reservoir_samples;
+               options.sector_align = sector_align;
+
+               retval = flac__encode_wav(encode_infile, infilesize, infilename, forced_outfilename, lookahead, lookahead_length, options);
+       }
+       else {
+               raw_encode_options_t options;
+
+               options.common = common_options;
+               options.is_big_endian = format_is_big_endian;
+               options.is_unsigned_samples = format_is_unsigned_samples;
+               options.channels = format_channels;
+               options.bps = format_bps;
+               options.sample_rate = format_sample_rate;
+
+               retval = flac__encode_raw(encode_infile, infilesize, infilename, forced_outfilename, lookahead, lookahead_length, options);
+       }
 
        if(retval == 0 && strcmp(infilename, "-")) {
                if(strcmp(forced_outfilename, "-"))
@@ -648,6 +719,7 @@ int decode_file(const char *infilename, const char *forced_outfilename)
        char outfilename[4096]; /* @@@ bad MAGIC NUMBER */
        char *p;
        int retval;
+       decode_options_t common_options;
 
        if(!test_only && !analyze) {
                if(format_is_wave < 0) {
@@ -681,10 +753,28 @@ int decode_file(const char *infilename, const char *forced_outfilename)
        if(0 != cmdline_forced_outfilename)
                forced_outfilename = cmdline_forced_outfilename;
 
-       if(format_is_wave)
-               retval = flac__decode_wav(infilename, test_only? 0 : forced_outfilename, analyze, aopts, verbose, skip);
-       else
-               retval = flac__decode_raw(infilename, test_only? 0 : forced_outfilename, analyze, aopts, verbose, skip, format_is_big_endian, format_is_unsigned_samples);
+       common_options.verbose = verbose;
+#ifdef FLaC__HAS_OGG
+       common_options.is_ogg = is_ogg;
+#endif
+       common_options.skip = skip;
+
+       if(format_is_wave) {
+               wav_decode_options_t options;
+
+               options.common = common_options;
+
+               retval = flac__decode_wav(infilename, test_only? 0 : forced_outfilename, analyze, aopts, options);
+       }
+       else {
+               raw_decode_options_t options;
+
+               options.common = common_options;
+               options.is_big_endian = format_is_big_endian;
+               options.is_unsigned_samples = format_is_unsigned_samples;
+
+               retval = flac__decode_raw(infilename, test_only? 0 : forced_outfilename, analyze, aopts, options);
+       }
 
        if(retval == 0 && strcmp(infilename, "-")) {
                if(strcmp(forced_outfilename, "-"))