Commit c28efe22 authored by Josh Coalson's avatar Josh Coalson

add support from encoding from ogg flac input

parent 2dd9d916
......@@ -69,7 +69,7 @@
<li>Much better recovery for corrupted files</li>
<li>Better multichannel support</li>
<li>Large file (&gt;2GB) support everywhere</li>
<li><span class="commandname">flac</span> now supports FLAC as input to the encoder (i.e. can re-encode FLAC to FLAC) and preserve all the metadata like tags, etc.</li>
<li><span class="commandname">flac</span> now supports FLAC and Ogg FLAC as input to the encoder (i.e. can re-encode FLAC to FLAC) and preserve all the metadata like tags, etc.</li>
<li>New <span class="code"><a href="format.html#def_PICTURE">PICTURE</a></span> metadata block for storing things like cover art, new <span class="argument"><a href="documentation.html#flac_options_picture">--picture</a></span> option to <span class="commandname">flac</span> and <span class="argument"><a href="documentation.html#metaflac_shorthand_import_picture_from">--import-picture-from</a></span> option to <span class="commandname">metaflac</span> for importing pictures, new <span class="argument"><a href="documentation.html#metaflac_shorthand_export_picture_to">--export-picture-to</a></span> option to <span class="commandname">metaflac</span> for exporting pictures, and metadata API <a href="api/group__flac__metadata__level0.html#ga3">additions</a> for searching for suitable pictures based on type, size and color constraints.</li>
<li>Support for new <tt>REPLAYGAIN_REFERENCE_LOUDNESS</tt> tag.</li>
<li>In the developer libraries, the interface has been simplfied by merging the three decoding layers into a single class; ditto for the encoders. Also, libOggFLAC has been merged into libFLAC and libOggFLAC++ has been merged into libFLAC++ so there is a single API supporting both native FLAC and Ogg FLAC.</li>
......@@ -93,7 +93,7 @@
flac:
<ul>
<li>Improved the <span class="argument"><a href="documentation.html#flac_options_decode_through_errors">-F</a></span> option to allow decoding of FLAC files whose metadata is corrupted, and other kinds of severe corruption.</li>
<li>Encoder can now take FLAC as input. The output FLAC file will have all the same metadata as the original unless overridden with options on the command line.</li>
<li>Encoder can now take FLAC and Ogg FLAC as input. The output FLAC file will have all the same metadata as the original unless overridden with options on the command line.</li>
<li>Encoder can now take WAVEFORMATEXTENSIBLE WAVE files as input; decoder will output WAVEFORMATEXTENSIBLE WAVE files when necessary to conform to the latest Microsoft specifications.</li>
<li>Now properly supports AIFF and WAVEFORMATEXTENSIBLE multichannel input, performing necessary channel reordering both for encoding and decoding. WAVEFORMATEXTENSIBLE channel mask is also saved to a tag on encoding and restored on decoding for situations when there is no natural mapping to FLAC channel assignments.</li>
<li>Expanded support for "odd" sample resolutions to WAVE and AIFF input; all resolutions from 4 to 24 bits-per-sample now supported for all input types.</li>
......
......@@ -143,9 +143,9 @@
</div>
<div class="box_header"></div>
<div class="box_body">
<span class="commandname">flac</span> is the command-line file encoder/decoder. The encoder currently supports as input RIFF WAVE, AIFF, or FLAC format, or raw interleaved samples. The decoder currently can output to RIFF WAVE or AIFF format, or raw interleaved samples. <span class="commandname">flac</span> only supports linear PCM samples (in other words, no A-LAW, uLAW, etc.), and the input must be between 4 and 24 bits per sample. This is not a limitation of the FLAC format, just the reference encoder/decoder.
<span class="commandname">flac</span> is the command-line file encoder/decoder. The encoder currently supports as input RIFF WAVE, AIFF, FLAC or Ogg FLAC format, or raw interleaved samples. The decoder currently can output to RIFF WAVE or AIFF format, or raw interleaved samples. <span class="commandname">flac</span> only supports linear PCM samples (in other words, no A-LAW, uLAW, etc.), and the input must be between 4 and 24 bits per sample. This is not a limitation of the FLAC format, just the reference encoder/decoder.
<br /><br />
<span class="commandname">flac</span> assumes that files ending in ".wav" or that have the RIFF WAVE header present are WAVE files, files ending in ".aif" or ".aiff" or have the AIFF header present are AIFF files, and files ending in ".flac" or have the FLAC header present are FLAC files. This assumption may be overridden with a command-line option. It also assumes that files ending in ".ogg" are Ogg FLAC files. Other than this, <span class="commandname">flac</span> makes no assumptions about file extensions, though the convention is that FLAC files have the extension ".flac" (or ".fla" on ancient file systems like FAT-16).
<span class="commandname">flac</span> assumes that files ending in ".wav" or that have the RIFF WAVE header present are WAVE files, files ending in ".aif" or ".aiff" or have the AIFF header present are AIFF files, and files ending in ".flac" or have the FLAC header present are FLAC files. This assumption may be overridden with a command-line option. It also assumes that files ending in ".ogg" of have the Ogg FLAC header present are Ogg FLAC files. Other than this, <span class="commandname">flac</span> makes no assumptions about file extensions, though the convention is that FLAC files have the extension ".flac" (or ".fla" on ancient "8.3" file systems like FAT-16).
<br /><br />
Before going into the full command-line description, a few other things help to sort it out: 1) <span class="commandname">flac</span> encodes by default, so you must use <b>-d</b> to decode; 2) the options <span class="argument">-0</span> .. <span class="argument">-8</span> (or <span class="argument">--fast</span> and <span class="argument">--best</span>) that control the compression level actually are just synonyms for different groups of specific encoding options (described later) and you can get the same effect by using the same options; 3) <span class="commandname">flac</span> behaves similarly to gzip in the way it handles input and output files.
<br /><br />
......@@ -198,7 +198,7 @@
<br /><br />
In test mode, <span class="commandname">flac</span> acts just like in decode mode, except no output file is written. Both decode and test modes detect errors in the stream, but they also detect when the MD5 signature of the decoded audio does not match the stored MD5 signature, even when the bitstream is valid.
<br /><br />
<span class="commandname">flac</span> can also re-encode FLAC files. In other words, you can specify a FLAC file as an input to the encoder and it will decoder it and re-encode it according to the options you specify. It will also preserve all the metadata unless you override it with other options (e.g. specifying new tags, seekpoints, cuesheet, padding, etc.).
<span class="commandname">flac</span> can also re-encode FLAC files. In other words, you can specify a FLAC or Ogg FLAC file as an input to the encoder and it will decoder it and re-encode it according to the options you specify. It will also preserve all the metadata unless you override it with other options (e.g. specifying new tags, seekpoints, cuesheet, padding, etc.).
<br /><br />
<table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#EEEED4"><tr><td>
......
......@@ -45,12 +45,13 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>flac</command>
<arg choice=opt><replaceable>options</replaceable></arg>
<arg choice=opt><replaceable>OPTIONS</replaceable></arg>
<group rep=repeat>
<arg><replaceable>infile.wav</replaceable></arg>
<arg><replaceable>infile.aiff</replaceable></arg>
<arg><replaceable>infile.raw</replaceable></arg>
<arg><replaceable>infile.flac</replaceable></arg>
<arg><replaceable>infile.ogg</replaceable></arg>
<arg>-</arg>
</group>
</cmdsynopsis>
......@@ -62,7 +63,11 @@
<arg>-a</arg> <arg>--analyze</arg>
</group>
<arg choice=opt><replaceable>OPTIONS</replaceable></arg>
<arg choice=opt rep=repeat><replaceable>infile.flac</replaceable></arg>
<group rep=repeat>
<arg><replaceable>infile.flac</replaceable></arg>
<arg><replaceable>infile.ogg</replaceable></arg>
<arg>-</arg>
</group>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
......
......@@ -1344,7 +1344,7 @@ 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)
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, FLAC__bool input_is_ogg)
{
EncoderSession encoder_session;
FLAC__StreamDecoder *decoder = 0;
......@@ -1391,7 +1391,13 @@ int flac__encode_flac(FILE *infile, off_t infilesize, const char *infilename, co
goto fubar1; /*@@@ yuck */
}
if (FLAC__stream_decoder_init_stream(decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/&decoder_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
if (input_is_ogg) {
if (FLAC__stream_decoder_init_ogg_stream(decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/&decoder_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for Ogg FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder));
goto fubar1; /*@@@ yuck */
}
}
else if (FLAC__stream_decoder_init_stream(decoder, flac_decoder_read_callback, flac_decoder_seek_callback, flac_decoder_tell_callback, flac_decoder_length_callback, flac_decoder_eof_callback, flac_decoder_write_callback, flac_decoder_metadata_callback, flac_decoder_error_callback, /*client_data=*/&decoder_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
flac__utils_printf(stderr, 1, "%s: ERROR: initializing decoder for FLAC input, state = %s\n", encoder_session.inbasefilename, FLAC__stream_decoder_get_resolved_state_string(decoder));
goto fubar1; /*@@@ yuck */
}
......@@ -2259,7 +2265,12 @@ FLAC__StreamDecoderReadStatus flac_decoder_read_callback(const FLAC__StreamDecod
/* 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__STREAM_DECODER_READ_STATUS_ABORT : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
if(ferror(data->encoder_session->fin))
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
else if(0 == *bytes && feof(data->encoder_session->fin))
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
else
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
else
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
......
......@@ -116,6 +116,6 @@ typedef struct {
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);
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, FLAC__bool input_is_ogg);
#endif
......@@ -56,7 +56,7 @@
# include "share/getopt.h"
#endif
typedef enum { RAW, WAV, AIF, FLAC } FileFormat;
typedef enum { RAW, WAV, AIF, FLAC, OGGFLAC } FileFormat;
static int do_it();
......@@ -1537,6 +1537,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), ".flac"))
fmt= FLAC;
else if(strlen(infilename) >= 4 && 0 == FLAC__STRCASECMP(infilename+(strlen(infilename)-4), ".ogg"))
fmt= OGGFLAC;
/* attempt to guess the file type based on the first 12 bytes */
if((lookahead_length = fread(lookahead, 1, 12, encode_infile)) < 12) {
......@@ -1555,6 +1557,9 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_
}
else if(!memcmp(lookahead, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING)))
fmt= FLAC;
/* this could be made more accurate by looking at the first packet */
else if(!memcmp(lookahead, "OggS", 4))
fmt= OGGFLAC;
else {
if(fmt != RAW)
format_mistake(infilename, fmt == AIF ? "AIFF" : "WAVE", "raw");
......@@ -1579,6 +1584,17 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_
outfilename
);
}
else if(fmt == OGGFLAC) {
/* 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 -ogg' encodes files to Ogg FLAC format; if you meant to decode\n"
"this file from Ogg FLAC to something else, use -d. If you meant to re-encode\n"
"this file from Ogg FLAC to Ogg FLAC again, use -f to force writing to the same\n"
"file, or -o to specify 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;
......@@ -1594,8 +1610,8 @@ 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");
if(option_values.sector_align && (fmt == FLAC || fmt == OGGFLAC)) {
flac__utils_printf(stderr, 1, "ERROR: can't use --sector-align when the input file is FLAC or Ogg FLAC\n");
return 1;
}
if(option_values.sector_align && fmt == RAW && infilesize < 0) {
......@@ -1682,12 +1698,12 @@ int encode_file(const char *infilename, FLAC__bool is_first_file, FLAC__bool is_
retval = flac__encode_raw(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options);
}
else if(fmt == FLAC) {
else if(fmt == FLAC || fmt == OGGFLAC) {
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);
retval = flac__encode_flac(encode_infile, infilesize, infilename, internal_outfilename? internal_outfilename : outfilename, lookahead, lookahead_length, options, fmt==OGGFLAC);
}
else {
wav_encode_options_t options;
......
......@@ -195,6 +195,22 @@ rt_test_flac ()
rm -f rt.wav rt.flac rt2.flac
}
# assumes input file is WAVE; does not check the metadata-preserving features of flac-to-flac; that is checked later
rt_test_ogg_flac ()
{
f="$1"
echo -n "round-trip test ($f->oggflac->oggflac->wav) encode... "
run_flac $SILENT --force --verify --channel-map=none --lax -o rt.ogg --ogg $f || die "ERROR"
echo -n "re-encode... "
run_flac $SILENT --force --verify --lax -o rt2.ogg --ogg rt.ogg || die "ERROR"
echo -n "decode... "
run_flac $SILENT --force --decode --channel-map=none -o rt.wav rt2.ogg || die "ERROR"
echo -n "compare... "
cmp $f rt.wav || die "ERROR: file mismatch"
echo "OK"
rm -f rt.wav rt.ogg rt2.ogg
}
for f in rt-*.raw ; do
rt_test_raw $f
done
......@@ -207,6 +223,11 @@ done
for f in rt-*.wav ; do
rt_test_flac $f
done
if [ $has_ogg = yes ] ; then
for f in rt-*.wav ; do
rt_test_ogg_flac $f
done
fi
############################################################################
# test --skip and --until
......@@ -241,7 +262,7 @@ raw_eopt="$wav_eopt --force-raw-format --endian=big --sign=signed --sample-rate=
raw_dopt="$wav_dopt --force-raw-format --endian=big --sign=signed"
#
# convert them to WAVE and AIFF files
# convert them to WAVE/AIFF/Ogg FLAC files
#
convert_to_wav ()
{
......@@ -287,12 +308,35 @@ convert_to_aiff 50c.skip10.until40 "$raw_eopt" "$wav_dopt"
convert_to_aiff 50c.skip20.until30 "$raw_eopt" "$wav_dopt"
convert_to_aiff 50c.skip20.until40 "$raw_eopt" "$wav_dopt"
convert_to_ogg ()
{
run_flac "$wav_eopt" --ogg $1.wav || die "ERROR converting $1.raw to Ogg FLAC"
}
if [ $has_ogg = yes ] ; then
convert_to_ogg 50c
convert_to_ogg 50c.skip10
convert_to_ogg 50c.skip11
convert_to_ogg 50c.skip20
convert_to_ogg 50c.skip30
convert_to_ogg 50c.skip40
convert_to_ogg 50c.until10
convert_to_ogg 50c.until20
convert_to_ogg 50c.until30
convert_to_ogg 50c.until39
convert_to_ogg 50c.until40
convert_to_ogg 50c.skip10.until30
convert_to_ogg 50c.skip10.until39
convert_to_ogg 50c.skip10.until40
convert_to_ogg 50c.skip20.until30
convert_to_ogg 50c.skip20.until40
fi
test_skip_until ()
{
in_fmt=$1
out_fmt=$2
[ "$in_fmt" = wav ] || [ "$in_fmt" = aiff ] || [ "$in_fmt" = raw ] || [ "$in_fmt" = flac ] || die "ERROR: internal error, bad 'in' format '$in_fmt'"
[ "$in_fmt" = wav ] || [ "$in_fmt" = aiff ] || [ "$in_fmt" = raw ] || [ "$in_fmt" = flac ] || [ "$in_fmt" = ogg ] || die "ERROR: internal error, bad 'in' format '$in_fmt'"
[ "$out_fmt" = flac ] || [ "$out_fmt" = ogg ] || die "ERROR: internal error, bad 'out' format '$out_fmt'"
......@@ -304,7 +348,7 @@ test_skip_until ()
dopt="$wav_dopt"
fi
if [ $in_fmt = flac ] && [ $out_fmt = flac ] ; then
if ( [ $in_fmt = flac ] || [ $in_fmt = ogg ] ) && ( [ $out_fmt = flac ] || [ $out_fmt = ogg ] ) ; then
CMP=md5cmp
else
CMP=cmp
......@@ -574,13 +618,18 @@ test_skip_until raw flac
test_skip_until wav flac
test_skip_until aiff flac
test_skip_until flac flac
#@@@if [ $has_ogg = yes ] ; then
#@@@ #@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
#@@@ test_skip_until ogg flac
#@@@fi
if [ $has_ogg = "yes" ] ; then
if [ $has_ogg = yes ] ; then
test_skip_until raw ogg
test_skip_until wav ogg
test_skip_until aiff ogg
#@@@ doesn't work yet, no comparison step written since metaflac doesn't work on ogg flac yet
#@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
#@@@test_skip_until flac ogg
#@@@test_skip_until ogg ogg
fi
echo "testing seek extremes:"
......@@ -652,7 +701,7 @@ test_cue ()
in_fmt=$1
out_fmt=$2
[ "$in_fmt" = wav ] || [ "$in_fmt" = aiff ] || [ "$in_fmt" = raw ] || [ "$in_fmt" = flac ] || die "ERROR: internal error, bad 'in' format '$in_fmt'"
[ "$in_fmt" = wav ] || [ "$in_fmt" = aiff ] || [ "$in_fmt" = raw ] || [ "$in_fmt" = flac ] || [ "$in_fmt" = ogg ] || die "ERROR: internal error, bad 'in' format '$in_fmt'"
[ "$out_fmt" = flac ] || [ "$out_fmt" = ogg ] || die "ERROR: internal error, bad 'out' format '$out_fmt'"
......@@ -664,7 +713,7 @@ test_cue ()
dopt="$wav_dopt"
fi
if [ $in_fmt = flac ] && [ $out_fmt = flac ] ; then
if ( [ $in_fmt = flac ] || [ $in_fmt = ogg ] ) && ( [ $out_fmt = flac ] || [ $out_fmt = ogg ] ) ; then
CMP=md5cmp
else
CMP=cmp
......@@ -799,13 +848,18 @@ test_cue raw flac
test_cue wav flac
test_cue aiff flac
test_cue flac flac
#@@@if [ $has_ogg = yes ] ; then
#@@@ #@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
#@@@ test_cue ogg flac
#@@@fi
if [ $has_ogg = "yes" ] ; then
if [ $has_ogg = yes ] ; then
test_cue raw ogg
test_cue wav ogg
test_cue aiff ogg
#@@@ doesn't work yet, no comparison step written since metaflac doesn't work on ogg flac yet
#@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
#@@@test_cue flac ogg
#@@@test_cue ogg ogg
fi
############################################################################
......@@ -955,7 +1009,7 @@ test_multifile ()
encode_options="$encode_options --sector-align"
fi
if [ $input_type = flac ] ; then
if [ $input_type = flac ] || [ $input_type = ogg ] ; then
CMP=md5cmp
else
CMP=cmp
......@@ -980,14 +1034,19 @@ test_multifile ()
done
}
for input_type in raw wav aiff flac ; do
input_types="raw wav aiff flac"
#@@@ doesn't work yet because md5cmp doesn't work because metaflac doesn't work on ogg flac yet
#@@@if [ $has_ogg = yes ] ; then
#@@@ input_types="$input_types ogg"
#@@@fi
for input_type in $input_types ; do
echo "Testing multiple $input_type files without verify..."
test_multifile $input_type flac no_sector_align ""
echo "Testing multiple $input_type files with verify..."
test_multifile $input_type flac no_sector_align "--verify"
if [ $input_type != flac ] ; then # --sector-align not supported for FLAC input
if [ $input_type != flac ] && [ $input_type != ogg ] ; then # --sector-align not supported for FLAC input
echo "Testing multiple $input_type files with --sector-align, without verify..."
test_multifile $input_type flac sector_align ""
......@@ -995,7 +1054,7 @@ for input_type in raw wav aiff flac ; do
test_multifile $input_type flac sector_align "--verify"
fi
if [ $has_ogg = "yes" ] ; then
if [ $has_ogg = yes ] ; then
echo "Testing multiple $input_type files with --ogg, without verify..."
test_multifile $input_type ogg no_sector_align ""
......@@ -1085,4 +1144,6 @@ flac2flac input-SCVA.flac case04e "$TOTALLY_SILENT --no-padding -S 5x"
rm -f out.flac out.meta
#@@@ when metaflac handles ogg flac, duplicate flac2flac tests here
cd ..
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment