📄 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 2048typedef 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_OGGextern 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_OGGstatic 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);#endifstatic 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 */intflac__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 */ if(!read_big_endian_uint32(infile, &xx, false, encoder_session.inbasefilename)) return EncoderSession_finish_error(&encoder_session); offset= xx; data_bytes-= offset;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -