Index: src/opus_multistream_encoder.c |
diff --git a/src/opus_multistream_encoder.c b/src/opus_multistream_encoder.c |
index 49e27913ee0cd64887df8e3a04eb24885a3806dc..6e87337d93f97d0c55d7ecc1e624f04261c2d5be 100644 |
--- a/src/opus_multistream_encoder.c |
+++ b/src/opus_multistream_encoder.c |
@@ -267,7 +267,7 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b |
freq[i] = 0; |
} |
- compute_band_energies(celt_mode, freq, bandE, 21, 1, 1<<LM); |
+ compute_band_energies(celt_mode, freq, bandE, 21, 1, LM); |
amp2Log2(celt_mode, 21, 21, bandE, bandLogE+21*c, 1); |
/* Apply spreading function with -6 dB/band going up and -12 dB/band going down. */ |
for (i=1;i<21;i++) |
@@ -408,7 +408,7 @@ static int opus_multistream_encoder_init_impl( |
char *ptr; |
if ((channels>255) || (channels<1) || (coupled_streams>streams) || |
- (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0)) |
+ (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) |
return OPUS_BAD_ARG; |
st->layout.nb_channels = channels; |
@@ -530,7 +530,7 @@ OpusMSEncoder *opus_multistream_encoder_create( |
int ret; |
OpusMSEncoder *st; |
if ((channels>255) || (channels<1) || (coupled_streams>streams) || |
- (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0)) |
+ (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) |
{ |
if (error) |
*error = OPUS_BAD_ARG; |
@@ -566,6 +566,7 @@ OpusMSEncoder *opus_multistream_surround_encoder_create( |
) |
{ |
int ret; |
+ opus_int32 size; |
OpusMSEncoder *st; |
if ((channels>255) || (channels<1)) |
{ |
@@ -573,7 +574,14 @@ OpusMSEncoder *opus_multistream_surround_encoder_create( |
*error = OPUS_BAD_ARG; |
return NULL; |
} |
- st = (OpusMSEncoder *)opus_alloc(opus_multistream_surround_encoder_get_size(channels, mapping_family)); |
+ size = opus_multistream_surround_encoder_get_size(channels, mapping_family); |
+ if (!size) |
+ { |
+ if (error) |
+ *error = OPUS_UNIMPLEMENTED; |
+ return NULL; |
+ } |
+ st = (OpusMSEncoder *)opus_alloc(size); |
if (st==NULL) |
{ |
if (error) |
@@ -591,7 +599,7 @@ OpusMSEncoder *opus_multistream_surround_encoder_create( |
return st; |
} |
-static void surround_rate_allocation( |
+static opus_int32 surround_rate_allocation( |
OpusMSEncoder *st, |
opus_int32 *rate, |
int frame_size |
@@ -605,6 +613,7 @@ static void surround_rate_allocation( |
int lfe_offset; |
int coupled_ratio; /* Q8 */ |
int lfe_ratio; /* Q8 */ |
+ opus_int32 rate_sum=0; |
ptr = (char*)st + align(sizeof(OpusMSEncoder)); |
opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); |
@@ -660,7 +669,10 @@ static void surround_rate_allocation( |
rate[i] = stream_offset+channel_rate; |
else |
rate[i] = lfe_offset+(channel_rate*lfe_ratio>>8); |
+ rate[i] = IMAX(rate[i], 500); |
+ rate_sum += rate[i]; |
} |
+ return rate_sum; |
} |
/* Max size in case the encoder decides to return three frames */ |
@@ -674,7 +686,8 @@ static int opus_multistream_encode_native |
unsigned char *data, |
opus_int32 max_data_bytes, |
int lsb_depth, |
- downmix_func downmix |
+ downmix_func downmix, |
+ int float_api |
) |
{ |
opus_int32 Fs; |
@@ -694,6 +707,8 @@ static int opus_multistream_encode_native |
opus_val32 *mem = NULL; |
opus_val32 *preemph_mem=NULL; |
int frame_size; |
+ opus_int32 rate_sum; |
+ opus_int32 smallest_packet; |
ALLOC_STACK; |
if (st->surround) |
@@ -737,6 +752,14 @@ static int opus_multistream_encode_native |
RESTORE_STACK; |
return OPUS_BAD_ARG; |
} |
+ |
+ /* Smallest packet the encoder can produce. */ |
+ smallest_packet = st->layout.nb_streams*2-1; |
+ if (max_data_bytes < smallest_packet) |
+ { |
+ RESTORE_STACK; |
+ return OPUS_BUFFER_TOO_SMALL; |
+ } |
ALLOC(buf, 2*frame_size, opus_val16); |
coupled_size = opus_encoder_get_size(2); |
mono_size = opus_encoder_get_size(1); |
@@ -747,18 +770,20 @@ static int opus_multistream_encode_native |
surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in); |
} |
- if (max_data_bytes < 4*st->layout.nb_streams-1) |
- { |
- RESTORE_STACK; |
- return OPUS_BUFFER_TOO_SMALL; |
- } |
- |
/* Compute bitrate allocation between streams (this could be a lot better) */ |
- surround_rate_allocation(st, bitrates, frame_size); |
+ rate_sum = surround_rate_allocation(st, bitrates, frame_size); |
if (!vbr) |
- max_data_bytes = IMIN(max_data_bytes, 3*st->bitrate_bps/(3*8*Fs/frame_size)); |
- |
+ { |
+ if (st->bitrate_bps == OPUS_AUTO) |
+ { |
+ max_data_bytes = IMIN(max_data_bytes, 3*rate_sum/(3*8*Fs/frame_size)); |
+ } else if (st->bitrate_bps != OPUS_BITRATE_MAX) |
+ { |
+ max_data_bytes = IMIN(max_data_bytes, IMAX(smallest_packet, |
+ 3*st->bitrate_bps/(3*8*Fs/frame_size))); |
+ } |
+ } |
ptr = (char*)st + align(sizeof(OpusMSEncoder)); |
for (s=0;s<st->layout.nb_streams;s++) |
{ |
@@ -843,13 +868,15 @@ static int opus_multistream_encode_native |
opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE)); |
/* number of bytes left (+Toc) */ |
curr_max = max_data_bytes - tot_size; |
- /* Reserve three bytes for the last stream and four for the others */ |
- curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1); |
+ /* Reserve one byte for the last stream and two for the others */ |
+ curr_max -= IMAX(0,2*(st->layout.nb_streams-s-1)-1); |
curr_max = IMIN(curr_max,MS_FRAME_TMP); |
+ /* Repacketizer will add one or two bytes for self-delimited frames */ |
+ if (s != st->layout.nb_streams-1) curr_max -= curr_max>253 ? 2 : 1; |
if (!vbr && s == st->layout.nb_streams-1) |
opus_encoder_ctl(enc, OPUS_SET_BITRATE(curr_max*(8*Fs/frame_size))); |
len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth, |
- pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix); |
+ pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix, float_api); |
if (len<0) |
{ |
RESTORE_STACK; |
@@ -922,7 +949,7 @@ int opus_multistream_encode( |
) |
{ |
return opus_multistream_encode_native(st, opus_copy_channel_in_short, |
- pcm, frame_size, data, max_data_bytes, 16, downmix_int); |
+ pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0); |
} |
#ifndef DISABLE_FLOAT_API |
@@ -935,7 +962,7 @@ int opus_multistream_encode_float( |
) |
{ |
return opus_multistream_encode_native(st, opus_copy_channel_in_float, |
- pcm, frame_size, data, max_data_bytes, 16, downmix_float); |
+ pcm, frame_size, data, max_data_bytes, 16, downmix_float, 1); |
} |
#endif |
@@ -951,7 +978,7 @@ int opus_multistream_encode_float |
) |
{ |
return opus_multistream_encode_native(st, opus_copy_channel_in_float, |
- pcm, frame_size, data, max_data_bytes, 24, downmix_float); |
+ pcm, frame_size, data, max_data_bytes, 24, downmix_float, 1); |
} |
int opus_multistream_encode( |
@@ -963,7 +990,7 @@ int opus_multistream_encode( |
) |
{ |
return opus_multistream_encode_native(st, opus_copy_channel_in_short, |
- pcm, frame_size, data, max_data_bytes, 16, downmix_int); |
+ pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0); |
} |
#endif |