diff --git a/include/FLAC/stream_encoder.h b/include/FLAC/stream_encoder.h index 6986ea4d..0c13b0a6 100644 --- a/include/FLAC/stream_encoder.h +++ b/include/FLAC/stream_encoder.h @@ -538,11 +538,16 @@ typedef FLAC__StreamEncoderReadStatus (*FLAC__StreamEncoderReadCallback)(const F * callback is being called to write metadata. * * \note - * Unlike when writing to native FLAC, when writing to Ogg FLAC the - * write callback will be called twice when writing each audio - * frame; once for the page header, and once for the page body. - * When writing the page header, the \a samples argument to the - * write callback will be \c 0. + * Unlike when writing to native FLAC, when writing to Ogg FLAC the write + * callback will be called at least twice when writing each audio frame; once + * for the page header and once for the page body, possibly repeating this + * pair of calls several times in a batch with the same value of + * \a current_frame. When writing the page header, as well as in all but the + * first page body write of the batch, the \a samples argument to the write + * callback will be \c 0. The full number of samples of the batch will be + * passed in the first page body write. Furthermore, it is possible that a few + * of these samples are retained in an internal Ogg encoding buffer and not + * actually encoded until the next batch. * * \note In general, FLAC__StreamEncoder functions which change the * state should not be called on the \a encoder while in the callback. diff --git a/src/libFLAC/include/private/ogg_encoder_aspect.h b/src/libFLAC/include/private/ogg_encoder_aspect.h index 6bee3b7c..73f56b47 100644 --- a/src/libFLAC/include/private/ogg_encoder_aspect.h +++ b/src/libFLAC/include/private/ogg_encoder_aspect.h @@ -49,6 +49,7 @@ typedef struct FLAC__OggEncoderAspect { FLAC__bool seen_magic; /* true if we've seen the fLaC magic in the write callback yet */ FLAC__bool is_first_packet; FLAC__uint64 samples_written; + uint32_t samples_in_submit_buffer; } FLAC__OggEncoderAspect; void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value); diff --git a/src/libFLAC/ogg_encoder_aspect.c b/src/libFLAC/ogg_encoder_aspect.c index b2ccbe9c..3b4d8a74 100644 --- a/src/libFLAC/ogg_encoder_aspect.c +++ b/src/libFLAC/ogg_encoder_aspect.c @@ -57,6 +57,7 @@ FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect) aspect->seen_magic = false; aspect->is_first_packet = true; aspect->samples_written = 0; + aspect->samples_in_submit_buffer = 0; return true; } @@ -192,21 +193,27 @@ FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(F if(ogg_stream_packetin(&aspect->stream_state, &packet) != 0) return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; - /*@@@ can't figure out a way to pass a useful number for 'samples' to the write_callback, so we'll just pass 0 */ + /* For a batch of write_callback calls associated with the same current_frame, pass the number of samples in the + * first non-metadata page body call, and then set to zero in case there are more iterations of the while loop (so + * as not to give the impression of more samples being processed). + */ + aspect->samples_in_submit_buffer += samples; if(is_metadata) { while(ogg_stream_flush(&aspect->stream_state, &aspect->page) != 0) { if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; - if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + if(write_callback(encoder, aspect->page.body, aspect->page.body_len, aspect->samples_in_submit_buffer, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + aspect->samples_in_submit_buffer = 0; } } else { while(ogg_stream_pageout(&aspect->stream_state, &aspect->page) != 0) { if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; - if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) + if(write_callback(encoder, aspect->page.body, aspect->page.body_len, aspect->samples_in_submit_buffer, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; + aspect->samples_in_submit_buffer = 0; } } }