Let --keep-foreign-metadata on decode pick the right decode format

This commit is contained in:
Martijn van Beurden 2023-01-29 20:59:08 +01:00
parent a12c6f3236
commit a8c20a6af1
5 changed files with 131 additions and 88 deletions

View File

@ -309,26 +309,7 @@ FLAC__bool DecoderSession_init_decoder(DecoderSession *decoder_session, const ch
is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
if(!decoder_session->analysis_mode && !decoder_session->test_only && decoder_session->foreign_metadata) {
const char *error;
if(!flac__foreign_metadata_read_from_flac(decoder_session->foreign_metadata, infilename, &error)) {
if(decoder_session->relaxed_foreign_metadata_handling) {
flac__utils_printf(stderr, 1, "%s: WARNING reading foreign metadata: %s\n", decoder_session->inbasefilename, error);
if(decoder_session->treat_warnings_as_errors) {
return false;
}
else {
/* Couldn't find foreign metadata, stop processing */
decoder_session->foreign_metadata = 0;
}
}
else {
flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", decoder_session->inbasefilename, error);
return false;
}
}
}
else if(decoder_session->test_only && strcmp(infilename, "-") != 0) {
if(decoder_session->test_only && strcmp(infilename, "-") != 0) {
/* When testing, we can be a little more pedantic, as long
* as we can seek properly */
FLAC__byte buffer[3];

View File

@ -498,8 +498,7 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat
{
FLAC__byte id[4], buffer[32];
FLAC__off_t offset;
FLAC__bool foreign_metadata_found = false, type_found = false, ds64_found = false;
uint32_t foreign_metadata_found_type = 0;
FLAC__bool first_block = true, type_found = false, ds64_found = false;
FLAC__ASSERT(FLAC__STREAM_METADATA_APPLICATION_ID_LEN == sizeof(id)*8);
@ -510,18 +509,18 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat
if(error) *error = "FLAC__metadata_simple_iterator_get_application_id() error (002)";
return false;
}
if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id))) {
/* The found application metadata block is not of the right type, check
* whether it is of another recognized type so we can tell the user it
* is decoding to the wrong file format */
if(first_block) {
uint32_t i;
for(i = 0; i < FLAC__FOREIGN_METADATA_NUMBER_OF_RECOGNIZED_APPLICATION_IDS; i++)
if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[i], sizeof(id)) == 0) {
foreign_metadata_found = true;
foreign_metadata_found_type = i;
fm->type = i;
first_block = false;
}
continue;
if(first_block) /* means no first foreign metadata block was found yet */
continue;
}
else if(memcmp(id, FLAC__FOREIGN_METADATA_APPLICATION_ID[fm->type], sizeof(id)))
continue;
offset = FLAC__metadata_simple_iterator_get_block_offset(it);
/* skip over header and app ID */
offset += (FLAC__STREAM_METADATA_IS_LAST_LEN + FLAC__STREAM_METADATA_TYPE_LEN + FLAC__STREAM_METADATA_LENGTH_LEN) / 8;
@ -671,23 +670,6 @@ static FLAC__bool read_from_flac_(foreign_metadata_t *fm, FILE *f, FLAC__Metadat
if(!append_block_(fm, offset, FLAC__metadata_simple_iterator_get_block_length(it)-sizeof(id), error))
return false;
}
if(!type_found) {
if(foreign_metadata_found) {
if(error) {
if(foreign_metadata_found_type == 0 /*"aiff"*/)
*error = "found foreign metadata of wrong type, try decoding to AIFF instead";
else if(foreign_metadata_found_type == 1 /*"riff"*/)
*error = "found foreign metadata of wrong type, try decoding to WAV or RF64 instead";
else if(foreign_metadata_found_type == 2 /*"w64 "*/)
*error = "found foreign metadata of wrong type, try decoding to WAVE64 instead";
}
return false;
}
else {
if(error) *error = "no foreign metadata found (022)";
return false;
}
}
if(fm->is_rf64 && !ds64_found) {
if(error) *error = "invalid RF64 file: second chunk is not \"ds64\" (023)";
return false;

View File

@ -75,7 +75,7 @@ static int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__b
static int decode_file(const char *infilename);
static const char *get_encoded_outfilename(const char *infilename);
static const char *get_decoded_outfilename(const char *infilename);
static const char *get_decoded_outfilename(const char *infilename, const FileFormat format);
static const char *get_outfilename(const char *infilename, const char *suffix);
static void die(const char *message);
@ -1726,8 +1726,7 @@ void show_explain(void)
void format_mistake(const char *infilename, FileFormat wrong, FileFormat right)
{
/* WATCHOUT: indexed by FileFormat */
static const char * const ff[] = { " raw", " WAVE", " Wave64", "n RF64", "n AIFF", "n AIFF-C", " FLAC", "n Ogg FLAC" };
flac__utils_printf(stderr, 1, "WARNING: %s is not a%s file; treating as a%s file\n", infilename, ff[wrong], ff[right]);
flac__utils_printf(stderr, 1, "WARNING: %s is not a%s file; treating as a%s file\n", infilename, FileFormatString[wrong], FileFormatString[right]);
}
int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_last_file)
@ -2108,7 +2107,9 @@ int decode_file(const char *infilename)
FLAC__bool treat_as_ogg = false;
FileFormat output_format = FORMAT_WAVE;
decode_options_t decode_options;
const char *outfilename = get_decoded_outfilename(infilename);
foreign_metadata_t foreign_metadata_instance = {0}; /* Allocate space */
foreign_metadata_t *foreign_metadata = 0;
const char *outfilename = get_outfilename(infilename, ". "); /* Placeholder until we know what the actual suffix is */
size_t infilename_length;
if(0 == outfilename) {
@ -2116,13 +2117,29 @@ int decode_file(const char *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 && strcmp(outfilename, "-") && grabbag__file_get_filesize(outfilename) != (FLAC__off_t)(-1)) {
flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename);
return 1;
if(!option_values.analyze && !option_values.test_only &&(option_values.keep_foreign_metadata || option_values.keep_foreign_metadata_if_present)) {
const char *error;
if(0 == strcmp(infilename, "-") || 0 == strcmp(outfilename, "-"))
return usage_error("ERROR: --keep-foreign-metadata cannot be used when decoding from stdin or to stdout\n");
if(output_format == FORMAT_RAW)
return usage_error("ERROR: --keep-foreign-metadata cannot be used with raw output\n");
foreign_metadata = &foreign_metadata_instance;
if(!flac__foreign_metadata_read_from_flac(foreign_metadata, infilename, &error)) {
if(option_values.keep_foreign_metadata_if_present) {
flac__utils_printf(stderr, 1, "%s: WARNING reading foreign metadata: %s\n", infilename, error);
if(option_values.treat_warnings_as_errors) {
return 1;
}
else {
/* Couldn't find foreign metadata, stop processing */
foreign_metadata = 0;
}
}
else {
flac__utils_printf(stderr, 1, "%s: ERROR reading foreign metadata: %s\n", infilename, error);
return 1;
}
}
}
if(option_values.force_raw_format)
@ -2143,21 +2160,53 @@ int decode_file(const char *infilename)
(strlen(outfilename) >= 4 && 0 == FLAC__STRCASECMP(outfilename+(strlen(outfilename)-4), ".w64"))
)
output_format = FORMAT_WAVE64;
else if(foreign_metadata != NULL) {
/* Pick a format based on what the foreign metadata contains */
if(foreign_metadata->type == FOREIGN_BLOCK_TYPE__WAVE64)
output_format = FORMAT_WAVE64;
else if(foreign_metadata->is_rf64)
output_format = FORMAT_RF64;
else if(foreign_metadata->type == FOREIGN_BLOCK_TYPE__AIFF) {
output_format = FORMAT_AIFF;
if(foreign_metadata->is_aifc) {
flac__utils_printf(stderr, 1, "ERROR restoring foreign metadata: restoring AIFF-C files is not yet supported\n");
return 1;
}
}
else
output_format = FORMAT_WAVE;
/* Further split is determined in decode.c */
}
else
output_format = FORMAT_WAVE;
/* Check whether output format agrees with foreign metadata */
if(foreign_metadata != NULL) {
if((output_format != FORMAT_WAVE && output_format != FORMAT_RF64) && foreign_metadata->type == FOREIGN_BLOCK_TYPE__RIFF)
return usage_error("ERROR: foreign metadata type RIFF cannot be restored to a%s file, only to WAVE and RF64\n",FileFormatString[output_format]);
if((output_format != FORMAT_AIFF && output_format != FORMAT_AIFF_C) && foreign_metadata->type == FOREIGN_BLOCK_TYPE__AIFF)
return usage_error("ERROR: foreign metadata type AIFF cannot be restored to a%s file, only to AIFF and AIFF-C\n",FileFormatString[output_format]);
if(output_format != FORMAT_WAVE64 && foreign_metadata->type == FOREIGN_BLOCK_TYPE__WAVE64)
return usage_error("ERROR: foreign metadata type Wave64 cannot be restored to a%s file, only to Wave64\n",FileFormatString[output_format]);
}
/* Now reassemble outfilename */
get_decoded_outfilename(infilename, output_format);
/*
* 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) != (FLAC__off_t)(-1)) {
flac__utils_printf(stderr, 1, "ERROR: output file %s already exists, use -f to override\n", outfilename);
return 1;
}
if(!option_values.test_only && !option_values.analyze) {
if(output_format == FORMAT_RAW && (option_values.format_is_big_endian < 0 || option_values.format_is_unsigned_samples < 0))
return usage_error("ERROR: for decoding to a raw file you must specify a value for --endian and --sign\n");
}
if(option_values.keep_foreign_metadata || option_values.keep_foreign_metadata_if_present) {
if(0 == strcmp(infilename, "-") || 0 == strcmp(outfilename, "-"))
return usage_error("ERROR: --keep-foreign-metadata cannot be used when decoding from stdin or to stdout\n");
if(output_format != FORMAT_WAVE && output_format != FORMAT_WAVE64 && output_format != FORMAT_RF64 && output_format != FORMAT_AIFF && output_format != FORMAT_AIFF_C)
return usage_error("ERROR: --keep-foreign-metadata can only be used with WAVE, Wave64, RF64, or AIFF output\n");
}
infilename_length = strlen(infilename);
if(option_values.use_ogg)
treat_as_ogg = true;
@ -2212,28 +2261,10 @@ int decode_file(const char *infilename)
retval = flac__decode_file(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, decode_options);
}
else {
decode_options.format_options.iff.foreign_metadata = 0;
/* initialize foreign metadata if requested */
if(option_values.keep_foreign_metadata || option_values.keep_foreign_metadata_if_present) {
decode_options.format_options.iff.foreign_metadata =
flac__foreign_metadata_new(
output_format==FORMAT_WAVE || output_format==FORMAT_RF64?
FOREIGN_BLOCK_TYPE__RIFF :
output_format==FORMAT_WAVE64?
FOREIGN_BLOCK_TYPE__WAVE64 :
FOREIGN_BLOCK_TYPE__AIFF
);
if(0 == decode_options.format_options.iff.foreign_metadata) {
flac__utils_printf(stderr, 1, "ERROR: creating foreign metadata object\n");
return 1;
}
}
decode_options.format_options.iff.foreign_metadata = foreign_metadata;
retval = flac__decode_file(infilename, option_values.test_only? 0 : outfilename, option_values.analyze, option_values.aopts, decode_options);
if(decode_options.format_options.iff.foreign_metadata)
flac__foreign_metadata_delete(decode_options.format_options.iff.foreign_metadata);
}
if(retval == 0 && strcmp(infilename, "-")) {
@ -2261,7 +2292,7 @@ const char *get_encoded_outfilename(const char *infilename)
return get_outfilename(p, suffix);
}
const char *get_decoded_outfilename(const char *infilename)
const char *get_decoded_outfilename(const char *infilename, const FileFormat format)
{
const char *suffix;
const char *p;
@ -2276,16 +2307,16 @@ const char *get_decoded_outfilename(const char *infilename)
if(option_values.analyze) {
suffix = ".ana";
}
else if(option_values.force_raw_format) {
else if(format == FORMAT_RAW) {
suffix = ".raw";
}
else if(option_values.force_aiff_format) {
else if(format == FORMAT_AIFF) {
suffix = ".aiff";
}
else if(option_values.force_rf64_format) {
else if(format == FORMAT_RF64) {
suffix = ".rf64";
}
else if(option_values.force_wave64_format) {
else if(format == FORMAT_WAVE64) {
suffix = ".w64";
}
else {

View File

@ -29,6 +29,7 @@
#include <stdio.h> /* for FILE */
typedef enum { FORMAT_RAW, FORMAT_WAVE, FORMAT_WAVE64, FORMAT_RF64, FORMAT_AIFF, FORMAT_AIFF_C, FORMAT_FLAC, FORMAT_OGGFLAC } FileFormat;
static const char * const FileFormatString[] = { " raw", " WAVE", " Wave64", "n RF64", "n AIFF", "n AIFF-C", " FLAC", "n Ogg FLAC" };
typedef struct {
FLAC__bool is_relative; /* i.e. specification string started with + or - */

View File

@ -182,6 +182,20 @@ rt_test_wav ()
rm -f rt.flac rt.wav
}
rt_test_wav_autokf ()
{
f="$1"
extra="$2"
echo $ECHO_N "round-trip test ($f) encode... " $ECHO_C
run_flac --force --verify --channel-map=none --no-padding --lax -o rt.flac $extra $f || die "ERROR"
echo $ECHO_N "decode... " $ECHO_C
run_flac --force --decode --channel-map=none $extra rt.flac || die "ERROR"
echo $ECHO_N "compare... " $ECHO_C
cmp $f rt.wav || die "ERROR: file mismatch"
echo "OK"
rm -f rt.flac rt.wav
}
rt_test_w64 ()
{
f="$1"
@ -196,6 +210,20 @@ rt_test_w64 ()
rm -f rt.flac rt.w64
}
rt_test_w64_autokf ()
{
f="$1"
extra="$2"
echo $ECHO_N "round-trip test ($f) encode... " $ECHO_C
run_flac --force --verify --channel-map=none --no-padding --lax -o rt.flac $extra $f || die "ERROR"
echo $ECHO_N "decode... " $ECHO_C
run_flac --force --decode --channel-map=none $extra rt.flac || die "ERROR"
echo $ECHO_N "compare... " $ECHO_C
cmp $f rt.w64 || die "ERROR: file mismatch"
echo "OK"
rm -f rt.flac rt.w64
}
rt_test_rf64 ()
{
f="$1"
@ -210,6 +238,20 @@ rt_test_rf64 ()
rm -f rt.flac rt.rf64
}
rt_test_rf64_autokf ()
{
f="$1"
extra="$2"
echo $ECHO_N "round-trip test ($f) encode... " $ECHO_C
run_flac --force --verify --channel-map=none --no-padding --lax -o rt.flac $extra $f || die "ERROR"
echo $ECHO_N "decode... " $ECHO_C
run_flac --force --decode --channel-map=none $extra rt.flac || die "ERROR"
echo $ECHO_N "compare... " $ECHO_C
cmp $f rt.rf64 || die "ERROR: file mismatch"
echo "OK"
rm -f rt.flac rt.rf64
}
rt_test_aiff ()
{
f="$1"
@ -1177,6 +1219,12 @@ rt_test_w64 wacky2.w64 '--keep-foreign-metadata'
rt_test_rf64 wacky1.rf64 '--keep-foreign-metadata'
rt_test_rf64 wacky2.rf64 '--keep-foreign-metadata'
rt_test_wav_autokf wacky1.wav '--keep-foreign-metadata'
rt_test_wav_autokf wacky2.wav '--keep-foreign-metadata'
rt_test_w64_autokf wacky1.w64 '--keep-foreign-metadata'
rt_test_w64_autokf wacky2.w64 '--keep-foreign-metadata'
rt_test_rf64_autokf wacky1.rf64 '--keep-foreign-metadata'
rt_test_rf64_autokf wacky2.rf64 '--keep-foreign-metadata'
############################################################################
# test the metadata-handling properties of flac-to-flac encoding