file_encoder.c 29.7 KB
Newer Older
1
/* libFLAC - Free Lossless Audio Codec library
Josh Coalson's avatar
Josh Coalson committed
2
 * Copyright (C) 2002,2003,2004  Josh Coalson
3
 *
4
5
6
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
7
 *
8
9
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
10
 *
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of the Xiph.org Foundation nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31
32
33
 */

#include <stdio.h>
#include <stdlib.h> /* for malloc() */
Josh Coalson's avatar
Josh Coalson committed
34
#include <string.h> /* for strlen(), strcpy() */
35
36
37
#include "FLAC/assert.h"
#include "protected/file_encoder.h"

38
39
40
41
42
#ifdef max
#undef max
#endif
#define max(x,y) ((x)>(y)?(x):(y))

43
44
45
46
47
48
/***********************************************************************
 *
 * Private class method prototypes
 *
 ***********************************************************************/

49
50
51
52
53
/* unpublished debug routines */
extern FLAC__bool FLAC__seekable_stream_encoder_disable_constant_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
extern FLAC__bool FLAC__seekable_stream_encoder_disable_fixed_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);
extern FLAC__bool FLAC__seekable_stream_encoder_disable_verbatim_subframes(FLAC__SeekableStreamEncoder *encoder, FLAC__bool value);

54
static void set_defaults_(FLAC__FileEncoder *encoder);
Josh Coalson's avatar
Josh Coalson committed
55
static FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
56
static FLAC__SeekableStreamEncoderTellStatus tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
Josh Coalson's avatar
Josh Coalson committed
57
static FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
58
59
60
61
62
63
64
65

/***********************************************************************
 *
 * Private class data
 *
 ***********************************************************************/

typedef struct FLAC__FileEncoderPrivate {
66
67
	FLAC__FileEncoderProgressCallback progress_callback;
	void *client_data;
68
	char *filename;
69
	FLAC__uint64 bytes_written;
70
	FLAC__uint64 samples_written;
Josh Coalson's avatar
Josh Coalson committed
71
	unsigned frames_written;
72
	unsigned total_frames_estimate;
73
	FLAC__SeekableStreamEncoder *seekable_stream_encoder;
74
	FILE *file;
75
76
77
78
79
80
81
82
} FLAC__FileEncoderPrivate;

/***********************************************************************
 *
 * Public static class data
 *
 ***********************************************************************/

83
FLAC_API const char * const FLAC__FileEncoderStateString[] = {
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
	"FLAC__FILE_ENCODER_OK",
	"FLAC__FILE_ENCODER_NO_FILENAME",
	"FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR",
	"FLAC__FILE_ENCODER_FATAL_ERROR_WHILE_WRITING",
	"FLAC__FILE_ENCODER_ERROR_OPENING_FILE",
	"FLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR",
	"FLAC__FILE_ENCODER_ALREADY_INITIALIZED",
	"FLAC__FILE_ENCODER_UNINITIALIZED"
};


/***********************************************************************
 *
 * Class constructor/destructor
 *
 ***********************************************************************/
Josh Coalson's avatar
Josh Coalson committed
100

101
FLAC_API FLAC__FileEncoder *FLAC__file_encoder_new()
102
103
104
105
106
{
	FLAC__FileEncoder *encoder;

	FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */

107
	encoder = (FLAC__FileEncoder*)calloc(1, sizeof(FLAC__FileEncoder));
108
109
110
	if(encoder == 0) {
		return 0;
	}
Josh Coalson's avatar
Josh Coalson committed
111

112
	encoder->protected_ = (FLAC__FileEncoderProtected*)calloc(1, sizeof(FLAC__FileEncoderProtected));
113
114
115
116
	if(encoder->protected_ == 0) {
		free(encoder);
		return 0;
	}
Josh Coalson's avatar
Josh Coalson committed
117

118
	encoder->private_ = (FLAC__FileEncoderPrivate*)calloc(1, sizeof(FLAC__FileEncoderPrivate));
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
	if(encoder->private_ == 0) {
		free(encoder->protected_);
		free(encoder);
		return 0;
	}

	encoder->private_->seekable_stream_encoder = FLAC__seekable_stream_encoder_new();
	if(0 == encoder->private_->seekable_stream_encoder) {
		free(encoder->private_);
		free(encoder->protected_);
		free(encoder);
		return 0;
	}

	encoder->private_->file = 0;

	set_defaults_(encoder);

	encoder->protected_->state = FLAC__FILE_ENCODER_UNINITIALIZED;

	return encoder;
}

142
FLAC_API void FLAC__file_encoder_delete(FLAC__FileEncoder *encoder)
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);

	(void)FLAC__file_encoder_finish(encoder);

	FLAC__seekable_stream_encoder_delete(encoder->private_->seekable_stream_encoder);

	free(encoder->private_);
	free(encoder->protected_);
	free(encoder);
}

/***********************************************************************
 *
 * Public class methods
 *
 ***********************************************************************/

164
FLAC_API FLAC__FileEncoderState FLAC__file_encoder_init(FLAC__FileEncoder *encoder)
165
166
167
168
169
170
171
172
173
{
	FLAC__ASSERT(0 != encoder);

	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return encoder->protected_->state = FLAC__FILE_ENCODER_ALREADY_INITIALIZED;

	if(0 == encoder->private_->filename)
		return encoder->protected_->state = FLAC__FILE_ENCODER_NO_FILENAME;

Josh Coalson's avatar
Josh Coalson committed
174
	encoder->private_->file = fopen(encoder->private_->filename, "w+b");
175
176
177
178

	if(encoder->private_->file == 0)
		return encoder->protected_->state = FLAC__FILE_ENCODER_ERROR_OPENING_FILE;

179
	encoder->private_->bytes_written = 0;
180
	encoder->private_->samples_written = 0;
181
	encoder->private_->frames_written = 0;
182

Josh Coalson's avatar
Josh Coalson committed
183
	FLAC__seekable_stream_encoder_set_seek_callback(encoder->private_->seekable_stream_encoder, seek_callback_);
184
	FLAC__seekable_stream_encoder_set_tell_callback(encoder->private_->seekable_stream_encoder, tell_callback_);
185
186
187
	FLAC__seekable_stream_encoder_set_write_callback(encoder->private_->seekable_stream_encoder, write_callback_);
	FLAC__seekable_stream_encoder_set_client_data(encoder->private_->seekable_stream_encoder, encoder);

Josh Coalson's avatar
Josh Coalson committed
188
	if(FLAC__seekable_stream_encoder_init(encoder->private_->seekable_stream_encoder) != FLAC__SEEKABLE_STREAM_ENCODER_OK)
189
190
		return encoder->protected_->state = FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR;

191
192
193
194
	{
		unsigned blocksize = FLAC__file_encoder_get_blocksize(encoder);

		FLAC__ASSERT(blocksize != 0);
Josh Coalson's avatar
Josh Coalson committed
195
		encoder->private_->total_frames_estimate = (unsigned)((FLAC__file_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize);
196
197
	}

Josh Coalson's avatar
Josh Coalson committed
198
	return encoder->protected_->state = FLAC__FILE_ENCODER_OK;
199
200
}

201
FLAC_API void FLAC__file_encoder_finish(FLAC__FileEncoder *encoder)
202
203
204
205
206
207
208
209
{
	FLAC__ASSERT(0 != encoder);

	if(encoder->protected_->state == FLAC__FILE_ENCODER_UNINITIALIZED)
		return;

	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);

210
211
212
213
	/* FLAC__seekable_stream_encoder_finish() might write data so we must close the file after it. */

	FLAC__seekable_stream_encoder_finish(encoder->private_->seekable_stream_encoder);

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
	if(0 != encoder->private_->file) {
		fclose(encoder->private_->file);
		encoder->private_->file = 0;
	}

	if(0 != encoder->private_->filename) {
		free(encoder->private_->filename);
		encoder->private_->filename = 0;
	}

	set_defaults_(encoder);

	encoder->protected_->state = FLAC__FILE_ENCODER_UNINITIALIZED;
}

229
FLAC_API FLAC__bool FLAC__file_encoder_set_verify(FLAC__FileEncoder *encoder, FLAC__bool value)
Josh Coalson's avatar
Josh Coalson committed
230
231
232
233
234
235
236
237
238
239
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_verify(encoder->private_->seekable_stream_encoder, value);
}

240
FLAC_API FLAC__bool FLAC__file_encoder_set_streamable_subset(FLAC__FileEncoder *encoder, FLAC__bool value)
241
242
243
244
245
246
247
248
249
250
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_streamable_subset(encoder->private_->seekable_stream_encoder, value);
}

251
FLAC_API FLAC__bool FLAC__file_encoder_set_do_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value)
252
253
254
255
256
257
258
259
260
261
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_do_mid_side_stereo(encoder->private_->seekable_stream_encoder, value);
}

262
FLAC_API FLAC__bool FLAC__file_encoder_set_loose_mid_side_stereo(FLAC__FileEncoder *encoder, FLAC__bool value)
263
264
265
266
267
268
269
270
271
272
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_loose_mid_side_stereo(encoder->private_->seekable_stream_encoder, value);
}

273
FLAC_API FLAC__bool FLAC__file_encoder_set_channels(FLAC__FileEncoder *encoder, unsigned value)
274
275
276
277
278
279
280
281
282
283
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_channels(encoder->private_->seekable_stream_encoder, value);
}

284
FLAC_API FLAC__bool FLAC__file_encoder_set_bits_per_sample(FLAC__FileEncoder *encoder, unsigned value)
285
286
287
288
289
290
291
292
293
294
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_bits_per_sample(encoder->private_->seekable_stream_encoder, value);
}

295
FLAC_API FLAC__bool FLAC__file_encoder_set_sample_rate(FLAC__FileEncoder *encoder, unsigned value)
296
297
298
299
300
301
302
303
304
305
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_sample_rate(encoder->private_->seekable_stream_encoder, value);
}

306
FLAC_API FLAC__bool FLAC__file_encoder_set_blocksize(FLAC__FileEncoder *encoder, unsigned value)
307
308
309
310
311
312
313
314
315
316
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_blocksize(encoder->private_->seekable_stream_encoder, value);
}

317
FLAC_API FLAC__bool FLAC__file_encoder_set_max_lpc_order(FLAC__FileEncoder *encoder, unsigned value)
318
319
320
321
322
323
324
325
326
327
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_max_lpc_order(encoder->private_->seekable_stream_encoder, value);
}

328
FLAC_API FLAC__bool FLAC__file_encoder_set_qlp_coeff_precision(FLAC__FileEncoder *encoder, unsigned value)
329
330
331
332
333
334
335
336
337
338
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_qlp_coeff_precision(encoder->private_->seekable_stream_encoder, value);
}

339
FLAC_API FLAC__bool FLAC__file_encoder_set_do_qlp_coeff_prec_search(FLAC__FileEncoder *encoder, FLAC__bool value)
340
341
342
343
344
345
346
347
348
349
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(encoder->private_->seekable_stream_encoder, value);
}

350
FLAC_API FLAC__bool FLAC__file_encoder_set_do_escape_coding(FLAC__FileEncoder *encoder, FLAC__bool value)
351
352
353
354
355
356
357
358
359
360
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_do_escape_coding(encoder->private_->seekable_stream_encoder, value);
}

361
FLAC_API FLAC__bool FLAC__file_encoder_set_do_exhaustive_model_search(FLAC__FileEncoder *encoder, FLAC__bool value)
362
363
364
365
366
367
368
369
370
371
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_do_exhaustive_model_search(encoder->private_->seekable_stream_encoder, value);
}

372
FLAC_API FLAC__bool FLAC__file_encoder_set_min_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value)
373
374
375
376
377
378
379
380
381
382
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_min_residual_partition_order(encoder->private_->seekable_stream_encoder, value);
}

383
FLAC_API FLAC__bool FLAC__file_encoder_set_max_residual_partition_order(FLAC__FileEncoder *encoder, unsigned value)
384
385
386
387
388
389
390
391
392
393
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_max_residual_partition_order(encoder->private_->seekable_stream_encoder, value);
}

394
FLAC_API FLAC__bool FLAC__file_encoder_set_rice_parameter_search_dist(FLAC__FileEncoder *encoder, unsigned value)
395
396
397
398
399
400
401
402
403
404
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_rice_parameter_search_dist(encoder->private_->seekable_stream_encoder, value);
}

405
FLAC_API FLAC__bool FLAC__file_encoder_set_total_samples_estimate(FLAC__FileEncoder *encoder, FLAC__uint64 value)
406
407
408
409
410
411
412
413
414
415
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_set_total_samples_estimate(encoder->private_->seekable_stream_encoder, value);
}

416
FLAC_API FLAC__bool FLAC__file_encoder_set_metadata(FLAC__FileEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
417
418
419
420
421
422
423
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != encoder->private_->seekable_stream_encoder);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
Josh Coalson's avatar
Josh Coalson committed
424
	return FLAC__seekable_stream_encoder_set_metadata(encoder->private_->seekable_stream_encoder, metadata, num_blocks);
