Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion celt/bands.c
Original file line number Diff line number Diff line change
Expand Up @@ -1475,7 +1475,9 @@ static void quant_all_bands_twoch(int encode, const CELTMode *m, int start, int
ctx.disable_inv = disable_inv;
ctx.resynth = resynth;
ctx.theta_round = 0;
ALLOC(bytes_save, theta_rdo ? 1275 : ALLOC_NONE, unsigned char);
/* The theta RDO path saves everything between ec->offs and ec->storage.
ec->offs only grows from here, so this is an upper bound. */
ALLOC(bytes_save, theta_rdo ? (int)(ec->storage - ec->offs) : ALLOC_NONE, unsigned char);

/* Avoid injecting noise in the first band on transients. */
ctx.avoid_split_noise = B > 1;
Expand Down
13 changes: 11 additions & 2 deletions celt/celt.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,22 @@ typedef struct {
#define CELT_SET_SILK_INFO_REQUEST 10028
#define CELT_SET_SILK_INFO(x) CELT_SET_SILK_INFO_REQUEST, celt_check_silkinfo_ptr(x)

/* Highest bit-rate the frame length signalling can represent: a full
OAC_SIZE_MAX payload every 20 ms. Only used to saturate the bits<->bit-rate
conversions below, so they cannot overflow oac_int32. */
#define OAC_MAX_BITRATE ((oac_int32)OAC_SIZE_MAX*8*50)

/* Maximum bitrate per channel the CELT layer will ever emit. Lossless coding is
handled in the OAC encoder layer and is deliberately NOT bound by this. */
#define CELT_MAX_BITRATE_PER_CHANNEL 750000

static OAC_INLINE oac_int32 oaci_bits_to_bitrate(oac_int32 bits, oac_int32 Fs, oac_int32 frame_size) {
return bits*(6*Fs/frame_size)/6;
oac_int64 rate = (oac_int64)bits * (6 * Fs / frame_size) / 6;
return (oac_int32)IMIN(rate, OAC_MAX_BITRATE);
}

static OAC_INLINE oac_int32 oaci_bitrate_to_bits(oac_int32 bitrate, oac_int32 Fs, oac_int32 frame_size) {
return bitrate*6/(6*Fs/frame_size);
return (oac_int32)((oac_int64)bitrate * 6 / (6 * Fs / frame_size));
}

/* Encoder stuff */
Expand Down
5 changes: 4 additions & 1 deletion celt/celt_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -1191,7 +1191,10 @@ int oaci_celt_decode_with_ec_dred(CELTDecoder * OAC_RESTRICT st, const unsigned
}
M = 1<<LM;

if (len < 0 || len > (st->format == OAC_FORMAT_STANDARD ? 1275 : 1275*OAC_MAX_CHANNELS) || pcm == NULL)
/* Accept any explicitly representable payload size (up to OAC_SIZE_MAX).
If a stricter per-channel or mode-specific upper bound is desired in
the future, enforce it here using st->channels and frame_size. */
if (len < 0 || len > OAC_SIZE_MAX || pcm == NULL)
return OAC_BAD_ARG;

N = M*mode->shortMdctSize;
Expand Down
18 changes: 12 additions & 6 deletions celt/celt_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -1763,7 +1763,7 @@ int oaci_celt_encode_with_ec(CELTEncoder * OAC_RESTRICT st, const oac_res * pcm,
oac_val16 tone_freq = -1;
oac_val32 toneishness = 0;
VARDECL(celt_glog, surround_dynalloc);
int packet_size_cap = (st->format == OAC_FORMAT_STANDARD) ? 1275 : 1275*OAC_MAX_AMBISONICS_CHANNELS;
oac_int32 packet_size_cap;
int qext_scale = 1;
ALLOC_STACK;

Expand Down Expand Up @@ -1836,8 +1836,17 @@ int oaci_celt_encode_with_ec(CELTEncoder * OAC_RESTRICT st, const oac_res * pcm,
celt_assert(st->signalling == 0);
#endif

/* Can't produce more than 1275 output bytes for the main payload. */
/* The CELT layer never emits more than CELT_MAX_BITRATE_PER_CHANNEL per
channel. This has to be a byte-level clamp rather than just the ctl
bit-rate clamp, because the OAC_BITRATE_MAX sentinel bypasses the latter
by design. frame_size is already in mode->Fs units here. */
packet_size_cap = oaci_bitrate_to_bits(CELT_MAX_BITRATE_PER_CHANNEL*(oac_int32)CC,
mode->Fs, frame_size)/8;
nbCompressedBytes = IMIN(nbCompressedBytes, packet_size_cap);
/* Keep the range coder's idea of the buffer in sync, otherwise the raw bits
written from the end would land outside the returned packet. */
if (enc != NULL && enc->storage > (oac_uint32)nbCompressedBytes)
oaci_ec_enc_shrink(enc, nbCompressedBytes);

if (st->vbr && st->bitrate != OAC_BITRATE_MAX) {
vbr_rate = oaci_bitrate_to_bits(st->bitrate, mode->Fs, frame_size)<<BITRES;
Expand Down Expand Up @@ -2349,9 +2358,6 @@ int oaci_celt_encode_with_ec(CELTEncoder * OAC_RESTRICT st, const oac_res * pcm,
oac_int32 target, base_target;
int lm_diff = mode->maxLM - LM;

/* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms.
The CELT allocator will just not be able to use more than that anyway. */
nbCompressedBytes = IMIN(nbCompressedBytes, packet_size_cap>>(3 - LM));
if (!hybrid) {
base_target = vbr_rate - ((40*C + 20)<<BITRES);
} else {
Expand Down Expand Up @@ -2782,7 +2788,7 @@ int oac_custom_encoder_ctl(CELTEncoder * OAC_RESTRICT st, int request, ...) {
oac_int32 value = va_arg(ap, oac_int32);
if (value <= 500 && value != OAC_BITRATE_MAX)
goto bad_arg;
value = IMIN(value, 750000*st->channels);
value = IMIN(value, CELT_MAX_BITRATE_PER_CHANNEL*st->channels);
st->bitrate = value;
}
break;
Expand Down
8 changes: 6 additions & 2 deletions celt/oac_custom_demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@
#include <math.h>
#include <string.h>

#define MAX_PACKET 1275
/* Largest payload the frame length signalling can represent. The buffer is
malloc'd rather than on the stack because of its size. */
#define MAX_PACKET OAC_SIZE_MAX

static OAC_INLINE void _oac_ctl_failed(const char *file, int line) {
fprintf(stderr, "\n ***************************************************\n");
Expand Down Expand Up @@ -145,7 +147,7 @@ int main(int argc, char *argv[]) {
oac_int32 frame_size, channels, rate;
int format = FORMAT_S16_LE;
int bytes_per_packet = 0;
unsigned char data[MAX_PACKET];
unsigned char *data = NULL;
int complexity = -1;
float percent_loss = -1;
int i;
Expand Down Expand Up @@ -292,6 +294,7 @@ int main(int argc, char *argv[]) {
in = (oac_int32*)malloc(frame_size*channels*sizeof(oac_int32));
out = (oac_int32*)malloc(frame_size*channels*sizeof(oac_int32));
fbytes = (unsigned char*)malloc(frame_size*channels*4);
data = (unsigned char*)malloc(MAX_PACKET);

while (!feof(fin)) {
int lost = 0;
Expand Down Expand Up @@ -488,5 +491,6 @@ int main(int argc, char *argv[]) {
if (in) free(in);
if (out) free(out);
if (fbytes) free(fbytes);
if (data) free(data);
return ret;
}
3 changes: 2 additions & 1 deletion doc/trivial_example.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@
#define BITRATE 64000

#define MAX_FRAME_SIZE 6*960
#define MAX_PACKET_SIZE (3*1276)
/* Enough for a 20 ms stereo frame at any bitrate the encoder will produce. */
#define MAX_PACKET_SIZE 4000

int main(int argc, char **argv) {
char *inFile;
Expand Down
29 changes: 16 additions & 13 deletions include/oac.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ extern "C" {
* stereo music. Its main features are:

* @li Sampling rates from 8 to 48 kHz
* @li Bit-rates from 6 kb/s to 510 kb/s
* @li Bit-rates from 6 kb/s to 750 kb/s per channel (and higher for lossless)
* @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR)
* @li Audio bandwidth from narrowband to full-band
* @li Support for speech and music
Expand Down Expand Up @@ -752,8 +752,8 @@ OAC_EXPORT int oac_decoder_dred_decode_float(OacDecoder *st, const OacDRED *dred
* @param [in] data <tt>char*</tt>: Oac packet to be parsed
* @param [in] len <tt>oac_int32</tt>: size of data
* @param [out] out_toc <tt>char*</tt>: TOC pointer
* @param [out] frames <tt>char*[48]</tt> encapsulated frames
* @param [out] size <tt>oac_int16[48]</tt> sizes of the encapsulated frames
* @param [out] frames <tt>char*[OAC_MAX_FRAMES_PER_PACKET]</tt> encapsulated frames
* @param [out] size <tt>oac_int32[OAC_MAX_FRAMES_PER_PACKET]</tt> sizes of the encapsulated frames
* @param [out] payload_offset <tt>int*</tt>: returns the position of the payload within the packet (in bytes)
* @param [in] format <tt>int</tt>: Audio format (OAC_FORMAT_STANDARD or OAC_FORMAT_AMBISONICS)
* @returns number of frames
Expand All @@ -762,8 +762,8 @@ OAC_EXPORT int oac_packet_parse(
const unsigned char *data,
oac_int32 len,
unsigned char *out_toc,
const unsigned char *frames[48],
oac_int16 size[48],
const unsigned char *frames[OAC_MAX_FRAMES_PER_PACKET],
oac_int32 size[OAC_MAX_FRAMES_PER_PACKET],
int *payload_offset,
int format) OAC_ARG_NONNULL(1) OAC_ARG_NONNULL(5);

Expand Down Expand Up @@ -891,7 +891,7 @@ OAC_EXPORT void oac_pcm_soft_clip(float *pcm, int frame_size, int channels, floa
* int len;
* while (get_next_packet(&data, &len))
* {
* unsigned char out[1276];
* unsigned char out[OAC_SIZE_MAX + 1];
* oac_int32 out_len;
* int nb_frames;
* int err;
Expand Down Expand Up @@ -927,7 +927,10 @@ OAC_EXPORT void oac_pcm_soft_clip(float *pcm, int frame_size, int channels, floa
* unsigned char *data[(TARGET_DURATION_MS*2/5)+1];
* oac_int32 len[(TARGET_DURATION_MS*2/5)+1];
* int nb_packets;
* unsigned char out[1277*(TARGET_DURATION_MS*2/2)];
* // Worst case output size: every frame may need a three-byte length field,
* // plus the TOC and frame count bytes. MAX_FRAME_BYTES is the largest frame
* // the producer emits; frames may be up to OAC_SIZE_MAX bytes long.
* unsigned char out[(MAX_FRAME_BYTES+3)*(TARGET_DURATION_MS*2/5)+2];
* oac_int32 out_len;
* int prev_toc;
* nb_packets = 0;
Expand Down Expand Up @@ -1101,10 +1104,10 @@ OAC_EXPORT int oac_repacketizer_cat(OacRepacketizer *rp, const unsigned char *da
* @param maxlen <tt>oac_int32</tt>: The maximum number of bytes to store in
* the output buffer. In order to guarantee
* success, this should be at least
* <code>1276</code> for a single frame,
* or for multiple frames,
* <code>1277*(end-begin)</code>.
* However, <code>1*(end-begin)</code> plus
* <code>OAC_SIZE_MAX+1</code> for a single
* frame, or for multiple frames,
* <code>(OAC_SIZE_MAX+4)*(end-begin)</code>.
* However, <code>3*(end-begin)</code> plus
* the size of all packet data submitted to
* the repacketizer since the last call to
* oac_repacketizer_init() or
Expand Down Expand Up @@ -1149,9 +1152,9 @@ OAC_EXPORT OAC_WARN_UNUSED_RESULT int oac_repacketizer_get_nb_frames(OacRepacket
* @param maxlen <tt>oac_int32</tt>: The maximum number of bytes to store in
* the output buffer. In order to guarantee
* success, this should be at least
* <code>1277*oac_repacketizer_get_nb_frames(rp)</code>.
* <code>(OAC_SIZE_MAX+4)*oac_repacketizer_get_nb_frames(rp)</code>.
* However,
* <code>1*oac_repacketizer_get_nb_frames(rp)</code>
* <code>3*oac_repacketizer_get_nb_frames(rp)</code>
* plus the size of all packet data
* submitted to the repacketizer since the
* last call to oac_repacketizer_init() or
Expand Down
19 changes: 18 additions & 1 deletion include/oac_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,23 @@ extern "C" {
#define OAC_FORMAT_STANDARD 0
/** Ambisonics format supporting orders 0 to OAC_MAX_AMBISONICS_ORDER @hideinitializer */
#define OAC_FORMAT_AMBISONICS 1

/** Maximum number of frames that can be packed in a single OAC packet
* (48 x 2.5 ms = 120 ms). @hideinitializer */
#define OAC_MAX_FRAMES_PER_PACKET 48

/** Largest frame size (in bytes) that the frame length signalling can represent.
*
* Frame lengths are coded on 1 to 3 bytes:
* - @c p[0] in [0,191]: 1 byte, size = @c p[0] (0 - 191)
* - @c p[0] in [192,223]: 2 bytes, size = @c 32*p[1]+p[0] (192 - 8383)
* - @c p[0] in [224,255]: 3 bytes, size = @c 32*(256*p[2]+p[1])+p[0]+8160 (8384 - 2105535)
*
* The mapping is bijective: every size has exactly one representation, so there
* are no non-canonical encodings for a parser to reject.
* @hideinitializer */
#define OAC_SIZE_MAX 2105535

#define OAC_SIGNAL_VOICE 3001 /**< Signal being encoded is voice */
#define OAC_SIGNAL_MUSIC 3002 /**< Signal being encoded is music */
#define OAC_BANDWIDTH_NARROWBAND 1101 /**< 4 kHz bandpass @hideinitializer*/
Expand Down Expand Up @@ -324,7 +341,7 @@ extern "C" {
#define OAC_GET_COMPLEXITY(x) OAC_GET_COMPLEXITY_REQUEST, oac_check_int_ptr(x)

/** Configures the bitrate in the encoder.
* Rates from 500 to 512000 bits per second are meaningful, as well as the
* Rates from 500 to 750000 bits per second per channel for lossy coding (and higher for lossless) are meaningful, as well as the
* special values #OAC_AUTO and #OAC_BITRATE_MAX.
* The value #OAC_BITRATE_MAX can be used to cause the codec to use as much
* rate as it can, which is useful for controlling the rate by adjusting the
Expand Down
4 changes: 4 additions & 0 deletions silk/define.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@
/* Limits on bitrate */
#define MIN_TARGET_RATE_BPS 5000
#define MAX_TARGET_RATE_BPS 80000
/* Largest payload SILK will ever be asked to produce for one frame. SILK cannot
make use of a higher rate, so its bit budget is clamped to this even when the
packet itself may be much larger. */
#define SILK_MAX_BYTES 1275

/* LBRR thresholds */
#define LBRR_NB_MIN_RATE_BPS 12000
Expand Down
6 changes: 3 additions & 3 deletions silk/fixed/encode_frame_FIX.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ oac_int oaci_silk_encode_frame_FIX(
seed_copy = psEnc->sCmn.indices.Seed;
ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
ALLOC( ec_buf_copy, 1275, oac_uint8 );
ALLOC( ec_buf_copy, SILK_MAX_BYTES, oac_uint8 );
for (iter = 0; ; iter++) {
if (gainsID == gainsID_lower) {
nBits = nBits_lower;
Expand Down Expand Up @@ -306,7 +306,7 @@ oac_int oaci_silk_encode_frame_FIX(
if (found_lower && (gainsID == gainsID_lower || nBits > maxBits)) {
/* Restore output state from earlier iteration that did meet the bitrate budget */
silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof(ec_enc));
celt_assert( sRangeEnc_copy2.offs <= 1275 );
celt_assert( sRangeEnc_copy2.offs <= SILK_MAX_BYTES );
silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy[1], sizeof(silk_nsq_state));
psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
Expand Down Expand Up @@ -334,7 +334,7 @@ oac_int oaci_silk_encode_frame_FIX(
gainsID_lower = gainsID;
/* Copy part of the output state */
silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof(ec_enc));
celt_assert( psRangeEnc->offs <= 1275 );
celt_assert( psRangeEnc->offs <= SILK_MAX_BYTES );
silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
silk_memcpy( &sNSQ_copy[1], &psEnc->sCmn.sNSQ, sizeof(silk_nsq_state));
LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
Expand Down
6 changes: 3 additions & 3 deletions silk/float/encode_frame_FLP.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ oac_int oaci_silk_encode_frame_FLP(
seed_copy = psEnc->sCmn.indices.Seed;
ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
ALLOC( ec_buf_copy, 1275, oac_uint8 );
ALLOC( ec_buf_copy, SILK_MAX_BYTES, oac_uint8 );
for (iter = 0; ; iter++) {
if (gainsID == gainsID_lower) {
nBits = nBits_lower;
Expand Down Expand Up @@ -291,7 +291,7 @@ oac_int oaci_silk_encode_frame_FLP(
if (found_lower && (gainsID == gainsID_lower || nBits > maxBits)) {
/* Restore output state from earlier iteration that did meet the bitrate budget */
silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof(ec_enc));
celt_assert( sRangeEnc_copy2.offs <= 1275 );
celt_assert( sRangeEnc_copy2.offs <= SILK_MAX_BYTES );
silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy[1], sizeof(silk_nsq_state));
psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
Expand Down Expand Up @@ -321,7 +321,7 @@ oac_int oaci_silk_encode_frame_FLP(
gainsID_lower = gainsID;
/* Copy part of the output state */
silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof(ec_enc));
celt_assert( psRangeEnc->offs <= 1275 );
celt_assert( psRangeEnc->offs <= SILK_MAX_BYTES );
silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
silk_memcpy( &sNSQ_copy[1], &psEnc->sCmn.sNSQ, sizeof(silk_nsq_state));
LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
Expand Down
8 changes: 4 additions & 4 deletions src/extensions.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,17 +493,17 @@ static int oaci_write_extension(unsigned char *data, oac_int32 len, oac_int32 po
oac_int32 oac_packet_extensions_generate(unsigned char *data, oac_int32 len,
const oac_extension_data *extensions, oac_int32 nb_extensions,
int nb_frames, int pad) {
oac_int32 frame_min_idx[48];
oac_int32 frame_max_idx[48];
oac_int32 frame_repeat_idx[48];
oac_int32 frame_min_idx[OAC_MAX_FRAMES_PER_PACKET];
oac_int32 frame_max_idx[OAC_MAX_FRAMES_PER_PACKET];
oac_int32 frame_repeat_idx[OAC_MAX_FRAMES_PER_PACKET];
oac_int32 i;
int f;
int curr_frame = 0;
oac_int32 pos = 0;
oac_int32 written = 0;

celt_assert(len >= 0);
if (nb_frames > 48) return OAC_BAD_ARG;
if (nb_frames > OAC_MAX_FRAMES_PER_PACKET) return OAC_BAD_ARG;

/* Do a little work up-front to make this O(nb_extensions) instead of
O(nb_extensions*nb_frames) so long as the extensions are in frame
Expand Down
Loading
Loading