📄 decode.c
字号:
/* flac - Command-line FLAC encoder/decoder
* Copyright (C) 2000,2001,2002,2003,2004,2005 Josh Coalson
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if defined _WIN32 && !defined __CYGWIN__
/* where MSVC puts unlink() */
# include <io.h>
#else
# include <unistd.h>
#endif
#include <errno.h>
#include <math.h> /* for floor() */
#include <stdio.h> /* for FILE et al. */
#include <string.h> /* for strcmp() */
#include "FLAC/all.h"
#include "share/grabbag.h"
#include "share/replaygain_synthesis.h"
#include "decode.h"
#ifdef FLAC__HAS_OGG
#include "OggFLAC/file_decoder.h"
#endif
typedef struct {
#ifdef FLAC__HAS_OGG
FLAC__bool is_ogg;
#endif
FLAC__bool is_aiff_out;
FLAC__bool is_wave_out;
FLAC__bool continue_through_decode_errors;
struct {
replaygain_synthesis_spec_t spec;
FLAC__bool apply; /* 'spec.apply' is just a request; this 'apply' means we actually parsed the RG tags and are ready to go */
double scale;
DitherContext dither_context;
} replaygain;
FLAC__bool test_only;
FLAC__bool analysis_mode;
analysis_options aopts;
utils__SkipUntilSpecification *skip_specification;
utils__SkipUntilSpecification *until_specification; /* a canonicalized value of 0 mean end-of-stream (i.e. --until=-0) */
utils__CueSpecification *cue_specification;
const char *inbasefilename;
const char *outfilename;
FLAC__uint64 samples_processed;
unsigned frame_counter;
FLAC__bool abort_flag;
FLAC__bool aborting_due_to_until; /* true if we intentionally abort decoding prematurely because we hit the --until point */
struct {
FLAC__bool needs_fixup;
unsigned riff_offset; /* or FORM offset for AIFF */
unsigned data_offset; /* or SSND offset for AIFF */
unsigned frames_offset; /* AIFF only */
} wave_chunk_size_fixup;
FLAC__bool is_big_endian;
FLAC__bool is_unsigned_samples;
FLAC__uint64 total_samples;
unsigned bps;
unsigned channels;
unsigned sample_rate;
union {
union {
FLAC__FileDecoder *file;
} flac;
#ifdef FLAC__HAS_OGG
union {
OggFLAC__FileDecoder *file;
} ogg;
#endif
} decoder;
FILE *fout;
} DecoderSession;
static FLAC__bool is_big_endian_host_;
/*
* local routines
*/
static FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool is_aiff_out, FLAC__bool is_wave_out, FLAC__bool continue_through_decode_errors, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, const char *infilename, const char *outfilename);
static void DecoderSession_destroy(DecoderSession *d, FLAC__bool error_occurred);
static FLAC__bool DecoderSession_init_decoder(DecoderSession *d, decode_options_t decode_options, const char *infilename);
static FLAC__bool DecoderSession_process(DecoderSession *d);
static int DecoderSession_finish_ok(DecoderSession *d);
static int DecoderSession_finish_error(DecoderSession *d);
static FLAC__bool canonicalize_until_specification(utils__SkipUntilSpecification *spec, const char *inbasefilename, unsigned sample_rate, FLAC__uint64 skip, FLAC__uint64 total_samples_in_input);
static FLAC__bool write_necessary_headers(DecoderSession *decoder_session);
static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 val);
static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 val);
static FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 val);
static FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 val);
static FLAC__bool write_sane_extended(FILE *f, unsigned val);
static FLAC__bool fixup_wave_chunk_size(const char *outfilename, FLAC__bool is_wave_out, unsigned riff_offset, unsigned data_offset, unsigned frames_offset, FLAC__uint32 total_samples, unsigned channels, unsigned bps);
/*
* We use 'void *' so that we can use the same callbacks for the
* FLAC__StreamDecoder and FLAC__FileDecoder. The 'decoder' argument is
* actually never used in the callbacks.
*/
static FLAC__StreamDecoderWriteStatus write_callback(const void *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
static void metadata_callback(const void *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
static void error_callback(const void *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
static void print_error_with_state(const DecoderSession *d, const char *message);
static void print_stats(const DecoderSession *decoder_session);
/*
* public routines
*/
int flac__decode_aiff(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options)
{
DecoderSession decoder_session;
if(!
DecoderSession_construct(
&decoder_session,
#ifdef FLAC__HAS_OGG
options.common.is_ogg,
#else
/*is_ogg=*/false,
#endif
/*is_aiff_out=*/true,
/*is_wave_out=*/false,
options.common.continue_through_decode_errors,
options.common.replaygain_synthesis_spec,
analysis_mode,
aopts,
&options.common.skip_specification,
&options.common.until_specification,
options.common.has_cue_specification? &options.common.cue_specification : 0,
infilename,
outfilename
)
)
return 1;
if(!DecoderSession_init_decoder(&decoder_session, options.common, infilename))
return DecoderSession_finish_error(&decoder_session);
if(!DecoderSession_process(&decoder_session))
return DecoderSession_finish_error(&decoder_session);
return DecoderSession_finish_ok(&decoder_session);
}
int flac__decode_wav(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, wav_decode_options_t options)
{
DecoderSession decoder_session;
if(!
DecoderSession_construct(
&decoder_session,
#ifdef FLAC__HAS_OGG
options.common.is_ogg,
#else
/*is_ogg=*/false,
#endif
/*is_aiff_out=*/false,
/*is_wave_out=*/true,
options.common.continue_through_decode_errors,
options.common.replaygain_synthesis_spec,
analysis_mode,
aopts,
&options.common.skip_specification,
&options.common.until_specification,
options.common.has_cue_specification? &options.common.cue_specification : 0,
infilename,
outfilename
)
)
return 1;
if(!DecoderSession_init_decoder(&decoder_session, options.common, infilename))
return DecoderSession_finish_error(&decoder_session);
if(!DecoderSession_process(&decoder_session))
return DecoderSession_finish_error(&decoder_session);
return DecoderSession_finish_ok(&decoder_session);
}
int flac__decode_raw(const char *infilename, const char *outfilename, FLAC__bool analysis_mode, analysis_options aopts, raw_decode_options_t options)
{
DecoderSession decoder_session;
decoder_session.is_big_endian = options.is_big_endian;
decoder_session.is_unsigned_samples = options.is_unsigned_samples;
if(!
DecoderSession_construct(
&decoder_session,
#ifdef FLAC__HAS_OGG
options.common.is_ogg,
#else
/*is_ogg=*/false,
#endif
/*is_aiff_out=*/false,
/*is_wave_out=*/false,
options.common.continue_through_decode_errors,
options.common.replaygain_synthesis_spec,
analysis_mode,
aopts,
&options.common.skip_specification,
&options.common.until_specification,
options.common.has_cue_specification? &options.common.cue_specification : 0,
infilename,
outfilename
)
)
return 1;
if(!DecoderSession_init_decoder(&decoder_session, options.common, infilename))
return DecoderSession_finish_error(&decoder_session);
if(!DecoderSession_process(&decoder_session))
return DecoderSession_finish_error(&decoder_session);
return DecoderSession_finish_ok(&decoder_session);
}
FLAC__bool DecoderSession_construct(DecoderSession *d, FLAC__bool is_ogg, FLAC__bool is_aiff_out, FLAC__bool is_wave_out, FLAC__bool continue_through_decode_errors, replaygain_synthesis_spec_t replaygain_synthesis_spec, FLAC__bool analysis_mode, analysis_options aopts, utils__SkipUntilSpecification *skip_specification, utils__SkipUntilSpecification *until_specification, utils__CueSpecification *cue_specification, const char *infilename, const char *outfilename)
{
#ifdef FLAC__HAS_OGG
d->is_ogg = is_ogg;
#else
(void)is_ogg;
#endif
d->is_aiff_out = is_aiff_out;
d->is_wave_out = is_wave_out;
d->continue_through_decode_errors = continue_through_decode_errors;
d->replaygain.spec = replaygain_synthesis_spec;
d->replaygain.apply = false;
d->replaygain.scale = 0.0;
/* d->replaygain.dither_context gets initialized later once we know the sample resolution */
d->test_only = (0 == outfilename);
d->analysis_mode = analysis_mode;
d->aopts = aopts;
d->skip_specification = skip_specification;
d->until_specification = until_specification;
d->cue_specification = cue_specification;
d->inbasefilename = grabbag__file_get_basename(infilename);
d->outfilename = outfilename;
d->samples_processed = 0;
d->frame_counter = 0;
d->abort_flag = false;
d->aborting_due_to_until = false;
d->wave_chunk_size_fixup.needs_fixup = false;
d->decoder.flac.file = 0;
#ifdef FLAC__HAS_OGG
d->decoder.ogg.file = 0;
#endif
d->fout = 0; /* initialized with an open file later if necessary */
FLAC__ASSERT(!(d->test_only && d->analysis_mode));
if(!d->test_only) {
if(0 == strcmp(outfilename, "-")) {
d->fout = grabbag__file_get_binary_stdout();
}
else {
if(0 == (d->fout = fopen(outfilename, "wb"))) {
flac__utils_printf(stderr, 1, "%s: ERROR: can't open output file %s\n", d->inbasefilename, outfilename);
DecoderSession_destroy(d, /*error_occurred=*/true);
return false;
}
}
}
if(analysis_mode)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -