From 086c044dc34dfc0f74fbe41f4ecb402b2cd34884 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:13:33 +0200 Subject: Merging upstream version 125.0.1. Signed-off-by: Daniel Baumann --- media/libopus/src/analysis.c | 6 +- media/libopus/src/extensions.c | 315 +++++++++++++ media/libopus/src/mapping_matrix.c | 561 +++++++++++++++++++++++ media/libopus/src/mapping_matrix.h | 12 + media/libopus/src/mlp.c | 42 +- media/libopus/src/mlp.h | 20 +- media/libopus/src/mlp_data.c | 6 +- media/libopus/src/opus.c | 10 +- media/libopus/src/opus_decoder.c | 495 +++++++++++++++++++- media/libopus/src/opus_encoder.c | 651 ++++++++++++++++++++------- media/libopus/src/opus_multistream_decoder.c | 4 +- media/libopus/src/opus_multistream_encoder.c | 2 +- media/libopus/src/opus_private.h | 28 +- media/libopus/src/opus_projection_encoder.c | 42 ++ media/libopus/src/repacketizer.c | 144 +++++- media/libopus/src/tansig_table.h | 45 -- 16 files changed, 2087 insertions(+), 296 deletions(-) create mode 100644 media/libopus/src/extensions.c delete mode 100644 media/libopus/src/tansig_table.h (limited to 'media/libopus/src') diff --git a/media/libopus/src/analysis.c b/media/libopus/src/analysis.c index 058328f0fd..1f58013812 100644 --- a/media/libopus/src/analysis.c +++ b/media/libopus/src/analysis.c @@ -929,9 +929,9 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt features[23] = info->tonality_slope + 0.069216f; features[24] = tonal->lowECount - 0.067930f; - compute_dense(&layer0, layer_out, features); - compute_gru(&layer1, tonal->rnn_state, layer_out); - compute_dense(&layer2, frame_probs, tonal->rnn_state); + analysis_compute_dense(&layer0, layer_out, features); + analysis_compute_gru(&layer1, tonal->rnn_state, layer_out); + analysis_compute_dense(&layer2, frame_probs, tonal->rnn_state); /* Probability of speech or music vs noise */ info->activity_probability = frame_probs[1]; diff --git a/media/libopus/src/extensions.c b/media/libopus/src/extensions.c new file mode 100644 index 0000000000..bb6c0b0268 --- /dev/null +++ b/media/libopus/src/extensions.c @@ -0,0 +1,315 @@ +/* Copyright (c) 2022 Amazon */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "opus_types.h" +#include "opus_defines.h" +#include "arch.h" +#include "os_support.h" +#include "opus_private.h" + + +/* Given an extension payload, advance data to the next extension and return the + length of the remaining extensions. */ +opus_int32 skip_extension(const unsigned char **data, opus_int32 len, opus_int32 *header_size) +{ + int id, L; + if (len==0) + return 0; + id = **data>>1; + L = **data&1; + if (id == 0 && L == 1) + { + *header_size = 1; + if (len < 1) + return -1; + (*data)++; + len--; + return len; + } else if (id > 0 && id < 32) + { + if (len < 1+L) + return -1; + *data += 1+L; + len -= 1+L; + *header_size = 1; + return len; + } else { + if (L==0) + { + *data += len; + *header_size = 1; + return 0; + } else { + opus_int32 bytes=0; + *header_size = 1; + do { + (*data)++; + len--; + if (len == 0) + return -1; + bytes += **data; + (*header_size)++; + } while (**data == 255); + (*data)++; + len--; + if (bytes <= len) + { + len -= bytes; + *data += bytes; + } else { + return -1; + } + return len; + } + } +} + +/* Count the number of extensions, excluding real padding and separators. */ +opus_int32 opus_packet_extensions_count(const unsigned char *data, opus_int32 len) +{ + opus_int32 curr_len; + opus_int32 count=0; + const unsigned char *curr_data = data; + + celt_assert(len >= 0); + celt_assert(data != NULL || len == 0); + + curr_len = len; + while (curr_len > 0) + { + int id; + opus_int32 header_size; + id = *curr_data>>1; + curr_len = skip_extension(&curr_data, curr_len, &header_size); + if (curr_len < 0) + return OPUS_INVALID_PACKET; + if (id > 1) + count++; + } + return count; +} + +/* Extract extensions from Opus padding (excluding real padding and separators) */ +opus_int32 opus_packet_extensions_parse(const unsigned char *data, opus_int32 len, opus_extension_data *extensions, opus_int32 *nb_extensions) +{ + const unsigned char *curr_data; + opus_int32 curr_len; + int curr_frame=0; + opus_int32 count=0; + + celt_assert(len >= 0); + celt_assert(data != NULL || len == 0); + celt_assert(nb_extensions != NULL); + celt_assert(extensions != NULL || *nb_extensions == 0); + + curr_data = data; + curr_len = len; + while (curr_len > 0) + { + int id; + opus_int32 header_size; + opus_extension_data curr_ext; + id = *curr_data>>1; + if (id > 1) + { + curr_ext.id = id; + curr_ext.frame = curr_frame; + curr_ext.data = curr_data; + } else if (id == 1) + { + int L = *curr_data&1; + if (L==0) + curr_frame++; + else { + if (curr_len >= 2) + curr_frame += curr_data[1]; + /* Else we're at the end and it doesn't matter. */ + } + if (curr_frame >= 48) + { + *nb_extensions = count; + return OPUS_INVALID_PACKET; + } + } + curr_len = skip_extension(&curr_data, curr_len, &header_size); + /* printf("curr_len = %d, header_size = %d\n", curr_len, header_size); */ + if (curr_len < 0) + { + *nb_extensions = count; + return OPUS_INVALID_PACKET; + } + celt_assert(curr_data - data == len - curr_len); + if (id > 1) + { + if (count == *nb_extensions) + { + return OPUS_BUFFER_TOO_SMALL; + } + curr_ext.len = curr_data - curr_ext.data - header_size; + curr_ext.data += header_size; + extensions[count++] = curr_ext; + } + } + celt_assert(curr_len == 0); + *nb_extensions = count; + return OPUS_OK; +} + +opus_int32 opus_packet_extensions_generate(unsigned char *data, opus_int32 len, const opus_extension_data *extensions, opus_int32 nb_extensions, int pad) +{ + int max_frame=0; + opus_int32 i; + int frame; + int curr_frame = 0; + opus_int32 pos = 0; + opus_int32 written = 0; + + celt_assert(len >= 0); + + for (i=0;i 127) + return OPUS_BAD_ARG; + } + if (max_frame >= 48) return OPUS_BAD_ARG; + for (frame=0;frame<=max_frame;frame++) + { + for (i=0;i 1) + return OPUS_BAD_ARG; + if (len-pos < extensions[i].len+1) + return OPUS_BUFFER_TOO_SMALL; + if (data) data[pos] = (extensions[i].id<<1) + extensions[i].len; + pos++; + if (extensions[i].len > 0) { + if (data) data[pos] = extensions[i].data[0]; + pos++; + } + } else { + int last; + opus_int32 length_bytes; + if (extensions[i].len < 0) + return OPUS_BAD_ARG; + last = (written == nb_extensions - 1); + length_bytes = 1 + extensions[i].len/255; + if (last) + length_bytes = 0; + if (len-pos < 1 + length_bytes + extensions[i].len) + return OPUS_BUFFER_TOO_SMALL; + if (data) data[pos] = (extensions[i].id<<1) + !last; + pos++; + if (!last) + { + opus_int32 j; + for (j=0;j +int main() +{ + opus_extension_data ext[] = {{2, 0, (const unsigned char *)"a", 1}, + {32, 10, (const unsigned char *)"DRED", 4}, + {33, 1, (const unsigned char *)"NOT DRED", 8}, + {3, 4, (const unsigned char *)NULL, 0} + }; + opus_extension_data ext2[10]; + int i, len; + int nb_ext = 10; + unsigned char packet[10000]; + len = opus_packet_extensions_generate(packet, 32, ext, 4, 1); + for (i=0;i-8)) - return -1; -#ifndef FIXED_POINT - /* Another check in case of -ffast-math */ - if (celt_isnan(x)) - return 0; -#endif - if (x<0) - { - x=-x; - sign=-1; - } - i = (int)floor(.5f+25*x); - x -= .04f*i; - y = tansig_table[i]; - dy = 1-y*y; - y = y + x*dy*(1 - y*x); - return sign*y; + const float N0 = 952.52801514f; + const float N1 = 96.39235687f; + const float N2 = 0.60863042f; + const float D0 = 952.72399902f; + const float D1 = 413.36801147f; + const float D2 = 11.88600922f; + float X2, num, den; + X2 = x*x; + num = fmadd(fmadd(N2, X2, N1), X2, N0); + den = fmadd(fmadd(D2, X2, D1), X2, D0); + num = num*x/den; + return MAX32(-1.f, MIN32(1.f, num)); } static OPUS_INLINE float sigmoid_approx(float x) @@ -79,7 +67,7 @@ static void gemm_accum(float *out, const opus_int8 *weights, int rows, int cols, } } -void compute_dense(const DenseLayer *layer, float *output, const float *input) +void analysis_compute_dense(const AnalysisDenseLayer *layer, float *output, const float *input) { int i; int N, M; @@ -101,7 +89,7 @@ void compute_dense(const DenseLayer *layer, float *output, const float *input) } } -void compute_gru(const GRULayer *gru, float *state, const float *input) +void analysis_compute_gru(const AnalysisGRULayer *gru, float *state, const float *input) { int i; int N, M; diff --git a/media/libopus/src/mlp.h b/media/libopus/src/mlp.h index d7670550fd..e6b1a8f76c 100644 --- a/media/libopus/src/mlp.h +++ b/media/libopus/src/mlp.h @@ -24,8 +24,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _MLP_H_ -#define _MLP_H_ +#ifndef MLP_H_ +#define MLP_H_ #include "opus_types.h" @@ -39,7 +39,7 @@ typedef struct { int nb_inputs; int nb_neurons; int sigmoid; -} DenseLayer; +} AnalysisDenseLayer; typedef struct { const opus_int8 *bias; @@ -47,14 +47,14 @@ typedef struct { const opus_int8 *recurrent_weights; int nb_inputs; int nb_neurons; -} GRULayer; +} AnalysisGRULayer; -extern const DenseLayer layer0; -extern const GRULayer layer1; -extern const DenseLayer layer2; +extern const AnalysisDenseLayer layer0; +extern const AnalysisGRULayer layer1; +extern const AnalysisDenseLayer layer2; -void compute_dense(const DenseLayer *layer, float *output, const float *input); +void analysis_compute_dense(const AnalysisDenseLayer *layer, float *output, const float *input); -void compute_gru(const GRULayer *gru, float *state, const float *input); +void analysis_compute_gru(const AnalysisGRULayer *gru, float *state, const float *input); -#endif /* _MLP_H_ */ +#endif /* MLP_H_ */ diff --git a/media/libopus/src/mlp_data.c b/media/libopus/src/mlp_data.c index ae4178df76..65f7448ea0 100644 --- a/media/libopus/src/mlp_data.c +++ b/media/libopus/src/mlp_data.c @@ -651,20 +651,20 @@ static const opus_int8 layer2_bias[2] = { 14, 117 }; -const DenseLayer layer0 = { +const AnalysisDenseLayer layer0 = { layer0_bias, layer0_weights, 25, 32, 0 }; -const GRULayer layer1 = { +const AnalysisGRULayer layer1 = { layer1_bias, layer1_weights, layer1_recur_weights, 32, 24 }; -const DenseLayer layer2 = { +const AnalysisDenseLayer layer2 = { layer2_bias, layer2_weights, 24, 2, 1 diff --git a/media/libopus/src/opus.c b/media/libopus/src/opus.c index 538b5ea74e..816a4dd5fa 100644 --- a/media/libopus/src/opus.c +++ b/media/libopus/src/opus.c @@ -194,7 +194,8 @@ int opus_packet_get_samples_per_frame(const unsigned char *data, int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, int self_delimited, unsigned char *out_toc, const unsigned char *frames[48], opus_int16 size[48], - int *payload_offset, opus_int32 *packet_offset) + int *payload_offset, opus_int32 *packet_offset, + const unsigned char **padding, opus_int32 *padding_len) { int i, bytes; int count; @@ -337,6 +338,11 @@ int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, data += size[i]; } + if (padding != NULL) + { + *padding = data; + *padding_len = pad; + } if (packet_offset) *packet_offset = pad+(opus_int32)(data-data0); @@ -351,6 +357,6 @@ int opus_packet_parse(const unsigned char *data, opus_int32 len, opus_int16 size[48], int *payload_offset) { return opus_packet_parse_impl(data, len, 0, out_toc, - frames, size, payload_offset, NULL); + frames, size, payload_offset, NULL, NULL, NULL); } diff --git a/media/libopus/src/opus_decoder.c b/media/libopus/src/opus_decoder.c index 6520e748ea..b57c809434 100644 --- a/media/libopus/src/opus_decoder.c +++ b/media/libopus/src/opus_decoder.c @@ -52,6 +52,15 @@ #include "mathops.h" #include "cpu_support.h" +#ifdef ENABLE_DEEP_PLC +#include "dred_rdovae_dec_data.h" +#include "dred_rdovae_dec.h" +#endif + +#ifdef ENABLE_OSCE +#include "osce.h" +#endif + struct OpusDecoder { int celt_dec_offset; int silk_dec_offset; @@ -59,7 +68,11 @@ struct OpusDecoder { opus_int32 Fs; /** Sampling rate (at the API level) */ silk_DecControlStruct DecControl; int decode_gain; + int complexity; int arch; +#ifdef ENABLE_DEEP_PLC + LPCNetPLCState lpcnet; +#endif /* Everything beyond this point gets cleared on a reset */ #define OPUS_DECODER_RESET_START stream_channels @@ -135,6 +148,7 @@ int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) silk_dec = (char*)st+st->silk_dec_offset; celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); st->stream_channels = st->channels = channels; + st->complexity = 0; st->Fs = Fs; st->DecControl.API_sampleRate = st->Fs; @@ -152,6 +166,9 @@ int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) st->prev_mode = 0; st->frame_size = Fs/400; +#ifdef ENABLE_DEEP_PLC + lpcnet_plc_init( &st->lpcnet); +#endif st->arch = opus_select_arch(); return OPUS_OK; } @@ -370,7 +387,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, pcm_ptr = pcm_silk; if (st->prev_mode==MODE_CELT_ONLY) - silk_InitDecoder( silk_dec ); + silk_ResetDecoder( silk_dec ); /* The SILK PLC cannot produce frames of less than 10 ms */ st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs); @@ -394,14 +411,28 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, st->DecControl.internalSampleRate = 16000; } } + st->DecControl.enable_deep_plc = st->complexity >= 5; +#ifdef ENABLE_OSCE + st->DecControl.osce_method = OSCE_METHOD_NONE; +#ifndef DISABLE_LACE + if (st->complexity >= 6) {st->DecControl.osce_method = OSCE_METHOD_LACE;} +#endif +#ifndef DISABLE_NOLACE + if (st->complexity >= 7) {st->DecControl.osce_method = OSCE_METHOD_NOLACE;} +#endif +#endif - lost_flag = data == NULL ? 1 : 2 * decode_fec; + lost_flag = data == NULL ? 1 : 2 * !!decode_fec; decoded_samples = 0; do { /* Call SILK decoder */ int first_frame = decoded_samples == 0; silk_ret = silk_Decode( silk_dec, &st->DecControl, - lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size, st->arch ); + lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size, +#ifdef ENABLE_DEEP_PLC + &st->lpcnet, +#endif + st->arch ); if( silk_ret ) { if (lost_flag) { /* PLC failure should not be fatal */ @@ -521,8 +552,12 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy) MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE)); /* Decode CELT */ - celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, - len, pcm, celt_frame_size, &dec, celt_accum); + celt_ret = celt_decode_with_ec_dred(celt_dec, decode_fec ? NULL : data, + len, pcm, celt_frame_size, &dec, celt_accum +#ifdef ENABLE_DEEP_PLC + , &st->lpcnet +#endif + ); } else { unsigned char silence[2] = {0xFF, 0xFF}; if (!celt_accum) @@ -634,7 +669,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec, - int self_delimited, opus_int32 *packet_offset, int soft_clip) + int self_delimited, opus_int32 *packet_offset, int soft_clip, const OpusDRED *dred, opus_int32 dred_offset) { int i, nb_samples; int count, offset; @@ -648,6 +683,35 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data, /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) return OPUS_BAD_ARG; +#ifdef ENABLE_DRED + if (dred != NULL && dred->process_stage == 2) { + int F10; + int features_per_frame; + int needed_feature_frames; + int init_frames; + lpcnet_plc_fec_clear(&st->lpcnet); + F10 = st->Fs/100; + /* if blend==0, the last PLC call was "update" and we need to feed two extra 10-ms frames. */ + init_frames = (st->lpcnet.blend == 0) ? 2 : 0; + features_per_frame = IMAX(1, frame_size/F10); + needed_feature_frames = init_frames + features_per_frame; + lpcnet_plc_fec_clear(&st->lpcnet); + for (i=0;idred_offset*F10/4)/F10); + if (feature_offset <= 4*dred->nb_latents-1 && feature_offset >= 0) { + lpcnet_plc_fec_add(&st->lpcnet, dred->fec_features+feature_offset*DRED_NUM_FEATURES); + } else { + if (feature_offset >= 0) lpcnet_plc_fec_add(&st->lpcnet, NULL); + } + + } + } +#else + (void)dred; + (void)dred_offset; +#endif if (len==0 || data==NULL) { int pcm_count=0; @@ -672,7 +736,7 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data, packet_stream_channels = opus_packet_get_nb_channels(data); count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, - size, &offset, packet_offset); + size, &offset, packet_offset, NULL, NULL); if (count<0) return count; @@ -684,12 +748,12 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data, int ret; /* If no FEC can be present, run the PLC (recursive call) */ if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY) - return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip); + return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip, NULL, 0); /* Otherwise, run the PLC on everything except the size for which we might have FEC */ duration_copy = st->last_packet_duration; if (frame_size-packet_frame_size!=0) { - ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip); + ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip, NULL, 0); if (ret<0) { st->last_packet_duration = duration_copy; @@ -753,7 +817,7 @@ int opus_decode(OpusDecoder *st, const unsigned char *data, { if(frame_size<=0) return OPUS_BAD_ARG; - return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0, NULL, 0); } #ifndef DISABLE_FLOAT_API @@ -781,7 +845,7 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data, celt_assert(st->channels == 1 || st->channels == 2); ALLOC(out, frame_size*st->channels, opus_int16); - ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0); + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0, NULL, 0); if (ret > 0) { for (i=0;ichannels;i++) @@ -819,7 +883,7 @@ int opus_decode(OpusDecoder *st, const unsigned char *data, celt_assert(st->channels == 1 || st->channels == 2); ALLOC(out, frame_size*st->channels, float); - ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1); + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1, NULL, 0); if (ret > 0) { for (i=0;ichannels;i++) @@ -834,7 +898,7 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data, { if(frame_size<=0) return OPUS_BAD_ARG; - return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0, NULL, 0); } #endif @@ -864,6 +928,27 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...) *value = st->bandwidth; } break; + case OPUS_SET_COMPLEXITY_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>10) + { + goto bad_arg; + } + st->complexity = value; + celt_decoder_ctl(celt_dec, OPUS_SET_COMPLEXITY(value)); + } + break; + case OPUS_GET_COMPLEXITY_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->complexity; + } + break; case OPUS_GET_FINAL_RANGE_REQUEST: { opus_uint32 *value = va_arg(ap, opus_uint32*); @@ -881,9 +966,12 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...) ((char*)&st->OPUS_DECODER_RESET_START - (char*)st)); celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); - silk_InitDecoder( silk_dec ); + silk_ResetDecoder( silk_dec ); st->stream_channels = st->channels; st->frame_size = st->Fs/400; +#ifdef ENABLE_DEEP_PLC + lpcnet_plc_reset( &st->lpcnet ); +#endif } break; case OPUS_GET_SAMPLE_RATE_REQUEST: @@ -959,6 +1047,20 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...) ret = celt_decoder_ctl(celt_dec, OPUS_GET_PHASE_INVERSION_DISABLED(value)); } break; +#ifdef USE_WEIGHTS_FILE + case OPUS_SET_DNN_BLOB_REQUEST: + { + const unsigned char *data = va_arg(ap, const unsigned char *); + opus_int32 len = va_arg(ap, opus_int32); + if(len<0 || data == NULL) + { + goto bad_arg; + } + ret = lpcnet_plc_load_model(&st->lpcnet, data, len); + ret = silk_LoadOSCEModels(silk_dec, data, len) || ret; + } + break; +#endif default: /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ ret = OPUS_UNIMPLEMENTED; @@ -1034,8 +1136,373 @@ int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, return samples; } +int opus_packet_has_lbrr(const unsigned char packet[], opus_int32 len) +{ + int ret; + const unsigned char *frames[48]; + opus_int16 size[48]; + int packet_mode, packet_frame_size, packet_stream_channels; + int nb_frames=1; + int lbrr; + + packet_mode = opus_packet_get_mode(packet); + if (packet_mode == MODE_CELT_ONLY) + return 0; + packet_frame_size = opus_packet_get_samples_per_frame(packet, 48000); + if (packet_frame_size > 960) + nb_frames = packet_frame_size/960; + packet_stream_channels = opus_packet_get_nb_channels(packet); + ret = opus_packet_parse(packet, len, NULL, frames, size, NULL); + if (ret <= 0) + return ret; + lbrr = (frames[0][0] >> (7-nb_frames)) & 0x1; + if (packet_stream_channels == 2) + lbrr = lbrr || ((frames[0][0] >> (6-2*nb_frames)) & 0x1); + return lbrr; +} + int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) { return opus_packet_get_nb_samples(packet, len, dec->Fs); } + +struct OpusDREDDecoder { +#ifdef ENABLE_DRED + RDOVAEDec model; +#endif + int loaded; + int arch; + opus_uint32 magic; +}; + +#if defined(ENABLE_DRED) && (defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS)) +static void validate_dred_decoder(OpusDREDDecoder *st) +{ + celt_assert(st->magic == 0xD8EDDEC0); +#ifdef OPUS_ARCHMASK + celt_assert(st->arch >= 0); + celt_assert(st->arch <= OPUS_ARCHMASK); +#endif +} +#define VALIDATE_DRED_DECODER(st) validate_dred_decoder(st) +#else +#define VALIDATE_DRED_DECODER(st) +#endif + + +int opus_dred_decoder_get_size(void) +{ + return sizeof(OpusDREDDecoder); +} + +#ifdef ENABLE_DRED +int dred_decoder_load_model(OpusDREDDecoder *dec, const unsigned char *data, int len) +{ + WeightArray *list; + int ret; + parse_weights(&list, data, len); + ret = init_rdovaedec(&dec->model, list); + opus_free(list); + if (ret == 0) dec->loaded = 1; + return (ret == 0) ? OPUS_OK : OPUS_BAD_ARG; +} +#endif + +int opus_dred_decoder_init(OpusDREDDecoder *dec) +{ + int ret = 0; + dec->loaded = 0; +#if defined(ENABLE_DRED) && !defined(USE_WEIGHTS_FILE) + ret = init_rdovaedec(&dec->model, rdovaedec_arrays); + if (ret == 0) dec->loaded = 1; +#endif + dec->arch = opus_select_arch(); + /* To make sure nobody forgets to init, use a magic number. */ + dec->magic = 0xD8EDDEC0; + return (ret == 0) ? OPUS_OK : OPUS_UNIMPLEMENTED; +} + +OpusDREDDecoder *opus_dred_decoder_create(int *error) +{ + int ret; + OpusDREDDecoder *dec; + dec = (OpusDREDDecoder *)opus_alloc(opus_dred_decoder_get_size()); + if (dec == NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_dred_decoder_init(dec); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(dec); + dec = NULL; + } + return dec; +} + +void opus_dred_decoder_destroy(OpusDREDDecoder *dec) +{ + if (dec) dec->magic = 0xDE57801D; + opus_free(dec); +} + +int opus_dred_decoder_ctl(OpusDREDDecoder *dred_dec, int request, ...) +{ +#ifdef ENABLE_DRED + int ret = OPUS_OK; + va_list ap; + + va_start(ap, request); + (void)dred_dec; + switch (request) + { +# ifdef USE_WEIGHTS_FILE + case OPUS_SET_DNN_BLOB_REQUEST: + { + const unsigned char *data = va_arg(ap, const unsigned char *); + opus_int32 len = va_arg(ap, opus_int32); + if(len<0 || data == NULL) + { + goto bad_arg; + } + return dred_decoder_load_model(dred_dec, data, len); + } + break; +# endif + default: + /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + va_end(ap); + return ret; +# ifdef USE_WEIGHTS_FILE +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +# endif +#else + (void)dred_dec; + (void)request; + return OPUS_UNIMPLEMENTED; +#endif +} + +#ifdef ENABLE_DRED +static int dred_find_payload(const unsigned char *data, opus_int32 len, const unsigned char **payload, int *dred_frame_offset) +{ + const unsigned char *data0; + int len0; + int frame = 0; + int ret; + const unsigned char *frames[48]; + opus_int16 size[48]; + int frame_size; + + *payload = NULL; + /* Get the padding section of the packet. */ + ret = opus_packet_parse_impl(data, len, 0, NULL, frames, size, NULL, NULL, &data0, &len0); + if (ret < 0) + return ret; + frame_size = opus_packet_get_samples_per_frame(data, 48000); + data = data0; + len = len0; + /* Scan extensions in order until we find the earliest frame with DRED data. */ + while (len > 0) + { + opus_int32 header_size; + int id, L; + len0 = len; + data0 = data; + id = *data0 >> 1; + L = *data0 & 0x1; + len = skip_extension(&data, len, &header_size); + if (len < 0) + break; + if (id == 1) + { + if (L==0) + { + frame++; + } else { + frame += data0[1]; + } + } else if (id == DRED_EXTENSION_ID) + { + const unsigned char *curr_payload; + opus_int32 curr_payload_len; + curr_payload = data0+header_size; + curr_payload_len = (data-data0)-header_size; + /* DRED position in the packet, in units of 2.5 ms like for the signaled DRED offset. */ + *dred_frame_offset = frame*frame_size/120; +#ifdef DRED_EXPERIMENTAL_VERSION + /* Check that temporary extension type and version match. + This check will be removed once extension is finalized. */ + if (curr_payload_len > DRED_EXPERIMENTAL_BYTES && curr_payload[0] == 'D' && curr_payload[1] == DRED_EXPERIMENTAL_VERSION) { + *payload = curr_payload+2; + return curr_payload_len-2; + } +#else + if (curr_payload_len > 0) { + *payload = curr_payload; + return curr_payload_len; + } +#endif + } + } + return 0; +} +#endif + +int opus_dred_get_size(void) +{ +#ifdef ENABLE_DRED + return sizeof(OpusDRED); +#else + return 0; +#endif +} + +OpusDRED *opus_dred_alloc(int *error) +{ +#ifdef ENABLE_DRED + OpusDRED *dec; + dec = (OpusDRED *)opus_alloc(opus_dred_get_size()); + if (dec == NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + return dec; +#else + if (error) + *error = OPUS_UNIMPLEMENTED; + return NULL; +#endif +} + +void opus_dred_free(OpusDRED *dec) +{ +#ifdef ENABLE_DRED + opus_free(dec); +#else + (void)dec; +#endif +} + +int opus_dred_parse(OpusDREDDecoder *dred_dec, OpusDRED *dred, const unsigned char *data, opus_int32 len, opus_int32 max_dred_samples, opus_int32 sampling_rate, int *dred_end, int defer_processing) +{ +#ifdef ENABLE_DRED + const unsigned char *payload; + opus_int32 payload_len; + int dred_frame_offset=0; + VALIDATE_DRED_DECODER(dred_dec); + if (!dred_dec->loaded) return OPUS_UNIMPLEMENTED; + dred->process_stage = -1; + payload_len = dred_find_payload(data, len, &payload, &dred_frame_offset); + if (payload_len < 0) + return payload_len; + if (payload != NULL) + { + int offset; + int min_feature_frames; + offset = 100*max_dred_samples/sampling_rate; + min_feature_frames = IMIN(2 + offset, 2*DRED_NUM_REDUNDANCY_FRAMES); + dred_ec_decode(dred, payload, payload_len, min_feature_frames, dred_frame_offset); + if (!defer_processing) + opus_dred_process(dred_dec, dred, dred); + if (dred_end) *dred_end = IMAX(0, -dred->dred_offset*sampling_rate/400); + return IMAX(0, dred->nb_latents*sampling_rate/25 - dred->dred_offset* sampling_rate/400); + } + if (dred_end) *dred_end = 0; + return 0; +#else + (void)dred_dec; + (void)dred; + (void)data; + (void)len; + (void)max_dred_samples; + (void)sampling_rate; + (void)defer_processing; + (void)dred_end; + return OPUS_UNIMPLEMENTED; +#endif +} + +int opus_dred_process(OpusDREDDecoder *dred_dec, const OpusDRED *src, OpusDRED *dst) +{ +#ifdef ENABLE_DRED + if (dred_dec == NULL || src == NULL || dst == NULL || (src->process_stage != 1 && src->process_stage != 2)) + return OPUS_BAD_ARG; + VALIDATE_DRED_DECODER(dred_dec); + if (!dred_dec->loaded) return OPUS_UNIMPLEMENTED; + if (src != dst) + OPUS_COPY(dst, src, 1); + if (dst->process_stage == 2) + return OPUS_OK; + DRED_rdovae_decode_all(&dred_dec->model, dst->fec_features, dst->state, dst->latents, dst->nb_latents, dred_dec->arch); + dst->process_stage = 2; + return OPUS_OK; +#else + (void)dred_dec; + (void)src; + (void)dst; + return OPUS_UNIMPLEMENTED; +#endif +} + +int opus_decoder_dred_decode(OpusDecoder *st, const OpusDRED *dred, opus_int32 dred_offset, opus_int16 *pcm, opus_int32 frame_size) +{ +#ifdef ENABLE_DRED + VARDECL(float, out); + int ret, i; + ALLOC_STACK; + + if(frame_size<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + celt_assert(st->channels == 1 || st->channels == 2); + ALLOC(out, frame_size*st->channels, float); + + ret = opus_decode_native(st, NULL, 0, out, frame_size, 0, 0, NULL, 1, dred, dred_offset); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = FLOAT2INT16(out[i]); + } + RESTORE_STACK; + return ret; +#else + (void)st; + (void)dred; + (void)dred_offset; + (void)pcm; + (void)frame_size; + return OPUS_UNIMPLEMENTED; +#endif +} + +int opus_decoder_dred_decode_float(OpusDecoder *st, const OpusDRED *dred, opus_int32 dred_offset, float *pcm, opus_int32 frame_size) +{ +#ifdef ENABLE_DRED + if(frame_size<=0) + return OPUS_BAD_ARG; + return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, 0, dred, dred_offset); +#else + (void)st; + (void)dred; + (void)dred_offset; + (void)pcm; + (void)frame_size; + return OPUS_UNIMPLEMENTED; +#endif +} diff --git a/media/libopus/src/opus_encoder.c b/media/libopus/src/opus_encoder.c index 8c8db5a546..d18d582f03 100644 --- a/media/libopus/src/opus_encoder.c +++ b/media/libopus/src/opus_encoder.c @@ -45,11 +45,19 @@ #include "analysis.h" #include "mathops.h" #include "tuning_parameters.h" + +#ifdef ENABLE_DRED +#include "dred_coding.h" +#endif + #ifdef FIXED_POINT #include "fixed/structs_FIX.h" #else #include "float/structs_FLP.h" #endif +#ifdef ENABLE_OSCE_TRAINING_DATA +#include +#endif #define MAX_ENCODER_BUFFER 480 @@ -67,6 +75,9 @@ struct OpusEncoder { int celt_enc_offset; int silk_enc_offset; silk_EncControlStruct silk_mode; +#ifdef ENABLE_DRED + DREDEnc dred_encoder; +#endif int application; int channels; int delay_compensation; @@ -115,6 +126,14 @@ struct OpusEncoder { int detected_bandwidth; int nb_no_activity_ms_Q1; opus_val32 peak_signal_energy; +#endif +#ifdef ENABLE_DRED + int dred_duration; + int dred_q0; + int dred_dQ; + int dred_qmax; + int dred_target_chunks; + unsigned char activity_mem[DRED_MAX_FRAMES*4]; /* 2.5ms resolution*/ #endif int nonfinal_frame; /* current frame is not the final in a packet */ opus_uint32 rangeFinal; @@ -224,6 +243,7 @@ int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int applicat st->silk_mode.packetLossPercentage = 0; st->silk_mode.complexity = 9; st->silk_mode.useInBandFEC = 0; + st->silk_mode.useDRED = 0; st->silk_mode.useDTX = 0; st->silk_mode.useCBR = 0; st->silk_mode.reducedDependency = 0; @@ -236,6 +256,11 @@ int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int applicat celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0)); celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(st->silk_mode.complexity)); +#ifdef ENABLE_DRED + /* Initialize DRED Encoder */ + dred_encoder_init( &st->dred_encoder, Fs, channels ); +#endif + st->use_vbr = 1; /* Makes constrained VBR the default (safer for real-time use) */ st->vbr_constraint = 1; @@ -544,6 +569,73 @@ OpusEncoder *opus_encoder_create(opus_int32 Fs, int channels, int application, i return st; } +#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 qmax, 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;isilk_mode.useInBandFEC) { + dred_frac = MIN16(.7f, 3.f*st->silk_mode.packetLossPercentage/100.f); + bitrate_offset = 20000; + } else { + if (st->silk_mode.packetLossPercentage > 5) { + dred_frac = MIN16(.8f, .55f + st->silk_mode.packetLossPercentage/100.f); + } else { + dred_frac = 12*st->silk_mode.packetLossPercentage/100.f; + } + bitrate_offset = 12000; + } + /* Account for the fact that longer packets require less redundancy. */ + dred_frac = dred_frac/(dred_frac + (1-dred_frac)*(frame_size*50.f)/st->Fs); + /* 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; + qmax = 15; + target_dred_bitrate = IMAX(0, (int)(dred_frac*(bitrate_bps-bitrate_offset))); + if (st->dred_duration > 0) { + opus_int32 target_bits = target_dred_bitrate*frame_size/st->Fs; + max_dred_bits = estimate_dred_bitrate(q0, dQ, qmax, 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 (target_chunks < 2) + dred_bitrate = 0; + st->dred_q0 = q0; + st->dred_dQ = dQ; + st->dred_qmax = qmax; + st->dred_target_chunks = target_chunks; + return dred_bitrate; +} +#endif + static opus_int32 user_bitrate_to_bitrate(OpusEncoder *st, int frame_size, int max_data_bytes) { if(!frame_size)frame_size=st->Fs/400; @@ -872,7 +964,7 @@ static opus_val32 compute_frame_energy(const opus_val16 *pcm, int frame_size, in /* Compute the right shift required in the MAC to avoid an overflow */ max_shift = celt_ilog2(len); - shift = IMAX(0, (celt_ilog2(sample_max) << 1) + max_shift - 28); + shift = IMAX(0, (celt_ilog2(1+sample_max) << 1) + max_shift - 28); /* Compute the energy */ for (i=0; i2 frames: Code 3 VBR */ - max_header_bytes = nb_frames == 2 ? 3 : (2+(nb_frames-1)*2); - - 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/(frame_size*nb_frames)); - repacketize_len = IMIN(cbr_bytes, out_data_bytes); - } - bytes_per_frame = IMIN(1276, 1+(repacketize_len-max_header_bytes)/nb_frames); - - ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char); - ALLOC(rp, 1, OpusRepacketizer); - opus_repacketizer_init(rp); - - bak_mode = st->user_forced_mode; - bak_bandwidth = st->user_bandwidth; - bak_channels = st->force_channels; - - st->user_forced_mode = st->mode; - st->user_bandwidth = st->bandwidth; - st->force_channels = st->stream_channels; - - bak_to_mono = st->silk_mode.toMono; - if (bak_to_mono) - st->force_channels = 1; - else - st->prev_channels = st->stream_channels; - - for (i=0;isilk_mode.toMono = 0; - st->nonfinal_frame = i<(nb_frames-1); - - /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */ - if (to_celt && i==nb_frames-1) - st->user_forced_mode = MODE_CELT_ONLY; - - tmp_len = opus_encode_native(st, pcm+i*(st->channels*frame_size), frame_size, - tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth, NULL, 0, 0, 0, 0, - NULL, float_api); - - if (tmp_len<0) - { - RESTORE_STACK; - return OPUS_INTERNAL_ERROR; - } - - ret = opus_repacketizer_cat(rp, tmp_data+i*bytes_per_frame, tmp_len); - - if (ret<0) - { - RESTORE_STACK; - return OPUS_INTERNAL_ERROR; - } - } - - ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr); - - if (ret<0) - { - RESTORE_STACK; - return OPUS_INTERNAL_ERROR; - } - - /* Discard configs that were forced locally for the purpose of repacketization */ - st->user_forced_mode = bak_mode; - st->user_bandwidth = bak_bandwidth; - st->force_channels = bak_channels; - st->silk_mode.toMono = bak_to_mono; - - RESTORE_STACK; - return ret; -} - static int compute_redundancy_bytes(opus_int32 max_data_bytes, opus_int32 bitrate_bps, int frame_rate, int channels) { int redundancy_bytes_cap; @@ -1049,6 +1042,18 @@ static int compute_redundancy_bytes(opus_int32 max_data_bytes, opus_int32 bitrat return redundancy_bytes; } +static opus_int32 opus_encode_frame_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 max_data_bytes, + int float_api, int first_frame, +#ifdef ENABLE_DRED + opus_int32 dred_bitrate_bps, +#endif +#ifndef DISABLE_FLOAT_API + AnalysisInfo *analysis_info, int is_silence, +#endif + int redundancy, int celt_to_silk, int prefill, + opus_int32 equiv_rate, int to_celt); + opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, unsigned char *data, opus_int32 out_data_bytes, int lsb_depth, const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, @@ -1058,28 +1063,17 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ CELTEncoder *celt_enc; int i; int ret=0; - opus_int32 nBytes; - ec_enc enc; - int bytes_target; int prefill=0; - int start_band = 0; int redundancy = 0; - int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */ int celt_to_silk = 0; - VARDECL(opus_val16, pcm_buf); - int nb_compr_bytes; int to_celt = 0; - opus_uint32 redundant_rng = 0; - int cutoff_Hz, hp_freq_smth1; int voice_est; /* Probability of voice in Q7 */ opus_int32 equiv_rate; - int delay_compensation; int frame_rate; opus_int32 max_rate; /* Max bitrate we're allowed to use */ int curr_bandwidth; - opus_val16 HB_gain; opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */ - int total_buffer; + opus_int32 cbr_bytes=-1; opus_val16 stereo_width; const CELTMode *celt_mode; #ifndef DISABLE_FLOAT_API @@ -1088,10 +1082,9 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ int analysis_read_subframe_bak=-1; int is_silence = 0; #endif - opus_int activity = VAD_NO_DECISION; - - VARDECL(opus_val16, tmp_prefill); - +#ifdef ENABLE_DRED + opus_int32 dred_bitrate_bps; +#endif ALLOC_STACK; max_data_bytes = IMIN(1276, out_data_bytes); @@ -1112,10 +1105,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ silk_enc = (char*)st+st->silk_enc_offset; celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); - if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) - delay_compensation = 0; - else - delay_compensation = st->delay_compensation; lsb_depth = IMIN(lsb_depth, st->lsb_depth); @@ -1157,20 +1146,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (!is_silence) st->voice_ratio = -1; - if (is_silence) - { - activity = !is_silence; - } else if (analysis_info.valid) - { - activity = analysis_info.activity_probability >= DTX_ACTIVITY_THRESHOLD; - if (!activity) - { - /* Mark as active if this noise frame is sufficiently loud */ - opus_val32 noise_energy = compute_frame_energy(pcm, frame_size, st->channels, st->arch); - activity = st->peak_signal_energy < (PSEUDO_SNR_THRESHOLD * noise_energy); - } - } - st->detected_bandwidth = 0; if (analysis_info.valid) { @@ -1207,21 +1182,24 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ stereo_width = compute_stereo_width(pcm, frame_size, st->Fs, &st->width_mem); else stereo_width = 0; - total_buffer = delay_compensation; st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes); 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. */ + dred_bitrate_bps = compute_dred_bitrate(st, st->bitrate_bps, frame_size); + st->bitrate_bps -= dred_bitrate_bps; +#endif if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8 || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400))) { @@ -1575,6 +1553,15 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ { int enc_frame_size; int nb_frames; + VARDECL(unsigned char, tmp_data); + VARDECL(OpusRepacketizer, rp); + int max_header_bytes; + opus_int32 repacketize_len; + opus_int32 max_len_sum; + opus_int32 tot_size=0; + unsigned char *curr_data; + int tmp_len; + int dtx_count = 0; if (st->mode == MODE_SILK_ONLY) { @@ -1593,17 +1580,186 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ #ifndef DISABLE_FLOAT_API if (analysis_read_pos_bak!= -1) { + /* Reset analysis position to the beginning of the first frame so we + can use it one frame at a time. */ st->analysis.read_pos = analysis_read_pos_bak; st->analysis.read_subframe = analysis_read_subframe_bak; } #endif - ret = encode_multiframe_packet(st, pcm, nb_frames, enc_frame_size, data, - out_data_bytes, to_celt, lsb_depth, float_api); + /* Worst cases: + * 2 frames: Code 2 with different compressed sizes + * >2 frames: Code 3 VBR */ + max_header_bytes = nb_frames == 2 ? 3 : (2+(nb_frames-1)*2); + + if (st->use_vbr || st->user_bitrate_bps==OPUS_BITRATE_MAX) + repacketize_len = out_data_bytes; + else { + celt_assert(cbr_bytes>=0); + repacketize_len = IMIN(cbr_bytes, out_data_bytes); + } + max_len_sum = nb_frames + repacketize_len - max_header_bytes; + + ALLOC(tmp_data, max_len_sum, unsigned char); + curr_data = tmp_data; + ALLOC(rp, 1, OpusRepacketizer); + opus_repacketizer_init(rp); + + int bak_to_mono = st->silk_mode.toMono; + if (bak_to_mono) + st->force_channels = 1; + else + st->prev_channels = st->stream_channels; + + for (i=0;isilk_mode.toMono = 0; + st->nonfinal_frame = i<(nb_frames-1); + + /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */ + frame_to_celt = to_celt && i==nb_frames-1; + frame_redundancy = redundancy && (frame_to_celt || (!to_celt && i==0)); + + curr_max = IMIN(3*st->bitrate_bps/(3*8*st->Fs/enc_frame_size), max_len_sum/nb_frames); +#ifdef ENABLE_DRED + curr_max = IMIN(curr_max, (max_len_sum-3*dred_bitrate_bps/(3*8*st->Fs/frame_size))/nb_frames); + 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); + /* Get analysis for current frame. */ + tonality_get_info(&st->analysis, &analysis_info, enc_frame_size); + } +#endif + + tmp_len = opus_encode_frame_native(st, pcm+i*(st->channels*enc_frame_size), enc_frame_size, curr_data, curr_max, float_api, first_frame, +#ifdef ENABLE_DRED + dred_bitrate_bps, +#endif +#ifndef DISABLE_FLOAT_API + &analysis_info, + is_silence, +#endif + frame_redundancy, celt_to_silk, prefill, + equiv_rate, frame_to_celt + ); + if (tmp_len<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } else if (tmp_len==1) { + dtx_count++; + } + ret = opus_repacketizer_cat(rp, curr_data, 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 && (dtx_count != nb_frames), NULL, 0); + if (ret<0) + { + ret = OPUS_INTERNAL_ERROR; + } + st->silk_mode.toMono = bak_to_mono; RESTORE_STACK; return ret; + } else { + ret = opus_encode_frame_native(st, pcm, frame_size, data, max_data_bytes, float_api, 1, +#ifdef ENABLE_DRED + dred_bitrate_bps, +#endif +#ifndef DISABLE_FLOAT_API + &analysis_info, + is_silence, +#endif + redundancy, celt_to_silk, prefill, + equiv_rate, to_celt + ); + RESTORE_STACK; + return ret; } +} + +static opus_int32 opus_encode_frame_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 max_data_bytes, + int float_api, int first_frame, +#ifdef ENABLE_DRED + opus_int32 dred_bitrate_bps, +#endif +#ifndef DISABLE_FLOAT_API + AnalysisInfo *analysis_info, int is_silence, +#endif + int redundancy, int celt_to_silk, int prefill, + opus_int32 equiv_rate, int to_celt) +{ + void *silk_enc; + CELTEncoder *celt_enc; + const CELTMode *celt_mode; + int i; + int ret=0; + opus_int32 nBytes; + ec_enc enc; + int bytes_target; + int start_band = 0; + int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */ + int nb_compr_bytes; + opus_uint32 redundant_rng = 0; + int cutoff_Hz; + int hp_freq_smth1; + opus_val16 HB_gain; + int apply_padding; + int frame_rate; + int curr_bandwidth; + int delay_compensation; + int total_buffer; + opus_int activity = VAD_NO_DECISION; + VARDECL(opus_val16, pcm_buf); + VARDECL(opus_val16, tmp_prefill); + SAVE_STACK; + + st->rangeFinal = 0; + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode)); + curr_bandwidth = st->bandwidth; + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + total_buffer = delay_compensation; + + frame_rate = st->Fs/frame_size; + +#ifndef DISABLE_FLOAT_API + if (is_silence) + { + activity = !is_silence; + } else if (analysis_info->valid) + { + activity = analysis_info->activity_probability >= DTX_ACTIVITY_THRESHOLD; + if (!activity) + { + /* Mark as active if this noise frame is sufficiently loud */ + opus_val32 noise_energy = compute_frame_energy(pcm, frame_size, st->channels, st->arch); + activity = st->peak_signal_energy < (PSEUDO_SNR_THRESHOLD * noise_energy); + } + } +#endif /* For the first frame at a new SILK bandwidth */ if (st->silk_bw_switch) @@ -1611,7 +1767,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ redundancy = 1; celt_to_silk = 1; st->silk_bw_switch = 0; - /* Do a prefill without reseting the sampling rate control. */ + /* Do a prefill without resetting the sampling rate control. */ prefill=2; } @@ -1651,6 +1807,25 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->application == OPUS_APPLICATION_VOIP) { hp_cutoff(pcm, cutoff_Hz, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs, st->arch); + +#ifdef ENABLE_OSCE_TRAINING_DATA + /* write out high pass filtered clean signal*/ + static FILE *fout =NULL; + if (fout == NULL) + { + fout = fopen("clean_hp.s16", "wb"); + } + + { + int idx; + opus_int16 tmp; + for (idx = 0; idx < frame_size; idx++) + { + tmp = (opus_int16) (32768 * pcm_buf[total_buffer + idx] + 0.5f); + fwrite(&tmp, sizeof(tmp), 1, fout); + } + } +#endif } else { dc_reject(pcm, 3, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); } @@ -1667,8 +1842,24 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ st->hp_mem[0] = st->hp_mem[1] = st->hp_mem[2] = st->hp_mem[3] = 0; } } +#else + (void)float_api; #endif +#ifdef ENABLE_DRED + if ( st->dred_duration > 0 && st->dred_encoder.loaded ) { + int frame_size_400Hz; + /* DRED Encoder */ + dred_compute_latents( &st->dred_encoder, &pcm_buf[total_buffer*st->channels], frame_size, total_buffer, st->arch ); + frame_size_400Hz = frame_size*400/st->Fs; + OPUS_MOVE(&st->activity_mem[frame_size_400Hz], st->activity_mem, 4*DRED_MAX_FRAMES-frame_size_400Hz); + for (i=0;iactivity_mem[i] = activity; + } else { + st->dred_encoder.latents_buffer_fill = 0; + OPUS_CLEAR(st->activity_mem, DRED_MAX_FRAMES); + } +#endif /* SILK processing */ HB_gain = Q15ONE; @@ -1763,7 +1954,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ st->silk_mode.maxInternalSampleRate = 16000; if (st->mode == MODE_SILK_ONLY) { - opus_int32 effective_max_rate = max_rate; + opus_int32 effective_max_rate = frame_rate*max_data_bytes*8; if (frame_rate > 50) effective_max_rate = effective_max_rate*2/3; if (effective_max_rate < 8000) @@ -1793,9 +1984,19 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ } if (st->silk_mode.useCBR) { + /* When we're in CBR mode, but we have non-SILK data to encode, switch SILK to VBR with cap to + save on complexity. Any variations will be absorbed by CELT and/or DRED and we can still + produce a constant bitrate without wasting bits. */ +#ifdef ENABLE_DRED + if (st->mode == MODE_HYBRID || dred_bitrate_bps > 0) +#else if (st->mode == MODE_HYBRID) +#endif { - st->silk_mode.maxBits = IMIN(st->silk_mode.maxBits, st->silk_mode.bitRate * frame_size / st->Fs); + /* Allow SILK to steal up to 25% of the remaining bits */ + opus_int16 other_bits = IMAX(0, st->silk_mode.maxBits - st->silk_mode.bitRate * frame_size / st->Fs); + st->silk_mode.maxBits = IMAX(0, st->silk_mode.maxBits - other_bits*3/4); + st->silk_mode.useCBR = 0; } } else { /* Constrained VBR. */ @@ -1908,26 +2109,10 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->mode != MODE_SILK_ONLY) { opus_val32 celt_pred=2; - celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); /* We may still decide to disable prediction later */ if (st->silk_mode.reducedDependency) celt_pred = 0; celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(celt_pred)); - - if (st->mode == MODE_HYBRID) - { - if( st->use_vbr ) { - celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); - celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0)); - } - } else { - if (st->use_vbr) - { - celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); - celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint)); - celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps)); - } - } } ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16); @@ -2021,13 +2206,27 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ ec_enc_done(&enc); nb_compr_bytes = ret; } else { - nb_compr_bytes = (max_data_bytes-1)-redundancy_bytes; - ec_enc_shrink(&enc, nb_compr_bytes); + nb_compr_bytes = (max_data_bytes-1)-redundancy_bytes; +#ifdef ENABLE_DRED + if (st->dred_duration > 0) + { + int max_celt_bytes; + opus_int32 dred_bytes = dred_bitrate_bps/(frame_rate*8); + /* Allow CELT to steal up to 25% of the remaining bits. */ + max_celt_bytes = nb_compr_bytes - dred_bytes*3/4; + /* But try to give CELT at least 5 bytes to prevent a mismatch with + the redundancy signaling. */ + max_celt_bytes = IMAX((ec_tell(&enc)+7)/8 + 5, max_celt_bytes); + /* Subject to the original max. */ + nb_compr_bytes = IMIN(nb_compr_bytes, max_celt_bytes); + } +#endif + ec_enc_shrink(&enc, nb_compr_bytes); } #ifndef DISABLE_FLOAT_API if (redundancy || st->mode != MODE_SILK_ONLY) - celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(&analysis_info)); + celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(analysis_info)); #endif if (st->mode == MODE_HYBRID) { SILKInfo info; @@ -2057,6 +2256,34 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->mode != MODE_SILK_ONLY) { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(st->use_vbr)); + if (st->mode == MODE_HYBRID) + { + if( st->use_vbr ) { + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0)); + } + } else { + if (st->use_vbr) + { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps)); + } + } +#ifdef ENABLE_DRED + /* When Using DRED CBR, we can actually make the CELT part VBR and have DRED pick up the slack. */ + if (!st->use_vbr && st->dred_duration > 0) + { + opus_int32 celt_bitrate = st->bitrate_bps; + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0)); + if (st->mode == MODE_HYBRID) { + celt_bitrate -= st->silk_mode.bitRate; + } + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(celt_bitrate)); + } +#endif if (st->mode != st->prev_mode && st->prev_mode > 0) { unsigned char dummy[2]; @@ -2069,10 +2296,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ /* If false, we already busted the budget and we'll end up with a "PLC frame" */ if (ec_tell(&enc) <= 8*nb_compr_bytes) { - /* Set the bitrate again if it was overridden in the redundancy code above*/ - if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) - celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); - celt_encoder_ctl(celt_enc, OPUS_SET_VBR(st->use_vbr)); ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc); if (ret < 0) { @@ -2080,10 +2303,10 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ return OPUS_INTERNAL_ERROR; } /* Put CELT->SILK redundancy data in the right place. */ - if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) + if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && nb_compr_bytes != ret) { OPUS_MOVE(data+ret, data+nb_compr_bytes, redundancy_bytes); - nb_compr_bytes = nb_compr_bytes+redundancy_bytes; + nb_compr_bytes = ret+redundancy_bytes; } } } @@ -2140,7 +2363,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ /* DTX decision */ #ifndef DISABLE_FLOAT_API - if (st->use_dtx && (analysis_info.valid || is_silence)) + if (st->use_dtx && (analysis_info->valid || is_silence)) { if (decide_dtx_mode(activity, &st->nb_no_activity_ms_Q1, 2*1000*frame_size/st->Fs)) { @@ -2178,7 +2401,51 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ } /* Count ToC and redundancy */ ret += 1+redundancy_bytes; - if (!st->use_vbr) + apply_padding = !st->use_vbr; +#ifdef ENABLE_DRED + if (st->dred_duration > 0 && st->dred_encoder.loaded && first_frame) { + opus_extension_data extension; + unsigned char buf[DRED_MAX_DATA_SIZE]; + 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); + /* Account for the extra bytes required to signal large padding length. */ + dred_bytes_left -= (dred_bytes_left+1+DRED_EXPERIMENTAL_BYTES)/255; + /* Check whether we actually have something to encode. */ + if (dred_chunks >= 1 && dred_bytes_left >= DRED_MIN_BYTES+DRED_EXPERIMENTAL_BYTES) { + int dred_bytes; +#ifdef DRED_EXPERIMENTAL_VERSION + /* Add temporary extension type and version. + These bytes will be removed once extension is finalized. */ + 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->dred_q0, st->dred_dQ, st->dred_qmax, st->activity_mem, st->arch); + if (dred_bytes > 0) { + dred_bytes += DRED_EXPERIMENTAL_BYTES; + celt_assert(dred_bytes <= dred_bytes_left); + extension.id = DRED_EXTENSION_ID; + extension.frame = 0; + extension.data = buf; + extension.len = dred_bytes; + ret = opus_packet_pad_impl(data, ret, max_data_bytes, !st->use_vbr, &extension, 1); + if (ret < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + apply_padding = 0; + } + } + } +#else + (void)first_frame; /* Avoids a warning about first_frame being unused. */ +#endif + if (apply_padding) { if (opus_packet_pad(data, ret, max_data_bytes) != OPUS_OK) { @@ -2677,6 +2944,29 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) celt_encoder_ctl(celt_enc, OPUS_GET_PHASE_INVERSION_DISABLED(value)); } break; +#ifdef ENABLE_DRED + case OPUS_SET_DRED_DURATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>DRED_MAX_FRAMES) + { + goto bad_arg; + } + st->dred_duration = value; + st->silk_mode.useDRED = !!value; + } + break; + case OPUS_GET_DRED_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->dred_duration; + } + break; +#endif case OPUS_RESET_STATE: { void *silk_enc; @@ -2692,6 +2982,10 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); silk_InitEncoder( silk_enc, st->arch, &dummy ); +#ifdef ENABLE_DRED + /* Initialize DRED Encoder */ + dred_encoder_reset( &st->dred_encoder ); +#endif st->stream_channels = st->channels; st->hybrid_stereo_width_Q14 = 1 << 14; st->prev_HB_gain = Q15ONE; @@ -2752,6 +3046,21 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) } } break; +#ifdef USE_WEIGHTS_FILE + case OPUS_SET_DNN_BLOB_REQUEST: + { + const unsigned char *data = va_arg(ap, const unsigned char *); + opus_int32 len = va_arg(ap, opus_int32); + if(len<0 || data == NULL) + { + goto bad_arg; + } +#ifdef ENABLE_DRED + ret = dred_encoder_load_model(&st->dred_encoder, data, len); +#endif + } + break; +#endif case CELT_GET_MODE_REQUEST: { const CELTMode ** value = va_arg(ap, const CELTMode**); diff --git a/media/libopus/src/opus_multistream_decoder.c b/media/libopus/src/opus_multistream_decoder.c index a2837c3549..4ae877a759 100644 --- a/media/libopus/src/opus_multistream_decoder.c +++ b/media/libopus/src/opus_multistream_decoder.c @@ -162,7 +162,7 @@ static int opus_multistream_packet_validate(const unsigned char *data, if (len<=0) return OPUS_INVALID_PACKET; count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL, - size, NULL, &packet_offset); + size, NULL, &packet_offset, NULL, NULL); if (count<0) return count; tmp_samples = opus_packet_get_nb_samples(data, packet_offset, Fs); @@ -250,7 +250,7 @@ int opus_multistream_decode_native( return OPUS_INTERNAL_ERROR; } packet_offset = 0; - ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip); + ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip, NULL, 0); if (!do_plc) { data += packet_offset; diff --git a/media/libopus/src/opus_multistream_encoder.c b/media/libopus/src/opus_multistream_encoder.c index 213e3eb2c2..1725ade75a 100644 --- a/media/libopus/src/opus_multistream_encoder.c +++ b/media/libopus/src/opus_multistream_encoder.c @@ -1003,7 +1003,7 @@ int opus_multistream_encode_native return OPUS_INTERNAL_ERROR; } len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), - data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1); + data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1, NULL, 0); data += len; tot_size += len; } diff --git a/media/libopus/src/opus_private.h b/media/libopus/src/opus_private.h index 5e2463f546..364c21cebc 100644 --- a/media/libopus/src/opus_private.h +++ b/media/libopus/src/opus_private.h @@ -42,8 +42,17 @@ struct OpusRepacketizer { const unsigned char *frames[48]; opus_int16 len[48]; int framesize; + const unsigned char *paddings[48]; + opus_int32 padding_len[48]; }; +typedef struct { + int id; + int frame; + const unsigned char *data; + opus_int32 len; +} opus_extension_data; + typedef struct ChannelLayout { int nb_channels; int nb_streams; @@ -148,7 +157,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, - opus_int32 *packet_offset, int soft_clip); + opus_int32 *packet_offset, int soft_clip, const OpusDRED *dred, opus_int32 dred_offset); /* Make sure everything is properly aligned. */ static OPUS_INLINE int align(int i) @@ -162,13 +171,18 @@ static OPUS_INLINE int align(int i) return ((i + alignment - 1) / alignment) * alignment; } +/* More than that is ridiculous for now (3 * max frames per packet)*/ +opus_int32 skip_extension(const unsigned char **data, opus_int32 len, opus_int32 *header_size); + int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, int self_delimited, unsigned char *out_toc, const unsigned char *frames[48], opus_int16 size[48], - int *payload_offset, opus_int32 *packet_offset); + int *payload_offset, opus_int32 *packet_offset, + const unsigned char **padding, opus_int32 *padding_len); opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, - unsigned char *data, opus_int32 maxlen, int self_delimited, int pad); + unsigned char *data, opus_int32 maxlen, int self_delimited, int pad, + const opus_extension_data *extensions, int nb_extensions); int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len); @@ -198,4 +212,12 @@ int opus_multistream_decode_native( void *user_data ); +opus_int32 opus_packet_extensions_parse(const unsigned char *data, opus_int32 len, opus_extension_data *extensions, opus_int32 *nb_extensions); + +opus_int32 opus_packet_extensions_generate(unsigned char *data, opus_int32 len, const opus_extension_data *extensions, int nb_extensions, int pad); + +opus_int32 opus_packet_extensions_count(const unsigned char *data, opus_int32 len); + +opus_int32 opus_packet_pad_impl(unsigned char *data, opus_int32 len, opus_int32 new_len, int pad, const opus_extension_data *extensions, int nb_extensions); + #endif /* OPUS_PRIVATE_H */ diff --git a/media/libopus/src/opus_projection_encoder.c b/media/libopus/src/opus_projection_encoder.c index 06fb2d2526..92813ad01f 100644 --- a/media/libopus/src/opus_projection_encoder.c +++ b/media/libopus/src/opus_projection_encoder.c @@ -177,6 +177,20 @@ opus_int32 opus_projection_ambisonics_encoder_get_size(int channels, demixing_matrix_rows = mapping_matrix_toa_demixing.rows; demixing_matrix_cols = mapping_matrix_toa_demixing.cols; } + else if (order_plus_one == 5) + { + mixing_matrix_rows = mapping_matrix_fourthoa_mixing.rows; + mixing_matrix_cols = mapping_matrix_fourthoa_mixing.cols; + demixing_matrix_rows = mapping_matrix_fourthoa_demixing.rows; + demixing_matrix_cols = mapping_matrix_fourthoa_demixing.cols; + } + else if (order_plus_one == 6) + { + mixing_matrix_rows = mapping_matrix_fifthoa_mixing.rows; + mixing_matrix_cols = mapping_matrix_fifthoa_mixing.cols; + demixing_matrix_rows = mapping_matrix_fifthoa_demixing.rows; + demixing_matrix_cols = mapping_matrix_fifthoa_demixing.cols; + } else return 0; @@ -245,6 +259,20 @@ int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int3 mapping_matrix_toa_mixing_data, sizeof(mapping_matrix_toa_mixing_data)); } + else if (order_plus_one == 5) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_fourthoa_mixing.rows, + mapping_matrix_fourthoa_mixing.cols, mapping_matrix_fourthoa_mixing.gain, + mapping_matrix_fourthoa_mixing_data, + sizeof(mapping_matrix_fourthoa_mixing_data)); + } + else if (order_plus_one == 6) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_fifthoa_mixing.rows, + mapping_matrix_fifthoa_mixing.cols, mapping_matrix_fifthoa_mixing.gain, + mapping_matrix_fifthoa_mixing_data, + sizeof(mapping_matrix_fifthoa_mixing_data)); + } else return OPUS_BAD_ARG; @@ -275,6 +303,20 @@ int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int3 mapping_matrix_toa_demixing.cols, mapping_matrix_toa_demixing.gain, mapping_matrix_toa_demixing_data, sizeof(mapping_matrix_toa_demixing_data)); + } + else if (order_plus_one == 5) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_fourthoa_demixing.rows, + mapping_matrix_fourthoa_demixing.cols, mapping_matrix_fourthoa_demixing.gain, + mapping_matrix_fourthoa_demixing_data, + sizeof(mapping_matrix_fourthoa_demixing_data)); + } + else if (order_plus_one == 6) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_fifthoa_demixing.rows, + mapping_matrix_fifthoa_demixing.cols, mapping_matrix_fifthoa_demixing.gain, + mapping_matrix_fifthoa_demixing_data, + sizeof(mapping_matrix_fifthoa_demixing_data)); } else return OPUS_BAD_ARG; diff --git a/media/libopus/src/repacketizer.c b/media/libopus/src/repacketizer.c index bda44a148a..6a7a8b3d8e 100644 --- a/media/libopus/src/repacketizer.c +++ b/media/libopus/src/repacketizer.c @@ -32,6 +32,7 @@ #include "opus.h" #include "opus_private.h" #include "os_support.h" +#include "stack_alloc.h" int opus_repacketizer_get_size(void) @@ -82,10 +83,19 @@ static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char return OPUS_INVALID_PACKET; } - ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL); + ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], + NULL, NULL, &rp->paddings[rp->nb_frames], &rp->padding_len[rp->nb_frames]); if(ret<1)return ret; - rp->nb_frames += curr_nb_frames; + /* set padding length to zero for all but the first frame */ + while (curr_nb_frames > 1) + { + rp->nb_frames++; + rp->padding_len[rp->nb_frames] = 0; + rp->paddings[rp->nb_frames] = NULL; + curr_nb_frames--; + } + rp->nb_frames++; return OPUS_OK; } @@ -100,17 +110,23 @@ int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) } opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, - unsigned char *data, opus_int32 maxlen, int self_delimited, int pad) + unsigned char *data, opus_int32 maxlen, int self_delimited, int pad, const opus_extension_data *extensions, int nb_extensions) { int i, count; opus_int32 tot_size; opus_int16 *len; const unsigned char **frames; unsigned char * ptr; + int ones_begin=0, ones_end=0; + int ext_begin=0, ext_len=0; + int ext_count, total_ext_count; + VARDECL(opus_extension_data, all_extensions); + SAVE_STACK; if (begin<0 || begin>=end || end>rp->nb_frames) { /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/ + RESTORE_STACK; return OPUS_BAD_ARG; } count = end-begin; @@ -122,13 +138,50 @@ opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int else tot_size = 0; + /* figure out total number of extensions */ + total_ext_count = nb_extensions; + for (i=begin;ipaddings[i], rp->padding_len[i]); + if (n > 0) total_ext_count += n; + } + ALLOC(all_extensions, total_ext_count ? total_ext_count : ALLOC_NONE, opus_extension_data); + /* copy over any extensions that were passed in */ + for (ext_count=0;ext_countpaddings[i], rp->padding_len[i], + &all_extensions[ext_count], &frame_ext_count); + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + /* renumber the extension frame numbers */ + for (j=0;j maxlen) + { + RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; + } *ptr++ = rp->toc&0xFC; } else if (count==2) { @@ -137,18 +190,24 @@ opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int /* Code 1 */ tot_size += 2*len[0]+1; if (tot_size > maxlen) + { + RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; + } *ptr++ = (rp->toc&0xFC) | 0x1; } else { /* Code 2 */ tot_size += len[0]+len[1]+2+(len[0]>=252); if (tot_size > maxlen) + { + RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; + } *ptr++ = (rp->toc&0xFC) | 0x2; ptr += encode_size(len[0], ptr); } } - if (count > 2 || (pad && tot_size < maxlen)) + if (count > 2 || (pad && tot_size < maxlen) || ext_count > 0) { /* Code 3 */ int vbr; @@ -177,22 +236,45 @@ opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int tot_size += len[count-1]; if (tot_size > maxlen) + { + RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; + } *ptr++ = (rp->toc&0xFC) | 0x3; *ptr++ = count | 0x80; } else { tot_size += count*len[0]+2; if (tot_size > maxlen) + { + RESTORE_STACK; return OPUS_BUFFER_TOO_SMALL; + } *ptr++ = (rp->toc&0xFC) | 0x3; *ptr++ = count; } pad_amount = pad ? (maxlen-tot_size) : 0; + if (ext_count>0) + { + /* figure out how much space we need for the extensions */ + ext_len = opus_packet_extensions_generate(NULL, maxlen-tot_size, all_extensions, ext_count, 0); + if (ext_len < 0) return ext_len; + if (!pad) + pad_amount = ext_len + ext_len/254 + 1; + } if (pad_amount != 0) { int nb_255s; data[1] |= 0x40; nb_255s = (pad_amount-1)/255; + if (tot_size + ext_len + nb_255s + 1 > maxlen) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + ext_begin = tot_size+pad_amount-ext_len; + /* Prepend 0x01 padding */ + ones_begin = tot_size+nb_255s+1; + ones_end = tot_size+pad_amount-ext_len; for (i=0;i 0) { + int ret = opus_packet_extensions_generate(&data[ext_begin], ext_len, all_extensions, ext_count, 0); + celt_assert(ret == ext_len); + } + for (i=ones_begin;inb_frames, data, maxlen, 0, 0); + return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0, NULL, 0); } -int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len) +opus_int32 opus_packet_pad_impl(unsigned char *data, opus_int32 len, opus_int32 new_len, int pad, const opus_extension_data *extensions, int nb_extensions) { OpusRepacketizer rp; opus_int32 ret; + VARDECL(unsigned char, copy); + SAVE_STACK; if (len < 1) return OPUS_BAD_ARG; if (len==new_len) return OPUS_OK; else if (len > new_len) return OPUS_BAD_ARG; + ALLOC(copy, len, unsigned char); opus_repacketizer_init(&rp); /* Moving payload to the end of the packet so we can do in-place padding */ - OPUS_MOVE(data+new_len-len, data, len); - ret = opus_repacketizer_cat(&rp, data+new_len-len, len); + OPUS_COPY(copy, data, len); + ret = opus_repacketizer_cat(&rp, copy, len); if (ret != OPUS_OK) return ret; - ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1); + ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, pad, extensions, nb_extensions); + RESTORE_STACK; + return ret; +} + +int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len) +{ + opus_int32 ret; + ALLOC_STACK; + ret = opus_packet_pad_impl(data, len, new_len, 1, NULL, 0); + RESTORE_STACK; if (ret > 0) return OPUS_OK; else @@ -264,13 +366,19 @@ opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len) { OpusRepacketizer rp; opus_int32 ret; + int i; if (len < 1) return OPUS_BAD_ARG; opus_repacketizer_init(&rp); ret = opus_repacketizer_cat(&rp, data, len); if (ret < 0) return ret; - ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0); + /* Discard all padding and extensions. */ + for (i=0;i 0 && ret <= len); return ret; } @@ -297,7 +405,7 @@ int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 if (len<=0) return OPUS_INVALID_PACKET; count = opus_packet_parse_impl(data, len, 1, &toc, NULL, - size, NULL, &packet_offset); + size, NULL, &packet_offset, NULL, NULL); if (count<0) return count; data += packet_offset; @@ -324,18 +432,24 @@ opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, in for (s=0;s