Rename _flac_stat to flac_stat_s.
[flac.git] / src / test_libFLAC++ / encoders.cpp
1 /* test_libFLAC++ - Unit tester for libFLAC++
2  * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009  Josh Coalson
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include "encoders.h"
20 #include "FLAC/assert.h"
21 #include "FLAC++/encoder.h"
22 #include "share/grabbag.h"
23 extern "C" {
24 #include "test_libs_common/file_utils_flac.h"
25 #include "test_libs_common/metadata_utils.h"
26 }
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include "share/compat.h"
32
33 typedef enum {
34         LAYER_STREAM = 0, /* FLAC__stream_encoder_init_stream() without seeking */
35         LAYER_SEEKABLE_STREAM, /* FLAC__stream_encoder_init_stream() with seeking */
36         LAYER_FILE, /* FLAC__stream_encoder_init_FILE() */
37         LAYER_FILENAME /* FLAC__stream_encoder_init_file() */
38 } Layer;
39
40 static const char * const LayerString[] = {
41         "Stream",
42         "Seekable Stream",
43         "FILE*",
44         "Filename"
45 };
46
47 static ::FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
48 static ::FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ };
49 static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
50
51 static const char *flacfilename(bool is_ogg)
52 {
53         return is_ogg? "metadata.oga" : "metadata.flac";
54 }
55
56 static bool die_(const char *msg)
57 {
58         printf("ERROR: %s\n", msg);
59         return false;
60 }
61
62 static bool die_s_(const char *msg, const FLAC::Encoder::Stream *encoder)
63 {
64         FLAC::Encoder::Stream::State state = encoder->get_state();
65
66         if(msg)
67                 printf("FAILED, %s", msg);
68         else
69                 printf("FAILED");
70
71         printf(", state = %u (%s)\n", (unsigned)((::FLAC__StreamEncoderState)state), state.as_cstring());
72         if(state == ::FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
73                 FLAC::Decoder::Stream::State dstate = encoder->get_verify_decoder_state();
74                 printf("      verify decoder state = %u (%s)\n", (unsigned)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
75         }
76
77         return false;
78 }
79
80 static void init_metadata_blocks_()
81 {
82         mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
83 }
84
85 static void free_metadata_blocks_()
86 {
87         mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
88 }
89
90 class StreamEncoder : public FLAC::Encoder::Stream {
91 public:
92         Layer layer_;
93         FILE *file_;
94
95         StreamEncoder(Layer layer): FLAC::Encoder::Stream(), layer_(layer), file_(0) { }
96         ~StreamEncoder() { }
97
98         // from FLAC::Encoder::Stream
99         ::FLAC__StreamEncoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes);
100         ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame);
101         ::FLAC__StreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset);
102         ::FLAC__StreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset);
103         void metadata_callback(const ::FLAC__StreamMetadata *metadata);
104 };
105
106 ::FLAC__StreamEncoderReadStatus StreamEncoder::read_callback(FLAC__byte buffer[], size_t *bytes)
107 {
108         if(*bytes > 0) {
109                 *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file_);
110                 if(ferror(file_))
111                         return ::FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
112                 else if(*bytes == 0)
113                         return ::FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
114                 else
115                         return ::FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
116         }
117         else
118                 return ::FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
119 }
120
121 ::FLAC__StreamEncoderWriteStatus StreamEncoder::write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame)
122 {
123         (void)samples, (void)current_frame;
124
125         if(fwrite(buffer, 1, bytes, file_) != bytes)
126                 return ::FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
127         else
128                 return ::FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
129 }
130
131 ::FLAC__StreamEncoderSeekStatus StreamEncoder::seek_callback(FLAC__uint64 absolute_byte_offset)
132 {
133         if(layer_==LAYER_STREAM)
134                 return ::FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
135         else if(fseeko(file_, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0)
136                 return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
137         else
138                 return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
139 }
140
141 ::FLAC__StreamEncoderTellStatus StreamEncoder::tell_callback(FLAC__uint64 *absolute_byte_offset)
142 {
143         FLAC__off_t pos;
144         if(layer_==LAYER_STREAM)
145                 return ::FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
146         else if((pos = ftello(file_)) < 0)
147                 return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
148         else {
149                 *absolute_byte_offset = (FLAC__uint64)pos;
150                 return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
151         }
152 }
153
154 void StreamEncoder::metadata_callback(const ::FLAC__StreamMetadata *metadata)
155 {
156         (void)metadata;
157 }
158
159 class FileEncoder : public FLAC::Encoder::File {
160 public:
161         Layer layer_;
162
163         FileEncoder(Layer layer): FLAC::Encoder::File(), layer_(layer) { }
164         ~FileEncoder() { }
165
166         // from FLAC::Encoder::File
167         void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate);
168 };
169
170 void FileEncoder::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate)
171 {
172         (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate;
173 }
174
175 static FLAC::Encoder::Stream *new_by_layer(Layer layer)
176 {
177         if(layer < LAYER_FILE)
178                 return new StreamEncoder(layer);
179         else
180                 return new FileEncoder(layer);
181 }
182
183 static bool test_stream_encoder(Layer layer, bool is_ogg)
184 {
185         FLAC::Encoder::Stream *encoder;
186         ::FLAC__StreamEncoderInitStatus init_status;
187         FILE *file = 0;
188         FLAC__int32 samples[1024];
189         FLAC__int32 *samples_array[1] = { samples };
190         unsigned i;
191
192         printf("\n+++ libFLAC++ unit test: FLAC::Encoder::%s (layer: %s, format: %s)\n\n", layer<LAYER_FILE? "Stream":"File", LayerString[layer], is_ogg? "Ogg FLAC":"FLAC");
193
194         printf("allocating encoder instance... ");
195         encoder = new_by_layer(layer);
196         if(0 == encoder) {
197                 printf("FAILED, new returned NULL\n");
198                 return false;
199         }
200         printf("OK\n");
201
202         printf("testing is_valid()... ");
203         if(!encoder->is_valid()) {
204                 printf("FAILED, returned false\n");
205                 return false;
206         }
207         printf("OK\n");
208
209         if(is_ogg) {
210                 printf("testing set_ogg_serial_number()... ");
211                 if(!encoder->set_ogg_serial_number(file_utils__ogg_serial_number))
212                         return die_s_("returned false", encoder);
213                 printf("OK\n");
214         }
215
216         printf("testing set_verify()... ");
217         if(!encoder->set_verify(true))
218                 return die_s_("returned false", encoder);
219         printf("OK\n");
220
221         printf("testing set_streamable_subset()... ");
222         if(!encoder->set_streamable_subset(true))
223                 return die_s_("returned false", encoder);
224         printf("OK\n");
225
226         printf("testing set_channels()... ");
227         if(!encoder->set_channels(streaminfo_.data.stream_info.channels))
228                 return die_s_("returned false", encoder);
229         printf("OK\n");
230
231         printf("testing set_bits_per_sample()... ");
232         if(!encoder->set_bits_per_sample(streaminfo_.data.stream_info.bits_per_sample))
233                 return die_s_("returned false", encoder);
234         printf("OK\n");
235
236         printf("testing set_sample_rate()... ");
237         if(!encoder->set_sample_rate(streaminfo_.data.stream_info.sample_rate))
238                 return die_s_("returned false", encoder);
239         printf("OK\n");
240
241         printf("testing set_compression_level()... ");
242         if(!encoder->set_compression_level((unsigned)(-1)))
243                 return die_s_("returned false", encoder);
244         printf("OK\n");
245
246         printf("testing set_blocksize()... ");
247         if(!encoder->set_blocksize(streaminfo_.data.stream_info.min_blocksize))
248                 return die_s_("returned false", encoder);
249         printf("OK\n");
250
251         printf("testing set_do_mid_side_stereo()... ");
252         if(!encoder->set_do_mid_side_stereo(false))
253                 return die_s_("returned false", encoder);
254         printf("OK\n");
255
256         printf("testing set_loose_mid_side_stereo()... ");
257         if(!encoder->set_loose_mid_side_stereo(false))
258                 return die_s_("returned false", encoder);
259         printf("OK\n");
260
261         printf("testing set_max_lpc_order()... ");
262         if(!encoder->set_max_lpc_order(0))
263                 return die_s_("returned false", encoder);
264         printf("OK\n");
265
266         printf("testing set_qlp_coeff_precision()... ");
267         if(!encoder->set_qlp_coeff_precision(0))
268                 return die_s_("returned false", encoder);
269         printf("OK\n");
270
271         printf("testing set_do_qlp_coeff_prec_search()... ");
272         if(!encoder->set_do_qlp_coeff_prec_search(false))
273                 return die_s_("returned false", encoder);
274         printf("OK\n");
275
276         printf("testing set_do_escape_coding()... ");
277         if(!encoder->set_do_escape_coding(false))
278                 return die_s_("returned false", encoder);
279         printf("OK\n");
280
281         printf("testing set_do_exhaustive_model_search()... ");
282         if(!encoder->set_do_exhaustive_model_search(false))
283                 return die_s_("returned false", encoder);
284         printf("OK\n");
285
286         printf("testing set_min_residual_partition_order()... ");
287         if(!encoder->set_min_residual_partition_order(0))
288                 return die_s_("returned false", encoder);
289         printf("OK\n");
290
291         printf("testing set_max_residual_partition_order()... ");
292         if(!encoder->set_max_residual_partition_order(0))
293                 return die_s_("returned false", encoder);
294         printf("OK\n");
295
296         printf("testing set_rice_parameter_search_dist()... ");
297         if(!encoder->set_rice_parameter_search_dist(0))
298                 return die_s_("returned false", encoder);
299         printf("OK\n");
300
301         printf("testing set_total_samples_estimate()... ");
302         if(!encoder->set_total_samples_estimate(streaminfo_.data.stream_info.total_samples))
303                 return die_s_("returned false", encoder);
304         printf("OK\n");
305
306         printf("testing set_metadata()... ");
307         if(!encoder->set_metadata(metadata_sequence_, num_metadata_))
308                 return die_s_("returned false", encoder);
309         printf("OK\n");
310
311         if(layer < LAYER_FILENAME) {
312                 printf("opening file for FLAC output... ");
313                 file = ::flac_fopen(flacfilename(is_ogg), "w+b");
314                 if(0 == file) {
315                         printf("ERROR (%s)\n", strerror(errno));
316                         return false;
317                 }
318                 printf("OK\n");
319                 if(layer < LAYER_FILE)
320                         dynamic_cast<StreamEncoder*>(encoder)->file_ = file;
321         }
322
323         switch(layer) {
324                 case LAYER_STREAM:
325                 case LAYER_SEEKABLE_STREAM:
326                         printf("testing init%s()... ", is_ogg? "_ogg":"");
327                         init_status = is_ogg? encoder->init_ogg() : encoder->init();
328                         break;
329                 case LAYER_FILE:
330                         printf("testing init%s()... ", is_ogg? "_ogg":"");
331                         init_status = is_ogg?
332                                 dynamic_cast<FLAC::Encoder::File*>(encoder)->init_ogg(file) :
333                                 dynamic_cast<FLAC::Encoder::File*>(encoder)->init(file);
334                         break;
335                 case LAYER_FILENAME:
336                         printf("testing init%s()... ", is_ogg? "_ogg":"");
337                         init_status = is_ogg?
338                                 dynamic_cast<FLAC::Encoder::File*>(encoder)->init_ogg(flacfilename(is_ogg)) :
339                                 dynamic_cast<FLAC::Encoder::File*>(encoder)->init(flacfilename(is_ogg));
340                         break;
341                 default:
342                         die_("internal error 001");
343                         return false;
344         }
345         if(init_status != ::FLAC__STREAM_ENCODER_INIT_STATUS_OK)
346                 return die_s_(0, encoder);
347         printf("OK\n");
348
349         printf("testing get_state()... ");
350         FLAC::Encoder::Stream::State state = encoder->get_state();
351         printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamEncoderState)state), state.as_cstring());
352
353         printf("testing get_verify_decoder_state()... ");
354         FLAC::Decoder::Stream::State dstate = encoder->get_verify_decoder_state();
355         printf("returned state = %u (%s)... OK\n", (unsigned)((::FLAC__StreamDecoderState)dstate), dstate.as_cstring());
356
357         {
358                 FLAC__uint64 absolute_sample;
359                 unsigned frame_number;
360                 unsigned channel;
361                 unsigned sample;
362                 FLAC__int32 expected;
363                 FLAC__int32 got;
364
365                 printf("testing get_verify_decoder_error_stats()... ");
366                 encoder->get_verify_decoder_error_stats(&absolute_sample, &frame_number, &channel, &sample, &expected, &got);
367                 printf("OK\n");
368         }
369
370         printf("testing get_verify()... ");
371         if(encoder->get_verify() != true) {
372                 printf("FAILED, expected true, got false\n");
373                 return false;
374         }
375         printf("OK\n");
376
377         printf("testing get_streamable_subset()... ");
378         if(encoder->get_streamable_subset() != true) {
379                 printf("FAILED, expected true, got false\n");
380                 return false;
381         }
382         printf("OK\n");
383
384         printf("testing get_do_mid_side_stereo()... ");
385         if(encoder->get_do_mid_side_stereo() != false) {
386                 printf("FAILED, expected false, got true\n");
387                 return false;
388         }
389         printf("OK\n");
390
391         printf("testing get_loose_mid_side_stereo()... ");
392         if(encoder->get_loose_mid_side_stereo() != false) {
393                 printf("FAILED, expected false, got true\n");
394                 return false;
395         }
396         printf("OK\n");
397
398         printf("testing get_channels()... ");
399         if(encoder->get_channels() != streaminfo_.data.stream_info.channels) {
400                 printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, encoder->get_channels());
401                 return false;
402         }
403         printf("OK\n");
404
405         printf("testing get_bits_per_sample()... ");
406         if(encoder->get_bits_per_sample() != streaminfo_.data.stream_info.bits_per_sample) {
407                 printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, encoder->get_bits_per_sample());
408                 return false;
409         }
410         printf("OK\n");
411
412         printf("testing get_sample_rate()... ");
413         if(encoder->get_sample_rate() != streaminfo_.data.stream_info.sample_rate) {
414                 printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, encoder->get_sample_rate());
415                 return false;
416         }
417         printf("OK\n");
418
419         printf("testing get_blocksize()... ");
420         if(encoder->get_blocksize() != streaminfo_.data.stream_info.min_blocksize) {
421                 printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, encoder->get_blocksize());
422                 return false;
423         }
424         printf("OK\n");
425
426         printf("testing get_max_lpc_order()... ");
427         if(encoder->get_max_lpc_order() != 0) {
428                 printf("FAILED, expected %u, got %u\n", 0, encoder->get_max_lpc_order());
429                 return false;
430         }
431         printf("OK\n");
432
433         printf("testing get_qlp_coeff_precision()... ");
434         (void)encoder->get_qlp_coeff_precision();
435         /* we asked the encoder to auto select this so we accept anything */
436         printf("OK\n");
437
438         printf("testing get_do_qlp_coeff_prec_search()... ");
439         if(encoder->get_do_qlp_coeff_prec_search() != false) {
440                 printf("FAILED, expected false, got true\n");
441                 return false;
442         }
443         printf("OK\n");
444
445         printf("testing get_do_escape_coding()... ");
446         if(encoder->get_do_escape_coding() != false) {
447                 printf("FAILED, expected false, got true\n");
448                 return false;
449         }
450         printf("OK\n");
451
452         printf("testing get_do_exhaustive_model_search()... ");
453         if(encoder->get_do_exhaustive_model_search() != false) {
454                 printf("FAILED, expected false, got true\n");
455                 return false;
456         }
457         printf("OK\n");
458
459         printf("testing get_min_residual_partition_order()... ");
460         if(encoder->get_min_residual_partition_order() != 0) {
461                 printf("FAILED, expected %u, got %u\n", 0, encoder->get_min_residual_partition_order());
462                 return false;
463         }
464         printf("OK\n");
465
466         printf("testing get_max_residual_partition_order()... ");
467         if(encoder->get_max_residual_partition_order() != 0) {
468                 printf("FAILED, expected %u, got %u\n", 0, encoder->get_max_residual_partition_order());
469                 return false;
470         }
471         printf("OK\n");
472
473         printf("testing get_rice_parameter_search_dist()... ");
474         if(encoder->get_rice_parameter_search_dist() != 0) {
475                 printf("FAILED, expected %u, got %u\n", 0, encoder->get_rice_parameter_search_dist());
476                 return false;
477         }
478         printf("OK\n");
479
480         printf("testing get_total_samples_estimate()... ");
481         if(encoder->get_total_samples_estimate() != streaminfo_.data.stream_info.total_samples) {
482                 printf("FAILED, expected %" PRIu64 ", got %" PRIu64 "\n", streaminfo_.data.stream_info.total_samples, encoder->get_total_samples_estimate());
483                 return false;
484         }
485         printf("OK\n");
486
487         /* init the dummy sample buffer */
488         for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
489                 samples[i] = i & 7;
490
491         printf("testing process()... ");
492         if(!encoder->process(samples_array, sizeof(samples) / sizeof(FLAC__int32)))
493                 return die_s_("returned false", encoder);
494         printf("OK\n");
495
496         printf("testing process_interleaved()... ");
497         if(!encoder->process_interleaved(samples, sizeof(samples) / sizeof(FLAC__int32)))
498                 return die_s_("returned false", encoder);
499         printf("OK\n");
500
501         printf("testing finish()... ");
502         if(!encoder->finish()) {
503                 state = encoder->get_state();
504                 printf("FAILED, returned false, state = %u (%s)\n", (unsigned)((::FLAC__StreamEncoderState)state), state.as_cstring());
505                 return false;
506         }
507         printf("OK\n");
508
509         if(layer < LAYER_FILE)
510                 ::fclose(dynamic_cast<StreamEncoder*>(encoder)->file_);
511
512         printf("freeing encoder instance... ");
513         delete encoder;
514         printf("OK\n");
515
516         printf("\nPASSED!\n");
517
518         return true;
519 }
520
521 bool test_encoders()
522 {
523         FLAC__bool is_ogg = false;
524
525         while(1) {
526                 init_metadata_blocks_();
527
528                 if(!test_stream_encoder(LAYER_STREAM, is_ogg))
529                         return false;
530
531                 if(!test_stream_encoder(LAYER_SEEKABLE_STREAM, is_ogg))
532                         return false;
533
534                 if(!test_stream_encoder(LAYER_FILE, is_ogg))
535                         return false;
536
537                 if(!test_stream_encoder(LAYER_FILENAME, is_ogg))
538                         return false;
539
540                 (void) grabbag__file_remove_file(flacfilename(is_ogg));
541
542                 free_metadata_blocks_();
543
544                 if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
545                         break;
546                 is_ogg = true;
547         }
548
549         return true;
550 }