1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4
5 flac.c
6
7 FLAC compression wrappers
8
9 ***************************************************************************/
10
11 #include <cassert>
12
13 #include "flac.h"
14 #include <new>
15
16
17 //**************************************************************************
18 // FLAC ENCODER
19 //**************************************************************************
20
21 //-------------------------------------------------
22 // flac_encoder - constructors
23 //-------------------------------------------------
24
flac_encoder()25 flac_encoder::flac_encoder()
26 {
27 init_common();
28 }
29
30
flac_encoder(void * buffer,uint32_t buflength)31 flac_encoder::flac_encoder(void *buffer, uint32_t buflength)
32 {
33 init_common();
34 reset(buffer, buflength);
35 }
36
37
flac_encoder(util::core_file & file)38 flac_encoder::flac_encoder(util::core_file &file)
39 {
40 init_common();
41 reset(file);
42 }
43
44
45 //-------------------------------------------------
46 // ~flac_encoder - destructor
47 //-------------------------------------------------
48
~flac_encoder()49 flac_encoder::~flac_encoder()
50 {
51 // delete the encoder
52 FLAC__stream_encoder_delete(m_encoder);
53 }
54
55
56 //-------------------------------------------------
57 // reset - reset state with the original
58 // parameters
59 //-------------------------------------------------
60
reset()61 bool flac_encoder::reset()
62 {
63 // configure the output
64 m_compressed_offset = 0;
65 m_ignore_bytes = m_strip_metadata ? 4 : 0;
66 m_found_audio = !m_strip_metadata;
67
68 // configure the encoder in a standard way
69 // note we do this on each reset; if we don't, results are NOT consistent!
70 FLAC__stream_encoder_set_verify(m_encoder, false);
71 // FLAC__stream_encoder_set_do_md5(m_encoder, false);
72 FLAC__stream_encoder_set_compression_level(m_encoder, 8);
73 FLAC__stream_encoder_set_channels(m_encoder, m_channels);
74 FLAC__stream_encoder_set_bits_per_sample(m_encoder, 16);
75 FLAC__stream_encoder_set_sample_rate(m_encoder, m_sample_rate);
76 FLAC__stream_encoder_set_total_samples_estimate(m_encoder, 0);
77 FLAC__stream_encoder_set_streamable_subset(m_encoder, false);
78 FLAC__stream_encoder_set_blocksize(m_encoder, m_block_size);
79
80 // re-start processing
81 return (FLAC__stream_encoder_init_stream(m_encoder, write_callback_static, nullptr, nullptr, nullptr, this) == FLAC__STREAM_ENCODER_INIT_STATUS_OK);
82 }
83
84
85 //-------------------------------------------------
86 // reset - reset state with new memory parameters
87 //-------------------------------------------------
88
reset(void * buffer,uint32_t buflength)89 bool flac_encoder::reset(void *buffer, uint32_t buflength)
90 {
91 // configure the output
92 m_compressed_start = reinterpret_cast<FLAC__byte *>(buffer);
93 m_compressed_length = buflength;
94 m_file = nullptr;
95 return reset();
96 }
97
98
99 //-------------------------------------------------
100 // reset - reset state with new file parameters
101 //-------------------------------------------------
102
reset(util::core_file & file)103 bool flac_encoder::reset(util::core_file &file)
104 {
105 // configure the output
106 m_compressed_start = nullptr;
107 m_compressed_length = 0;
108 m_file = &file;
109 return reset();
110 }
111
112
113 //-------------------------------------------------
114 // encode_interleaved - encode a buffer with
115 // interleaved samples
116 //-------------------------------------------------
117
encode_interleaved(const int16_t * samples,uint32_t samples_per_channel,bool swap_endian)118 bool flac_encoder::encode_interleaved(const int16_t *samples, uint32_t samples_per_channel, bool swap_endian)
119 {
120 int shift = swap_endian ? 8 : 0;
121
122 // loop over source samples
123 int num_channels = FLAC__stream_encoder_get_channels(m_encoder);
124 uint32_t srcindex = 0;
125 while (samples_per_channel != 0)
126 {
127 // process in batches of 2k samples
128 FLAC__int32 converted_buffer[2048];
129 FLAC__int32 *dest = converted_buffer;
130 uint32_t cur_samples = (std::min<size_t>)(ARRAY_LENGTH(converted_buffer) / num_channels, samples_per_channel);
131
132 // convert a buffers' worth
133 for (uint32_t sampnum = 0; sampnum < cur_samples; sampnum++)
134 for (int channel = 0; channel < num_channels; channel++, srcindex++)
135 *dest++ = int16_t((uint16_t(samples[srcindex]) << shift) | (uint16_t(samples[srcindex]) >> shift));
136
137 // process this batch
138 if (!FLAC__stream_encoder_process_interleaved(m_encoder, converted_buffer, cur_samples))
139 return false;
140 samples_per_channel -= cur_samples;
141 }
142 return true;
143 }
144
145
146 //-------------------------------------------------
147 // encode - encode a buffer with individual
148 // sample streams
149 //-------------------------------------------------
150
encode(int16_t * const * samples,uint32_t samples_per_channel,bool swap_endian)151 bool flac_encoder::encode(int16_t *const *samples, uint32_t samples_per_channel, bool swap_endian)
152 {
153 int shift = swap_endian ? 8 : 0;
154
155 // loop over source samples
156 int num_channels = FLAC__stream_encoder_get_channels(m_encoder);
157 uint32_t srcindex = 0;
158 while (samples_per_channel != 0)
159 {
160 // process in batches of 2k samples
161 FLAC__int32 converted_buffer[2048];
162 FLAC__int32 *dest = converted_buffer;
163 uint32_t cur_samples = (std::min<size_t>)(ARRAY_LENGTH(converted_buffer) / num_channels, samples_per_channel);
164
165 // convert a buffers' worth
166 for (uint32_t sampnum = 0; sampnum < cur_samples; sampnum++, srcindex++)
167 for (int channel = 0; channel < num_channels; channel++)
168 *dest++ = int16_t((uint16_t(samples[channel][srcindex]) << shift) | (uint16_t(samples[channel][srcindex]) >> shift));
169
170 // process this batch
171 if (!FLAC__stream_encoder_process_interleaved(m_encoder, converted_buffer, cur_samples))
172 return false;
173 samples_per_channel -= cur_samples;
174 }
175 return true;
176 }
177
178
179 //-------------------------------------------------
180 // finish - complete encoding and flush the
181 // stream
182 //-------------------------------------------------
183
finish()184 uint32_t flac_encoder::finish()
185 {
186 // process the data and return the amount written
187 FLAC__stream_encoder_finish(m_encoder);
188 return (m_file != nullptr) ? m_file->tell() : m_compressed_offset;
189 }
190
191
192 //-------------------------------------------------
193 // init_common - common initialization
194 //-------------------------------------------------
195
init_common()196 void flac_encoder::init_common()
197 {
198 // allocate the encoder
199 m_encoder = FLAC__stream_encoder_new();
200 if (m_encoder == nullptr)
201 throw std::bad_alloc();
202
203 // initialize default state
204 m_file = nullptr;
205 m_compressed_offset = 0;
206 m_compressed_start = nullptr;
207 m_compressed_length = 0;
208 m_sample_rate = 44100;
209 m_channels = 2;
210 m_block_size = 0;
211 m_strip_metadata = false;
212 m_ignore_bytes = 0;
213 m_found_audio = false;
214 }
215
216
217 //-------------------------------------------------
218 // write_callback - handle writes to the
219 // output stream
220 //-------------------------------------------------
221
write_callback_static(const FLAC__StreamEncoder * encoder,const FLAC__byte buffer[],size_t bytes,unsigned samples,unsigned current_frame,void * client_data)222 FLAC__StreamEncoderWriteStatus flac_encoder::write_callback_static(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
223 {
224 return reinterpret_cast<flac_encoder *>(client_data)->write_callback(buffer, bytes, samples, current_frame);
225 }
226
write_callback(const FLAC__byte buffer[],size_t bytes,unsigned samples,unsigned current_frame)227 FLAC__StreamEncoderWriteStatus flac_encoder::write_callback(const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame)
228 {
229 // loop over output data
230 size_t offset = 0;
231 while (offset < bytes)
232 {
233 // if we're ignoring, continue to do so
234 if (m_ignore_bytes != 0)
235 {
236 size_t ignore = std::min(bytes - offset, size_t(m_ignore_bytes));
237 offset += ignore;
238 m_ignore_bytes -= ignore;
239 }
240
241 // if we haven't hit the end of metadata, process a new piece
242 else if (!m_found_audio)
243 {
244 assert(bytes - offset >= 4);
245 m_found_audio = ((buffer[offset] & 0x80) != 0);
246 m_ignore_bytes = (buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3];
247 offset += 4;
248 }
249
250 // otherwise process as audio data and copy to the output
251 else
252 {
253 int count = bytes - offset;
254 if (m_file != nullptr)
255 m_file->write(buffer, count);
256 else
257 {
258 if (m_compressed_offset + count <= m_compressed_length)
259 memcpy(m_compressed_start + m_compressed_offset, buffer, count);
260 m_compressed_offset += count;
261 }
262 offset += count;
263 }
264 }
265 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
266 }
267
268
269
270 //**************************************************************************
271 // FLAC DECODER
272 //**************************************************************************
273
274 //-------------------------------------------------
275 // flac_decoder - constructor
276 //-------------------------------------------------
277
flac_decoder()278 flac_decoder::flac_decoder()
279 : m_decoder(FLAC__stream_decoder_new()),
280 m_file(nullptr),
281 m_sample_rate(0),
282 m_channels(0),
283 m_bits_per_sample(0),
284 m_compressed_offset(0),
285 m_compressed_start(nullptr),
286 m_compressed_length(0),
287 m_compressed2_start(nullptr),
288 m_compressed2_length(0),
289 m_uncompressed_offset(0),
290 m_uncompressed_length(0),
291 m_uncompressed_swap(false)
292 {
293 }
294
295
296 //-------------------------------------------------
297 // flac_decoder - constructor
298 //-------------------------------------------------
299
flac_decoder(const void * buffer,uint32_t length,const void * buffer2,uint32_t length2)300 flac_decoder::flac_decoder(const void *buffer, uint32_t length, const void *buffer2, uint32_t length2)
301 : m_decoder(FLAC__stream_decoder_new()),
302 m_file(nullptr),
303 m_compressed_offset(0),
304 m_compressed_start(reinterpret_cast<const FLAC__byte *>(buffer)),
305 m_compressed_length(length),
306 m_compressed2_start(reinterpret_cast<const FLAC__byte *>(buffer2)),
307 m_compressed2_length(length2)
308 {
309 reset();
310 }
311
312
313 //-------------------------------------------------
314 // flac_decoder - constructor
315 //-------------------------------------------------
316
flac_decoder(util::core_file & file)317 flac_decoder::flac_decoder(util::core_file &file)
318 : m_decoder(FLAC__stream_decoder_new()),
319 m_file(&file),
320 m_compressed_offset(0),
321 m_compressed_start(nullptr),
322 m_compressed_length(0),
323 m_compressed2_start(nullptr),
324 m_compressed2_length(0)
325 {
326 reset();
327 }
328
329
330 //-------------------------------------------------
331 // flac_decoder - destructor
332 //-------------------------------------------------
333
~flac_decoder()334 flac_decoder::~flac_decoder()
335 {
336 FLAC__stream_decoder_delete(m_decoder);
337 }
338
339
340 //-------------------------------------------------
341 // reset - reset state with the original
342 // parameters
343 //-------------------------------------------------
344
reset()345 bool flac_decoder::reset()
346 {
347 m_compressed_offset = 0;
348 if (FLAC__stream_decoder_init_stream(m_decoder,
349 &flac_decoder::read_callback_static,
350 nullptr,
351 &flac_decoder::tell_callback_static,
352 nullptr,
353 nullptr,
354 &flac_decoder::write_callback_static,
355 &flac_decoder::metadata_callback_static,
356 &flac_decoder::error_callback_static, this) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
357 return false;
358 return FLAC__stream_decoder_process_until_end_of_metadata(m_decoder);
359 }
360
361
362 //-------------------------------------------------
363 // reset - reset state with new memory parameters
364 //-------------------------------------------------
365
reset(const void * buffer,uint32_t length,const void * buffer2,uint32_t length2)366 bool flac_decoder::reset(const void *buffer, uint32_t length, const void *buffer2, uint32_t length2)
367 {
368 m_file = nullptr;
369 m_compressed_start = reinterpret_cast<const FLAC__byte *>(buffer);
370 m_compressed_length = length;
371 m_compressed2_start = reinterpret_cast<const FLAC__byte *>(buffer2);
372 m_compressed2_length = length2;
373 return reset();
374 }
375
376
377 //-------------------------------------------------
378 // reset - reset state with new memory parameters
379 // and a custom-generated header
380 //-------------------------------------------------
381
reset(uint32_t sample_rate,uint8_t num_channels,uint32_t block_size,const void * buffer,uint32_t length)382 bool flac_decoder::reset(uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)
383 {
384 // modify the template header with our parameters
385 static const uint8_t s_header_template[0x2a] =
386 {
387 0x66, 0x4C, 0x61, 0x43, // +00: 'fLaC' stream header
388 0x80, // +04: metadata block type 0 (STREAMINFO),
389 // flagged as last block
390 0x00, 0x00, 0x22, // +05: metadata block length = 0x22
391 0x00, 0x00, // +08: minimum block size
392 0x00, 0x00, // +0A: maximum block size
393 0x00, 0x00, 0x00, // +0C: minimum frame size (0 == unknown)
394 0x00, 0x00, 0x00, // +0F: maximum frame size (0 == unknown)
395 0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, // +12: sample rate (0x0ac44 == 44100),
396 // numchannels (2), sample bits (16),
397 // samples in stream (0 == unknown)
398 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +1A: MD5 signature (0 == none)
399 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 //
400 // +2A: start of stream data
401 };
402 memcpy(m_custom_header, s_header_template, sizeof(s_header_template));
403 m_custom_header[0x08] = m_custom_header[0x0a] = block_size >> 8;
404 m_custom_header[0x09] = m_custom_header[0x0b] = block_size & 0xff;
405 m_custom_header[0x12] = sample_rate >> 12;
406 m_custom_header[0x13] = sample_rate >> 4;
407 m_custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);
408
409 // configure the header ahead of the provided buffer
410 m_file = nullptr;
411 m_compressed_start = reinterpret_cast<const FLAC__byte *>(m_custom_header);
412 m_compressed_length = sizeof(m_custom_header);
413 m_compressed2_start = reinterpret_cast<const FLAC__byte *>(buffer);
414 m_compressed2_length = length;
415 return reset();
416 }
417
418
419 //-------------------------------------------------
420 // reset - reset state with new file parameter
421 //-------------------------------------------------
422
reset(util::core_file & file)423 bool flac_decoder::reset(util::core_file &file)
424 {
425 m_file = &file;
426 m_compressed_start = nullptr;
427 m_compressed_length = 0;
428 m_compressed2_start = nullptr;
429 m_compressed2_length = 0;
430 return reset();
431 }
432
433
434 //-------------------------------------------------
435 // decode_interleaved - decode to an interleaved
436 // sound stream
437 //-------------------------------------------------
438
decode_interleaved(int16_t * samples,uint32_t num_samples,bool swap_endian)439 bool flac_decoder::decode_interleaved(int16_t *samples, uint32_t num_samples, bool swap_endian)
440 {
441 // configure the uncompressed buffer
442 memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));
443 m_uncompressed_start[0] = samples;
444 m_uncompressed_offset = 0;
445 m_uncompressed_length = num_samples;
446 m_uncompressed_swap = swap_endian;
447
448 // loop until we get everything we want
449 while (m_uncompressed_offset < m_uncompressed_length)
450 if (!FLAC__stream_decoder_process_single(m_decoder))
451 return false;
452 return true;
453 }
454
455
456 //-------------------------------------------------
457 // decode - decode to an multiple independent
458 // data streams
459 //-------------------------------------------------
460
decode(int16_t ** samples,uint32_t num_samples,bool swap_endian)461 bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian)
462 {
463 // make sure we don't have too many channels
464 int chans = channels();
465 if (chans > ARRAY_LENGTH(m_uncompressed_start))
466 return false;
467
468 // configure the uncompressed buffer
469 memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start));
470 for (int curchan = 0; curchan < chans; curchan++)
471 m_uncompressed_start[curchan] = samples[curchan];
472 m_uncompressed_offset = 0;
473 m_uncompressed_length = num_samples;
474 m_uncompressed_swap = swap_endian;
475
476 // loop until we get everything we want
477 while (m_uncompressed_offset < m_uncompressed_length)
478 if (!FLAC__stream_decoder_process_single(m_decoder))
479 return false;
480 return true;
481 }
482
483
484 //-------------------------------------------------
485 // finish - finish up the decode
486 //-------------------------------------------------
487
finish()488 uint32_t flac_decoder::finish()
489 {
490 // get the final decoding position and move forward
491 FLAC__uint64 position = 0;
492 FLAC__stream_decoder_get_decode_position(m_decoder, &position);
493 FLAC__stream_decoder_finish(m_decoder);
494
495 // adjust position if we provided the header
496 if (position == 0)
497 return 0;
498 if (m_compressed_start == reinterpret_cast<const FLAC__byte *>(m_custom_header))
499 position -= m_compressed_length;
500 return position;
501 }
502
503
504 //-------------------------------------------------
505 // read_callback - handle reads from the input
506 // stream
507 //-------------------------------------------------
508
read_callback_static(const FLAC__StreamDecoder * decoder,FLAC__byte buffer[],size_t * bytes,void * client_data)509 FLAC__StreamDecoderReadStatus flac_decoder::read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
510 {
511 return reinterpret_cast<flac_decoder *>(client_data)->read_callback(buffer, bytes);
512 }
513
read_callback(FLAC__byte buffer[],size_t * bytes)514 FLAC__StreamDecoderReadStatus flac_decoder::read_callback(FLAC__byte buffer[], size_t *bytes)
515 {
516 uint32_t expected = *bytes;
517
518 // if a file, just read
519 if (m_file != nullptr)
520 *bytes = m_file->read(buffer, expected);
521
522 // otherwise, copy from memory
523 else
524 {
525 // copy from primary buffer first
526 uint32_t outputpos = 0;
527 if (outputpos < *bytes && m_compressed_offset < m_compressed_length)
528 {
529 uint32_t bytes_to_copy = (std::min<size_t>)(*bytes - outputpos, m_compressed_length - m_compressed_offset);
530 memcpy(&buffer[outputpos], m_compressed_start + m_compressed_offset, bytes_to_copy);
531 outputpos += bytes_to_copy;
532 m_compressed_offset += bytes_to_copy;
533 }
534
535 // once we're out of that, copy from the secondary buffer
536 if (outputpos < *bytes && m_compressed_offset < m_compressed_length + m_compressed2_length)
537 {
538 uint32_t bytes_to_copy = (std::min<size_t>)(*bytes - outputpos, m_compressed2_length - (m_compressed_offset - m_compressed_length));
539 memcpy(&buffer[outputpos], m_compressed2_start + m_compressed_offset - m_compressed_length, bytes_to_copy);
540 outputpos += bytes_to_copy;
541 m_compressed_offset += bytes_to_copy;
542 }
543 *bytes = outputpos;
544 }
545
546 // return based on whether we ran out of data
547 return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
548 }
549
550
551 //-------------------------------------------------
552 // metadata_callback - handle STREAMINFO metadata
553 //-------------------------------------------------
554
metadata_callback_static(const FLAC__StreamDecoder * decoder,const FLAC__StreamMetadata * metadata,void * client_data)555 void flac_decoder::metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
556 {
557 // ignore all but STREAMINFO metadata
558 if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO)
559 return;
560
561 // parse out the data we care about
562 auto *fldecoder = reinterpret_cast<flac_decoder *>(client_data);
563 fldecoder->m_sample_rate = metadata->data.stream_info.sample_rate;
564 fldecoder->m_bits_per_sample = metadata->data.stream_info.bits_per_sample;
565 fldecoder->m_channels = metadata->data.stream_info.channels;
566 }
567
568
569 //-------------------------------------------------
570 // tell_callback - handle requests to find out
571 // where in the input stream we are
572 //-------------------------------------------------
573
tell_callback_static(const FLAC__StreamDecoder * decoder,FLAC__uint64 * absolute_byte_offset,void * client_data)574 FLAC__StreamDecoderTellStatus flac_decoder::tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
575 {
576 *absolute_byte_offset = reinterpret_cast<flac_decoder *>(client_data)->m_compressed_offset;
577 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
578 }
579
580
581 //-------------------------------------------------
582 // write_callback - handle writes to the output
583 // stream
584 //-------------------------------------------------
585
write_callback_static(const FLAC__StreamDecoder * decoder,const::FLAC__Frame * frame,const FLAC__int32 * const buffer[],void * client_data)586 FLAC__StreamDecoderWriteStatus flac_decoder::write_callback_static(const FLAC__StreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
587 {
588 return reinterpret_cast<flac_decoder *>(client_data)->write_callback(frame, buffer);
589 }
590
write_callback(const::FLAC__Frame * frame,const FLAC__int32 * const buffer[])591 FLAC__StreamDecoderWriteStatus flac_decoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[])
592 {
593 assert(frame->header.channels == channels());
594
595 // interleaved case
596 int shift = m_uncompressed_swap ? 8 : 0;
597 int blocksize = frame->header.blocksize;
598 if (m_uncompressed_start[1] == nullptr)
599 {
600 int16_t *dest = m_uncompressed_start[0] + m_uncompressed_offset * frame->header.channels;
601 for (int sampnum = 0; sampnum < blocksize && m_uncompressed_offset < m_uncompressed_length; sampnum++, m_uncompressed_offset++)
602 for (int chan = 0; chan < frame->header.channels; chan++)
603 *dest++ = int16_t((uint16_t(buffer[chan][sampnum]) << shift) | (uint16_t(buffer[chan][sampnum]) >> shift));
604 }
605
606 // non-interleaved case
607 else
608 {
609 for (int sampnum = 0; sampnum < blocksize && m_uncompressed_offset < m_uncompressed_length; sampnum++, m_uncompressed_offset++)
610 for (int chan = 0; chan < frame->header.channels; chan++)
611 if (m_uncompressed_start[chan] != nullptr)
612 m_uncompressed_start[chan][m_uncompressed_offset] = int16_t((uint16_t(buffer[chan][sampnum]) << shift) | (uint16_t(buffer[chan][sampnum]) >> shift));
613 }
614 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
615 }
616
617 /**
618 * @fn void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
619 *
620 * @brief -------------------------------------------------
621 * error_callback - handle errors (ignore them)
622 * -------------------------------------------------.
623 *
624 * @param decoder The decoder.
625 * @param status The status.
626 * @param [in,out] client_data If non-null, information describing the client.
627 */
628
error_callback_static(const FLAC__StreamDecoder * decoder,FLAC__StreamDecoderErrorStatus status,void * client_data)629 void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
630 {
631 }
632