FLAC: Porting from FLAC 1.1.2 to 1.1.3

FLAC 1.4.3 Free Lossless Audio Codec

Porting from FLAC 1.1.2 to 1.1.3
Porting Guide for New Versions

This module describes porting from FLAC 1.1.2 to FLAC 1.1.3.

The main change between the APIs in 1.1.2 and 1.1.3 is that they have been simplified. First, libOggFLAC has been merged into libFLAC and libOggFLAC++ has been merged into libFLAC++. Second, both the three decoding layers and three encoding layers have been merged into a single stream decoder and stream encoder. That is, the functionality of FLAC__SeekableStreamDecoder and FLAC__FileDecoder has been merged into FLAC__StreamDecoder, and FLAC__SeekableStreamEncoder and FLAC__FileEncoder into FLAC__StreamEncoder. Only the FLAC__StreamDecoder and FLAC__StreamEncoder remain. What this means is there is now a single API that can be used to encode or decode streams to/from native FLAC or Ogg FLAC and the single API can work on both seekable and non-seekable streams.

Instead of creating an encoder or decoder of a certain layer, now the client will always create a FLAC__StreamEncoder or FLAC__StreamDecoder. The old layers are now differentiated by the initialization function. For example, for the decoder, FLAC__stream_decoder_init() has been replaced by FLAC__stream_decoder_init_stream(). This init function takes callbacks for the I/O, and the seeking callbacks are optional. This allows the client to use the same object for seekable and non-seekable streams. For decoding a FLAC file directly, the client can use FLAC__stream_decoder_init_file() and pass just a filename and fewer callbacks; most of the other callbacks are supplied internally. For situations where fopen()ing by filename is not possible (e.g. Unicode filenames on Windows) the client can instead open the file itself and supply the FILE* to FLAC__stream_decoder_init_FILE(). The init functions now returns a FLAC__StreamDecoderInitStatus instead of FLAC__StreamDecoderState. Since the callbacks and client data are now passed to the init function, the FLAC__stream_decoder_set_*_callback() functions and FLAC__stream_decoder_set_client_data() are no longer needed. The rest of the calls to the decoder are the same as before.

There are counterpart init functions for Ogg FLAC, e.g. FLAC__stream_decoder_init_ogg_stream(). All the rest of the calls and callbacks are the same as for native FLAC.

As an example, in FLAC 1.1.2 a seekable stream decoder would have been set up like so:

FLAC__SeekableStreamDecoder *decoder = FLAC__seekable_stream_decoder_new();
if(decoder == NULL) do_something;
FLAC__seekable_stream_decoder_set_md5_checking(decoder, true);
[... other settings ...]
FLAC__seekable_stream_decoder_set_read_callback(decoder, my_read_callback);
FLAC__seekable_stream_decoder_set_seek_callback(decoder, my_seek_callback);
FLAC__seekable_stream_decoder_set_tell_callback(decoder, my_tell_callback);
FLAC__seekable_stream_decoder_set_length_callback(decoder, my_length_callback);
FLAC__seekable_stream_decoder_set_eof_callback(decoder, my_eof_callback);
FLAC__seekable_stream_decoder_set_write_callback(decoder, my_write_callback);
FLAC__seekable_stream_decoder_set_metadata_callback(decoder, my_metadata_callback);
FLAC__seekable_stream_decoder_set_error_callback(decoder, my_error_callback);
FLAC__seekable_stream_decoder_set_client_data(decoder, my_client_data);
if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) do_something;

In FLAC 1.1.3 it is like this:

FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
if(decoder == NULL) do_something;
FLAC__stream_decoder_set_md5_checking(decoder, true);
[... other settings ...]
if(FLAC__stream_decoder_init_stream(
decoder,
my_read_callback,
my_seek_callback, // or NULL
my_tell_callback, // or NULL
my_length_callback, // or NULL
my_eof_callback, // or NULL
my_write_callback,
my_metadata_callback, // or NULL
my_error_callback,
my_client_data
) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
FLAC__stream_decoder_init_stream
FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(FLAC__StreamDecoder *decoder, FLAC__StreamDecoderReadCallback read_callback, FLAC__StreamDecoderSeekCallback seek_callback, FLAC__StreamDecoderTellCallback tell_callback, FLAC__StreamDecoderLengthCallback length_callback, FLAC__StreamDecoderEofCallback eof_callback, FLAC__StreamDecoderWriteCallback write_callback, FLAC__StreamDecoderMetadataCallback metadata_callback, FLAC__StreamDecoderErrorCallback error_callback, void *client_data)
FLAC__stream_decoder_set_md5_checking
FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value)
FLAC__stream_decoder_new
FLAC__StreamDecoder * FLAC__stream_decoder_new(void)
FLAC__STREAM_DECODER_INIT_STATUS_OK
@ FLAC__STREAM_DECODER_INIT_STATUS_OK
Definition stream_decoder.h:258
FLAC__StreamDecoder
Definition stream_decoder.h:470

or you could do;

[...]
FILE *file = fopen("somefile.flac","rb");
if(file == NULL) do_somthing;
if(FLAC__stream_decoder_init_FILE(
decoder,
file,
my_write_callback,
my_metadata_callback, // or NULL
my_error_callback,
my_client_data
) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
FLAC__stream_decoder_init_FILE
FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(FLAC__StreamDecoder *decoder, FILE *file, FLAC__StreamDecoderWriteCallback write_callback, FLAC__StreamDecoderMetadataCallback metadata_callback, FLAC__StreamDecoderErrorCallback error_callback, void *client_data)

or just:

[...]
if(FLAC__stream_decoder_init_file(
decoder,
"somefile.flac",
my_write_callback,
my_metadata_callback, // or NULL
my_error_callback,
my_client_data
) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
FLAC__stream_decoder_init_file
FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(FLAC__StreamDecoder *decoder, const char *filename, FLAC__StreamDecoderWriteCallback write_callback, FLAC__StreamDecoderMetadataCallback metadata_callback, FLAC__StreamDecoderErrorCallback error_callback, void *client_data)

Another small change to the decoder is in how it handles unparseable streams. Before, when the decoder found an unparseable stream (reserved for when the decoder encounters a stream from a future encoder that it can't parse), it changed the state to `FLAC__STREAM_DECODER_UNPARSEABLE_STREAM`. Now the decoder instead drops sync and calls the error callback with a new error code `FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM`. This is more robust. If your error callback does not discriminate on the the error state, your code does not need to be changed.

The encoder now has a new setting: FLAC__stream_encoder_set_apodization(). This is for setting the method used to window the data before LPC analysis. You only need to add a call to this function if the default is not suitable. There are also two new convenience functions that may be useful: FLAC__metadata_object_cuesheet_calculate_cddb_id() and FLAC__metadata_get_cuesheet().

The bytes parameter to FLAC__StreamDecoderReadCallback, FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback is now `size_t` instead of `uint32_t`.

Copyright (c) 2000-2009 Josh Coalson Copyright (c) 2011-2023 Xiph.Org Foundation