/src/flac/oss-fuzz/encoder_v2.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* fuzzer_encoder_v2 |
2 | | * Copyright (C) 2022-2025 Xiph.Org Foundation |
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 <cstdlib> |
33 | | #include <cstring> /* for memcpy */ |
34 | | #include "FLAC/stream_encoder.h" |
35 | | #include "FLAC/metadata.h" |
36 | | extern "C" { |
37 | | #include "share/private.h" |
38 | | } |
39 | | #include "common.h" |
40 | | |
41 | | /* This C++ fuzzer uses the FLAC and not FLAC++ because the latter lacks a few |
42 | | * hidden functions like FLAC__stream_encoder_disable_constant_subframes. It |
43 | | * is still processed by a C++ compiler because that's what oss-fuzz expects */ |
44 | | |
45 | | |
46 | | static FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data) |
47 | 80.8k | { |
48 | 80.8k | (void)encoder, (void)buffer, (void)bytes, (void)samples, (void)current_frame, (void)client_data; |
49 | 80.8k | return FLAC__STREAM_ENCODER_WRITE_STATUS_OK; |
50 | 80.8k | } |
51 | | |
52 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
53 | 12.2k | { |
54 | 12.2k | FLAC__bool encoder_valid = true; |
55 | 12.2k | FLAC__StreamEncoder *encoder = 0; |
56 | 12.2k | FLAC__StreamEncoderState state; |
57 | 12.2k | const char* state_string = ""; |
58 | 12.2k | FLAC__StreamMetadata *metadata[16] = {NULL}; |
59 | 12.2k | unsigned num_metadata = 0; |
60 | 12.2k | FLAC__StreamMetadata_VorbisComment_Entry VorbisCommentField; |
61 | | |
62 | 12.2k | unsigned sample_rate, channels, bps; |
63 | 12.2k | uint64_t samples_estimate, samples_in_input; |
64 | 12.2k | unsigned compression_level, input_data_width, blocksize, max_lpc_order, qlp_coeff_precision, min_residual_partition_order, max_residual_partition_order, metadata_mask, instruction_set_disable_mask; |
65 | 12.2k | FLAC__bool ogg, write_to_file, interleaved; |
66 | | |
67 | 12.2k | FLAC__bool data_bools[24]; |
68 | | |
69 | | /* Set alloc threshold. This check was added later and no spare config |
70 | | * bytes were left, so we're reusing the sample rate as that of little |
71 | | * consequence to the encoder and decoder except reading the frame header */ |
72 | | |
73 | 12.2k | if(size < 3) |
74 | 2 | return 0; |
75 | 12.2k | alloc_check_threshold = data[2]; |
76 | 12.2k | alloc_check_counter = 0; |
77 | | |
78 | | /* allocate the encoder */ |
79 | 12.2k | if((encoder = FLAC__stream_encoder_new()) == NULL) { |
80 | 12 | return 0; |
81 | 12 | } |
82 | | |
83 | | /* Use first 20 byte for configuration */ |
84 | 12.2k | if(size < 20){ |
85 | 21 | FLAC__stream_encoder_delete(encoder); |
86 | 21 | return 0; |
87 | 21 | } |
88 | | |
89 | | /* First 3 byte for sample rate, 4th byte for channels, 5th byte for bps */ |
90 | 12.2k | sample_rate = ((unsigned)data[0] << 16) + ((unsigned)data[1] << 8) + data[2]; |
91 | 12.2k | channels = data[3]; |
92 | 12.2k | bps = data[4]; |
93 | | |
94 | | /* Number of samples estimate, format accepts 36-bit max */ |
95 | 12.2k | samples_estimate = ((uint64_t)data[5] << 32) + ((unsigned)data[6] << 24) + ((unsigned)data[7] << 16) + ((unsigned)data[8] << 8) + data[9]; |
96 | | |
97 | 12.2k | compression_level = data[10]&0b1111; |
98 | 12.2k | input_data_width = 1 + (data[10]>>4)%4; |
99 | 12.2k | samples_in_input = (size-20)/input_data_width; |
100 | 12.2k | blocksize = ((unsigned)data[11] << 8) + (unsigned)data[12]; |
101 | 12.2k | max_lpc_order = data[13]; |
102 | 12.2k | qlp_coeff_precision = data[14]; |
103 | 12.2k | min_residual_partition_order = data[15] & 0b1111; |
104 | 12.2k | max_residual_partition_order = data[15] & 0b11110000; |
105 | 12.2k | metadata_mask = data[16]; |
106 | 12.2k | instruction_set_disable_mask = data[17]; |
107 | | |
108 | | /* Get array of bools from configuration */ |
109 | 208k | for(int i = 0; i < 16; i++) |
110 | 196k | data_bools[i] = data[18+i/8] & (1 << (i % 8)); |
111 | | |
112 | 12.2k | ogg = data_bools[0]; |
113 | 12.2k | interleaved = data_bools[1]; |
114 | 12.2k | write_to_file = data_bools[13]; |
115 | | |
116 | | /* Set input and process parameters */ |
117 | 12.2k | encoder_valid &= FLAC__stream_encoder_set_verify(encoder, data_bools[2]); |
118 | 12.2k | encoder_valid &= FLAC__stream_encoder_set_channels(encoder, channels); |
119 | 12.2k | encoder_valid &= FLAC__stream_encoder_set_bits_per_sample(encoder, bps); |
120 | 12.2k | encoder_valid &= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate); |
121 | 12.2k | encoder_valid &= FLAC__stream_encoder_set_total_samples_estimate(encoder, samples_estimate); |
122 | 12.2k | encoder_valid &= FLAC__stream_encoder_disable_instruction_set(encoder, instruction_set_disable_mask); |
123 | 12.2k | encoder_valid &= FLAC__stream_encoder_set_limit_min_bitrate(encoder, data_bools[15]); |
124 | 12.2k | encoder_valid &= (FLAC__stream_encoder_set_num_threads(encoder,data[9]) == FLAC__STREAM_ENCODER_SET_NUM_THREADS_OK); /* reuse data[9] */ |
125 | | |
126 | | /* Set compression related parameters */ |
127 | 12.2k | encoder_valid &= FLAC__stream_encoder_set_compression_level(encoder, compression_level); |
128 | 12.2k | if(data_bools[3]){ |
129 | | /* Bias towards regular compression levels */ |
130 | 9.70k | encoder_valid &= FLAC__stream_encoder_set_blocksize(encoder, blocksize); |
131 | 9.70k | encoder_valid &= FLAC__stream_encoder_set_max_lpc_order(encoder, max_lpc_order); |
132 | 9.70k | encoder_valid &= FLAC__stream_encoder_set_qlp_coeff_precision(encoder, qlp_coeff_precision); |
133 | 9.70k | encoder_valid &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, min_residual_partition_order); |
134 | | |
135 | | /* With large inputs and expensive options enabled, the fuzzer can get *really* slow. |
136 | | * Some combinations can make the fuzzer timeout (>60 seconds). However, while combining |
137 | | * options makes the fuzzer slower, most options do not expose new code when combined. |
138 | | * Therefore, combining slow options is disabled for large inputs. Any input containing |
139 | | * more than 65536 * 2 samples (max blocksize, stereo) is considered large |
140 | | */ |
141 | 9.70k | if(samples_in_input < (2*65536)) { |
142 | 9.53k | encoder_valid &= FLAC__stream_encoder_set_streamable_subset(encoder, data_bools[4]); |
143 | 9.53k | encoder_valid &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, data_bools[5]); |
144 | 9.53k | encoder_valid &= FLAC__stream_encoder_set_do_escape_coding(encoder, data_bools[6]); |
145 | 9.53k | encoder_valid &= FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, data_bools[7]); |
146 | | /* Combining model search, precision search and a high residual partition order is especially |
147 | | * expensive, so limit that even further. This high partition order can only be set on |
148 | | * large blocksize and with streamable subset disabled */ |
149 | 9.53k | if(samples_in_input < (2 * 4609) || data_bools[4] || !data_bools[7] || !data_bools[5] || max_residual_partition_order < 9 || blocksize < 4609) |
150 | 9.46k | encoder_valid &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, max_residual_partition_order); |
151 | 9.53k | } |
152 | 173 | else { |
153 | 173 | if(!data_bools[4]) |
154 | 129 | encoder_valid &= FLAC__stream_encoder_set_streamable_subset(encoder, false); |
155 | 44 | else if(data_bools[6]) |
156 | 23 | encoder_valid &= FLAC__stream_encoder_set_do_escape_coding(encoder, true); |
157 | 21 | else if(data_bools[7]) |
158 | 10 | encoder_valid &= FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, true); |
159 | 11 | else if(data_bools[5]) |
160 | 1 | encoder_valid &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, true); |
161 | 173 | } |
162 | 9.70k | encoder_valid &= FLAC__stream_encoder_set_do_mid_side_stereo(encoder, data_bools[8]); |
163 | 9.70k | encoder_valid &= FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, data_bools[9]); |
164 | | |
165 | 9.70k | encoder_valid &= FLAC__stream_encoder_disable_constant_subframes(encoder, data_bools[10]); |
166 | 9.70k | encoder_valid &= FLAC__stream_encoder_disable_fixed_subframes(encoder, data_bools[11]); |
167 | 9.70k | encoder_valid &= FLAC__stream_encoder_disable_verbatim_subframes(encoder, data_bools[12]); |
168 | 9.70k | } |
169 | | |
170 | | /* Disable alloc check if requested */ |
171 | 12.2k | if(encoder_valid && data_bools[14]) |
172 | 7.23k | alloc_check_threshold = INT32_MAX; |
173 | | |
174 | | /* add metadata */ |
175 | 12.2k | if(encoder_valid && (metadata_mask & 1)) { |
176 | 79 | if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO)) == NULL) |
177 | 0 | encoder_valid = false; |
178 | 79 | else |
179 | 79 | num_metadata++; |
180 | 79 | } |
181 | 12.2k | if(encoder_valid && (metadata_mask & 2) && size > 21){ |
182 | 4.85k | if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL) |
183 | 0 | encoder_valid = false; |
184 | 4.85k | else { |
185 | 4.85k | metadata[num_metadata++]->length = (((unsigned)data[20]) << 8) + (unsigned)(data[21]); |
186 | 4.85k | } |
187 | 4.85k | } |
188 | 12.2k | if(encoder_valid && (metadata_mask & 4) && size > 20){ |
189 | 4.95k | FLAC__byte * application_data = (FLAC__byte *)malloc(size-20); |
190 | 4.95k | if(0 != application_data && ((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)) == NULL)) |
191 | 0 | encoder_valid = false; |
192 | 4.95k | else { |
193 | 4.95k | memcpy(application_data,data+20,size-20); |
194 | 4.95k | FLAC__metadata_object_application_set_data(metadata[num_metadata++], application_data, size-20, 0); |
195 | 4.95k | } |
196 | 4.95k | } |
197 | 12.2k | if(encoder_valid && (metadata_mask & 8) && size > 25){ |
198 | 5.84k | if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE)) == NULL) |
199 | 0 | encoder_valid = false; |
200 | 5.84k | else { |
201 | 5.84k | unsigned seekpoint_spacing = ((unsigned)data[22] << 8) + data[23]; |
202 | 5.84k | unsigned total_samples_for_seekpoints = ((unsigned)data[24] << 8) + data[25]; |
203 | 5.84k | FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(metadata[num_metadata++], seekpoint_spacing, total_samples_for_seekpoints); |
204 | 5.84k | } |
205 | 5.84k | } |
206 | 12.2k | if(encoder_valid && (metadata_mask & 16)){ |
207 | 3.50k | if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) != NULL) { |
208 | 3.50k | bool vorbiscomment_valid = true; |
209 | | /* Append a vorbis comment */ |
210 | 3.50k | if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&VorbisCommentField, "COMMENTARY", "Nothing to 🤔 report")) |
211 | 1 | vorbiscomment_valid = false; |
212 | 3.50k | else { |
213 | 3.50k | if(FLAC__metadata_object_vorbiscomment_append_comment(metadata[num_metadata], VorbisCommentField, false)) { |
214 | | |
215 | | /* Insert a vorbis comment at the first index */ |
216 | 3.50k | if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&VorbisCommentField, "COMMENTARY", "Still nothing to report 🤔🤣")) |
217 | 1 | vorbiscomment_valid = false; |
218 | 3.49k | else |
219 | 3.49k | if(!FLAC__metadata_object_vorbiscomment_insert_comment(metadata[num_metadata], 0, VorbisCommentField, false)) { |
220 | 2 | free(VorbisCommentField.entry); |
221 | 2 | vorbiscomment_valid = false; |
222 | 2 | } |
223 | 3.50k | } |
224 | 5 | else { |
225 | 5 | free(VorbisCommentField.entry); |
226 | 5 | vorbiscomment_valid = false; |
227 | 5 | } |
228 | 3.50k | } |
229 | 3.50k | if(!vorbiscomment_valid) { |
230 | 9 | FLAC__metadata_object_delete(metadata[num_metadata]); |
231 | 9 | metadata[num_metadata] = 0; |
232 | 9 | encoder_valid = false; |
233 | 9 | } |
234 | 3.49k | else |
235 | 3.49k | num_metadata++; |
236 | 3.50k | } |
237 | 2 | else { |
238 | 2 | encoder_valid = false; |
239 | 2 | } |
240 | 3.50k | } |
241 | 12.2k | if(encoder_valid && (metadata_mask & 32)){ |
242 | 3.99k | if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET)) != NULL) { |
243 | 3.99k | if(!FLAC__metadata_object_cuesheet_insert_blank_track(metadata[num_metadata],0)) { |
244 | 2 | FLAC__metadata_object_delete(metadata[num_metadata]); |
245 | 2 | metadata[num_metadata] = 0; |
246 | 2 | encoder_valid = false; |
247 | 2 | } |
248 | 3.98k | else { |
249 | 3.98k | if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(metadata[num_metadata],0,0)) { |
250 | 1 | FLAC__metadata_object_delete(metadata[num_metadata]); |
251 | 1 | metadata[num_metadata] = 0; |
252 | 1 | encoder_valid = false; |
253 | 1 | } |
254 | 3.98k | else { |
255 | 3.98k | metadata[num_metadata]->data.cue_sheet.tracks[0].number = 1; |
256 | 3.98k | num_metadata++; |
257 | 3.98k | } |
258 | 3.98k | } |
259 | 3.99k | } |
260 | 0 | else { |
261 | 0 | encoder_valid = false; |
262 | 0 | } |
263 | 3.99k | } |
264 | 12.2k | if(encoder_valid && (metadata_mask & 64)){ |
265 | 4.31k | if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE)) != NULL) { |
266 | 4.31k | num_metadata++; |
267 | 4.31k | } |
268 | 0 | else { |
269 | 0 | encoder_valid = false; |
270 | 0 | } |
271 | 4.31k | } |
272 | 12.2k | if(encoder_valid && (metadata_mask & 128)){ |
273 | 3.32k | if((metadata[num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_UNDEFINED)) != NULL) { |
274 | 3.32k | metadata[num_metadata]->length = 24; |
275 | 3.32k | metadata[num_metadata]->data.unknown.data = (FLAC__byte *)calloc(24, 1); |
276 | 3.32k | num_metadata++; |
277 | 3.32k | } |
278 | 0 | else { |
279 | 0 | encoder_valid = false; |
280 | 0 | } |
281 | 3.32k | } |
282 | | |
283 | 12.2k | if(num_metadata && encoder_valid) |
284 | 8.16k | encoder_valid = FLAC__stream_encoder_set_metadata(encoder, metadata, num_metadata); |
285 | | |
286 | | /* initialize encoder */ |
287 | 12.2k | if(encoder_valid) { |
288 | 12.2k | FLAC__StreamEncoderInitStatus init_status; |
289 | 12.2k | if(ogg) |
290 | 4.85k | if(write_to_file) |
291 | 2.67k | init_status = FLAC__stream_encoder_init_ogg_file(encoder, "/tmp/tmp.flac", NULL, NULL); |
292 | 2.18k | else |
293 | 2.18k | init_status = FLAC__stream_encoder_init_ogg_stream(encoder, NULL, write_callback, NULL, NULL, NULL, NULL); |
294 | 7.36k | else |
295 | 7.36k | if(write_to_file) |
296 | 3.47k | init_status = FLAC__stream_encoder_init_file(encoder, "/tmp/tmp.flac", NULL, NULL); |
297 | 3.89k | else |
298 | 3.89k | init_status = FLAC__stream_encoder_init_stream(encoder, write_callback, NULL, NULL, NULL, NULL); |
299 | 12.2k | if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { |
300 | 277 | encoder_valid = false; |
301 | 277 | } |
302 | 12.2k | } |
303 | | |
304 | | |
305 | | /* send samples to encoder */ |
306 | 12.2k | if(encoder_valid && size > (input_data_width*channels+26)) { |
307 | 11.6k | unsigned samples = (size - 26)/input_data_width/channels; |
308 | 11.6k | const uint8_t * pcm_data = data + 26; |
309 | 11.6k | int32_t * data_as_int32 = (int32_t *)malloc(4*samples*channels); |
310 | 11.6k | if(0 != data_as_int32){ |
311 | 97.9M | for(unsigned i = 0; i < samples*channels; i++) |
312 | 97.9M | if(input_data_width == 1) |
313 | 82.6M | data_as_int32[i] = (int32_t)pcm_data[i] - 0x80; |
314 | 15.2M | else if(input_data_width == 2) |
315 | 324k | data_as_int32[i] = (((int32_t)pcm_data[i*2] << 8) + pcm_data[i*2+1]) - 0x8000; |
316 | 14.9M | else if(input_data_width == 3) |
317 | 2.91M | data_as_int32[i] = (((int32_t)pcm_data[i*3] << 16) + ((int32_t)pcm_data[i*3+1] << 8) + pcm_data[i*3+2]) - 0x800000; |
318 | 12.0M | else if(input_data_width == 4) |
319 | 12.0M | data_as_int32[i] = (((int64_t)pcm_data[i*4] << 24) + ((int32_t)pcm_data[i*4+1] << 16) + ((int32_t)pcm_data[i*4+2] << 8) + pcm_data[i*4+3]) - 0x80000000; |
320 | | |
321 | | /* feed samples to encoder */ |
322 | 11.6k | if(interleaved) |
323 | 5.12k | encoder_valid = FLAC__stream_encoder_process_interleaved(encoder, data_as_int32, samples); |
324 | 6.54k | else { |
325 | 6.54k | encoder_valid = FLAC__stream_encoder_process(encoder, (const int32_t*[]){data_as_int32, |
326 | 6.54k | data_as_int32+samples, |
327 | 6.54k | data_as_int32+samples*2, |
328 | 6.54k | data_as_int32+samples*3, |
329 | 6.54k | data_as_int32+samples*4, data_as_int32+samples*5, data_as_int32+samples*6, data_as_int32+samples*7}, samples); |
330 | 6.54k | } |
331 | 11.6k | free(data_as_int32); |
332 | 11.6k | } |
333 | 0 | else { |
334 | 0 | encoder_valid = false; |
335 | 0 | } |
336 | 11.6k | } |
337 | | |
338 | 12.2k | state = FLAC__stream_encoder_get_state(encoder); |
339 | 12.2k | state_string = FLAC__stream_encoder_get_resolved_state_string(encoder); |
340 | 12.2k | if(!(state == FLAC__STREAM_ENCODER_OK || |
341 | 12.2k | state == FLAC__STREAM_ENCODER_UNINITIALIZED || |
342 | 12.2k | state == FLAC__STREAM_ENCODER_CLIENT_ERROR || |
343 | 12.2k | ((state == FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR || |
344 | 110 | state == FLAC__STREAM_ENCODER_FRAMING_ERROR || |
345 | 110 | (state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR && |
346 | 12 | FLAC__stream_encoder_get_verify_decoder_state(encoder) == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR)) && |
347 | 110 | alloc_check_threshold < INT32_MAX))) { |
348 | 0 | fprintf(stderr,"-----\nERROR: stream encoder returned %s\n-----\n",FLAC__stream_encoder_get_resolved_state_string(encoder)); |
349 | 0 | if(state == FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA) { |
350 | 0 | uint32_t frame_number, channel, sample_number; |
351 | 0 | FLAC__int32 expected, got; |
352 | 0 | FLAC__stream_encoder_get_verify_decoder_error_stats(encoder, NULL, &frame_number, &channel, &sample_number, &expected, &got); |
353 | 0 | fprintf(stderr,"Frame number %d\nChannel %d\n Sample number %d\nExpected value %d\nGot %d\n", frame_number, channel, sample_number, expected, got); |
354 | 0 | } |
355 | 0 | abort(); |
356 | 0 | } |
357 | | |
358 | 12.2k | FLAC__stream_encoder_finish(encoder); |
359 | | |
360 | | /* now that encoding is finished, the metadata can be freed */ |
361 | 208k | for(unsigned i = 0; i < 16; i++) |
362 | 196k | if(0 != metadata[i]) |
363 | 30.8k | FLAC__metadata_object_delete(metadata[i]); |
364 | | |
365 | 12.2k | FLAC__stream_encoder_delete(encoder); |
366 | | |
367 | 12.2k | return 0; |
368 | 12.2k | } |
369 | | |