implement --cuesheet and --no-cued-seekpoints
This commit is contained in:
parent
cef5703fc3
commit
d7fa6ab5b1
@ -125,7 +125,7 @@ static int EncoderSession_finish_ok(EncoderSession *e, int info_align_carry, int
|
||||
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_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, EncoderSession *e);
|
||||
static FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int num_requested_seek_points, FLAC__StreamMetadata *cuesheet, EncoderSession *e);
|
||||
static void format_input(FLAC__int32 *dest[], unsigned wide_samples, FLAC__bool is_big_endian, FLAC__bool is_unsigned_samples, unsigned channels, unsigned bps);
|
||||
#ifdef FLAC__HAS_OGG
|
||||
static FLAC__StreamEncoderWriteStatus ogg_stream_encoder_write_callback(const OggFLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
|
||||
@ -133,6 +133,7 @@ static FLAC__StreamEncoderWriteStatus ogg_stream_encoder_write_callback(const Og
|
||||
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__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);
|
||||
@ -1178,8 +1179,8 @@ int EncoderSession_finish_error(EncoderSession *e)
|
||||
FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t options, unsigned channels, unsigned bps, unsigned sample_rate)
|
||||
{
|
||||
unsigned num_metadata;
|
||||
FLAC__StreamMetadata padding;
|
||||
FLAC__StreamMetadata *metadata[3];
|
||||
FLAC__StreamMetadata padding, *cuesheet = 0;
|
||||
FLAC__StreamMetadata *metadata[4];
|
||||
|
||||
e->replay_gain = options.replay_gain;
|
||||
e->channels = channels;
|
||||
@ -1206,17 +1207,24 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
|
||||
if(channels != 2)
|
||||
options.do_mid_side = options.loose_mid_side = false;
|
||||
|
||||
if(!convert_to_seek_table_template(options.requested_seek_points, options.num_requested_seek_points, e)) {
|
||||
if(!parse_cuesheet_(&cuesheet, options.cuesheet_filename, e->inbasefilename, 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)) {
|
||||
fprintf(stderr, "%s: ERROR allocating memory for seek table\n", e->inbasefilename);
|
||||
if(0 != cuesheet)
|
||||
free(cuesheet);
|
||||
return false;
|
||||
}
|
||||
|
||||
num_metadata = 0;
|
||||
metadata[num_metadata++] = options.vorbis_comment;
|
||||
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;
|
||||
@ -1258,6 +1266,8 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
|
||||
|
||||
if(OggFLAC__stream_encoder_init(e->encoder.ogg.stream) != FLAC__STREAM_ENCODER_OK) {
|
||||
print_error_with_state(e, "ERROR initializing encoder");
|
||||
if(0 != cuesheet)
|
||||
free(cuesheet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1292,6 +1302,8 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
|
||||
|
||||
if(FLAC__stream_encoder_init(e->encoder.flac.stream) != FLAC__STREAM_ENCODER_OK) {
|
||||
print_error_with_state(e, "ERROR initializing encoder");
|
||||
if(0 != cuesheet)
|
||||
free(cuesheet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1324,10 +1336,15 @@ FLAC__bool EncoderSession_init_encoder(EncoderSession *e, encode_options_t optio
|
||||
|
||||
if(FLAC__file_encoder_init(e->encoder.flac.file) != FLAC__FILE_ENCODER_OK) {
|
||||
print_error_with_state(e, "ERROR initializing encoder");
|
||||
if(0 != cuesheet)
|
||||
free(cuesheet);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(0 != cuesheet)
|
||||
free(cuesheet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1352,16 +1369,18 @@ FLAC__bool EncoderSession_process(EncoderSession *e, const FLAC__int32 * const b
|
||||
}
|
||||
}
|
||||
|
||||
FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int num_requested_seek_points, EncoderSession *e)
|
||||
FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int num_requested_seek_points, FLAC__StreamMetadata *cuesheet, EncoderSession *e)
|
||||
{
|
||||
FLAC__bool only_placeholders;
|
||||
FLAC__bool has_real_points;
|
||||
|
||||
if(num_requested_seek_points == 0)
|
||||
if(num_requested_seek_points == 0 && 0 == cuesheet)
|
||||
return true;
|
||||
|
||||
if(num_requested_seek_points < 0)
|
||||
if(num_requested_seek_points < 0) {
|
||||
requested_seek_points = "100x;";
|
||||
num_requested_seek_points = 1;
|
||||
}
|
||||
|
||||
if(e->is_stdout)
|
||||
only_placeholders = true;
|
||||
@ -1372,8 +1391,26 @@ FLAC__bool convert_to_seek_table_template(const char *requested_seek_points, int
|
||||
else
|
||||
only_placeholders = false;
|
||||
|
||||
if(!grabbag__seektable_convert_specification_to_template(requested_seek_points, only_placeholders, e->total_samples_to_encode, e->sample_rate, e->seek_table_template, &has_real_points))
|
||||
return false;
|
||||
if(num_requested_seek_points > 0) {
|
||||
if(!grabbag__seektable_convert_specification_to_template(requested_seek_points, only_placeholders, e->total_samples_to_encode, e->sample_rate, e->seek_table_template, &has_real_points))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(0 != cuesheet) {
|
||||
unsigned i, j;
|
||||
const FLAC__StreamMetadata_CueSheet *cs = &cuesheet->data.cue_sheet;
|
||||
for(i = 0; i < cs->num_tracks; i++) {
|
||||
const FLAC__StreamMetadata_CueSheet_Track *tr = cs->tracks+i;
|
||||
for(j = 0; j < tr->num_indices; j++) {
|
||||
if(!FLAC__metadata_object_seektable_template_append_point(e->seek_table_template, tr->offset + tr->indices[j].offset))
|
||||
return false;
|
||||
has_real_points = true;
|
||||
}
|
||||
}
|
||||
if(has_real_points)
|
||||
if(!FLAC__metadata_object_seektable_template_sort(e->seek_table_template, /*compact=*/true))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(has_real_points) {
|
||||
if(e->is_stdout)
|
||||
@ -1524,6 +1561,37 @@ 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__uint64 lead_out_offset)
|
||||
{
|
||||
FILE *f;
|
||||
unsigned last_line_read;
|
||||
const char *error_message;
|
||||
|
||||
if(0 == cuesheet_filename)
|
||||
return true;
|
||||
|
||||
if(lead_out_offset == 0) {
|
||||
fprintf(stderr, "%s: ERROR cannot import cuesheet when the number of input samples to encode is unknown\n", inbasefilename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(0 == (f = fopen(cuesheet_filename, "r"))) {
|
||||
fprintf(stderr, "%s: ERROR opening cuesheet \"%s\" for reading\n", inbasefilename, cuesheet_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
*cuesheet = grabbag__cuesheet_parse(f, &error_message, &last_line_read, /*@@@@is_cdda=*/true, lead_out_offset);
|
||||
|
||||
fclose(f);
|
||||
|
||||
if(0 == *cuesheet) {
|
||||
fprintf(stderr, "%s: ERROR parsing cuesheet \"%s\" on line %u: %s\n", inbasefilename, cuesheet_filename, last_line_read, error_message);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void print_stats(const EncoderSession *encoder_session)
|
||||
{
|
||||
const FLAC__uint64 samples_written = min(encoder_session->total_samples_to_encode, encoder_session->samples_written);
|
||||
|
@ -49,6 +49,8 @@ typedef struct {
|
||||
int padding;
|
||||
char *requested_seek_points;
|
||||
int num_requested_seek_points;
|
||||
const char *cuesheet_filename;
|
||||
FLAC__bool cued_seekpoints;
|
||||
|
||||
/* options related to --replay-gain and --sector-align */
|
||||
FLAC__bool is_first_file;
|
||||
|
@ -103,6 +103,8 @@ static struct share__option long_options_[] = {
|
||||
/*
|
||||
* encoding options
|
||||
*/
|
||||
{ "cuesheet", 1, 0, 0 },
|
||||
{ "no-cued-seekpoints", 0, 0, 0 },
|
||||
{ "tag", 1, 0, 'T' },
|
||||
{ "compression-level-0", 0, 0, '0' },
|
||||
{ "compression-level-1", 0, 0, '1' },
|
||||
@ -116,7 +118,7 @@ static struct share__option long_options_[] = {
|
||||
{ "compression-level-9", 0, 0, '9' },
|
||||
{ "best", 0, 0, '8' },
|
||||
{ "fast", 0, 0, '0' },
|
||||
{ "super-secret-impractical-compression-level", 0, 0, 0 },
|
||||
{ "super-secret-totally-impractical-compression-level", 0, 0, 0 },
|
||||
{ "verify", 0, 0, 'V' },
|
||||
{ "force-raw-format", 0, 0, 0 },
|
||||
{ "lax", 0, 0, 0 },
|
||||
@ -236,8 +238,10 @@ static struct {
|
||||
int min_residual_partition_order;
|
||||
int max_residual_partition_order;
|
||||
int rice_parameter_search_dist;
|
||||
char requested_seek_points[50000]; /* @@@ bad MAGIC NUMBER */
|
||||
char requested_seek_points[50000]; /* @@@ bad MAGIC NUMBER but buffer overflow is checked */
|
||||
int num_requested_seek_points; /* -1 => no -S options were given, 0 => -S- was given */
|
||||
const char *cuesheet_filename;
|
||||
FLAC__bool cued_seekpoints;
|
||||
|
||||
unsigned num_files;
|
||||
char **filenames;
|
||||
@ -409,6 +413,9 @@ int do_it()
|
||||
if(option_values.cmdline_forced_outfilename && option_values.output_prefix) {
|
||||
return usage_error("ERROR: --output-prefix conflicts with -o/--output-name\n");
|
||||
}
|
||||
if(!option_values.mode_decode && 0 != option_values.cuesheet_filename && option_values.num_files > 1) {
|
||||
return usage_error("ERROR: --cuesheet cannot be used when encoding multiple files\n");
|
||||
}
|
||||
}
|
||||
if(option_values.verbose) {
|
||||
fprintf(stderr, "\n");
|
||||
@ -539,6 +546,8 @@ FLAC__bool init_options()
|
||||
option_values.rice_parameter_search_dist = -1;
|
||||
option_values.requested_seek_points[0] = '\0';
|
||||
option_values.num_requested_seek_points = -1;
|
||||
option_values.cuesheet_filename = 0;
|
||||
option_values.cued_seekpoints = true;
|
||||
|
||||
option_values.num_files = 0;
|
||||
option_values.filenames = 0;
|
||||
@ -612,7 +621,15 @@ int parse_option(int short_option, const char *long_option, const char *option_a
|
||||
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 */
|
||||
}
|
||||
else if(0 == strcmp(long_option, "super-secret-impractical-compression-level")) {
|
||||
else if(0 == strcmp(long_option, "cuesheet")) {
|
||||
FLAC__ASSERT(0 != option_argument);
|
||||
option_values.cuesheet_filename = option_argument;
|
||||
}
|
||||
else if(0 == strcmp(long_option, "no-cued-seekpoints")) {
|
||||
option_values.cued_seekpoints = false;
|
||||
}
|
||||
else if(0 == strcmp(long_option, "super-secret-totally-impractical-compression-level")) {
|
||||
option_values.lax = true;
|
||||
option_values.do_exhaustive_model_search = true;
|
||||
option_values.do_escape_coding = true;
|
||||
option_values.do_mid_side = true;
|
||||
@ -895,8 +912,13 @@ int parse_option(int short_option, const char *long_option, const char *option_a
|
||||
if(option_values.num_requested_seek_points < 0)
|
||||
option_values.num_requested_seek_points = 0;
|
||||
option_values.num_requested_seek_points++;
|
||||
strcat(option_values.requested_seek_points, option_argument);
|
||||
strcat(option_values.requested_seek_points, ";");
|
||||
if(strlen(option_values.requested_seek_points)+strlen(option_argument)+2 >= sizeof(option_values.requested_seek_points)) {
|
||||
return usage_error("ERROR: too many seekpoints requested\n");
|
||||
}
|
||||
else {
|
||||
strcat(option_values.requested_seek_points, option_argument);
|
||||
strcat(option_values.requested_seek_points, ";");
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
FLAC__ASSERT(0 != option_argument);
|
||||
@ -1069,9 +1091,10 @@ void show_help()
|
||||
printf(" --lax Allow encoder to generate non-Subset files\n");
|
||||
printf(" --sector-align Align multiple files on sector boundaries\n");
|
||||
printf(" --replay-gain Calculate ReplayGain & store in Vorbis comments\n");
|
||||
printf(" --cuesheet=FILENAME Import cuesheet and store in CUESHEET block\n");
|
||||
printf(" -T, --tag=FIELD=VALUE Add a Vorbis comment; may appear multiple times\n");
|
||||
printf(" -S, --seekpoint={#|X|#x|#s} Add seek point(s)\n");
|
||||
printf(" -P, --padding=# Write a PADDING block of length #\n");
|
||||
printf(" -T, --tag=FIELD=VALUE Add a Vorbis comment; may appear multiple times\n");
|
||||
printf(" -0, --compression-level-0, --fast Synonymous with -l 0 -b 1152 -r 2,2\n");
|
||||
printf(" -1, --compression-level-1 Synonymous with -l 0 -b 1152 -M -r 2,2\n");
|
||||
printf(" -2, --compression-level-2 Synonymous with -l 0 -b 1152 -m -r 3\n");
|
||||
@ -1222,6 +1245,16 @@ void show_explain()
|
||||
printf(" one of 8, 11.025, 12, 16, 22.05, 24, 32, 44.1,\n");
|
||||
printf(" or 48 kHz. NOTE: this option may also leave a\n");
|
||||
printf(" few extra bytes in the PADDING block.\n");
|
||||
printf(" --cuesheet=FILENAME Import the given cuesheet file and store it in\n");
|
||||
printf(" a CUESHEET metadata block. This option may only\n");
|
||||
printf(" be used when encoding a single file. A\n");
|
||||
printf(" seekpoint will be added for each index point in\n");
|
||||
printf(" the cuesheet to the SEEKTABLE unless\n");
|
||||
printf(" --no-cued-seekpoints is specified.\n");
|
||||
printf(" -T, --tag=FIELD=VALUE Add a Vorbis comment. Make sure to quote the\n");
|
||||
printf(" comment if necessary. This option may appear\n");
|
||||
printf(" more than once to add several comments. NOTE:\n");
|
||||
printf(" all tags will be added to all encoded files.\n");
|
||||
printf(" -S, --seekpoint={#|X|#x|#s} Include a point or points in a SEEKTABLE\n");
|
||||
printf(" # : a specific sample number for a seek point\n");
|
||||
printf(" X : a placeholder point (always goes at the end of the SEEKTABLE)\n");
|
||||
@ -1253,10 +1286,6 @@ void show_explain()
|
||||
printf(" 576, 1152, 2304, 4608, 256, 512, 1024, 2048,\n");
|
||||
printf(" 4096, 8192, 16384, or 32768 (unless --lax is\n");
|
||||
printf(" used)\n");
|
||||
printf(" -T, --tag=FIELD=VALUE Add a Vorbis comment. Make sure to quote the\n");
|
||||
printf(" comment if necessary. This option may appear\n");
|
||||
printf(" more than once to add several comments. NOTE:\n");
|
||||
printf(" all tags will be added to all encoded files.\n");
|
||||
printf(" -0, --compression-level-0, --fast Synonymous with -l 0 -b 1152 -r 2,2\n");
|
||||
printf(" -1, --compression-level-1 Synonymous with -l 0 -b 1152 -M -r 2,2\n");
|
||||
printf(" -2, --compression-level-2 Synonymous with -l 0 -b 1152 -m -r 3\n");
|
||||
@ -1424,6 +1453,8 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_
|
||||
common_options.padding = option_values.padding;
|
||||
common_options.requested_seek_points = option_values.requested_seek_points;
|
||||
common_options.num_requested_seek_points = option_values.num_requested_seek_points;
|
||||
common_options.cuesheet_filename = option_values.cuesheet_filename;
|
||||
common_options.cued_seekpoints = option_values.cued_seekpoints;
|
||||
common_options.is_first_file = is_first_file;
|
||||
common_options.is_last_file = is_last_file;
|
||||
common_options.align_reservoir = align_reservoir;
|
||||
|
Loading…
Reference in New Issue
Block a user