FLAC__bool test_only;
FLAC__bool analysis_mode;
analysis_options aopts;
- FLAC__uint64 skip;
+ utils__SkipUntilSpecification *skip_specification;
const char *inbasefilename;
const char *outfilename;
/*
* 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);
options.common.continue_through_decode_errors,
analysis_mode,
aopts,
- options.common.skip,
+ &options.common.skip_specification,
infilename,
outfilename
)
options.common.continue_through_decode_errors,
analysis_mode,
aopts,
- options.common.skip,
+ &options.common.skip_specification,
infilename,
outfilename
)
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;
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;
FLAC__bool DecoderSession_process(DecoderSession *d)
{
- if(d->skip > 0) {
#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;
}
+ 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
+ {
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;
}
- 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;
- 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;
}
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' */
- 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;
}
- 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
- 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);
#define flac__decode_h
#include "analyze.h"
+#include "utils.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
FLAC__bool use_first_serial_number;
long serial_number;
#endif
- FLAC__uint64 skip;
+ utils__SkipUntilSpecification skip_specification;
} decode_options_t;
typedef struct {
const char *inbasefilename;
const char *outfilename;
+ FLAC__uint64 skip;
FLAC__bool replay_gain;
unsigned channels;
unsigned bits_per_sample;
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 */
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 */
}
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 */
}
}
- 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);
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;
}
}
+ /*
+ * 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" */
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;
- 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);
}
}
- 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);
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.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));
)
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) {
- 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 -= 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;
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;
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;
#define flac__encode_h
#include "FLAC/metadata.h"
+#include "utils.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
typedef struct {
FLAC__bool verbose;
- FLAC__uint64 skip;
+ utils__SkipUntilSpecification skip_specification;
FLAC__bool verify;
#ifdef FLAC__HAS_OGG
FLAC__bool use_ogg;
#include "analyze.h"
#include "decode.h"
#include "encode.h"
+#include "utils.h"
#include "vorbiscomment.h"
#if 0
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;
}
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");
}
}
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");
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;
}
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);
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(" 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");
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.skip = option_values.skip;
common_options.verify = option_values.verify;
#ifdef FLAC__HAS_OGG
common_options.use_ogg = option_values.use_ogg;
}
#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.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;