add method for skipping an audio frame, plus tests
authorJosh Coalson <jcoalson@users.sourceforce.net>
Fri, 16 Jul 2004 00:53:38 +0000 (00:53 +0000)
committerJosh Coalson <jcoalson@users.sourceforce.net>
Fri, 16 Jul 2004 00:53:38 +0000 (00:53 +0000)
12 files changed:
include/FLAC++/decoder.h
include/FLAC/file_decoder.h
include/FLAC/seekable_stream_decoder.h
include/FLAC/stream_decoder.h
src/libFLAC++/file_decoder.cpp
src/libFLAC++/seekable_stream_decoder.cpp
src/libFLAC++/stream_decoder.cpp
src/libFLAC/file_decoder.c
src/libFLAC/seekable_stream_decoder.c
src/libFLAC/stream_decoder.c
src/test_libFLAC++/decoders.cpp
src/test_libFLAC/decoders.c

index 51d2138..8a91391 100644 (file)
@@ -134,6 +134,7 @@ namespace FLAC {
                        bool process_single();
                        bool process_until_end_of_metadata();
                        bool process_until_end_of_stream();
+                       bool skip_single_frame();
                protected:
                        virtual ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], unsigned *bytes) = 0;
                        virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) = 0;
@@ -222,6 +223,7 @@ namespace FLAC {
                        bool process_single();
                        bool process_until_end_of_metadata();
                        bool process_until_end_of_stream();
+                       bool skip_single_frame();
 
                        bool seek_absolute(FLAC__uint64 sample);
                protected:
@@ -319,6 +321,7 @@ namespace FLAC {
                        bool process_single();
                        bool process_until_end_of_metadata();
                        bool process_until_end_of_file();
+                       bool skip_single_frame();
 
                        bool seek_absolute(FLAC__uint64 sample);
                protected:
index fedf4cc..04e05ff 100644 (file)
@@ -627,6 +627,17 @@ FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_metadata(FLAC__FileD
  */
 FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_file(FLAC__FileDecoder *decoder);
 
+/** This is inherited from FLAC__SeekableStreamDecoder; see
+ *  FLAC__seekable_stream_decoder_skip_single_frame().
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__file_decoder_skip_single_frame(FLAC__FileDecoder *decoder);
+
 /** Flush the input and seek to an absolute sample.
  *  This is inherited from FLAC__SeekableStreamDecoder; see
  *  FLAC__seekable_stream_decoder_seek_absolute().
index c47d084..b28f447 100644 (file)
@@ -898,6 +898,17 @@ FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_metadata(
  */
 FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_stream(FLAC__SeekableStreamDecoder *decoder);
 
+/** This is inherited from FLAC__StreamDecoder; see
+ *  FLAC__stream_decoder_skip_single_frame().
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_skip_single_frame(FLAC__SeekableStreamDecoder *decoder);
+
 /** Flush the input and seek to an absolute sample.
  *  Decoding will resume at the given sample.  Note that because of
  *  this, the next write callback may contain a partial block.
index 894e28f..cd6ebe8 100644 (file)
@@ -751,11 +751,21 @@ FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder);
  *  occurred.  If the decoder loses sync it will call the error callback
  *  instead.
  *
- * \param  decoder  An initialized decoder instance in the state
- *                  \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC.
+ *  Unless there is a fatal read error or end of stream, this function
+ *  will return once one whole frame is decoded.  In other words, if the
+ *  stream is not syncronized or points to a corrupt frame header, the
+ *  decoder will continue to try and resync until it gets to a valid
+ *  frame, then decode one frame, then return.  If the decoder points to
+ *  frame whose frame CRC in the frame footer does not match the
+ *  computed frame CRC, this function will issue a
+ *  FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the
+ *  error callback, and return, having decoded one complete, although
+ *  corrupt, frame.  (Such corrupted frames are sent as silence of the
+ *  correct length to the write callback.)
+ *
+ * \param  decoder  An initialized decoder instance.
  * \assert
  *    \code decoder != NULL \endcode
- *    \code FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC \endcode
  * \retval FLAC__bool
  *    \c false if any read or write error occurred (except
  *    \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true;
@@ -776,11 +786,9 @@ FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *dec
  *  with the decoded metadata.  If the decoder loses sync it will call the
  *  error callback.
  *
- * \param  decoder  An initialized decoder instance in the state
- *                  \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA.
+ * \param  decoder  An initialized decoder instance.
  * \assert
  *    \code decoder != NULL \endcode
- *    \code FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA \endcode
  * \retval FLAC__bool
  *    \c false if any read or write error occurred (except
  *    \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true;
@@ -801,11 +809,9 @@ FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__Str
  *  callback will be called with the decoded metadata or frame.  If the
  *  decoder loses sync it will call the error callback.
  *
- * \param  decoder  An initialized decoder instance in the state
- *                  \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA.
+ * \param  decoder  An initialized decoder instance.
  * \assert
  *    \code decoder != NULL \endcode
- *    \code FLAC__stream_decoder_get_state(decoder) == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA \endcode
  * \retval FLAC__bool
  *    \c false if any read or write error occurred (except
  *    \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true;
@@ -815,6 +821,49 @@ FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__Str
  */
 FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder);
 
+/** Skip one audio frame.
+ *  This version instructs the decoder to 'skip' a single frame and stop,
+ *  unless the callbacks return a fatal error or the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ *  The decoding flow is the same as what occurs when
+ *  FLAC__stream_decoder_process_single() is called to process an audio
+ *  frame, except that this function does not decode the parsed data into
+ *  PCM or call the write callback.  The integrity of the frame is still
+ *  checked the same way as in the other process functions.
+ *
+ *  This function will return once one whole frame is skipped, in the
+ *  same way that FLAC__stream_decoder_process_single() will return once
+ *  one whole frame is decoded.
+ *
+ *  This function, when used from the higher FLAC__SeekableStreamDecoder
+ *  layer, can be used in more quickly determining FLAC frame boundaries
+ *  when decoding of the actual data is not needed, for example when a
+ *  application is separating a FLAC stream into frames for editing or
+ *  storing in a container.  To do this, the application can use
+ *  FLAC__seekable_stream_decoder_skip_single_frame() to quickly advance
+ *  to the next frame, then use
+ *  FLAC__seekable_stream_decoder_get_decode_position() to find the new
+ *  frame boundary.
+ *
+ *  This function should only be called when the stream has advanced
+ *  past all the metadata, otherwise it will return \c false.
+ *
+ * \param  decoder  An initialized decoder instance not in a metadata
+ *                  state.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any read or write error occurred (except
+ *    \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), or if the decoder
+ *    is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or
+ *    FLAC__STREAM_DECODER_READ_METADATA state, else \c true;
+ *    in any case, check the decoder state with
+ *    FLAC__stream_decoder_get_state() to see what went wrong or to
+ *    check for lost synchronization (a sign of stream corruption).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder);
+
 /* \} */
 
 #ifdef __cplusplus
index 9a2ae39..b7c549f 100644 (file)
@@ -193,6 +193,12 @@ namespace FLAC {
                        return (bool)::FLAC__file_decoder_process_until_end_of_file(decoder_);
                }
 
+               bool File::skip_single_frame()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__file_decoder_skip_single_frame(decoder_);
+               }
+
                bool File::seek_absolute(FLAC__uint64 sample)
                {
                        FLAC__ASSERT(0 != decoder_);
index 0db8a61..ca14c20 100644 (file)
@@ -198,6 +198,12 @@ namespace FLAC {
                        return (bool)::FLAC__seekable_stream_decoder_process_until_end_of_stream(decoder_);
                }
 
+               bool SeekableStream::skip_single_frame()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__seekable_stream_decoder_skip_single_frame(decoder_);
+               }
+
                bool SeekableStream::seek_absolute(FLAC__uint64 sample)
                {
                        FLAC__ASSERT(is_valid());
index 3f23a3b..af17688 100644 (file)
@@ -176,6 +176,12 @@ namespace FLAC {
                        return (bool)::FLAC__stream_decoder_process_until_end_of_stream(decoder_);
                }
 
+               bool Stream::skip_single_frame()
+               {
+                       FLAC__ASSERT(is_valid());
+                       return (bool)::FLAC__stream_decoder_skip_single_frame(decoder_);
+               }
+
                ::FLAC__StreamDecoderReadStatus Stream::read_callback_(const ::FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data)
                {
                        (void)decoder;
index c11c664..94e5c94 100644 (file)
@@ -505,6 +505,26 @@ FLAC_API FLAC__bool FLAC__file_decoder_process_until_end_of_file(FLAC__FileDecod
        return ret;
 }
 
+FLAC_API FLAC__bool FLAC__file_decoder_skip_single_frame(FLAC__FileDecoder *decoder)
+{
+       FLAC__bool ret;
+       FLAC__ASSERT(0 != decoder);
+
+       if(decoder->private_->seekable_stream_decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
+               decoder->protected_->state = FLAC__FILE_DECODER_END_OF_FILE;
+
+       if(decoder->protected_->state == FLAC__FILE_DECODER_END_OF_FILE)
+               return true;
+
+       FLAC__ASSERT(decoder->protected_->state == FLAC__FILE_DECODER_OK);
+
+       ret = FLAC__seekable_stream_decoder_skip_single_frame(decoder->private_->seekable_stream_decoder);
+       if(!ret)
+               decoder->protected_->state = FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR;
+
+       return ret;
+}
+
 FLAC_API FLAC__bool FLAC__file_decoder_seek_absolute(FLAC__FileDecoder *decoder, FLAC__uint64 sample)
 {
        FLAC__ASSERT(0 != decoder);
index b80390c..ede2312 100644 (file)
@@ -647,6 +647,26 @@ FLAC_API FLAC__bool FLAC__seekable_stream_decoder_process_until_end_of_stream(FL
        return ret;
 }
 
+FLAC_API FLAC__bool FLAC__seekable_stream_decoder_skip_single_frame(FLAC__SeekableStreamDecoder *decoder)
+{
+       FLAC__bool ret;
+       FLAC__ASSERT(0 != decoder);
+
+       if(decoder->private_->stream_decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM)
+               decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM;
+
+       if(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM)
+               return true;
+
+       FLAC__ASSERT(decoder->protected_->state == FLAC__SEEKABLE_STREAM_DECODER_OK);
+
+       ret = FLAC__stream_decoder_skip_single_frame(decoder->private_->stream_decoder);
+       if(!ret)
+               decoder->protected_->state = FLAC__SEEKABLE_STREAM_DECODER_STREAM_DECODER_ERROR;
+
+       return ret;
+}
+
 FLAC_API FLAC__bool FLAC__seekable_stream_decoder_seek_absolute(FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 sample)
 {
        FLAC__uint64 length;
index 575068c..4b6f6e2 100644 (file)
@@ -76,13 +76,13 @@ static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLA
 static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj);
 static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder);
 static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder);
-static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame);
+static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode);
 static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder);
