<li>Improved compression with no change to format or decrease in speed.</li>
<li>Encoding and decoding speedups for all modes. Encoding at -8 is twice as fast.</li>
<li>Added a new option <span class="argument"><a href="documentation_tools_flac.html#flac_options_warnings_as_errors">-w,--warnings-as-errors</a></span> for treating all warnings as errors.</li>
+ <li>Added a new undocumented option <span class="argument">--ignore-chunk-sizes</span> 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.</li>
<li>Allow <span class="argument"><a href="documentation_tools_flac.html#flac_options_picture">--picture</a></span> option to take only a filename, and have all other attributes extracted from the file itself.</li>
<li>Fixed a bug that caused suboptimal default compression settings in some locales (<a href="https://sourceforge.net/tracker/index.php?func=detail&aid=1608883&group_id=13478&atid=113478">SF #1608883</a>).</li>
<li>Fixed a bug where FLAC-to-FLAC transcoding of a corrupted FLAC file would truncate the transcoded file at the first error (<a href="http://sourceforge.net/tracker/index.php?func=detail&aid=1615019&group_id=13478&atid=113478">SF #1615019</a>).</li>
}
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;
/* 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))
}
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);
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;
}
}
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;
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;
}
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);
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;
}
}
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,
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;
{ "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' },
{ "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
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;
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");
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);
}
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;
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;
}
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;
}
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");
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");
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");
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");
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));