diff options
author | Josh Coalson <jcoalson@users.sourceforce.net> | 2003-09-25 04:01:49 +0000 |
---|---|---|
committer | Josh Coalson <jcoalson@users.sourceforce.net> | 2003-09-25 04:01:49 +0000 |
commit | 6e2c6d9958163acf0711e5bc39a8ea02d720d314 (patch) | |
tree | 6954a08a9900e59533e850926c0be8be0c490c60 | |
parent | 792ddbf4c5b513f1b399986e43f6f122795bca45 (diff) | |
download | flac-6e2c6d9958163acf0711e5bc39a8ea02d720d314.tar.gz |
add a "tell" callback to the seekable stream encoder to make the metadata writeback more robust
-rw-r--r-- | include/FLAC++/encoder.h | 2 | ||||
-rw-r--r-- | include/FLAC/seekable_stream_encoder.h | 74 | ||||
-rw-r--r-- | src/libFLAC++/seekable_stream_encoder.cpp | 10 | ||||
-rw-r--r-- | src/libFLAC/file_encoder.c | 22 | ||||
-rw-r--r-- | src/libFLAC/include/protected/seekable_stream_encoder.h | 1 | ||||
-rw-r--r-- | src/libFLAC/seekable_stream_encoder.c | 163 | ||||
-rw-r--r-- | src/test_libFLAC++/encoders.cpp | 8 | ||||
-rw-r--r-- | src/test_libFLAC/encoders.c | 11 |
8 files changed, 237 insertions, 54 deletions
diff --git a/include/FLAC++/encoder.h b/include/FLAC++/encoder.h index 9142436f..a1252bd0 100644 --- a/include/FLAC++/encoder.h +++ b/include/FLAC++/encoder.h @@ -249,11 +249,13 @@ namespace FLAC { bool process_interleaved(const FLAC__int32 buffer[], unsigned samples); protected: virtual ::FLAC__SeekableStreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) = 0; + virtual ::FLAC__SeekableStreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) = 0; virtual ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame) = 0; ::FLAC__SeekableStreamEncoder *encoder_; private: static ::FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); + static ::FLAC__SeekableStreamEncoderTellStatus tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); static ::FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data); // Private and undefined so you can't use them: diff --git a/include/FLAC/seekable_stream_encoder.h b/include/FLAC/seekable_stream_encoder.h index e6ca0bff..271383ed 100644 --- a/include/FLAC/seekable_stream_encoder.h +++ b/include/FLAC/seekable_stream_encoder.h @@ -77,11 +77,12 @@ extern "C" { * * The seekable stream encoder is a wrapper around the * \link flac_stream_encoder stream encoder \endlink with callbacks for - * seeking the output. This allows the encoder to go back and rewrite - * some of the metadata after encoding if necessary, and provides the - * metadata callback of the stream encoder internally. However, you - * must provide a seek callback (see - * FLAC__seekable_stream_encoder_set_seek_callback()). + * seeking the output and reporting the output stream position. This + * allows the encoder to go back and rewrite some of the metadata after + * encoding if necessary, and provides the metadata callback of the stream + * encoder internally. However, you must provide seek and tell callbacks + * (see FLAC__seekable_stream_encoder_set_seek_callback() and + * FLAC__seekable_stream_encoder_set_tell_callback()). * * Make sure to read the detailed description of the * \link flac_stream_encoder stream encoder module \endlink since the @@ -135,6 +136,9 @@ typedef enum { FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR, /**< The seek callback returned an error. */ + FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR, + /**< The tell callback returned an error. */ + FLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED, /**< FLAC__seekable_stream_encoder_init() was called when the encoder was * already initialized, usually because @@ -184,6 +188,26 @@ typedef enum { extern FLAC_API const char * const FLAC__SeekableStreamEncoderSeekStatusString[]; +/** Return values for the FLAC__SeekableStreamEncoder tell callback. + */ +typedef enum { + + FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK, + /**< The tell was OK and encoding can continue. */ + + FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR + /**< An unrecoverable error occurred. The encoder will return from the process call. */ + +} FLAC__SeekableStreamEncoderTellStatus; + +/** Maps a FLAC__SeekableStreamEncoderTellStatus to a C string. + * + * Using a FLAC__SeekableStreamEncoderTellStatus as the index to this array + * will give the string equivalent. The contents should not be modified. + */ +extern FLAC_API const char * const FLAC__SeekableStreamEncoderTellStatusString[]; + + /*********************************************************************** * * class FLAC__SeekableStreamEncoder @@ -214,6 +238,28 @@ typedef struct { */ typedef FLAC__SeekableStreamEncoderSeekStatus (*FLAC__SeekableStreamEncoderSeekCallback)(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); +/** Signature for the tell callback. + * See FLAC__seekable_stream_encoder_set_tell_callback() for more info. + * + * \warning + * The callback must return the true current byte offset of the output to + * which the encoder is writing. If you are buffering the output, make + * sure and take this into account. If you are writing directly to a + * FILE* from your write callback, ftell() is sufficient. If you are + * writing directly to a file descriptor from your write callback, you + * can use lseek(fd, SEEK_CUR, 0). The encoder may later seek back to + * these points to rewrite metadata after encoding. + * + * \param encoder The encoder instance calling the callback. + * \param absolute_byte_offset The address at which to store the current + * position of the output. + * \param client_data The callee's client data set through + * FLAC__seekable_stream_encoder_set_client_data(). + * \retval FLAC__SeekableStreamEncoderTellStatus + * The callee's return status. + */ +typedef FLAC__SeekableStreamEncoderTellStatus (*FLAC__SeekableStreamEncoderTellCallback)(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); + /** Signature for the write callback. * See FLAC__seekable_stream_encoder_set_write_callback() * and FLAC__StreamEncoderWriteCallback for more info. @@ -542,6 +588,24 @@ FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_metadata(FLAC__SeekableStr */ FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_seek_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderSeekCallback value); +/** Set the tell callback. + * The supplied function will be called when the encoder needs to know + * the current position of the output stream. + * + * \note + * The callback is mandatory and must be set before initialization. + * + * \default \c NULL + * \param encoder An encoder instance to set. + * \param value See above. + * \assert + * \code encoder != NULL \endcode + * \code value != NULL \endcode + * \retval FLAC__bool + * \c false if the encoder is already initialized, else \c true. + */ +FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_tell_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderTellCallback value); + /** Set the write callback. * This is inherited from FLAC__StreamEncoder; see * FLAC__stream_encoder_set_write_callback(). diff --git a/src/libFLAC++/seekable_stream_encoder.cpp b/src/libFLAC++/seekable_stream_encoder.cpp index b23a082d..926e4c9d 100644 --- a/src/libFLAC++/seekable_stream_encoder.cpp +++ b/src/libFLAC++/seekable_stream_encoder.cpp @@ -290,6 +290,7 @@ namespace FLAC { { FLAC__ASSERT(is_valid()); ::FLAC__seekable_stream_encoder_set_seek_callback(encoder_, seek_callback_); + ::FLAC__seekable_stream_encoder_set_tell_callback(encoder_, tell_callback_); ::FLAC__seekable_stream_encoder_set_write_callback(encoder_, write_callback_); ::FLAC__seekable_stream_encoder_set_client_data(encoder_, (void*)this); return State(::FLAC__seekable_stream_encoder_init(encoder_)); @@ -322,6 +323,15 @@ namespace FLAC { return instance->seek_callback(absolute_byte_offset); } + ::FLAC__SeekableStreamEncoderTellStatus SeekableStream::tell_callback_(const ::FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) + { + (void)encoder; + FLAC__ASSERT(0 != client_data); + SeekableStream *instance = reinterpret_cast<SeekableStream *>(client_data); + FLAC__ASSERT(0 != instance); + return instance->tell_callback(absolute_byte_offset); + } + ::FLAC__StreamEncoderWriteStatus SeekableStream::write_callback_(const ::FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data) { (void)encoder; diff --git a/src/libFLAC/file_encoder.c b/src/libFLAC/file_encoder.c index a0849801..98a81326 100644 --- a/src/libFLAC/file_encoder.c +++ b/src/libFLAC/file_encoder.c @@ -49,6 +49,7 @@ extern FLAC__bool FLAC__seekable_stream_encoder_disable_verbatim_subframes(FLAC_ static void set_defaults_(FLAC__FileEncoder *encoder); static FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data); +static FLAC__SeekableStreamEncoderTellStatus tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data); static FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data); /*********************************************************************** @@ -174,6 +175,7 @@ FLAC_API FLAC__FileEncoderState FLAC__file_encoder_init(FLAC__FileEncoder *encod encoder->private_->samples_written = 0; FLAC__seekable_stream_encoder_set_seek_callback(encoder->private_->seekable_stream_encoder, seek_callback_); + FLAC__seekable_stream_encoder_set_tell_callback(encoder->private_->seekable_stream_encoder, tell_callback_); FLAC__seekable_stream_encoder_set_write_callback(encoder->private_->seekable_stream_encoder, write_callback_); FLAC__seekable_stream_encoder_set_client_data(encoder->private_->seekable_stream_encoder, encoder); @@ -711,6 +713,26 @@ FLAC__SeekableStreamEncoderSeekStatus seek_callback_(const FLAC__SeekableStreamE return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK; } +FLAC__SeekableStreamEncoderSeekStatus tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + FLAC__FileEncoder *file_encoder = (FLAC__FileEncoder*)client_data; + long offset; + + (void)encoder; + + FLAC__ASSERT(0 != file_encoder); + + offset = ftell(file_encoder->private_->file); + + if(offset < 0) { + return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR; + } + else { + *absolute_byte_offset = (FLAC__uint64)offset; + return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK; + } +} + #ifdef FLAC__VALGRIND_TESTING static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { diff --git a/src/libFLAC/include/protected/seekable_stream_encoder.h b/src/libFLAC/include/protected/seekable_stream_encoder.h index a1f00c84..d94bc0af 100644 --- a/src/libFLAC/include/protected/seekable_stream_encoder.h +++ b/src/libFLAC/include/protected/seekable_stream_encoder.h @@ -36,6 +36,7 @@ typedef struct FLAC__SeekableStreamEncoderProtected { FLAC__SeekableStreamEncoderState state; + FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset; } FLAC__SeekableStreamEncoderProtected; #endif diff --git a/src/libFLAC/seekable_stream_encoder.c b/src/libFLAC/seekable_stream_encoder.c index 711e699e..b5aa5042 100644 --- a/src/libFLAC/seekable_stream_encoder.c +++ b/src/libFLAC/seekable_stream_encoder.c @@ -64,14 +64,13 @@ static void metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__S typedef struct FLAC__SeekableStreamEncoderPrivate { FLAC__SeekableStreamEncoderSeekCallback seek_callback; + FLAC__SeekableStreamEncoderTellCallback tell_callback; FLAC__SeekableStreamEncoderWriteCallback write_callback; void *client_data; FLAC__StreamEncoder *stream_encoder; FLAC__StreamMetadata_SeekTable *seek_table; /* internal vars (all the above are class settings) */ unsigned first_seekpoint_to_check; - FLAC__uint64 stream_offset, seektable_offset; - FLAC__uint64 bytes_written; FLAC__uint64 samples_written; } FLAC__SeekableStreamEncoderPrivate; @@ -88,6 +87,7 @@ FLAC_API const char * const FLAC__SeekableStreamEncoderStateString[] = { "FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR", "FLAC__SEEKABLE_STREAM_ENCODER_READ_ERROR", "FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR", + "FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR", "FLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED", "FLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK", "FLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE", @@ -99,6 +99,11 @@ FLAC_API const char * const FLAC__SeekableStreamEncoderSeekStatusString[] = { "FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_ERROR" }; +FLAC_API const char * const FLAC__SeekableStreamEncoderTellStatusString[] = { + "FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK", + "FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_ERROR" +}; + /*********************************************************************** * @@ -175,21 +180,21 @@ FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_init(FLA if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_ALREADY_INITIALIZED; - if(0 == encoder->private_->seek_callback || 0 == encoder->private_->write_callback) + if(0 == encoder->private_->seek_callback || 0 == encoder->private_->tell_callback || 0 == encoder->private_->write_callback) return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_INVALID_CALLBACK; if(0 != encoder->private_->seek_table && !FLAC__format_seektable_is_legal(encoder->private_->seek_table)) return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_INVALID_SEEKTABLE; /* - * This must be done before we init the stream encoder because that + * These must be done before we init the stream encoder because that * calls the write_callback, which uses these values. */ encoder->private_->first_seekpoint_to_check = 0; - encoder->private_->stream_offset = 0; - encoder->private_->seektable_offset = 0; - encoder->private_->bytes_written = 0; encoder->private_->samples_written = 0; + encoder->protected_->streaminfo_offset = 0; + encoder->protected_->seektable_offset = 0; + encoder->protected_->audio_offset = 0; FLAC__stream_encoder_set_write_callback(encoder->private_->stream_encoder, write_callback_); FLAC__stream_encoder_set_metadata_callback(encoder->private_->stream_encoder, metadata_callback_); @@ -202,7 +207,8 @@ FLAC_API FLAC__SeekableStreamEncoderState FLAC__seekable_stream_encoder_init(FLA * Initializing the stream encoder writes all the metadata, so we * save the stream offset now. */ - encoder->private_->stream_offset = encoder->private_->bytes_written; + if(encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK) + return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR; return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_OK; } @@ -443,6 +449,17 @@ FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_seek_callback(FLAC__Seekab return true; } +FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_tell_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderTellCallback value) +{ + FLAC__ASSERT(0 != encoder); + FLAC__ASSERT(0 != encoder->private_); + FLAC__ASSERT(0 != encoder->protected_); + if(encoder->protected_->state != FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) + return false; + encoder->private_->tell_callback = value; + return true; +} + FLAC_API FLAC__bool FLAC__seekable_stream_encoder_set_write_callback(FLAC__SeekableStreamEncoder *encoder, FLAC__SeekableStreamEncoderWriteCallback value) { FLAC__ASSERT(0 != encoder); @@ -692,6 +709,7 @@ void set_defaults_(FLAC__SeekableStreamEncoder *encoder) FLAC__ASSERT(0 != encoder->protected_); encoder->private_->seek_callback = 0; + encoder->private_->tell_callback = 0; encoder->private_->write_callback = 0; encoder->private_->client_data = 0; @@ -702,19 +720,28 @@ FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *encode { FLAC__SeekableStreamEncoder *seekable_stream_encoder = (FLAC__SeekableStreamEncoder*)client_data; FLAC__StreamEncoderWriteStatus status; + FLAC__uint64 output_position; + + if(seekable_stream_encoder->private_->tell_callback(seekable_stream_encoder, &output_position, seekable_stream_encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK) + return encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_TELL_ERROR; /* - * Watch for the first SEEKTABLE block to go by and store its offset. + * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets. */ - if(samples == 0 && (buffer[0] & 0x7f) == FLAC__METADATA_TYPE_SEEKTABLE) - seekable_stream_encoder->private_->seektable_offset = seekable_stream_encoder->private_->bytes_written; + if(samples == 0) { + FLAC__MetadataType type = (buffer[0] & 0x7f); + if(type == FLAC__METADATA_TYPE_STREAMINFO) + seekable_stream_encoder->protected_->streaminfo_offset = output_position; + else if(type == FLAC__METADATA_TYPE_SEEKTABLE && seekable_stream_encoder->protected_->seektable_offset == 0) + seekable_stream_encoder->protected_->seektable_offset = output_position; + } /* - * Mark the current seek point if hit (if stream_offset == 0 that + * Mark the current seek point if hit (if audio_offset == 0 that * means we're still writing metadata and haven't hit the first * frame yet) */ - if(0 != seekable_stream_encoder->private_->seek_table && seekable_stream_encoder->private_->stream_offset > 0 && seekable_stream_encoder->private_->seek_table->num_points > 0) { + if(0 != seekable_stream_encoder->private_->seek_table && seekable_stream_encoder->protected_->audio_offset > 0 && seekable_stream_encoder->private_->seek_table->num_points > 0) { const unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder); const FLAC__uint64 frame_first_sample = seekable_stream_encoder->private_->samples_written; const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1; @@ -727,7 +754,7 @@ FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *encode } else if(test_sample >= frame_first_sample) { seekable_stream_encoder->private_->seek_table->points[i].sample_number = frame_first_sample; - seekable_stream_encoder->private_->seek_table->points[i].stream_offset = seekable_stream_encoder->private_->bytes_written - seekable_stream_encoder->private_->stream_offset; + seekable_stream_encoder->private_->seek_table->points[i].stream_offset = output_position - seekable_stream_encoder->protected_->audio_offset; seekable_stream_encoder->private_->seek_table->points[i].frame_samples = blocksize; seekable_stream_encoder->private_->first_seekpoint_to_check++; /* DO NOT: "break;" and here's why: @@ -746,7 +773,6 @@ FLAC__StreamEncoderWriteStatus write_callback_(const FLAC__StreamEncoder *encode status = seekable_stream_encoder->private_->write_callback(seekable_stream_encoder, buffer, bytes, samples, current_frame, seekable_stream_encoder->private_->client_data); if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - seekable_stream_encoder->private_->bytes_written += bytes; seekable_stream_encoder->private_->samples_written += samples; } else @@ -783,61 +809,100 @@ void metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMe /* * Write MD5 signature */ - if(seekable_stream_encoder->private_->seek_callback(seekable_stream_encoder, 26, seekable_stream_encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { - seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; - return; - } - if(seekable_stream_encoder->private_->write_callback(seekable_stream_encoder, metadata->data.stream_info.md5sum, 16, 0, 0, seekable_stream_encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; - return; + { + const unsigned md5_offset = + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + + FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN + ) / 8; + + if(seekable_stream_encoder->private_->seek_callback(seekable_stream_encoder, seekable_stream_encoder->protected_->streaminfo_offset + md5_offset, seekable_stream_encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { + seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; + return; + } + if(seekable_stream_encoder->private_->write_callback(seekable_stream_encoder, metadata->data.stream_info.md5sum, 16, 0, 0, seekable_stream_encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; + return; + } } /* * Write total samples */ - b[0] = ((FLAC__byte)(bps-1) << 4) | (FLAC__byte)((samples >> 32) & 0x0F); - b[1] = (FLAC__byte)((samples >> 24) & 0xFF); - b[2] = (FLAC__byte)((samples >> 16) & 0xFF); - b[3] = (FLAC__byte)((samples >> 8) & 0xFF); - b[4] = (FLAC__byte)(samples & 0xFF); - if(seekable_stream_encoder->private_->seek_callback(seekable_stream_encoder, 21, seekable_stream_encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { - seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; - return; - } - if(seekable_stream_encoder->private_->write_callback(seekable_stream_encoder, b, 5, 0, 0, seekable_stream_encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; - return; + { + const unsigned total_samples_byte_offset = + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN + + FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN + - 4 + ) / 8; + + b[0] = ((FLAC__byte)(bps-1) << 4) | (FLAC__byte)((samples >> 32) & 0x0F); + b[1] = (FLAC__byte)((samples >> 24) & 0xFF); + b[2] = (FLAC__byte)((samples >> 16) & 0xFF); + b[3] = (FLAC__byte)((samples >> 8) & 0xFF); + b[4] = (FLAC__byte)(samples & 0xFF); + if(seekable_stream_encoder->private_->seek_callback(seekable_stream_encoder, seekable_stream_encoder->protected_->streaminfo_offset + total_samples_byte_offset, seekable_stream_encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { + seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; + return; + } + if(seekable_stream_encoder->private_->write_callback(seekable_stream_encoder, b, 5, 0, 0, seekable_stream_encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; + return; + } } /* * Write min/max framesize */ - b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF); - b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF); - b[2] = (FLAC__byte)(min_framesize & 0xFF); - b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF); - b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF); - b[5] = (FLAC__byte)(max_framesize & 0xFF); - if(seekable_stream_encoder->private_->seek_callback(seekable_stream_encoder, 12, seekable_stream_encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { - seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; - return; - } - if(seekable_stream_encoder->private_->write_callback(seekable_stream_encoder, b, 6, 0, 0, seekable_stream_encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { - seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; - return; + { + const unsigned min_framesize_offset = + FLAC__STREAM_METADATA_HEADER_LENGTH + + ( + FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN + + FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN + ) / 8; + + b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF); + b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF); + b[2] = (FLAC__byte)(min_framesize & 0xFF); + b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF); + b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF); + b[5] = (FLAC__byte)(max_framesize & 0xFF); + if(seekable_stream_encoder->private_->seek_callback(seekable_stream_encoder, seekable_stream_encoder->protected_->streaminfo_offset + min_framesize_offset, seekable_stream_encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { + seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; + return; + } + if(seekable_stream_encoder->private_->write_callback(seekable_stream_encoder, b, 6, 0, 0, seekable_stream_encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) { + seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_WRITE_ERROR; + return; + } } /* * Write seektable */ - if(0 != seekable_stream_encoder->private_->seek_table && seekable_stream_encoder->private_->seek_table->num_points > 0 && seekable_stream_encoder->private_->seektable_offset > 0) { + if(0 != seekable_stream_encoder->private_->seek_table && seekable_stream_encoder->private_->seek_table->num_points > 0 && seekable_stream_encoder->protected_->seektable_offset > 0) { unsigned i; FLAC__format_seektable_sort(seekable_stream_encoder->private_->seek_table); FLAC__ASSERT(FLAC__format_seektable_is_legal(seekable_stream_encoder->private_->seek_table)); - if(seekable_stream_encoder->private_->seek_callback(seekable_stream_encoder, seekable_stream_encoder->private_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, seekable_stream_encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { + if(seekable_stream_encoder->private_->seek_callback(seekable_stream_encoder, seekable_stream_encoder->protected_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, seekable_stream_encoder->private_->client_data) != FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK) { seekable_stream_encoder->protected_->state = FLAC__SEEKABLE_STREAM_ENCODER_SEEK_ERROR; return; } diff --git a/src/test_libFLAC++/encoders.cpp b/src/test_libFLAC++/encoders.cpp index cc75f8d4..c2788452 100644 --- a/src/test_libFLAC++/encoders.cpp +++ b/src/test_libFLAC++/encoders.cpp @@ -375,6 +375,7 @@ public: // from FLAC::Encoder::SeekableStream ::FLAC__SeekableStreamEncoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset); + ::FLAC__SeekableStreamEncoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset); ::FLAC__StreamEncoderWriteStatus write_callback(const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame); bool die(const char *msg = 0) const; @@ -387,6 +388,13 @@ public: return ::FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK; } +::FLAC__SeekableStreamEncoderTellStatus SeekableStreamEncoder::tell_callback(FLAC__uint64 *absolute_byte_offset) +{ + (void)absolute_byte_offset; + + return ::FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK; +} + ::FLAC__StreamEncoderWriteStatus SeekableStreamEncoder::write_callback(const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame) { (void)buffer, (void)bytes, (void)samples, (void)current_frame; diff --git a/src/test_libFLAC/encoders.c b/src/test_libFLAC/encoders.c index dff9122c..2fa07796 100644 --- a/src/test_libFLAC/encoders.c +++ b/src/test_libFLAC/encoders.c @@ -422,6 +422,12 @@ FLAC__SeekableStreamEncoderSeekStatus seekable_stream_encoder_seek_callback_(con return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK; } +FLAC__SeekableStreamEncoderTellStatus seekable_stream_encoder_tell_callback_(const FLAC__SeekableStreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + (void)encoder, (void)absolute_byte_offset, (void)client_data; + return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK; +} + FLAC__StreamEncoderWriteStatus seekable_stream_encoder_write_callback_(const FLAC__SeekableStreamEncoder *encoder, const FLAC__byte buffer[], unsigned bytes, unsigned samples, unsigned current_frame, void *client_data) { (void)encoder, (void)buffer, (void)bytes, (void)samples, (void)current_frame, (void)client_data; @@ -545,6 +551,11 @@ static FLAC__bool test_seekable_stream_encoder() return die_ss_("returned false", encoder); printf("OK\n"); + printf("testing FLAC__seekable_stream_encoder_set_tell_callback()... "); + if(!FLAC__seekable_stream_encoder_set_tell_callback(encoder, seekable_stream_encoder_tell_callback_)) + return die_ss_("returned false", encoder); + printf("OK\n"); + printf("testing FLAC__seekable_stream_encoder_set_write_callback()... "); if(!FLAC__seekable_stream_encoder_set_write_callback(encoder, seekable_stream_encoder_write_callback_)) return die_ss_("returned false", encoder); |