blob: 26f7dbce59f8b409517bf1c82179126f17d916bd [file] [log] [blame]
Josh Coalson26560dd2001-02-08 00:38:41 +00001/* libFLAC - Free Lossless Audio Codec library
Josh Coalson0395dac2006-04-25 06:59:33 +00002 * Copyright (C) 2000,2001,2002,2003,2004,2005,2006 Josh Coalson
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003 *
Josh Coalsonafd81072003-01-31 23:34:56 +00004 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00007 *
Josh Coalsonafd81072003-01-31 23:34:56 +00008 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000010 *
Josh Coalsonafd81072003-01-31 23:34:56 +000011 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of the Xiph.org Foundation nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000030 */
31
Josh Coalsonb1ec7962006-05-24 04:41:36 +000032#if HAVE_CONFIG_H
33# include <config.h>
34#endif
35
Josh Coalson6b21f662006-09-13 01:42:27 +000036#if defined _MSC_VER || defined __MINGW32__
37#include <io.h> /* for _setmode() */
38#include <fcntl.h> /* for _O_BINARY */
39#endif
40#if defined __CYGWIN__ || defined __EMX__
41#include <io.h> /* for setmode(), O_BINARY */
42#include <fcntl.h> /* for _O_BINARY */
43#endif
Josh Coalsone6b3bbe2002-10-08 06:03:25 +000044#include <limits.h>
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000045#include <stdio.h>
46#include <stdlib.h> /* for malloc() */
47#include <string.h> /* for memcpy() */
Josh Coalson6b21f662006-09-13 01:42:27 +000048#include <sys/types.h> /* for off_t */
Josh Coalson2beca732006-11-21 01:51:58 +000049#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
50#if _MSC_VER <= 1200 || defined __BORLANDC__ /* @@@ [2G limit] */
Josh Coalson6b21f662006-09-13 01:42:27 +000051#define fseeko fseek
52#define ftello ftell
53#endif
Josh Coalson825e72c2006-10-03 01:16:59 +000054#endif
Josh Coalson1b689822001-05-31 20:11:02 +000055#include "FLAC/assert.h"
Josh Coalsond86e03b2002-08-03 21:56:15 +000056#include "FLAC/stream_decoder.h"
Josh Coalson0a15c142001-06-13 17:59:57 +000057#include "protected/stream_encoder.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000058#include "private/bitbuffer.h"
Josh Coalsoneef56702001-03-30 00:45:22 +000059#include "private/bitmath.h"
Josh Coalson215af572001-03-27 01:15:58 +000060#include "private/crc.h"
Josh Coalsoncf30f502001-05-23 20:57:44 +000061#include "private/cpu.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000062#include "private/fixed.h"
Josh Coalsonb7023aa2002-08-17 15:23:43 +000063#include "private/format.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000064#include "private/lpc.h"
Josh Coalsonfa37f1c2001-01-12 23:55:11 +000065#include "private/md5.h"
Josh Coalsond98c43d2001-05-13 05:17:01 +000066#include "private/memory.h"
Josh Coalsonf1ac7d92006-11-16 07:20:09 +000067#if FLAC__HAS_OGG
Josh Coalson8da98c82006-10-15 04:24:05 +000068#include "private/ogg_helper.h"
Josh Coalsonc986d132006-11-15 08:53:32 +000069#include "private/ogg_mapping.h"
Josh Coalson8da98c82006-10-15 04:24:05 +000070#endif
Josh Coalsonb7023aa2002-08-17 15:23:43 +000071#include "private/stream_encoder_framing.h"
Josh Coalsonbf0f52c2006-04-25 06:38:43 +000072#include "private/window.h"
Josh Coalsonbb7f6b92000-12-10 04:09:52 +000073
74#ifdef min
75#undef min
76#endif
77#define min(x,y) ((x)<(y)?(x):(y))
78
79#ifdef max
80#undef max
81#endif
82#define max(x,y) ((x)>(y)?(x):(y))
83
Josh Coalsonce1d07c2007-01-23 05:00:46 +000084/* Exact Rice codeword length calculation is off by default. The simple
85 * (and fast) estimation (of how many bits a residual value will be
86 * encoded with) in this encoder is very good, almost always yielding
87 * compression within 0.1% of exact calculation.
88 */
89#undef EXACT_RICE_BITS_CALCULATION
90/* Rice parameter searching is off by default. The simple (and fast)
91 * parameter estimation in this encoder is very good, almost always
92 * yielding compression within 0.1% of the optimal parameters.
93 */
94#undef ENABLE_RICE_PARAMETER_SEARCH
95
Josh Coalsond86e03b2002-08-03 21:56:15 +000096typedef struct {
97 FLAC__int32 *data[FLAC__MAX_CHANNELS];
98 unsigned size; /* of each data[] in samples */
99 unsigned tail;
100} verify_input_fifo;
101
102typedef struct {
103 const FLAC__byte *data;
104 unsigned capacity;
105 unsigned bytes;
106} verify_output;
107
108typedef enum {
109 ENCODER_IN_MAGIC = 0,
110 ENCODER_IN_METADATA = 1,
111 ENCODER_IN_AUDIO = 2
112} EncoderStateHint;
113
Josh Coalson425609c2006-11-03 16:08:52 +0000114static struct CompressionLevels {
115 FLAC__bool do_mid_side_stereo;
116 FLAC__bool loose_mid_side_stereo;
Josh Coalson425609c2006-11-03 16:08:52 +0000117 unsigned max_lpc_order;
118 unsigned qlp_coeff_precision;
119 FLAC__bool do_qlp_coeff_prec_search;
120 FLAC__bool do_escape_coding;
121 FLAC__bool do_exhaustive_model_search;
122 unsigned min_residual_partition_order;
123 unsigned max_residual_partition_order;
124 unsigned rice_parameter_search_dist;
125} compression_levels_[] = {
Josh Coalson4e8fe852006-12-05 01:36:46 +0000126 { false, false, 0, 0, false, false, false, 2, 2, 0 },
127 { true , true , 0, 0, false, false, false, 2, 2, 0 },
128 { true , false, 0, 0, false, false, false, 0, 3, 0 },
129 { false, false, 6, 0, false, false, false, 3, 3, 0 },
130 { true , true , 8, 0, false, false, false, 3, 3, 0 },
131 { true , false, 8, 0, false, false, false, 3, 3, 0 },
132 { true , false, 8, 0, false, false, false, 0, 4, 0 },
133 { true , false, 8, 0, false, false, true , 0, 6, 0 },
134 { true , false, 12, 0, false, false, true , 0, 6, 0 }
Josh Coalson425609c2006-11-03 16:08:52 +0000135};
136
137
Josh Coalson0a15c142001-06-13 17:59:57 +0000138/***********************************************************************
139 *
140 * Private class method prototypes
141 *
142 ***********************************************************************/
143
Josh Coalsonf1eff452002-07-31 07:05:33 +0000144static void set_defaults_(FLAC__StreamEncoder *encoder);
145static void free_(FLAC__StreamEncoder *encoder);
Josh Coalson85aaed82006-11-09 01:19:13 +0000146static FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize);
Josh Coalson49f2f162006-11-09 16:54:52 +0000147static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block);
148static FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, FLAC__bool is_last_block);
Josh Coalson6b21f662006-09-13 01:42:27 +0000149static void update_metadata_(const FLAC__StreamEncoder *encoder);
Josh Coalson15b8eb82006-10-15 05:15:55 +0000150#if FLAC__HAS_OGG
Josh Coalson8da98c82006-10-15 04:24:05 +0000151static void update_ogg_metadata_(FLAC__StreamEncoder *encoder);
Josh Coalson15b8eb82006-10-15 05:15:55 +0000152#endif
Josh Coalson49f2f162006-11-09 16:54:52 +0000153static FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block);
Josh Coalson85aaed82006-11-09 01:19:13 +0000154static FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block);
Josh Coalson6fe72f72002-08-20 04:01:59 +0000155
156static FLAC__bool process_subframe_(
157 FLAC__StreamEncoder *encoder,
158 unsigned min_partition_order,
159 unsigned max_partition_order,
160 FLAC__bool precompute_partition_sums,
Josh Coalson6fe72f72002-08-20 04:01:59 +0000161 const FLAC__FrameHeader *frame_header,
162 unsigned subframe_bps,
163 const FLAC__int32 integer_signal[],
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000164#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson6fe72f72002-08-20 04:01:59 +0000165 const FLAC__real real_signal[],
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000166#endif
Josh Coalson6fe72f72002-08-20 04:01:59 +0000167 FLAC__Subframe *subframe[2],
168 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
169 FLAC__int32 *residual[2],
170 unsigned *best_subframe,
171 unsigned *best_bits
172);
173
174static FLAC__bool add_subframe_(
175 FLAC__StreamEncoder *encoder,
Josh Coalsonce1d07c2007-01-23 05:00:46 +0000176 unsigned blocksize,
Josh Coalson6fe72f72002-08-20 04:01:59 +0000177 unsigned subframe_bps,
178 const FLAC__Subframe *subframe,
179 FLAC__BitBuffer *frame
180);
181
182static unsigned evaluate_constant_subframe_(
Josh Coalsonce1d07c2007-01-23 05:00:46 +0000183 FLAC__StreamEncoder *encoder,
Josh Coalson6fe72f72002-08-20 04:01:59 +0000184 const FLAC__int32 signal,
Josh Coalsonce1d07c2007-01-23 05:00:46 +0000185 unsigned blocksize,
Josh Coalson6fe72f72002-08-20 04:01:59 +0000186 unsigned subframe_bps,
187 FLAC__Subframe *subframe
188);
189
190static unsigned evaluate_fixed_subframe_(
191 FLAC__StreamEncoder *encoder,
192 const FLAC__int32 signal[],
193 FLAC__int32 residual[],
194 FLAC__uint32 abs_residual[],
195 FLAC__uint64 abs_residual_partition_sums[],
196 unsigned raw_bits_per_partition[],
197 unsigned blocksize,
198 unsigned subframe_bps,
199 unsigned order,
200 unsigned rice_parameter,
201 unsigned min_partition_order,
202 unsigned max_partition_order,
203 FLAC__bool precompute_partition_sums,
204 FLAC__bool do_escape_coding,
205 unsigned rice_parameter_search_dist,
206 FLAC__Subframe *subframe,
207 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
208);
209
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000210#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson6fe72f72002-08-20 04:01:59 +0000211static unsigned evaluate_lpc_subframe_(
212 FLAC__StreamEncoder *encoder,
213 const FLAC__int32 signal[],
214 FLAC__int32 residual[],
215 FLAC__uint32 abs_residual[],
216 FLAC__uint64 abs_residual_partition_sums[],
217 unsigned raw_bits_per_partition[],
218 const FLAC__real lp_coeff[],
219 unsigned blocksize,
220 unsigned subframe_bps,
221 unsigned order,
222 unsigned qlp_coeff_precision,
223 unsigned rice_parameter,
224 unsigned min_partition_order,
225 unsigned max_partition_order,
226 FLAC__bool precompute_partition_sums,
227 FLAC__bool do_escape_coding,
228 unsigned rice_parameter_search_dist,
229 FLAC__Subframe *subframe,
230 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
231);
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000232#endif
Josh Coalson6fe72f72002-08-20 04:01:59 +0000233
234static unsigned evaluate_verbatim_subframe_(
Josh Coalsonce1d07c2007-01-23 05:00:46 +0000235 FLAC__StreamEncoder *encoder,
Josh Coalson6fe72f72002-08-20 04:01:59 +0000236 const FLAC__int32 signal[],
237 unsigned blocksize,
238 unsigned subframe_bps,
239 FLAC__Subframe *subframe
240);
241
242static unsigned find_best_partition_order_(
243 struct FLAC__StreamEncoderPrivate *private_,
244 const FLAC__int32 residual[],
245 FLAC__uint32 abs_residual[],
246 FLAC__uint64 abs_residual_partition_sums[],
247 unsigned raw_bits_per_partition[],
248 unsigned residual_samples,
249 unsigned predictor_order,
250 unsigned rice_parameter,
251 unsigned min_partition_order,
252 unsigned max_partition_order,
253 FLAC__bool precompute_partition_sums,
254 FLAC__bool do_escape_coding,
255 unsigned rice_parameter_search_dist,
256 FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice
257);
258
259static void precompute_partition_info_sums_(
260 const FLAC__uint32 abs_residual[],
261 FLAC__uint64 abs_residual_partition_sums[],
262 unsigned residual_samples,
263 unsigned predictor_order,
264 unsigned min_partition_order,
265 unsigned max_partition_order
266);
267
268static void precompute_partition_info_escapes_(
269 const FLAC__int32 residual[],
270 unsigned raw_bits_per_partition[],
271 unsigned residual_samples,
272 unsigned predictor_order,
273 unsigned min_partition_order,
274 unsigned max_partition_order
275);
276
Josh Coalson6fe72f72002-08-20 04:01:59 +0000277static FLAC__bool set_partitioned_rice_(
278 const FLAC__uint32 abs_residual[],
Josh Coalsonce1d07c2007-01-23 05:00:46 +0000279#ifdef EXACT_RICE_BITS_CALCULATION
Josh Coalson6fe72f72002-08-20 04:01:59 +0000280 const FLAC__int32 residual[],
Josh Coalson0a15c142001-06-13 17:59:57 +0000281#endif
Josh Coalsonce1d07c2007-01-23 05:00:46 +0000282 const unsigned residual_samples,
283 const unsigned predictor_order,
284 const unsigned suggested_rice_parameter,
285 const unsigned rice_parameter_search_dist,
286 const unsigned partition_order,
287 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
288 unsigned *bits
289);
290
291static FLAC__bool set_partitioned_rice_with_precompute_(
292#ifdef EXACT_RICE_BITS_CALCULATION
293 const FLAC__int32 residual[],
294#else
295 const FLAC__uint32 abs_residual[],
296#endif
297 const FLAC__uint64 abs_residual_partition_sums[],
298 const unsigned raw_bits_per_partition[],
299 const unsigned residual_samples,
300 const unsigned predictor_order,
301 const unsigned suggested_rice_parameter,
302 const unsigned rice_parameter_search_dist,
303 const unsigned partition_order,
304 const FLAC__bool search_for_escapes,
305 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
306 unsigned *bits
307);
Josh Coalson6fe72f72002-08-20 04:01:59 +0000308
Josh Coalsonf1eff452002-07-31 07:05:33 +0000309static unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples);
Josh Coalson6fe72f72002-08-20 04:01:59 +0000310
Josh Coalsond86e03b2002-08-03 21:56:15 +0000311/* verify-related routines: */
Josh Coalson6fe72f72002-08-20 04:01:59 +0000312static void append_to_verify_fifo_(
313 verify_input_fifo *fifo,
314 const FLAC__int32 * const input[],
315 unsigned input_offset,
316 unsigned channels,
317 unsigned wide_samples
318);
319
320static void append_to_verify_fifo_interleaved_(
321 verify_input_fifo *fifo,
322 const FLAC__int32 input[],
323 unsigned input_offset,
324 unsigned channels,
325 unsigned wide_samples
326);
327
Josh Coalson8065a2d2006-10-15 08:32:56 +0000328static FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
Josh Coalson6b21f662006-09-13 01:42:27 +0000329static FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
330static void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
331static void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
Josh Coalson6fe72f72002-08-20 04:01:59 +0000332
Josh Coalson8065a2d2006-10-15 08:32:56 +0000333static FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
Josh Coalson6b21f662006-09-13 01:42:27 +0000334static FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
335static FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
Josh Coalson352feb52006-10-15 17:08:52 +0000336static FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
Josh Coalson6b21f662006-09-13 01:42:27 +0000337static FILE *get_binary_stdout_();
Josh Coalson6fe72f72002-08-20 04:01:59 +0000338
Josh Coalson0a15c142001-06-13 17:59:57 +0000339
340/***********************************************************************
341 *
342 * Private class data
343 *
344 ***********************************************************************/
345
346typedef struct FLAC__StreamEncoderPrivate {
Josh Coalson8395d022001-07-12 21:25:22 +0000347 unsigned input_capacity; /* current size (in samples) of the signal and residual buffers */
Josh Coalson77e3f312001-06-23 03:03:24 +0000348 FLAC__int32 *integer_signal[FLAC__MAX_CHANNELS]; /* the integer version of the input signal */
349 FLAC__int32 *integer_signal_mid_side[2]; /* the integer version of the mid-side input signal (stereo only) */
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000350#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson77e3f312001-06-23 03:03:24 +0000351 FLAC__real *real_signal[FLAC__MAX_CHANNELS]; /* the floating-point version of the input signal */
352 FLAC__real *real_signal_mid_side[2]; /* the floating-point version of the mid-side input signal (stereo only) */
Josh Coalsonbf0f52c2006-04-25 06:38:43 +0000353 FLAC__real *window[FLAC__MAX_APODIZATION_FUNCTIONS]; /* the pre-computed floating-point window for each apodization function */
354 FLAC__real *windowed_signal; /* the real_signal[] * current window[] */
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000355#endif
Josh Coalson8395d022001-07-12 21:25:22 +0000356 unsigned subframe_bps[FLAC__MAX_CHANNELS]; /* the effective bits per sample of the input signal (stream bps - wasted bits) */
357 unsigned subframe_bps_mid_side[2]; /* the effective bits per sample of the mid-side input signal (stream bps - wasted bits + 0/1) */
Josh Coalson77e3f312001-06-23 03:03:24 +0000358 FLAC__int32 *residual_workspace[FLAC__MAX_CHANNELS][2]; /* each channel has a candidate and best workspace where the subframe residual signals will be stored */
359 FLAC__int32 *residual_workspace_mid_side[2][2];
Josh Coalson94e02cd2001-01-25 10:41:06 +0000360 FLAC__Subframe subframe_workspace[FLAC__MAX_CHANNELS][2];
361 FLAC__Subframe subframe_workspace_mid_side[2][2];
362 FLAC__Subframe *subframe_workspace_ptr[FLAC__MAX_CHANNELS][2];
363 FLAC__Subframe *subframe_workspace_ptr_mid_side[2][2];
Josh Coalsona37ba462002-08-19 21:36:39 +0000364 FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace[FLAC__MAX_CHANNELS][2];
365 FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace_mid_side[FLAC__MAX_CHANNELS][2];
366 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr[FLAC__MAX_CHANNELS][2];
367 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr_mid_side[FLAC__MAX_CHANNELS][2];
Josh Coalsonce1d07c2007-01-23 05:00:46 +0000368 unsigned best_subframe[FLAC__MAX_CHANNELS]; /* index (0 or 1) into 2nd dimension of the above workspaces */
Josh Coalson94e02cd2001-01-25 10:41:06 +0000369 unsigned best_subframe_mid_side[2];
Josh Coalson8395d022001-07-12 21:25:22 +0000370 unsigned best_subframe_bits[FLAC__MAX_CHANNELS]; /* size in bits of the best subframe for each channel */
Josh Coalson94e02cd2001-01-25 10:41:06 +0000371 unsigned best_subframe_bits_mid_side[2];
Josh Coalson77e3f312001-06-23 03:03:24 +0000372 FLAC__uint32 *abs_residual; /* workspace where abs(candidate residual) is stored */
Josh Coalsonb3347bd2001-07-16 18:06:41 +0000373 FLAC__uint64 *abs_residual_partition_sums; /* workspace where the sum of abs(candidate residual) for each partition is stored */
Josh Coalson8395d022001-07-12 21:25:22 +0000374 unsigned *raw_bits_per_partition; /* workspace where the sum of silog2(candidate residual) for each partition is stored */
Josh Coalsonaec256b2002-03-12 16:19:54 +0000375 FLAC__BitBuffer *frame; /* the current frame being worked on */
Josh Coalson8395d022001-07-12 21:25:22 +0000376 unsigned loose_mid_side_stereo_frames; /* rounded number of frames the encoder will use before trying both independent and mid/side frames again */
377 unsigned loose_mid_side_stereo_frame_count; /* number of frames using the current channel assignment */
Josh Coalsonb5e60e52001-01-28 09:27:27 +0000378 FLAC__ChannelAssignment last_channel_assignment;
Josh Coalson6b21f662006-09-13 01:42:27 +0000379 FLAC__StreamMetadata streaminfo; /* scratchpad for STREAMINFO as it is built */
380 FLAC__StreamMetadata_SeekTable *seek_table; /* pointer into encoder->protected_->metadata_ where the seek table is */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000381 unsigned current_sample_number;
382 unsigned current_frame_number;
Josh Coalson3e7a96e2004-07-23 05:18:22 +0000383 struct FLAC__MD5Context md5context;
Josh Coalsoncf30f502001-05-23 20:57:44 +0000384 FLAC__CPUInfo cpuinfo;
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000385#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson09758432004-10-20 00:21:50 +0000386 unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000387#else
388 unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
389#endif
390#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson77e3f312001-06-23 03:03:24 +0000391 void (*local_lpc_compute_autocorrelation)(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
Josh Coalson7446e182005-01-26 04:04:38 +0000392 void (*local_lpc_compute_residual_from_qlp_coefficients)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
393 void (*local_lpc_compute_residual_from_qlp_coefficients_64bit)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
394 void (*local_lpc_compute_residual_from_qlp_coefficients_16bit)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000395#endif
Josh Coalson3262b0d2002-08-14 20:58:42 +0000396 FLAC__bool use_wide_by_block; /* use slow 64-bit versions of some functions because of the block size */
397 FLAC__bool use_wide_by_partition; /* use slow 64-bit versions of some functions because of the min partition order and blocksize */
398 FLAC__bool use_wide_by_order; /* use slow 64-bit versions of some functions because of the lpc order */
Josh Coalsonce1d07c2007-01-23 05:00:46 +0000399 FLAC__bool precompute_partition_sums; /* our initial guess as to whether precomputing the partitions sums could be a speed improvement */
Josh Coalsone6b3bbe2002-10-08 06:03:25 +0000400 FLAC__bool disable_constant_subframes;
401 FLAC__bool disable_fixed_subframes;
402 FLAC__bool disable_verbatim_subframes;
Josh Coalson8da98c82006-10-15 04:24:05 +0000403#if FLAC__HAS_OGG
404 FLAC__bool is_ogg;
405#endif
406 FLAC__StreamEncoderReadCallback read_callback; /* currently only needed for Ogg FLAC */
Josh Coalson6b21f662006-09-13 01:42:27 +0000407 FLAC__StreamEncoderSeekCallback seek_callback;
408 FLAC__StreamEncoderTellCallback tell_callback;
Josh Coalson681c2932002-08-01 08:19:37 +0000409 FLAC__StreamEncoderWriteCallback write_callback;
410 FLAC__StreamEncoderMetadataCallback metadata_callback;
Josh Coalson6b21f662006-09-13 01:42:27 +0000411 FLAC__StreamEncoderProgressCallback progress_callback;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000412 void *client_data;
Josh Coalson6b21f662006-09-13 01:42:27 +0000413 unsigned first_seekpoint_to_check;
414 FILE *file; /* only used when encoding to a file */
415 FLAC__uint64 bytes_written;
416 FLAC__uint64 samples_written;
417 unsigned frames_written;
418 unsigned total_frames_estimate;
Josh Coalsond98c43d2001-05-13 05:17:01 +0000419 /* unaligned (original) pointers to allocated data */
Josh Coalson77e3f312001-06-23 03:03:24 +0000420 FLAC__int32 *integer_signal_unaligned[FLAC__MAX_CHANNELS];
421 FLAC__int32 *integer_signal_mid_side_unaligned[2];
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000422#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson77e3f312001-06-23 03:03:24 +0000423 FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS];
424 FLAC__real *real_signal_mid_side_unaligned[2];
Josh Coalsonbf0f52c2006-04-25 06:38:43 +0000425 FLAC__real *window_unaligned[FLAC__MAX_APODIZATION_FUNCTIONS];
426 FLAC__real *windowed_signal_unaligned;
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000427#endif
Josh Coalson77e3f312001-06-23 03:03:24 +0000428 FLAC__int32 *residual_workspace_unaligned[FLAC__MAX_CHANNELS][2];
429 FLAC__int32 *residual_workspace_mid_side_unaligned[2][2];
430 FLAC__uint32 *abs_residual_unaligned;
Josh Coalsonb3347bd2001-07-16 18:06:41 +0000431 FLAC__uint64 *abs_residual_partition_sums_unaligned;
Josh Coalsond98c43d2001-05-13 05:17:01 +0000432 unsigned *raw_bits_per_partition_unaligned;
Josh Coalson8084b052001-11-01 00:27:29 +0000433 /*
434 * These fields have been moved here from private function local
435 * declarations merely to save stack space during encoding.
436 */
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000437#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonf1eff452002-07-31 07:05:33 +0000438 FLAC__real lp_coeff[FLAC__MAX_LPC_ORDER][FLAC__MAX_LPC_ORDER]; /* from process_subframe_() */
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000439#endif
Josh Coalsona37ba462002-08-19 21:36:39 +0000440 FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_extra[2]; /* from find_best_partition_order_() */
Josh Coalsond86e03b2002-08-03 21:56:15 +0000441 /*
442 * The data for the verify section
443 */
444 struct {
445 FLAC__StreamDecoder *decoder;
446 EncoderStateHint state_hint;
447 FLAC__bool needs_magic_hack;
448 verify_input_fifo input_fifo;
449 verify_output output;
450 struct {
451 FLAC__uint64 absolute_sample;
452 unsigned frame_number;
453 unsigned channel;
454 unsigned sample;
455 FLAC__int32 expected;
456 FLAC__int32 got;
457 } error_stats;
458 } verify;
Josh Coalson3262b0d2002-08-14 20:58:42 +0000459 FLAC__bool is_being_deleted; /* if true, call to ..._finish() from ..._delete() will not call the callbacks */
Josh Coalson0a15c142001-06-13 17:59:57 +0000460} FLAC__StreamEncoderPrivate;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000461
Josh Coalson0a15c142001-06-13 17:59:57 +0000462/***********************************************************************
463 *
464 * Public static class data
465 *
466 ***********************************************************************/
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000467
Josh Coalson6afed9f2002-10-16 22:29:47 +0000468FLAC_API const char * const FLAC__StreamEncoderStateString[] = {
Josh Coalson0a15c142001-06-13 17:59:57 +0000469 "FLAC__STREAM_ENCODER_OK",
Josh Coalson6b21f662006-09-13 01:42:27 +0000470 "FLAC__STREAM_ENCODER_UNINITIALIZED",
Josh Coalson8da98c82006-10-15 04:24:05 +0000471 "FLAC__STREAM_ENCODER_OGG_ERROR",
Josh Coalsond86e03b2002-08-03 21:56:15 +0000472 "FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR",
473 "FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA",
Josh Coalson6b21f662006-09-13 01:42:27 +0000474 "FLAC__STREAM_ENCODER_CLIENT_ERROR",
475 "FLAC__STREAM_ENCODER_IO_ERROR",
Josh Coalson0a15c142001-06-13 17:59:57 +0000476 "FLAC__STREAM_ENCODER_FRAMING_ERROR",
Josh Coalson6b21f662006-09-13 01:42:27 +0000477 "FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR"
478};
479
480FLAC_API const char * const FLAC__StreamEncoderInitStatusString[] = {
481 "FLAC__STREAM_ENCODER_INIT_STATUS_OK",
482 "FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR",
Josh Coalson8da98c82006-10-15 04:24:05 +0000483 "FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER",
Josh Coalson6b21f662006-09-13 01:42:27 +0000484 "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS",
485 "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS",
486 "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE",
487 "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE",
488 "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE",
489 "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER",
490 "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION",
Josh Coalson6b21f662006-09-13 01:42:27 +0000491 "FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER",
492 "FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE",
493 "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA",
494 "FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED"
Josh Coalsoncbf595f2000-12-22 22:35:33 +0000495};
496
Josh Coalson8da98c82006-10-15 04:24:05 +0000497FLAC_API const char * const FLAC__treamEncoderReadStatusString[] = {
498 "FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE",
499 "FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM",
500 "FLAC__STREAM_ENCODER_READ_STATUS_ABORT",
501 "FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED"
502};
503
Josh Coalson6afed9f2002-10-16 22:29:47 +0000504FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[] = {
Josh Coalson5c491a12002-08-01 06:39:40 +0000505 "FLAC__STREAM_ENCODER_WRITE_STATUS_OK",
506 "FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR"
Josh Coalsoncbf595f2000-12-22 22:35:33 +0000507};
508
Josh Coalson6b21f662006-09-13 01:42:27 +0000509FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[] = {
510 "FLAC__STREAM_ENCODER_SEEK_STATUS_OK",
511 "FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR",
512 "FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED"
513};
514
515FLAC_API const char * const FLAC__StreamEncoderTellStatusString[] = {
516 "FLAC__STREAM_ENCODER_TELL_STATUS_OK",
517 "FLAC__STREAM_ENCODER_TELL_STATUS_ERROR",
518 "FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED"
519};
520
Josh Coalson49f2f162006-11-09 16:54:52 +0000521/* Number of samples that will be overread to watch for end of stream. By
522 * 'overread', we mean that the FLAC__stream_encoder_process*() calls will
523 * always try to read blocksize+1 samples before encoding a block, so that
524 * even if the stream has a total sample count that is an integral multiple
525 * of the blocksize, we will still notice when we are encoding the last
526 * block. This is needed, for example, to correctly set the end-of-stream
527 * marker in Ogg FLAC.
528 *
529 * WATCHOUT: some parts of the code assert that OVERREAD_ == 1 and there's
530 * not really any reason to change it.
531 */
532static const unsigned OVERREAD_ = 1;
533
Josh Coalson0a15c142001-06-13 17:59:57 +0000534/***********************************************************************
535 *
536 * Class constructor/destructor
537 *
Josh Coalsond86e03b2002-08-03 21:56:15 +0000538 */
Josh Coalson6afed9f2002-10-16 22:29:47 +0000539FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new()
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000540{
Josh Coalson0a15c142001-06-13 17:59:57 +0000541 FLAC__StreamEncoder *encoder;
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000542 unsigned i;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000543
Josh Coalson0a15c142001-06-13 17:59:57 +0000544 FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000545
Josh Coalsonea7155f2002-10-18 05:49:19 +0000546 encoder = (FLAC__StreamEncoder*)calloc(1, sizeof(FLAC__StreamEncoder));
Josh Coalson0a15c142001-06-13 17:59:57 +0000547 if(encoder == 0) {
548 return 0;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000549 }
Josh Coalsond86e03b2002-08-03 21:56:15 +0000550
Josh Coalsonea7155f2002-10-18 05:49:19 +0000551 encoder->protected_ = (FLAC__StreamEncoderProtected*)calloc(1, sizeof(FLAC__StreamEncoderProtected));
Josh Coalsonfa697a92001-08-16 20:07:29 +0000552 if(encoder->protected_ == 0) {
Josh Coalson0a15c142001-06-13 17:59:57 +0000553 free(encoder);
554 return 0;
Josh Coalsond98c43d2001-05-13 05:17:01 +0000555 }
Josh Coalsond86e03b2002-08-03 21:56:15 +0000556
Josh Coalsonea7155f2002-10-18 05:49:19 +0000557 encoder->private_ = (FLAC__StreamEncoderPrivate*)calloc(1, sizeof(FLAC__StreamEncoderPrivate));
Josh Coalsonfa697a92001-08-16 20:07:29 +0000558 if(encoder->private_ == 0) {
559 free(encoder->protected_);
Josh Coalson0a15c142001-06-13 17:59:57 +0000560 free(encoder);
561 return 0;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000562 }
Josh Coalsond86e03b2002-08-03 21:56:15 +0000563
Josh Coalsonaec256b2002-03-12 16:19:54 +0000564 encoder->private_->frame = FLAC__bitbuffer_new();
565 if(encoder->private_->frame == 0) {
566 free(encoder->private_);
567 free(encoder->protected_);
568 free(encoder);
569 return 0;
570 }
Josh Coalsond98c43d2001-05-13 05:17:01 +0000571
Josh Coalson6b21f662006-09-13 01:42:27 +0000572 encoder->private_->file = 0;
573
Josh Coalsonf1eff452002-07-31 07:05:33 +0000574 set_defaults_(encoder);
Josh Coalson92031602002-07-24 06:02:11 +0000575
Josh Coalson3262b0d2002-08-14 20:58:42 +0000576 encoder->private_->is_being_deleted = false;
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000577
578 for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
579 encoder->private_->subframe_workspace_ptr[i][0] = &encoder->private_->subframe_workspace[i][0];
580 encoder->private_->subframe_workspace_ptr[i][1] = &encoder->private_->subframe_workspace[i][1];
581 }
582 for(i = 0; i < 2; i++) {
583 encoder->private_->subframe_workspace_ptr_mid_side[i][0] = &encoder->private_->subframe_workspace_mid_side[i][0];
584 encoder->private_->subframe_workspace_ptr_mid_side[i][1] = &encoder->private_->subframe_workspace_mid_side[i][1];
585 }
586 for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
Josh Coalsona37ba462002-08-19 21:36:39 +0000587 encoder->private_->partitioned_rice_contents_workspace_ptr[i][0] = &encoder->private_->partitioned_rice_contents_workspace[i][0];
588 encoder->private_->partitioned_rice_contents_workspace_ptr[i][1] = &encoder->private_->partitioned_rice_contents_workspace[i][1];
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000589 }
590 for(i = 0; i < 2; i++) {
Josh Coalsona37ba462002-08-19 21:36:39 +0000591 encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][0] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0];
592 encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][1] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1];
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000593 }
594
595 for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
Josh Coalsona37ba462002-08-19 21:36:39 +0000596 FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
597 FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000598 }
599 for(i = 0; i < 2; i++) {
Josh Coalsona37ba462002-08-19 21:36:39 +0000600 FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
601 FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000602 }
603 for(i = 0; i < 2; i++)
Josh Coalsona37ba462002-08-19 21:36:39 +0000604 FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_extra[i]);
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000605
Josh Coalsonfa697a92001-08-16 20:07:29 +0000606 encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000607
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000608 return encoder;
609}
610
Josh Coalson6afed9f2002-10-16 22:29:47 +0000611FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000612{
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000613 unsigned i;
614
Josh Coalsonf1eff452002-07-31 07:05:33 +0000615 FLAC__ASSERT(0 != encoder);
616 FLAC__ASSERT(0 != encoder->protected_);
617 FLAC__ASSERT(0 != encoder->private_);
618 FLAC__ASSERT(0 != encoder->private_->frame);
Josh Coalson0a15c142001-06-13 17:59:57 +0000619
Josh Coalson3262b0d2002-08-14 20:58:42 +0000620 encoder->private_->is_being_deleted = true;
621
Josh Coalsona5862262006-11-09 06:58:26 +0000622 (void)FLAC__stream_encoder_finish(encoder);
Josh Coalson3262b0d2002-08-14 20:58:42 +0000623
Josh Coalson4fa90592002-12-04 07:01:37 +0000624 if(0 != encoder->private_->verify.decoder)
Josh Coalsond86e03b2002-08-03 21:56:15 +0000625 FLAC__stream_decoder_delete(encoder->private_->verify.decoder);
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000626
627 for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
Josh Coalsona37ba462002-08-19 21:36:39 +0000628 FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
629 FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000630 }
631 for(i = 0; i < 2; i++) {
Josh Coalsona37ba462002-08-19 21:36:39 +0000632 FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
633 FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000634 }
635 for(i = 0; i < 2; i++)
Josh Coalsona37ba462002-08-19 21:36:39 +0000636 FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_extra[i]);
Josh Coalsonb7023aa2002-08-17 15:23:43 +0000637
Josh Coalsonaec256b2002-03-12 16:19:54 +0000638 FLAC__bitbuffer_delete(encoder->private_->frame);
Josh Coalsonfa697a92001-08-16 20:07:29 +0000639 free(encoder->private_);
640 free(encoder->protected_);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000641 free(encoder);
642}
643
Josh Coalson0a15c142001-06-13 17:59:57 +0000644/***********************************************************************
645 *
646 * Public class methods
647 *
648 ***********************************************************************/
649
Josh Coalson8da98c82006-10-15 04:24:05 +0000650static FLAC__StreamEncoderInitStatus init_stream_internal_(
651 FLAC__StreamEncoder *encoder,
652 FLAC__StreamEncoderReadCallback read_callback,
653 FLAC__StreamEncoderWriteCallback write_callback,
654 FLAC__StreamEncoderSeekCallback seek_callback,
655 FLAC__StreamEncoderTellCallback tell_callback,
656 FLAC__StreamEncoderMetadataCallback metadata_callback,
657 void *client_data,
658 FLAC__bool is_ogg
659)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000660{
661 unsigned i;
Josh Coalson3957c472006-09-24 16:25:42 +0000662 FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment, metadata_picture_has_type1, metadata_picture_has_type2;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000663
Josh Coalsonf1eff452002-07-31 07:05:33 +0000664 FLAC__ASSERT(0 != encoder);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000665
Josh Coalsonfa697a92001-08-16 20:07:29 +0000666 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson6b21f662006-09-13 01:42:27 +0000667 return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000668
Josh Coalsonf1ac7d92006-11-16 07:20:09 +0000669#if !FLAC__HAS_OGG
Josh Coalson8da98c82006-10-15 04:24:05 +0000670 if(is_ogg)
671 return FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
672#endif
673
Josh Coalson6b21f662006-09-13 01:42:27 +0000674 if(0 == write_callback || (seek_callback && 0 == tell_callback))
675 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000676
Josh Coalsonfa697a92001-08-16 20:07:29 +0000677 if(encoder->protected_->channels == 0 || encoder->protected_->channels > FLAC__MAX_CHANNELS)
Josh Coalson6b21f662006-09-13 01:42:27 +0000678 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS;
Josh Coalson69f1ee02001-01-24 00:54:43 +0000679
Josh Coalson425609c2006-11-03 16:08:52 +0000680 if(encoder->protected_->channels != 2) {
681 encoder->protected_->do_mid_side_stereo = false;
682 encoder->protected_->loose_mid_side_stereo = false;
683 }
684 else if(!encoder->protected_->do_mid_side_stereo)
685 encoder->protected_->loose_mid_side_stereo = false;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000686
Josh Coalsonfa697a92001-08-16 20:07:29 +0000687 if(encoder->protected_->bits_per_sample >= 32)
Josh Coalson6b21f662006-09-13 01:42:27 +0000688 encoder->protected_->do_mid_side_stereo = false; /* since we currenty do 32-bit math, the side channel would have 33 bps and overflow */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000689
Josh Coalson76c68bc2002-05-17 06:22:02 +0000690 if(encoder->protected_->bits_per_sample < FLAC__MIN_BITS_PER_SAMPLE || encoder->protected_->bits_per_sample > FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE)
Josh Coalson6b21f662006-09-13 01:42:27 +0000691 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000692
Josh Coalson0833f342002-07-15 05:31:55 +0000693 if(!FLAC__format_sample_rate_is_valid(encoder->protected_->sample_rate))
Josh Coalson6b21f662006-09-13 01:42:27 +0000694 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000695
Josh Coalson425609c2006-11-03 16:08:52 +0000696 if(encoder->protected_->blocksize == 0) {
697 if(encoder->protected_->max_lpc_order == 0)
698 encoder->protected_->blocksize = 1152;
699 else
700 encoder->protected_->blocksize = 4608;
701 }
702
Josh Coalsonfa697a92001-08-16 20:07:29 +0000703 if(encoder->protected_->blocksize < FLAC__MIN_BLOCK_SIZE || encoder->protected_->blocksize > FLAC__MAX_BLOCK_SIZE)
Josh Coalson6b21f662006-09-13 01:42:27 +0000704 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE;
Josh Coalson0a15c142001-06-13 17:59:57 +0000705
Josh Coalson20ac2c12002-08-30 05:47:14 +0000706 if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER)
Josh Coalson6b21f662006-09-13 01:42:27 +0000707 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER;
Josh Coalson20ac2c12002-08-30 05:47:14 +0000708
Josh Coalsonfa697a92001-08-16 20:07:29 +0000709 if(encoder->protected_->blocksize < encoder->protected_->max_lpc_order)
Josh Coalson6b21f662006-09-13 01:42:27 +0000710 return FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER;
Josh Coalson0a15c142001-06-13 17:59:57 +0000711
Josh Coalsonfa697a92001-08-16 20:07:29 +0000712 if(encoder->protected_->qlp_coeff_precision == 0) {
713 if(encoder->protected_->bits_per_sample < 16) {
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000714 /* @@@ need some data about how to set this here w.r.t. blocksize and sample rate */
715 /* @@@ until then we'll make a guess */
Josh Coalsonc9c0d132002-10-04 05:29:05 +0000716 encoder->protected_->qlp_coeff_precision = max(FLAC__MIN_QLP_COEFF_PRECISION, 2 + encoder->protected_->bits_per_sample / 2);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000717 }
Josh Coalsonfa697a92001-08-16 20:07:29 +0000718 else if(encoder->protected_->bits_per_sample == 16) {
719 if(encoder->protected_->blocksize <= 192)
720 encoder->protected_->qlp_coeff_precision = 7;
721 else if(encoder->protected_->blocksize <= 384)
722 encoder->protected_->qlp_coeff_precision = 8;
723 else if(encoder->protected_->blocksize <= 576)
724 encoder->protected_->qlp_coeff_precision = 9;
725 else if(encoder->protected_->blocksize <= 1152)
726 encoder->protected_->qlp_coeff_precision = 10;
727 else if(encoder->protected_->blocksize <= 2304)
728 encoder->protected_->qlp_coeff_precision = 11;
729 else if(encoder->protected_->blocksize <= 4608)
730 encoder->protected_->qlp_coeff_precision = 12;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000731 else
Josh Coalsonfa697a92001-08-16 20:07:29 +0000732 encoder->protected_->qlp_coeff_precision = 13;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000733 }
734 else {
Josh Coalsonc9c0d132002-10-04 05:29:05 +0000735 if(encoder->protected_->blocksize <= 384)
736 encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-2;
737 else if(encoder->protected_->blocksize <= 1152)
738 encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-1;
739 else
740 encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000741 }
Josh Coalsonc9c0d132002-10-04 05:29:05 +0000742 FLAC__ASSERT(encoder->protected_->qlp_coeff_precision <= FLAC__MAX_QLP_COEFF_PRECISION);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000743 }
Josh Coalsonc9c0d132002-10-04 05:29:05 +0000744 else if(encoder->protected_->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->protected_->qlp_coeff_precision > FLAC__MAX_QLP_COEFF_PRECISION)
Josh Coalson6b21f662006-09-13 01:42:27 +0000745 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000746
Josh Coalsonfa697a92001-08-16 20:07:29 +0000747 if(encoder->protected_->streamable_subset) {
Josh Coalson20ac2c12002-08-30 05:47:14 +0000748 if(
749 encoder->protected_->blocksize != 192 &&
750 encoder->protected_->blocksize != 576 &&
751 encoder->protected_->blocksize != 1152 &&
752 encoder->protected_->blocksize != 2304 &&
753 encoder->protected_->blocksize != 4608 &&
754 encoder->protected_->blocksize != 256 &&
755 encoder->protected_->blocksize != 512 &&
756 encoder->protected_->blocksize != 1024 &&
757 encoder->protected_->blocksize != 2048 &&
758 encoder->protected_->blocksize != 4096 &&
759 encoder->protected_->blocksize != 8192 &&
760 encoder->protected_->blocksize != 16384
761 )
Josh Coalson6b21f662006-09-13 01:42:27 +0000762 return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
Josh Coalson20ac2c12002-08-30 05:47:14 +0000763 if(
764 encoder->protected_->sample_rate != 8000 &&
765 encoder->protected_->sample_rate != 16000 &&
766 encoder->protected_->sample_rate != 22050 &&
767 encoder->protected_->sample_rate != 24000 &&
768 encoder->protected_->sample_rate != 32000 &&
769 encoder->protected_->sample_rate != 44100 &&
770 encoder->protected_->sample_rate != 48000 &&
771 encoder->protected_->sample_rate != 96000
772 )
Josh Coalson6b21f662006-09-13 01:42:27 +0000773 return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
Josh Coalson20ac2c12002-08-30 05:47:14 +0000774 if(
775 encoder->protected_->bits_per_sample != 8 &&
776 encoder->protected_->bits_per_sample != 12 &&
777 encoder->protected_->bits_per_sample != 16 &&
778 encoder->protected_->bits_per_sample != 20 &&
779 encoder->protected_->bits_per_sample != 24
780 )
Josh Coalson6b21f662006-09-13 01:42:27 +0000781 return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
Josh Coalsonc1c8d492002-09-26 04:42:10 +0000782 if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER)
Josh Coalson6b21f662006-09-13 01:42:27 +0000783 return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
Josh Coalsond0edb972006-10-07 06:50:08 +0000784 if(
785 encoder->protected_->sample_rate <= 48000 &&
786 (
787 encoder->protected_->blocksize > FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ ||
788 encoder->protected_->max_lpc_order > FLAC__SUBSET_MAX_LPC_ORDER_48000HZ
789 )
790 ) {
791 return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
792 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000793 }
794
Josh Coalsonfa697a92001-08-16 20:07:29 +0000795 if(encoder->protected_->max_residual_partition_order >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
796 encoder->protected_->max_residual_partition_order = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1;
797 if(encoder->protected_->min_residual_partition_order >= encoder->protected_->max_residual_partition_order)
798 encoder->protected_->min_residual_partition_order = encoder->protected_->max_residual_partition_order;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000799
Josh Coalson8da98c82006-10-15 04:24:05 +0000800#if FLAC__HAS_OGG
801 /* reorder metadata if necessary to ensure that any VORBIS_COMMENT is the first, according to the mapping spec */
802 if(is_ogg && 0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 1) {
803 unsigned i;
804 for(i = 1; i < encoder->protected_->num_metadata_blocks; i++) {
805 if(0 != encoder->protected_->metadata[i] && encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
806 FLAC__StreamMetadata *vc = encoder->protected_->metadata[i];
807 for( ; i > 0; i--)
808 encoder->protected_->metadata[i] = encoder->protected_->metadata[i-1];
809 encoder->protected_->metadata[0] = vc;
810 break;
811 }
812 }
813 }
814#endif
815 /* keep track of any SEEKTABLE block */
816 if(0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) {
817 unsigned i;
818 for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
819 if(0 != encoder->protected_->metadata[i] && encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) {
820 encoder->private_->seek_table = &encoder->protected_->metadata[i]->data.seek_table;
821 break; /* take only the first one */
822 }
823 }
824 }
825
Josh Coalson66075c12002-06-01 05:39:38 +0000826 /* validate metadata */
827 if(0 == encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0)
Josh Coalson6b21f662006-09-13 01:42:27 +0000828 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
Josh Coalsoncb9d93a2002-08-25 05:27:15 +0000829 metadata_has_seektable = false;
830 metadata_has_vorbis_comment = false;
Josh Coalson3957c472006-09-24 16:25:42 +0000831 metadata_picture_has_type1 = false;
832 metadata_picture_has_type2 = false;
Josh Coalson66075c12002-06-01 05:39:38 +0000833 for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
Josh Coalson3957c472006-09-24 16:25:42 +0000834 const FLAC__StreamMetadata *m = encoder->protected_->metadata[i];
835 if(m->type == FLAC__METADATA_TYPE_STREAMINFO)
Josh Coalson6b21f662006-09-13 01:42:27 +0000836 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
Josh Coalson3957c472006-09-24 16:25:42 +0000837 else if(m->type == FLAC__METADATA_TYPE_SEEKTABLE) {
Josh Coalsoncb9d93a2002-08-25 05:27:15 +0000838 if(metadata_has_seektable) /* only one is allowed */
Josh Coalson6b21f662006-09-13 01:42:27 +0000839 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
Josh Coalsoncb9d93a2002-08-25 05:27:15 +0000840 metadata_has_seektable = true;
Josh Coalson3957c472006-09-24 16:25:42 +0000841 if(!FLAC__format_seektable_is_legal(&m->data.seek_table))
Josh Coalson6b21f662006-09-13 01:42:27 +0000842 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
Josh Coalson66075c12002-06-01 05:39:38 +0000843 }
Josh Coalson3957c472006-09-24 16:25:42 +0000844 else if(m->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
Josh Coalsoncb9d93a2002-08-25 05:27:15 +0000845 if(metadata_has_vorbis_comment) /* only one is allowed */
Josh Coalson6b21f662006-09-13 01:42:27 +0000846 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
Josh Coalsoncb9d93a2002-08-25 05:27:15 +0000847 metadata_has_vorbis_comment = true;
848 }
Josh Coalson3957c472006-09-24 16:25:42 +0000849 else if(m->type == FLAC__METADATA_TYPE_CUESHEET) {
850 if(!FLAC__format_cuesheet_is_legal(&m->data.cue_sheet, m->data.cue_sheet.is_cd, /*violation=*/0))
Josh Coalson6b21f662006-09-13 01:42:27 +0000851 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
Josh Coalsone4869382002-11-15 05:41:48 +0000852 }
Josh Coalson3957c472006-09-24 16:25:42 +0000853 else if(m->type == FLAC__METADATA_TYPE_PICTURE) {
854 if(!FLAC__format_picture_is_legal(&m->data.picture, /*violation=*/0))
Josh Coalsone343ab22006-09-23 19:21:19 +0000855 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
Josh Coalson3957c472006-09-24 16:25:42 +0000856 if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) {
857 if(metadata_picture_has_type1) /* there should only be 1 per stream */
858 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
859 metadata_picture_has_type1 = true;
860 /* standard icon must be 32x32 pixel PNG */
861 if(
862 m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD &&
863 (
864 (strcmp(m->data.picture.mime_type, "image/png") && strcmp(m->data.picture.mime_type, "-->")) ||
865 m->data.picture.width != 32 ||
866 m->data.picture.height != 32
867 )
868 )
869 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
870 }
871 else if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) {
872 if(metadata_picture_has_type2) /* there should only be 1 per stream */
873 return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
874 metadata_picture_has_type2 = true;
875 }
Josh Coalsone343ab22006-09-23 19:21:19 +0000876 }
Josh Coalson66075c12002-06-01 05:39:38 +0000877 }
878
Josh Coalsonfa697a92001-08-16 20:07:29 +0000879 encoder->private_->input_capacity = 0;
880 for(i = 0; i < encoder->protected_->channels; i++) {
881 encoder->private_->integer_signal_unaligned[i] = encoder->private_->integer_signal[i] = 0;
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000882#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonfa697a92001-08-16 20:07:29 +0000883 encoder->private_->real_signal_unaligned[i] = encoder->private_->real_signal[i] = 0;
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000884#endif
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000885 }
886 for(i = 0; i < 2; i++) {
Josh Coalsonfa697a92001-08-16 20:07:29 +0000887 encoder->private_->integer_signal_mid_side_unaligned[i] = encoder->private_->integer_signal_mid_side[i] = 0;
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000888#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonfa697a92001-08-16 20:07:29 +0000889 encoder->private_->real_signal_mid_side_unaligned[i] = encoder->private_->real_signal_mid_side[i] = 0;
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000890#endif
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000891 }
Josh Coalsonbf0f52c2006-04-25 06:38:43 +0000892#ifndef FLAC__INTEGER_ONLY_LIBRARY
893 for(i = 0; i < encoder->protected_->num_apodizations; i++)
894 encoder->private_->window_unaligned[i] = encoder->private_->window[i] = 0;
895 encoder->private_->windowed_signal_unaligned = encoder->private_->windowed_signal = 0;
896#endif
Josh Coalsonfa697a92001-08-16 20:07:29 +0000897 for(i = 0; i < encoder->protected_->channels; i++) {
898 encoder->private_->residual_workspace_unaligned[i][0] = encoder->private_->residual_workspace[i][0] = 0;
899 encoder->private_->residual_workspace_unaligned[i][1] = encoder->private_->residual_workspace[i][1] = 0;
900 encoder->private_->best_subframe[i] = 0;
Josh Coalson94e02cd2001-01-25 10:41:06 +0000901 }
902 for(i = 0; i < 2; i++) {
Josh Coalsonfa697a92001-08-16 20:07:29 +0000903 encoder->private_->residual_workspace_mid_side_unaligned[i][0] = encoder->private_->residual_workspace_mid_side[i][0] = 0;
904 encoder->private_->residual_workspace_mid_side_unaligned[i][1] = encoder->private_->residual_workspace_mid_side[i][1] = 0;
905 encoder->private_->best_subframe_mid_side[i] = 0;
Josh Coalson94e02cd2001-01-25 10:41:06 +0000906 }
Josh Coalsonfa697a92001-08-16 20:07:29 +0000907 encoder->private_->abs_residual_unaligned = encoder->private_->abs_residual = 0;
908 encoder->private_->abs_residual_partition_sums_unaligned = encoder->private_->abs_residual_partition_sums = 0;
909 encoder->private_->raw_bits_per_partition_unaligned = encoder->private_->raw_bits_per_partition = 0;
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000910#ifndef FLAC__INTEGER_ONLY_LIBRARY
911 encoder->private_->loose_mid_side_stereo_frames = (unsigned)((FLAC__double)encoder->protected_->sample_rate * 0.4 / (FLAC__double)encoder->protected_->blocksize + 0.5);
912#else
913 /* 26214 is the approximate fixed-point equivalent to 0.4 (0.4 * 2^16) */
914 /* sample rate can be up to 655350 Hz, and thus use 20 bits, so we do the multiply&divide by hand */
915 FLAC__ASSERT(FLAC__MAX_SAMPLE_RATE <= 655350);
916 FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535);
917 FLAC__ASSERT(encoder->protected_->sample_rate <= 655350);
918 FLAC__ASSERT(encoder->protected_->blocksize <= 65535);
919 encoder->private_->loose_mid_side_stereo_frames = (unsigned)FLAC__fixedpoint_trunc((((FLAC__uint64)(encoder->protected_->sample_rate) * (FLAC__uint64)(26214)) << 16) / (encoder->protected_->blocksize<<16) + FLAC__FP_ONE_HALF);
920#endif
Josh Coalsonfa697a92001-08-16 20:07:29 +0000921 if(encoder->private_->loose_mid_side_stereo_frames == 0)
922 encoder->private_->loose_mid_side_stereo_frames = 1;
923 encoder->private_->loose_mid_side_stereo_frame_count = 0;
924 encoder->private_->current_sample_number = 0;
925 encoder->private_->current_frame_number = 0;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +0000926
Josh Coalsonfa697a92001-08-16 20:07:29 +0000927 encoder->private_->use_wide_by_block = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(encoder->protected_->blocksize)+1 > 30);
928 encoder->private_->use_wide_by_order = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(max(encoder->protected_->max_lpc_order, FLAC__MAX_FIXED_ORDER))+1 > 30); /*@@@ need to use this? */
929 encoder->private_->use_wide_by_partition = (false); /*@@@ need to set this */
Josh Coalson8395d022001-07-12 21:25:22 +0000930
Josh Coalsoncf30f502001-05-23 20:57:44 +0000931 /*
932 * get the CPU info and set the function pointers
933 */
Josh Coalsonfa697a92001-08-16 20:07:29 +0000934 FLAC__cpu_info(&encoder->private_->cpuinfo);
Josh Coalsoncf30f502001-05-23 20:57:44 +0000935 /* first default to the non-asm routines */
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000936#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonfa697a92001-08-16 20:07:29 +0000937 encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000938#endif
Josh Coalsonfa697a92001-08-16 20:07:29 +0000939 encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor;
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000940#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonfa697a92001-08-16 20:07:29 +0000941 encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients;
Josh Coalsonc9c0d132002-10-04 05:29:05 +0000942 encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide;
Josh Coalsonfa697a92001-08-16 20:07:29 +0000943 encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients;
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000944#endif
Josh Coalsoncf30f502001-05-23 20:57:44 +0000945 /* now override with asm where appropriate */
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000946#ifndef FLAC__INTEGER_ONLY_LIBRARY
947# ifndef FLAC__NO_ASM
Josh Coalsonfa697a92001-08-16 20:07:29 +0000948 if(encoder->private_->cpuinfo.use_asm) {
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000949# ifdef FLAC__CPU_IA32
Josh Coalsonfa697a92001-08-16 20:07:29 +0000950 FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000951# ifdef FLAC__HAS_NASM
952# ifdef FLAC__SSE_OS
Josh Coalson48cbe662002-12-30 23:38:14 +0000953 if(encoder->private_->cpuinfo.data.ia32.sse) {
Josh Coalsonfa697a92001-08-16 20:07:29 +0000954 if(encoder->protected_->max_lpc_order < 4)
955 encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4;
956 else if(encoder->protected_->max_lpc_order < 8)
957 encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8;
958 else if(encoder->protected_->max_lpc_order < 12)
959 encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12;
Josh Coalson021ad3b2001-07-18 00:25:52 +0000960 else
Josh Coalsonfa697a92001-08-16 20:07:29 +0000961 encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
Josh Coalson021ad3b2001-07-18 00:25:52 +0000962 }
Josh Coalson48cbe662002-12-30 23:38:14 +0000963 else
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000964# endif /* FLAC__SSE_OS */
Josh Coalson48cbe662002-12-30 23:38:14 +0000965 if(encoder->private_->cpuinfo.data.ia32._3dnow)
Josh Coalsonfa697a92001-08-16 20:07:29 +0000966 encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow;
Josh Coalsonaa255362001-05-31 06:17:41 +0000967 else
Josh Coalsonfa697a92001-08-16 20:07:29 +0000968 encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
Josh Coalsonfa697a92001-08-16 20:07:29 +0000969 if(encoder->private_->cpuinfo.data.ia32.mmx) {
970 encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
971 encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx;
Josh Coalson021ad3b2001-07-18 00:25:52 +0000972 }
973 else {
Josh Coalsonfa697a92001-08-16 20:07:29 +0000974 encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
975 encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
Josh Coalson021ad3b2001-07-18 00:25:52 +0000976 }
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000977 if(encoder->private_->cpuinfo.data.ia32.mmx && encoder->private_->cpuinfo.data.ia32.cmov)
978 encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov;
979# endif /* FLAC__HAS_NASM */
980# endif /* FLAC__CPU_IA32 */
Josh Coalson021ad3b2001-07-18 00:25:52 +0000981 }
Josh Coalson5f2b46d2004-11-09 01:34:01 +0000982# endif /* !FLAC__NO_ASM */
983#endif /* !FLAC__INTEGER_ONLY_LIBRARY */
Josh Coalson8395d022001-07-12 21:25:22 +0000984 /* finally override based on wide-ness if necessary */
Josh Coalsonfa697a92001-08-16 20:07:29 +0000985 if(encoder->private_->use_wide_by_block) {
986 encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_wide;
Josh Coalson8395d022001-07-12 21:25:22 +0000987 }
Josh Coalsoncf30f502001-05-23 20:57:44 +0000988
Josh Coalson8395d022001-07-12 21:25:22 +0000989 /* we require precompute_partition_sums if do_escape_coding because of their intertwined nature */
Josh Coalsonfa697a92001-08-16 20:07:29 +0000990 encoder->private_->precompute_partition_sums = (encoder->protected_->max_residual_partition_order > encoder->protected_->min_residual_partition_order) || encoder->protected_->do_escape_coding;
Josh Coalsoneef56702001-03-30 00:45:22 +0000991
Josh Coalson6b21f662006-09-13 01:42:27 +0000992 /* set state to OK; from here on, errors are fatal and we'll override the state then */
993 encoder->protected_->state = FLAC__STREAM_ENCODER_OK;
994
Josh Coalson8da98c82006-10-15 04:24:05 +0000995#if FLAC__HAS_OGG
996 encoder->private_->is_ogg = is_ogg;
997 if(is_ogg && !FLAC__ogg_encoder_aspect_init(&encoder->protected_->ogg_encoder_aspect)) {
998 encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
999 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1000 }
1001#endif
1002
1003 encoder->private_->read_callback = read_callback;
Josh Coalson6b21f662006-09-13 01:42:27 +00001004 encoder->private_->write_callback = write_callback;
1005 encoder->private_->seek_callback = seek_callback;
1006 encoder->private_->tell_callback = tell_callback;
1007 encoder->private_->metadata_callback = metadata_callback;
1008 encoder->private_->client_data = client_data;
1009
Josh Coalsonf1eff452002-07-31 07:05:33 +00001010 if(!resize_buffers_(encoder, encoder->protected_->blocksize)) {
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001011 /* the above function sets the state for us in case of an error */
Josh Coalson6b21f662006-09-13 01:42:27 +00001012 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001013 }
Josh Coalsonaec256b2002-03-12 16:19:54 +00001014
Josh Coalson6b21f662006-09-13 01:42:27 +00001015 if(!FLAC__bitbuffer_init(encoder->private_->frame)) {
1016 encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
1017 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1018 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001019
1020 /*
Josh Coalsond86e03b2002-08-03 21:56:15 +00001021 * Set up the verify stuff if necessary
1022 */
1023 if(encoder->protected_->verify) {
1024 /*
1025 * First, set up the fifo which will hold the
1026 * original signal to compare against
1027 */
Josh Coalson49f2f162006-11-09 16:54:52 +00001028 encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize+OVERREAD_;
Josh Coalsond86e03b2002-08-03 21:56:15 +00001029 for(i = 0; i < encoder->protected_->channels; i++) {
Josh Coalson6b21f662006-09-13 01:42:27 +00001030 if(0 == (encoder->private_->verify.input_fifo.data[i] = (FLAC__int32*)malloc(sizeof(FLAC__int32) * encoder->private_->verify.input_fifo.size))) {
1031 encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
1032 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1033 }
Josh Coalsond86e03b2002-08-03 21:56:15 +00001034 }
1035 encoder->private_->verify.input_fifo.tail = 0;
1036
1037 /*
1038 * Now set up a stream decoder for verification
1039 */
1040 encoder->private_->verify.decoder = FLAC__stream_decoder_new();
Josh Coalson6b21f662006-09-13 01:42:27 +00001041 if(0 == encoder->private_->verify.decoder) {
1042 encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
1043 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1044 }
Josh Coalsond86e03b2002-08-03 21:56:15 +00001045
Josh Coalson6b21f662006-09-13 01:42:27 +00001046 if(FLAC__stream_decoder_init_stream(encoder->private_->verify.decoder, verify_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, verify_write_callback_, verify_metadata_callback_, verify_error_callback_, /*client_data=*/encoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
1047 encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
1048 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1049 }
Josh Coalsond86e03b2002-08-03 21:56:15 +00001050 }
Josh Coalson589f8c72002-08-07 23:54:55 +00001051 encoder->private_->verify.error_stats.absolute_sample = 0;
1052 encoder->private_->verify.error_stats.frame_number = 0;
1053 encoder->private_->verify.error_stats.channel = 0;
1054 encoder->private_->verify.error_stats.sample = 0;
1055 encoder->private_->verify.error_stats.expected = 0;
1056 encoder->private_->verify.error_stats.got = 0;
Josh Coalsond86e03b2002-08-03 21:56:15 +00001057
1058 /*
Josh Coalson6b21f662006-09-13 01:42:27 +00001059 * These must be done before we write any metadata, because that
1060 * calls the write_callback, which uses these values.
1061 */
1062 encoder->private_->first_seekpoint_to_check = 0;
1063 encoder->private_->samples_written = 0;
1064 encoder->protected_->streaminfo_offset = 0;
1065 encoder->protected_->seektable_offset = 0;
1066 encoder->protected_->audio_offset = 0;
1067
1068 /*
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001069 * write the stream header
1070 */
Josh Coalsond86e03b2002-08-03 21:56:15 +00001071 if(encoder->protected_->verify)
1072 encoder->private_->verify.state_hint = ENCODER_IN_MAGIC;
Josh Coalson6b21f662006-09-13 01:42:27 +00001073 if(!FLAC__bitbuffer_write_raw_uint32(encoder->private_->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN)) {
1074 encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
1075 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1076 }
Josh Coalson49f2f162006-11-09 16:54:52 +00001077 if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
Josh Coalsond86e03b2002-08-03 21:56:15 +00001078 /* the above function sets the state for us in case of an error */
Josh Coalson6b21f662006-09-13 01:42:27 +00001079 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
Josh Coalsond86e03b2002-08-03 21:56:15 +00001080 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001081
Josh Coalson5c491a12002-08-01 06:39:40 +00001082 /*
1083 * write the STREAMINFO metadata block
1084 */
Josh Coalsond86e03b2002-08-03 21:56:15 +00001085 if(encoder->protected_->verify)
1086 encoder->private_->verify.state_hint = ENCODER_IN_METADATA;
Josh Coalson6b21f662006-09-13 01:42:27 +00001087 encoder->private_->streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
1088 encoder->private_->streaminfo.is_last = false; /* we will have at a minimum a VORBIS_COMMENT afterwards */
1089 encoder->private_->streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
1090 encoder->private_->streaminfo.data.stream_info.min_blocksize = encoder->protected_->blocksize; /* this encoder uses the same blocksize for the whole stream */
1091 encoder->private_->streaminfo.data.stream_info.max_blocksize = encoder->protected_->blocksize;
1092 encoder->private_->streaminfo.data.stream_info.min_framesize = 0; /* we don't know this yet; have to fill it in later */
1093 encoder->private_->streaminfo.data.stream_info.max_framesize = 0; /* we don't know this yet; have to fill it in later */
1094 encoder->private_->streaminfo.data.stream_info.sample_rate = encoder->protected_->sample_rate;
1095 encoder->private_->streaminfo.data.stream_info.channels = encoder->protected_->channels;
1096 encoder->private_->streaminfo.data.stream_info.bits_per_sample = encoder->protected_->bits_per_sample;
1097 encoder->private_->streaminfo.data.stream_info.total_samples = encoder->protected_->total_samples_estimate; /* we will replace this later with the real total */
1098 memset(encoder->private_->streaminfo.data.stream_info.md5sum, 0, 16); /* we don't know this yet; have to fill it in later */
Josh Coalson3e7a96e2004-07-23 05:18:22 +00001099 FLAC__MD5Init(&encoder->private_->md5context);
Josh Coalson6b21f662006-09-13 01:42:27 +00001100 if(!FLAC__bitbuffer_clear(encoder->private_->frame)) {
1101 encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
1102 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1103 }
1104 if(!FLAC__add_metadata_block(&encoder->private_->streaminfo, encoder->private_->frame)) {
1105 encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
1106 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1107 }
Josh Coalson49f2f162006-11-09 16:54:52 +00001108 if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
Josh Coalsond86e03b2002-08-03 21:56:15 +00001109 /* the above function sets the state for us in case of an error */
Josh Coalson6b21f662006-09-13 01:42:27 +00001110 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
Josh Coalsond86e03b2002-08-03 21:56:15 +00001111 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001112
Josh Coalson5c491a12002-08-01 06:39:40 +00001113 /*
1114 * Now that the STREAMINFO block is written, we can init this to an
1115 * absurdly-high value...
1116 */
Josh Coalson6b21f662006-09-13 01:42:27 +00001117 encoder->private_->streaminfo.data.stream_info.min_framesize = (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN) - 1;
Josh Coalsoncbbbb5f2001-01-23 00:41:48 +00001118 /* ... and clear this to 0 */
Josh Coalson6b21f662006-09-13 01:42:27 +00001119 encoder->private_->streaminfo.data.stream_info.total_samples = 0;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001120
Josh Coalson5c491a12002-08-01 06:39:40 +00001121 /*
Josh Coalsoncb9d93a2002-08-25 05:27:15 +00001122 * Check to see if the supplied metadata contains a VORBIS_COMMENT;
1123 * if not, we will write an empty one (FLAC__add_metadata_block()
1124 * automatically supplies the vendor string).
Josh Coalson69cfda72004-09-10 00:38:21 +00001125 *
Josh Coalson8da98c82006-10-15 04:24:05 +00001126 * WATCHOUT: the Ogg FLAC mapping requires us to write this block after
1127 * the STREAMINFO. (In the case that metadata_has_vorbis_comment is
1128 * true it will have already insured that the metadata list is properly
1129 * ordered.)
Josh Coalsoncb9d93a2002-08-25 05:27:15 +00001130 */
1131 if(!metadata_has_vorbis_comment) {
1132 FLAC__StreamMetadata vorbis_comment;
1133 vorbis_comment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
1134 vorbis_comment.is_last = (encoder->protected_->num_metadata_blocks == 0);
1135 vorbis_comment.length = 4 + 4; /* MAGIC NUMBER */
1136 vorbis_comment.data.vorbis_comment.vendor_string.length = 0;
1137 vorbis_comment.data.vorbis_comment.vendor_string.entry = 0;
1138 vorbis_comment.data.vorbis_comment.num_comments = 0;
1139 vorbis_comment.data.vorbis_comment.comments = 0;
Josh Coalson6b21f662006-09-13 01:42:27 +00001140 if(!FLAC__bitbuffer_clear(encoder->private_->frame)) {
1141 encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
1142 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1143 }
1144 if(!FLAC__add_metadata_block(&vorbis_comment, encoder->private_->frame)) {
1145 encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
1146 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1147 }
Josh Coalson49f2f162006-11-09 16:54:52 +00001148 if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
Josh Coalsoncb9d93a2002-08-25 05:27:15 +00001149 /* the above function sets the state for us in case of an error */
Josh Coalson6b21f662006-09-13 01:42:27 +00001150 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
Josh Coalsoncb9d93a2002-08-25 05:27:15 +00001151 }
1152 }
1153
1154 /*
Josh Coalson5c491a12002-08-01 06:39:40 +00001155 * write the user's metadata blocks
1156 */
1157 for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
1158 encoder->protected_->metadata[i]->is_last = (i == encoder->protected_->num_metadata_blocks - 1);
Josh Coalson6b21f662006-09-13 01:42:27 +00001159 if(!FLAC__bitbuffer_clear(encoder->private_->frame)) {
1160 encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
1161 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1162 }
1163 if(!FLAC__add_metadata_block(encoder->protected_->metadata[i], encoder->private_->frame)) {
1164 encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
1165 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1166 }
Josh Coalson49f2f162006-11-09 16:54:52 +00001167 if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
Josh Coalsond86e03b2002-08-03 21:56:15 +00001168 /* the above function sets the state for us in case of an error */
Josh Coalson6b21f662006-09-13 01:42:27 +00001169 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
Josh Coalsond86e03b2002-08-03 21:56:15 +00001170 }
Josh Coalson5c491a12002-08-01 06:39:40 +00001171 }
1172
Josh Coalson6b21f662006-09-13 01:42:27 +00001173 /* now that all the metadata is written, we save the stream offset */
1174 if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */
1175 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
1176 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1177 }
1178
Josh Coalsond86e03b2002-08-03 21:56:15 +00001179 if(encoder->protected_->verify)
1180 encoder->private_->verify.state_hint = ENCODER_IN_AUDIO;
1181
Josh Coalson6b21f662006-09-13 01:42:27 +00001182 return FLAC__STREAM_ENCODER_INIT_STATUS_OK;
1183}
1184
Josh Coalson8da98c82006-10-15 04:24:05 +00001185FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(
1186 FLAC__StreamEncoder *encoder,
1187 FLAC__StreamEncoderWriteCallback write_callback,
1188 FLAC__StreamEncoderSeekCallback seek_callback,
1189 FLAC__StreamEncoderTellCallback tell_callback,
1190 FLAC__StreamEncoderMetadataCallback metadata_callback,
1191 void *client_data
1192)
1193{
1194 return init_stream_internal_(
1195 encoder,
1196 /*read_callback=*/0,
1197 write_callback,
1198 seek_callback,
1199 tell_callback,
1200 metadata_callback,
1201 client_data,
1202 /*is_ogg=*/false
1203 );
1204}
1205
1206FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream(
1207 FLAC__StreamEncoder *encoder,
1208 FLAC__StreamEncoderReadCallback read_callback,
1209 FLAC__StreamEncoderWriteCallback write_callback,
1210 FLAC__StreamEncoderSeekCallback seek_callback,
1211 FLAC__StreamEncoderTellCallback tell_callback,
1212 FLAC__StreamEncoderMetadataCallback metadata_callback,
1213 void *client_data
1214)
1215{
1216 return init_stream_internal_(
1217 encoder,
1218 read_callback,
1219 write_callback,
1220 seek_callback,
1221 tell_callback,
1222 metadata_callback,
1223 client_data,
1224 /*is_ogg=*/true
1225 );
1226}
1227
1228static FLAC__StreamEncoderInitStatus init_FILE_internal_(
1229 FLAC__StreamEncoder *encoder,
1230 FILE *file,
1231 FLAC__StreamEncoderProgressCallback progress_callback,
1232 void *client_data,
1233 FLAC__bool is_ogg
1234)
Josh Coalson6b21f662006-09-13 01:42:27 +00001235{
1236 FLAC__StreamEncoderInitStatus init_status;
1237
1238 FLAC__ASSERT(0 != encoder);
1239 FLAC__ASSERT(0 != file);
1240
Josh Coalson6b21f662006-09-13 01:42:27 +00001241 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1242 return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
1243
1244 /* double protection */
1245 if(file == 0) {
1246 encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR;
1247 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1248 }
1249
Josh Coalson92f7fa92006-10-09 05:34:21 +00001250 /*
1251 * To make sure that our file does not go unclosed after an error, we
1252 * must assign the FILE pointer before any further error can occur in
1253 * this routine.
1254 */
Josh Coalson6b21f662006-09-13 01:42:27 +00001255 if(file == stdout)
1256 file = get_binary_stdout_(); /* just to be safe */
1257
1258 encoder->private_->file = file;
1259
1260 encoder->private_->progress_callback = progress_callback;
1261 encoder->private_->bytes_written = 0;
1262 encoder->private_->samples_written = 0;
1263 encoder->private_->frames_written = 0;
1264
Josh Coalson8da98c82006-10-15 04:24:05 +00001265 init_status = init_stream_internal_(
1266 encoder,
Josh Coalsoncf1422e2006-11-16 01:32:25 +00001267 encoder->private_->file == stdout? 0 : is_ogg? file_read_callback_ : 0,
Josh Coalson8da98c82006-10-15 04:24:05 +00001268 file_write_callback_,
Josh Coalsoncf1422e2006-11-16 01:32:25 +00001269 encoder->private_->file == stdout? 0 : file_seek_callback_,
1270 encoder->private_->file == stdout? 0 : file_tell_callback_,
Josh Coalson8da98c82006-10-15 04:24:05 +00001271 /*metadata_callback=*/0,
1272 client_data,
1273 is_ogg
1274 );
Josh Coalson6b21f662006-09-13 01:42:27 +00001275 if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
1276 /* the above function sets the state for us in case of an error */
1277 return init_status;
1278 }
1279
1280 {
1281 unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder);
1282
1283 FLAC__ASSERT(blocksize != 0);
1284 encoder->private_->total_frames_estimate = (unsigned)((FLAC__stream_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize);
1285 }
1286
1287 return init_status;
1288}
Josh Coalson8da98c82006-10-15 04:24:05 +00001289
1290FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(
1291 FLAC__StreamEncoder *encoder,
1292 FILE *file,
1293 FLAC__StreamEncoderProgressCallback progress_callback,
1294 void *client_data
1295)
1296{
1297 return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/false);
1298}
1299
1300FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(
1301 FLAC__StreamEncoder *encoder,
1302 FILE *file,
1303 FLAC__StreamEncoderProgressCallback progress_callback,
1304 void *client_data
1305)
1306{
1307 return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/true);
1308}
Josh Coalson6b21f662006-09-13 01:42:27 +00001309
Josh Coalson8da98c82006-10-15 04:24:05 +00001310static FLAC__StreamEncoderInitStatus init_file_internal_(
1311 FLAC__StreamEncoder *encoder,
1312 const char *filename,
1313 FLAC__StreamEncoderProgressCallback progress_callback,
1314 void *client_data,
1315 FLAC__bool is_ogg
1316)
Josh Coalson6b21f662006-09-13 01:42:27 +00001317{
1318 FILE *file;
1319
1320 FLAC__ASSERT(0 != encoder);
1321
1322 /*
1323 * To make sure that our file does not go unclosed after an error, we
1324 * have to do the same entrance checks here that are later performed
1325 * in FLAC__stream_encoder_init_FILE() before the FILE* is assigned.
1326 */
1327 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1328 return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
1329
1330 file = filename? fopen(filename, "w+b") : stdout;
1331
1332 if(file == 0) {
1333 encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR;
1334 return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
1335 }
1336
Josh Coalson8da98c82006-10-15 04:24:05 +00001337 return init_FILE_internal_(encoder, file, progress_callback, client_data, is_ogg);
1338}
1339
1340FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(
1341 FLAC__StreamEncoder *encoder,
1342 const char *filename,
1343 FLAC__StreamEncoderProgressCallback progress_callback,
1344 void *client_data
1345)
1346{
1347 return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/false);
1348}
1349
1350FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file(
1351 FLAC__StreamEncoder *encoder,
1352 const char *filename,
1353 FLAC__StreamEncoderProgressCallback progress_callback,
1354 void *client_data
1355)
1356{
1357 return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/true);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001358}
1359
Josh Coalsona5862262006-11-09 06:58:26 +00001360FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001361{
Josh Coalsoncf1422e2006-11-16 01:32:25 +00001362 FLAC__bool error = false;
Josh Coalsona5862262006-11-09 06:58:26 +00001363
Josh Coalsonf1eff452002-07-31 07:05:33 +00001364 FLAC__ASSERT(0 != encoder);
Josh Coalson6b21f662006-09-13 01:42:27 +00001365 FLAC__ASSERT(0 != encoder->private_);
1366 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalson2b245f22002-08-07 17:10:50 +00001367
Josh Coalsonfa697a92001-08-16 20:07:29 +00001368 if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalsona5862262006-11-09 06:58:26 +00001369 return true;
Josh Coalson2b245f22002-08-07 17:10:50 +00001370
Josh Coalson3262b0d2002-08-14 20:58:42 +00001371 if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) {
Josh Coalson2b245f22002-08-07 17:10:50 +00001372 if(encoder->private_->current_sample_number != 0) {
Josh Coalson49f2f162006-11-09 16:54:52 +00001373 const FLAC__bool is_fractional_block = encoder->protected_->blocksize != encoder->private_->current_sample_number;
Josh Coalson2b245f22002-08-07 17:10:50 +00001374 encoder->protected_->blocksize = encoder->private_->current_sample_number;
Josh Coalsoncf1422e2006-11-16 01:32:25 +00001375 if(!process_frame_(encoder, is_fractional_block, /*is_last_block=*/true))
1376 error = true;
Josh Coalson2b245f22002-08-07 17:10:50 +00001377 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001378 }
Josh Coalson2b245f22002-08-07 17:10:50 +00001379
Josh Coalson6b21f662006-09-13 01:42:27 +00001380 FLAC__MD5Final(encoder->private_->streaminfo.data.stream_info.md5sum, &encoder->private_->md5context);
Josh Coalson2b245f22002-08-07 17:10:50 +00001381
Josh Coalsoncf1422e2006-11-16 01:32:25 +00001382 if(!encoder->private_->is_being_deleted) {
1383 if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK) {
1384 if(encoder->private_->seek_callback) {
Josh Coalson8da98c82006-10-15 04:24:05 +00001385#if FLAC__HAS_OGG
Josh Coalsoncf1422e2006-11-16 01:32:25 +00001386 if(encoder->private_->is_ogg)
1387 update_ogg_metadata_(encoder);
1388 else
Josh Coalson8da98c82006-10-15 04:24:05 +00001389#endif
Josh Coalsoncf1422e2006-11-16 01:32:25 +00001390 update_metadata_(encoder);
Josh Coalson0a15c142001-06-13 17:59:57 +00001391
Josh Coalsoncf1422e2006-11-16 01:32:25 +00001392 /* check if an error occurred while updating metadata */
1393 if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK)
1394 error = true;
1395 }
1396 if(encoder->private_->metadata_callback)
1397 encoder->private_->metadata_callback(encoder, &encoder->private_->streaminfo, encoder->private_->client_data);
1398 }
1399
1400 if(encoder->protected_->verify && 0 != encoder->private_->verify.decoder && !FLAC__stream_decoder_finish(encoder->private_->verify.decoder)) {
1401 if(!error)
1402 encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA;
1403 error = true;
1404 }
1405 }
Josh Coalsond86e03b2002-08-03 21:56:15 +00001406
Josh Coalson6b21f662006-09-13 01:42:27 +00001407 if(0 != encoder->private_->file) {
1408 if(encoder->private_->file != stdout)
1409 fclose(encoder->private_->file);
1410 encoder->private_->file = 0;
1411 }
1412
Josh Coalson8da98c82006-10-15 04:24:05 +00001413#if FLAC__HAS_OGG
1414 if(encoder->private_->is_ogg)
1415 FLAC__ogg_encoder_aspect_finish(&encoder->protected_->ogg_encoder_aspect);
1416#endif
1417
Josh Coalsonf1eff452002-07-31 07:05:33 +00001418 free_(encoder);
1419 set_defaults_(encoder);
Josh Coalson92031602002-07-24 06:02:11 +00001420
Josh Coalsoncf1422e2006-11-16 01:32:25 +00001421 if(!error)
Josh Coalsona5862262006-11-09 06:58:26 +00001422 encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
1423
Josh Coalsoncf1422e2006-11-16 01:32:25 +00001424 return !error;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001425}
1426
Josh Coalson71d5c252006-10-15 06:04:55 +00001427FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long value)
Josh Coalson8da98c82006-10-15 04:24:05 +00001428{
1429 FLAC__ASSERT(0 != encoder);
1430 FLAC__ASSERT(0 != encoder->private_);
1431 FLAC__ASSERT(0 != encoder->protected_);
1432 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1433 return false;
Josh Coalsonf1ac7d92006-11-16 07:20:09 +00001434#if FLAC__HAS_OGG
Josh Coalson8da98c82006-10-15 04:24:05 +00001435 /* can't check encoder->private_->is_ogg since that's not set until init time */
1436 FLAC__ogg_encoder_aspect_set_serial_number(&encoder->protected_->ogg_encoder_aspect, value);
1437 return true;
1438#else
1439 (void)value;
1440 return false;
1441#endif
1442}
1443
Josh Coalson6afed9f2002-10-16 22:29:47 +00001444FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value)
Josh Coalsond86e03b2002-08-03 21:56:15 +00001445{
1446 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001447 FLAC__ASSERT(0 != encoder->private_);
1448 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsond86e03b2002-08-03 21:56:15 +00001449 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1450 return false;
Josh Coalson47c7b142005-01-29 06:08:58 +00001451#ifndef FLAC__MANDATORY_VERIFY_WHILE_ENCODING
Josh Coalsond86e03b2002-08-03 21:56:15 +00001452 encoder->protected_->verify = value;
Josh Coalson47c7b142005-01-29 06:08:58 +00001453#endif
Josh Coalsond86e03b2002-08-03 21:56:15 +00001454 return true;
1455}
1456
Josh Coalson6afed9f2002-10-16 22:29:47 +00001457FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value)
Josh Coalson00e53872001-06-16 07:32:25 +00001458{
Josh Coalson92031602002-07-24 06:02:11 +00001459 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001460 FLAC__ASSERT(0 != encoder->private_);
1461 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001462 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001463 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001464 encoder->protected_->streamable_subset = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001465 return true;
1466}
1467
Josh Coalson6afed9f2002-10-16 22:29:47 +00001468FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value)
Josh Coalson00e53872001-06-16 07:32:25 +00001469{
Josh Coalson92031602002-07-24 06:02:11 +00001470 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001471 FLAC__ASSERT(0 != encoder->private_);
1472 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001473 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001474 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001475 encoder->protected_->channels = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001476 return true;
1477}
1478
Josh Coalson6afed9f2002-10-16 22:29:47 +00001479FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value)
Josh Coalson00e53872001-06-16 07:32:25 +00001480{
Josh Coalson92031602002-07-24 06:02:11 +00001481 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001482 FLAC__ASSERT(0 != encoder->private_);
1483 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001484 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001485 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001486 encoder->protected_->bits_per_sample = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001487 return true;
1488}
1489
Josh Coalson6afed9f2002-10-16 22:29:47 +00001490FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value)
Josh Coalson00e53872001-06-16 07:32:25 +00001491{
Josh Coalson92031602002-07-24 06:02:11 +00001492 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001493 FLAC__ASSERT(0 != encoder->private_);
1494 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001495 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001496 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001497 encoder->protected_->sample_rate = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001498 return true;
1499}
1500
Josh Coalson425609c2006-11-03 16:08:52 +00001501FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value)
1502{
1503 FLAC__bool ok = true;
1504 FLAC__ASSERT(0 != encoder);
1505 FLAC__ASSERT(0 != encoder->private_);
1506 FLAC__ASSERT(0 != encoder->protected_);
1507 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1508 return false;
1509 if(value >= sizeof(compression_levels_)/sizeof(compression_levels_[0]))
1510 value = sizeof(compression_levels_)/sizeof(compression_levels_[0]) - 1;
1511 ok &= FLAC__stream_encoder_set_do_mid_side_stereo (encoder, compression_levels_[value].do_mid_side_stereo);
1512 ok &= FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, compression_levels_[value].loose_mid_side_stereo);
Josh Coalson4e8fe852006-12-05 01:36:46 +00001513#if 0
1514 /* was: */
Josh Coalson425609c2006-11-03 16:08:52 +00001515 ok &= FLAC__stream_encoder_set_apodization (encoder, compression_levels_[value].apodization);
Josh Coalson4e8fe852006-12-05 01:36:46 +00001516 /* but it's too hard to specify the string in a locale-specific way */
1517#else
1518 encoder->protected_->num_apodizations = 1;
1519 encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
1520 encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
1521#endif
Josh Coalson425609c2006-11-03 16:08:52 +00001522 ok &= FLAC__stream_encoder_set_max_lpc_order (encoder, compression_levels_[value].max_lpc_order);
1523 ok &= FLAC__stream_encoder_set_qlp_coeff_precision (encoder, compression_levels_[value].qlp_coeff_precision);
1524 ok &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search (encoder, compression_levels_[value].do_qlp_coeff_prec_search);
1525 ok &= FLAC__stream_encoder_set_do_escape_coding (encoder, compression_levels_[value].do_escape_coding);
1526 ok &= FLAC__stream_encoder_set_do_exhaustive_model_search (encoder, compression_levels_[value].do_exhaustive_model_search);
1527 ok &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, compression_levels_[value].min_residual_partition_order);
1528 ok &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, compression_levels_[value].max_residual_partition_order);
1529 ok &= FLAC__stream_encoder_set_rice_parameter_search_dist (encoder, compression_levels_[value].rice_parameter_search_dist);
1530 return ok;
1531}
1532
Josh Coalson6afed9f2002-10-16 22:29:47 +00001533FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value)
Josh Coalson00e53872001-06-16 07:32:25 +00001534{
Josh Coalson92031602002-07-24 06:02:11 +00001535 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001536 FLAC__ASSERT(0 != encoder->private_);
1537 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001538 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001539 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001540 encoder->protected_->blocksize = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001541 return true;
1542}
1543
Josh Coalson425609c2006-11-03 16:08:52 +00001544FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
1545{
1546 FLAC__ASSERT(0 != encoder);
1547 FLAC__ASSERT(0 != encoder->private_);
1548 FLAC__ASSERT(0 != encoder->protected_);
1549 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1550 return false;
1551 encoder->protected_->do_mid_side_stereo = value;
1552 return true;
1553}
1554
1555FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
1556{
1557 FLAC__ASSERT(0 != encoder);
1558 FLAC__ASSERT(0 != encoder->private_);
1559 FLAC__ASSERT(0 != encoder->protected_);
1560 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1561 return false;
1562 encoder->protected_->loose_mid_side_stereo = value;
1563 return true;
1564}
1565
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00001566FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification)
1567{
1568 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001569 FLAC__ASSERT(0 != encoder->private_);
1570 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00001571 FLAC__ASSERT(0 != specification);
1572 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1573 return false;
1574#ifdef FLAC__INTEGER_ONLY_LIBRARY
1575 (void)specification; /* silently ignore since we haven't integerized; will always use a rectangular window */
1576#else
1577 encoder->protected_->num_apodizations = 0;
1578 while(1) {
1579 const char *s = strchr(specification, ';');
1580 const size_t n = s? (size_t)(s - specification) : strlen(specification);
1581 if (n==8 && 0 == strncmp("bartlett" , specification, n))
1582 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT;
1583 else if(n==13 && 0 == strncmp("bartlett_hann", specification, n))
1584 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT_HANN;
1585 else if(n==8 && 0 == strncmp("blackman" , specification, n))
1586 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN;
1587 else if(n==26 && 0 == strncmp("blackman_harris_4term_92db", specification, n))
1588 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE;
1589 else if(n==6 && 0 == strncmp("connes" , specification, n))
1590 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_CONNES;
1591 else if(n==7 && 0 == strncmp("flattop" , specification, n))
1592 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_FLATTOP;
1593 else if(n>7 && 0 == strncmp("gauss(" , specification, 6)) {
1594 FLAC__real stddev = (FLAC__real)strtod(specification+6, 0);
1595 if (stddev > 0.0 && stddev <= 0.5) {
1596 encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.gauss.stddev = stddev;
1597 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_GAUSS;
1598 }
1599 }
1600 else if(n==7 && 0 == strncmp("hamming" , specification, n))
1601 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HAMMING;
1602 else if(n==4 && 0 == strncmp("hann" , specification, n))
1603 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HANN;
1604 else if(n==13 && 0 == strncmp("kaiser_bessel", specification, n))
1605 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_KAISER_BESSEL;
1606 else if(n==7 && 0 == strncmp("nuttall" , specification, n))
1607 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_NUTTALL;
1608 else if(n==9 && 0 == strncmp("rectangle" , specification, n))
1609 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_RECTANGLE;
1610 else if(n==8 && 0 == strncmp("triangle" , specification, n))
1611 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TRIANGLE;
1612 else if(n>7 && 0 == strncmp("tukey(" , specification, 6)) {
1613 FLAC__real p = (FLAC__real)strtod(specification+6, 0);
1614 if (p >= 0.0 && p <= 1.0) {
1615 encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = p;
1616 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
1617 }
1618 }
1619 else if(n==5 && 0 == strncmp("welch" , specification, n))
1620 encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_WELCH;
1621 if (encoder->protected_->num_apodizations == 32)
1622 break;
1623 if (s)
1624 specification = s+1;
1625 else
1626 break;
1627 }
1628 if(encoder->protected_->num_apodizations == 0) {
1629 encoder->protected_->num_apodizations = 1;
Josh Coalson82389362006-05-01 05:58:35 +00001630 encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
1631 encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00001632 }
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00001633#endif
1634 return true;
1635}
1636
Josh Coalson6afed9f2002-10-16 22:29:47 +00001637FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value)
Josh Coalson00e53872001-06-16 07:32:25 +00001638{
Josh Coalson92031602002-07-24 06:02:11 +00001639 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001640 FLAC__ASSERT(0 != encoder->private_);
1641 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001642 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001643 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001644 encoder->protected_->max_lpc_order = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001645 return true;
1646}
1647
Josh Coalson6afed9f2002-10-16 22:29:47 +00001648FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value)
Josh Coalson00e53872001-06-16 07:32:25 +00001649{
Josh Coalson92031602002-07-24 06:02:11 +00001650 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001651 FLAC__ASSERT(0 != encoder->private_);
1652 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001653 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001654 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001655 encoder->protected_->qlp_coeff_precision = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001656 return true;
1657}
1658
Josh Coalson6afed9f2002-10-16 22:29:47 +00001659FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
Josh Coalson00e53872001-06-16 07:32:25 +00001660{
Josh Coalson92031602002-07-24 06:02:11 +00001661 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001662 FLAC__ASSERT(0 != encoder->private_);
1663 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001664 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001665 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001666 encoder->protected_->do_qlp_coeff_prec_search = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001667 return true;
1668}
1669
Josh Coalson6afed9f2002-10-16 22:29:47 +00001670FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value)
Josh Coalson8395d022001-07-12 21:25:22 +00001671{
Josh Coalson92031602002-07-24 06:02:11 +00001672 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001673 FLAC__ASSERT(0 != encoder->private_);
1674 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001675 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson8395d022001-07-12 21:25:22 +00001676 return false;
Josh Coalson680e3aa2002-08-01 07:32:17 +00001677#if 0
1678 /*@@@ deprecated: */
Josh Coalsonfa697a92001-08-16 20:07:29 +00001679 encoder->protected_->do_escape_coding = value;
Josh Coalson680e3aa2002-08-01 07:32:17 +00001680#else
1681 (void)value;
1682#endif
Josh Coalson8395d022001-07-12 21:25:22 +00001683 return true;
1684}
1685
Josh Coalson6afed9f2002-10-16 22:29:47 +00001686FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
Josh Coalson00e53872001-06-16 07:32:25 +00001687{
Josh Coalson92031602002-07-24 06:02:11 +00001688 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001689 FLAC__ASSERT(0 != encoder->private_);
1690 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001691 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001692 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001693 encoder->protected_->do_exhaustive_model_search = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001694 return true;
1695}
1696
Josh Coalson6afed9f2002-10-16 22:29:47 +00001697FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value)
Josh Coalson00e53872001-06-16 07:32:25 +00001698{
Josh Coalson92031602002-07-24 06:02:11 +00001699 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001700 FLAC__ASSERT(0 != encoder->private_);
1701 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001702 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001703 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001704 encoder->protected_->min_residual_partition_order = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001705 return true;
1706}
1707
Josh Coalson6afed9f2002-10-16 22:29:47 +00001708FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value)
Josh Coalson00e53872001-06-16 07:32:25 +00001709{
Josh Coalson92031602002-07-24 06:02:11 +00001710 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001711 FLAC__ASSERT(0 != encoder->private_);
1712 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001713 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001714 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001715 encoder->protected_->max_residual_partition_order = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001716 return true;
1717}
1718
Josh Coalson6afed9f2002-10-16 22:29:47 +00001719FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value)
Josh Coalson00e53872001-06-16 07:32:25 +00001720{
Josh Coalson92031602002-07-24 06:02:11 +00001721 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001722 FLAC__ASSERT(0 != encoder->private_);
1723 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001724 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001725 return false;
Josh Coalson680e3aa2002-08-01 07:32:17 +00001726#if 0
1727 /*@@@ deprecated: */
Josh Coalsonfa697a92001-08-16 20:07:29 +00001728 encoder->protected_->rice_parameter_search_dist = value;
Josh Coalson680e3aa2002-08-01 07:32:17 +00001729#else
1730 (void)value;
1731#endif
Josh Coalson00e53872001-06-16 07:32:25 +00001732 return true;
1733}
1734
Josh Coalson6afed9f2002-10-16 22:29:47 +00001735FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value)
Josh Coalson00e53872001-06-16 07:32:25 +00001736{
Josh Coalson92031602002-07-24 06:02:11 +00001737 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001738 FLAC__ASSERT(0 != encoder->private_);
1739 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001740 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001741 return false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001742 encoder->protected_->total_samples_estimate = value;
Josh Coalson00e53872001-06-16 07:32:25 +00001743 return true;
1744}
1745
Josh Coalson6afed9f2002-10-16 22:29:47 +00001746FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
Josh Coalson00e53872001-06-16 07:32:25 +00001747{
Josh Coalson92031602002-07-24 06:02:11 +00001748 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001749 FLAC__ASSERT(0 != encoder->private_);
1750 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001751 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
Josh Coalson00e53872001-06-16 07:32:25 +00001752 return false;
Josh Coalson66075c12002-06-01 05:39:38 +00001753 encoder->protected_->metadata = metadata;
1754 encoder->protected_->num_metadata_blocks = num_blocks;
Josh Coalson8da98c82006-10-15 04:24:05 +00001755#if FLAC__HAS_OGG
1756 if(!FLAC__ogg_encoder_aspect_set_num_metadata(&encoder->protected_->ogg_encoder_aspect, num_blocks))
1757 return false;
1758#endif
Josh Coalson00e53872001-06-16 07:32:25 +00001759 return true;
1760}
1761
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00001762/*
1763 * These three functions are not static, but not publically exposed in
1764 * include/FLAC/ either. They are used by the test suite.
1765 */
Josh Coalson6afed9f2002-10-16 22:29:47 +00001766FLAC_API FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00001767{
1768 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001769 FLAC__ASSERT(0 != encoder->private_);
1770 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00001771 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1772 return false;
1773 encoder->private_->disable_constant_subframes = value;
1774 return true;
1775}
1776
Josh Coalson6afed9f2002-10-16 22:29:47 +00001777FLAC_API FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00001778{
1779 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001780 FLAC__ASSERT(0 != encoder->private_);
1781 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00001782 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1783 return false;
1784 encoder->private_->disable_fixed_subframes = value;
1785 return true;
1786}
1787
Josh Coalson6afed9f2002-10-16 22:29:47 +00001788FLAC_API FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value)
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00001789{
1790 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001791 FLAC__ASSERT(0 != encoder->private_);
1792 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00001793 if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
1794 return false;
1795 encoder->private_->disable_verbatim_subframes = value;
1796 return true;
1797}
1798
Josh Coalson6afed9f2002-10-16 22:29:47 +00001799FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001800{
Josh Coalson92031602002-07-24 06:02:11 +00001801 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001802 FLAC__ASSERT(0 != encoder->private_);
1803 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001804 return encoder->protected_->state;
Josh Coalson0a15c142001-06-13 17:59:57 +00001805}
1806
Josh Coalson6afed9f2002-10-16 22:29:47 +00001807FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder)
Josh Coalsond86e03b2002-08-03 21:56:15 +00001808{
1809 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001810 FLAC__ASSERT(0 != encoder->private_);
1811 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsond86e03b2002-08-03 21:56:15 +00001812 if(encoder->protected_->verify)
1813 return FLAC__stream_decoder_get_state(encoder->private_->verify.decoder);
1814 else
1815 return FLAC__STREAM_DECODER_UNINITIALIZED;
1816}
1817
Josh Coalson02954222002-11-08 06:16:31 +00001818FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder)
1819{
Josh Coalson8da98c82006-10-15 04:24:05 +00001820 FLAC__ASSERT(0 != encoder);
1821 FLAC__ASSERT(0 != encoder->private_);
1822 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalson02954222002-11-08 06:16:31 +00001823 if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR)
1824 return FLAC__StreamEncoderStateString[encoder->protected_->state];
1825 else
Josh Coalson807140d2003-09-24 22:10:51 +00001826 return FLAC__stream_decoder_get_resolved_state_string(encoder->private_->verify.decoder);
Josh Coalson02954222002-11-08 06:16:31 +00001827}
1828
Josh Coalson6afed9f2002-10-16 22:29:47 +00001829FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
Josh Coalson589f8c72002-08-07 23:54:55 +00001830{
1831 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001832 FLAC__ASSERT(0 != encoder->private_);
1833 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalson589f8c72002-08-07 23:54:55 +00001834 if(0 != absolute_sample)
1835 *absolute_sample = encoder->private_->verify.error_stats.absolute_sample;
1836 if(0 != frame_number)
1837 *frame_number = encoder->private_->verify.error_stats.frame_number;
1838 if(0 != channel)
1839 *channel = encoder->private_->verify.error_stats.channel;
1840 if(0 != sample)
1841 *sample = encoder->private_->verify.error_stats.sample;
1842 if(0 != expected)
1843 *expected = encoder->private_->verify.error_stats.expected;
1844 if(0 != got)
1845 *got = encoder->private_->verify.error_stats.got;
1846}
1847
Josh Coalson6afed9f2002-10-16 22:29:47 +00001848FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder)
Josh Coalsond86e03b2002-08-03 21:56:15 +00001849{
1850 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001851 FLAC__ASSERT(0 != encoder->private_);
1852 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsond86e03b2002-08-03 21:56:15 +00001853 return encoder->protected_->verify;
1854}
1855
Josh Coalson6afed9f2002-10-16 22:29:47 +00001856FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001857{
Josh Coalson92031602002-07-24 06:02:11 +00001858 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001859 FLAC__ASSERT(0 != encoder->private_);
1860 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001861 return encoder->protected_->streamable_subset;
Josh Coalson0a15c142001-06-13 17:59:57 +00001862}
1863
Josh Coalson6afed9f2002-10-16 22:29:47 +00001864FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001865{
Josh Coalson92031602002-07-24 06:02:11 +00001866 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001867 FLAC__ASSERT(0 != encoder->private_);
1868 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001869 return encoder->protected_->channels;
Josh Coalson0a15c142001-06-13 17:59:57 +00001870}
1871
Josh Coalson6afed9f2002-10-16 22:29:47 +00001872FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001873{
Josh Coalson92031602002-07-24 06:02:11 +00001874 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001875 FLAC__ASSERT(0 != encoder->private_);
1876 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001877 return encoder->protected_->bits_per_sample;
Josh Coalson0a15c142001-06-13 17:59:57 +00001878}
1879
Josh Coalson6afed9f2002-10-16 22:29:47 +00001880FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001881{
Josh Coalson92031602002-07-24 06:02:11 +00001882 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001883 FLAC__ASSERT(0 != encoder->private_);
1884 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001885 return encoder->protected_->sample_rate;
Josh Coalson0a15c142001-06-13 17:59:57 +00001886}
1887
Josh Coalson6afed9f2002-10-16 22:29:47 +00001888FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001889{
Josh Coalson92031602002-07-24 06:02:11 +00001890 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001891 FLAC__ASSERT(0 != encoder->private_);
1892 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001893 return encoder->protected_->blocksize;
Josh Coalson0a15c142001-06-13 17:59:57 +00001894}
1895
Josh Coalson425609c2006-11-03 16:08:52 +00001896FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder)
1897{
1898 FLAC__ASSERT(0 != encoder);
1899 FLAC__ASSERT(0 != encoder->private_);
1900 FLAC__ASSERT(0 != encoder->protected_);
1901 return encoder->protected_->do_mid_side_stereo;
1902}
1903
1904FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder)
1905{
1906 FLAC__ASSERT(0 != encoder);
1907 FLAC__ASSERT(0 != encoder->private_);
1908 FLAC__ASSERT(0 != encoder->protected_);
1909 return encoder->protected_->loose_mid_side_stereo;
1910}
1911
Josh Coalson6afed9f2002-10-16 22:29:47 +00001912FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001913{
Josh Coalson92031602002-07-24 06:02:11 +00001914 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001915 FLAC__ASSERT(0 != encoder->private_);
1916 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001917 return encoder->protected_->max_lpc_order;
Josh Coalson0a15c142001-06-13 17:59:57 +00001918}
1919
Josh Coalson6afed9f2002-10-16 22:29:47 +00001920FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001921{
Josh Coalson92031602002-07-24 06:02:11 +00001922 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001923 FLAC__ASSERT(0 != encoder->private_);
1924 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001925 return encoder->protected_->qlp_coeff_precision;
Josh Coalson0a15c142001-06-13 17:59:57 +00001926}
1927
Josh Coalson6afed9f2002-10-16 22:29:47 +00001928FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001929{
Josh Coalson92031602002-07-24 06:02:11 +00001930 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001931 FLAC__ASSERT(0 != encoder->private_);
1932 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001933 return encoder->protected_->do_qlp_coeff_prec_search;
Josh Coalson0a15c142001-06-13 17:59:57 +00001934}
1935
Josh Coalson6afed9f2002-10-16 22:29:47 +00001936FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder)
Josh Coalson8395d022001-07-12 21:25:22 +00001937{
Josh Coalson92031602002-07-24 06:02:11 +00001938 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001939 FLAC__ASSERT(0 != encoder->private_);
1940 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001941 return encoder->protected_->do_escape_coding;
Josh Coalson8395d022001-07-12 21:25:22 +00001942}
1943
Josh Coalson6afed9f2002-10-16 22:29:47 +00001944FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001945{
Josh Coalson92031602002-07-24 06:02:11 +00001946 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001947 FLAC__ASSERT(0 != encoder->private_);
1948 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001949 return encoder->protected_->do_exhaustive_model_search;
Josh Coalson0a15c142001-06-13 17:59:57 +00001950}
1951
Josh Coalson6afed9f2002-10-16 22:29:47 +00001952FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001953{
Josh Coalson92031602002-07-24 06:02:11 +00001954 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001955 FLAC__ASSERT(0 != encoder->private_);
1956 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001957 return encoder->protected_->min_residual_partition_order;
Josh Coalson0a15c142001-06-13 17:59:57 +00001958}
1959
Josh Coalson6afed9f2002-10-16 22:29:47 +00001960FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001961{
Josh Coalson92031602002-07-24 06:02:11 +00001962 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001963 FLAC__ASSERT(0 != encoder->private_);
1964 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001965 return encoder->protected_->max_residual_partition_order;
Josh Coalson0a15c142001-06-13 17:59:57 +00001966}
1967
Josh Coalson6afed9f2002-10-16 22:29:47 +00001968FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder)
Josh Coalson0a15c142001-06-13 17:59:57 +00001969{
Josh Coalson92031602002-07-24 06:02:11 +00001970 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001971 FLAC__ASSERT(0 != encoder->private_);
1972 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001973 return encoder->protected_->rice_parameter_search_dist;
Josh Coalson0a15c142001-06-13 17:59:57 +00001974}
1975
Josh Coalson6afed9f2002-10-16 22:29:47 +00001976FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder)
Josh Coalson3a7b2c92002-08-02 07:38:20 +00001977{
1978 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001979 FLAC__ASSERT(0 != encoder->private_);
1980 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalson3a7b2c92002-08-02 07:38:20 +00001981 return encoder->protected_->total_samples_estimate;
1982}
1983
Josh Coalson6afed9f2002-10-16 22:29:47 +00001984FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001985{
1986 unsigned i, j, channel;
Josh Coalson77e3f312001-06-23 03:03:24 +00001987 FLAC__int32 x, mid, side;
Josh Coalsonfa697a92001-08-16 20:07:29 +00001988 const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001989
Josh Coalsonf1eff452002-07-31 07:05:33 +00001990 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00001991 FLAC__ASSERT(0 != encoder->private_);
1992 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00001993 FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00001994
1995 j = 0;
Josh Coalsonc549f0f2004-12-30 03:47:49 +00001996 /*
1997 * we have several flavors of the same basic loop, optimized for
1998 * different conditions:
1999 */
2000 if(encoder->protected_->max_lpc_order > 0) {
2001 if(encoder->protected_->do_mid_side_stereo && channels == 2) {
2002 /*
2003 * stereo coding: unroll channel loop
2004 * with LPC: calculate floating point version of signal
2005 */
2006 do {
2007 if(encoder->protected_->verify)
Josh Coalson49f2f162006-11-09 16:54:52 +00002008 append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+1-encoder->private_->current_sample_number, samples-j));
Josh Coalsond86e03b2002-08-03 21:56:15 +00002009
Josh Coalson49f2f162006-11-09 16:54:52 +00002010 /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
2011 for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002012 x = mid = side = buffer[0][j];
2013 encoder->private_->integer_signal[0][i] = x;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002014#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002015 encoder->private_->real_signal[0][i] = (FLAC__real)x;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002016#endif
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002017 x = buffer[1][j];
2018 encoder->private_->integer_signal[1][i] = x;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002019#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002020 encoder->private_->real_signal[1][i] = (FLAC__real)x;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002021#endif
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002022 mid += x;
2023 side -= x;
2024 mid >>= 1; /* NOTE: not the same as 'mid = (buffer[0][j] + buffer[1][j]) / 2' ! */
2025 encoder->private_->integer_signal_mid_side[1][i] = side;
2026 encoder->private_->integer_signal_mid_side[0][i] = mid;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002027#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002028 encoder->private_->real_signal_mid_side[1][i] = (FLAC__real)side;
2029 encoder->private_->real_signal_mid_side[0][i] = (FLAC__real)mid;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002030#endif
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002031 encoder->private_->current_sample_number++;
2032 }
Josh Coalson49f2f162006-11-09 16:54:52 +00002033 /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
2034 if(i > blocksize) {
2035 if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002036 return false;
Josh Coalson49f2f162006-11-09 16:54:52 +00002037 /* move unprocessed overread samples to beginnings of arrays */
2038 FLAC__ASSERT(i == blocksize+OVERREAD_);
2039 FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
2040 i--;
2041 encoder->private_->integer_signal[0][0] = encoder->private_->integer_signal[0][i];
2042 encoder->private_->integer_signal[1][0] = encoder->private_->integer_signal[1][i];
2043 encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][i];
2044 encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][i];
2045#ifndef FLAC__INTEGER_ONLY_LIBRARY
2046 encoder->private_->real_signal[0][0] = encoder->private_->real_signal[0][i];
2047 encoder->private_->real_signal[1][0] = encoder->private_->real_signal[1][i];
2048 encoder->private_->real_signal_mid_side[0][0] = encoder->private_->real_signal_mid_side[0][i];
2049 encoder->private_->real_signal_mid_side[1][0] = encoder->private_->real_signal_mid_side[1][i];
2050#endif
2051 encoder->private_->current_sample_number = 1;
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002052 }
2053 } while(j < samples);
2054 }
2055 else {
2056 /*
2057 * independent channel coding: buffer each channel in inner loop
2058 * with LPC: calculate floating point version of signal
2059 */
2060 do {
2061 if(encoder->protected_->verify)
Josh Coalson49f2f162006-11-09 16:54:52 +00002062 append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+1-encoder->private_->current_sample_number, samples-j));
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002063
Josh Coalson49f2f162006-11-09 16:54:52 +00002064 /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
2065 for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002066 for(channel = 0; channel < channels; channel++) {
2067 x = buffer[channel][j];
2068 encoder->private_->integer_signal[channel][i] = x;
2069#ifndef FLAC__INTEGER_ONLY_LIBRARY
2070 encoder->private_->real_signal[channel][i] = (FLAC__real)x;
2071#endif
2072 }
2073 encoder->private_->current_sample_number++;
2074 }
Josh Coalson49f2f162006-11-09 16:54:52 +00002075 /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
2076 if(i > blocksize) {
2077 if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002078 return false;
Josh Coalson49f2f162006-11-09 16:54:52 +00002079 /* move unprocessed overread samples to beginnings of arrays */
2080 FLAC__ASSERT(i == blocksize+OVERREAD_);
2081 FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
2082 i--;
2083 for(channel = 0; channel < channels; channel++) {
2084 encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][i];
2085#ifndef FLAC__INTEGER_ONLY_LIBRARY
2086 encoder->private_->real_signal[channel][0] = encoder->private_->real_signal[channel][i];
2087#endif
2088 }
2089 encoder->private_->current_sample_number = 1;
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002090 }
2091 } while(j < samples);
2092 }
Josh Coalsonaa255362001-05-31 06:17:41 +00002093 }
2094 else {
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002095 if(encoder->protected_->do_mid_side_stereo && channels == 2) {
2096 /*
2097 * stereo coding: unroll channel loop
2098 * without LPC: no need to calculate floating point version of signal
2099 */
2100 do {
2101 if(encoder->protected_->verify)
Josh Coalson49f2f162006-11-09 16:54:52 +00002102 append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+1-encoder->private_->current_sample_number, samples-j));
Josh Coalsond86e03b2002-08-03 21:56:15 +00002103
Josh Coalson49f2f162006-11-09 16:54:52 +00002104 /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
2105 for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002106 encoder->private_->integer_signal[0][i] = mid = side = buffer[0][j];
2107 x = buffer[1][j];
2108 encoder->private_->integer_signal[1][i] = x;
2109 mid += x;
2110 side -= x;
2111 mid >>= 1; /* NOTE: not the same as 'mid = (buffer[0][j] + buffer[1][j]) / 2' ! */
2112 encoder->private_->integer_signal_mid_side[1][i] = side;
2113 encoder->private_->integer_signal_mid_side[0][i] = mid;
2114 encoder->private_->current_sample_number++;
Josh Coalsonaa255362001-05-31 06:17:41 +00002115 }
Josh Coalson49f2f162006-11-09 16:54:52 +00002116 /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
2117 if(i > blocksize) {
2118 if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002119 return false;
Josh Coalson49f2f162006-11-09 16:54:52 +00002120 /* move unprocessed overread samples to beginnings of arrays */
2121 FLAC__ASSERT(i == blocksize+OVERREAD_);
2122 FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
2123 i--;
2124 encoder->private_->integer_signal[0][0] = encoder->private_->integer_signal[0][i];
2125 encoder->private_->integer_signal[1][0] = encoder->private_->integer_signal[1][i];
2126 encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][i];
2127 encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][i];
2128 encoder->private_->current_sample_number = 1;
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002129 }
2130 } while(j < samples);
2131 }
2132 else {
2133 /*
2134 * independent channel coding: buffer each channel in inner loop
2135 * without LPC: no need to calculate floating point version of signal
2136 */
2137 do {
2138 if(encoder->protected_->verify)
Josh Coalson49f2f162006-11-09 16:54:52 +00002139 append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+1-encoder->private_->current_sample_number, samples-j));
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002140
Josh Coalson49f2f162006-11-09 16:54:52 +00002141 /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
2142 for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002143 for(channel = 0; channel < channels; channel++)
2144 encoder->private_->integer_signal[channel][i] = buffer[channel][j];
2145 encoder->private_->current_sample_number++;
2146 }
Josh Coalson49f2f162006-11-09 16:54:52 +00002147 /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
2148 if(i > blocksize) {
2149 if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002150 return false;
Josh Coalson49f2f162006-11-09 16:54:52 +00002151 /* move unprocessed overread samples to beginnings of arrays */
2152 FLAC__ASSERT(i == blocksize+OVERREAD_);
2153 FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
2154 i--;
2155 for(channel = 0; channel < channels; channel++)
2156 encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][i];
2157 encoder->private_->current_sample_number = 1;
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002158 }
2159 } while(j < samples);
2160 }
Josh Coalsonaa255362001-05-31 06:17:41 +00002161 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00002162
2163 return true;
2164}
2165
Josh Coalson6afed9f2002-10-16 22:29:47 +00002166FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00002167{
2168 unsigned i, j, k, channel;
Josh Coalson77e3f312001-06-23 03:03:24 +00002169 FLAC__int32 x, mid, side;
Josh Coalsonfa697a92001-08-16 20:07:29 +00002170 const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00002171
Josh Coalsonf1eff452002-07-31 07:05:33 +00002172 FLAC__ASSERT(0 != encoder);
Josh Coalson8da98c82006-10-15 04:24:05 +00002173 FLAC__ASSERT(0 != encoder->private_);
2174 FLAC__ASSERT(0 != encoder->protected_);
Josh Coalsonfa697a92001-08-16 20:07:29 +00002175 FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00002176
2177 j = k = 0;
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002178 /*
2179 * we have several flavors of the same basic loop, optimized for
2180 * different conditions:
2181 */
2182 if(encoder->protected_->max_lpc_order > 0) {
2183 if(encoder->protected_->do_mid_side_stereo && channels == 2) {
2184 /*
2185 * stereo coding: unroll channel loop
2186 * with LPC: calculate floating point version of signal
2187 */
2188 do {
2189 if(encoder->protected_->verify)
Josh Coalson49f2f162006-11-09 16:54:52 +00002190 append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+1-encoder->private_->current_sample_number, samples-j));
Josh Coalsond86e03b2002-08-03 21:56:15 +00002191
Josh Coalson49f2f162006-11-09 16:54:52 +00002192 /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
2193 for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002194 x = mid = side = buffer[k++];
2195 encoder->private_->integer_signal[0][i] = x;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002196#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002197 encoder->private_->real_signal[0][i] = (FLAC__real)x;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002198#endif
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002199 x = buffer[k++];
2200 encoder->private_->integer_signal[1][i] = x;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002201#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002202 encoder->private_->real_signal[1][i] = (FLAC__real)x;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002203#endif
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002204 mid += x;
2205 side -= x;
2206 mid >>= 1; /* NOTE: not the same as 'mid = (left + right) / 2' ! */
2207 encoder->private_->integer_signal_mid_side[1][i] = side;
2208 encoder->private_->integer_signal_mid_side[0][i] = mid;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002209#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002210 encoder->private_->real_signal_mid_side[1][i] = (FLAC__real)side;
2211 encoder->private_->real_signal_mid_side[0][i] = (FLAC__real)mid;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002212#endif
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002213 encoder->private_->current_sample_number++;
2214 }
Josh Coalson49f2f162006-11-09 16:54:52 +00002215 /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
2216 if(i > blocksize) {
2217 if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002218 return false;
Josh Coalson49f2f162006-11-09 16:54:52 +00002219 /* move unprocessed overread samples to beginnings of arrays */
2220 FLAC__ASSERT(i == blocksize+OVERREAD_);
2221 FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
2222 i--;
2223 encoder->private_->integer_signal[0][0] = encoder->private_->integer_signal[0][i];
2224 encoder->private_->integer_signal[1][0] = encoder->private_->integer_signal[1][i];
2225 encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][i];
2226 encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][i];
2227#ifndef FLAC__INTEGER_ONLY_LIBRARY
2228 encoder->private_->real_signal[0][0] = encoder->private_->real_signal[0][i];
2229 encoder->private_->real_signal[1][0] = encoder->private_->real_signal[1][i];
2230 encoder->private_->real_signal_mid_side[0][0] = encoder->private_->real_signal_mid_side[0][i];
2231 encoder->private_->real_signal_mid_side[1][0] = encoder->private_->real_signal_mid_side[1][i];
2232#endif
2233 encoder->private_->current_sample_number = 1;
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002234 }
2235 } while(j < samples);
2236 }
2237 else {
2238 /*
2239 * independent channel coding: buffer each channel in inner loop
2240 * with LPC: calculate floating point version of signal
2241 */
2242 do {
2243 if(encoder->protected_->verify)
Josh Coalson49f2f162006-11-09 16:54:52 +00002244 append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+1-encoder->private_->current_sample_number, samples-j));
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002245
Josh Coalson49f2f162006-11-09 16:54:52 +00002246 /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
2247 for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002248 for(channel = 0; channel < channels; channel++) {
2249 x = buffer[k++];
2250 encoder->private_->integer_signal[channel][i] = x;
2251#ifndef FLAC__INTEGER_ONLY_LIBRARY
2252 encoder->private_->real_signal[channel][i] = (FLAC__real)x;
2253#endif
2254 }
2255 encoder->private_->current_sample_number++;
2256 }
Josh Coalson49f2f162006-11-09 16:54:52 +00002257 /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
2258 if(i > blocksize) {
2259 if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002260 return false;
Josh Coalson49f2f162006-11-09 16:54:52 +00002261 /* move unprocessed overread samples to beginnings of arrays */
2262 FLAC__ASSERT(i == blocksize+OVERREAD_);
2263 FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
2264 i--;
2265 for(channel = 0; channel < channels; channel++) {
2266 encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][i];
2267#ifndef FLAC__INTEGER_ONLY_LIBRARY
2268 encoder->private_->real_signal[channel][0] = encoder->private_->real_signal[channel][i];
2269#endif
2270 }
2271 encoder->private_->current_sample_number = 1;
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002272 }
2273 } while(j < samples);
2274 }
Josh Coalsonaa255362001-05-31 06:17:41 +00002275 }
2276 else {
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002277 if(encoder->protected_->do_mid_side_stereo && channels == 2) {
2278 /*
2279 * stereo coding: unroll channel loop
2280 * without LPC: no need to calculate floating point version of signal
2281 */
2282 do {
2283 if(encoder->protected_->verify)
Josh Coalson49f2f162006-11-09 16:54:52 +00002284 append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+1-encoder->private_->current_sample_number, samples-j));
Josh Coalsond86e03b2002-08-03 21:56:15 +00002285
Josh Coalson49f2f162006-11-09 16:54:52 +00002286 /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
2287 for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002288 encoder->private_->integer_signal[0][i] = mid = side = buffer[k++];
Josh Coalson57ba6f42002-06-07 05:27:37 +00002289 x = buffer[k++];
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002290 encoder->private_->integer_signal[1][i] = x;
2291 mid += x;
2292 side -= x;
2293 mid >>= 1; /* NOTE: not the same as 'mid = (left + right) / 2' ! */
2294 encoder->private_->integer_signal_mid_side[1][i] = side;
2295 encoder->private_->integer_signal_mid_side[0][i] = mid;
2296 encoder->private_->current_sample_number++;
Josh Coalsonaa255362001-05-31 06:17:41 +00002297 }
Josh Coalson49f2f162006-11-09 16:54:52 +00002298 /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
2299 if(i > blocksize) {
2300 if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002301 return false;
Josh Coalson49f2f162006-11-09 16:54:52 +00002302 /* move unprocessed overread samples to beginnings of arrays */
2303 FLAC__ASSERT(i == blocksize+OVERREAD_);
2304 FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
2305 i--;
2306 encoder->private_->integer_signal[0][0] = encoder->private_->integer_signal[0][i];
2307 encoder->private_->integer_signal[1][0] = encoder->private_->integer_signal[1][i];
2308 encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][i];
2309 encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][i];
2310 encoder->private_->current_sample_number = 1;
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002311 }
2312 } while(j < samples);
2313 }
2314 else {
2315 /*
2316 * independent channel coding: buffer each channel in inner loop
2317 * without LPC: no need to calculate floating point version of signal
2318 */
2319 do {
2320 if(encoder->protected_->verify)
Josh Coalson49f2f162006-11-09 16:54:52 +00002321 append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+1-encoder->private_->current_sample_number, samples-j));
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002322
Josh Coalson49f2f162006-11-09 16:54:52 +00002323 /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
2324 for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002325 for(channel = 0; channel < channels; channel++)
2326 encoder->private_->integer_signal[channel][i] = buffer[k++];
2327 encoder->private_->current_sample_number++;
2328 }
Josh Coalson49f2f162006-11-09 16:54:52 +00002329 /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
2330 if(i > blocksize) {
2331 if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002332 return false;
Josh Coalson49f2f162006-11-09 16:54:52 +00002333 /* move unprocessed overread samples to beginnings of arrays */
2334 FLAC__ASSERT(i == blocksize+OVERREAD_);
2335 FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
2336 i--;
2337 for(channel = 0; channel < channels; channel++)
2338 encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][i];
2339 encoder->private_->current_sample_number = 1;
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002340 }
2341 } while(j < samples);
2342 }
Josh Coalsonaa255362001-05-31 06:17:41 +00002343 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00002344
2345 return true;
2346}
2347
Josh Coalsonf1eff452002-07-31 07:05:33 +00002348/***********************************************************************
2349 *
2350 * Private class methods
2351 *
2352 ***********************************************************************/
2353
2354void set_defaults_(FLAC__StreamEncoder *encoder)
Josh Coalson92031602002-07-24 06:02:11 +00002355{
2356 FLAC__ASSERT(0 != encoder);
2357
Josh Coalson47c7b142005-01-29 06:08:58 +00002358#ifdef FLAC__MANDATORY_VERIFY_WHILE_ENCODING
2359 encoder->protected_->verify = true;
2360#else
Josh Coalsond86e03b2002-08-03 21:56:15 +00002361 encoder->protected_->verify = false;
Josh Coalson47c7b142005-01-29 06:08:58 +00002362#endif
Josh Coalson92031602002-07-24 06:02:11 +00002363 encoder->protected_->streamable_subset = true;
2364 encoder->protected_->do_mid_side_stereo = false;
2365 encoder->protected_->loose_mid_side_stereo = false;
2366 encoder->protected_->channels = 2;
2367 encoder->protected_->bits_per_sample = 16;
2368 encoder->protected_->sample_rate = 44100;
Josh Coalson425609c2006-11-03 16:08:52 +00002369 encoder->protected_->blocksize = 0;
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002370#ifndef FLAC__INTEGER_ONLY_LIBRARY
2371 encoder->protected_->num_apodizations = 1;
Josh Coalson82389362006-05-01 05:58:35 +00002372 encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
2373 encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002374#endif
Josh Coalson92031602002-07-24 06:02:11 +00002375 encoder->protected_->max_lpc_order = 0;
2376 encoder->protected_->qlp_coeff_precision = 0;
2377 encoder->protected_->do_qlp_coeff_prec_search = false;
2378 encoder->protected_->do_exhaustive_model_search = false;
2379 encoder->protected_->do_escape_coding = false;
2380 encoder->protected_->min_residual_partition_order = 0;
2381 encoder->protected_->max_residual_partition_order = 0;
2382 encoder->protected_->rice_parameter_search_dist = 0;
2383 encoder->protected_->total_samples_estimate = 0;
2384 encoder->protected_->metadata = 0;
2385 encoder->protected_->num_metadata_blocks = 0;
2386
Josh Coalson6b21f662006-09-13 01:42:27 +00002387 encoder->private_->seek_table = 0;
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00002388 encoder->private_->disable_constant_subframes = false;
2389 encoder->private_->disable_fixed_subframes = false;
2390 encoder->private_->disable_verbatim_subframes = false;
Josh Coalson8da98c82006-10-15 04:24:05 +00002391#if FLAC__HAS_OGG
2392 encoder->private_->is_ogg = false;
2393#endif
2394 encoder->private_->read_callback = 0;
Josh Coalson92031602002-07-24 06:02:11 +00002395 encoder->private_->write_callback = 0;
Josh Coalson6b21f662006-09-13 01:42:27 +00002396 encoder->private_->seek_callback = 0;
2397 encoder->private_->tell_callback = 0;
Josh Coalson92031602002-07-24 06:02:11 +00002398 encoder->private_->metadata_callback = 0;
Josh Coalson6b21f662006-09-13 01:42:27 +00002399 encoder->private_->progress_callback = 0;
Josh Coalson92031602002-07-24 06:02:11 +00002400 encoder->private_->client_data = 0;
Josh Coalson8da98c82006-10-15 04:24:05 +00002401
2402#if FLAC__HAS_OGG
2403 FLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect);
2404#endif
Josh Coalson92031602002-07-24 06:02:11 +00002405}
2406
Josh Coalsonf1eff452002-07-31 07:05:33 +00002407void free_(FLAC__StreamEncoder *encoder)
Josh Coalson639aeb02002-07-25 05:38:23 +00002408{
2409 unsigned i, channel;
2410
Josh Coalsonf1eff452002-07-31 07:05:33 +00002411 FLAC__ASSERT(0 != encoder);
Josh Coalson639aeb02002-07-25 05:38:23 +00002412 for(i = 0; i < encoder->protected_->channels; i++) {
Josh Coalsonf1eff452002-07-31 07:05:33 +00002413 if(0 != encoder->private_->integer_signal_unaligned[i]) {
Josh Coalson639aeb02002-07-25 05:38:23 +00002414 free(encoder->private_->integer_signal_unaligned[i]);
2415 encoder->private_->integer_signal_unaligned[i] = 0;
2416 }
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002417#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonf1eff452002-07-31 07:05:33 +00002418 if(0 != encoder->private_->real_signal_unaligned[i]) {
Josh Coalson639aeb02002-07-25 05:38:23 +00002419 free(encoder->private_->real_signal_unaligned[i]);
2420 encoder->private_->real_signal_unaligned[i] = 0;
2421 }
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002422#endif
Josh Coalson639aeb02002-07-25 05:38:23 +00002423 }
2424 for(i = 0; i < 2; i++) {
Josh Coalsonf1eff452002-07-31 07:05:33 +00002425 if(0 != encoder->private_->integer_signal_mid_side_unaligned[i]) {
Josh Coalson639aeb02002-07-25 05:38:23 +00002426 free(encoder->private_->integer_signal_mid_side_unaligned[i]);
2427 encoder->private_->integer_signal_mid_side_unaligned[i] = 0;
2428 }
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002429#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonf1eff452002-07-31 07:05:33 +00002430 if(0 != encoder->private_->real_signal_mid_side_unaligned[i]) {
Josh Coalson639aeb02002-07-25 05:38:23 +00002431 free(encoder->private_->real_signal_mid_side_unaligned[i]);
2432 encoder->private_->real_signal_mid_side_unaligned[i] = 0;
2433 }
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002434#endif
Josh Coalson639aeb02002-07-25 05:38:23 +00002435 }
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002436#ifndef FLAC__INTEGER_ONLY_LIBRARY
2437 for(i = 0; i < encoder->protected_->num_apodizations; i++) {
2438 if(0 != encoder->private_->window_unaligned[i]) {
2439 free(encoder->private_->window_unaligned[i]);
2440 encoder->private_->window_unaligned[i] = 0;
2441 }
2442 }
2443 if(0 != encoder->private_->windowed_signal_unaligned) {
2444 free(encoder->private_->windowed_signal_unaligned);
2445 encoder->private_->windowed_signal_unaligned = 0;
2446 }
2447#endif
Josh Coalson639aeb02002-07-25 05:38:23 +00002448 for(channel = 0; channel < encoder->protected_->channels; channel++) {
2449 for(i = 0; i < 2; i++) {
Josh Coalsonf1eff452002-07-31 07:05:33 +00002450 if(0 != encoder->private_->residual_workspace_unaligned[channel][i]) {
Josh Coalson639aeb02002-07-25 05:38:23 +00002451 free(encoder->private_->residual_workspace_unaligned[channel][i]);
2452 encoder->private_->residual_workspace_unaligned[channel][i] = 0;
2453 }
2454 }
2455 }
2456 for(channel = 0; channel < 2; channel++) {
2457 for(i = 0; i < 2; i++) {
Josh Coalsonf1eff452002-07-31 07:05:33 +00002458 if(0 != encoder->private_->residual_workspace_mid_side_unaligned[channel][i]) {
Josh Coalson639aeb02002-07-25 05:38:23 +00002459 free(encoder->private_->residual_workspace_mid_side_unaligned[channel][i]);
2460 encoder->private_->residual_workspace_mid_side_unaligned[channel][i] = 0;
2461 }
2462 }
2463 }
Josh Coalsonf1eff452002-07-31 07:05:33 +00002464 if(0 != encoder->private_->abs_residual_unaligned) {
Josh Coalson639aeb02002-07-25 05:38:23 +00002465 free(encoder->private_->abs_residual_unaligned);
2466 encoder->private_->abs_residual_unaligned = 0;
2467 }
Josh Coalsonf1eff452002-07-31 07:05:33 +00002468 if(0 != encoder->private_->abs_residual_partition_sums_unaligned) {
Josh Coalson639aeb02002-07-25 05:38:23 +00002469 free(encoder->private_->abs_residual_partition_sums_unaligned);
2470 encoder->private_->abs_residual_partition_sums_unaligned = 0;
2471 }
Josh Coalsonf1eff452002-07-31 07:05:33 +00002472 if(0 != encoder->private_->raw_bits_per_partition_unaligned) {
Josh Coalson639aeb02002-07-25 05:38:23 +00002473 free(encoder->private_->raw_bits_per_partition_unaligned);
2474 encoder->private_->raw_bits_per_partition_unaligned = 0;
2475 }
Josh Coalsond86e03b2002-08-03 21:56:15 +00002476 if(encoder->protected_->verify) {
2477 for(i = 0; i < encoder->protected_->channels; i++) {
2478 if(0 != encoder->private_->verify.input_fifo.data[i]) {
2479 free(encoder->private_->verify.input_fifo.data[i]);
2480 encoder->private_->verify.input_fifo.data[i] = 0;
2481 }
2482 }
2483 }
Josh Coalson639aeb02002-07-25 05:38:23 +00002484 FLAC__bitbuffer_free(encoder->private_->frame);
2485}
2486
Josh Coalson85aaed82006-11-09 01:19:13 +00002487FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize)
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00002488{
Josh Coalson77e3f312001-06-23 03:03:24 +00002489 FLAC__bool ok;
Josh Coalson0a15c142001-06-13 17:59:57 +00002490 unsigned i, channel;
2491
Josh Coalson85aaed82006-11-09 01:19:13 +00002492 FLAC__ASSERT(new_blocksize > 0);
Josh Coalsonfa697a92001-08-16 20:07:29 +00002493 FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
2494 FLAC__ASSERT(encoder->private_->current_sample_number == 0);
Josh Coalson0a15c142001-06-13 17:59:57 +00002495
2496 /* To avoid excessive malloc'ing, we only grow the buffer; no shrinking. */
Josh Coalson85aaed82006-11-09 01:19:13 +00002497 if(new_blocksize <= encoder->private_->input_capacity)
Josh Coalson0a15c142001-06-13 17:59:57 +00002498 return true;
2499
2500 ok = true;
Josh Coalson8395d022001-07-12 21:25:22 +00002501
Josh Coalsonc9c0d132002-10-04 05:29:05 +00002502 /* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx()
2503 * requires that the input arrays (in our case the integer signals)
2504 * have a buffer of up to 3 zeroes in front (at negative indices) for
Josh Coalson85aaed82006-11-09 01:19:13 +00002505 * alignment purposes; we use 4 in front to keep the data well-aligned.
Josh Coalsonc9c0d132002-10-04 05:29:05 +00002506 */
Josh Coalson8395d022001-07-12 21:25:22 +00002507
Josh Coalsonfa697a92001-08-16 20:07:29 +00002508 for(i = 0; ok && i < encoder->protected_->channels; i++) {
Josh Coalson49f2f162006-11-09 16:54:52 +00002509 ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_unaligned[i], &encoder->private_->integer_signal[i]);
Josh Coalsonfa697a92001-08-16 20:07:29 +00002510 memset(encoder->private_->integer_signal[i], 0, sizeof(FLAC__int32)*4);
2511 encoder->private_->integer_signal[i] += 4;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002512#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalsonc549f0f2004-12-30 03:47:49 +00002513 if(encoder->protected_->max_lpc_order > 0)
Josh Coalson49f2f162006-11-09 16:54:52 +00002514 ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_unaligned[i], &encoder->private_->real_signal[i]);
Josh Coalson5f2b46d2004-11-09 01:34:01 +00002515#endif
Josh Coalson85aaed82006-11-09 01:19:13 +00002516 }
2517 for(i = 0; ok && i < 2; i++) {
Josh Coalson49f2f162006-11-09 16:54:52 +00002518 ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_mid_side_unaligned[i], &encoder->private_->integer_signal_mid_side[i]);
Josh Coalsonfa697a92001-08-16 20:07:29 +00002519 memset(encoder->private_->integer_signal_mid_side[i], 0, sizeof(FLAC__int32)*4);
2520 encoder->private_->integer_signal_mid_side[i] += 4;
Josh Coalson85aaed82006-11-09 01:19:13 +00002521#ifndef FLAC__INTEGER_ONLY_LIBRARY
2522 if(encoder->protected_->max_lpc_order > 0)
Josh Coalson49f2f162006-11-09 16:54:52 +00002523 ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_mid_side_unaligned[i], &encoder->private_->real_signal_mid_side[i]);
Josh Coalson85aaed82006-11-09 01:19:13 +00002524#endif
Josh Coalson0a15c142001-06-13 17:59:57 +00002525 }
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002526#ifndef FLAC__INTEGER_ONLY_LIBRARY
2527 if(ok && encoder->protected_->max_lpc_order > 0) {
2528 for(i = 0; ok && i < encoder->protected_->num_apodizations; i++)
Josh Coalson85aaed82006-11-09 01:19:13 +00002529 ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->window_unaligned[i], &encoder->private_->window[i]);
2530 ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->windowed_signal_unaligned, &encoder->private_->windowed_signal);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002531 }
2532#endif
Josh Coalsonfa697a92001-08-16 20:07:29 +00002533 for(channel = 0; ok && channel < encoder->protected_->channels; channel++) {
Josh Coalson0a15c142001-06-13 17:59:57 +00002534 for(i = 0; ok && i < 2; i++) {
Josh Coalson85aaed82006-11-09 01:19:13 +00002535 ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_unaligned[channel][i], &encoder->private_->residual_workspace[channel][i]);
Josh Coalson0a15c142001-06-13 17:59:57 +00002536 }
2537 }
2538 for(channel = 0; ok && channel < 2; channel++) {
2539 for(i = 0; ok && i < 2; i++) {
Josh Coalson85aaed82006-11-09 01:19:13 +00002540 ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_mid_side_unaligned[channel][i], &encoder->private_->residual_workspace_mid_side[channel][i]);
Josh Coalson0a15c142001-06-13 17:59:57 +00002541 }
2542 }
Josh Coalson85aaed82006-11-09 01:19:13 +00002543 ok = ok && FLAC__memory_alloc_aligned_uint32_array(new_blocksize, &encoder->private_->abs_residual_unaligned, &encoder->private_->abs_residual);
Josh Coalsonfa697a92001-08-16 20:07:29 +00002544 if(encoder->private_->precompute_partition_sums || encoder->protected_->do_escape_coding) /* we require precompute_partition_sums if do_escape_coding because of their intertwined nature */
Josh Coalson85aaed82006-11-09 01:19:13 +00002545 ok = ok && FLAC__memory_alloc_aligned_uint64_array(new_blocksize * 2, &encoder->private_->abs_residual_partition_sums_unaligned, &encoder->private_->abs_residual_partition_sums);
Josh Coalsonfa697a92001-08-16 20:07:29 +00002546 if(encoder->protected_->do_escape_coding)
Josh Coalson85aaed82006-11-09 01:19:13 +00002547 ok = ok && FLAC__memory_alloc_aligned_unsigned_array(new_blocksize * 2, &encoder->private_->raw_bits_per_partition_unaligned, &encoder->private_->raw_bits_per_partition);
Josh Coalson0a15c142001-06-13 17:59:57 +00002548
Josh Coalson85aaed82006-11-09 01:19:13 +00002549 /* now adjust the windows if the blocksize has changed */
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002550#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson85aaed82006-11-09 01:19:13 +00002551 if(ok && new_blocksize != encoder->private_->input_capacity && encoder->protected_->max_lpc_order > 0) {
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002552 for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) {
2553 switch(encoder->protected_->apodizations[i].type) {
2554 case FLAC__APODIZATION_BARTLETT:
Josh Coalson85aaed82006-11-09 01:19:13 +00002555 FLAC__window_bartlett(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002556 break;
2557 case FLAC__APODIZATION_BARTLETT_HANN:
Josh Coalson85aaed82006-11-09 01:19:13 +00002558 FLAC__window_bartlett_hann(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002559 break;
2560 case FLAC__APODIZATION_BLACKMAN:
Josh Coalson85aaed82006-11-09 01:19:13 +00002561 FLAC__window_blackman(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002562 break;
2563 case FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE:
Josh Coalson85aaed82006-11-09 01:19:13 +00002564 FLAC__window_blackman_harris_4term_92db_sidelobe(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002565 break;
2566 case FLAC__APODIZATION_CONNES:
Josh Coalson85aaed82006-11-09 01:19:13 +00002567 FLAC__window_connes(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002568 break;
2569 case FLAC__APODIZATION_FLATTOP:
Josh Coalson85aaed82006-11-09 01:19:13 +00002570 FLAC__window_flattop(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002571 break;
2572 case FLAC__APODIZATION_GAUSS:
Josh Coalson85aaed82006-11-09 01:19:13 +00002573 FLAC__window_gauss(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.gauss.stddev);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002574 break;
2575 case FLAC__APODIZATION_HAMMING:
Josh Coalson85aaed82006-11-09 01:19:13 +00002576 FLAC__window_hamming(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002577 break;
2578 case FLAC__APODIZATION_HANN:
Josh Coalson85aaed82006-11-09 01:19:13 +00002579 FLAC__window_hann(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002580 break;
2581 case FLAC__APODIZATION_KAISER_BESSEL:
Josh Coalson85aaed82006-11-09 01:19:13 +00002582 FLAC__window_kaiser_bessel(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002583 break;
2584 case FLAC__APODIZATION_NUTTALL:
Josh Coalson85aaed82006-11-09 01:19:13 +00002585 FLAC__window_nuttall(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002586 break;
2587 case FLAC__APODIZATION_RECTANGLE:
Josh Coalson85aaed82006-11-09 01:19:13 +00002588 FLAC__window_rectangle(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002589 break;
2590 case FLAC__APODIZATION_TRIANGLE:
Josh Coalson85aaed82006-11-09 01:19:13 +00002591 FLAC__window_triangle(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002592 break;
2593 case FLAC__APODIZATION_TUKEY:
Josh Coalson85aaed82006-11-09 01:19:13 +00002594 FLAC__window_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.tukey.p);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002595 break;
2596 case FLAC__APODIZATION_WELCH:
Josh Coalson85aaed82006-11-09 01:19:13 +00002597 FLAC__window_welch(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002598 break;
2599 default:
2600 FLAC__ASSERT(0);
2601 /* double protection */
Josh Coalson85aaed82006-11-09 01:19:13 +00002602 FLAC__window_hann(encoder->private_->window[i], new_blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00002603 break;
2604 }
2605 }
2606 }
2607#endif
2608
Josh Coalson85aaed82006-11-09 01:19:13 +00002609 if(ok)
2610 encoder->private_->input_capacity = new_blocksize;
2611 else
2612 encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
2613
Josh Coalson0a15c142001-06-13 17:59:57 +00002614 return ok;
2615}
2616
Josh Coalson49f2f162006-11-09 16:54:52 +00002617FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block)
Josh Coalson5c491a12002-08-01 06:39:40 +00002618{
2619 const FLAC__byte *buffer;
Josh Coalson352feb52006-10-15 17:08:52 +00002620 size_t bytes;
Josh Coalson5c491a12002-08-01 06:39:40 +00002621
2622 FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(encoder->private_->frame));
2623
2624 FLAC__bitbuffer_get_buffer(encoder->private_->frame, &buffer, &bytes);
2625
Josh Coalsond86e03b2002-08-03 21:56:15 +00002626 if(encoder->protected_->verify) {
2627 encoder->private_->verify.output.data = buffer;
2628 encoder->private_->verify.output.bytes = bytes;
2629 if(encoder->private_->verify.state_hint == ENCODER_IN_MAGIC) {
2630 encoder->private_->verify.needs_magic_hack = true;
2631 }
2632 else {
2633 if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder)) {
2634 FLAC__bitbuffer_release_buffer(encoder->private_->frame);
2635 if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA)
2636 encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
2637 return false;
2638 }
2639 }
2640 }
2641
Josh Coalson49f2f162006-11-09 16:54:52 +00002642 if(write_frame_(encoder, buffer, bytes, samples, is_last_block) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
Josh Coalsondd190232002-12-29 09:30:23 +00002643 FLAC__bitbuffer_release_buffer(encoder->private_->frame);
Josh Coalson6b21f662006-09-13 01:42:27 +00002644 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
Josh Coalson5c491a12002-08-01 06:39:40 +00002645 return false;
Josh Coalsond86e03b2002-08-03 21:56:15 +00002646 }
Josh Coalson5c491a12002-08-01 06:39:40 +00002647
2648 FLAC__bitbuffer_release_buffer(encoder->private_->frame);
2649
Josh Coalsond86e03b2002-08-03 21:56:15 +00002650 if(samples > 0) {
Josh Coalson6b21f662006-09-13 01:42:27 +00002651 encoder->private_->streaminfo.data.stream_info.min_framesize = min(bytes, encoder->private_->streaminfo.data.stream_info.min_framesize);
2652 encoder->private_->streaminfo.data.stream_info.max_framesize = max(bytes, encoder->private_->streaminfo.data.stream_info.max_framesize);
Josh Coalsond86e03b2002-08-03 21:56:15 +00002653 }
2654
Josh Coalson5c491a12002-08-01 06:39:40 +00002655 return true;
2656}
2657
Josh Coalson49f2f162006-11-09 16:54:52 +00002658FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, FLAC__bool is_last_block)
Josh Coalson6b21f662006-09-13 01:42:27 +00002659{
2660 FLAC__StreamEncoderWriteStatus status;
2661 FLAC__uint64 output_position = 0;
2662
2663 /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */
2664 if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) {
2665 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
2666 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
2667 }
2668
2669 /*
2670 * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets.
2671 */
2672 if(samples == 0) {
2673 FLAC__MetadataType type = (buffer[0] & 0x7f);
2674 if(type == FLAC__METADATA_TYPE_STREAMINFO)
2675 encoder->protected_->streaminfo_offset = output_position;
2676 else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0)
2677 encoder->protected_->seektable_offset = output_position;
2678 }
2679
2680 /*
2681 * Mark the current seek point if hit (if audio_offset == 0 that
2682 * means we're still writing metadata and haven't hit the first
2683 * frame yet)
2684 */
2685 if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) {
2686 const unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder);
2687 const FLAC__uint64 frame_first_sample = encoder->private_->samples_written;
2688 const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1;
2689 FLAC__uint64 test_sample;
2690 unsigned i;
2691 for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) {
2692 test_sample = encoder->private_->seek_table->points[i].sample_number;
2693 if(test_sample > frame_last_sample) {
2694 break;
2695 }
2696 else if(test_sample >= frame_first_sample) {
2697 encoder->private_->seek_table->points[i].sample_number = frame_first_sample;
2698 encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset;
2699 encoder->private_->seek_table->points[i].frame_samples = blocksize;
2700 encoder->private_->first_seekpoint_to_check++;
2701 /* DO NOT: "break;" and here's why:
2702 * The seektable template may contain more than one target
2703 * sample for any given frame; we will keep looping, generating
2704 * duplicate seekpoints for them, and we'll clean it up later,
2705 * just before writing the seektable back to the metadata.
2706 */
2707 }
2708 else {
2709 encoder->private_->first_seekpoint_to_check++;
2710 }
2711 }
2712 }
2713
Josh Coalson8da98c82006-10-15 04:24:05 +00002714#if FLAC__HAS_OGG
2715 if(encoder->private_->is_ogg) {
2716 status = FLAC__ogg_encoder_aspect_write_callback_wrapper(
2717 &encoder->protected_->ogg_encoder_aspect,
Josh Coalson8da98c82006-10-15 04:24:05 +00002718 buffer,
2719 bytes,
2720 samples,
2721 encoder->private_->current_frame_number,
Josh Coalson49f2f162006-11-09 16:54:52 +00002722 is_last_block,
Josh Coalson8da98c82006-10-15 04:24:05 +00002723 (FLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback,
2724 encoder,
2725 encoder->private_->client_data
2726 );
2727 }
2728 else
2729#endif
Josh Coalson6b21f662006-09-13 01:42:27 +00002730 status = encoder->private_->write_callback(encoder, buffer, bytes, samples, encoder->private_->current_frame_number, encoder->private_->client_data);
2731
2732 if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
2733 encoder->private_->bytes_written += bytes;
2734 encoder->private_->samples_written += samples;
2735 /* we keep a high watermark on the number of frames written because
2736 * when the encoder goes back to write metadata, 'current_frame'
2737 * will drop back to 0.
2738 */
2739 encoder->private_->frames_written = max(encoder->private_->frames_written, encoder->private_->current_frame_number+1);
2740 }
2741 else
2742 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
2743
2744 return status;
2745}
2746
2747/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks. */
2748void update_metadata_(const FLAC__StreamEncoder *encoder)
2749{
2750 FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
2751 const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo;
2752 const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
2753 const unsigned min_framesize = metadata->data.stream_info.min_framesize;
2754 const unsigned max_framesize = metadata->data.stream_info.max_framesize;
2755 const unsigned bps = metadata->data.stream_info.bits_per_sample;
2756 FLAC__StreamEncoderSeekStatus seek_status;
2757
2758 FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
2759
2760 /* All this is based on intimate knowledge of the stream header
2761 * layout, but a change to the header format that would break this
2762 * would also break all streams encoded in the previous format.
2763 */
2764
2765 /*
2766 * Write MD5 signature
2767 */
2768 {
2769 const unsigned md5_offset =
2770 FLAC__STREAM_METADATA_HEADER_LENGTH +
2771 (
2772 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
2773 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
2774 FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
2775 FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
2776 FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
2777 FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
2778 FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN +
2779 FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN
2780 ) / 8;
2781
2782 if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + md5_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
2783 if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
2784 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
2785 return;
2786 }
2787 if(encoder->private_->write_callback(encoder, metadata->data.stream_info.md5sum, 16, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
2788 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
2789 return;
2790 }
2791 }
2792
2793 /*
2794 * Write total samples
2795 */
2796 {
2797 const unsigned total_samples_byte_offset =
2798 FLAC__STREAM_METADATA_HEADER_LENGTH +
2799 (
2800 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
2801 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
2802 FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
2803 FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
2804 FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
2805 FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
2806 FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN
2807 - 4
2808 ) / 8;
2809
2810 b[0] = ((FLAC__byte)(bps-1) << 4) | (FLAC__byte)((samples >> 32) & 0x0F);
2811 b[1] = (FLAC__byte)((samples >> 24) & 0xFF);
2812 b[2] = (FLAC__byte)((samples >> 16) & 0xFF);
2813 b[3] = (FLAC__byte)((samples >> 8) & 0xFF);
2814 b[4] = (FLAC__byte)(samples & 0xFF);
2815 if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + total_samples_byte_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
2816 if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
2817 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
2818 return;
2819 }
2820 if(encoder->private_->write_callback(encoder, b, 5, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
2821 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
2822 return;
2823 }
2824 }
2825
2826 /*
2827 * Write min/max framesize
2828 */
2829 {
2830 const unsigned min_framesize_offset =
2831 FLAC__STREAM_METADATA_HEADER_LENGTH +
2832 (
2833 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
2834 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
2835 ) / 8;
2836
2837 b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF);
2838 b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF);
2839 b[2] = (FLAC__byte)(min_framesize & 0xFF);
2840 b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF);
2841 b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF);
2842 b[5] = (FLAC__byte)(max_framesize & 0xFF);
2843 if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + min_framesize_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
2844 if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
2845 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
2846 return;
2847 }
2848 if(encoder->private_->write_callback(encoder, b, 6, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
2849 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
2850 return;
2851 }
2852 }
2853
2854 /*
2855 * Write seektable
2856 */
2857 if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
2858 unsigned i;
2859
2860 FLAC__format_seektable_sort(encoder->private_->seek_table);
2861
2862 FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
2863
2864 if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
2865 if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
2866 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
2867 return;
2868 }
2869
2870 for(i = 0; i < encoder->private_->seek_table->num_points; i++) {
2871 FLAC__uint64 xx;
2872 unsigned x;
2873 xx = encoder->private_->seek_table->points[i].sample_number;
2874 b[7] = (FLAC__byte)xx; xx >>= 8;
2875 b[6] = (FLAC__byte)xx; xx >>= 8;
2876 b[5] = (FLAC__byte)xx; xx >>= 8;
2877 b[4] = (FLAC__byte)xx; xx >>= 8;
2878 b[3] = (FLAC__byte)xx; xx >>= 8;
2879 b[2] = (FLAC__byte)xx; xx >>= 8;
2880 b[1] = (FLAC__byte)xx; xx >>= 8;
2881 b[0] = (FLAC__byte)xx; xx >>= 8;
2882 xx = encoder->private_->seek_table->points[i].stream_offset;
2883 b[15] = (FLAC__byte)xx; xx >>= 8;
2884 b[14] = (FLAC__byte)xx; xx >>= 8;
2885 b[13] = (FLAC__byte)xx; xx >>= 8;
2886 b[12] = (FLAC__byte)xx; xx >>= 8;
2887 b[11] = (FLAC__byte)xx; xx >>= 8;
2888 b[10] = (FLAC__byte)xx; xx >>= 8;
2889 b[9] = (FLAC__byte)xx; xx >>= 8;
2890 b[8] = (FLAC__byte)xx; xx >>= 8;
2891 x = encoder->private_->seek_table->points[i].frame_samples;
2892 b[17] = (FLAC__byte)x; x >>= 8;
2893 b[16] = (FLAC__byte)x; x >>= 8;
2894 if(encoder->private_->write_callback(encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
2895 encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
2896 return;
2897 }
2898 }
2899 }
2900}
2901
Josh Coalson15b8eb82006-10-15 05:15:55 +00002902#if FLAC__HAS_OGG
Josh Coalson8da98c82006-10-15 04:24:05 +00002903/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks. */
2904void update_ogg_metadata_(FLAC__StreamEncoder *encoder)
2905{
Josh Coalsonc986d132006-11-15 08:53:32 +00002906 /* the # of bytes in the 1st packet that precede the STREAMINFO */
2907 static const unsigned FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH =
2908 FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
2909 FLAC__OGG_MAPPING_MAGIC_LENGTH +
2910 FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
2911 FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
2912 FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH +
2913 FLAC__STREAM_SYNC_LENGTH
2914 ;
Josh Coalson8da98c82006-10-15 04:24:05 +00002915 FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
2916 const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo;
2917 const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
2918 const unsigned min_framesize = metadata->data.stream_info.min_framesize;
2919 const unsigned max_framesize = metadata->data.stream_info.max_framesize;
2920 ogg_page page;
2921
2922 FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
Josh Coalsoncf1422e2006-11-16 01:32:25 +00002923 FLAC__ASSERT(0 != encoder->private_->seek_callback);
2924
2925 /* Pre-check that client supports seeking, since we don't want the
2926 * ogg_helper code to ever have to deal with this condition.
2927 */
2928 if(encoder->private_->seek_callback(encoder, 0, encoder->private_->client_data) == FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED)
2929 return;
Josh Coalson8da98c82006-10-15 04:24:05 +00002930
2931 /* All this is based on intimate knowledge of the stream header
2932 * layout, but a change to the header format that would break this
2933 * would also break all streams encoded in the previous format.
2934 */
2935
2936 /**
2937 ** Write STREAMINFO stats
2938 **/
2939 simple_ogg_page__init(&page);
2940 if(!simple_ogg_page__get_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
2941 simple_ogg_page__clear(&page);
2942 return; /* state already set */
2943 }
2944
2945 /*
2946 * Write MD5 signature
2947 */
2948 {
2949 const unsigned md5_offset =
Josh Coalsonc986d132006-11-15 08:53:32 +00002950 FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
Josh Coalson8da98c82006-10-15 04:24:05 +00002951 FLAC__STREAM_METADATA_HEADER_LENGTH +
2952 (
2953 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
2954 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
2955 FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
2956 FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
2957 FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
2958 FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
2959 FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN +
2960 FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN
2961 ) / 8;
2962
2963 if(md5_offset + 16 > (unsigned)page.body_len) {
2964 encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
2965 simple_ogg_page__clear(&page);
2966 return;
2967 }
2968 memcpy(page.body + md5_offset, metadata->data.stream_info.md5sum, 16);
2969 }
2970
2971 /*
2972 * Write total samples
2973 */
2974 {
2975 const unsigned total_samples_byte_offset =
Josh Coalsonc986d132006-11-15 08:53:32 +00002976 FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
Josh Coalson8da98c82006-10-15 04:24:05 +00002977 FLAC__STREAM_METADATA_HEADER_LENGTH +
2978 (
2979 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
2980 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
2981 FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
2982 FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
2983 FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
2984 FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
2985 FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN
2986 - 4
2987 ) / 8;
2988
2989 if(total_samples_byte_offset + 5 > (unsigned)page.body_len) {
2990 encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
2991 simple_ogg_page__clear(&page);
2992 return;
2993 }
2994 b[0] = (FLAC__byte)page.body[total_samples_byte_offset] & 0xF0;
2995 b[0] |= (FLAC__byte)((samples >> 32) & 0x0F);
2996 b[1] = (FLAC__byte)((samples >> 24) & 0xFF);
2997 b[2] = (FLAC__byte)((samples >> 16) & 0xFF);
2998 b[3] = (FLAC__byte)((samples >> 8) & 0xFF);
2999 b[4] = (FLAC__byte)(samples & 0xFF);
3000 memcpy(page.body + total_samples_byte_offset, b, 5);
3001 }
3002
3003 /*
3004 * Write min/max framesize
3005 */
3006 {
3007 const unsigned min_framesize_offset =
Josh Coalsonc986d132006-11-15 08:53:32 +00003008 FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
Josh Coalson8da98c82006-10-15 04:24:05 +00003009 FLAC__STREAM_METADATA_HEADER_LENGTH +
3010 (
3011 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
3012 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
3013 ) / 8;
3014
3015 if(min_framesize_offset + 6 > (unsigned)page.body_len) {
3016 encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
3017 simple_ogg_page__clear(&page);
3018 return;
3019 }
3020 b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF);
3021 b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF);
3022 b[2] = (FLAC__byte)(min_framesize & 0xFF);
3023 b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF);
3024 b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF);
3025 b[5] = (FLAC__byte)(max_framesize & 0xFF);
3026 memcpy(page.body + min_framesize_offset, b, 6);
3027 }
3028 if(!simple_ogg_page__set_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
3029 simple_ogg_page__clear(&page);
3030 return; /* state already set */
3031 }
3032 simple_ogg_page__clear(&page);
3033
3034 /*
3035 * Write seektable
3036 */
3037 if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
3038 unsigned i;
3039 FLAC__byte *p;
3040
3041 FLAC__format_seektable_sort(encoder->private_->seek_table);
3042
3043 FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
3044
3045 simple_ogg_page__init(&page);
3046 if(!simple_ogg_page__get_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
3047 simple_ogg_page__clear(&page);
3048 return; /* state already set */
3049 }
3050
Josh Coalsonc986d132006-11-15 08:53:32 +00003051 if((FLAC__STREAM_METADATA_HEADER_LENGTH + 18*encoder->private_->seek_table->num_points) != (unsigned)page.body_len) {
Josh Coalson8da98c82006-10-15 04:24:05 +00003052 encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
3053 simple_ogg_page__clear(&page);
3054 return;
3055 }
3056
3057 for(i = 0, p = page.body + FLAC__STREAM_METADATA_HEADER_LENGTH; i < encoder->private_->seek_table->num_points; i++, p += 18) {
3058 FLAC__uint64 xx;
3059 unsigned x;
3060 xx = encoder->private_->seek_table->points[i].sample_number;
3061 b[7] = (FLAC__byte)xx; xx >>= 8;
3062 b[6] = (FLAC__byte)xx; xx >>= 8;
3063 b[5] = (FLAC__byte)xx; xx >>= 8;
3064 b[4] = (FLAC__byte)xx; xx >>= 8;
3065 b[3] = (FLAC__byte)xx; xx >>= 8;
3066 b[2] = (FLAC__byte)xx; xx >>= 8;
3067 b[1] = (FLAC__byte)xx; xx >>= 8;
3068 b[0] = (FLAC__byte)xx; xx >>= 8;
3069 xx = encoder->private_->seek_table->points[i].stream_offset;
3070 b[15] = (FLAC__byte)xx; xx >>= 8;
3071 b[14] = (FLAC__byte)xx; xx >>= 8;
3072 b[13] = (FLAC__byte)xx; xx >>= 8;
3073 b[12] = (FLAC__byte)xx; xx >>= 8;
3074 b[11] = (FLAC__byte)xx; xx >>= 8;
3075 b[10] = (FLAC__byte)xx; xx >>= 8;
3076 b[9] = (FLAC__byte)xx; xx >>= 8;
3077 b[8] = (FLAC__byte)xx; xx >>= 8;
3078 x = encoder->private_->seek_table->points[i].frame_samples;
3079 b[17] = (FLAC__byte)x; x >>= 8;
3080 b[16] = (FLAC__byte)x; x >>= 8;
Josh Coalson8da98c82006-10-15 04:24:05 +00003081 memcpy(p, b, 18);
3082 }
3083
3084 if(!simple_ogg_page__set_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
3085 simple_ogg_page__clear(&page);
3086 return; /* state already set */
3087 }
3088 simple_ogg_page__clear(&page);
3089 }
3090}
Josh Coalson15b8eb82006-10-15 05:15:55 +00003091#endif
Josh Coalson8da98c82006-10-15 04:24:05 +00003092
Josh Coalson49f2f162006-11-09 16:54:52 +00003093FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block)
Josh Coalson0a15c142001-06-13 17:59:57 +00003094{
Josh Coalsonfa697a92001-08-16 20:07:29 +00003095 FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003096
3097 /*
Josh Coalsonfa37f1c2001-01-12 23:55:11 +00003098 * Accumulate raw signal to the MD5 signature
3099 */
Josh Coalson57ba6f42002-06-07 05:27:37 +00003100 if(!FLAC__MD5Accumulate(&encoder->private_->md5context, (const FLAC__int32 * const *)encoder->private_->integer_signal, encoder->protected_->channels, encoder->protected_->blocksize, (encoder->protected_->bits_per_sample+7) / 8)) {
Josh Coalsonfa697a92001-08-16 20:07:29 +00003101 encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
Josh Coalsonfa37f1c2001-01-12 23:55:11 +00003102 return false;
3103 }
3104
3105 /*
Josh Coalson94e02cd2001-01-25 10:41:06 +00003106 * Process the frame header and subframes into the frame bitbuffer
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003107 */
Josh Coalson85aaed82006-11-09 01:19:13 +00003108 if(!process_subframes_(encoder, is_fractional_block)) {
Josh Coalson94e02cd2001-01-25 10:41:06 +00003109 /* the above function sets the state for us in case of an error */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003110 return false;
3111 }
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003112
3113 /*
3114 * Zero-pad the frame to a byte_boundary
3115 */
Josh Coalsonaec256b2002-03-12 16:19:54 +00003116 if(!FLAC__bitbuffer_zero_pad_to_byte_boundary(encoder->private_->frame)) {
Josh Coalsonfa697a92001-08-16 20:07:29 +00003117 encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003118 return false;
3119 }
3120
3121 /*
Josh Coalson215af572001-03-27 01:15:58 +00003122 * CRC-16 the whole thing
3123 */
Josh Coalsonaec256b2002-03-12 16:19:54 +00003124 FLAC__ASSERT(FLAC__bitbuffer_is_byte_aligned(encoder->private_->frame));
3125 FLAC__bitbuffer_write_raw_uint32(encoder->private_->frame, FLAC__bitbuffer_get_write_crc16(encoder->private_->frame), FLAC__FRAME_FOOTER_CRC_LEN);
Josh Coalson215af572001-03-27 01:15:58 +00003126
3127 /*
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003128 * Write it
3129 */
Josh Coalson49f2f162006-11-09 16:54:52 +00003130 if(!write_bitbuffer_(encoder, encoder->protected_->blocksize, is_last_block)) {
Josh Coalsond86e03b2002-08-03 21:56:15 +00003131 /* the above function sets the state for us in case of an error */
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003132 return false;
3133 }
3134
3135 /*
3136 * Get ready for the next frame
3137 */
Josh Coalsonfa697a92001-08-16 20:07:29 +00003138 encoder->private_->current_sample_number = 0;
3139 encoder->private_->current_frame_number++;
Josh Coalson6b21f662006-09-13 01:42:27 +00003140 encoder->private_->streaminfo.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize;
Josh Coalsonbb7f6b92000-12-10 04:09:52 +00003141
3142 return true;
3143}
3144
Josh Coalson85aaed82006-11-09 01:19:13 +00003145FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block)
Josh Coalson94e02cd2001-01-25 10:41:06 +00003146{
3147 FLAC__FrameHeader frame_header;
Josh Coalsonfa697a92001-08-16 20:07:29 +00003148 unsigned channel, min_partition_order = encoder->protected_->min_residual_partition_order, max_partition_order;
Josh Coalson8395d022001-07-12 21:25:22 +00003149 FLAC__bool do_independent, do_mid_side, precompute_partition_sums;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003150
3151 /*
Josh Coalson60f77d72001-04-25 02:16:36 +00003152 * Calculate the min,max Rice partition orders
Josh Coalson94e02cd2001-01-25 10:41:06 +00003153 */
Josh Coalson85aaed82006-11-09 01:19:13 +00003154 if(is_fractional_block) {
Josh Coalson94e02cd2001-01-25 10:41:06 +00003155 max_partition_order = 0;
3156 }
3157 else {
Josh Coalsonb7023aa2002-08-17 15:23:43 +00003158 max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize(encoder->protected_->blocksize);
3159 max_partition_order = min(max_partition_order, encoder->protected_->max_residual_partition_order);
Josh Coalson94e02cd2001-01-25 10:41:06 +00003160 }
Josh Coalson60f77d72001-04-25 02:16:36 +00003161 min_partition_order = min(min_partition_order, max_partition_order);
Josh Coalson94e02cd2001-01-25 10:41:06 +00003162
Josh Coalsonfa697a92001-08-16 20:07:29 +00003163 precompute_partition_sums = encoder->private_->precompute_partition_sums && ((max_partition_order > min_partition_order) || encoder->protected_->do_escape_coding);
Josh Coalson8395d022001-07-12 21:25:22 +00003164
Josh Coalson94e02cd2001-01-25 10:41:06 +00003165 /*
3166 * Setup the frame
3167 */
Josh Coalsonaec256b2002-03-12 16:19:54 +00003168 if(!FLAC__bitbuffer_clear(encoder->private_->frame)) {
Josh Coalsonfa697a92001-08-16 20:07:29 +00003169 encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003170 return false;
3171 }
Josh Coalsonfa697a92001-08-16 20:07:29 +00003172 frame_header.blocksize = encoder->protected_->blocksize;
3173 frame_header.sample_rate = encoder->protected_->sample_rate;
3174 frame_header.channels = encoder->protected_->channels;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003175 frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */
Josh Coalsonfa697a92001-08-16 20:07:29 +00003176 frame_header.bits_per_sample = encoder->protected_->bits_per_sample;
Josh Coalsonb3347bd2001-07-16 18:06:41 +00003177 frame_header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
Josh Coalsonfa697a92001-08-16 20:07:29 +00003178 frame_header.number.frame_number = encoder->private_->current_frame_number;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003179
3180 /*
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003181 * Figure out what channel assignments to try
3182 */
Josh Coalsonfa697a92001-08-16 20:07:29 +00003183 if(encoder->protected_->do_mid_side_stereo) {
3184 if(encoder->protected_->loose_mid_side_stereo) {
3185 if(encoder->private_->loose_mid_side_stereo_frame_count == 0) {
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003186 do_independent = true;
3187 do_mid_side = true;
3188 }
3189 else {
Josh Coalsonfa697a92001-08-16 20:07:29 +00003190 do_independent = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT);
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003191 do_mid_side = !do_independent;
3192 }
3193 }
3194 else {
3195 do_independent = true;
3196 do_mid_side = true;
3197 }
3198 }
3199 else {
3200 do_independent = true;
3201 do_mid_side = false;
3202 }
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003203
Josh Coalson1b689822001-05-31 20:11:02 +00003204 FLAC__ASSERT(do_independent || do_mid_side);
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003205
3206 /*
Josh Coalson82b73242001-03-28 22:17:05 +00003207 * Check for wasted bits; set effective bps for each subframe
Josh Coalson859bc542001-03-27 22:22:27 +00003208 */
3209 if(do_independent) {
Josh Coalsonfa697a92001-08-16 20:07:29 +00003210 for(channel = 0; channel < encoder->protected_->channels; channel++) {
Josh Coalsonb7023aa2002-08-17 15:23:43 +00003211 const unsigned w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize);
Josh Coalsonfa697a92001-08-16 20:07:29 +00003212 encoder->private_->subframe_workspace[channel][0].wasted_bits = encoder->private_->subframe_workspace[channel][1].wasted_bits = w;
3213 encoder->private_->subframe_bps[channel] = encoder->protected_->bits_per_sample - w;
Josh Coalson82b73242001-03-28 22:17:05 +00003214 }
Josh Coalson859bc542001-03-27 22:22:27 +00003215 }
3216 if(do_mid_side) {
Josh Coalsonfa697a92001-08-16 20:07:29 +00003217 FLAC__ASSERT(encoder->protected_->channels == 2);
Josh Coalson82b73242001-03-28 22:17:05 +00003218 for(channel = 0; channel < 2; channel++) {
Josh Coalsonb7023aa2002-08-17 15:23:43 +00003219 const unsigned w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize);
Josh Coalsonfa697a92001-08-16 20:07:29 +00003220 encoder->private_->subframe_workspace_mid_side[channel][0].wasted_bits = encoder->private_->subframe_workspace_mid_side[channel][1].wasted_bits = w;
3221 encoder->private_->subframe_bps_mid_side[channel] = encoder->protected_->bits_per_sample - w + (channel==0? 0:1);
Josh Coalson82b73242001-03-28 22:17:05 +00003222 }
Josh Coalson859bc542001-03-27 22:22:27 +00003223 }
3224
3225 /*
Josh Coalson94e02cd2001-01-25 10:41:06 +00003226 * First do a normal encoding pass of each independent channel
3227 */
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003228 if(do_independent) {
Josh Coalsonfa697a92001-08-16 20:07:29 +00003229 for(channel = 0; channel < encoder->protected_->channels; channel++) {
Josh Coalson6fe72f72002-08-20 04:01:59 +00003230 if(!
3231 process_subframe_(
3232 encoder,
3233 min_partition_order,
3234 max_partition_order,
3235 precompute_partition_sums,
Josh Coalson6fe72f72002-08-20 04:01:59 +00003236 &frame_header,
3237 encoder->private_->subframe_bps[channel],
3238 encoder->private_->integer_signal[channel],
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003239#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson6fe72f72002-08-20 04:01:59 +00003240 encoder->private_->real_signal[channel],
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003241#endif
Josh Coalson6fe72f72002-08-20 04:01:59 +00003242 encoder->private_->subframe_workspace_ptr[channel],
3243 encoder->private_->partitioned_rice_contents_workspace_ptr[channel],
3244 encoder->private_->residual_workspace[channel],
3245 encoder->private_->best_subframe+channel,
3246 encoder->private_->best_subframe_bits+channel
3247 )
3248 )
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003249 return false;
3250 }
Josh Coalson94e02cd2001-01-25 10:41:06 +00003251 }
3252
3253 /*
3254 * Now do mid and side channels if requested
3255 */
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003256 if(do_mid_side) {
Josh Coalsonfa697a92001-08-16 20:07:29 +00003257 FLAC__ASSERT(encoder->protected_->channels == 2);
Josh Coalson94e02cd2001-01-25 10:41:06 +00003258
3259 for(channel = 0; channel < 2; channel++) {
Josh Coalson6fe72f72002-08-20 04:01:59 +00003260 if(!
3261 process_subframe_(
3262 encoder,
3263 min_partition_order,
3264 max_partition_order,
3265 precompute_partition_sums,
Josh Coalson6fe72f72002-08-20 04:01:59 +00003266 &frame_header,
3267 encoder->private_->subframe_bps_mid_side[channel],
3268 encoder->private_->integer_signal_mid_side[channel],
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003269#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson6fe72f72002-08-20 04:01:59 +00003270 encoder->private_->real_signal_mid_side[channel],
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003271#endif
Josh Coalson6fe72f72002-08-20 04:01:59 +00003272 encoder->private_->subframe_workspace_ptr_mid_side[channel],
3273 encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[channel],
3274 encoder->private_->residual_workspace_mid_side[channel],
3275 encoder->private_->best_subframe_mid_side+channel,
3276 encoder->private_->best_subframe_bits_mid_side+channel
3277 )
3278 )
Josh Coalson94e02cd2001-01-25 10:41:06 +00003279 return false;
3280 }
3281 }
3282
3283 /*
3284 * Compose the frame bitbuffer
3285 */
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003286 if(do_mid_side) {
Josh Coalson82b73242001-03-28 22:17:05 +00003287 unsigned left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */
3288 FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003289 FLAC__ChannelAssignment channel_assignment;
3290
Josh Coalsonfa697a92001-08-16 20:07:29 +00003291 FLAC__ASSERT(encoder->protected_->channels == 2);
Josh Coalson94e02cd2001-01-25 10:41:06 +00003292
Josh Coalsonfa697a92001-08-16 20:07:29 +00003293 if(encoder->protected_->loose_mid_side_stereo && encoder->private_->loose_mid_side_stereo_frame_count > 0) {
3294 channel_assignment = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT? FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT : FLAC__CHANNEL_ASSIGNMENT_MID_SIDE);
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003295 }
3296 else {
3297 unsigned bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */
3298 unsigned min_bits;
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003299 int ca;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003300
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003301 FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT == 0);
3302 FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE == 1);
3303 FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE == 2);
3304 FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_MID_SIDE == 3);
Josh Coalson1b689822001-05-31 20:11:02 +00003305 FLAC__ASSERT(do_independent && do_mid_side);
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003306
3307 /* We have to figure out which channel assignent results in the smallest frame */
Josh Coalsonfa697a92001-08-16 20:07:29 +00003308 bits[FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT] = encoder->private_->best_subframe_bits [0] + encoder->private_->best_subframe_bits [1];
3309 bits[FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE ] = encoder->private_->best_subframe_bits [0] + encoder->private_->best_subframe_bits_mid_side[1];
3310 bits[FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE ] = encoder->private_->best_subframe_bits [1] + encoder->private_->best_subframe_bits_mid_side[1];
3311 bits[FLAC__CHANNEL_ASSIGNMENT_MID_SIDE ] = encoder->private_->best_subframe_bits_mid_side[0] + encoder->private_->best_subframe_bits_mid_side[1];
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003312
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003313 channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
3314 min_bits = bits[channel_assignment];
3315 for(ca = 1; ca <= 3; ca++) {
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003316 if(bits[ca] < min_bits) {
3317 min_bits = bits[ca];
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003318 channel_assignment = (FLAC__ChannelAssignment)ca;
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003319 }
Josh Coalson94e02cd2001-01-25 10:41:06 +00003320 }
3321 }
3322
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003323 frame_header.channel_assignment = channel_assignment;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003324
Josh Coalsond0edb972006-10-07 06:50:08 +00003325 if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) {
Josh Coalsonfa697a92001-08-16 20:07:29 +00003326 encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003327 return false;
3328 }
3329
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003330 switch(channel_assignment) {
Josh Coalson94e02cd2001-01-25 10:41:06 +00003331 case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
Josh Coalsonfa697a92001-08-16 20:07:29 +00003332 left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]];
3333 right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]];
Josh Coalson94e02cd2001-01-25 10:41:06 +00003334 break;
3335 case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
Josh Coalsonfa697a92001-08-16 20:07:29 +00003336 left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]];
3337 right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
Josh Coalson94e02cd2001-01-25 10:41:06 +00003338 break;
3339 case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
Josh Coalsonfa697a92001-08-16 20:07:29 +00003340 left_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
3341 right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]];
Josh Coalson94e02cd2001-01-25 10:41:06 +00003342 break;
3343 case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
Josh Coalsonfa697a92001-08-16 20:07:29 +00003344 left_subframe = &encoder->private_->subframe_workspace_mid_side[0][encoder->private_->best_subframe_mid_side[0]];
3345 right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
Josh Coalson94e02cd2001-01-25 10:41:06 +00003346 break;
3347 default:
Josh Coalson1b689822001-05-31 20:11:02 +00003348 FLAC__ASSERT(0);
Josh Coalson94e02cd2001-01-25 10:41:06 +00003349 }
Josh Coalson82b73242001-03-28 22:17:05 +00003350
3351 switch(channel_assignment) {
3352 case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
Josh Coalsonfa697a92001-08-16 20:07:29 +00003353 left_bps = encoder->private_->subframe_bps [0];
3354 right_bps = encoder->private_->subframe_bps [1];
Josh Coalson82b73242001-03-28 22:17:05 +00003355 break;
3356 case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
Josh Coalsonfa697a92001-08-16 20:07:29 +00003357 left_bps = encoder->private_->subframe_bps [0];
3358 right_bps = encoder->private_->subframe_bps_mid_side[1];
Josh Coalson82b73242001-03-28 22:17:05 +00003359 break;
3360 case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
Josh Coalsonfa697a92001-08-16 20:07:29 +00003361 left_bps = encoder->private_->subframe_bps_mid_side[1];
3362 right_bps = encoder->private_->subframe_bps [1];
Josh Coalson82b73242001-03-28 22:17:05 +00003363 break;
3364 case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
Josh Coalsonfa697a92001-08-16 20:07:29 +00003365 left_bps = encoder->private_->subframe_bps_mid_side[0];
3366 right_bps = encoder->private_->subframe_bps_mid_side[1];
Josh Coalson82b73242001-03-28 22:17:05 +00003367 break;
3368 default:
Josh Coalson1b689822001-05-31 20:11:02 +00003369 FLAC__ASSERT(0);
Josh Coalson82b73242001-03-28 22:17:05 +00003370 }
3371
3372 /* note that encoder_add_subframe_ sets the state for us in case of an error */
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003373 if(!add_subframe_(encoder, frame_header.blocksize, left_bps , left_subframe , encoder->private_->frame))
Josh Coalson82b73242001-03-28 22:17:05 +00003374 return false;
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003375 if(!add_subframe_(encoder, frame_header.blocksize, right_bps, right_subframe, encoder->private_->frame))
Josh Coalson82b73242001-03-28 22:17:05 +00003376 return false;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003377 }
3378 else {
Josh Coalsond0edb972006-10-07 06:50:08 +00003379 if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) {
Josh Coalsonfa697a92001-08-16 20:07:29 +00003380 encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003381 return false;
3382 }
3383
Josh Coalsonfa697a92001-08-16 20:07:29 +00003384 for(channel = 0; channel < encoder->protected_->channels; channel++) {
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003385 if(!add_subframe_(encoder, frame_header.blocksize, encoder->private_->subframe_bps[channel], &encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]], encoder->private_->frame)) {
Josh Coalson94e02cd2001-01-25 10:41:06 +00003386 /* the above function sets the state for us in case of an error */
3387 return false;
3388 }
3389 }
3390 }
3391
Josh Coalsonfa697a92001-08-16 20:07:29 +00003392 if(encoder->protected_->loose_mid_side_stereo) {
3393 encoder->private_->loose_mid_side_stereo_frame_count++;
3394 if(encoder->private_->loose_mid_side_stereo_frame_count >= encoder->private_->loose_mid_side_stereo_frames)
3395 encoder->private_->loose_mid_side_stereo_frame_count = 0;
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003396 }
3397
Josh Coalsonfa697a92001-08-16 20:07:29 +00003398 encoder->private_->last_channel_assignment = frame_header.channel_assignment;
Josh Coalsonb5e60e52001-01-28 09:27:27 +00003399
Josh Coalson94e02cd2001-01-25 10:41:06 +00003400 return true;
3401}
3402
Josh Coalson6fe72f72002-08-20 04:01:59 +00003403FLAC__bool process_subframe_(
3404 FLAC__StreamEncoder *encoder,
3405 unsigned min_partition_order,
3406 unsigned max_partition_order,
3407 FLAC__bool precompute_partition_sums,
Josh Coalson6fe72f72002-08-20 04:01:59 +00003408 const FLAC__FrameHeader *frame_header,
3409 unsigned subframe_bps,
3410 const FLAC__int32 integer_signal[],
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003411#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson6fe72f72002-08-20 04:01:59 +00003412 const FLAC__real real_signal[],
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003413#endif
Josh Coalson6fe72f72002-08-20 04:01:59 +00003414 FLAC__Subframe *subframe[2],
3415 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
3416 FLAC__int32 *residual[2],
3417 unsigned *best_subframe,
3418 unsigned *best_bits
3419)
Josh Coalson94e02cd2001-01-25 10:41:06 +00003420{
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003421#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson09758432004-10-20 00:21:50 +00003422 FLAC__float fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1];
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003423#else
3424 FLAC__fixedpoint fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1];
3425#endif
3426#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson09758432004-10-20 00:21:50 +00003427 FLAC__double lpc_residual_bits_per_sample;
Josh Coalsonfa697a92001-08-16 20:07:29 +00003428 FLAC__real autoc[FLAC__MAX_LPC_ORDER+1]; /* WATCHOUT: the size is important even though encoder->protected_->max_lpc_order might be less; some asm routines need all the space */
Josh Coalson09758432004-10-20 00:21:50 +00003429 FLAC__double lpc_error[FLAC__MAX_LPC_ORDER];
Josh Coalson94e02cd2001-01-25 10:41:06 +00003430 unsigned min_lpc_order, max_lpc_order, lpc_order;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003431 unsigned min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003432#endif
3433 unsigned min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003434 unsigned rice_parameter;
3435 unsigned _candidate_bits, _best_bits;
3436 unsigned _best_subframe;
3437
3438 /* verbatim subframe is the baseline against which we measure other compressed subframes */
3439 _best_subframe = 0;
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003440 if(encoder->private_->disable_verbatim_subframes && frame_header->blocksize >= FLAC__MAX_FIXED_ORDER)
3441 _best_bits = UINT_MAX;
3442 else
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003443 _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
Josh Coalson94e02cd2001-01-25 10:41:06 +00003444
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003445 if(frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) {
3446 unsigned signal_is_constant = false;
Josh Coalsonfa697a92001-08-16 20:07:29 +00003447 guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor(integer_signal+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample);
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003448 /* check for constant subframe */
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003449 if(
3450 !encoder->private_->disable_constant_subframes &&
3451#ifndef FLAC__INTEGER_ONLY_LIBRARY
3452 fixed_residual_bits_per_sample[1] == 0.0
3453#else
3454 fixed_residual_bits_per_sample[1] == FLAC__FP_ZERO
3455#endif
3456 ) {
3457 /* the above means it's possible all samples are the same value; now double-check it: */
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003458 unsigned i;
3459 signal_is_constant = true;
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003460 for(i = 1; i < frame_header->blocksize; i++) {
Josh Coalson94e02cd2001-01-25 10:41:06 +00003461 if(integer_signal[0] != integer_signal[i]) {
3462 signal_is_constant = false;
3463 break;
3464 }
3465 }
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003466 }
3467 if(signal_is_constant) {
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003468 _candidate_bits = evaluate_constant_subframe_(encoder, integer_signal[0], frame_header->blocksize, subframe_bps, subframe[!_best_subframe]);
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003469 if(_candidate_bits < _best_bits) {
3470 _best_subframe = !_best_subframe;
3471 _best_bits = _candidate_bits;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003472 }
3473 }
3474 else {
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003475 if(!encoder->private_->disable_fixed_subframes || (encoder->protected_->max_lpc_order == 0 && _best_bits == UINT_MAX)) {
3476 /* encode fixed */
3477 if(encoder->protected_->do_exhaustive_model_search) {
3478 min_fixed_order = 0;
3479 max_fixed_order = FLAC__MAX_FIXED_ORDER;
Josh Coalson8395d022001-07-12 21:25:22 +00003480 }
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003481 else {
3482 min_fixed_order = max_fixed_order = guess_fixed_order;
3483 }
3484 for(fixed_order = min_fixed_order; fixed_order <= max_fixed_order; fixed_order++) {
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003485#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson09758432004-10-20 00:21:50 +00003486 if(fixed_residual_bits_per_sample[fixed_order] >= (FLAC__float)subframe_bps)
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003487 continue; /* don't even try */
3488 rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > 0.0)? (unsigned)(fixed_residual_bits_per_sample[fixed_order]+0.5) : 0; /* 0.5 is for rounding */
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003489#else
3490 if(FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]) >= (int)subframe_bps)
3491 continue; /* don't even try */
3492 rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > FLAC__FP_ZERO)? (unsigned)FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]+FLAC__FP_ONE_HALF) : 0; /* 0.5 is for rounding */
3493#endif
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003494 rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003495 if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
3496#ifdef DEBUG_VERBOSE
3497 fprintf(stderr, "clipping rice_parameter (%u -> %u) @0\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
3498#endif
3499 rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
3500 }
3501 _candidate_bits =
3502 evaluate_fixed_subframe_(
3503 encoder,
3504 integer_signal,
3505 residual[!_best_subframe],
3506 encoder->private_->abs_residual,
3507 encoder->private_->abs_residual_partition_sums,
3508 encoder->private_->raw_bits_per_partition,
3509 frame_header->blocksize,
3510 subframe_bps,
3511 fixed_order,
3512 rice_parameter,
3513 min_partition_order,
3514 max_partition_order,
3515 precompute_partition_sums,
3516 encoder->protected_->do_escape_coding,
3517 encoder->protected_->rice_parameter_search_dist,
3518 subframe[!_best_subframe],
3519 partitioned_rice_contents[!_best_subframe]
3520 );
3521 if(_candidate_bits < _best_bits) {
3522 _best_subframe = !_best_subframe;
3523 _best_bits = _candidate_bits;
3524 }
Josh Coalson94e02cd2001-01-25 10:41:06 +00003525 }
3526 }
3527
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003528#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson94e02cd2001-01-25 10:41:06 +00003529 /* encode lpc */
Josh Coalsonfa697a92001-08-16 20:07:29 +00003530 if(encoder->protected_->max_lpc_order > 0) {
3531 if(encoder->protected_->max_lpc_order >= frame_header->blocksize)
Josh Coalson94e02cd2001-01-25 10:41:06 +00003532 max_lpc_order = frame_header->blocksize-1;
3533 else
Josh Coalsonfa697a92001-08-16 20:07:29 +00003534 max_lpc_order = encoder->protected_->max_lpc_order;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003535 if(max_lpc_order > 0) {
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00003536 unsigned a;
3537 for (a = 0; a < encoder->protected_->num_apodizations; a++) {
Josh Coalson0abc7352006-05-03 00:13:25 +00003538 FLAC__lpc_window_data(real_signal, encoder->private_->window[a], encoder->private_->windowed_signal, frame_header->blocksize);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00003539 encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_signal, frame_header->blocksize, max_lpc_order+1, autoc);
3540 /* if autoc[0] == 0.0, the signal is constant and we usually won't get here, but it can happen */
3541 if(autoc[0] != 0.0) {
Josh Coalson32b9bae2006-11-27 16:27:41 +00003542 FLAC__lpc_compute_lp_coefficients(autoc, &max_lpc_order, encoder->private_->lp_coeff, lpc_error);
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00003543 if(encoder->protected_->do_exhaustive_model_search) {
3544 min_lpc_order = 1;
Josh Coalsonc9c0d132002-10-04 05:29:05 +00003545 }
3546 else {
Josh Coalsondf598452006-04-28 00:13:34 +00003547 const unsigned guess_lpc_order =
3548 FLAC__lpc_compute_best_order(
3549 lpc_error,
3550 max_lpc_order,
3551 frame_header->blocksize,
3552 subframe_bps + (
3553 encoder->protected_->do_qlp_coeff_prec_search?
3554 FLAC__MIN_QLP_COEFF_PRECISION : /* have to guess; use the min possible size to avoid accidentally favoring lower orders */
3555 encoder->protected_->qlp_coeff_precision
3556 )
3557 );
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00003558 min_lpc_order = max_lpc_order = guess_lpc_order;
Josh Coalsonc9c0d132002-10-04 05:29:05 +00003559 }
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00003560 for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order; lpc_order++) {
3561 lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize-lpc_order);
3562 if(lpc_residual_bits_per_sample >= (FLAC__double)subframe_bps)
3563 continue; /* don't even try */
3564 rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (unsigned)(lpc_residual_bits_per_sample+0.5) : 0; /* 0.5 is for rounding */
3565 rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */
3566 if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
Josh Coalsondf598452006-04-28 00:13:34 +00003567#ifdef DEBUG_VERBOSE
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00003568 fprintf(stderr, "clipping rice_parameter (%u -> %u) @1\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
Josh Coalsondf598452006-04-28 00:13:34 +00003569#endif
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00003570 rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
3571 }
3572 if(encoder->protected_->do_qlp_coeff_prec_search) {
3573 min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION;
Josh Coalsondf598452006-04-28 00:13:34 +00003574 /* try to ensure a 32-bit datapath throughout for 16bps(+1bps for side channel) or less */
3575 if(subframe_bps <= 17) {
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00003576 max_qlp_coeff_precision = min(32 - subframe_bps - lpc_order, FLAC__MAX_QLP_COEFF_PRECISION);
Josh Coalsondf598452006-04-28 00:13:34 +00003577 max_qlp_coeff_precision = max(max_qlp_coeff_precision, min_qlp_coeff_precision);
3578 }
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00003579 else
3580 max_qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION;
3581 }
3582 else {
3583 min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->protected_->qlp_coeff_precision;
3584 }
3585 for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) {
3586 _candidate_bits =
3587 evaluate_lpc_subframe_(
3588 encoder,
3589 integer_signal,
3590 residual[!_best_subframe],
3591 encoder->private_->abs_residual,
3592 encoder->private_->abs_residual_partition_sums,
3593 encoder->private_->raw_bits_per_partition,
3594 encoder->private_->lp_coeff[lpc_order-1],
3595 frame_header->blocksize,
3596 subframe_bps,
3597 lpc_order,
3598 qlp_coeff_precision,
3599 rice_parameter,
3600 min_partition_order,
3601 max_partition_order,
3602 precompute_partition_sums,
3603 encoder->protected_->do_escape_coding,
3604 encoder->protected_->rice_parameter_search_dist,
3605 subframe[!_best_subframe],
3606 partitioned_rice_contents[!_best_subframe]
Josh Coalsonbf0f52c2006-04-25 06:38:43 +00003607 );
3608 if(_candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */
3609 if(_candidate_bits < _best_bits) {
3610 _best_subframe = !_best_subframe;
3611 _best_bits = _candidate_bits;
3612 }
Josh Coalsonf4ce50b2001-02-28 23:45:15 +00003613 }
Josh Coalson94e02cd2001-01-25 10:41:06 +00003614 }
3615 }
3616 }
3617 }
3618 }
3619 }
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003620#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
Josh Coalson94e02cd2001-01-25 10:41:06 +00003621 }
3622 }
3623
Josh Coalson72695802002-10-11 06:25:16 +00003624 /* under rare circumstances this can happen when all but lpc subframe types are disabled: */
3625 if(_best_bits == UINT_MAX) {
3626 FLAC__ASSERT(_best_subframe == 0);
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003627 _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
Josh Coalson72695802002-10-11 06:25:16 +00003628 }
Josh Coalsone6b3bbe2002-10-08 06:03:25 +00003629
Josh Coalson94e02cd2001-01-25 10:41:06 +00003630 *best_subframe = _best_subframe;
3631 *best_bits = _best_bits;
3632
3633 return true;
3634}
3635
Josh Coalson6fe72f72002-08-20 04:01:59 +00003636FLAC__bool add_subframe_(
3637 FLAC__StreamEncoder *encoder,
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003638 unsigned blocksize,
Josh Coalson6fe72f72002-08-20 04:01:59 +00003639 unsigned subframe_bps,
3640 const FLAC__Subframe *subframe,
3641 FLAC__BitBuffer *frame
3642)
Josh Coalson94e02cd2001-01-25 10:41:06 +00003643{
3644 switch(subframe->type) {
3645 case FLAC__SUBFRAME_TYPE_CONSTANT:
Josh Coalson82b73242001-03-28 22:17:05 +00003646 if(!FLAC__subframe_add_constant(&(subframe->data.constant), subframe_bps, subframe->wasted_bits, frame)) {
Josh Coalson6b21f662006-09-13 01:42:27 +00003647 encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003648 return false;
3649 }
3650 break;
3651 case FLAC__SUBFRAME_TYPE_FIXED:
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003652 if(!FLAC__subframe_add_fixed(&(subframe->data.fixed), blocksize - subframe->data.fixed.order, subframe_bps, subframe->wasted_bits, frame)) {
Josh Coalson6b21f662006-09-13 01:42:27 +00003653 encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003654 return false;
3655 }
3656 break;
3657 case FLAC__SUBFRAME_TYPE_LPC:
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003658 if(!FLAC__subframe_add_lpc(&(subframe->data.lpc), blocksize - subframe->data.lpc.order, subframe_bps, subframe->wasted_bits, frame)) {
Josh Coalson6b21f662006-09-13 01:42:27 +00003659 encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003660 return false;
3661 }
3662 break;
3663 case FLAC__SUBFRAME_TYPE_VERBATIM:
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003664 if(!FLAC__subframe_add_verbatim(&(subframe->data.verbatim), blocksize, subframe_bps, subframe->wasted_bits, frame)) {
Josh Coalson6b21f662006-09-13 01:42:27 +00003665 encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003666 return false;
3667 }
3668 break;
3669 default:
Josh Coalson1b689822001-05-31 20:11:02 +00003670 FLAC__ASSERT(0);
Josh Coalson94e02cd2001-01-25 10:41:06 +00003671 }
3672
3673 return true;
3674}
3675
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003676#define SPOTCHECK_ESTIMATE 0 //@@@@@@@@@
3677#if SPOTCHECK_ESTIMATE
3678static void spotcheck_subframe_estimate_(
3679 FLAC__StreamEncoder *encoder,
3680 unsigned blocksize,
3681 unsigned subframe_bps,
3682 const FLAC__Subframe *subframe,
3683 unsigned estimate
3684)
3685{
3686 FLAC__bool ret;
3687 FLAC__BitBuffer *frame = FLAC__bitbuffer_new();
3688 if(frame == 0) {
3689 fprintf(stderr, "EST: can't allocate frame\n");
3690 return;
3691 }
3692 if(!FLAC__bitbuffer_init(frame)) {
3693 fprintf(stderr, "EST: can't init frame\n");
3694 return;
3695 }
3696 ret = add_subframe_(encoder, blocksize, subframe_bps, subframe, frame);
3697 FLAC__ASSERT(ret);
3698 {
3699 const unsigned actual = FLAC__bitbuffer_get_input_bits_unconsumed(frame);
3700 if(estimate != actual)
3701 fprintf(stderr, "EST: bad, frame#%u sub#%%d type=%8s est=%u, actual=%u, delta=%d\n", encoder->private_->current_frame_number, FLAC__SubframeTypeString[subframe->type], estimate, actual, (int)actual-(int)estimate);
3702 }
3703 FLAC__bitbuffer_delete(frame);
3704}
3705#endif
3706
Josh Coalson6fe72f72002-08-20 04:01:59 +00003707unsigned evaluate_constant_subframe_(
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003708 FLAC__StreamEncoder *encoder,
Josh Coalson6fe72f72002-08-20 04:01:59 +00003709 const FLAC__int32 signal,
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003710 unsigned blocksize,
Josh Coalson6fe72f72002-08-20 04:01:59 +00003711 unsigned subframe_bps,
3712 FLAC__Subframe *subframe
3713)
Josh Coalson94e02cd2001-01-25 10:41:06 +00003714{
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003715 unsigned estimate;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003716 subframe->type = FLAC__SUBFRAME_TYPE_CONSTANT;
3717 subframe->data.constant.value = signal;
3718
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003719 estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe_bps;
3720
3721#if SPOTCHECK_ESTIMATE
3722 spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
3723#else
3724 (void)encoder, (void)blocksize;
3725#endif
3726
3727 return estimate;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003728}
3729
Josh Coalson6fe72f72002-08-20 04:01:59 +00003730unsigned evaluate_fixed_subframe_(
3731 FLAC__StreamEncoder *encoder,
3732 const FLAC__int32 signal[],
3733 FLAC__int32 residual[],
3734 FLAC__uint32 abs_residual[],
3735 FLAC__uint64 abs_residual_partition_sums[],
3736 unsigned raw_bits_per_partition[],
3737 unsigned blocksize,
3738 unsigned subframe_bps,
3739 unsigned order,
3740 unsigned rice_parameter,
3741 unsigned min_partition_order,
3742 unsigned max_partition_order,
3743 FLAC__bool precompute_partition_sums,
3744 FLAC__bool do_escape_coding,
3745 unsigned rice_parameter_search_dist,
3746 FLAC__Subframe *subframe,
3747 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
3748)
Josh Coalson94e02cd2001-01-25 10:41:06 +00003749{
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003750 unsigned i, residual_bits, estimate;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003751 const unsigned residual_samples = blocksize - order;
3752
3753 FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual);
3754
3755 subframe->type = FLAC__SUBFRAME_TYPE_FIXED;
3756
3757 subframe->data.fixed.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
Josh Coalsona37ba462002-08-19 21:36:39 +00003758 subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003759 subframe->data.fixed.residual = residual;
3760
Josh Coalson6fe72f72002-08-20 04:01:59 +00003761 residual_bits =
3762 find_best_partition_order_(
3763 encoder->private_,
3764 residual,
3765 abs_residual,
3766 abs_residual_partition_sums,
3767 raw_bits_per_partition,
3768 residual_samples,
3769 order,
3770 rice_parameter,
3771 min_partition_order,
3772 max_partition_order,
3773 precompute_partition_sums,
3774 do_escape_coding,
3775 rice_parameter_search_dist,
3776 &subframe->data.fixed.entropy_coding_method.data.partitioned_rice
3777 );
Josh Coalson94e02cd2001-01-25 10:41:06 +00003778
3779 subframe->data.fixed.order = order;
3780 for(i = 0; i < order; i++)
3781 subframe->data.fixed.warmup[i] = signal[i];
3782
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003783 estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + (order * subframe_bps) + residual_bits;
3784
3785#if SPOTCHECK_ESTIMATE
3786 spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
3787#endif
3788
3789 return estimate;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003790}
3791
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003792#ifndef FLAC__INTEGER_ONLY_LIBRARY
Josh Coalson6fe72f72002-08-20 04:01:59 +00003793unsigned evaluate_lpc_subframe_(
3794 FLAC__StreamEncoder *encoder,
3795 const FLAC__int32 signal[],
3796 FLAC__int32 residual[],
3797 FLAC__uint32 abs_residual[],
3798 FLAC__uint64 abs_residual_partition_sums[],
3799 unsigned raw_bits_per_partition[],
3800 const FLAC__real lp_coeff[],
3801 unsigned blocksize,
3802 unsigned subframe_bps,
3803 unsigned order,
3804 unsigned qlp_coeff_precision,
3805 unsigned rice_parameter,
3806 unsigned min_partition_order,
3807 unsigned max_partition_order,
3808 FLAC__bool precompute_partition_sums,
3809 FLAC__bool do_escape_coding,
3810 unsigned rice_parameter_search_dist,
3811 FLAC__Subframe *subframe,
3812 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
3813)
Josh Coalson94e02cd2001-01-25 10:41:06 +00003814{
Josh Coalson77e3f312001-06-23 03:03:24 +00003815 FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003816 unsigned i, residual_bits, estimate;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003817 int quantization, ret;
3818 const unsigned residual_samples = blocksize - order;
3819
Josh Coalson20ac2c12002-08-30 05:47:14 +00003820 /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps streams */
3821 if(subframe_bps <= 16) {
3822 FLAC__ASSERT(order > 0);
3823 FLAC__ASSERT(order <= FLAC__MAX_LPC_ORDER);
3824 qlp_coeff_precision = min(qlp_coeff_precision, 32 - subframe_bps - FLAC__bitmath_ilog2(order));
3825 }
3826
Josh Coalsonc9c0d132002-10-04 05:29:05 +00003827 ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, qlp_coeff, &quantization);
Josh Coalson94e02cd2001-01-25 10:41:06 +00003828 if(ret != 0)
3829 return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */
3830
Josh Coalsonfb9d18f2002-10-21 07:04:07 +00003831 if(subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
3832 if(subframe_bps <= 16 && qlp_coeff_precision <= 16)
3833 encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
3834 else
3835 encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
Josh Coalsonc9c0d132002-10-04 05:29:05 +00003836 else
3837 encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
Josh Coalson94e02cd2001-01-25 10:41:06 +00003838
3839 subframe->type = FLAC__SUBFRAME_TYPE_LPC;
3840
3841 subframe->data.lpc.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
Josh Coalsona37ba462002-08-19 21:36:39 +00003842 subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003843 subframe->data.lpc.residual = residual;
3844
Josh Coalson6fe72f72002-08-20 04:01:59 +00003845 residual_bits =
3846 find_best_partition_order_(
3847 encoder->private_,
3848 residual,
3849 abs_residual,
3850 abs_residual_partition_sums,
3851 raw_bits_per_partition,
3852 residual_samples,
3853 order,
3854 rice_parameter,
3855 min_partition_order,
3856 max_partition_order,
3857 precompute_partition_sums,
3858 do_escape_coding,
3859 rice_parameter_search_dist,
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003860 &subframe->data.lpc.entropy_coding_method.data.partitioned_rice
Josh Coalson6fe72f72002-08-20 04:01:59 +00003861 );
Josh Coalson94e02cd2001-01-25 10:41:06 +00003862
3863 subframe->data.lpc.order = order;
3864 subframe->data.lpc.qlp_coeff_precision = qlp_coeff_precision;
3865 subframe->data.lpc.quantization_level = quantization;
Josh Coalson77e3f312001-06-23 03:03:24 +00003866 memcpy(subframe->data.lpc.qlp_coeff, qlp_coeff, sizeof(FLAC__int32)*FLAC__MAX_LPC_ORDER);
Josh Coalson94e02cd2001-01-25 10:41:06 +00003867 for(i = 0; i < order; i++)
3868 subframe->data.lpc.warmup[i] = signal[i];
3869
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003870 estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)) + residual_bits;
3871
3872#if SPOTCHECK_ESTIMATE
3873 spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
3874#endif
3875
3876 return estimate;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003877}
Josh Coalson5f2b46d2004-11-09 01:34:01 +00003878#endif
Josh Coalson94e02cd2001-01-25 10:41:06 +00003879
Josh Coalson6fe72f72002-08-20 04:01:59 +00003880unsigned evaluate_verbatim_subframe_(
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003881 FLAC__StreamEncoder *encoder,
Josh Coalson6fe72f72002-08-20 04:01:59 +00003882 const FLAC__int32 signal[],
3883 unsigned blocksize,
3884 unsigned subframe_bps,
3885 FLAC__Subframe *subframe
3886)
Josh Coalson94e02cd2001-01-25 10:41:06 +00003887{
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003888 unsigned estimate;
3889
Josh Coalson94e02cd2001-01-25 10:41:06 +00003890 subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM;
3891
3892 subframe->data.verbatim.data = signal;
3893
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003894 estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + (blocksize * subframe_bps);
3895
3896#if SPOTCHECK_ESTIMATE
3897 spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
3898#else
3899 (void)encoder;
3900#endif
3901
3902 return estimate;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003903}
3904
Josh Coalson6fe72f72002-08-20 04:01:59 +00003905unsigned find_best_partition_order_(
3906 FLAC__StreamEncoderPrivate *private_,
3907 const FLAC__int32 residual[],
3908 FLAC__uint32 abs_residual[],
3909 FLAC__uint64 abs_residual_partition_sums[],
3910 unsigned raw_bits_per_partition[],
3911 unsigned residual_samples,
3912 unsigned predictor_order,
3913 unsigned rice_parameter,
3914 unsigned min_partition_order,
3915 unsigned max_partition_order,
3916 FLAC__bool precompute_partition_sums,
3917 FLAC__bool do_escape_coding,
3918 unsigned rice_parameter_search_dist,
3919 FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice
3920)
Josh Coalson94e02cd2001-01-25 10:41:06 +00003921{
Josh Coalson77e3f312001-06-23 03:03:24 +00003922 FLAC__int32 r;
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00003923 unsigned residual_bits, best_residual_bits = 0;
Josh Coalsonafcd8772001-04-18 22:59:25 +00003924 unsigned residual_sample;
Josh Coalson8084b052001-11-01 00:27:29 +00003925 unsigned best_parameters_index = 0;
Josh Coalsonb3347bd2001-07-16 18:06:41 +00003926 const unsigned blocksize = residual_samples + predictor_order;
Josh Coalson94e02cd2001-01-25 10:41:06 +00003927
Josh Coalson2051dd42001-04-12 22:22:34 +00003928 /* compute abs(residual) for use later */
3929 for(residual_sample = 0; residual_sample < residual_samples; residual_sample++) {
3930 r = residual[residual_sample];
Josh Coalson77e3f312001-06-23 03:03:24 +00003931 abs_residual[residual_sample] = (FLAC__uint32)(r<0? -r : r);
Josh Coalson2051dd42001-04-12 22:22:34 +00003932 }
3933
Josh Coalsonb7023aa2002-08-17 15:23:43 +00003934 max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(max_partition_order, blocksize, predictor_order);
Josh Coalsonb3347bd2001-07-16 18:06:41 +00003935 min_partition_order = min(min_partition_order, max_partition_order);
3936
Josh Coalson8395d022001-07-12 21:25:22 +00003937 if(precompute_partition_sums) {
3938 int partition_order;
3939 unsigned sum;
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00003940
Josh Coalsonf1eff452002-07-31 07:05:33 +00003941 precompute_partition_info_sums_(abs_residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order);
Josh Coalson8395d022001-07-12 21:25:22 +00003942
3943 if(do_escape_coding)
Josh Coalsonf1eff452002-07-31 07:05:33 +00003944 precompute_partition_info_escapes_(residual, raw_bits_per_partition, residual_samples, predictor_order, min_partition_order, max_partition_order);
Josh Coalson8395d022001-07-12 21:25:22 +00003945
3946 for(partition_order = (int)max_partition_order, sum = 0; partition_order >= (int)min_partition_order; partition_order--) {
Josh Coalson6fe72f72002-08-20 04:01:59 +00003947 if(!
3948 set_partitioned_rice_with_precompute_(
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003949#ifdef EXACT_RICE_BITS_CALCULATION
Josh Coalson6fe72f72002-08-20 04:01:59 +00003950 residual,
Josh Coalsonafcd8772001-04-18 22:59:25 +00003951#else
Josh Coalson6fe72f72002-08-20 04:01:59 +00003952 abs_residual,
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003953#endif
Josh Coalson6fe72f72002-08-20 04:01:59 +00003954 abs_residual_partition_sums+sum,
3955 raw_bits_per_partition+sum,
3956 residual_samples,
3957 predictor_order,
3958 rice_parameter,
3959 rice_parameter_search_dist,
3960 (unsigned)partition_order,
3961 do_escape_coding,
3962 &private_->partitioned_rice_contents_extra[!best_parameters_index],
3963 &residual_bits
3964 )
3965 )
Josh Coalson8395d022001-07-12 21:25:22 +00003966 {
Josh Coalsonb3347bd2001-07-16 18:06:41 +00003967 FLAC__ASSERT(best_residual_bits != 0);
3968 break;
Josh Coalson8395d022001-07-12 21:25:22 +00003969 }
3970 sum += 1u << partition_order;
3971 if(best_residual_bits == 0 || residual_bits < best_residual_bits) {
3972 best_residual_bits = residual_bits;
Josh Coalson8395d022001-07-12 21:25:22 +00003973 best_parameters_index = !best_parameters_index;
Josh Coalsonb7023aa2002-08-17 15:23:43 +00003974 best_partitioned_rice->order = partition_order;
Josh Coalson8395d022001-07-12 21:25:22 +00003975 }
Josh Coalsonafcd8772001-04-18 22:59:25 +00003976 }
3977 }
Josh Coalson8395d022001-07-12 21:25:22 +00003978 else {
3979 unsigned partition_order;
3980 for(partition_order = min_partition_order; partition_order <= max_partition_order; partition_order++) {
Josh Coalson6fe72f72002-08-20 04:01:59 +00003981 if(!
3982 set_partitioned_rice_(
3983 abs_residual,
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003984#ifdef EXACT_RICE_BITS_CALCULATION
Josh Coalson6fe72f72002-08-20 04:01:59 +00003985 residual,
Josh Coalsonafcd8772001-04-18 22:59:25 +00003986#endif
Josh Coalsonce1d07c2007-01-23 05:00:46 +00003987 residual_samples,
3988 predictor_order,
3989 rice_parameter,
3990 rice_parameter_search_dist,
3991 partition_order,
3992 &private_->partitioned_rice_contents_extra[!best_parameters_index],
3993 &residual_bits
3994 )
3995 )
Josh Coalson8395d022001-07-12 21:25:22 +00003996 {
3997 FLAC__ASSERT(best_residual_bits != 0);
3998 break;
3999 }
4000 if(best_residual_bits == 0 || residual_bits < best_residual_bits) {
4001 best_residual_bits = residual_bits;
Josh Coalson8395d022001-07-12 21:25:22 +00004002 best_parameters_index = !best_parameters_index;
Josh Coalsonb7023aa2002-08-17 15:23:43 +00004003 best_partitioned_rice->order = partition_order;
Josh Coalson8395d022001-07-12 21:25:22 +00004004 }
4005 }
4006 }
4007
Josh Coalsona37ba462002-08-19 21:36:39 +00004008 /*
Josh Coalson20ac2c12002-08-30 05:47:14 +00004009 * We are allowed to de-const the pointer based on our special knowledge;
Josh Coalsona37ba462002-08-19 21:36:39 +00004010 * it is const to the outside world.
4011 */
4012 {
4013 FLAC__EntropyCodingMethod_PartitionedRiceContents* best_partitioned_rice_contents = (FLAC__EntropyCodingMethod_PartitionedRiceContents*)best_partitioned_rice->contents;
4014 FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(best_partitioned_rice_contents, max(6, best_partitioned_rice->order));
4015 memcpy(best_partitioned_rice_contents->parameters, private_->partitioned_rice_contents_extra[best_parameters_index].parameters, sizeof(unsigned)*(1<<(best_partitioned_rice->order)));
4016 memcpy(best_partitioned_rice_contents->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, sizeof(unsigned)*(1<<(best_partitioned_rice->order)));
4017 }
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004018
4019 return best_residual_bits;
4020}
4021
Josh Coalson6fe72f72002-08-20 04:01:59 +00004022void precompute_partition_info_sums_(
4023 const FLAC__uint32 abs_residual[],
4024 FLAC__uint64 abs_residual_partition_sums[],
4025 unsigned residual_samples,
4026 unsigned predictor_order,
4027 unsigned min_partition_order,
4028 unsigned max_partition_order
4029)
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004030{
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004031 int partition_order;
Josh Coalsonaef013c2001-04-24 01:25:42 +00004032 unsigned from_partition, to_partition = 0;
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004033 const unsigned blocksize = residual_samples + predictor_order;
4034
Josh Coalsonaef013c2001-04-24 01:25:42 +00004035 /* first do max_partition_order */
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004036 for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) {
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004037 FLAC__uint64 abs_residual_partition_sum;
Josh Coalsonaef013c2001-04-24 01:25:42 +00004038 unsigned partition, partition_sample, partition_samples, residual_sample;
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004039 const unsigned partitions = 1u << partition_order;
4040 const unsigned default_partition_samples = blocksize >> partition_order;
4041
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004042 FLAC__ASSERT(default_partition_samples > predictor_order);
4043
4044 for(partition = residual_sample = 0; partition < partitions; partition++) {
4045 partition_samples = default_partition_samples;
4046 if(partition == 0)
4047 partition_samples -= predictor_order;
4048 abs_residual_partition_sum = 0;
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004049 for(partition_sample = 0; partition_sample < partition_samples; partition_sample++)
4050 abs_residual_partition_sum += abs_residual[residual_sample++];
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004051 abs_residual_partition_sums[partition] = abs_residual_partition_sum;
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004052 }
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004053 to_partition = partitions;
4054 break;
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004055 }
Josh Coalsonf76a3612001-04-18 02:28:11 +00004056
Josh Coalson8395d022001-07-12 21:25:22 +00004057 /* now merge partitions for lower orders */
Josh Coalson6bd17572001-05-25 19:02:01 +00004058 for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) {
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004059 FLAC__uint64 s;
Josh Coalsonaef013c2001-04-24 01:25:42 +00004060 unsigned i;
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004061 const unsigned partitions = 1u << partition_order;
4062 for(i = 0; i < partitions; i++) {
Josh Coalsonaef013c2001-04-24 01:25:42 +00004063 s = abs_residual_partition_sums[from_partition];
Josh Coalsonaef013c2001-04-24 01:25:42 +00004064 from_partition++;
Josh Coalsonaef013c2001-04-24 01:25:42 +00004065 abs_residual_partition_sums[to_partition] = s + abs_residual_partition_sums[from_partition];
Josh Coalsonaef013c2001-04-24 01:25:42 +00004066 from_partition++;
4067 to_partition++;
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004068 }
4069 }
Josh Coalson94e02cd2001-01-25 10:41:06 +00004070}
Josh Coalson8395d022001-07-12 21:25:22 +00004071
Josh Coalson6fe72f72002-08-20 04:01:59 +00004072void precompute_partition_info_escapes_(
4073 const FLAC__int32 residual[],
4074 unsigned raw_bits_per_partition[],
4075 unsigned residual_samples,
4076 unsigned predictor_order,
4077 unsigned min_partition_order,
4078 unsigned max_partition_order
4079)
Josh Coalson8395d022001-07-12 21:25:22 +00004080{
4081 int partition_order;
4082 unsigned from_partition, to_partition = 0;
4083 const unsigned blocksize = residual_samples + predictor_order;
4084
4085 /* first do max_partition_order */
4086 for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) {
4087 FLAC__int32 r, residual_partition_min, residual_partition_max;
4088 unsigned silog2_min, silog2_max;
4089 unsigned partition, partition_sample, partition_samples, residual_sample;
4090 const unsigned partitions = 1u << partition_order;
4091 const unsigned default_partition_samples = blocksize >> partition_order;
4092
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004093 FLAC__ASSERT(default_partition_samples > predictor_order);
4094
4095 for(partition = residual_sample = 0; partition < partitions; partition++) {
4096 partition_samples = default_partition_samples;
4097 if(partition == 0)
4098 partition_samples -= predictor_order;
4099 residual_partition_min = residual_partition_max = 0;
4100 for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) {
4101 r = residual[residual_sample];
4102 if(r < residual_partition_min)
4103 residual_partition_min = r;
4104 else if(r > residual_partition_max)
4105 residual_partition_max = r;
4106 residual_sample++;
Josh Coalson8395d022001-07-12 21:25:22 +00004107 }
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004108 silog2_min = FLAC__bitmath_silog2(residual_partition_min);
4109 silog2_max = FLAC__bitmath_silog2(residual_partition_max);
4110 raw_bits_per_partition[partition] = max(silog2_min, silog2_max);
Josh Coalson8395d022001-07-12 21:25:22 +00004111 }
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004112 to_partition = partitions;
Josh Coalson369a6da2006-10-10 00:37:48 +00004113 break; /*@@@ yuck, should remove the 'for' loop instead */
Josh Coalson8395d022001-07-12 21:25:22 +00004114 }
4115
4116 /* now merge partitions for lower orders */
4117 for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) {
4118 unsigned m;
4119 unsigned i;
4120 const unsigned partitions = 1u << partition_order;
4121 for(i = 0; i < partitions; i++) {
4122 m = raw_bits_per_partition[from_partition];
4123 from_partition++;
4124 raw_bits_per_partition[to_partition] = max(m, raw_bits_per_partition[from_partition]);
4125 from_partition++;
4126 to_partition++;
4127 }
4128 }
4129}
Josh Coalson94e02cd2001-01-25 10:41:06 +00004130
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004131#ifdef EXACT_RICE_BITS_CALCULATION
4132static __inline unsigned count_rice_bits_(
4133 const unsigned rice_parameter,
4134 const unsigned partition_samples,
4135 const FLAC__int32 *residual
Josh Coalson6fe72f72002-08-20 04:01:59 +00004136)
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004137{
4138 unsigned i, partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
4139 for(i = 0; i < partition_samples; i++)
4140 partition_bits += FLAC__bitbuffer_rice_bits(residual[i], rice_parameter);
4141 return partition_bits;
4142}
Josh Coalson8395d022001-07-12 21:25:22 +00004143#else
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004144static __inline unsigned count_rice_bits_(
4145 const unsigned rice_parameter,
4146 const unsigned partition_samples,
4147 const FLAC__uint32 *abs_residual
4148)
4149{
4150 const unsigned rice_parameter_estimate = rice_parameter-1;
4151 unsigned i, partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + (1+rice_parameter) * partition_samples;
4152 for(i = 0; i < partition_samples; i++)
Josh Coalson792c10d2007-01-24 04:25:03 +00004153 partition_bits += (abs_residual[i] >> rice_parameter_estimate);
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004154 return partition_bits;
4155}
4156#endif
4157
Josh Coalson6fe72f72002-08-20 04:01:59 +00004158FLAC__bool set_partitioned_rice_(
4159 const FLAC__uint32 abs_residual[],
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004160#ifdef EXACT_RICE_BITS_CALCULATION
4161 const FLAC__int32 residual[],
4162#endif
Josh Coalson6fe72f72002-08-20 04:01:59 +00004163 const unsigned residual_samples,
4164 const unsigned predictor_order,
4165 const unsigned suggested_rice_parameter,
4166 const unsigned rice_parameter_search_dist,
4167 const unsigned partition_order,
4168 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
4169 unsigned *bits
4170)
Josh Coalson94e02cd2001-01-25 10:41:06 +00004171{
Josh Coalson034dfab2001-04-27 19:10:23 +00004172 unsigned rice_parameter, partition_bits;
Josh Coalson94e02cd2001-01-25 10:41:06 +00004173 unsigned bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN;
Josh Coalsonb7023aa2002-08-17 15:23:43 +00004174 unsigned *parameters;
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004175#ifdef ENABLE_RICE_PARAMETER_SEARCH
4176 unsigned best_partition_bits, best_rice_parameter = 0;
4177 unsigned min_rice_parameter, max_rice_parameter;
4178#else
4179 (void)rice_parameter_search_dist;
4180#endif
Josh Coalson94e02cd2001-01-25 10:41:06 +00004181
Josh Coalson1b689822001-05-31 20:11:02 +00004182 FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER);
Josh Coalson2051dd42001-04-12 22:22:34 +00004183
Josh Coalsona37ba462002-08-19 21:36:39 +00004184 FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order));
4185 parameters = partitioned_rice_contents->parameters;
Josh Coalsonb7023aa2002-08-17 15:23:43 +00004186
Josh Coalson94e02cd2001-01-25 10:41:06 +00004187 if(partition_order == 0) {
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004188#ifdef ENABLE_RICE_PARAMETER_SEARCH
4189 best_partition_bits = 0xffffffff;
Josh Coalson60f77d72001-04-25 02:16:36 +00004190 if(rice_parameter_search_dist) {
Josh Coalson034dfab2001-04-27 19:10:23 +00004191 if(suggested_rice_parameter < rice_parameter_search_dist)
Josh Coalson60f77d72001-04-25 02:16:36 +00004192 min_rice_parameter = 0;
4193 else
Josh Coalson034dfab2001-04-27 19:10:23 +00004194 min_rice_parameter = suggested_rice_parameter - rice_parameter_search_dist;
4195 max_rice_parameter = suggested_rice_parameter + rice_parameter_search_dist;
Josh Coalson8395d022001-07-12 21:25:22 +00004196 if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
Josh Coalson31209492001-07-18 23:43:01 +00004197#ifdef DEBUG_VERBOSE
Josh Coalson8395d022001-07-12 21:25:22 +00004198 fprintf(stderr, "clipping rice_parameter (%u -> %u) @2\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
4199#endif
Josh Coalson60f77d72001-04-25 02:16:36 +00004200 max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
Josh Coalson8395d022001-07-12 21:25:22 +00004201 }
4202 }
4203 else
4204 min_rice_parameter = max_rice_parameter = suggested_rice_parameter;
4205
Josh Coalson8395d022001-07-12 21:25:22 +00004206 for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
Josh Coalson8395d022001-07-12 21:25:22 +00004207#else
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004208 rice_parameter = suggested_rice_parameter;
Josh Coalson8395d022001-07-12 21:25:22 +00004209#endif
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004210#ifdef EXACT_RICE_BITS_CALCULATION
4211 partition_bits = count_rice_bits_(rice_parameter, residual_samples, residual);
Josh Coalson8395d022001-07-12 21:25:22 +00004212#else
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004213 partition_bits = count_rice_bits_(rice_parameter, residual_samples, abs_residual);
Josh Coalson8395d022001-07-12 21:25:22 +00004214#endif
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004215#ifdef ENABLE_RICE_PARAMETER_SEARCH
Josh Coalson8395d022001-07-12 21:25:22 +00004216 if(partition_bits < best_partition_bits) {
4217 best_rice_parameter = rice_parameter;
4218 best_partition_bits = partition_bits;
4219 }
4220 }
Josh Coalson8395d022001-07-12 21:25:22 +00004221 parameters[0] = best_rice_parameter;
4222 bits_ += best_partition_bits;
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004223#else
4224 parameters[0] = rice_parameter;
4225 bits_ += partition_bits;
4226#endif
Josh Coalson8395d022001-07-12 21:25:22 +00004227 }
4228 else {
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004229 unsigned partition, residual_sample;
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004230 unsigned partition_samples;
4231 FLAC__uint64 mean, k;
Josh Coalson8395d022001-07-12 21:25:22 +00004232 const unsigned partitions = 1u << partition_order;
4233 for(partition = residual_sample = 0; partition < partitions; partition++) {
4234 partition_samples = (residual_samples+predictor_order) >> partition_order;
4235 if(partition == 0) {
4236 if(partition_samples <= predictor_order)
4237 return false;
4238 else
4239 partition_samples -= predictor_order;
4240 }
4241 mean = 0;
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004242 {
4243 unsigned rs, ps;
4244 for(ps = 0, rs = residual_sample; ps < partition_samples; ps++)
4245 mean += abs_residual[rs++];
4246 }
Josh Coalsonf81b6df2005-02-04 01:34:35 +00004247 /* we are basically calculating the size in bits of the
4248 * average residual magnitude in the partition:
4249 * rice_parameter = floor(log2(mean/partition_samples))
4250 * 'mean' is not a good name for the variable, it is
4251 * actually the sum of magnitudes of all residual values
4252 * in the partition, so the actual mean is
4253 * mean/partition_samples
4254 */
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004255 for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1)
Josh Coalson8395d022001-07-12 21:25:22 +00004256 ;
Josh Coalson8395d022001-07-12 21:25:22 +00004257 if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
Josh Coalson31209492001-07-18 23:43:01 +00004258#ifdef DEBUG_VERBOSE
Josh Coalson8395d022001-07-12 21:25:22 +00004259 fprintf(stderr, "clipping rice_parameter (%u -> %u) @3\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
4260#endif
4261 rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
4262 }
4263
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004264#ifdef ENABLE_RICE_PARAMETER_SEARCH
4265 best_partition_bits = 0xffffffff;
Josh Coalson8395d022001-07-12 21:25:22 +00004266 if(rice_parameter_search_dist) {
4267 if(rice_parameter < rice_parameter_search_dist)
4268 min_rice_parameter = 0;
4269 else
4270 min_rice_parameter = rice_parameter - rice_parameter_search_dist;
4271 max_rice_parameter = rice_parameter + rice_parameter_search_dist;
4272 if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
Josh Coalson31209492001-07-18 23:43:01 +00004273#ifdef DEBUG_VERBOSE
Josh Coalson8395d022001-07-12 21:25:22 +00004274 fprintf(stderr, "clipping rice_parameter (%u -> %u) @4\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
4275#endif
4276 max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
4277 }
4278 }
4279 else
4280 min_rice_parameter = max_rice_parameter = rice_parameter;
4281
Josh Coalson8395d022001-07-12 21:25:22 +00004282 for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
4283#endif
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004284#ifdef EXACT_RICE_BITS_CALCULATION
4285 partition_bits = count_rice_bits_(rice_parameter, partition_samples, residual+residual_sample);
Josh Coalson8395d022001-07-12 21:25:22 +00004286#else
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004287 partition_bits = count_rice_bits_(rice_parameter, partition_samples, abs_residual+residual_sample);
Josh Coalson8395d022001-07-12 21:25:22 +00004288#endif
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004289#ifdef ENABLE_RICE_PARAMETER_SEARCH
Josh Coalson8395d022001-07-12 21:25:22 +00004290 if(partition_bits < best_partition_bits) {
4291 best_rice_parameter = rice_parameter;
4292 best_partition_bits = partition_bits;
4293 }
4294 }
Josh Coalson8395d022001-07-12 21:25:22 +00004295 parameters[partition] = best_rice_parameter;
4296 bits_ += best_partition_bits;
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004297#else
4298 parameters[partition] = rice_parameter;
4299 bits_ += partition_bits;
4300#endif
4301 residual_sample += partition_samples;
Josh Coalson8395d022001-07-12 21:25:22 +00004302 }
4303 }
4304
4305 *bits = bits_;
4306 return true;
4307}
4308
Josh Coalson6fe72f72002-08-20 04:01:59 +00004309FLAC__bool set_partitioned_rice_with_precompute_(
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004310#ifdef EXACT_RICE_BITS_CALCULATION
Josh Coalson6fe72f72002-08-20 04:01:59 +00004311 const FLAC__int32 residual[],
Josh Coalson8395d022001-07-12 21:25:22 +00004312#else
Josh Coalson6fe72f72002-08-20 04:01:59 +00004313 const FLAC__uint32 abs_residual[],
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004314#endif
Josh Coalson6fe72f72002-08-20 04:01:59 +00004315 const FLAC__uint64 abs_residual_partition_sums[],
4316 const unsigned raw_bits_per_partition[],
4317 const unsigned residual_samples,
4318 const unsigned predictor_order,
4319 const unsigned suggested_rice_parameter,
4320 const unsigned rice_parameter_search_dist,
4321 const unsigned partition_order,
4322 const FLAC__bool search_for_escapes,
4323 FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
4324 unsigned *bits
4325)
Josh Coalson8395d022001-07-12 21:25:22 +00004326{
4327 unsigned rice_parameter, partition_bits;
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004328 unsigned best_partition_bits, best_rice_parameter = 0;
Josh Coalson8395d022001-07-12 21:25:22 +00004329 unsigned flat_bits;
4330 unsigned bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN;
Josh Coalsonb7023aa2002-08-17 15:23:43 +00004331 unsigned *parameters, *raw_bits;
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004332#ifdef ENABLE_RICE_PARAMETER_SEARCH
4333 unsigned min_rice_parameter, max_rice_parameter;
4334#else
4335 (void)rice_parameter_search_dist;
4336#endif
Josh Coalson8395d022001-07-12 21:25:22 +00004337
4338 FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER);
4339
Josh Coalsona37ba462002-08-19 21:36:39 +00004340 FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order));
4341 parameters = partitioned_rice_contents->parameters;
4342 raw_bits = partitioned_rice_contents->raw_bits;
Josh Coalsonb7023aa2002-08-17 15:23:43 +00004343
Josh Coalson8395d022001-07-12 21:25:22 +00004344 if(partition_order == 0) {
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004345 best_partition_bits = 0xffffffff;
4346#ifdef ENABLE_RICE_PARAMETER_SEARCH
Josh Coalson8395d022001-07-12 21:25:22 +00004347 if(rice_parameter_search_dist) {
4348 if(suggested_rice_parameter < rice_parameter_search_dist)
4349 min_rice_parameter = 0;
4350 else
4351 min_rice_parameter = suggested_rice_parameter - rice_parameter_search_dist;
4352 max_rice_parameter = suggested_rice_parameter + rice_parameter_search_dist;
4353 if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
Josh Coalson31209492001-07-18 23:43:01 +00004354#ifdef DEBUG_VERBOSE
Josh Coalson8395d022001-07-12 21:25:22 +00004355 fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
4356#endif
4357 max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
4358 }
Josh Coalson60f77d72001-04-25 02:16:36 +00004359 }
4360 else
Josh Coalson034dfab2001-04-27 19:10:23 +00004361 min_rice_parameter = max_rice_parameter = suggested_rice_parameter;
Josh Coalson2051dd42001-04-12 22:22:34 +00004362
Josh Coalson034dfab2001-04-27 19:10:23 +00004363 for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
Josh Coalson034dfab2001-04-27 19:10:23 +00004364#else
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004365 rice_parameter = suggested_rice_parameter;
Josh Coalson94e02cd2001-01-25 10:41:06 +00004366#endif
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004367#ifdef EXACT_RICE_BITS_CALCULATION
4368 partition_bits = count_rice_bits_(rice_parameter, residual_samples, residual);
Josh Coalsonb9433f92001-03-17 01:07:00 +00004369#else
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004370 partition_bits = count_rice_bits_(rice_parameter, residual_samples, abs_residual);
Josh Coalson94e02cd2001-01-25 10:41:06 +00004371#endif
Josh Coalson034dfab2001-04-27 19:10:23 +00004372 if(partition_bits < best_partition_bits) {
4373 best_rice_parameter = rice_parameter;
4374 best_partition_bits = partition_bits;
Josh Coalson352e0f62001-03-20 22:55:50 +00004375 }
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004376#ifdef ENABLE_RICE_PARAMETER_SEARCH
Josh Coalson352e0f62001-03-20 22:55:50 +00004377 }
Josh Coalson034dfab2001-04-27 19:10:23 +00004378#endif
Josh Coalson8395d022001-07-12 21:25:22 +00004379 if(search_for_escapes) {
4380 flat_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[0] * residual_samples;
4381 if(flat_bits <= best_partition_bits) {
4382 raw_bits[0] = raw_bits_per_partition[0];
4383 best_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
4384 best_partition_bits = flat_bits;
4385 }
Josh Coalson034dfab2001-04-27 19:10:23 +00004386 }
Josh Coalson034dfab2001-04-27 19:10:23 +00004387 parameters[0] = best_rice_parameter;
4388 bits_ += best_partition_bits;
Josh Coalson94e02cd2001-01-25 10:41:06 +00004389 }
4390 else {
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004391 unsigned partition, residual_sample;
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004392 unsigned partition_samples;
4393 FLAC__uint64 mean, k;
Josh Coalsond4e0ddb2001-04-18 02:20:52 +00004394 const unsigned partitions = 1u << partition_order;
Josh Coalson4dacd192001-06-06 21:11:44 +00004395 for(partition = residual_sample = 0; partition < partitions; partition++) {
Josh Coalson94e02cd2001-01-25 10:41:06 +00004396 partition_samples = (residual_samples+predictor_order) >> partition_order;
Josh Coalson034dfab2001-04-27 19:10:23 +00004397 if(partition == 0) {
Josh Coalson94e02cd2001-01-25 10:41:06 +00004398 if(partition_samples <= predictor_order)
4399 return false;
4400 else
4401 partition_samples -= predictor_order;
4402 }
Josh Coalson05d20792001-06-29 23:12:26 +00004403 mean = abs_residual_partition_sums[partition];
Josh Coalsonf81b6df2005-02-04 01:34:35 +00004404 /* we are basically calculating the size in bits of the
4405 * average residual magnitude in the partition:
4406 * rice_parameter = floor(log2(mean/partition_samples))
4407 * 'mean' is not a good name for the variable, it is
4408 * actually the sum of magnitudes of all residual values
4409 * in the partition, so the actual mean is
4410 * mean/partition_samples
4411 */
Josh Coalsonb3347bd2001-07-16 18:06:41 +00004412 for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1)
Josh Coalson05d20792001-06-29 23:12:26 +00004413 ;
Josh Coalson8395d022001-07-12 21:25:22 +00004414 if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
Josh Coalson31209492001-07-18 23:43:01 +00004415#ifdef DEBUG_VERBOSE
Josh Coalson8395d022001-07-12 21:25:22 +00004416 fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
4417#endif
Josh Coalson034dfab2001-04-27 19:10:23 +00004418 rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
Josh Coalson8395d022001-07-12 21:25:22 +00004419 }
Josh Coalson60f77d72001-04-25 02:16:36 +00004420
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004421 best_partition_bits = 0xffffffff;
4422#ifdef ENABLE_RICE_PARAMETER_SEARCH
Josh Coalson60f77d72001-04-25 02:16:36 +00004423 if(rice_parameter_search_dist) {
Josh Coalson034dfab2001-04-27 19:10:23 +00004424 if(rice_parameter < rice_parameter_search_dist)
Josh Coalson60f77d72001-04-25 02:16:36 +00004425 min_rice_parameter = 0;
4426 else
Josh Coalson034dfab2001-04-27 19:10:23 +00004427 min_rice_parameter = rice_parameter - rice_parameter_search_dist;
4428 max_rice_parameter = rice_parameter + rice_parameter_search_dist;
Josh Coalson8395d022001-07-12 21:25:22 +00004429 if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
Josh Coalson31209492001-07-18 23:43:01 +00004430#ifdef DEBUG_VERBOSE
Josh Coalson8395d022001-07-12 21:25:22 +00004431 fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
4432#endif
Josh Coalson60f77d72001-04-25 02:16:36 +00004433 max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
Josh Coalson8395d022001-07-12 21:25:22 +00004434 }
Josh Coalson60f77d72001-04-25 02:16:36 +00004435 }
4436 else
4437 min_rice_parameter = max_rice_parameter = rice_parameter;
Josh Coalson60f77d72001-04-25 02:16:36 +00004438
Josh Coalson034dfab2001-04-27 19:10:23 +00004439 for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
4440#endif
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004441#ifdef EXACT_RICE_BITS_CALCULATION
4442 partition_bits = count_rice_bits_(rice_parameter, partition_samples, residual+residual_sample);
Josh Coalson034dfab2001-04-27 19:10:23 +00004443#else
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004444 partition_bits = count_rice_bits_(rice_parameter, partition_samples, abs_residual+residual_sample);
Josh Coalson94e02cd2001-01-25 10:41:06 +00004445#endif
Josh Coalson034dfab2001-04-27 19:10:23 +00004446 if(partition_bits < best_partition_bits) {
4447 best_rice_parameter = rice_parameter;
4448 best_partition_bits = partition_bits;
4449 }
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004450#ifdef ENABLE_RICE_PARAMETER_SEARCH
Josh Coalson2051dd42001-04-12 22:22:34 +00004451 }
Josh Coalson034dfab2001-04-27 19:10:23 +00004452#endif
Josh Coalson8395d022001-07-12 21:25:22 +00004453 if(search_for_escapes) {
4454 flat_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[partition] * partition_samples;
4455 if(flat_bits <= best_partition_bits) {
4456 raw_bits[partition] = raw_bits_per_partition[partition];
4457 best_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
4458 best_partition_bits = flat_bits;
4459 }
Josh Coalson2051dd42001-04-12 22:22:34 +00004460 }
Josh Coalson034dfab2001-04-27 19:10:23 +00004461 parameters[partition] = best_rice_parameter;
4462 bits_ += best_partition_bits;
Josh Coalsonce1d07c2007-01-23 05:00:46 +00004463 residual_sample += partition_samples;
Josh Coalson94e02cd2001-01-25 10:41:06 +00004464 }
4465 }
4466
4467 *bits = bits_;
4468 return true;
4469}
Josh Coalson859bc542001-03-27 22:22:27 +00004470
Josh Coalsonf1eff452002-07-31 07:05:33 +00004471unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples)
Josh Coalson859bc542001-03-27 22:22:27 +00004472{
4473 unsigned i, shift;
Josh Coalson77e3f312001-06-23 03:03:24 +00004474 FLAC__int32 x = 0;
Josh Coalson859bc542001-03-27 22:22:27 +00004475
4476 for(i = 0; i < samples && !(x&1); i++)
4477 x |= signal[i];
4478
4479 if(x == 0) {
4480 shift = 0;
4481 }
4482 else {
4483 for(shift = 0; !(x&1); shift++)
4484 x >>= 1;
4485 }
4486
4487 if(shift > 0) {
4488 for(i = 0; i < samples; i++)
4489 signal[i] >>= shift;
4490 }
4491
4492 return shift;
4493}
Josh Coalsond86e03b2002-08-03 21:56:15 +00004494
4495void append_to_verify_fifo_(verify_input_fifo *fifo, const FLAC__int32 * const input[], unsigned input_offset, unsigned channels, unsigned wide_samples)
4496{
4497 unsigned channel;
4498
4499 for(channel = 0; channel < channels; channel++)
4500 memcpy(&fifo->data[channel][fifo->tail], &input[channel][input_offset], sizeof(FLAC__int32) * wide_samples);
4501
4502 fifo->tail += wide_samples;
4503
4504 FLAC__ASSERT(fifo->tail <= fifo->size);
4505}
4506
4507void append_to_verify_fifo_interleaved_(verify_input_fifo *fifo, const FLAC__int32 input[], unsigned input_offset, unsigned channels, unsigned wide_samples)
4508{
4509 unsigned channel;
4510 unsigned sample, wide_sample;
4511 unsigned tail = fifo->tail;
4512
4513 sample = input_offset * channels;
4514 for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
4515 for(channel = 0; channel < channels; channel++)
4516 fifo->data[channel][tail] = input[sample++];
4517 tail++;
4518 }
4519 fifo->tail = tail;
4520
4521 FLAC__ASSERT(fifo->tail <= fifo->size);
4522}
4523
Josh Coalson8065a2d2006-10-15 08:32:56 +00004524FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
Josh Coalsond86e03b2002-08-03 21:56:15 +00004525{
4526 FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
Josh Coalson8065a2d2006-10-15 08:32:56 +00004527 const size_t encoded_bytes = encoder->private_->verify.output.bytes;
Josh Coalsond86e03b2002-08-03 21:56:15 +00004528 (void)decoder;
4529
4530 if(encoder->private_->verify.needs_magic_hack) {
4531 FLAC__ASSERT(*bytes >= FLAC__STREAM_SYNC_LENGTH);
4532 *bytes = FLAC__STREAM_SYNC_LENGTH;
4533 memcpy(buffer, FLAC__STREAM_SYNC_STRING, *bytes);
4534 encoder->private_->verify.needs_magic_hack = false;
4535 }
4536 else {
4537 if(encoded_bytes == 0) {
Josh Coalsonfc2b7372002-08-16 05:39:34 +00004538 /*
4539 * If we get here, a FIFO underflow has occurred,
4540 * which means there is a bug somewhere.
4541 */
4542 FLAC__ASSERT(0);
Josh Coalsond86e03b2002-08-03 21:56:15 +00004543 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
4544 }
4545 else if(encoded_bytes < *bytes)
4546 *bytes = encoded_bytes;
4547 memcpy(buffer, encoder->private_->verify.output.data, *bytes);
4548 encoder->private_->verify.output.data += *bytes;
4549 encoder->private_->verify.output.bytes -= *bytes;
4550 }
4551
4552 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
4553}
4554
4555FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
4556{
4557 FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data;
4558 unsigned channel;
Josh Coalson49f2f162006-11-09 16:54:52 +00004559 const unsigned channels = frame->header.channels;
Josh Coalsond86e03b2002-08-03 21:56:15 +00004560 const unsigned blocksize = frame->header.blocksize;
4561 const unsigned bytes_per_block = sizeof(FLAC__int32) * blocksize;
4562
Josh Coalson49f2f162006-11-09 16:54:52 +00004563 (void)decoder;
4564
Josh Coalsond86e03b2002-08-03 21:56:15 +00004565 for(channel = 0; channel < channels; channel++) {
4566 if(0 != memcmp(buffer[channel], encoder->private_->verify.input_fifo.data[channel], bytes_per_block)) {
4567 unsigned i, sample = 0;
4568 FLAC__int32 expect = 0, got = 0;
4569
4570 for(i = 0; i < blocksize; i++) {
4571 if(buffer[channel][i] != encoder->private_->verify.input_fifo.data[channel][i]) {
4572 sample = i;
4573 expect = (FLAC__int32)encoder->private_->verify.input_fifo.data[channel][i];
4574 got = (FLAC__int32)buffer[channel][i];
4575 break;
4576 }
4577 }
4578 FLAC__ASSERT(i < blocksize);
4579 FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
4580 encoder->private_->verify.error_stats.absolute_sample = frame->header.number.sample_number + sample;
Josh Coalson5f39e9f2002-08-21 05:27:01 +00004581 encoder->private_->verify.error_stats.frame_number = (unsigned)(frame->header.number.sample_number / blocksize);
Josh Coalsond86e03b2002-08-03 21:56:15 +00004582 encoder->private_->verify.error_stats.channel = channel;
4583 encoder->private_->verify.error_stats.sample = sample;
4584 encoder->private_->verify.error_stats.expected = expect;
4585 encoder->private_->verify.error_stats.got = got;
4586 encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA;
4587 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
4588 }
4589 }
4590 /* dequeue the frame from the fifo */
Josh Coalsond86e03b2002-08-03 21:56:15 +00004591 encoder->private_->verify.input_fifo.tail -= blocksize;
Josh Coalson49f2f162006-11-09 16:54:52 +00004592 FLAC__ASSERT(encoder->private_->verify.input_fifo.tail <= OVERREAD_);
Josh Coalsonb7b57ef2006-11-09 07:06:33 +00004593 for(channel = 0; channel < channels; channel++)
4594 memmove(&encoder->private_->verify.input_fifo.data[channel][0], &encoder->private_->verify.input_fifo.data[channel][blocksize], encoder->private_->verify.input_fifo.tail * sizeof(encoder->private_->verify.input_fifo.data[0][0]));
Josh Coalsond86e03b2002-08-03 21:56:15 +00004595 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
4596}
4597
4598void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
4599{
4600 (void)decoder, (void)metadata, (void)client_data;
4601}
4602
4603void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
4604{
4605 FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
4606 (void)decoder, (void)status;
4607 encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
4608}
Josh Coalson6b21f662006-09-13 01:42:27 +00004609
Josh Coalson8065a2d2006-10-15 08:32:56 +00004610FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
Josh Coalson8da98c82006-10-15 04:24:05 +00004611{
4612 (void)client_data;
4613
Josh Coalson8065a2d2006-10-15 08:32:56 +00004614 *bytes = fread(buffer, 1, *bytes, encoder->private_->file);
Josh Coalson8da98c82006-10-15 04:24:05 +00004615 if (*bytes == 0) {
4616 if (feof(encoder->private_->file))
4617 return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
4618 else if (ferror(encoder->private_->file))
4619 return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
4620 }
4621 return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
4622}
4623
Josh Coalson6b21f662006-09-13 01:42:27 +00004624FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
4625{
4626 (void)client_data;
4627
4628 if(fseeko(encoder->private_->file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
4629 return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
4630 else
4631 return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
4632}
4633
4634FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
4635{
4636 off_t offset;
4637
4638 (void)client_data;
4639
4640 offset = ftello(encoder->private_->file);
4641
4642 if(offset < 0) {
4643 return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
4644 }
4645 else {
4646 *absolute_byte_offset = (FLAC__uint64)offset;
4647 return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
4648 }
4649}
4650
4651#ifdef FLAC__VALGRIND_TESTING
4652static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
4653{
4654 size_t ret = fwrite(ptr, size, nmemb, stream);
4655 if(!ferror(stream))
4656 fflush(stream);
4657 return ret;
4658}
4659#else
4660#define local__fwrite fwrite
4661#endif
4662
Josh Coalson352feb52006-10-15 17:08:52 +00004663FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
Josh Coalson6b21f662006-09-13 01:42:27 +00004664{
Josh Coalson2d6b8c62006-10-11 06:30:38 +00004665 (void)client_data, (void)current_frame;
Josh Coalson6b21f662006-09-13 01:42:27 +00004666
4667 if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, encoder->private_->file) == bytes) {
Josh Coalson8da98c82006-10-15 04:24:05 +00004668 FLAC__bool call_it = 0 != encoder->private_->progress_callback && (
4669#if FLAC__HAS_OGG
4670 /* We would like to be able to use 'samples > 0' in the
4671 * clause here but currently because of the nature of our
4672 * Ogg writing implementation, 'samples' is always 0 (see
4673 * ogg_encoder_aspect.c). The downside is extra progress
4674 * callbacks.
4675 */
4676 encoder->private_->is_ogg? true :
4677#endif
4678 samples > 0
4679 );
4680 if(call_it) {
Josh Coalson2d6b8c62006-10-11 06:30:38 +00004681 /* NOTE: We have to add +bytes, +samples, and +1 to the stats
4682 * because at this point in the callback chain, the stats
4683 * have not been updated. Only after we return and control
4684 * gets back to write_frame_() are the stats updated
4685 */
4686 encoder->private_->progress_callback(encoder, encoder->private_->bytes_written+bytes, encoder->private_->samples_written+samples, encoder->private_->frames_written+(samples?1:0), encoder->private_->total_frames_estimate, encoder->private_->client_data);
4687 }
Josh Coalson6b21f662006-09-13 01:42:27 +00004688 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
4689 }
4690 else
4691 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
4692}
4693
4694/*
4695 * This will forcibly set stdout to binary mode (for OSes that require it)
4696 */
4697FILE *get_binary_stdout_()
4698{
4699 /* if something breaks here it is probably due to the presence or
4700 * absence of an underscore before the identifiers 'setmode',
4701 * 'fileno', and/or 'O_BINARY'; check your system header files.
4702 */
4703#if defined _MSC_VER || defined __MINGW32__
4704 _setmode(_fileno(stdout), _O_BINARY);
4705#elif defined __CYGWIN__
4706 /* almost certainly not needed for any modern Cygwin, but let's be safe... */
4707 setmode(_fileno(stdout), _O_BINARY);
4708#elif defined __EMX__
4709 setmode(fileno(stdout), O_BINARY);
4710#endif
4711
4712 return stdout;
4713}