diff options
Diffstat (limited to 'src/flac')
-rw-r--r-- | src/flac/encode.c | 534 | ||||
-rw-r--r-- | src/flac/encode.h | 7 | ||||
-rw-r--r-- | src/flac/main.c | 119 |
3 files changed, 598 insertions, 62 deletions
diff --git a/src/flac/encode.c b/src/flac/encode.c index 6528c7a4..8bafa5bd 100644 --- a/src/flac/encode.c +++ b/src/flac/encode.c @@ -103,6 +103,19 @@ typedef struct { FLAC__StreamMetadata *seek_table_template; } EncoderSession; +/* this is data attached to the FLAC decoder when encoding from a FLAC file */ +typedef struct { + EncoderSession *encoder_session; + off_t filesize; + const FLAC__byte *lookahead; + unsigned lookahead_length; + size_t num_metadata_blocks; + FLAC__StreamMetadata *metadata_blocks[1024]; /*@@@ BAD MAGIC number */ + FLAC__uint64 samples_left_to_process; + FLAC__bool fatal_error; +} FLACDecoderData; + +const int FLAC_ENCODE__DEFAULT_PADDING = 4096; static FLAC__bool is_big_endian_host_; @@ -140,7 +153,7 @@ static FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg static void EncoderSession_destroy(EncoderSession *e); static int EncoderSession_finish_ok(EncoderSession *e, int info_align_carry, int info_align_zero); static int EncoderSession_finish_error(EncoderSession *e); -static FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options, unsigned channels, unsigned bps, unsigned sample_rate); +static FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options, unsigned channels, unsigned bps, unsigned sample_rate, FLACDecoderData *flac_decoder_data); static FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const buffer[], unsigned samples); static FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int num_requested_seek_points, FLAC__StreamMetadata *cuesheet, EncoderSession *e); static FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input); @@ -153,7 +166,15 @@ static void ogg_file_encoder_progress_callback(const OggFLAC__FileEncoder *encod static FLAC__StreamEncoderWriteStatus flac_stream_encoder_write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data); static void flac_stream_encoder_metadata_callback(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data); static void flac_file_encoder_progress_callback(const FLAC__FileEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data); -static FLAC__bool parse_cuesheet_(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset); +static FLAC__SeekableStreamDecoderReadStatus flac_decoder_read_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data); +static FLAC__SeekableStreamDecoderSeekStatus flac_decoder_seek_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); +static FLAC__SeekableStreamDecoderTellStatus flac_decoder_tell_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); +static FLAC__SeekableStreamDecoderLengthStatus flac_decoder_length_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); +static FLAC__bool flac_decoder_eof_callback(const FLAC__SeekableStreamDecoder *decoder, void *client_data); +static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +static void flac_decoder_metadata_callback(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static void flac_decoder_error_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); +static FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset); static void print_stats(const EncoderSession *encoder_session); static void print_error_with_state(const EncoderSession *e, const char *message); static void print_verify_error(EncoderSession *e); @@ -386,7 +407,7 @@ int flac__encode_aif(FILE *infile, off_t infilesize, const char *infilename, con /* +54 for the size of the AIFF headers; this is just an estimate for the progress indicator and doesn't need to be exact */ encoder_session.unencoded_size= encoder_session.total_samples_to_encode*bytes_per_frame+54; - if(!EncoderSession_init_encoder(&encoder_session, options.common, channels, bps, sample_rate)) + if(!EncoderSession_init_encoder(&encoder_session, options.common, channels, bps, sample_rate, /*flac_decoder_data=*/0)) return EncoderSession_finish_error(&encoder_session); /* first do any samples in the reservoir */ @@ -714,7 +735,7 @@ int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, con /* +44 for the size of the WAV headers; this is just an estimate for the progress indicator and doesn't need to be exact */ encoder_session.unencoded_size = encoder_session.total_samples_to_encode * bytes_per_wide_sample + 44; - if(!EncoderSession_init_encoder(&encoder_session, options.common, channels, bps, sample_rate)) + if(!EncoderSession_init_encoder(&encoder_session, options.common, channels, bps, sample_rate, /*flac_decoder_data=*/0)) return EncoderSession_finish_error(&encoder_session); /* @@ -963,7 +984,7 @@ int flac__encode_raw(FILE *infile, off_t infilesize, const char *infilename, con } } - if(!EncoderSession_init_encoder(&encoder_session, options.common, options.channels, options.bps, options.sample_rate)) + if(!EncoderSession_init_encoder(&encoder_session, options.common, options.channels, options.bps, options.sample_rate, /*flac_decoder_data=*/0)) return EncoderSession_finish_error(&encoder_session); /* @@ -1036,7 +1057,7 @@ int flac__encode_raw(FILE *infile, off_t infilesize, const char *infilename, con while(total_input_bytes_read < max_input_bytes) { { size_t wanted = (CHUNK_OF_SAMPLES * bytes_per_wide_sample); - wanted = (size_t) min((off_t)wanted, max_input_bytes - total_input_bytes_read); + wanted = (size_t) min((FLAC__uint64)wanted, max_input_bytes - total_input_bytes_read); if(lookahead_length > 0) { FLAC__ASSERT(lookahead_length <= wanted); @@ -1126,6 +1147,163 @@ int flac__encode_raw(FILE *infile, off_t infilesize, const char *infilename, con return EncoderSession_finish_ok(&encoder_session, info_align_carry, info_align_zero); } +int flac__encode_flac(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, flac_encode_options_t options) +{ + EncoderSession encoder_session; + FLAC__SeekableStreamDecoder *decoder = 0; + FLACDecoderData decoder_data; + size_t i; + int retval; + + if(! + EncoderSession_construct( + &encoder_session, +#ifdef FLAC__HAS_OGG + options.common.use_ogg, +#else + /*use_ogg=*/false, +#endif + options.common.verify, + infile, + infilename, + outfilename + ) + ) + return 1; + + decoder_data.encoder_session = &encoder_session; + decoder_data.filesize = (infilesize == (off_t)(-1)? 0 : infilesize); + decoder_data.lookahead = lookahead; + decoder_data.lookahead_length = lookahead_length; + decoder_data.num_metadata_blocks = 0; + decoder_data.samples_left_to_process = 0; + decoder_data.fatal_error = false; + + /* + * set up FLAC decoder for the input + */ + if (0 == (decoder = FLAC__seekable_stream_decoder_new())) { + flac__utils_printf(stderr, 1, "%s: ERROR: creating decoder for FLAC input\n", encoder_session.inbasefilename); + return EncoderSession_finish_error(&encoder_session); + } + if (!( + FLAC__seekable_stream_decoder_set_md5_checking(decoder, false) && + FLAC__seekable_stream_decoder_set_read_callback(decoder, flac_decoder_read_callback) && + FLAC__seekable_stream_decoder_set_seek_callback(decoder, flac_decoder_seek_callback) && + FLAC__seekable_stream_decoder_set_tell_callback(decoder, flac_decoder_tell_callback) && + FLAC__seekable_stream_decoder_set_length_callback(decoder, flac_decoder_length_callback) && + FLAC__seekable_stream_decoder_set_eof_callback(decoder, flac_decoder_eof_callback) && + FLAC__seekable_stream_decoder_set_write_callback(decoder, flac_decoder_write_callback) && + FLAC__seekable_stream_decoder_set_metadata_callback(decoder, flac_decoder_metadata_callback) && + FLAC__seekable_stream_decoder_set_error_callback(decoder, flac_decoder_error_callback) && + FLAC__seekable_stream_decoder_set_client_data(decoder, &decoder_data) && + FLAC__seekable_stream_decoder_set_metadata_respond_all(decoder) + )) { + flac__utils_printf(stderr, 1, "%s: ERROR: setting up decoder for FLAC input\n", encoder_session.inbasefilename); + goto fubar1; /*@@@ yuck */ + } + + if (FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) { + flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__seekable_stream_decoder_get_resolved_state_string(decoder)); + goto fubar1; /*@@@ yuck */ + } + + if (!FLAC__seekable_stream_decoder_process_until_end_of_metadata(decoder) || decoder_data.fatal_error) { + if (decoder_data.fatal_error) + flac__utils_printf(stderr, 1, "%s: ERROR: out of memory or too many metadata blocks while reading metadata in FLAC input\n", encoder_session.inbasefilename); + else + flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__seekable_stream_decoder_get_resolved_state_string(decoder)); + goto fubar1; /*@@@ yuck */ + } + + if (decoder_data.num_metadata_blocks == 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, got no metadata blocks\n", encoder_session.inbasefilename); + goto fubar2; /*@@@ yuck */ + } + else if (decoder_data.metadata_blocks[0]->type != FLAC__METADATA_TYPE_STREAMINFO) { + flac__utils_printf(stderr, 1, "%s: ERROR: reading metadata in FLAC input, first metadata block is not STREAMINFO\n", encoder_session.inbasefilename); + goto fubar2; /*@@@ yuck */ + } + else if (decoder_data.metadata_blocks[0]->data.stream_info.total_samples == 0) { + flac__utils_printf(stderr, 1, "%s: ERROR: FLAC input has STREAMINFO with unknown total samples which is not supported\n", encoder_session.inbasefilename); + goto fubar2; /*@@@ yuck */ + } + + /* + * now that we have the STREAMINFO and know the sample rate, + * canonicalize the --skip string to a number of samples: + */ + flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, decoder_data.metadata_blocks[0]->data.stream_info.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); /* --sector-align with FLAC input is not supported */ + + { + FLAC__uint64 total_samples_in_input, trim = 0; + + total_samples_in_input = decoder_data.metadata_blocks[0]->data.stream_info.total_samples; + + /* + * now that we know the input size, canonicalize the + * --until string to an absolute sample number: + */ + if(!canonicalize_until_specification(&options.common.until_specification, encoder_session.inbasefilename, decoder_data.metadata_blocks[0]->data.stream_info.sample_rate, encoder_session.skip, total_samples_in_input)) + goto fubar2; /*@@@ yuck */ + encoder_session.until = (FLAC__uint64)options.common.until_specification.value.samples; + + 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); + encoder_session.total_samples_to_encode -= trim; + } + + encoder_session.unencoded_size = decoder_data.filesize; + + if(!EncoderSession_init_encoder(&encoder_session, options.common, decoder_data.metadata_blocks[0]->data.stream_info.channels, decoder_data.metadata_blocks[0]->data.stream_info.bits_per_sample, decoder_data.metadata_blocks[0]->data.stream_info.sample_rate, &decoder_data)) + return EncoderSession_finish_error(&encoder_session); + + /* + * have to wait until the FLAC encoder is set up for writing + * before any seeking in the input FLAC file, because the seek + * itself will usually call the decoder's write callback, and + * our decoder's write callback passes samples to our FLAC + * encoder + */ + decoder_data.samples_left_to_process = encoder_session.total_samples_to_encode; + if(encoder_session.skip > 0) { + if(!FLAC__seekable_stream_decoder_seek_absolute(decoder, encoder_session.skip)) { + flac__utils_printf(stderr, 1, "%s: ERROR while skipping samples, FLAC decoder state = %s\n", encoder_session.inbasefilename, FLAC__seekable_stream_decoder_get_resolved_state_string(decoder)); + goto fubar2; /*@@@ yuck */ + } + } + + /* + * now do samples from the file + */ + while(!decoder_data.fatal_error && decoder_data.samples_left_to_process > 0) { + if(!FLAC__seekable_stream_decoder_process_single(decoder)) { + flac__utils_printf(stderr, 1, "%s: ERROR: while decoding FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__seekable_stream_decoder_get_resolved_state_string(decoder)); + goto fubar2; /*@@@ yuck */ + } + } + } + + FLAC__seekable_stream_decoder_delete(decoder); + retval = EncoderSession_finish_ok(&encoder_session, -1, -1); + /* have to wail until encoder is completely finished before deleting because of the final step of writing the seekpoint offsets */ + for(i = 0; i < decoder_data.num_metadata_blocks; i++) + free(decoder_data.metadata_blocks[i]); + return retval; + +fubar2: + for(i = 0; i < decoder_data.num_metadata_blocks; i++) + free(decoder_data.metadata_blocks[i]); +fubar1: + FLAC__seekable_stream_decoder_delete(decoder); + return EncoderSession_finish_error(&encoder_session); +} + FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg, FLAC__bool verify, FILE *infile, const char *infilename, const char *outfilename) { unsigned i; @@ -1355,6 +1533,7 @@ int EncoderSession_finish_error(EncoderSession *e) if(fse_state == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) print_verify_error(e); else + /*@@@@@@@@@ BUG: if error was caused because the output file already exists but the file encoder could not write on top of it (i.e. it's not writable), this will delete the pre-existing file, which is not what we want */ unlink(e->outfilename); EncoderSession_destroy(e); @@ -1362,11 +1541,12 @@ int EncoderSession_finish_error(EncoderSession *e) return 1; } -FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options, unsigned channels, unsigned bps, unsigned sample_rate) +FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options, unsigned channels, unsigned bps, unsigned sample_rate, FLACDecoderData *flac_decoder_data) { unsigned num_metadata; FLAC__StreamMetadata padding, *cuesheet = 0; - FLAC__StreamMetadata *metadata[4]; + FLAC__StreamMetadata *static_metadata[4]; + FLAC__StreamMetadata **metadata = static_metadata; const FLAC__bool is_cdda = (channels == 1 || channels == 2) && (bps == 16) && (sample_rate == 44100); e->replay_gain = options.replay_gain; @@ -1394,7 +1574,7 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio if(channels != 2) options.do_mid_side = options.loose_mid_side = false; - if(!parse_cuesheet_(&cuesheet, options.cuesheet_filename, e->inbasefilename, is_cdda, e->total_samples_to_encode)) + if(!parse_cuesheet(&cuesheet, options.cuesheet_filename, e->inbasefilename, is_cdda, e->total_samples_to_encode)) return false; if(!convert_to_seek_table_template(options.requested_seek_points, options.num_requested_seek_points, options.cued_seekpoints? cuesheet : 0, e)) { @@ -1404,19 +1584,206 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio return false; } - num_metadata = 0; - if(e->seek_table_template->data.seek_table.num_points > 0) { - e->seek_table_template->is_last = false; /* the encoder will set this for us */ - metadata[num_metadata++] = e->seek_table_template; + if(flac_decoder_data) { + /* + * we're encoding from FLAC so we will use the FLAC file's + * metadata as the basic for the encoded file + */ + { + /* + * first handle padding: if --no-padding was specified, + * then delete all padding; else if -P was specified, + * use that instead of existing padding (if any); else + * if existing file has padding, move all existing + * padding blocks to one padding block at the end; else + * use default padding. + */ + int p = -1; + size_t i, j; + for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) { + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_PADDING) { + if(p < 0) + p = 0; + p += flac_decoder_data->metadata_blocks[i]->length; + FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]); + flac_decoder_data->metadata_blocks[i] = 0; + } + else + flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i]; + } + flac_decoder_data->num_metadata_blocks = j; + if(options.padding > 0) + p = options.padding; + if(p < 0) + p = FLAC_ENCODE__DEFAULT_PADDING; + if(options.padding != 0) { + if(p > 0 && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) { + flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING); + if(0 == flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for PADDING block\n", e->inbasefilename); + if(0 != cuesheet) + FLAC__metadata_object_delete(cuesheet); + return false; + } + flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]->is_last = false; /* the encoder will set this for us */ + flac_decoder_data->metadata_blocks[flac_decoder_data->num_metadata_blocks]->length = p; + flac_decoder_data->num_metadata_blocks++; + } + } + } + { + /* + * next handle vorbis comment: if any tags were specified + * or there is no existing vorbis comment, we create a + * new vorbis comment (discarding any existing one); else + * we keep the existing one + */ + size_t i, j; + FLAC__bool vc_found = false; + for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) { + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) + vc_found = true; + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT && options.vorbis_comment->data.vorbis_comment.num_comments > 0) { + if(options.vorbis_comment->data.vorbis_comment.num_comments > 0) + flac__utils_printf(stderr, 1, "%s: WARNING, replacing tags from input FLAC file with those given on the command-line\n", e->inbasefilename); + FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]); + flac_decoder_data->metadata_blocks[i] = 0; + } + else + flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i]; + } + flac_decoder_data->num_metadata_blocks = j; + if((!vc_found || options.vorbis_comment->data.vorbis_comment.num_comments > 0) && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) { + /* prepend ours */ + FLAC__StreamMetadata *vc = FLAC__metadata_object_clone(options.vorbis_comment); + if(0 == vc) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for VORBIS_COMMENT block\n", e->inbasefilename); + if(0 != cuesheet) + FLAC__metadata_object_delete(cuesheet); + return false; + } + for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--) + flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1]; + flac_decoder_data->metadata_blocks[1] = vc; + flac_decoder_data->num_metadata_blocks++; + } + } + { + /* + * next handle cuesheet: if --cuesheet was specified, use + * it; else if file has existing CUESHEET and cuesheet's + * lead-out offset is correct, keep it; else no CUESHEET + */ + size_t i, j; + for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) { + FLAC__bool existing_cuesheet_is_bad = false; + /* check if existing cuesheet matches the input audio */ + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_CUESHEET && 0 == cuesheet) { + const FLAC__StreamMetadata_CueSheet *cs = &flac_decoder_data->metadata_blocks[i]->data.cue_sheet; + if(e->total_samples_to_encode == 0) { + flac__utils_printf(stderr, 1, "%s: WARNING, cuesheet in input FLAC file cannot be kept if input size is not known, dropping it...\n", e->inbasefilename); + existing_cuesheet_is_bad = true; + } + else if(e->total_samples_to_encode != cs->tracks[cs->num_tracks-1].offset) { + flac__utils_printf(stderr, 1, "%s: WARNING, lead-out offset of cuesheet in input FLAC file does not match input length, dropping existing cuesheet...\n", e->inbasefilename); + existing_cuesheet_is_bad = true; + } + } + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_CUESHEET && (existing_cuesheet_is_bad || 0 != cuesheet)) { + if(0 != cuesheet) + flac__utils_printf(stderr, 1, "%s: WARNING, replacing cuesheet in input FLAC file with the one given on the command-line\n", e->inbasefilename); + FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]); + flac_decoder_data->metadata_blocks[i] = 0; + } + else + flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i]; + } + flac_decoder_data->num_metadata_blocks = j; + if(0 != cuesheet && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) { + /* prepend ours */ + FLAC__StreamMetadata *cs = FLAC__metadata_object_clone(cuesheet); + if(0 == cs) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for CUESHEET block\n", e->inbasefilename); + if(0 != cuesheet) + FLAC__metadata_object_delete(cuesheet); + return false; + } + for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--) + flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1]; + flac_decoder_data->metadata_blocks[1] = cs; + flac_decoder_data->num_metadata_blocks++; + } + } + { + /* + * finally handle seektable: if -S- was specified, no + * SEEKTABLE; else if -S was specified, use it/them; + * else if file has existing SEEKTABLE and input size is + * preserved (no --skip/--until/etc specified), keep it; + * else use default seektable options + * + * note: meanings of num_requested_seek_points: + * -1 : no -S option given, default to some value + * 0 : -S- given (no seektable) + * >0 : one or more -S options given + */ + size_t i, j; + FLAC__bool existing_seektable = false; + for(i = 0, j = 0; i < flac_decoder_data->num_metadata_blocks; i++) { + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) + existing_seektable = true; + if(flac_decoder_data->metadata_blocks[i]->type == FLAC__METADATA_TYPE_SEEKTABLE && (e->total_samples_to_encode != flac_decoder_data->metadata_blocks[0]->data.stream_info.total_samples || options.num_requested_seek_points >= 0)) { + if(options.num_requested_seek_points > 0) + flac__utils_printf(stderr, 1, "%s: WARNING, replacing seektable in input FLAC file with the one given on the command-line\n", e->inbasefilename); + else if(options.num_requested_seek_points == 0) + ; /* no warning, silently delete existing SEEKTABLE since user specified --no-seektable (-S-) */ + else + flac__utils_printf(stderr, 1, "%s: WARNING, can't use existing seektable in input FLAC since the input size is changing or unknown, dropping existing SEEKTABLE block...\n", e->inbasefilename); + FLAC__metadata_object_delete(flac_decoder_data->metadata_blocks[i]); + flac_decoder_data->metadata_blocks[i] = 0; + existing_seektable = false; + } + else + flac_decoder_data->metadata_blocks[j++] = flac_decoder_data->metadata_blocks[i]; + } + flac_decoder_data->num_metadata_blocks = j; + if((options.num_requested_seek_points > 0 || (options.num_requested_seek_points < 0 && !existing_seektable)) && flac_decoder_data->num_metadata_blocks < sizeof(flac_decoder_data->metadata_blocks)/sizeof(flac_decoder_data->metadata_blocks[0])) { + /* prepend ours */ + FLAC__StreamMetadata *st = FLAC__metadata_object_clone(e->seek_table_template); + if(0 == st) { + flac__utils_printf(stderr, 1, "%s: ERROR allocating memory for SEEKTABLE block\n", e->inbasefilename); + if(0 != cuesheet) + FLAC__metadata_object_delete(cuesheet); + return false; + } + for(i = flac_decoder_data->num_metadata_blocks; i > 1; i--) + flac_decoder_data->metadata_blocks[i] = flac_decoder_data->metadata_blocks[i-1]; + flac_decoder_data->metadata_blocks[1] = st; + flac_decoder_data->num_metadata_blocks++; + } + } + metadata = &flac_decoder_data->metadata_blocks[1]; /* don't include STREAMINFO */ + num_metadata = flac_decoder_data->num_metadata_blocks - 1; } - if(0 != cuesheet) - metadata[num_metadata++] = cuesheet; - metadata[num_metadata++] = options.vorbis_comment; - if(options.padding > 0) { - padding.is_last = false; /* the encoder will set this for us */ - padding.type = FLAC__METADATA_TYPE_PADDING; - padding.length = (unsigned)options.padding; - metadata[num_metadata++] = &padding; + else { + /* + * we're not encoding from FLAC so we will build the metadata + * from scratch + */ + num_metadata = 0; + if(e->seek_table_template->data.seek_table.num_points > 0) { + e->seek_table_template->is_last = false; /* the encoder will set this for us */ + metadata[num_metadata++] = e->seek_table_template; + } + if(0 != cuesheet) + metadata[num_metadata++] = cuesheet; + metadata[num_metadata++] = options.vorbis_comment; + if(options.padding != 0) { + padding.is_last = false; /* the encoder will set this for us */ + padding.type = FLAC__METADATA_TYPE_PADDING; + padding.length = (unsigned)(options.padding>0? options.padding : FLAC_ENCODE__DEFAULT_PADDING); + metadata[num_metadata++] = &padding; + } } e->blocksize = options.blocksize; @@ -1850,7 +2217,122 @@ void flac_file_encoder_progress_callback(const FLAC__FileEncoder *encoder, FLAC_ print_stats(encoder_session); } -FLAC__bool parse_cuesheet_(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset) +FLAC__SeekableStreamDecoderReadStatus flac_decoder_read_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) +{ + size_t n = 0; + FLACDecoderData *data = (FLACDecoderData*)client_data; + (void)decoder; + + if (data->fatal_error) + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; + + /* use up lookahead first */ + if (data->lookahead_length) { + n = min(data->lookahead_length, *bytes); + memcpy(buffer, data->lookahead, n); + buffer += n; + data->lookahead += n; + data->lookahead_length -= n; + } + + /* get the rest from file */ + if (*bytes > n) { + *bytes = n + fread(buffer, 1, *bytes-n, data->encoder_session->fin); + return ferror(data->encoder_session->fin)? FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR : FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; + } + else + return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK; +} + +FLAC__SeekableStreamDecoderSeekStatus flac_decoder_seek_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + FLACDecoderData *data = (FLACDecoderData*)client_data; + (void)decoder; + + if(fseeko(data->encoder_session->fin, (off_t)absolute_byte_offset, SEEK_SET) < 0) + return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR; + else + return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK; +} + +FLAC__SeekableStreamDecoderTellStatus flac_decoder_tell_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + FLACDecoderData *data = (FLACDecoderData*)client_data; + off_t pos; + (void)decoder; + + if((pos = ftello(data->encoder_session->fin)) < 0) + return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR; + else { + *absolute_byte_offset = (FLAC__uint64)pos; + return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK; + } +} + +FLAC__SeekableStreamDecoderLengthStatus flac_decoder_length_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) +{ + FLACDecoderData *data = (FLACDecoderData*)client_data; + (void)decoder; + + if(0 == data->filesize) + return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR; + else { + *stream_length = (FLAC__uint64)data->filesize; + return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK; + } +} + +FLAC__bool flac_decoder_eof_callback(const FLAC__SeekableStreamDecoder *decoder, void *client_data) +{ + FLACDecoderData *data = (FLACDecoderData*)client_data; + (void)decoder; + + return feof(data->encoder_session->fin)? true : false; +} + +FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(const FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + FLACDecoderData *data = (FLACDecoderData*)client_data; + FLAC__uint64 n = min(data->samples_left_to_process, frame->header.blocksize); + (void)decoder; + + if(!EncoderSession_process(data->encoder_session, buffer, n)) { + print_error_with_state(data->encoder_session, "ERROR during encoding"); + data->fatal_error = true; + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + data->samples_left_to_process -= n; + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void flac_decoder_metadata_callback(const FLAC__SeekableStreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + FLACDecoderData *data = (FLACDecoderData*)client_data; + (void)decoder; + + if (data->fatal_error) + return; + + if ( + data->num_metadata_blocks == sizeof(data->metadata_blocks)/sizeof(data->metadata_blocks[0]) || + 0 == (data->metadata_blocks[data->num_metadata_blocks] = FLAC__metadata_object_clone(metadata)) + ) + data->fatal_error = true; + else + data->num_metadata_blocks++; +} + +void flac_decoder_error_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + FLACDecoderData *data = (FLACDecoderData*)client_data; + (void)decoder; + + flac__utils_printf(stderr, 1, "%s: ERROR got %s while decoding FLAC input\n", data->encoder_session->inbasefilename, FLAC__StreamDecoderErrorStatusString[status]); + data->fatal_error = true; +} + +FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_filename, const char *inbasefilename, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset) { FILE *f; unsigned last_line_read; @@ -1951,7 +2433,7 @@ void print_error_with_state(const EncoderSession *e, const char *message) "\n" "The encoding parameters specified do not conform to the FLAC Subset and may not\n" "be streamable or playable in hardware devices. Add --lax to the command-line\n" - "options to encode with these parameters.\n" + "options to encode with these parameters anyway.\n" ); } else if( @@ -2010,13 +2492,13 @@ void print_verify_error(EncoderSession *e) flac__utils_printf(stderr, 1, "%s: ERROR: mismatch in decoded data, verify FAILED!\n", e->inbasefilename); flac__utils_printf(stderr, 1, " Absolute sample=%u, frame=%u, channel=%u, sample=%u, expected %d, got %d\n", (unsigned)absolute_sample, frame_number, channel, sample, expected, got); flac__utils_printf(stderr, 1, " In all known cases, verify errors are caused by hardware problems,\n"); - flac__utils_printf(stderr, 1, " usually overclocking or bad RAM. Delete %s\n", e->inbasefilename); + flac__utils_printf(stderr, 1, " usually overclocking or bad RAM. Delete %s\n", e->outfilename); flac__utils_printf(stderr, 1, " and repeat the flac command exactly as before. If it does not give a\n"); flac__utils_printf(stderr, 1, " verify error in the exact same place each time you try it, then there is\n"); flac__utils_printf(stderr, 1, " a problem with your hardware; please see the FAQ:\n"); flac__utils_printf(stderr, 1, " http://flac.sourceforge.net/faq.html#tools__hardware_prob\n"); - flac__utils_printf(stderr, 1, " If it does fail in the exact same place every time, keep the bad FLAC\n"); - flac__utils_printf(stderr, 1, " file and submit a bug report to:\n"); + flac__utils_printf(stderr, 1, " If it does fail in the exact same place every time, keep\n"); + flac__utils_printf(stderr, 1, " %s and submit a bug report to:\n", e->outfilename); flac__utils_printf(stderr, 1, " https://sourceforge.net/bugs/?func=addbug&group_id=13478\n"); flac__utils_printf(stderr, 1, " Make sure to upload the FLAC file and use the \"Monitor\" feature to\n"); flac__utils_printf(stderr, 1, " monitor the bug status.\n"); diff --git a/src/flac/encode.h b/src/flac/encode.h index cfda5434..7a274d7f 100644 --- a/src/flac/encode.h +++ b/src/flac/encode.h @@ -31,6 +31,8 @@ #include <config.h> #endif +extern const int FLAC_ENCODE__DEFAULT_PADDING; + typedef struct { utils__SkipUntilSpecification skip_specification; utils__SkipUntilSpecification until_specification; @@ -89,8 +91,13 @@ typedef struct { unsigned sample_rate; } raw_encode_options_t; +typedef struct { + encode_options_t common; +} flac_encode_options_t; + int flac__encode_aif(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options, FLAC__bool is_aifc); int flac__encode_wav(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options); int flac__encode_raw(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, raw_encode_options_t options); +int flac__encode_flac(FILE *infile, off_t infilesize, const char *infilename, const char *outfilename, const FLAC__byte *lookahead, unsigned lookahead_length, flac_encode_options_t options); #endif diff --git a/src/flac/main.c b/src/flac/main.c index 14db8daf..07e98647 100644 --- a/src/flac/main.c +++ b/src/flac/main.c @@ -56,7 +56,7 @@ # include "share/getopt.h" #endif -typedef enum { RAW, WAV, AIF } FileFormat; +typedef enum { RAW, WAV, AIF, FLAC } FileFormat; static int do_it(); @@ -234,7 +234,7 @@ static struct { const char *cmdline_forced_outfilename; const char *output_prefix; analysis_options aopts; - int padding; + int padding; /* -1 => no -P options were given, 0 => -P- was given, else -P value */ char apodizations[1000]; /* bad MAGIC NUMBER but buffer overflow is checked */ unsigned max_lpc_order; unsigned qlp_coeff_precision; @@ -287,6 +287,7 @@ int main(int argc, char *argv[]) _wildcard(&argc, &argv); #endif + srand(time(0)); setlocale(LC_ALL, ""); if(!init_options()) { flac__utils_printf(stderr, 1, "ERROR: allocating memory\n"); @@ -435,7 +436,7 @@ int do_it() * tags that we will set later, to avoid rewriting the * whole file. */ - if(option_values.padding < 0) { + if(option_values.padding <= 0) { flac__utils_printf(stderr, 1, "NOTE: --replay-gain may leave a small PADDING block even with --no-padding\n"); option_values.padding = GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED; } @@ -461,10 +462,10 @@ int do_it() if(!option_values.mode_decode) { char padopt[16]; - if(option_values.padding < 0) + if(option_values.padding == 0) strcpy(padopt, "-"); else - sprintf(padopt, " %d", option_values.padding); + sprintf(padopt, " %d", option_values.padding > 0? option_values.padding : FLAC_ENCODE__DEFAULT_PADDING); flac__utils_printf(stderr, 2, "options:%s%s%s%s -P%s -b %u%s -l %u%s%s%s -q %u -r %u,%u%s\n", option_values.delete_input?" --delete-input-file":"", @@ -580,7 +581,7 @@ FLAC__bool init_options() option_values.output_prefix = 0; option_values.aopts.do_residual_text = false; option_values.aopts.do_residual_gnuplot = false; - option_values.padding = 4096; + option_values.padding = -1; option_values.apodizations[0] = '\0'; option_values.max_lpc_order = 8; option_values.qlp_coeff_precision = 0; @@ -860,7 +861,7 @@ int parse_option(int short_option, const char *long_option, const char *option_a option_values.do_qlp_coeff_prec_search = false; } else if(0 == strcmp(long_option, "no-padding")) { - option_values.padding = -1; + option_values.padding = 0; } else if(0 == strcmp(long_option, "no-verify")) { option_values.verify = false; @@ -1040,7 +1041,7 @@ int parse_option(int short_option, const char *long_option, const char *option_a FLAC__ASSERT(0 != option_argument); option_values.padding = atoi(option_argument); if(option_values.padding < 0) - return usage_error("ERROR: argument to -P must be >= 0\n"); + return usage_error("ERROR: argument to -P must be >= 0; for no padding use -P-\n"); break; case 'b': FLAC__ASSERT(0 != option_argument); @@ -1552,22 +1553,15 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ int retval; off_t infilesize; encode_options_t common_options; - const char *outfilename = get_encoded_outfilename(infilename); + const char *outfilename = get_encoded_outfilename(infilename); /* the final name of the encoded file */ + /* internal_outfilename is the file we will actually write to; it will be a temporary name if infilename==outfilename */ + char *internal_outfilename = 0; /* NULL implies 'use outfilename' */ if(0 == outfilename) { flac__utils_printf(stderr, 1, "ERROR: filename too long: %s", infilename); return 1; } - /* - * Error if output file already exists (and -f not used). - * Use grabbag__file_get_filesize() as a cheap way to check. - */ - if(!option_values.test_only && !option_values.force_file_overwrite && grabbag__file_get_filesize(outfilename) != (off_t)(-1)) { - flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename); - return 1; - } - if(0 == strcmp(infilename, "-")) { infilesize = (off_t)(-1); encode_infile = grabbag__file_get_binary_stdin(); @@ -1588,6 +1582,8 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ fmt= AIF; else if(strlen(infilename) >= 5 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-5), ".aiff")) fmt= AIF; + else if(strlen(infilename) >= 5 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-5), ".flac")) + fmt= FLAC; /* attempt to guess the file type based on the first 12 bytes */ if((lookahead_length = fread(lookahead, 1, 12, encode_infile)) < 12) { @@ -1604,6 +1600,8 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ fmt= AIF; is_aifc = true; } + else if(!strncmp((const char *)lookahead, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING))) + fmt= FLAC; else { if(fmt != RAW) format_mistake(infilename, fmt == AIF ? "AIFF" : "WAVE", "raw"); @@ -1612,6 +1610,27 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ } } + /* + * Error if output file already exists (and -f not used). + * Use grabbag__file_get_filesize() as a cheap way to check. + */ + if(!option_values.test_only && !option_values.force_file_overwrite && strcmp(outfilename, "-") && grabbag__file_get_filesize(outfilename) != (off_t)(-1)) { + if(fmt == FLAC) { + /* need more detailed error message when re-flac'ing to avoid confusing the user */ + flac__utils_printf(stderr, 1, + "ERROR: output file %s already exists.\n\n" + "By default flac encodes files to FLAC format; if you meant to decode this file\n" + "from FLAC to something else, use -d. If you meant to re-encode this file from\n" + "FLAC to FLAC again, use -f to force writing to the same file, or -o to specify\n" + "a different output filename.\n", + outfilename + ); + } + else + flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename); + return 1; + } + if(option_values.format_input_size >= 0) { if (fmt != RAW || infilesize >= 0) { flac__utils_printf(stderr, 1, "ERROR: can only use --input-size when encoding raw samples from stdin\n"); @@ -1622,8 +1641,12 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ } } + if(option_values.sector_align && fmt == FLAC) { + flac__utils_printf(stderr, 1, "ERROR: can't use --sector-align when the input file is FLAC\n"); + return 1; + } if(option_values.sector_align && fmt == RAW && infilesize < 0) { - flac__utils_printf(stderr, 1, "ERROR: can't --sector-align when the input size is unknown\n"); + flac__utils_printf(stderr, 1, "ERROR: can't use --sector-align when the input size is unknown\n"); return 1; } @@ -1651,7 +1674,6 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ common_options.use_ogg = option_values.use_ogg; /* set a random serial number if one has not yet been specified */ if(!option_values.has_serial_number) { - srand(time(0)); option_values.serial_number = rand(); option_values.has_serial_number = true; } @@ -1686,6 +1708,17 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ common_options.debug.disable_fixed_subframes = option_values.debug.disable_fixed_subframes; common_options.debug.disable_verbatim_subframes = option_values.debug.disable_verbatim_subframes; + /* if infilename==outfilename, we need to write to a temporary file */ + if(encode_infile != stdin && 0 == strcmp(infilename, outfilename)) { /*@@@@@@ BUG strcmp is not adequate to check if infilename and outfilename are the same file */ + static const char *tmp_suffix = ".tmp"; + if(0 == (internal_outfilename = malloc(strlen(outfilename)+strlen(tmp_suffix)+1))) { + flac__utils_printf(stderr, 1, "ERROR allocating memory for tempfile name\n"); + return 1; + } + strcpy(internal_outfilename, outfilename); + strcat(internal_outfilename, tmp_suffix); + } + if(fmt == RAW) { raw_encode_options_t options; @@ -1696,7 +1729,14 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ options.bps = option_values.format_bps; options.sample_rate = option_values.format_sample_rate; - retval = flac__encode_raw(encode_infile, infilesize, infilename, outfilename, lookahead, lookahead_length, options); + retval = flac__encode_raw(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options); + } + else if(fmt == FLAC) { + flac_encode_options_t options; + + options.common = common_options; + + retval = flac__encode_flac(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options); } else { wav_encode_options_t options; @@ -1704,27 +1744,41 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_ options.common = common_options; if(fmt == AIF) - retval = flac__encode_aif(encode_infile, infilesize, infilename, outfilename, lookahead, lookahead_length, options, is_aifc); + retval = flac__encode_aif(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options, is_aifc); else - retval = flac__encode_wav(encode_infile, infilesize, infilename, outfilename, lookahead, lookahead_length, options); + retval = flac__encode_wav(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options); } - if(retval == 0 && strcmp(infilename, "-")) { + if(retval == 0) { if(strcmp(outfilename, "-")) { if(option_values.replay_gain) { float title_gain, title_peak; const char *error; grabbag__replaygain_get_title(&title_gain, &title_peak); - if(0 != (error = grabbag__replaygain_store_to_file_title(outfilename, title_gain, title_peak, /*preserve_modtime=*/true))) { + if(0 != (error = grabbag__replaygain_store_to_file_title(internal_outfilename, title_gain, title_peak, /*preserve_modtime=*/true))) { flac__utils_printf(stderr, 1, "%s: ERROR writing ReplayGain title tags\n", outfilename); } } - grabbag__file_copy_metadata(infilename, outfilename); + if(strcmp(infilename, "-")) + grabbag__file_copy_metadata(infilename, internal_outfilename); } - if(option_values.delete_input) - unlink(infilename); } + /* rename temporary file if necessary */ + if(retval == 0 && internal_outfilename != 0) { + if(rename(internal_outfilename, outfilename) < 0) { + flac__utils_printf(stderr, 1, "ERROR: moving new FLAC file %s back on top of original FLAC file %s, keeping both\n", internal_outfilename, outfilename); + retval = 1; + } + } + + /* handle --delete-input-file, but don't want to delete if piping from stdin, or if input filename and output filename are the same */ + if(retval == 0 && option_values.delete_input && strcmp(infilename, "-") && internal_outfilename == 0) + unlink(infilename); + + if(internal_outfilename != 0) + free(internal_outfilename); + return retval; } @@ -1870,14 +1924,7 @@ const char *get_outfilename(const char *infilename, const char *suffix) return 0; } else { - if(0 == strcmp(p, suffix)) { - *p = '\0'; - if (flac__strlcat(buffer, "_new", sizeof buffer) >= sizeof buffer) - return 0; - } - else { - *p = '\0'; - } + *p = '\0'; if (flac__strlcat(buffer, suffix, sizeof buffer) >= sizeof buffer) return 0; } |