-static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps);
-static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps);
-static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order);
-static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order);
-static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps);
+static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
 static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual);
 static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder);
 static FLAC__bool read_callback_(FLAC__byte buffer[], unsigned *bytes, void *client_data);
@@ -610,7 +610,7 @@ FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *dec
                                        return true; /* above function sets the status for us */
                                break;
                        case FLAC__STREAM_DECODER_READ_FRAME:
-                               if(!read_frame_(decoder, &got_a_frame))
+                               if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true))
                                        return false; /* above function sets the status for us */
                                if(got_a_frame)
                                        return true; /* above function sets the status for us */
@@ -673,7 +673,7 @@ FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__Strea
                                        return true; /* above function sets the status for us */
                                break;
                        case FLAC__STREAM_DECODER_READ_FRAME:
-                               if(!read_frame_(decoder, &dummy))
+                               if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true))
                                        return false; /* above function sets the status for us */
                                break;
                        case FLAC__STREAM_DECODER_END_OF_STREAM:
@@ -686,6 +686,37 @@ FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__Strea
        }
 }
 
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder)
+{
+       FLAC__bool got_a_frame;
+       FLAC__ASSERT(0 != decoder);
+       FLAC__ASSERT(0 != decoder->protected_);
+
+       while(1) {
+               switch(decoder->protected_->state) {
+                       case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+                       case FLAC__STREAM_DECODER_READ_METADATA:
+                               return false; /* above function sets the status for us */
+                       case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+                               if(!frame_sync_(decoder))
+                                       return true; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_READ_FRAME:
+                               if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false))
+                                       return false; /* above function sets the status for us */
+                               if(got_a_frame)
+                                       return true; /* above function sets the status for us */
+                               break;
+                       case FLAC__STREAM_DECODER_END_OF_STREAM:
+                       case FLAC__STREAM_DECODER_ABORTED:
+                               return true;
+                       default:
+                               FLAC__ASSERT(0);
+                               return false;
+               }
+       }
+}
+
 /***********************************************************************
  *
  * Protected class methods
@@ -1315,7 +1346,7 @@ FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder)
        return true;
 }
 
-FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame)
+FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode)
 {
        unsigned channel;
        unsigned i;
@@ -1367,7 +1398,7 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame)
                /*
                 * now read it
                 */
