FLAC: Porting from FLAC 1.1.2 to 1.1.3

Main Page | Modules | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

# Porting from FLAC 1.1.2 to 1.1.3
[Porting Guide for New Versions]

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;

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;

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;

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 `unsigned`.

Copyright (c) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson |