diff --git a/doc/html/changelog.html b/doc/html/changelog.html
index c1b7086d..b467e270 100644
--- a/doc/html/changelog.html
+++ b/doc/html/changelog.html
@@ -165,6 +165,7 @@
Improved compression with no change to format or decrease in speed.
Encoding and decoding speedups for all modes. Encoding at -8 is twice as fast.
Added a new option -w,--warnings-as-errors for treating all warnings as errors.
+ Added a new undocumented option --ignore-chunk-sizes for ignoring the size of the 'data' chunk (WAVE) or 'SSND' chunk(AIFF). Can be used to encode files with bogus data sizes. Use with caution, all subsequent data is treated as audio, so the data/SSND chunk must be the last or the following data/tags will be treated as audio and encoded.
Allow --picture option to take only a filename, and have all other attributes extracted from the file itself.
Fixed a bug that caused suboptimal default compression settings in some locales (SF #1608883).
Fixed a bug where FLAC-to-FLAC transcoding of a corrupted FLAC file would truncate the transcoded file at the first error (SF #1615019).
diff --git a/src/flac/encode.c b/src/flac/encode.c
index cde28d08..38a8f013 100644
--- a/src/flac/encode.c
+++ b/src/flac/encode.c
@@ -343,7 +343,7 @@ int flac__encode_aif(FILE *infile, off_t infilesize, const char *infilename, con
}
else if(got_ssnd_chunk==false && !memcmp(chunk_id, "SSND", 4)) { /* sound data chunk */
unsigned int offset= 0U, block_size= 0U, align_remainder= 0U, data_bytes;
- size_t bytes_per_frame= channels*(bps>>3);
+ const size_t bytes_per_frame= channels*(bps>>3);
FLAC__uint64 total_samples_in_input, trim = 0;
FLAC__bool pad= false;
@@ -355,9 +355,15 @@ int flac__encode_aif(FILE *infile, off_t infilesize, const char *infilename, con
/* SSND chunk size */
if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
return EncoderSession_finish_error(&encoder_session);
- data_bytes= xx;
+ if(options.common.ignore_chunk_sizes) {
+ FLAC__ASSERT(!options.common.sector_align);
+ data_bytes = (unsigned)(-(int)bytes_per_frame); /* max out data_bytes; we'll use EOF as signal to stop reading */
+ }
+ else {
+ data_bytes= xx;
+ data_bytes-= 8U; /* discount the offset and block size fields */
+ }
pad= (data_bytes & 1U) ? true : false;
- data_bytes-= 8U; /* discount the offset and block size fields */
/* offset */
if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
@@ -406,7 +412,14 @@ int flac__encode_aif(FILE *infile, off_t infilesize, const char *infilename, con
}
data_bytes-= (unsigned int)encoder_session.skip*bytes_per_frame; /*@@@ WATCHOUT: 4GB limit */
- encoder_session.total_samples_to_encode= total_samples_in_input - encoder_session.skip;
+ if(options.common.ignore_chunk_sizes) {
+ encoder_session.total_samples_to_encode= 0;
+ flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n");
+ FLAC__ASSERT(0 == encoder_session.until);
+ }
+ else {
+ encoder_session.total_samples_to_encode= total_samples_in_input - encoder_session.skip;
+ }
if(encoder_session.until > 0) {
trim = total_samples_in_input - encoder_session.until;
FLAC__ASSERT(total_samples_in_input > 0);
@@ -457,9 +470,14 @@ int flac__encode_aif(FILE *infile, off_t infilesize, const char *infilename, con
return EncoderSession_finish_error(&encoder_session);
}
else if(feof(infile)) {
- flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned int)encoder_session.total_samples_to_encode, (unsigned int)encoder_session.samples_written);
- if(encoder_session.treat_warnings_as_errors)
- return EncoderSession_finish_error(&encoder_session);
+ if(options.common.ignore_chunk_sizes) {
+ flac__utils_printf(stderr, 1, "%s: INFO: hit EOF with --ignore-chunk-sizes, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.samples_written);
+ }
+ else {
+ flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written);
+ if(encoder_session.treat_warnings_as_errors)
+ return EncoderSession_finish_error(&encoder_session);
+ }
data_bytes= 0;
}
}
@@ -588,7 +606,7 @@ int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, con
EncoderSession encoder_session;
FLAC__bool is_unsigned_samples = false;
unsigned channels = 0, bps = 0, sample_rate = 0, shift = 0;
- size_t bytes_per_wide_sample, bytes_read;
+ size_t bytes_read;
size_t channel_map[FLAC__MAX_CHANNELS];
FLAC__uint16 x, format; /* format is the wFormatTag word from the 'fmt ' chunk */
FLAC__uint32 xx, channel_mask = 0;
@@ -902,20 +920,25 @@ int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, con
else if(xx == 0x61746164 && !got_data_chunk && got_fmt_chunk) { /* "data" */
FLAC__uint64 total_samples_in_input, trim = 0;
FLAC__bool pad = false;
+ const size_t bytes_per_wide_sample = channels * (bps >> 3);
unsigned data_bytes;
/* data size */
if(!read_little_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
return EncoderSession_finish_error(&encoder_session);
- data_bytes = xx;
- if(0 == data_bytes) {
- flac__utils_printf(stderr, 1, "%s: ERROR: 'data' subchunk has size of 0\n", encoder_session.inbasefilename);
- return EncoderSession_finish_error(&encoder_session);
+ if(options.common.ignore_chunk_sizes) {
+ FLAC__ASSERT(!options.common.sector_align);
+ data_bytes = (unsigned)(-(int)bytes_per_wide_sample); /* max out data_bytes; we'll use EOF as signal to stop reading */
+ }
+ else {
+ data_bytes = xx;
+ if(0 == data_bytes) {
+ flac__utils_printf(stderr, 1, "%s: ERROR: 'data' subchunk has size of 0\n", encoder_session.inbasefilename);
+ return EncoderSession_finish_error(&encoder_session);
+ }
}
pad = (data_bytes & 1U) ? true : false;
- bytes_per_wide_sample = channels * (bps >> 3);
-
/* *options.common.align_reservoir_samples will be 0 unless --sector-align is used */
FLAC__ASSERT(options.common.sector_align || *options.common.align_reservoir_samples == 0);
total_samples_in_input = data_bytes / bytes_per_wide_sample + *options.common.align_reservoir_samples;
@@ -937,7 +960,14 @@ int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, con
}
data_bytes -= (unsigned)encoder_session.skip * bytes_per_wide_sample; /*@@@ WATCHOUT: 4GB limit */
- encoder_session.total_samples_to_encode = total_samples_in_input - encoder_session.skip;
+ if(options.common.ignore_chunk_sizes) {
+ encoder_session.total_samples_to_encode = 0;
+ flac__utils_printf(stderr, 2, "(No runtime statistics possible; please wait for encoding to finish...)\n");
+ FLAC__ASSERT(0 == encoder_session.until);
+ }
+ else {
+ encoder_session.total_samples_to_encode = total_samples_in_input - encoder_session.skip;
+ }
if(encoder_session.until > 0) {
trim = total_samples_in_input - encoder_session.until;
FLAC__ASSERT(total_samples_in_input > 0);
@@ -993,9 +1023,14 @@ int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, con
return EncoderSession_finish_error(&encoder_session);
}
else if(feof(infile)) {
- flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written);
- if(encoder_session.treat_warnings_as_errors)
- return EncoderSession_finish_error(&encoder_session);
+ if(options.common.ignore_chunk_sizes) {
+ flac__utils_printf(stderr, 1, "%s: INFO: hit EOF with --ignore-chunk-sizes, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.samples_written);
+ }
+ else {
+ flac__utils_printf(stderr, 1, "%s: WARNING: unexpected EOF; expected %u samples, got %u samples\n", encoder_session.inbasefilename, (unsigned)encoder_session.total_samples_to_encode, (unsigned)encoder_session.samples_written);
+ if(encoder_session.treat_warnings_as_errors)
+ return EncoderSession_finish_error(&encoder_session);
+ }
data_bytes = 0;
}
}
@@ -2552,6 +2587,8 @@ void print_stats(const EncoderSession *encoder_session)
const double ratio = (double)encoder_session->bytes_written / ((double)encoder_session->unencoded_size * min(1.0, progress));
#endif
+ FLAC__ASSERT(encoder_session->total_samples_to_encode > 0);
+
if(samples_written == encoder_session->total_samples_to_encode) {
flac__utils_printf(stderr, 2, "\r%s:%s wrote %u bytes, ratio=%0.3f",
encoder_session->inbasefilename,
diff --git a/src/flac/encode.h b/src/flac/encode.h
index b98586d6..1394c89a 100644
--- a/src/flac/encode.h
+++ b/src/flac/encode.h
@@ -84,6 +84,7 @@ typedef struct {
FLAC__int32 **align_reservoir;
unsigned *align_reservoir_samples;
FLAC__bool replay_gain;
+ FLAC__bool ignore_chunk_sizes;
FLAC__bool sector_align;
FLAC__StreamMetadata *vorbis_comment;
diff --git a/src/flac/main.c b/src/flac/main.c
index 2a582172..ee9b69d5 100644
--- a/src/flac/main.c
+++ b/src/flac/main.c
@@ -149,6 +149,7 @@ static struct share__option long_options_[] = {
{ "force-raw-format" , share__no_argument, 0, 0 },
{ "lax" , share__no_argument, 0, 0 },
{ "replay-gain" , share__no_argument, 0, 0 },
+ { "ignore-chunk-sizes" , share__no_argument, 0, 0 },
{ "sector-align" , share__no_argument, 0, 0 },
{ "seekpoint" , share__required_argument, 0, 'S' },
{ "padding" , share__required_argument, 0, 'P' },
@@ -187,6 +188,7 @@ static struct share__option long_options_[] = {
{ "no-seektable" , share__no_argument, 0, 0 },
{ "no-delete-input-file" , share__no_argument, 0, 0 },
{ "no-replay-gain" , share__no_argument, 0, 0 },
+ { "no-ignore-chunk-sizes" , share__no_argument, 0, 0 },
{ "no-sector-align" , share__no_argument, 0, 0 },
{ "no-lax" , share__no_argument, 0, 0 },
#if FLAC__HAS_OGG
@@ -238,6 +240,7 @@ static struct {
FLAC__bool force_raw_format;
FLAC__bool delete_input;
FLAC__bool replay_gain;
+ FLAC__bool ignore_chunk_sizes;
FLAC__bool sector_align;
const char *cmdline_forced_outfilename;
const char *output_prefix;
@@ -385,6 +388,18 @@ int do_it(void)
return usage_error("ERROR: --sample-rate not allowed with --decode\n");
}
+ if(option_values.ignore_chunk_sizes) {
+ if(option_values.mode_decode)
+ return usage_error("ERROR: --ignore-chunk-sizes only allowed for encoding\n");
+ if(0 != option_values.sector_align)
+ return usage_error("ERROR: --ignore-chunk-sizes not allowed with --sector-align\n");
+ if(0 != option_values.until_specification)
+ return usage_error("ERROR: --ignore-chunk-sizes not allowed with --until\n");
+ if(0 != option_values.cue_specification)
+ return usage_error("ERROR: --ignore-chunk-sizes not allowed with --cue\n");
+ if(0 != option_values.cuesheet_filename)
+ return usage_error("ERROR: --ignore-chunk-sizes not allowed with --cuesheet\n");
+ }
if(option_values.sector_align) {
if(option_values.mode_decode)
return usage_error("ERROR: --sector-align only allowed for encoding\n");
@@ -460,6 +475,9 @@ int do_it(void)
else { /* encode */
FLAC__bool first = true;
+ if(option_values.ignore_chunk_sizes)
+ flac__utils_printf(stderr, 1, "INFO: Make sure you know what you're doing when using --ignore-chunk-sizes.\n Improper use can cause flac to encode non-audio data as audio.\n");
+
if(option_values.num_files == 0) {
retval = encode_file("-", first, true);
}
@@ -525,6 +543,7 @@ FLAC__bool init_options(void)
option_values.force_raw_format = false;
option_values.delete_input = false;
option_values.replay_gain = false;
+ option_values.ignore_chunk_sizes = false;
option_values.sector_align = false;
option_values.cmdline_forced_outfilename = 0;
option_values.output_prefix = 0;
@@ -718,6 +737,9 @@ int parse_option(int short_option, const char *long_option, const char *option_a
else if(0 == strcmp(long_option, "replay-gain")) {
option_values.replay_gain = true;
}
+ else if(0 == strcmp(long_option, "ignore-chunk-sizes")) {
+ option_values.ignore_chunk_sizes = true;
+ }
else if(0 == strcmp(long_option, "sector-align")) {
option_values.sector_align = true;
}
@@ -788,6 +810,9 @@ int parse_option(int short_option, const char *long_option, const char *option_a
else if(0 == strcmp(long_option, "no-replay-gain")) {
option_values.replay_gain = false;
}
+ else if(0 == strcmp(long_option, "no-ignore-chunk-sizes")) {
+ option_values.ignore_chunk_sizes = false;
+ }
else if(0 == strcmp(long_option, "no-sector-align")) {
option_values.sector_align = false;
}
@@ -1158,6 +1183,9 @@ void show_help(void)
printf("encoding options:\n");
printf(" -V, --verify Verify a correct encoding\n");
printf(" --lax Allow encoder to generate non-Subset files\n");
+#if 0 /*@@@ currently undocumented */
+ printf(" --ignore-chunk-sizes Ignore data chunk sizes in WAVE/AIFF files\n");
+#endif
printf(" --sector-align Align multiple files on sector boundaries\n");
printf(" --replay-gain Calculate ReplayGain & store in FLAC tags\n");
printf(" --cuesheet=FILENAME Import cuesheet and store in CUESHEET block\n");
@@ -1208,6 +1236,9 @@ void show_help(void)
printf(" --no-replay-gain\n");
printf(" --no-residual-gnuplot\n");
printf(" --no-residual-text\n");
+#if 0 /*@@@ currently undocumented */
+ printf(" --no-ignore-chunk-sizes\n");
+#endif
printf(" --no-sector-align\n");
printf(" --no-seektable\n");
printf(" --no-silent\n");
@@ -1330,6 +1361,11 @@ void show_explain(void)
printf(" output in parallel and comparing to the\n");
printf(" original\n");
printf(" --lax Allow encoder to generate non-Subset files\n");
+#if 0 /*@@@ currently undocumented */
+ printf(" --ignore-chunk-sizes Ignore data chunk sizes in WAVE/AIFF files;\n");
+ printf(" useful when piping data from programs which\n");
+ printf(" generate bogus data chunk sizes.\n");
+#endif
printf(" --sector-align Align encoding of multiple CD format WAVE files\n");
printf(" on sector boundaries.\n");
printf(" --replay-gain Calculate ReplayGain values and store them as\n");
@@ -1515,6 +1551,9 @@ void show_explain(void)
printf(" --no-qlp-coeff-prec-search\n");
printf(" --no-residual-gnuplot\n");
printf(" --no-residual-text\n");
+#if 0 /*@@@ currently undocumented */
+ printf(" --no-ignore-chunk-sizes\n");
+#endif
printf(" --no-sector-align\n");
printf(" --no-seektable\n");
printf(" --no-silent\n");
@@ -1729,6 +1768,7 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_
common_options.align_reservoir = align_reservoir;
common_options.align_reservoir_samples = &align_reservoir_samples;
common_options.replay_gain = option_values.replay_gain;
+ common_options.ignore_chunk_sizes = option_values.ignore_chunk_sizes;
common_options.sector_align = option_values.sector_align;
common_options.vorbis_comment = option_values.vorbis_comment;
FLAC__ASSERT(sizeof(common_options.pictures) >= sizeof(option_values.pictures));