-               if(!read_subframe_(decoder, channel, bps))
+               if(!read_subframe_(decoder, channel, bps, do_full_decode))
                        return false;
                if(decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME) {
                        decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
@@ -1384,45 +1415,49 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame)
        if(!FLAC__bitbuffer_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN, read_callback_, decoder))
                return false; /* the read_callback_ sets the state for us */
        if(frame_crc == (FLAC__uint16)x) {
-               /* Undo any special channel coding */
-               switch(decoder->private_->frame.header.channel_assignment) {
-                       case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
-                               /* do nothing */
-                               break;
-                       case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
-                               FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
-                               for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
-                                       decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i];
-                               break;
-                       case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
-                               FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
-                               for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
-                                       decoder->private_->output[0][i] += decoder->private_->output[1][i];
-                               break;
-                       case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
-                               FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
-                               for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
-                                       mid = decoder->private_->output[0][i];
-                                       side = decoder->private_->output[1][i];
-                                       mid <<= 1;
-                                       if(side & 1) /* i.e. if 'side' is odd... */
-                                               mid++;
-                                       left = mid + side;
-                                       right = mid - side;
-                                       decoder->private_->output[0][i] = left >> 1;
-                                       decoder->private_->output[1][i] = right >> 1;
-                               }
-                               break;
-                       default:
-                               FLAC__ASSERT(0);
-                               break;
+               if(do_full_decode) {
+                       /* Undo any special channel coding */
+                       switch(decoder->private_->frame.header.channel_assignment) {
+                               case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+                                       /* do nothing */
+                                       break;
+                               case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+                                       FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+                                       for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+                                               decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i];
+                                       break;
+                               case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+                                       FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+                                       for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+                                               decoder->private_->output[0][i] += decoder->private_->output[1][i];
+                                       break;
+                               case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+                                       FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+                                       for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+                                               mid = decoder->private_->output[0][i];
+                                               side = decoder->private_->output[1][i];
+                                               mid <<= 1;
+                                               if(side & 1) /* i.e. if 'side' is odd... */
+                                                       mid++;
+                                               left = mid + side;
+                                               right = mid - side;
+                                               decoder->private_->output[0][i] = left >> 1;
+                                               decoder->private_->output[1][i] = right >> 1;
+                                       }
+                                       break;
+                               default:
+                                       FLAC__ASSERT(0);
+                                       break;
+                       }
                }
        }
        else {
                /* Bad frame, emit error and zero the output signal */
                decoder->private_->error_callback(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH, decoder->private_->client_data);
-               for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
-                       memset(decoder->private_->output[channel], 0, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+               if(do_full_decode) {
+                       for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+                               memset(decoder->private_->output[channel], 0, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+                       }
                }
        }
 
@@ -1439,8 +1474,10 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame)
        decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize;
 
        /* write it */
-       if(decoder->private_->write_callback(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output, decoder->private_->client_data) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE)
-               return false;
+       if(do_full_decode) {
+               if(decoder->private_->write_callback(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output, decoder->private_->client_data) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE)
+                       return false;
+       }
 
        decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
        return true;
@@ -1725,7 +1762,7 @@ FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder)
        return true;
 }
 
-FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps)
+FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
 {
        FLAC__uint32 x;
        FLAC__bool wasted_bits;
@@ -1755,11 +1792,11 @@ FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsign
                return true;
        }
        else if(x == 0) {
-               if(!read_subframe_constant_(decoder, channel, bps))
+               if(!read_subframe_constant_(decoder, channel, bps, do_full_decode))
                        return false;
        }
        else if(x == 2) {
-               if(!read_subframe_verbatim_(decoder, channel, bps))
+               if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode))
                        return false;
        }
        else if(x < 16) {
@@ -1767,7 +1804,7 @@ FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsign
                return false;
        }
        else if(x <= 24) {
-               if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7))
+               if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7, do_full_decode))
                        return false;
        }
        else if(x < 64) {
@@ -1775,11 +1812,11 @@ FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsign
                return false;
        }
        else {
-               if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1))
+               if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1, do_full_decode))
                        return false;
        }
 
-       if(wasted_bits) {
+       if(wasted_bits && do_full_decode) {
                unsigned i;
                x = decoder->private_->frame.subframes[channel].wasted_bits;
                for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
@@ -1789,7 +1826,7 @@ FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsign
        return true;
 }
 
-FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps)
+FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
 {
        FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant;
        FLAC__int32 x;
@@ -1804,13 +1841,15 @@ FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channe
        subframe->value = x;
 
        /* decode the subframe */
-       for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
-               output[i] = x;
+       if(do_full_decode) {
+               for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+                       output[i] = x;
+       }
 
        return true;
 }
 
-FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order)
+FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode)
 {
        FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed;
        FLAC__int32 i32;
@@ -1856,13 +1895,15 @@ FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel,
        }
 
        /* decode the subframe */
-       memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
-       FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
+       if(do_full_decode) {
+               memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+               FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
+       }
 
        return true;
 }
 
-FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order)
+FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode)
 {
        FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc;
        FLAC__int32 i32;
@@ -1930,19 +1971,21 @@ FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, un
        }
 
        /* decode the subframe */
-       memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
-       if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
-               if(bps <= 16 && subframe->qlp_coeff_precision <= 16)
-                       decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+       if(do_full_decode) {
+               memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+               if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+                       if(bps <= 16 && subframe->qlp_coeff_precision <= 16)
+                               decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+                       else
+                               decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
                else
-                       decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
-       else
-               decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+                       decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+       }
 
        return true;
 }
 
-FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps)
+FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
 {
        FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim;
        FLAC__int32 x, *residual = decoder->private_->residual[channel];
@@ -1959,7 +2002,8 @@ FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channe
        }
 
        /* decode the subframe */
-       memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+       if(do_full_decode)
+               memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
 
        return true;
 }
index be4ef41..d44d34d 100644 (file)
@@ -343,6 +343,11 @@ static bool test_stream_decoder()
                return decoder->die("returned false");
        printf("OK\n");
 
+       printf("testing skip_single_frame()... ");
+       if(!decoder->skip_single_frame())
+               return decoder->die("returned false");
+       printf("OK\n");
+
        printf("testing flush()... ");
        if(!decoder->flush())
                return decoder->die("returned false");
@@ -1060,6 +1065,11 @@ static bool test_seekable_stream_decoder()
                return decoder->die("returned false");
        printf("OK\n");
 
+       printf("testing skip_single_frame()... ");
+       if(!decoder->skip_single_frame())
+               return decoder->die("returned false");
+       printf("OK\n");
+
        printf("testing flush()... ");
        if(!decoder->flush())
                return decoder->die("returned false");
@@ -1723,6 +1733,11 @@ static bool test_file_decoder()
                return decoder->die("returned false");
        printf("OK\n");
 
+       printf("testing skip_single_frame()... ");
+       if(!decoder->skip_single_frame())
+               return decoder->die("returned false");
+       printf("OK\n");
+
        printf("testing seek_absolute()... ");
        if(!decoder->seek_absolute(0))
                return decoder->die("returned false");
index 5fc9382..ebbd5ae 100644 (file)
@@ -386,6 +386,11 @@ static FLAC__bool test_stream_decoder()
                return die_s_("returned false", decoder);
        printf("OK\n");
 
+       printf("testing FLAC__stream_decoder_skip_single_frame()... ");
+       if(!FLAC__stream_decoder_skip_single_frame(decoder))
+               return die_s_("returned false", decoder);
+       printf("OK\n");
+
        printf("testing FLAC__stream_decoder_flush()... ");
        if(!FLAC__stream_decoder_flush(decoder))
                return die_s_("returned false", decoder);
@@ -1093,6 +1098,11 @@ static FLAC__bool test_seekable_stream_decoder()
                return die_ss_("returned false", decoder);
        printf("OK\n");
 
+       printf("testing FLAC__seekable_stream_decoder_skip_single_frame()... ");
+       if(!FLAC__seekable_stream_decoder_skip_single_frame(decoder))
+               return die_ss_("returned false", decoder);
+       printf("OK\n");
+
        printf("testing FLAC__seekable_stream_decoder_flush()... ");
        if(!FLAC__seekable_stream_decoder_flush(decoder))
                return die_ss_("returned false", decoder);
@@ -1664,6 +1674,11 @@ static FLAC__bool test_file_decoder()
                return die_f_("returned false", decoder);
        printf("OK\n");
 
+       printf("testing FLAC__file_decoder_skip_single_frame()... ");
+       if(!FLAC__file_decoder_skip_single_frame(decoder))
+               return die_f_("returned false", decoder);
+       printf("OK\n");
+
        printf("testing FLAC__file_decoder_seek_absolute()... ");
        if(!FLAC__file_decoder_seek_absolute(decoder, 0))
                return die_f_("returned false", decoder);