revamp --skip processing, allow new mm:ss.sss form
authorJosh Coalson <jcoalson@users.sourceforce.net>
Tue, 10 Dec 2002 06:43:59 +0000 (06:43 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Tue, 10 Dec 2002 06:43:59 +0000 (06:43 +0000)
src/flac/decode.c
src/flac/decode.h
src/flac/encode.c
src/flac/encode.h
src/flac/main.c

index c92cd96..e1a3906 100644 (file)
@@ -48,7 +48,7 @@ typedef struct {
        FLAC__bool test_only;
        FLAC__bool analysis_mode;
        analysis_options aopts;
        FLAC__bool test_only;
        FLAC__bool analysis_mode;
        analysis_options aopts;
-       FLAC__uint64 skip;
+       utils__SkipUntilSpecification *skip_specification;
 
        const char *inbasefilename;
        const char *outfilename;
 
        const char *inbasefilename;
        const char *outfilename;
@@ -94,7 +94,7 @@ static FLAC__bool is_big_endian_host_;
 /*
  * local routines
  */
 /*
  * local routines
  */
-static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool verbose, FLAC__bool is_wave_out, FLAC__bool continue_through_decode_errors, FLAC__bool analysis_mode, analysis_options aopts, FLAC__uint64 skip, const char *infilename, const char *outfilename);
+static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool verbose, FLAC__bool is_wave_out, FLAC__bool continue_through_decode_errors, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, const char *infilename, const char *outfilename);
 static void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred);
 static FLAC__bool DecoderSession_init_decoder(DecoderSession *d, decode_options_t decode_options, const char *infilename);
 static FLAC__bool DecoderSession_process(DecoderSession *d);
 static void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred);
 static FLAC__bool DecoderSession_init_decoder(DecoderSession *d, decode_options_t decode_options, const char *infilename);
 static FLAC__bool DecoderSession_process(DecoderSession *d);
@@ -138,7 +138,7 @@ int flac__decode_wav(const char *infilename, const char *outfilename, FLAC__bool
                        options.common.continue_through_decode_errors,
                        analysis_mode,
                        aopts,
                        options.common.continue_through_decode_errors,
                        analysis_mode,
                        aopts,
-                       options.common.skip,
+                       &options.common.skip_specification,
                        infilename,
                        outfilename
                )
                        infilename,
                        outfilename
                )
@@ -174,7 +174,7 @@ int flac__decode_raw(const char *infilename, const char *outfilename, FLAC__bool
                        options.common.continue_through_decode_errors,
                        analysis_mode,
                        aopts,
                        options.common.continue_through_decode_errors,
                        analysis_mode,
                        aopts,
-                       options.common.skip,
+                       &options.common.skip_specification,
                        infilename,
                        outfilename
                )
                        infilename,
                        outfilename
                )
@@ -190,7 +190,7 @@ int flac__decode_raw(const char *infilename, const char *outfilename, FLAC__bool
        return DecoderSession_finish_ok(&decoder_session);
 }
 
        return DecoderSession_finish_ok(&decoder_session);
 }
 
-FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool verbose, FLAC__bool is_wave_out, FLAC__bool continue_through_decode_errors, FLAC__bool analysis_mode, analysis_options aopts, FLAC__uint64 skip, const char *infilename, const char *outfilename)
+FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool verbose, FLAC__bool is_wave_out, FLAC__bool continue_through_decode_errors, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, const char *infilename, const char *outfilename)
 {
 #ifdef FLAC__HAS_OGG
        d->is_ogg = is_ogg;
 {
 #ifdef FLAC__HAS_OGG
        d->is_ogg = is_ogg;
@@ -204,7 +204,7 @@ FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__
        d->test_only = (0 == outfilename);
        d->analysis_mode = analysis_mode;
        d->aopts = aopts;
        d->test_only = (0 == outfilename);
        d->analysis_mode = analysis_mode;
        d->aopts = aopts;
-       d->skip = skip;
+       d->skip_specification = skip_specification;
 
        d->inbasefilename = grabbag__file_get_basename(infilename);
        d->outfilename = outfilename;
 
        d->inbasefilename = grabbag__file_get_basename(infilename);
        d->outfilename = outfilename;
@@ -341,20 +341,46 @@ FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, decode_o
 
 FLAC__bool DecoderSession_process(DecoderSession *d)
 {
 
 FLAC__bool DecoderSession_process(DecoderSession *d)
 {
-       if(d->skip > 0) {
 #ifdef FLAC__HAS_OGG
 #ifdef FLAC__HAS_OGG
-               if(d->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", d->inbasefilename);
+       if(d->is_ogg) {
+               if(!OggFLAC__stream_decoder_process_until_end_of_metadata(d->decoder.ogg.stream)) {
+                       if(d->verbose) fprintf(stderr, "\n");
+                       print_error_with_state(d, "ERROR while decoding metadata");
                        return false;
                }
                        return false;
                }
+               if(OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(d->decoder.ogg.stream) != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC && OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(d->decoder.ogg.stream) != FLAC__STREAM_DECODER_END_OF_STREAM) {
+                       if(d->verbose) fprintf(stderr, "\n");
+                       print_error_with_state(d, "ERROR during metadata decoding");
+                       return false;
+               }
+       }
+       else
 #endif
 #endif
+       {
                if(!FLAC__file_decoder_process_until_end_of_metadata(d->decoder.flac.file)) {
                if(!FLAC__file_decoder_process_until_end_of_metadata(d->decoder.flac.file)) {
+                       if(d->verbose) fprintf(stderr, "\n");
                        print_error_with_state(d, "ERROR while decoding metadata");
                        return false;
                }
                        print_error_with_state(d, "ERROR while decoding metadata");
                        return false;
                }
-               if(d->abort_flag)
+               if(FLAC__file_decoder_get_state(d->decoder.flac.file) != FLAC__FILE_DECODER_OK && FLAC__file_decoder_get_state(d->decoder.flac.file) != FLAC__FILE_DECODER_END_OF_FILE) {
+                       if(d->verbose) fprintf(stderr, "\n");
+                       print_error_with_state(d, "ERROR during metadata decoding");
                        return false;
                        return false;
-               if(!FLAC__file_decoder_seek_absolute(d->decoder.flac.file, d->skip)) {
+               }
+       }
+       if(d->abort_flag)
+               return false;
+
+       if(d->skip_specification->value.samples > 0) {
+               const FLAC__uint64 skip = (FLAC__uint64)d->skip_specification->value.samples;
+
+#ifdef FLAC__HAS_OGG
+               if(d->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", d->inbasefilename);
+                       return false;
+               }
+#endif
+               if(!FLAC__file_decoder_seek_absolute(d->decoder.flac.file, skip)) {
                        print_error_with_state(d, "ERROR seeking while skipping bytes");
                        return false;
                }
                        print_error_with_state(d, "ERROR seeking while skipping bytes");
                        return false;
                }
@@ -679,22 +705,28 @@ void metadata_callback(const void *decoder, const FLAC__StreamMetadata *metadata
        DecoderSession *decoder_session = (DecoderSession*)client_data;
        (void)decoder;
        if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
        DecoderSession *decoder_session = (DecoderSession*)client_data;
        (void)decoder;
        if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+               FLAC__uint64 skip;
+               decoder_session->bps = metadata->data.stream_info.bits_per_sample;
+               decoder_session->channels = metadata->data.stream_info.channels;
+               decoder_session->sample_rate = metadata->data.stream_info.sample_rate;
+
+               flac__utils_canonicalize_skip_until_specification(decoder_session->skip_specification, decoder_session->sample_rate);
+               FLAC__ASSERT(decoder_session->skip_specification->value.samples >= 0);
+               skip = (FLAC__uint64)decoder_session->skip_specification->value.samples;
+
                /* remember, metadata->data.stream_info.total_samples can be 0, meaning 'unknown' */
                /* remember, metadata->data.stream_info.total_samples can be 0, meaning 'unknown' */
-               if(metadata->data.stream_info.total_samples > 0 && decoder_session->skip >= metadata->data.stream_info.total_samples) {
+               if(metadata->data.stream_info.total_samples > 0 && skip >= metadata->data.stream_info.total_samples) {
                        fprintf(stderr, "%s: ERROR trying to skip more samples than in stream\n", decoder_session->inbasefilename);
                        decoder_session->abort_flag = true;
                        return;
                }
                        fprintf(stderr, "%s: ERROR trying to skip more samples than in stream\n", decoder_session->inbasefilename);
                        decoder_session->abort_flag = true;
                        return;
                }
-               else if(metadata->data.stream_info.total_samples == 0 && decoder_session->skip > 0) {
+               else if(metadata->data.stream_info.total_samples == 0 && skip > 0) {
                        fprintf(stderr, "%s: ERROR, can't skip when FLAC metadata has total sample count of 0\n", decoder_session->inbasefilename);
                        decoder_session->abort_flag = true;
                        return;
                }
                else
                        fprintf(stderr, "%s: ERROR, can't skip when FLAC metadata has total sample count of 0\n", decoder_session->inbasefilename);
                        decoder_session->abort_flag = true;
                        return;
                }
                else
-                       decoder_session->total_samples = metadata->data.stream_info.total_samples - decoder_session->skip;
-               decoder_session->bps = metadata->data.stream_info.bits_per_sample;
-               decoder_session->channels = metadata->data.stream_info.channels;
-               decoder_session->sample_rate = metadata->data.stream_info.sample_rate;
+                       decoder_session->total_samples = metadata->data.stream_info.total_samples - skip;
 
                if(decoder_session->bps != 8 && decoder_session->bps != 16 && decoder_session->bps != 24) {
                        fprintf(stderr, "%s: ERROR: bits per sample is not 8/16/24\n", decoder_session->inbasefilename);
 
                if(decoder_session->bps != 8 && decoder_session->bps != 16 && decoder_session->bps != 24) {
                        fprintf(stderr, "%s: ERROR: bits per sample is not 8/16/24\n", decoder_session->inbasefilename);
index 4298c31..5e0ee75 100644 (file)
@@ -20,6 +20,7 @@
 #define flac__decode_h
 
 #include "analyze.h"
 #define flac__decode_h
 
 #include "analyze.h"
+#include "utils.h"
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -33,7 +34,7 @@ typedef struct {
        FLAC__bool use_first_serial_number;
        long serial_number;
 #endif
        FLAC__bool use_first_serial_number;
        long serial_number;
 #endif
-       FLAC__uint64 skip;
+       utils__SkipUntilSpecification skip_specification;
 } decode_options_t;
 
 typedef struct {
 } decode_options_t;
 
 typedef struct {
index 02da8eb..b020aef 100644 (file)
@@ -58,6 +58,7 @@ typedef struct {
        const char *inbasefilename;
        const char *outfilename;
 
        const char *inbasefilename;
        const char *outfilename;
 
+       FLAC__uint64 skip;
        FLAC__bool replay_gain;
        unsigned channels;
        unsigned bits_per_sample;
        FLAC__bool replay_gain;
        unsigned channels;
        unsigned bits_per_sample;
@@ -157,8 +158,6 @@ flac__encode_aif(FILE *infile, long infilesize, const char *infilename, const ch
        FLAC__bool got_comm_chunk= false, got_ssnd_chunk= false;
        int info_align_carry= -1, info_align_zero= -1;
 
        FLAC__bool got_comm_chunk= false, got_ssnd_chunk= false;
        int info_align_carry= -1, info_align_zero= -1;
 
-       FLAC__ASSERT(!options.common.sector_align || options.common.skip == 0);
-
        (void)infilesize; /* silence compiler warning about unused parameter */
        (void)lookahead; /* silence compiler warning about unused parameter */
        (void)lookahead_length; /* silence compiler warning about unused parameter */
        (void)infilesize; /* silence compiler warning about unused parameter */
        (void)lookahead; /* silence compiler warning about unused parameter */
        (void)lookahead_length; /* silence compiler warning about unused parameter */
@@ -263,6 +262,15 @@ flac__encode_aif(FILE *infile, long infilesize, const char *infilename, const ch
                                skip-= need;
                        }
 
                                skip-= need;
                        }
 
+                       /*
+                        * now that we know the sample rate, canonicalize the
+                        * --skip string to a number of samples:
+                        */
+                       flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, sample_rate);
+                       FLAC__ASSERT(options.common.skip_specification.value.samples >= 0);
+                       encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples;
+                       FLAC__ASSERT(!options.common.sector_align || encoder_session.skip == 0);
+
                        got_comm_chunk= true;
                }
                else if(got_ssnd_chunk==false && !strncmp(chunk_id, "SSND", 4)) { /* sound data chunk */
                        got_comm_chunk= true;
                }
                else if(got_ssnd_chunk==false && !strncmp(chunk_id, "SSND", 4)) { /* sound data chunk */
@@ -303,8 +311,8 @@ flac__encode_aif(FILE *infile, long infilesize, const char *infilename, const ch
                        }
                        block_size= xx;
 
                        }
                        block_size= xx;
 
-                       if(options.common.skip>0U) {
-                               FLAC__uint64 remaining= options.common.skip*bytes_per_frame;
+                       if(encoder_session.skip>0U) {
+                               FLAC__uint64 remaining= encoder_session.skip*bytes_per_frame;
 
                                /* do 1<<30 bytes at a time, since 1<<30 is a nice round number, and */
                                /* is guaranteed to be less than LONG_MAX */
 
                                /* do 1<<30 bytes at a time, since 1<<30 is a nice round number, and */
                                /* is guaranteed to be less than LONG_MAX */
@@ -324,7 +332,7 @@ flac__encode_aif(FILE *infile, long infilesize, const char *infilename, const ch
                                }
                        }
 
                                }
                        }
 
-                       data_bytes-= (8U + (unsigned int)options.common.skip*bytes_per_frame); /*@@@ WATCHOUT: 4GB limit */
+                       data_bytes-= (8U + (unsigned int)encoder_session.skip*bytes_per_frame); /*@@@ WATCHOUT: 4GB limit */
                        encoder_session.total_samples_to_encode= data_bytes/bytes_per_frame + *options.common.align_reservoir_samples;
                        if(options.common.sector_align) {
                                align_remainder= (unsigned int)(encoder_session.total_samples_to_encode % 588U);
                        encoder_session.total_samples_to_encode= data_bytes/bytes_per_frame + *options.common.align_reservoir_samples;
                        if(options.common.sector_align) {
                                align_remainder= (unsigned int)(encoder_session.total_samples_to_encode % 588U);
@@ -487,8 +495,6 @@ 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;
 
        unsigned align_remainder = 0;
        int info_align_carry = -1, info_align_zero = -1;
 
-       FLAC__ASSERT(!options.common.sector_align || options.common.skip == 0);
-
        (void)infilesize;
        (void)lookahead;
        (void)lookahead_length;
        (void)infilesize;
        (void)lookahead;
        (void)lookahead_length;
@@ -595,6 +601,15 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                }
                        }
 
                                }
                        }
 
+                       /*
+                        * now that we know the sample rate, canonicalize the
+                        * --skip string to a number of samples:
+                        */
+                       flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, sample_rate);
+                       FLAC__ASSERT(options.common.skip_specification.value.samples >= 0);
+                       encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples;
+                       FLAC__ASSERT(!options.common.sector_align || encoder_session.skip == 0);
+
                        got_fmt_chunk = true;
                }
                else if(xx == 0x61746164 && !got_data_chunk && got_fmt_chunk) { /* "data" */
                        got_fmt_chunk = true;
                }
                else if(xx == 0x61746164 && !got_data_chunk && got_fmt_chunk) { /* "data" */
@@ -605,11 +620,11 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
 
                        bytes_per_wide_sample = channels * (bps >> 3);
 
 
                        bytes_per_wide_sample = channels * (bps >> 3);
 
-                       if(options.common.skip > 0) {
-                               if(fseek(infile, bytes_per_wide_sample * (unsigned)options.common.skip, SEEK_CUR) < 0) {
+                       if(encoder_session.skip > 0) {
+                               if(fseek(infile, bytes_per_wide_sample * (unsigned)encoder_session.skip, SEEK_CUR) < 0) {
                                        /* can't seek input, read ahead manually... */
                                        unsigned left, need;
                                        /* can't seek input, read ahead manually... */
                                        unsigned left, need;
-                                       for(left = (unsigned)options.common.skip; left > 0; ) { /*@@@ WATCHOUT: 4GB limit */
+                                       for(left = (unsigned)encoder_session.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_session.inbasefilename);
                                                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_session.inbasefilename);
@@ -620,7 +635,7 @@ int flac__encode_wav(FILE *infile, long infilesize, const char *infilename, cons
                                }
                        }
 
                                }
                        }
 
-                       data_bytes -= (unsigned)options.common.skip * bytes_per_wide_sample; /*@@@ WATCHOUT: 4GB limit */
+                       data_bytes -= (unsigned)encoder_session.skip * bytes_per_wide_sample; /*@@@ WATCHOUT: 4GB limit */
                        encoder_session.total_samples_to_encode = data_bytes / bytes_per_wide_sample + *options.common.align_reservoir_samples;
                        if(options.common.sector_align) {
                                align_remainder = (unsigned)(encoder_session.total_samples_to_encode % 588);
                        encoder_session.total_samples_to_encode = data_bytes / bytes_per_wide_sample + *options.common.align_reservoir_samples;
                        if(options.common.sector_align) {
                                align_remainder = (unsigned)(encoder_session.total_samples_to_encode % 588);
@@ -783,12 +798,10 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
        unsigned align_remainder = 0;
        int info_align_carry = -1, info_align_zero = -1;
 
        unsigned align_remainder = 0;
        int info_align_carry = -1, info_align_zero = -1;
 
-       FLAC__ASSERT(!options.common.sector_align || options.common.skip == 0);
        FLAC__ASSERT(!options.common.sector_align || options.channels == 2);
        FLAC__ASSERT(!options.common.sector_align || options.bps == 16);
        FLAC__ASSERT(!options.common.sector_align || options.sample_rate == 44100);
        FLAC__ASSERT(!options.common.sector_align || infilesize >= 0);
        FLAC__ASSERT(!options.common.sector_align || options.channels == 2);
        FLAC__ASSERT(!options.common.sector_align || options.bps == 16);
        FLAC__ASSERT(!options.common.sector_align || options.sample_rate == 44100);
        FLAC__ASSERT(!options.common.sector_align || infilesize >= 0);
-       FLAC__ASSERT(!options.common.replay_gain || options.common.skip == 0);
        FLAC__ASSERT(!options.common.replay_gain || options.channels <= 2);
        FLAC__ASSERT(!options.common.replay_gain || grabbag__replaygain_is_valid_sample_frequency(options.sample_rate));
 
        FLAC__ASSERT(!options.common.replay_gain || options.channels <= 2);
        FLAC__ASSERT(!options.common.replay_gain || grabbag__replaygain_is_valid_sample_frequency(options.sample_rate));
 
@@ -809,13 +822,23 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
        )
                return 1;
 
        )
                return 1;
 
+       /*
+        * now that we know the sample rate, canonicalize the
+        * --skip string to a number of samples:
+        */
+       flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, options.sample_rate);
+       FLAC__ASSERT(options.common.skip_specification.value.samples >= 0);
+       encoder_session.skip = (FLAC__uint64)options.common.skip_specification.value.samples;
+       FLAC__ASSERT(!options.common.sector_align || encoder_session.skip == 0);
+       FLAC__ASSERT(!options.common.replay_gain || encoder_session.skip == 0);
+
        /* get the file length */
        if(infilesize < 0) {
                encoder_session.total_samples_to_encode = encoder_session.unencoded_size = 0;
        }
        else {
                if(options.common.sector_align) {
        /* get the file length */
        if(infilesize < 0) {
                encoder_session.total_samples_to_encode = encoder_session.unencoded_size = 0;
        }
        else {
                if(options.common.sector_align) {
-                       FLAC__ASSERT(options.common.skip == 0);
+                       FLAC__ASSERT(encoder_session.skip == 0);
                        encoder_session.total_samples_to_encode = (unsigned)infilesize / bytes_per_wide_sample + *options.common.align_reservoir_samples;
                        align_remainder = (unsigned)(encoder_session.total_samples_to_encode % 588);
                        if(options.common.is_last_file)
                        encoder_session.total_samples_to_encode = (unsigned)infilesize / bytes_per_wide_sample + *options.common.align_reservoir_samples;
                        align_remainder = (unsigned)(encoder_session.total_samples_to_encode % 588);
                        if(options.common.is_last_file)
@@ -824,7 +847,7 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
                                encoder_session.total_samples_to_encode -= align_remainder; /* will stop short and carry over to next file */
                }
                else {
                                encoder_session.total_samples_to_encode -= align_remainder; /* will stop short and carry over to next file */
                }
                else {
-                       encoder_session.total_samples_to_encode = (unsigned)infilesize / bytes_per_wide_sample - options.common.skip;
+                       encoder_session.total_samples_to_encode = (unsigned)infilesize / bytes_per_wide_sample - encoder_session.skip;
                }
 
                encoder_session.unencoded_size = encoder_session.total_samples_to_encode * bytes_per_wide_sample;
                }
 
                encoder_session.unencoded_size = encoder_session.total_samples_to_encode * bytes_per_wide_sample;
@@ -833,8 +856,8 @@ int flac__encode_raw(FILE *infile, long infilesize, const char *infilename, cons
        if(encoder_session.verbose && encoder_session.total_samples_to_encode <= 0)
                fprintf(stderr, "(No runtime statistics possible; please wait for encoding to finish...)\n");
 
        if(encoder_session.verbose && encoder_session.total_samples_to_encode <= 0)
                fprintf(stderr, "(No runtime statistics possible; please wait for encoding to finish...)\n");
 
-       if(options.common.skip > 0) {
-               unsigned skip_bytes = bytes_per_wide_sample * (unsigned)options.common.skip;
+       if(encoder_session.skip > 0) {
+               unsigned skip_bytes = bytes_per_wide_sample * (unsigned)encoder_session.skip;
                if(skip_bytes > lookahead_length) {
                        skip_bytes -= lookahead_length;
                        lookahead_length = 0;
                if(skip_bytes > lookahead_length) {
                        skip_bytes -= lookahead_length;
                        lookahead_length = 0;
@@ -997,6 +1020,7 @@ FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg, FLAC_
        e->inbasefilename = grabbag__file_get_basename(infilename);
        e->outfilename = outfilename;
 
        e->inbasefilename = grabbag__file_get_basename(infilename);
        e->outfilename = outfilename;
 
+       e->skip = 0; /* filled in later after the sample_rate is known */
        e->unencoded_size = 0;
        e->total_samples_to_encode = 0;
        e->bytes_written = 0;
        e->unencoded_size = 0;
        e->total_samples_to_encode = 0;
        e->bytes_written = 0;
index add8595..b04fdb4 100644 (file)
@@ -20,6 +20,7 @@
 #define flac__encode_h
 
 #include "FLAC/metadata.h"
 #define flac__encode_h
 
 #include "FLAC/metadata.h"
+#include "utils.h"
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -27,7 +28,7 @@
 
 typedef struct {
        FLAC__bool verbose;
 
 typedef struct {
        FLAC__bool verbose;
-       FLAC__uint64 skip;
+       utils__SkipUntilSpecification skip_specification;
        FLAC__bool verify;
 #ifdef FLAC__HAS_OGG
        FLAC__bool use_ogg;
        FLAC__bool verify;
 #ifdef FLAC__HAS_OGG
        FLAC__bool use_ogg;
index 3106fd6..44aae3f 100644 (file)
@@ -38,6 +38,7 @@
 #include "analyze.h"
 #include "decode.h"
 #include "encode.h"
 #include "analyze.h"
 #include "decode.h"
 #include "encode.h"
+#include "utils.h"
 #include "vorbiscomment.h"
 
 #if 0
 #include "vorbiscomment.h"
 
 #if 0
@@ -228,7 +229,7 @@ static struct {
        int padding;
        unsigned max_lpc_order;
        unsigned qlp_coeff_precision;
        int padding;
        unsigned max_lpc_order;
        unsigned qlp_coeff_precision;
-       FLAC__uint64 skip;
+       const char *skip_specification;
        int format_is_big_endian;
        int format_is_unsigned_samples;
        int format_channels;
        int format_is_big_endian;
        int format_is_unsigned_samples;
        int format_channels;
@@ -333,7 +334,7 @@ int do_it()
                }
                else {
                        if(option_values.test_only) {
                }
                else {
                        if(option_values.test_only) {
-                               if(option_values.skip > 0)
+                               if(0 != option_values.skip_specification)
                                        return usage_error("ERROR: --skip is not allowed in test mode\n");
                        }
                }
                                        return usage_error("ERROR: --skip is not allowed in test mode\n");
                        }
                }
@@ -376,7 +377,7 @@ int do_it()
                if(option_values.sector_align) {
                        if(option_values.mode_decode)
                                return usage_error("ERROR: --sector-align only allowed for encoding\n");
                if(option_values.sector_align) {
                        if(option_values.mode_decode)
                                return usage_error("ERROR: --sector-align only allowed for encoding\n");
-                       if(option_values.skip > 0)
+                       if(0 != option_values.skip_specification)
                                return usage_error("ERROR: --sector-align not allowed with --skip\n");
                        if(option_values.format_channels >= 0 && option_values.format_channels != 2)
                                return usage_error("ERROR: --sector-align can only be done with stereo input\n");
                                return usage_error("ERROR: --sector-align not allowed with --skip\n");
                        if(option_values.format_channels >= 0 && option_values.format_channels != 2)
                                return usage_error("ERROR: --sector-align can only be done with stereo input\n");
@@ -534,7 +535,7 @@ FLAC__bool init_options()
        option_values.padding = 4096;
        option_values.max_lpc_order = 8;
        option_values.qlp_coeff_precision = 0;
        option_values.padding = 4096;
        option_values.max_lpc_order = 8;
        option_values.qlp_coeff_precision = 0;
-       option_values.skip = 0;
+       option_values.skip_specification = 0;
        option_values.format_is_big_endian = -1;
        option_values.format_is_unsigned_samples = -1;
        option_values.format_channels = -1;
        option_values.format_is_big_endian = -1;
        option_values.format_is_unsigned_samples = -1;
        option_values.format_channels = -1;
@@ -619,7 +620,7 @@ int parse_option(int short_option, const char *long_option, const char *option_a
                }
                else if(0 == strcmp(long_option, "skip")) {
                        FLAC__ASSERT(0 != option_argument);
                }
                else if(0 == strcmp(long_option, "skip")) {
                        FLAC__ASSERT(0 != option_argument);
-                       option_values.skip = (FLAC__uint64)atoi(option_argument); /* @@@ takes a pretty damn big file to overflow atoi() here, but it could happen */
+                       option_values.skip_specification = option_argument;
                }
                else if(0 == strcmp(long_option, "cuesheet")) {
                        FLAC__ASSERT(0 != option_argument);
                }
                else if(0 == strcmp(long_option, "cuesheet")) {
                        FLAC__ASSERT(0 != option_argument);
@@ -1082,7 +1083,7 @@ void show_help()
        printf("  -o, --output-name=FILENAME   Force the output file name\n");
        printf("      --output-prefix=STRING   Prepend STRING to output names\n");
        printf("      --delete-input-file      Deletes after a successful encode/decode\n");
        printf("  -o, --output-name=FILENAME   Force the output file name\n");
        printf("      --output-prefix=STRING   Prepend STRING to output names\n");
        printf("      --delete-input-file      Deletes after a successful encode/decode\n");
-       printf("      --skip=#                 Skip the first # samples of each input file\n");
+       printf("      --skip={#|mm:ss.ss}      Skip the given initial samples for each input\n");
        printf("analysis options:\n");
        printf("      --residual-text          Include residual signal in text output\n");
        printf("      --residual-gnuplot       Generate gnuplot files of residual distribution\n");
        printf("analysis options:\n");
        printf("      --residual-text          Include residual signal in text output\n");
        printf("      --residual-gnuplot       Generate gnuplot files of residual distribution\n");
@@ -1203,8 +1204,10 @@ void show_explain()
        printf("                               successful encode or decode.  If there was an\n");
        printf("                               error (including a verify error) the input file\n");
        printf("                               is left intact.\n");
        printf("                               successful encode or decode.  If there was an\n");
        printf("                               error (including a verify error) the input file\n");
        printf("                               is left intact.\n");
-       printf("      --skip=#                 Skip the first # samples of each input file; can\n");
-       printf("                               be used both for encoding and decoding\n");
+       printf("      --skip={#|mm:ss.ss}      Skip the first # samples of each input file; can\n");
+       printf("                               be used both for encoding and decoding.  The\n");
+       printf("                               alternative form mm:ss.ss can be used to specify\n");
+       printf("                               minutes, seconds, and fractions of a second.\n");
        printf("analysis options:\n");
        printf("      --residual-text          Include residual signal in text output.  This\n");
        printf("                               will make the file very big, much larger than\n");
        printf("analysis options:\n");
        printf("      --residual-text          Include residual signal in text output.  This\n");
        printf("                               will make the file very big, much larger than\n");
@@ -1436,8 +1439,10 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_
                        return usage_error("ERROR: --replay-gain cannot be used when encoding to stdout\n");
        }
 
                        return usage_error("ERROR: --replay-gain cannot be used when encoding to stdout\n");
        }
 
+       if(!flac__utils_parse_skip_until_specification(option_values.skip_specification, &common_options.skip_specification) || common_options.skip_specification.is_relative)
+               return usage_error("ERROR: invalid value for --skip\n");
+
        common_options.verbose = option_values.verbose;
        common_options.verbose = option_values.verbose;
-       common_options.skip = option_values.skip;
        common_options.verify = option_values.verify;
 #ifdef FLAC__HAS_OGG
        common_options.use_ogg = option_values.use_ogg;
        common_options.verify = option_values.verify;
 #ifdef FLAC__HAS_OGG
        common_options.use_ogg = option_values.use_ogg;
@@ -1540,6 +1545,9 @@ int decode_file(const char *infilename)
        }
 #endif
 
        }
 #endif
 
+       if(!flac__utils_parse_skip_until_specification(option_values.skip_specification, &common_options.skip_specification) || common_options.skip_specification.is_relative)
+               return usage_error("ERROR: invalid value for --skip\n");
+
        common_options.verbose = option_values.verbose;
        common_options.continue_through_decode_errors = option_values.continue_through_decode_errors;
 #ifdef FLAC__HAS_OGG
        common_options.verbose = option_values.verbose;
        common_options.continue_through_decode_errors = option_values.continue_through_decode_errors;
 #ifdef FLAC__HAS_OGG
@@ -1547,7 +1555,6 @@ int decode_file(const char *infilename)
        common_options.use_first_serial_number = !option_values.has_serial_number;
        common_options.serial_number = option_values.serial_number;
 #endif
        common_options.use_first_serial_number = !option_values.has_serial_number;
        common_options.serial_number = option_values.serial_number;
 #endif
-       common_options.skip = option_values.skip;
 
        if(!option_values.force_raw_format) {
                wav_decode_options_t options;
 
        if(!option_values.force_raw_format) {
                wav_decode_options_t options;