Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.xiph.org/xiph/opus.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Marc Valin <jmvalin@jmvalin.ca>2024-01-22 11:29:37 +0300
committerJean-Marc Valin <jmvalin@jmvalin.ca>2024-01-22 21:58:49 +0300
commita3ba0108d5a9dc122b1c623663b3480b192c7fbd (patch)
treeab0882408f6bfb9ea645fde857b295934a05c98f
parent3499d0aac76d20ba14918cafb8020278154bf2e6 (diff)
Initial DRED tuningexp_dred_tuning1
Adjust q0, qD and duration based on bitrate and loss.
-rw-r--r--silk/dred_config.h2
-rw-r--r--silk/dred_encoder.c6
-rw-r--r--silk/dred_encoder.h2
-rw-r--r--src/opus_encoder.c59
4 files changed, 54 insertions, 15 deletions
diff --git a/silk/dred_config.h b/silk/dred_config.h
index 86da3b00..a729e696 100644
--- a/silk/dred_config.h
+++ b/silk/dred_config.h
@@ -36,7 +36,7 @@
#define DRED_EXPERIMENTAL_BYTES 2
-#define DRED_MIN_BYTES 16
+#define DRED_MIN_BYTES 8
/* these are inpart duplicates to the values defined in dred_rdovae_constants.h */
#define DRED_SILK_ENCODER_DELAY (79+12-80)
diff --git a/silk/dred_encoder.c b/silk/dred_encoder.c
index 0e1bb33f..bd0fe3fb 100644
--- a/silk/dred_encoder.c
+++ b/silk/dred_encoder.c
@@ -249,21 +249,17 @@ static void dred_encode_latents(ec_enc *enc, const float *x, const opus_uint8 *s
}
}
-int dred_encode_silk_frame(const DREDEnc *enc, unsigned char *buf, int max_chunks, int max_bytes, int arch) {
+int dred_encode_silk_frame(const DREDEnc *enc, unsigned char *buf, int max_chunks, int max_bytes, int q0, int dQ, int arch) {
ec_enc ec_encoder;
int q_level;
int i;
int offset;
int ec_buffer_fill;
- int q0;
- int dQ;
int state_qoffset;
/* entropy coding of state and latents */
ec_enc_init(&ec_encoder, buf, max_bytes);
- q0 = DRED_ENC_Q0;
- dQ = 3;
ec_enc_uint(&ec_encoder, enc->dred_offset, 32);
ec_enc_uint(&ec_encoder, q0, 16);
ec_enc_uint(&ec_encoder, dQ, 8);
diff --git a/silk/dred_encoder.h b/silk/dred_encoder.h
index 795bee4f..469b8085 100644
--- a/silk/dred_encoder.h
+++ b/silk/dred_encoder.h
@@ -66,6 +66,6 @@ void dred_deinit_encoder(DREDEnc *enc);
void dred_compute_latents(DREDEnc *enc, const float *pcm, int frame_size, int extra_delay, int arch);
-int dred_encode_silk_frame(const DREDEnc *enc, unsigned char *buf, int max_chunks, int max_bytes, int arch);
+int dred_encode_silk_frame(const DREDEnc *enc, unsigned char *buf, int max_chunks, int max_bytes, int q0, int dQ, int arch);
#endif
diff --git a/src/opus_encoder.c b/src/opus_encoder.c
index 21dfe4ff..024a9efd 100644
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -45,6 +45,7 @@
#include "analysis.h"
#include "mathops.h"
#include "tuning_parameters.h"
+#include "silk/dred_coding.h"
#ifdef FIXED_POINT
#include "fixed/structs_FIX.h"
#else
@@ -124,6 +125,9 @@ struct OpusEncoder {
#endif
#ifdef ENABLE_DRED
int dred_duration;
+ int dred_q0;
+ int dred_dQ;
+ int dred_target_chunks;
#endif
int nonfinal_frame; /* current frame is not the final in a packet */
opus_uint32 rangeFinal;
@@ -560,22 +564,60 @@ OpusEncoder *opus_encoder_create(opus_int32 Fs, int channels, int application, i
}
#ifdef ENABLE_DRED
+
+static const float dred_bits_table[16] = {73.2f, 68.1f, 62.5f, 57.0f, 51.5f, 45.7f, 39.9f, 32.4f, 26.4f, 20.4f, 16.3f, 13.f, 9.3f, 8.2f, 7.2f, 6.4f};
+static int estimate_dred_bitrate(int q0, int dQ, int duration, opus_int32 target_bits, int *target_chunks) {
+ int dred_chunks;
+ int i;
+ float bits;
+ /* Signaling DRED costs 3 bytes. */
+ bits = 8*(3+DRED_EXPERIMENTAL_BYTES);
+ /* Approximation for the size of the IS. */
+ bits += 50.f+dred_bits_table[q0];
+ dred_chunks = IMIN((duration+5)/4, DRED_NUM_REDUNDANCY_FRAMES/2);
+ if (target_chunks != NULL) *target_chunks = 0;
+ for (i=0;i<dred_chunks;i++) {
+ int q = compute_quantizer(q0, dQ, i);
+ bits += dred_bits_table[q];
+ if (target_chunks != NULL && bits < target_bits) *target_chunks = i+1;
+ }
+ return (int)floor(.5f+bits);
+}
+
static opus_int32 compute_dred_bitrate(OpusEncoder *st, opus_int32 bitrate_bps, int frame_size)
{
float dred_frac;
int bitrate_offset;
opus_int32 dred_bitrate;
opus_int32 target_dred_bitrate;
- opus_int32 max_dred_bitrate;
- if (st->dred_duration > 0) max_dred_bitrate = (120 + 6*st->dred_duration)*st->Fs/frame_size;
- else max_dred_bitrate = 0;
- dred_frac = MIN16(.75f, 3.f*st->silk_mode.packetLossPercentage/100.f);
- bitrate_offset = st->silk_mode.useInBandFEC ? 18000 : 12000;
+ int target_chunks;
+ opus_int32 max_dred_bits;
+ int q0, dQ;
+ if (st->silk_mode.useInBandFEC) {
+ dred_frac = MIN16(.7f, 3.f*st->silk_mode.packetLossPercentage/100.f);
+ bitrate_offset = 20000;
+ } else {
+ dred_frac = MIN16(.8f, 4.f*st->silk_mode.packetLossPercentage/100.f);
+ bitrate_offset = 12000;
+ }
+ /* Approximate fit based on a few experiments. Could probably be improved. */
+ q0 = IMIN(15, IMAX(4, 51 - 3*EC_ILOG(IMAX(1, bitrate_bps-bitrate_offset))));
+ dQ = bitrate_bps-bitrate_offset > 36000 ? 3 : 5;
target_dred_bitrate = IMAX(0, (int)(dred_frac*(bitrate_bps-bitrate_offset)));
- dred_bitrate = IMIN(target_dred_bitrate, max_dred_bitrate);
+ if (st->dred_duration > 0) {
+ opus_int32 target_bits = target_dred_bitrate*frame_size/st->Fs;
+ max_dred_bits = estimate_dred_bitrate(q0, dQ, st->dred_duration, target_bits, &target_chunks);
+ } else {
+ max_dred_bits = 0;
+ target_chunks=0;
+ }
+ dred_bitrate = IMIN(target_dred_bitrate, max_dred_bits*st->Fs/frame_size);
/* If we can't afford enough bits, don't bother with DRED at all. */
- if (dred_bitrate <= (DRED_MIN_BYTES+DRED_EXPERIMENTAL_BYTES)*8*st->Fs/frame_size)
+ if (target_chunks < 2)
dred_bitrate = 0;
+ st->dred_q0 = q0;
+ st->dred_dQ = dQ;
+ st->dred_target_chunks = target_chunks;
return dred_bitrate;
}
#endif
@@ -2289,6 +2331,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_
int dred_chunks;
int dred_bytes_left;
dred_chunks = IMIN((st->dred_duration+5)/4, DRED_NUM_REDUNDANCY_FRAMES/2);
+ if (st->use_vbr) dred_chunks = IMIN(dred_chunks, st->dred_target_chunks);
/* Remaining space for DRED, accounting for cost the 3 extra bytes for code 3, padding length, and extension number. */
dred_bytes_left = IMIN(DRED_MAX_DATA_SIZE, max_data_bytes-ret-3);
/* Check whether we actually have something to encode. */
@@ -2300,7 +2343,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_
buf[0] = 'D';
buf[1] = DRED_EXPERIMENTAL_VERSION;
#endif
- dred_bytes = dred_encode_silk_frame(&st->dred_encoder, buf+DRED_EXPERIMENTAL_BYTES, dred_chunks, dred_bytes_left-DRED_EXPERIMENTAL_BYTES, st->arch);
+ dred_bytes = dred_encode_silk_frame(&st->dred_encoder, buf+DRED_EXPERIMENTAL_BYTES, dred_chunks, dred_bytes_left-DRED_EXPERIMENTAL_BYTES, st->dred_q0, st->dred_dQ, st->arch);
if (dred_bytes > 0) {
dred_bytes += DRED_EXPERIMENTAL_BYTES;
celt_assert(dred_bytes <= dred_bytes_left);