add undocumented option to flac: --ignore-chunk-sizes
authorJosh Coalson <jcoalson@users.sourceforce.net>
Sat, 7 Jul 2007 05:50:58 +0000 (05:50 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Sat, 7 Jul 2007 05:50:58 +0000 (05:50 +0000)
doc/html/changelog.html
src/flac/encode.c
src/flac/encode.h
src/flac/main.c

index c1b7086..b467e27 100644 (file)
                                        <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&amp;aid=1608883&amp;group_id=13478&amp;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&amp;aid=1615019&amp;group_id=13478&amp;atid=113478">SF #1615019</a>).</li>
index cde28d0..38a8f01 100644 (file)
@@ -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,
index b98586d..1394c89 100644 (file)
@@ -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;
index 2a58217..ee9b69d 100644 (file)
@@ -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));