From f7fc5c89e8d51edd8cbd06a8c9e81872f92f2e8e Mon Sep 17 00:00:00 2001 From: Josh Coalson Date: Wed, 31 Oct 2001 18:31:36 +0000 Subject: [PATCH] add support for writing ogg streams --- configure.in | 3 + src/flac/Makefile.am | 5 + src/flac/Makefile.lite | 6 +- src/flac/decode.c | 453 +++++++++++++++++++++++++++++++++-------- src/flac/decode.h | 23 ++- src/flac/encode.c | 215 +++++++++++++------ src/flac/encode.h | 47 ++++- src/flac/main.c | 122 +++++++++-- 8 files changed, 700 insertions(+), 174 deletions(-) diff --git a/configure.in b/configure.in index 206b1ffa..1c8ecc08 100644 --- a/configure.in +++ b/configure.in @@ -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) diff --git a/src/flac/Makefile.am b/src/flac/Makefile.am index cefea827..21be192c 100644 --- a/src/flac/Makefile.am +++ b/src/flac/Makefile.am @@ -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 diff --git a/src/flac/Makefile.lite b/src/flac/Makefile.lite index 40b55fa2..0414ae22 100644 --- a/src/flac/Makefile.lite +++ b/src/flac/Makefile.lite @@ -20,8 +20,10 @@ # 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 \ diff --git a/src/flac/decode.c b/src/flac/decode.c index 79f738ff..ed0972a3 100644 --- a/src/flac/decode.c +++ b/src/flac/decode.c @@ -28,9 +28,22 @@ #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; diff --git a/src/flac/decode.h b/src/flac/decode.h index 7b9aee33..6aff5507 100644 --- a/src/flac/decode.h +++ b/src/flac/decode.h @@ -21,8 +21,27 @@ #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 diff --git a/src/flac/encode.c b/src/flac/encode.c index 33909b0c..1f0dc7e7 100644 --- a/src/flac/encode.c +++ b/src/flac/encode.c @@ -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) @@ -1000,6 +1078,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 diff --git a/src/flac/encode.h b/src/flac/encode.h index 72335e02..8ac26f87 100644 --- a/src/flac/encode.h +++ b/src/flac/encode.h @@ -21,7 +21,50 @@ #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 diff --git a/src/flac/main.c b/src/flac/main.c index fee9d9bc..f284bba0 100644 --- a/src/flac/main.c +++ b/src/flac/main.c @@ -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, "-"))