Skip to content

Extend packet size coding up to 2105535 bytes - #30

Open
jmvalin wants to merge 1 commit into
mainfrom
jmvalin/size_coding5
Open

jmvalin wants to merge 1 commit into
mainfrom
jmvalin/size_coding5

Conversation

@jmvalin

@jmvalin jmvalin commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Replaces the Opus 1/2-byte frame length code (max 1275 bytes) with a 1/2/3-byte code that reaches OAC_SIZE_MAX = 2105535 bytes per frame. That's enough for a 20 ms, 256-channel, 96 kHz lossless frame that inflates instead of compressing (~34 bits per 96 kHz sample):

first byte bytes size
0..191 1 p[0] (0..191)
192..223 2 32p[1] + p[0] (192..8383)
224..255 3 32
(256*p[2] + p[1]) + p[0] + 8160 (8384..2105535)

The code is bijective, so there is no redundancy.

Main changes:

  • OAC_SIZE_MAX and OAC_MAX_FRAMES_PER_PACKET are now public, in include/oac_defines.h. oaci_encode_size()/oaci_parse_size() live out-of-line in src/oac.c; only the trivial oaci_size_bytes() is a static inline in src/oac_private.h.
  • All frame size arrays widen from oac_int16 to oac_int32, and every "1 + (len >= 252)" header-size computation becomes oaci_size_bytes().
  • New oaci_max_frame_bytes(frame_size, Fs, channels) is the single source of truth for "largest frame this configuration can produce", and is used to size the encoder scratch buffers, the multistream scratch buffer and the demo defaults, so we do not allocate multi-MB buffers for configurations that cannot use them.
  • OAC_BITRATE_MAX now scales with sampling rate, frame size and channel count via oaci_max_frame_bytes(), instead of being a fixed ceiling.
  • OAC_MAX_BITRATE is defined once, internally, in celt/celt.h. oaci_bits_to_bitrate() saturates at it and oaci_bitrate_to_bits() uses a 64-bit intermediate.
  • The CELT VBR 510 kb/s ceiling is dropped; the only remaining cap is CELT_MAX_BITRATE_PER_CHANNEL * channels.
  • SILK keeps an explicit SILK_MAX_BYTES = 1275 cap, since the SILK bitstream format itself is unchanged.
  • The range coder is initialised with max_data_bytes - 1 (the TOC byte is not part of the range-coded payload) and is shrunk whenever the CELT packet size cap kicks in.

New tests in tests/test_oac_api.c, all using an independent reference encoder so the test never links library internals:

  • test_frame_length_code(): exhaustive encode/parse round trip over all 2105536 representable sizes, tier-boundary encoder checks, and a repacketizer round trip across tiers.
  • test_encoder_buffer_independence(): the encoder output must not depend on the size of the caller's output buffer, across steady state, a bitrate sweep with FEC off (which is what actually reaches the SILK/hybrid/CELT transitions) and the same sweep with FEC on.

@jmvalin
jmvalin requested a review from janpbuethe September 18, 2026 15:46
@jmvalin jmvalin self-assigned this Sep 18, 2026
Replaces the Opus 1/2-byte frame length code (max 1275 bytes) with
a 1/2/3-byte code that reaches OAC_SIZE_MAX = 2105535 bytes per frame.
That's enough for a 20 ms, 256-channel, 96 kHz lossless frame that
inflates instead of compressing (~34 bits per 96 kHz sample):

  first byte   bytes   size
  0..191       1       p[0]                                (0..191)
  192..223     2       32*p[1] + p[0]                      (192..8383)
  224..255     3       32*(256*p[2] + p[1]) + p[0] + 8160  (8384..2105535)

The code is bijective, so there is no redundancy.

Main changes:

 - OAC_SIZE_MAX and OAC_MAX_FRAMES_PER_PACKET are now public, in
   include/oac_defines.h. oaci_encode_size()/oaci_parse_size() live
   out-of-line in src/oac.c; only the trivial oaci_size_bytes() is a
   static inline in src/oac_private.h.
 - All frame size arrays widen from oac_int16 to oac_int32, and every
   "1 + (len >= 252)" header-size computation becomes oaci_size_bytes().
 - New oaci_max_frame_bytes(frame_size, Fs, channels) is the single
   source of truth for "largest frame this configuration can produce",
   and is used to size the encoder scratch buffers, the multistream
   scratch buffer and the demo defaults, so we do not allocate multi-MB
   buffers for configurations that cannot use them.
 - OAC_BITRATE_MAX now scales with sampling rate, frame size and channel
   count via oaci_max_frame_bytes(), instead of being a fixed ceiling.
 - OAC_MAX_BITRATE is defined once, internally, in celt/celt.h.
   oaci_bits_to_bitrate() saturates at it and oaci_bitrate_to_bits()
   uses a 64-bit intermediate.
 - The CELT VBR 510 kb/s ceiling is dropped; the only remaining cap is
   CELT_MAX_BITRATE_PER_CHANNEL * channels.
 - SILK keeps an explicit SILK_MAX_BYTES = 1275 cap, since the SILK
   bitstream format itself is unchanged.
 - The range coder is initialised with max_data_bytes - 1 (the TOC byte
   is not part of the range-coded payload) and is shrunk whenever the
   CELT packet size cap kicks in.

New tests in tests/test_oac_api.c, all using an independent reference
encoder so the test never links library internals:

 - test_frame_length_code(): exhaustive encode/parse round trip over
   all 2105536 representable sizes, tier-boundary encoder checks, and a
   repacketizer round trip across tiers.
 - test_encoder_buffer_independence(): the encoder output must not
   depend on the size of the caller's output buffer, across steady
   state, a bitrate sweep with FEC off (which is what actually reaches
   the SILK/hybrid/CELT transitions) and the same sweep with FEC on.
@jmvalin
jmvalin force-pushed the jmvalin/size_coding5 branch from 4e26fae to eca958b Compare September 18, 2026 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant