add support for serial number in Ogg streams
[flac.git] / src / libOggFLAC / stream_decoder.c
index 958f9f4..4c9d595 100644 (file)
@@ -57,6 +57,7 @@ typedef struct OggFLAC__StreamDecoderPrivate {
        struct {
                ogg_stream_state stream_state;
                ogg_sync_state sync_state;
+               FLAC__bool need_serial_number;
        } ogg;
 } OggFLAC__StreamDecoderPrivate;
 
@@ -132,7 +133,7 @@ void OggFLAC__stream_decoder_delete(OggFLAC__StreamDecoder *decoder)
 
        OggFLAC__stream_decoder_finish(decoder);
 
-    FLAC__stream_decoder_delete(decoder->private_->FLAC_stream_decoder);
+       FLAC__stream_decoder_delete(decoder->private_->FLAC_stream_decoder);
 
        free(decoder->private_);
        free(decoder->protected_);
@@ -155,20 +156,22 @@ OggFLAC__StreamDecoderState OggFLAC__stream_decoder_init(OggFLAC__StreamDecoder
        if(0 == decoder->private_->read_callback || 0 == decoder->private_->write_callback || 0 == decoder->private_->metadata_callback || 0 == decoder->private_->error_callback)
                return decoder->protected_->state = OggFLAC__STREAM_DECODER_INVALID_CALLBACK;
 
-       if(ogg_stream_init(&decoder->private_->ogg.stream_state, 0) != 0)
+       decoder->private_->ogg.need_serial_number = decoder->protected_->use_first_serial_number;
+       /* we will determine the serial number later if necessary */
+       if(ogg_stream_init(&decoder->private_->ogg.stream_state, decoder->protected_->serial_number) != 0)
                return decoder->protected_->state = OggFLAC__STREAM_DECODER_OGG_ERROR;
 
        if(ogg_sync_init(&decoder->private_->ogg.sync_state) != 0)
                return decoder->protected_->state = OggFLAC__STREAM_DECODER_OGG_ERROR;
 
-    FLAC__stream_decoder_set_read_callback(decoder->private_->FLAC_stream_decoder, read_callback_);
-    FLAC__stream_decoder_set_write_callback(decoder->private_->FLAC_stream_decoder, write_callback_);
-    FLAC__stream_decoder_set_metadata_callback(decoder->private_->FLAC_stream_decoder, metadata_callback_);
-    FLAC__stream_decoder_set_error_callback(decoder->private_->FLAC_stream_decoder, error_callback_);
-    FLAC__stream_decoder_set_client_data(decoder->private_->FLAC_stream_decoder, decoder);
+       FLAC__stream_decoder_set_read_callback(decoder->private_->FLAC_stream_decoder, read_callback_);
+       FLAC__stream_decoder_set_write_callback(decoder->private_->FLAC_stream_decoder, write_callback_);
+       FLAC__stream_decoder_set_metadata_callback(decoder->private_->FLAC_stream_decoder, metadata_callback_);
+       FLAC__stream_decoder_set_error_callback(decoder->private_->FLAC_stream_decoder, error_callback_);
+       FLAC__stream_decoder_set_client_data(decoder->private_->FLAC_stream_decoder, decoder);
 
-    if(FLAC__stream_decoder_init(decoder->private_->FLAC_stream_decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
-        return decoder->protected_->state = OggFLAC__STREAM_DECODER_FLAC_STREAM_DECODER_ERROR;
+       if(FLAC__stream_decoder_init(decoder->private_->FLAC_stream_decoder) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
+               return decoder->protected_->state = OggFLAC__STREAM_DECODER_FLAC_STREAM_DECODER_ERROR;
 
        return decoder->protected_->state = OggFLAC__STREAM_DECODER_OK;
 }
@@ -249,6 +252,18 @@ FLAC__bool OggFLAC__stream_decoder_set_client_data(OggFLAC__StreamDecoder *decod
        return true;
 }
 
+FLAC__bool OggFLAC__stream_decoder_set_serial_number(OggFLAC__StreamDecoder *decoder, long value)
+{
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->private_);
+       FLAC__ASSERT(0 != decoder->protected_);
+       if(decoder->protected_->state != OggFLAC__STREAM_DECODER_UNINITIALIZED)
+               return false;
+       decoder->protected_->use_first_serial_number = false;
+       decoder->protected_->serial_number = value;
+       return true;
+}
+
 FLAC__bool OggFLAC__stream_decoder_set_metadata_respond(OggFLAC__StreamDecoder *decoder, FLAC__MetadataType type)
 {
        FLAC__ASSERT(0 != decoder);
@@ -432,6 +447,7 @@ void set_defaults_(OggFLAC__StreamDecoder *decoder)
        decoder->private_->metadata_callback = 0;
        decoder->private_->error_callback = 0;
        decoder->private_->client_data = 0;
+       decoder->protected_->use_first_serial_number = true;
 }
 
 FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *unused, FLAC__byte buffer[], unsigned *bytes, void *client_data)
@@ -448,7 +464,7 @@ FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *unused,
         * We have to be careful not to read in more than the
         * FLAC__StreamDecoder says it has room for.  We know
         * that the size of the decoded data must be no more
-        * than the encoded data we will read.  
+        * than the encoded data we will read.
         */
        ogg_bytes_to_read = min(*bytes, OGG_BYTES_CHUNK);
        oggbuf = ogg_sync_buffer(&decoder->private_->ogg.sync_state, ogg_bytes_to_read);
@@ -456,7 +472,7 @@ FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *unused,
        if(decoder->private_->read_callback(decoder, oggbuf, &ogg_bytes_to_read, decoder->private_->client_data) != FLAC__STREAM_DECODER_READ_STATUS_CONTINUE) {
                decoder->protected_->state = OggFLAC__STREAM_DECODER_READ_ERROR;
                return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
-       }   
+       }
        ogg_bytes_read = ogg_bytes_to_read;
 
        if(ogg_sync_wrote(&decoder->private_->ogg.sync_state, ogg_bytes_read) < 0) {
@@ -466,6 +482,11 @@ FLAC__StreamDecoderReadStatus read_callback_(const FLAC__StreamDecoder *unused,
 
        *bytes = 0;
        while(ogg_sync_pageout(&decoder->private_->ogg.sync_state, &page) == 1) {
+               /* grab the serial number if necessary */
+               if(decoder->private_->ogg.need_serial_number) {
+                       decoder->private_->ogg.stream_state.serialno = decoder->protected_->serial_number = ogg_page_serialno(&page);
+                       decoder->private_->ogg.need_serial_number = false;
+               }
                if(ogg_stream_pagein(&decoder->private_->ogg.stream_state, &page) == 0) {
                        ogg_packet packet;