Skip to content

Commit

Permalink
use ogg_page_granulepos to get number of samples written for Ogg FLAC
Browse files Browse the repository at this point in the history
The granule position of the Ogg page will tell us how many audio frames are
included in the page that we receive from libogg. Therefore, to count the
number of frames per page, we simply check the granule position and subtract it
from the granule position of the previous page.

A signed 64-bit integer type is used for the granule position, as libogg also
uses one as the return type of ogg_page_granulepos. An unsigned 32-bit integer
is sufficient to contain the number of frames, as the granule position of a
page is determined by the last complete packet in that page, the number of
frames in each packet is limited by the 32-bit unsigned integer type internally
in libflac, and an Ogg page, at most 65,307 bytes, can only contain at most
~20 million frames (tested experimentally with pure silence
with maximum compression level).
  • Loading branch information
ziplantil committed Sep 20, 2024
1 parent e42f723 commit b6d0430
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/libFLAC/include/private/ogg_encoder_aspect.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +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__int64 last_page_granule_pos;
} FLAC__OggEncoderAspect;

void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value);
Expand Down
15 changes: 9 additions & 6 deletions src/libFLAC/ogg_encoder_aspect.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +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;
aspect->last_page_granule_pos = 0;

return true;
}
Expand Down Expand Up @@ -197,23 +197,26 @@ FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(F
* 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) {
FLAC__int64 page_granule_pos = ogg_page_granulepos(&aspect->page);
uint32_t frames_in_this_page = (uint32_t)(page_granule_pos - aspect->last_page_granule_pos);
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, aspect->samples_in_submit_buffer, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
if(write_callback(encoder, aspect->page.body, aspect->page.body_len, frames_in_this_page, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
aspect->samples_in_submit_buffer = 0;
aspect->last_page_granule_pos = page_granule_pos;
}
}
else {
while(ogg_stream_pageout(&aspect->stream_state, &aspect->page) != 0) {
FLAC__int64 page_granule_pos = ogg_page_granulepos(&aspect->page);
uint32_t frames_in_this_page = (uint32_t)(page_granule_pos - aspect->last_page_granule_pos);
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, aspect->samples_in_submit_buffer, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
if(write_callback(encoder, aspect->page.body, aspect->page.body_len, frames_in_this_page, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
aspect->samples_in_submit_buffer = 0;
aspect->last_page_granule_pos = page_granule_pos;
}
}
}
Expand Down

0 comments on commit b6d0430

Please sign in to comment.