425
426
}

427
FLAC_API FLAC__bool FLAC__file_encoder_set_filename(FLAC__FileEncoder *encoder, const char *value)
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	FLAC__ASSERT(0 != value);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	if(0 != encoder->private_->filename) {
		free(encoder->private_->filename);
		encoder->private_->filename = 0;
	}
	if(0 == (encoder->private_->filename = (char*)malloc(strlen(value)+1))) {
		encoder->protected_->state = FLAC__FILE_ENCODER_MEMORY_ALLOCATION_ERROR;
		return false;
	}
	strcpy(encoder->private_->filename, value);
	return true;
}

447
FLAC_API FLAC__bool FLAC__file_encoder_set_progress_callback(FLAC__FileEncoder *encoder, FLAC__FileEncoderProgressCallback value)
448
449
450
451
452
453
454
455
456
457
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	encoder->private_->progress_callback = value;
	return true;
}

458
FLAC_API FLAC__bool FLAC__file_encoder_set_client_data(FLAC__FileEncoder *encoder, void *value)
459
460
461
462
463
464
465
466
467
468
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	encoder->private_->client_data = value;
	return true;
}

469
470
471
472
/*
 * These three functions are not static, but not publically exposed in
 * include/FLAC/ either.  They are used by the test suite.
 */
473
FLAC_API FLAC__bool FLAC__file_encoder_disable_constant_subframes(FLAC__FileEncoder *encoder, FLAC__bool value)
474
475
476
477
478
479
480
481
482
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_disable_constant_subframes(encoder->private_->seekable_stream_encoder, value);
}

483
FLAC_API FLAC__bool FLAC__file_encoder_disable_fixed_subframes(FLAC__FileEncoder *encoder, FLAC__bool value)
484
485
486
487
488
489
490
491
492
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_disable_fixed_subframes(encoder->private_->seekable_stream_encoder, value);
}

493
FLAC_API FLAC__bool FLAC__file_encoder_disable_verbatim_subframes(FLAC__FileEncoder *encoder, FLAC__bool value)
494
495
496
497
498
499
500
501
502
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	FLAC__ASSERT(0 != encoder->protected_);
	if(encoder->protected_->state != FLAC__FILE_ENCODER_UNINITIALIZED)
		return false;
	return FLAC__seekable_stream_encoder_disable_verbatim_subframes(encoder->private_->seekable_stream_encoder, value);
}

503
FLAC_API FLAC__FileEncoderState FLAC__file_encoder_get_state(const FLAC__FileEncoder *encoder)
504
505
506
507
508
509
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->protected_);
	return encoder->protected_->state;
}

510
FLAC_API FLAC__SeekableStreamEncoderState FLAC__file_encoder_get_seekable_stream_encoder_state(const FLAC__FileEncoder *encoder)
511
512
513
514
515
516
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_state(encoder->private_->seekable_stream_encoder);
}

517
FLAC_API FLAC__StreamEncoderState FLAC__file_encoder_get_stream_encoder_state(const FLAC__FileEncoder *encoder)
Josh Coalson's avatar
Josh Coalson committed
518
519
520
521
522
523
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_stream_encoder_state(encoder->private_->seekable_stream_encoder);
}

524
FLAC_API FLAC__StreamDecoderState FLAC__file_encoder_get_verify_decoder_state(const FLAC__FileEncoder *encoder)
Josh Coalson's avatar
Josh Coalson committed
525
526
527
528
529
530
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_verify_decoder_state(encoder->private_->seekable_stream_encoder);
}

531
532
533
534
535
536
537
538
FLAC_API const char *FLAC__file_encoder_get_resolved_state_string(const FLAC__FileEncoder *encoder)
{
	if(encoder->protected_->state != FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR)
		return FLAC__FileEncoderStateString[encoder->protected_->state];
	else
		return FLAC__seekable_stream_encoder_get_resolved_state_string(encoder->private_->seekable_stream_encoder);
}

539
FLAC_API void FLAC__file_encoder_get_verify_decoder_error_stats(const FLAC__FileEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
540
541
542
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
Josh Coalson's avatar
Josh Coalson committed
543
	FLAC__seekable_stream_encoder_get_verify_decoder_error_stats(encoder->private_->seekable_stream_encoder, absolute_sample, frame_number, channel, sample, expected, got);
544
545
}

546
FLAC_API FLAC__bool FLAC__file_encoder_get_verify(const FLAC__FileEncoder *encoder)
Josh Coalson's avatar
Josh Coalson committed
547
548
549
550
551
552
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_verify(encoder->private_->seekable_stream_encoder);
}

553
FLAC_API FLAC__bool FLAC__file_encoder_get_streamable_subset(const FLAC__FileEncoder *encoder)
554
555
556
557
558
559
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_streamable_subset(encoder->private_->seekable_stream_encoder);
}

560
FLAC_API FLAC__bool FLAC__file_encoder_get_do_mid_side_stereo(const FLAC__FileEncoder *encoder)
561
562
563
564
565
566
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_do_mid_side_stereo(encoder->private_->seekable_stream_encoder);
}

567
FLAC_API FLAC__bool FLAC__file_encoder_get_loose_mid_side_stereo(const FLAC__FileEncoder *encoder)
568
569
570
571
572
573
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_loose_mid_side_stereo(encoder->private_->seekable_stream_encoder);
}

574
FLAC_API unsigned FLAC__file_encoder_get_channels(const FLAC__FileEncoder *encoder)
575
576
577
578
579
580
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_channels(encoder->private_->seekable_stream_encoder);
}

581
FLAC_API unsigned FLAC__file_encoder_get_bits_per_sample(const FLAC__FileEncoder *encoder)
582
583
584
585
586
587
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_bits_per_sample(encoder->private_->seekable_stream_encoder);
}

588
FLAC_API unsigned FLAC__file_encoder_get_sample_rate(const FLAC__FileEncoder *encoder)
589
590
591
592
593
594
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_sample_rate(encoder->private_->seekable_stream_encoder);
}

595
FLAC_API unsigned FLAC__file_encoder_get_blocksize(const FLAC__FileEncoder *encoder)
596
597
598
599
600
601
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_blocksize(encoder->private_->seekable_stream_encoder);
}

602
FLAC_API unsigned FLAC__file_encoder_get_max_lpc_order(const FLAC__FileEncoder *encoder)
603
604
605
606
607
608
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_max_lpc_order(encoder->private_->seekable_stream_encoder);
}

609
FLAC_API unsigned FLAC__file_encoder_get_qlp_coeff_precision(const FLAC__FileEncoder *encoder)
610
611
612
613
614
615
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_qlp_coeff_precision(encoder->private_->seekable_stream_encoder);
}

616
FLAC_API FLAC__bool FLAC__file_encoder_get_do_qlp_coeff_prec_search(const FLAC__FileEncoder *encoder)
617
618
619
620
621
622
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(encoder->private_->seekable_stream_encoder);
}

623
FLAC_API FLAC__bool FLAC__file_encoder_get_do_escape_coding(const FLAC__FileEncoder *encoder)
624
625
626
627
628
629
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_do_escape_coding(encoder->private_->seekable_stream_encoder);
}

630
FLAC_API FLAC__bool FLAC__file_encoder_get_do_exhaustive_model_search(const FLAC__FileEncoder *encoder)
631
632
633
634
635
636
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_do_exhaustive_model_search(encoder->private_->seekable_stream_encoder);
}

637
FLAC_API unsigned FLAC__file_encoder_get_min_residual_partition_order(const FLAC__FileEncoder *encoder)
638
639
640
641
642
643
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_min_residual_partition_order(encoder->private_->seekable_stream_encoder);
}

644
FLAC_API unsigned FLAC__file_encoder_get_max_residual_partition_order(const FLAC__FileEncoder *encoder)
645
646
647
648
649
650
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_max_residual_partition_order(encoder->private_->seekable_stream_encoder);
}

651
FLAC_API unsigned FLAC__file_encoder_get_rice_parameter_search_dist(const FLAC__FileEncoder *encoder)
652
653
654
655
656
657
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_rice_parameter_search_dist(encoder->private_->seekable_stream_encoder);
}

658
FLAC_API FLAC__uint64 FLAC__file_encoder_get_total_samples_estimate(const FLAC__FileEncoder *encoder)
659
660
661
662
663
664
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
	return FLAC__seekable_stream_encoder_get_total_samples_estimate(encoder->private_->seekable_stream_encoder);
}

665
FLAC_API FLAC__bool FLAC__file_encoder_process(FLAC__FileEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
666
667
668
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
Josh Coalson's avatar
Josh Coalson committed
669
670
671
672
673
674
	if(!FLAC__seekable_stream_encoder_process(encoder->private_->seekable_stream_encoder, buffer, samples)) {
		encoder->protected_->state = FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR;
		return false;
	}
	else
		return true;
675
676
677
}

/* 'samples' is channel-wide samples, e.g. for 1 second at 44100Hz, 'samples' = 44100 regardless of the number of channels */
678
FLAC_API FLAC__bool FLAC__file_encoder_process_interleaved(FLAC__FileEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
679
680
681
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);
Josh Coalson's avatar
Josh Coalson committed
682
683
684
685
686
687
	if(!FLAC__seekable_stream_encoder_process_interleaved(encoder->private_->seekable_stream_encoder, buffer, samples)) {
		encoder->protected_->state = FLAC__FILE_ENCODER_SEEKABLE_STREAM_ENCODER_ERROR;
		return false;
	}
	else
		return true;
688
689
}

Josh Coalson's avatar
Josh Coalson committed
690

691
692
693
694
695
696
697
698
699
700
701
/***********************************************************************
 *
 * Private class methods
 *
 ***********************************************************************/

void set_defaults_(FLAC__FileEncoder *encoder)
{
	FLAC__ASSERT(0 != encoder);
	FLAC__ASSERT(0 != encoder->private_);

702
703
704
	encoder->private_->progress_callback = 0;
	encoder->private_->client_data = 0;
	encoder->private_->total_frames_estimate = 0;
Josh Coalson's avatar
Josh Coalson committed
705
	encoder->private_->filename = 0;
706
707
}

Josh Coalson's avatar
Josh Coalson committed
708
FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
709
710
711
{
	FLAC__FileEncoder *file_encoder = (FLAC__FileEncoder*)client_data;

Josh Coalson's avatar
Josh Coalson committed
712
	(void)encoder;
713

Josh Coalson's avatar
Josh Coalson committed
714
	FLAC__ASSERT(0 != file_encoder);
715

Josh Coalson's avatar
Josh Coalson committed
716
	if(fseek(file_encoder->private_->file, (long)absolute_byte_offset, SEEK_SET) < 0)
Josh Coalson's avatar
Josh Coalson committed
717
		return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR;
718
	else
Josh Coalson's avatar
Josh Coalson committed
719
		return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
720
721
}

Josh Coalson's avatar
Josh Coalson committed
722
FLAC__SeekableStreamEncoderTellStatus tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
{
	FLAC__FileEncoder *file_encoder = (FLAC__FileEncoder*)client_data;
	long offset;

	(void)encoder;

	FLAC__ASSERT(0 != file_encoder);

	offset = ftell(file_encoder->private_->file);

	if(offset < 0) {
		return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR;
	}
	else {
		*absolute_byte_offset = (FLAC__uint64)offset;
		return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
	}
}

742
743
744
745
746
747
748
749
750
751
752
753
#ifdef FLAC__VALGRIND_TESTING
static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
{
	size_t ret = fwrite(ptr, size, nmemb, stream);
	if(!ferror(stream))
		fflush(stream);
	return ret;
}
#else
#define local__fwrite fwrite
#endif

Josh Coalson's avatar
Josh Coalson committed
754
FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
755
{
Josh Coalson's avatar
Josh Coalson committed
756
	FLAC__FileEncoder *file_encoder = (FLAC__FileEncoder*)client_data;
757

Josh Coalson's avatar
Josh Coalson committed
758
	(void)encoder, (void)samples, (void)current_frame;
759

Josh Coalson's avatar
Josh Coalson committed
760
	FLAC__ASSERT(0 != file_encoder);
761

762
	if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, file_encoder->private_->file) == bytes) {
763
		file_encoder->private_->bytes_written += bytes;
764
		file_encoder->private_->samples_written += samples;
765
766
767
768
769
		/* we keep a high watermark on the number of frames written because
		 * when the encoder goes back to write metadata, 'current_frame'
		 * will drop back to 0.
		 */
		file_encoder->private_->frames_written = max(file_encoder->private_->frames_written, current_frame+1);
770
		if(0 != file_encoder->private_->progress_callback && samples > 0)
771
			file_encoder->private_->progress_callback(file_encoder, file_encoder->private_->bytes_written, file_encoder->private_->samples_written, file_encoder->private_->frames_written, file_encoder->private_->total_frames_estimate, file_encoder->private_->client_data);
Josh Coalson's avatar
Josh Coalson committed
772
		return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
773
	}
Josh Coalson's avatar
Josh Coalson committed
774
775
	else
		return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
776
}