ref: 073bec9160f6c39fef22eb0442ab6999ce822ffb
parent: fe86db66f47ba8d5d1b4f65f604e49852bbac90c
author: Jean-Marc Valin <jmvalin@amazon.com>
date: Fri Dec 15 22:52:20 EST 2023
First shot at multi-frame CBR with DRED
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -1065,6 +1065,7 @@
opus_int32 max_rate; /* Max bitrate we're allowed to use */
int curr_bandwidth;
opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */
+ opus_int32 cbr_bytes=-1;
opus_val16 stereo_width;
const CELTMode *celt_mode;
#ifndef DISABLE_FLOAT_API
@@ -1178,14 +1179,13 @@
frame_rate = st->Fs/frame_size;
if (!st->use_vbr)
{
- int cbrBytes;
/* Multiply by 12 to make sure the division is exact. */
int frame_rate12 = 12*st->Fs/frame_size;
/* We need to make sure that "int" values always fit in 16 bits. */
- cbrBytes = IMIN( (12*st->bitrate_bps/8 + frame_rate12/2)/frame_rate12, max_data_bytes);
- st->bitrate_bps = cbrBytes*(opus_int32)frame_rate12*8/12;
+ cbr_bytes = IMIN( (12*st->bitrate_bps/8 + frame_rate12/2)/frame_rate12, max_data_bytes);
+ st->bitrate_bps = cbr_bytes*(opus_int32)frame_rate12*8/12;
/* Make sure we provide at least one byte to avoid failing. */
- max_data_bytes = IMAX(1, cbrBytes);
+ max_data_bytes = IMAX(1, cbr_bytes);
}
#ifdef ENABLE_DRED
/* Allocate some of the bits to DRED if needed. */
@@ -1548,9 +1548,10 @@
VARDECL(unsigned char, tmp_data);
VARDECL(OpusRepacketizer, rp);
int max_header_bytes;
- opus_int32 bytes_per_frame;
- opus_int32 cbr_bytes;
opus_int32 repacketize_len;
+ opus_int32 max_len_sum;
+ opus_int32 tot_size=0;
+ unsigned char *curr_data;
int tmp_len;
ALLOC_STACK;
@@ -1586,12 +1587,13 @@
if (st->use_vbr || st->user_bitrate_bps==OPUS_BITRATE_MAX)
repacketize_len = out_data_bytes;
else {
- cbr_bytes = 3*st->bitrate_bps/(3*8*st->Fs/(enc_frame_size*nb_frames));
+ celt_assert(cbr_bytes>=0);
repacketize_len = IMIN(cbr_bytes, out_data_bytes);
}
- bytes_per_frame = IMIN(1276, 1+(repacketize_len-max_header_bytes)/nb_frames);
+ max_len_sum = nb_frames + repacketize_len - max_header_bytes;
- ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char);
+ ALLOC(tmp_data, max_len_sum, unsigned char);
+ curr_data = tmp_data;
ALLOC(rp, 1, OpusRepacketizer);
opus_repacketizer_init(rp);
@@ -1607,6 +1609,7 @@
int first_frame = i == 0;
int frame_to_celt;
int frame_redundancy;
+ opus_int32 curr_max;
st->silk_mode.toMono = 0;
st->nonfinal_frame = i<(nb_frames-1);
@@ -1614,6 +1617,11 @@
frame_to_celt = to_celt && i==nb_frames-1;
frame_redundancy = redundancy && (frame_to_celt || (!to_celt && i==0));
+ curr_max = 3*st->bitrate_bps/(3*8*st->Fs/enc_frame_size);
+#ifdef ENABLE_DRED
+ if (first_frame) curr_max += 3*dred_bitrate_bps/(3*8*st->Fs/frame_size);
+#endif
+ curr_max = IMIN(max_len_sum-tot_size, curr_max);
#ifndef DISABLE_FLOAT_API
if (analysis_read_pos_bak != -1) {
is_silence = is_digital_silence(pcm, frame_size, st->channels, lsb_depth);
@@ -1622,7 +1630,7 @@
}
#endif
- tmp_len = opus_encode_native_process(st, pcm+i*(st->channels*enc_frame_size), enc_frame_size, tmp_data+i*bytes_per_frame, float_api, first_frame,
+ tmp_len = opus_encode_native_process(st, pcm+i*(st->channels*enc_frame_size), enc_frame_size, curr_data, float_api, first_frame,
#ifdef ENABLE_DRED
dred_bitrate_bps,
#endif
@@ -1630,23 +1638,23 @@
&analysis_info,
is_silence,
#endif
- frame_redundancy, celt_to_silk, prefill, bytes_per_frame,
+ frame_redundancy, celt_to_silk, prefill, curr_max,
equiv_rate, frame_to_celt
);
-
if (tmp_len<0)
{
RESTORE_STACK;
return OPUS_INTERNAL_ERROR;
}
+ ret = opus_repacketizer_cat(rp, curr_data, tmp_len);
- ret = opus_repacketizer_cat(rp, tmp_data+i*bytes_per_frame, tmp_len);
-
if (ret<0)
{
RESTORE_STACK;
return OPUS_INTERNAL_ERROR;
}
+ tot_size += tmp_len;
+ curr_data += tmp_len;
}
ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr, NULL, 0);
if (ret<0)
--
⑨