📄 encode.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.
*/
#if defined _WIN32 && !defined __CYGWIN__
/* where MSVC puts unlink() */
# include <io.h>
#else
# include <unistd.h>
#endif
#include <limits.h> /* for LONG_MAX */
#include <math.h> /* for floor() */
#include <stdio.h> /* for FILE etc. */
#include <stdlib.h> /* for malloc */
#include <string.h> /* for strcmp() */
#include "FLAC/all.h"
#include "share/grabbag.h"
#include "encode.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef FLAC__HAS_OGG
#include "OggFLAC/stream_encoder.h"
#include "OggFLAC/file_encoder.h"
#endif
#ifdef min
#undef min
#endif
#define min(x,y) ((x)<(y)?(x):(y))
#ifdef max
#undef max
#endif
#define max(x,y) ((x)>(y)?(x):(y))
/* this MUST be >= 588 so that sector aligning can take place with one read */
#define CHUNK_OF_SAMPLES 2048
typedef struct {
#ifdef FLAC__HAS_OGG
FLAC__bool use_ogg;
#endif
FLAC__bool verify;
FLAC__bool is_stdout;
const char *inbasefilename;
const char *outfilename;
FLAC__uint64 skip;
FLAC__uint64 until; /* a value of 0 mean end-of-stream (i.e. --until=-0) */
FLAC__bool replay_gain;
unsigned channels;
unsigned bits_per_sample;
unsigned sample_rate;
FLAC__uint64 unencoded_size;
FLAC__uint64 total_samples_to_encode;
FLAC__uint64 bytes_written;
FLAC__uint64 samples_written;
unsigned blocksize;
unsigned stats_mask;
/*
* We use *.stream for encoding to stdout
* We use *.file for encoding to a regular file
*/
union {
union {
FLAC__StreamEncoder *stream;
FLAC__FileEncoder *file;
} flac;
#ifdef FLAC__HAS_OGG
union {
OggFLAC__StreamEncoder *stream;
OggFLAC__FileEncoder *file;
} ogg;
#endif
} encoder;
FILE *fin;
FILE *fout;
FLAC__StreamMetadata *seek_table_template;
} EncoderSession;
static FLAC__bool is_big_endian_host_;
static unsigned char ucbuffer_[CHUNK_OF_SAMPLES*FLAC__MAX_CHANNELS*((FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE+7)/8)];
static signed char *scbuffer_ = (signed char *)ucbuffer_;
static FLAC__uint16 *usbuffer_ = (FLAC__uint16 *)ucbuffer_;
static FLAC__int16 *ssbuffer_ = (FLAC__int16 *)ucbuffer_;
static FLAC__int32 in_[FLAC__MAX_CHANNELS][CHUNK_OF_SAMPLES];
static FLAC__int32 *input_[FLAC__MAX_CHANNELS];
/*
* unpublished debug routines from the FLAC libs
*/
extern FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
extern FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
extern FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
extern FLAC__bool FLAC__file_encoder_disable_constant_subframes(FLAC__FileEncoder *encoder, FLAC__bool value);
extern FLAC__bool FLAC__file_encoder_disable_fixed_subframes(FLAC__FileEncoder *encoder, FLAC__bool value);
extern FLAC__bool FLAC__file_encoder_disable_verbatim_subframes(FLAC__FileEncoder *encoder, FLAC__bool value);
#ifdef FLAC__HAS_OGG
extern FLAC__bool OggFLAC__stream_encoder_disable_constant_subframes(OggFLAC__StreamEncoder *encoder, FLAC__bool value);
extern FLAC__bool OggFLAC__stream_encoder_disable_fixed_subframes(OggFLAC__StreamEncoder *encoder, FLAC__bool value);
extern FLAC__bool OggFLAC__stream_encoder_disable_verbatim_subframes(OggFLAC__StreamEncoder *encoder, FLAC__bool value);
extern FLAC__bool OggFLAC__file_encoder_disable_constant_subframes(OggFLAC__FileEncoder *encoder, FLAC__bool value);
extern FLAC__bool OggFLAC__file_encoder_disable_fixed_subframes(OggFLAC__FileEncoder *encoder, FLAC__bool value);
extern FLAC__bool OggFLAC__file_encoder_disable_verbatim_subframes(OggFLAC__FileEncoder *encoder, FLAC__bool value);
#endif
/*
* local routines
*/
static FLAC__bool EncoderSession_construct(EncoderSession *e, FLAC__bool use_ogg, FLAC__bool verify, FILE *infile, const char *infilename, const char *outfilename);
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_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);
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);
static void ogg_stream_encoder_metadata_callback(const OggFLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data);
static void ogg_file_encoder_progress_callback(const OggFLAC__FileEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
#endif
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 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);
static FLAC__bool read_little_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ok, const char *fn);
static FLAC__bool read_little_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn);
static FLAC__bool read_big_endian_uint16(FILE *f, FLAC__uint16 *val, FLAC__bool eof_ok, const char *fn);
static FLAC__bool read_big_endian_uint32(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn);
static FLAC__bool read_sane_extended(FILE *f, FLAC__uint32 *val, FLAC__bool eof_ok, const char *fn);
static FLAC__bool fskip_ahead(FILE *f, FLAC__uint64 offset);
/*
* public routines
*/
int
flac__encode_aif(FILE *infile, long infilesize, const char *infilename, const char *outfilename,
const FLAC__byte *lookahead, unsigned lookahead_length, wav_encode_options_t options)
{
EncoderSession encoder_session;
FLAC__uint16 x;
FLAC__uint32 xx;
unsigned int channels= 0U, bps= 0U, sample_rate= 0U, sample_frames= 0U;
FLAC__bool got_comm_chunk= false, got_ssnd_chunk= false;
int info_align_carry= -1, info_align_zero= -1;
(void)infilesize; /* silence compiler warning about unused parameter */
(void)lookahead; /* silence compiler warning about unused parameter */
(void)lookahead_length; /* silence compiler warning about unused parameter */
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;
/* lookahead[] already has "FORMxxxxAIFF", do sub-chunks */
while(1) {
size_t c= 0U;
char chunk_id[4];
/* chunk identifier; really conservative about behavior of fread() and feof() */
if(feof(infile) || ((c= fread(chunk_id, 1U, 4U, infile)), c==0U && feof(infile)))
break;
else if(c<4U || feof(infile)) {
flac__utils_printf(stderr, 1, "%s: ERROR: incomplete chunk identifier\n", encoder_session.inbasefilename);
return EncoderSession_finish_error(&encoder_session);
}
if(got_comm_chunk==false && !strncmp(chunk_id, "COMM", 4)) { /* common chunk */
unsigned long skip;
/* COMM chunk size */
if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
return EncoderSession_finish_error(&encoder_session);
else if(xx<18U) {
flac__utils_printf(stderr, 1, "%s: ERROR: non-standard 'COMM' chunk has length = %u\n", encoder_session.inbasefilename, (unsigned int)xx);
return EncoderSession_finish_error(&encoder_session);
}
else if(xx!=18U) {
flac__utils_printf(stderr, 1, "%s: WARNING: non-standard 'COMM' chunk has length = %u\n", encoder_session.inbasefilename, (unsigned int)xx);
}
skip= (xx-18U)+(xx & 1U);
/* number of channels */
if(!read_big_endian_uint16(infile, &x, false, encoder_session.inbasefilename))
return EncoderSession_finish_error(&encoder_session);
else if(x==0U || x>FLAC__MAX_CHANNELS) {
flac__utils_printf(stderr, 1, "%s: ERROR: unsupported number channels %u\n", encoder_session.inbasefilename, (unsigned int)x);
return EncoderSession_finish_error(&encoder_session);
}
else if(options.common.sector_align && x!=2U) {
flac__utils_printf(stderr, 1, "%s: ERROR: file has %u channels, must be 2 for --sector-align\n", encoder_session.inbasefilename, (unsigned int)x);
return EncoderSession_finish_error(&encoder_session);
}
channels= x;
/* number of sample frames */
if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
return EncoderSession_finish_error(&encoder_session);
sample_frames= xx;
/* bits per sample */
if(!read_big_endian_uint16(infile, &x, false, encoder_session.inbasefilename))
return EncoderSession_finish_error(&encoder_session);
else if(x!=8U && x!=16U && x!=24U) {
flac__utils_printf(stderr, 1, "%s: ERROR: unsupported bits per sample %u\n", encoder_session.inbasefilename, (unsigned int)x);
return EncoderSession_finish_error(&encoder_session);
}
else if(options.common.sector_align && x!=16U) {
flac__utils_printf(stderr, 1, "%s: ERROR: file has %u bits per sample, must be 16 for --sector-align\n", encoder_session.inbasefilename, (unsigned int)x);
return EncoderSession_finish_error(&encoder_session);
}
bps= x;
/* sample rate */
if(!read_sane_extended(infile, &xx, false, encoder_session.inbasefilename))
return EncoderSession_finish_error(&encoder_session);
else if(!FLAC__format_sample_rate_is_valid(xx)) {
flac__utils_printf(stderr, 1, "%s: ERROR: unsupported sample rate %u\n", encoder_session.inbasefilename, (unsigned int)xx);
return EncoderSession_finish_error(&encoder_session);
}
else if(options.common.sector_align && xx!=44100U) {
flac__utils_printf(stderr, 1, "%s: ERROR: file's sample rate is %u, must be 44100 for --sector-align\n", encoder_session.inbasefilename, (unsigned int)xx);
return EncoderSession_finish_error(&encoder_session);
}
sample_rate= xx;
/* skip any extra data in the COMM chunk */
if(!fskip_ahead(infile, skip)) {
flac__utils_printf(stderr, 1, "%s: ERROR during read while skipping extra COMM data\n", encoder_session.inbasefilename);
return EncoderSession_finish_error(&encoder_session);
}
/*
* now that we know the sample rate, canonicalize the
* --skip string to a number of samples:
*/
flac__utils_canonicalize_skip_until_specification(&options.common.skip_specification, 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 || encoder_session.skip == 0);
got_comm_chunk= true;
}
else if(got_ssnd_chunk==false && !strncmp(chunk_id, "SSND", 4)) { /* sound data chunk */
unsigned int offset= 0U, block_size= 0U, align_remainder= 0U, data_bytes;
size_t bytes_per_frame= channels*(bps>>3);
FLAC__uint64 total_samples_in_input, trim = 0;
FLAC__bool pad= false;
if(got_comm_chunk==false) {
flac__utils_printf(stderr, 1, "%s: ERROR: got 'SSND' chunk before 'COMM' chunk\n", encoder_session.inbasefilename);
return EncoderSession_finish_error(&encoder_session);
}
/* SSND chunk size */
if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename))
return EncoderSession_finish_error(&encoder_session);
data_bytes= xx;
pad= (data_bytes & 1U) ? true : false;
data_bytes-= 8U; /* discount the offset and block size fields */
/* offset */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -