minor comments
[flac.git] / src / libOggFLAC / seekable_stream_encoder.c
1 /* libOggFLAC - Free Lossless Audio Codec + Ogg library
2  * Copyright (C) 2002,2003,2004  Josh Coalson
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * - Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * - 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.
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h> /* for calloc() */
34 #include <string.h> /* for memcpy() */
35 #include "FLAC/assert.h"
36 #include "OggFLAC/seekable_stream_encoder.h"
37 #include "protected/seekable_stream_encoder.h"
38 #include "private/ogg_helper.h"
39
40 #ifdef max
41 #undef max
42 #endif
43 #define max(a,b) ((a)>(b)?(a):(b))
44
45 /***********************************************************************
46  *
47  * Private class method prototypes
48  *
49  ***********************************************************************/
50
51 /* unpublished debug routines */
52 extern FLAC__bool FLAC__stream_encoder_disable_constant_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
53 extern FLAC__bool FLAC__stream_encoder_disable_fixed_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
54 extern FLAC__bool FLAC__stream_encoder_disable_verbatim_subframes(FLAC__StreamEncoder *encoder, FLAC__bool value);
55
56 static void set_defaults_(OggFLAC__SeekableStreamEncoder *encoder);
57 static FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data);
58 static void metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data);
59
60
61 /***********************************************************************
62  *
63  * Private class data
64  *
65  ***********************************************************************/
66
67 typedef struct OggFLAC__SeekableStreamEncoderPrivate {
68         OggFLAC__SeekableStreamEncoderReadCallback read_callback;
69         OggFLAC__SeekableStreamEncoderSeekCallback seek_callback;
70         OggFLAC__SeekableStreamEncoderTellCallback tell_callback;
71         OggFLAC__SeekableStreamEncoderWriteCallback write_callback;
72         void *client_data;
73         FLAC__StreamEncoder *FLAC_stream_encoder;
74         FLAC__StreamMetadata_SeekTable *seek_table;
75         /* internal vars (all the above are class settings) */
76         unsigned first_seekpoint_to_check;
77         FLAC__uint64 samples_written;
78 } OggFLAC__SeekableStreamEncoderPrivate;
79
80
81 /***********************************************************************
82  *
83  * Public static class data
84  *
85  ***********************************************************************/
86
87 OggFLAC_API const char * const OggFLAC__SeekableStreamEncoderStateString[] = {
88         "OggFLAC__SEEKABLE_STREAM_ENCODER_OK",
89         "OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR",
90         "OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR",
91         "OggFLAC__SEEKABLE_STREAM_ENCODER_MEMORY_ALLOCATION_ERROR",
92         "OggFLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR",
93         "OggFLAC__SEEKABLE_STREAM_ENCODER_READ_ERROR",
94         "OggFLAC__SEEKABLE_STREAM_ENCODER_READ_ERROR",
95         "OggFLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR",
96         "OggFLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR",
97         "OggFLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED",
98         "OggFLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK",
99         "OggFLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE",
100         "OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED"
101 };
102
103 OggFLAC_API const char * const OggFLAC__SeekableStreamEncoderReadStatusString[] = {
104         "OggFLAC__SEEKABLE_STREAM_ENCODER_READ_STATUS_CONTINUE",
105         "OggFLAC__SEEKABLE_STREAM_ENCODER_READ_STATUS_END_OF_STREAM",
106         "OggFLAC__SEEKABLE_STREAM_ENCODER_READ_STATUS_ABORT"
107 };
108
109
110 /***********************************************************************
111  *
112  * Class constructor/destructor
113  *
114  */
115 OggFLAC_API OggFLAC__SeekableStreamEncoder *OggFLAC__seekable_stream_encoder_new()
116 {
117         OggFLAC__SeekableStreamEncoder *encoder;
118
119         encoder = (OggFLAC__SeekableStreamEncoder*)calloc(1, sizeof(OggFLAC__SeekableStreamEncoder));
120         if(encoder == 0) {
121                 return 0;
122         }
123
124         encoder->protected_ = (OggFLAC__SeekableStreamEncoderProtected*)calloc(1, sizeof(OggFLAC__SeekableStreamEncoderProtected));
125         if(encoder->protected_ == 0) {
126                 free(encoder);
127                 return 0;
128         }
129
130         encoder->private_ = (OggFLAC__SeekableStreamEncoderPrivate*)calloc(1, sizeof(OggFLAC__SeekableStreamEncoderPrivate));
131         if(encoder->private_ == 0) {
132                 free(encoder->protected_);
133                 free(encoder);
134                 return 0;
135         }
136
137         encoder->private_->FLAC_stream_encoder = FLAC__stream_encoder_new();
138         if(0 == encoder->private_->FLAC_stream_encoder) {
139                 free(encoder->private_);
140                 free(encoder->protected_);
141                 free(encoder);
142                 return 0;
143         }
144
145         set_defaults_(encoder);
146
147         encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED;
148
149         return encoder;
150 }
151
152 OggFLAC_API void OggFLAC__seekable_stream_encoder_delete(OggFLAC__SeekableStreamEncoder *encoder)
153 {
154         FLAC__ASSERT(0 != encoder);
155         FLAC__ASSERT(0 != encoder->protected_);
156         FLAC__ASSERT(0 != encoder->private_);
157         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
158
159         (void)OggFLAC__seekable_stream_encoder_finish(encoder);
160
161         FLAC__stream_encoder_delete(encoder->private_->FLAC_stream_encoder);
162
163         free(encoder->private_);
164         free(encoder->protected_);
165         free(encoder);
166 }
167
168
169 /***********************************************************************
170  *
171  * Public class methods
172  *
173  ***********************************************************************/
174
175 OggFLAC_API OggFLAC__SeekableStreamEncoderState OggFLAC__seekable_stream_encoder_init(OggFLAC__SeekableStreamEncoder *encoder)
176 {
177         FLAC__ASSERT(0 != encoder);
178
179         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
180                 return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED;
181
182         if(0 == encoder->private_->seek_callback || 0 == encoder->private_->tell_callback || 0 == encoder->private_->write_callback)
183                 return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK;
184
185         if(!OggFLAC__ogg_encoder_aspect_init(&encoder->protected_->ogg_encoder_aspect))
186                         return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR;
187
188         if(0 != encoder->private_->seek_table && !FLAC__format_seektable_is_legal(encoder->private_->seek_table))
189                 return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE;
190
191         /*
192          * These must be done before we init the stream encoder because that
193          * calls the write_callback, which uses these values.
194          */
195         encoder->private_->first_seekpoint_to_check = 0;
196         encoder->private_->samples_written = 0;
197         encoder->protected_->streaminfo_offset = 0;
198         encoder->protected_->seektable_offset = 0;
199         encoder->protected_->audio_offset = 0;
200
201         FLAC__stream_encoder_set_write_callback(encoder->private_->FLAC_stream_encoder, write_callback_);
202         FLAC__stream_encoder_set_metadata_callback(encoder->private_->FLAC_stream_encoder, metadata_callback_);
203         FLAC__stream_encoder_set_client_data(encoder->private_->FLAC_stream_encoder, encoder);
204
205         if(FLAC__stream_encoder_init(encoder->private_->FLAC_stream_encoder) != FLAC__STREAM_ENCODER_OK)
206                 return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR;
207
208         /*
209          * Initializing the stream encoder writes all the metadata, so we
210          * save the stream offset now.
211          */
212         if(encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK)
213                 return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR;
214
215         return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OK;
216 }
217
218 OggFLAC_API void OggFLAC__seekable_stream_encoder_finish(OggFLAC__SeekableStreamEncoder *encoder)
219 {
220         FLAC__ASSERT(0 != encoder);
221         FLAC__ASSERT(0 != encoder->private_);
222         FLAC__ASSERT(0 != encoder->protected_);
223
224         if(encoder->protected_->state == OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
225                 return;
226
227         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
228
229         FLAC__stream_encoder_finish(encoder->private_->FLAC_stream_encoder);
230
231         OggFLAC__ogg_encoder_aspect_finish(&encoder->protected_->ogg_encoder_aspect);
232
233         set_defaults_(encoder);
234
235         encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED;
236 }
237
238 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_serial_number(OggFLAC__SeekableStreamEncoder *encoder, long value)
239 {
240         FLAC__ASSERT(0 != encoder);
241         FLAC__ASSERT(0 != encoder->private_);
242         FLAC__ASSERT(0 != encoder->protected_);
243         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
244         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
245                 return false;
246         OggFLAC__ogg_encoder_aspect_set_serial_number(&encoder->protected_->ogg_encoder_aspect, value);
247         return true;
248 }
249
250 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_verify(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
251 {
252         FLAC__ASSERT(0 != encoder);
253         FLAC__ASSERT(0 != encoder->private_);
254         FLAC__ASSERT(0 != encoder->protected_);
255         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
256         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
257                 return false;
258         return FLAC__stream_encoder_set_verify(encoder->private_->FLAC_stream_encoder, value);
259 }
260
261 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_streamable_subset(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
262 {
263         FLAC__ASSERT(0 != encoder);
264         FLAC__ASSERT(0 != encoder->private_);
265         FLAC__ASSERT(0 != encoder->protected_);
266         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
267         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
268                 return false;
269         return FLAC__stream_encoder_set_streamable_subset(encoder->private_->FLAC_stream_encoder, value);
270 }
271
272 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_mid_side_stereo(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
273 {
274         FLAC__ASSERT(0 != encoder);
275         FLAC__ASSERT(0 != encoder->private_);
276         FLAC__ASSERT(0 != encoder->protected_);
277         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
278         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
279                 return false;
280         return FLAC__stream_encoder_set_do_mid_side_stereo(encoder->private_->FLAC_stream_encoder, value);
281 }
282
283 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_loose_mid_side_stereo(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
284 {
285         FLAC__ASSERT(0 != encoder);
286         FLAC__ASSERT(0 != encoder->private_);
287         FLAC__ASSERT(0 != encoder->protected_);
288         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
289         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
290                 return false;
291         return FLAC__stream_encoder_set_loose_mid_side_stereo(encoder->private_->FLAC_stream_encoder, value);
292 }
293
294 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_channels(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
295 {
296         FLAC__ASSERT(0 != encoder);
297         FLAC__ASSERT(0 != encoder->private_);
298         FLAC__ASSERT(0 != encoder->protected_);
299         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
300         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
301                 return false;
302         return FLAC__stream_encoder_set_channels(encoder->private_->FLAC_stream_encoder, value);
303 }
304
305 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_bits_per_sample(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
306 {
307         FLAC__ASSERT(0 != encoder);
308         FLAC__ASSERT(0 != encoder->private_);
309         FLAC__ASSERT(0 != encoder->protected_);
310         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
311         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
312                 return false;
313         return FLAC__stream_encoder_set_bits_per_sample(encoder->private_->FLAC_stream_encoder, value);
314 }
315
316 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_sample_rate(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
317 {
318         FLAC__ASSERT(0 != encoder);
319         FLAC__ASSERT(0 != encoder->private_);
320         FLAC__ASSERT(0 != encoder->protected_);
321         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
322         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
323                 return false;
324         return FLAC__stream_encoder_set_sample_rate(encoder->private_->FLAC_stream_encoder, value);
325 }
326
327 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_blocksize(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
328 {
329         FLAC__ASSERT(0 != encoder);
330         FLAC__ASSERT(0 != encoder->private_);
331         FLAC__ASSERT(0 != encoder->protected_);
332         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
333         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
334                 return false;
335         return FLAC__stream_encoder_set_blocksize(encoder->private_->FLAC_stream_encoder, value);
336 }
337
338 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_max_lpc_order(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
339 {
340         FLAC__ASSERT(0 != encoder);
341         FLAC__ASSERT(0 != encoder->private_);
342         FLAC__ASSERT(0 != encoder->protected_);
343         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
344         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
345                 return false;
346         return FLAC__stream_encoder_set_max_lpc_order(encoder->private_->FLAC_stream_encoder, value);
347 }
348
349 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_qlp_coeff_precision(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
350 {
351         FLAC__ASSERT(0 != encoder);
352         FLAC__ASSERT(0 != encoder->private_);
353         FLAC__ASSERT(0 != encoder->protected_);
354         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
355         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
356                 return false;
357         return FLAC__stream_encoder_set_qlp_coeff_precision(encoder->private_->FLAC_stream_encoder, value);
358 }
359
360 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
361 {
362         FLAC__ASSERT(0 != encoder);
363         FLAC__ASSERT(0 != encoder->private_);
364         FLAC__ASSERT(0 != encoder->protected_);
365         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
366         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
367                 return false;
368         return FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder->private_->FLAC_stream_encoder, value);
369 }
370
371 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_escape_coding(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
372 {
373         FLAC__ASSERT(0 != encoder);
374         FLAC__ASSERT(0 != encoder->private_);
375         FLAC__ASSERT(0 != encoder->protected_);
376         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
377         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
378                 return false;
379         return FLAC__stream_encoder_set_do_escape_coding(encoder->private_->FLAC_stream_encoder, value);
380 }
381
382 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_do_exhaustive_model_search(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
383 {
384         FLAC__ASSERT(0 != encoder);
385         FLAC__ASSERT(0 != encoder->private_);
386         FLAC__ASSERT(0 != encoder->protected_);
387         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
388         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
389                 return false;
390         return FLAC__stream_encoder_set_do_exhaustive_model_search(encoder->private_->FLAC_stream_encoder, value);
391 }
392
393 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_min_residual_partition_order(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
394 {
395         FLAC__ASSERT(0 != encoder);
396         FLAC__ASSERT(0 != encoder->private_);
397         FLAC__ASSERT(0 != encoder->protected_);
398         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
399         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
400                 return false;
401         return FLAC__stream_encoder_set_min_residual_partition_order(encoder->private_->FLAC_stream_encoder, value);
402 }
403
404 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_max_residual_partition_order(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
405 {
406         FLAC__ASSERT(0 != encoder);
407         FLAC__ASSERT(0 != encoder->private_);
408         FLAC__ASSERT(0 != encoder->protected_);
409         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
410         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
411                 return false;
412         return FLAC__stream_encoder_set_max_residual_partition_order(encoder->private_->FLAC_stream_encoder, value);
413 }
414
415 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_rice_parameter_search_dist(OggFLAC__SeekableStreamEncoder *encoder, unsigned value)
416 {
417         FLAC__ASSERT(0 != encoder);
418         FLAC__ASSERT(0 != encoder->private_);
419         FLAC__ASSERT(0 != encoder->protected_);
420         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
421         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
422                 return false;
423         return FLAC__stream_encoder_set_rice_parameter_search_dist(encoder->private_->FLAC_stream_encoder, value);
424 }
425
426 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_total_samples_estimate(OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 value)
427 {
428         FLAC__ASSERT(0 != encoder);
429         FLAC__ASSERT(0 != encoder->private_);
430         FLAC__ASSERT(0 != encoder->protected_);
431         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
432         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
433                 return false;
434         return FLAC__stream_encoder_set_total_samples_estimate(encoder->private_->FLAC_stream_encoder, value);
435 }
436
437 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_metadata(OggFLAC__SeekableStreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
438 {
439         FLAC__ASSERT(0 != encoder);
440         FLAC__ASSERT(0 != encoder->private_);
441         FLAC__ASSERT(0 != encoder->protected_);
442         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
443         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
444                 return false;
445         if(0 != metadata && num_blocks > 0) {
446                 unsigned i;
447                 for(i = 0; i < num_blocks; i++) {
448                         if(0 != metadata[i] && metadata[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) {
449                                 encoder->private_->seek_table = &metadata[i]->data.seek_table;
450                                 break; /* take only the first one */
451                         }
452                 }
453         }
454         return FLAC__stream_encoder_set_metadata(encoder->private_->FLAC_stream_encoder, metadata, num_blocks);
455 }
456
457 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_read_callback(OggFLAC__SeekableStreamEncoder *encoder, OggFLAC__SeekableStreamEncoderReadCallback value)
458 {
459         FLAC__ASSERT(0 != encoder);
460         FLAC__ASSERT(0 != encoder->private_);
461         FLAC__ASSERT(0 != encoder->protected_);
462         FLAC__ASSERT(0 != value);
463         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
464                 return false;
465         encoder->private_->read_callback = value;
466         return true;
467 }
468
469 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_seek_callback(OggFLAC__SeekableStreamEncoder *encoder, OggFLAC__SeekableStreamEncoderSeekCallback value)
470 {
471         FLAC__ASSERT(0 != encoder);
472         FLAC__ASSERT(0 != encoder->private_);
473         FLAC__ASSERT(0 != encoder->protected_);
474         FLAC__ASSERT(0 != value);
475         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
476                 return false;
477         encoder->private_->seek_callback = value;
478         return true;
479 }
480
481 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_tell_callback(OggFLAC__SeekableStreamEncoder *encoder, OggFLAC__SeekableStreamEncoderTellCallback value)
482 {
483         FLAC__ASSERT(0 != encoder);
484         FLAC__ASSERT(0 != encoder->private_);
485         FLAC__ASSERT(0 != encoder->protected_);
486         FLAC__ASSERT(0 != value);
487         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
488                 return false;
489         encoder->private_->tell_callback = value;
490         return true;
491 }
492
493 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_write_callback(OggFLAC__SeekableStreamEncoder *encoder, OggFLAC__SeekableStreamEncoderWriteCallback value)
494 {
495         FLAC__ASSERT(0 != encoder);
496         FLAC__ASSERT(0 != encoder->private_);
497         FLAC__ASSERT(0 != encoder->protected_);
498         FLAC__ASSERT(0 != value);
499         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
500                 return false;
501         encoder->private_->write_callback = value;
502         return true;
503 }
504
505 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_set_client_data(OggFLAC__SeekableStreamEncoder *encoder, void *value)
506 {
507         FLAC__ASSERT(0 != encoder);
508         FLAC__ASSERT(0 != encoder->private_);
509         FLAC__ASSERT(0 != encoder->protected_);
510         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
511                 return false;
512         encoder->private_->client_data = value;
513         return true;
514 }
515
516 /*
517  * These three functions are not static, but not publically exposed in
518  * include/FLAC/ either.  They are used by the test suite.
519  */
520 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_disable_constant_subframes(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
521 {
522         FLAC__ASSERT(0 != encoder);
523         FLAC__ASSERT(0 != encoder->private_);
524         FLAC__ASSERT(0 != encoder->protected_);
525         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
526                 return false;
527         return FLAC__stream_encoder_disable_constant_subframes(encoder->private_->FLAC_stream_encoder, value);
528 }
529
530 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_disable_fixed_subframes(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
531 {
532         FLAC__ASSERT(0 != encoder);
533         FLAC__ASSERT(0 != encoder->private_);
534         FLAC__ASSERT(0 != encoder->protected_);
535         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
536                 return false;
537         return FLAC__stream_encoder_disable_fixed_subframes(encoder->private_->FLAC_stream_encoder, value);
538 }
539
540 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_disable_verbatim_subframes(OggFLAC__SeekableStreamEncoder *encoder, FLAC__bool value)
541 {
542         FLAC__ASSERT(0 != encoder);
543         FLAC__ASSERT(0 != encoder->private_);
544         FLAC__ASSERT(0 != encoder->protected_);
545         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
546                 return false;
547         return FLAC__stream_encoder_disable_verbatim_subframes(encoder->private_->FLAC_stream_encoder, value);
548 }
549
550 OggFLAC_API OggFLAC__SeekableStreamEncoderState OggFLAC__seekable_stream_encoder_get_state(const OggFLAC__SeekableStreamEncoder *encoder)
551 {
552         FLAC__ASSERT(0 != encoder);
553         FLAC__ASSERT(0 != encoder->private_);
554         FLAC__ASSERT(0 != encoder->protected_);
555         return encoder->protected_->state;
556 }
557
558 OggFLAC_API FLAC__StreamEncoderState OggFLAC__seekable_stream_encoder_get_FLAC_stream_encoder_state(const OggFLAC__SeekableStreamEncoder *encoder)
559 {
560         FLAC__ASSERT(0 != encoder);
561         FLAC__ASSERT(0 != encoder->private_);
562         FLAC__ASSERT(0 != encoder->protected_);
563         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
564         return FLAC__stream_encoder_get_state(encoder->private_->FLAC_stream_encoder);
565 }
566
567 OggFLAC_API FLAC__StreamDecoderState OggFLAC__seekable_stream_encoder_get_verify_decoder_state(const OggFLAC__SeekableStreamEncoder *encoder)
568 {
569         FLAC__ASSERT(0 != encoder);
570         FLAC__ASSERT(0 != encoder->private_);
571         FLAC__ASSERT(0 != encoder->protected_);
572         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
573         return FLAC__stream_encoder_get_verify_decoder_state(encoder->private_->FLAC_stream_encoder);
574 }
575
576 OggFLAC_API const char *OggFLAC__seekable_stream_encoder_get_resolved_state_string(const OggFLAC__SeekableStreamEncoder *encoder)
577 {
578         FLAC__ASSERT(0 != encoder);
579         FLAC__ASSERT(0 != encoder->private_);
580         FLAC__ASSERT(0 != encoder->protected_);
581         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
582         if(encoder->protected_->state != OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR)
583                 return OggFLAC__SeekableStreamEncoderStateString[encoder->protected_->state];
584         else
585                 return FLAC__stream_encoder_get_resolved_state_string(encoder->private_->FLAC_stream_encoder);
586 }
587
588 OggFLAC_API void OggFLAC__seekable_stream_encoder_get_verify_decoder_error_stats(const OggFLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
589 {
590         FLAC__ASSERT(0 != encoder);
591         FLAC__ASSERT(0 != encoder->private_);
592         FLAC__ASSERT(0 != encoder->protected_);
593         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
594         FLAC__stream_encoder_get_verify_decoder_error_stats(encoder->private_->FLAC_stream_encoder, absolute_sample, frame_number, channel, sample, expected, got);
595 }
596
597 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_verify(const OggFLAC__SeekableStreamEncoder *encoder)
598 {
599         FLAC__ASSERT(0 != encoder);
600         FLAC__ASSERT(0 != encoder->private_);
601         FLAC__ASSERT(0 != encoder->protected_);
602         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
603         return FLAC__stream_encoder_get_verify(encoder->private_->FLAC_stream_encoder);
604 }
605
606 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_streamable_subset(const OggFLAC__SeekableStreamEncoder *encoder)
607 {
608         FLAC__ASSERT(0 != encoder);
609         FLAC__ASSERT(0 != encoder->private_);
610         FLAC__ASSERT(0 != encoder->protected_);
611         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
612         return FLAC__stream_encoder_get_streamable_subset(encoder->private_->FLAC_stream_encoder);
613 }
614
615 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_mid_side_stereo(const OggFLAC__SeekableStreamEncoder *encoder)
616 {
617         FLAC__ASSERT(0 != encoder);
618         FLAC__ASSERT(0 != encoder->private_);
619         FLAC__ASSERT(0 != encoder->protected_);
620         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
621         return FLAC__stream_encoder_get_do_mid_side_stereo(encoder->private_->FLAC_stream_encoder);
622 }
623
624 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_loose_mid_side_stereo(const OggFLAC__SeekableStreamEncoder *encoder)
625 {
626         FLAC__ASSERT(0 != encoder);
627         FLAC__ASSERT(0 != encoder->private_);
628         FLAC__ASSERT(0 != encoder->protected_);
629         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
630         return FLAC__stream_encoder_get_loose_mid_side_stereo(encoder->private_->FLAC_stream_encoder);
631 }
632
633 OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_channels(const OggFLAC__SeekableStreamEncoder *encoder)
634 {
635         FLAC__ASSERT(0 != encoder);
636         FLAC__ASSERT(0 != encoder->private_);
637         FLAC__ASSERT(0 != encoder->protected_);
638         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
639         return FLAC__stream_encoder_get_channels(encoder->private_->FLAC_stream_encoder);
640 }
641
642 OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_bits_per_sample(const OggFLAC__SeekableStreamEncoder *encoder)
643 {
644         FLAC__ASSERT(0 != encoder);
645         FLAC__ASSERT(0 != encoder->private_);
646         FLAC__ASSERT(0 != encoder->protected_);
647         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
648         return FLAC__stream_encoder_get_bits_per_sample(encoder->private_->FLAC_stream_encoder);
649 }
650
651 OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_sample_rate(const OggFLAC__SeekableStreamEncoder *encoder)
652 {
653         FLAC__ASSERT(0 != encoder);
654         FLAC__ASSERT(0 != encoder->private_);
655         FLAC__ASSERT(0 != encoder->protected_);
656         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
657         return FLAC__stream_encoder_get_sample_rate(encoder->private_->FLAC_stream_encoder);
658 }
659
660 OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_blocksize(const OggFLAC__SeekableStreamEncoder *encoder)
661 {
662         FLAC__ASSERT(0 != encoder);
663         FLAC__ASSERT(0 != encoder->private_);
664         FLAC__ASSERT(0 != encoder->protected_);
665         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
666         return FLAC__stream_encoder_get_blocksize(encoder->private_->FLAC_stream_encoder);
667 }
668
669 OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_max_lpc_order(const OggFLAC__SeekableStreamEncoder *encoder)
670 {
671         FLAC__ASSERT(0 != encoder);
672         FLAC__ASSERT(0 != encoder->private_);
673         FLAC__ASSERT(0 != encoder->protected_);
674         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
675         return FLAC__stream_encoder_get_max_lpc_order(encoder->private_->FLAC_stream_encoder);
676 }
677
678 OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_qlp_coeff_precision(const OggFLAC__SeekableStreamEncoder *encoder)
679 {
680         FLAC__ASSERT(0 != encoder);
681         FLAC__ASSERT(0 != encoder->private_);
682         FLAC__ASSERT(0 != encoder->protected_);
683         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
684         return FLAC__stream_encoder_get_qlp_coeff_precision(encoder->private_->FLAC_stream_encoder);
685 }
686
687 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search(const OggFLAC__SeekableStreamEncoder *encoder)
688 {
689         FLAC__ASSERT(0 != encoder);
690         FLAC__ASSERT(0 != encoder->private_);
691         FLAC__ASSERT(0 != encoder->protected_);
692         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
693         return FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder->private_->FLAC_stream_encoder);
694 }
695
696 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_escape_coding(const OggFLAC__SeekableStreamEncoder *encoder)
697 {
698         FLAC__ASSERT(0 != encoder);
699         FLAC__ASSERT(0 != encoder->private_);
700         FLAC__ASSERT(0 != encoder->protected_);
701         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
702         return FLAC__stream_encoder_get_do_escape_coding(encoder->private_->FLAC_stream_encoder);
703 }
704
705 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_get_do_exhaustive_model_search(const OggFLAC__SeekableStreamEncoder *encoder)
706 {
707         FLAC__ASSERT(0 != encoder);
708         FLAC__ASSERT(0 != encoder->private_);
709         FLAC__ASSERT(0 != encoder->protected_);
710         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
711         return FLAC__stream_encoder_get_do_exhaustive_model_search(encoder->private_->FLAC_stream_encoder);
712 }
713
714 OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_min_residual_partition_order(const OggFLAC__SeekableStreamEncoder *encoder)
715 {
716         FLAC__ASSERT(0 != encoder);
717         FLAC__ASSERT(0 != encoder->private_);
718         FLAC__ASSERT(0 != encoder->protected_);
719         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
720         return FLAC__stream_encoder_get_min_residual_partition_order(encoder->private_->FLAC_stream_encoder);
721 }
722
723 OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_max_residual_partition_order(const OggFLAC__SeekableStreamEncoder *encoder)
724 {
725         FLAC__ASSERT(0 != encoder);
726         FLAC__ASSERT(0 != encoder->private_);
727         FLAC__ASSERT(0 != encoder->protected_);
728         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
729         return FLAC__stream_encoder_get_max_residual_partition_order(encoder->private_->FLAC_stream_encoder);
730 }
731
732 OggFLAC_API unsigned OggFLAC__seekable_stream_encoder_get_rice_parameter_search_dist(const OggFLAC__SeekableStreamEncoder *encoder)
733 {
734         FLAC__ASSERT(0 != encoder);
735         FLAC__ASSERT(0 != encoder->private_);
736         FLAC__ASSERT(0 != encoder->protected_);
737         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
738         return FLAC__stream_encoder_get_rice_parameter_search_dist(encoder->private_->FLAC_stream_encoder);
739 }
740
741 OggFLAC_API FLAC__uint64 OggFLAC__seekable_stream_encoder_get_total_samples_estimate(const OggFLAC__SeekableStreamEncoder *encoder)
742 {
743         FLAC__ASSERT(0 != encoder);
744         FLAC__ASSERT(0 != encoder->private_);
745         FLAC__ASSERT(0 != encoder->protected_);
746         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
747         return FLAC__stream_encoder_get_total_samples_estimate(encoder->private_->FLAC_stream_encoder);
748 }
749
750 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_process(OggFLAC__SeekableStreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
751 {
752         FLAC__ASSERT(0 != encoder);
753         FLAC__ASSERT(0 != encoder->private_);
754         FLAC__ASSERT(0 != encoder->protected_);
755         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
756         if(!FLAC__stream_encoder_process(encoder->private_->FLAC_stream_encoder, buffer, samples)) {
757                 encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR;
758                 return false;
759         }
760         else
761                 return true;
762 }
763
764 OggFLAC_API FLAC__bool OggFLAC__seekable_stream_encoder_process_interleaved(OggFLAC__SeekableStreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
765 {
766         FLAC__ASSERT(0 != encoder);
767         FLAC__ASSERT(0 != encoder->private_);
768         FLAC__ASSERT(0 != encoder->protected_);
769         FLAC__ASSERT(0 != encoder->private_->FLAC_stream_encoder);
770         if(!FLAC__stream_encoder_process_interleaved(encoder->private_->FLAC_stream_encoder, buffer, samples)) {
771                 encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_FLAC_STREAM_ENCODER_ERROR;
772                 return false;
773         }
774         else
775                 return true;
776 }
777
778 /***********************************************************************
779  *
780  * Private class methods
781  *
782  ***********************************************************************/
783
784 void set_defaults_(OggFLAC__SeekableStreamEncoder *encoder)
785 {
786         FLAC__ASSERT(0 != encoder);
787         FLAC__ASSERT(0 != encoder->private_);
788         FLAC__ASSERT(0 != encoder->protected_);
789
790         encoder->private_->seek_callback = 0;
791         encoder->private_->tell_callback = 0;
792         encoder->private_->write_callback = 0;
793         encoder->private_->client_data = 0;
794
795         encoder->private_->seek_table = 0;
796
797         OggFLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect);
798 }
799
800 FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *unused, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data)
801 {
802         OggFLAC__SeekableStreamEncoder *encoder = (OggFLAC__SeekableStreamEncoder*)client_data;
803         FLAC__StreamEncoderWriteStatus status;
804         FLAC__uint64 output_position;
805
806         (void)unused; /* silence compiler warning about unused parameter */
807         FLAC__ASSERT(encoder->private_->FLAC_stream_encoder == unused);
808
809         if(encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK)
810                 return encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR;
811
812         /*
813          * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets.
814          */
815         if(samples == 0) {
816                 FLAC__MetadataType type = (buffer[0] & 0x7f);
817                 if(type == FLAC__METADATA_TYPE_STREAMINFO)
818                         encoder->protected_->streaminfo_offset = output_position;
819                 else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0)
820                         encoder->protected_->seektable_offset = output_position;
821         }
822
823         /*
824          * Mark the current seek point if hit (if audio_offset == 0 that
825          * means we're still writing metadata and haven't hit the first
826          * frame yet)
827          */
828         if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) {
829                 const unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder->private_->FLAC_stream_encoder);
830                 const FLAC__uint64 frame_first_sample = encoder->private_->samples_written;
831                 const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1;
832                 FLAC__uint64 test_sample;
833                 unsigned i;
834                 for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) {
835                         test_sample = encoder->private_->seek_table->points[i].sample_number;
836                         if(test_sample > frame_last_sample) {
837                                 break;
838                         }
839                         else if(test_sample >= frame_first_sample) {
840                                 encoder->private_->seek_table->points[i].sample_number = frame_first_sample;
841                                 encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset;
842                                 encoder->private_->seek_table->points[i].frame_samples = blocksize;
843                                 encoder->private_->first_seekpoint_to_check++;
844                                 /* DO NOT: "break;" and here's why:
845                                  * The seektable template may contain more than one target
846                                  * sample for any given frame; we will keep looping, generating
847                                  * duplicate seekpoints for them, and we'll clean it up later,
848                                  * just before writing the seektable back to the metadata.
849                                  */
850                         }
851                         else {
852                                 encoder->private_->first_seekpoint_to_check++;
853                         }
854                 }
855         }
856
857         status = OggFLAC__ogg_encoder_aspect_write_callback_wrapper(&encoder->protected_->ogg_encoder_aspect, FLAC__stream_encoder_get_total_samples_estimate(encoder->private_->FLAC_stream_encoder), buffer, bytes, samples, current_frame, (OggFLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback, encoder, encoder->private_->client_data);
858
859         if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
860                 encoder->private_->samples_written += samples;
861         }
862         else
863                 encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR;
864
865         return status;
866 }
867
868 void metadata_callback_(const FLAC__StreamEncoder *unused, const FLAC__StreamMetadata *metadata, void *client_data)
869 {
870         OggFLAC__SeekableStreamEncoder *encoder = (OggFLAC__SeekableStreamEncoder*)client_data;
871         FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
872         const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
873         const unsigned min_framesize = metadata->data.stream_info.min_framesize;
874         const unsigned max_framesize = metadata->data.stream_info.max_framesize;
875         ogg_page page;
876
877         FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
878
879         /* We get called by the stream encoder when the encoding process
880          * has finished so that we can update the STREAMINFO and SEEKTABLE
881          * blocks.
882          */
883
884         (void)unused; /* silence compiler warning about unused parameter */
885         FLAC__ASSERT(encoder->private_->FLAC_stream_encoder == unused);
886
887         /*@@@ reopen callback here?  The docs currently require user to open files in update mode from the start */
888
889         /* All this is based on intimate knowledge of the stream header
890          * layout, but a change to the header format that would break this
891          * would also break all streams encoded in the previous format.
892          */
893
894         /*
895          * Write STREAMINFO stats
896          */
897         simple_ogg_page__init(&page);
898         if(!simple_ogg_page__get_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
899                 simple_ogg_page__clear(&page);
900                 return; /* state already set */
901         }
902         /*
903          * MD5 signature
904          */
905         {
906                 const unsigned md5_offset =
907                         FLAC__STREAM_METADATA_HEADER_LENGTH +
908                         (
909                                 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
910                                 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
911                                 FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
912                                 FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
913                                 FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
914                                 FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
915                                 FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN +
916                                 FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN
917                         ) / 8;
918
919                 if(md5_offset + 16 > (unsigned)page.body_len) {
920                         encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR;
921                         simple_ogg_page__clear(&page);
922                         return;
923                 }
924                 memcpy(page.body + md5_offset, metadata->data.stream_info.md5sum, 16);
925         }
926         /*
927          * total samples
928          */
929         {
930                 const unsigned total_samples_byte_offset =
931                         FLAC__STREAM_METADATA_HEADER_LENGTH +
932                         (
933                                 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
934                                 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
935                                 FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
936                                 FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
937                                 FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
938                                 FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
939                                 FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN
940                                 - 4
941                         ) / 8;
942
943                 if(total_samples_byte_offset + 5 > (unsigned)page.body_len) {
944                         encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR;
945                         simple_ogg_page__clear(&page);
946                         return;
947                 }
948                 b[0] = (FLAC__byte)page.body[total_samples_byte_offset] & 0xF0;
949                 b[0] |= (FLAC__byte)((samples >> 32) & 0x0F);
950                 b[1] = (FLAC__byte)((samples >> 24) & 0xFF);
951                 b[2] = (FLAC__byte)((samples >> 16) & 0xFF);
952                 b[3] = (FLAC__byte)((samples >> 8) & 0xFF);
953                 b[4] = (FLAC__byte)(samples & 0xFF);
954                 memcpy(page.body + total_samples_byte_offset, b, 5);
955         }
956         /*
957          * min/max framesize
958          */
959         {
960                 const unsigned min_framesize_offset =
961                         FLAC__STREAM_METADATA_HEADER_LENGTH +
962                         (
963                                 FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
964                                 FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
965                         ) / 8;
966
967                 if(min_framesize_offset + 6 > (unsigned)page.body_len) {
968                         encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR;
969                         simple_ogg_page__clear(&page);
970                         return;
971                 }
972                 b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF);
973                 b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF);
974                 b[2] = (FLAC__byte)(min_framesize & 0xFF);
975                 b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF);
976                 b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF);
977                 b[5] = (FLAC__byte)(max_framesize & 0xFF);
978                 memcpy(page.body + min_framesize_offset, b, 6);
979         }
980         if(!simple_ogg_page__set_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
981                 simple_ogg_page__clear(&page);
982                 return; /* state already set */
983         }
984         simple_ogg_page__clear(&page);
985
986         /*
987          * Write seektable
988          */
989         if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
990                 unsigned i;
991                 FLAC__byte *p;
992
993                 FLAC__format_seektable_sort(encoder->private_->seek_table);
994
995                 FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
996
997                 simple_ogg_page__init(&page);
998                 if(!simple_ogg_page__get_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
999                         simple_ogg_page__clear(&page);
1000                         return; /* state already set */
1001                 }
1002
1003                 if(FLAC__STREAM_METADATA_HEADER_LENGTH + (18*encoder->private_->seek_table->num_points) > (unsigned)page.body_len) {
1004                         encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_OGG_ERROR;
1005                         simple_ogg_page__clear(&page);
1006                         return;
1007                 }
1008
1009                 for(i = 0, p = page.body + FLAC__STREAM_METADATA_HEADER_LENGTH; i < encoder->private_->seek_table->num_points; i++, p += 18) {
1010                         FLAC__uint64 xx;
1011                         unsigned x;
1012                         xx = encoder->private_->seek_table->points[i].sample_number;
1013                         b[7] = (FLAC__byte)xx; xx >>= 8;
1014                         b[6] = (FLAC__byte)xx; xx >>= 8;
1015                         b[5] = (FLAC__byte)xx; xx >>= 8;
1016                         b[4] = (FLAC__byte)xx; xx >>= 8;
1017                         b[3] = (FLAC__byte)xx; xx >>= 8;
1018                         b[2] = (FLAC__byte)xx; xx >>= 8;
1019                         b[1] = (FLAC__byte)xx; xx >>= 8;
1020                         b[0] = (FLAC__byte)xx; xx >>= 8;
1021                         xx = encoder->private_->seek_table->points[i].stream_offset;
1022                         b[15] = (FLAC__byte)xx; xx >>= 8;
1023                         b[14] = (FLAC__byte)xx; xx >>= 8;
1024                         b[13] = (FLAC__byte)xx; xx >>= 8;
1025                         b[12] = (FLAC__byte)xx; xx >>= 8;
1026                         b[11] = (FLAC__byte)xx; xx >>= 8;
1027                         b[10] = (FLAC__byte)xx; xx >>= 8;
1028                         b[9] = (FLAC__byte)xx; xx >>= 8;
1029                         b[8] = (FLAC__byte)xx; xx >>= 8;
1030                         x = encoder->private_->seek_table->points[i].frame_samples;
1031                         b[17] = (FLAC__byte)x; x >>= 8;
1032                         b[16] = (FLAC__byte)x; x >>= 8;
1033                         if(encoder->private_->write_callback(encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
1034                                 encoder->protected_->state = OggFLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR;
1035                                 simple_ogg_page__clear(&page);
1036                                 return;
1037                         }
1038                         memcpy(p, b, 18);
1039                 }
1040
1041                 if(!simple_ogg_page__set_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
1042                         simple_ogg_page__clear(&page);
1043                         return; /* state already set */
1044                 }
1045                 simple_ogg_page__clear(&page);
1046         }
1047 }