ref: 5e2440fafceff49cd1377be7a74a4efca32fd2be
parent: ebfa29c7e1a435bb6a85a64a317272506359cea2
author: Jean-Marc Valin <jmvalin@amazon.com>
date: Sat May 13 19:56:50 EDT 2023
Complete switching to DRED object
--- a/include/opus.h
+++ b/include/opus.h
@@ -527,6 +527,10 @@
OPUS_EXPORT int opus_decoder_dred_parse(OpusDecoder *st, const unsigned char *data,
opus_int32 len, int offset) OPUS_ARG_NONNULL(1);
+OPUS_EXPORT int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, int dred_offset, opus_int16 *pcm, int frame_size);
+OPUS_EXPORT int opus_decoder_dred_output_float(OpusDecoder *st, OpusDRED *dred, int dred_offset, float *pcm, int frame_size);
+
+
/** Parse an opus packet into one or more frames.
* Opus_decode will perform this operation internally so most applications do
* not need to use this function.
@@ -598,6 +602,8 @@
* @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
*/
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_has_fec(const unsigned char packet[], opus_int32 len);
/** Gets the number of samples of an Opus packet.
* @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -639,7 +639,7 @@
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, OpusDRED *dred, opus_int32 dred_offset)
{
int i, nb_samples;
int count, offset;
@@ -656,16 +656,17 @@
if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0)
return OPUS_BAD_ARG;
#ifdef ENABLE_NEURAL_FEC
- if (decode_fec > 0 && st->nb_fec_frames > 0) {
+ if (dred != NULL) {
int features_per_frame;
int needed_feature_frames;
+ lpcnet_plc_fec_clear(silk_dec->sPLC.lpcnet);
features_per_frame = frame_size/(st->Fs/100);
needed_feature_frames = features_per_frame;
if (!silk_dec->sPLC.pre_filled) needed_feature_frames+=2;
for (i=0;i<needed_feature_frames;i++) {
- int feature_offset = (needed_feature_frames-i-1 + (decode_fec-1)*features_per_frame);
- if (feature_offset <= st->nb_fec_frames-1) {
- lpcnet_plc_fec_add(silk_dec->sPLC.lpcnet, st->fec_features+feature_offset*DRED_NUM_FEATURES);
+ int feature_offset = (needed_feature_frames-i-1 + (dred_offset-1)*features_per_frame);
+ if (feature_offset <= 4*dred->nb_latents-1) {
+ lpcnet_plc_fec_add(silk_dec->sPLC.lpcnet, dred->fec_features+feature_offset*DRED_NUM_FEATURES);
} else {
lpcnet_plc_fec_add(silk_dec->sPLC.lpcnet, NULL);
}
@@ -709,12 +710,12 @@
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;
@@ -778,7 +779,7 @@
{
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
@@ -806,7 +807,7 @@
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;i<ret*st->channels;i++)
@@ -844,7 +845,7 @@
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;i<ret*st->channels;i++)
@@ -859,7 +860,7 @@
{
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
@@ -1059,6 +1060,31 @@
return samples;
}
+int opus_packet_has_fec(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 0;
+ 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)
{
@@ -1130,8 +1156,6 @@
if (payload != NULL)
{
int min_feature_frames;
- silk_decoder_state *silk_dec;
- silk_dec = (silk_decoder_state*)((char*)st+st->silk_dec_offset);
/*printf("Found: %p of size %d\n", payload, payload_len);*/
min_feature_frames = IMIN(2 + offset, 2*DRED_NUM_REDUNDANCY_FRAMES);
dred_ec_decode(&st->dred_decoder, payload, payload_len, min_feature_frames);
@@ -1138,7 +1162,6 @@
opus_dred_process(&st->dred_decoder);
OPUS_COPY(st->fec_features, st->dred_decoder.fec_features, 4*st->dred_decoder.nb_latents*DRED_NUM_FEATURES);
st->nb_fec_frames = 4*st->dred_decoder.nb_latents;
- lpcnet_plc_fec_clear(silk_dec->sPLC.lpcnet);
return st->nb_fec_frames;
}
#endif
@@ -1145,6 +1168,26 @@
return 0;
}
+int opus_dred_parse(OpusDRED *dred, const unsigned char *data, opus_int32 len, opus_int32 max_dred_samples, opus_int32 sampling_rate, int defer_processing)
+{
+#ifdef ENABLE_NEURAL_FEC
+ const unsigned char *payload;
+ opus_int32 payload_len;
+ payload_len = dred_find_payload(data, len, &payload);
+ 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);
+ if (!defer_processing)
+ opus_dred_process(dred);
+ return dred->nb_latents*sampling_rate/25 - sampling_rate/50;
+ }
+#endif
+ return 0;
+}
int opus_dred_process(OpusDRED *dred)
{
@@ -1155,5 +1198,32 @@
int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, int dred_offset, opus_int16 *pcm, int frame_size)
{
- return OPUS_OK;
+ 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;i<ret*st->channels;i++)
+ pcm[i] = FLOAT2INT16(out[i]);
+ }
+ RESTORE_STACK;
+ return ret;
+}
+
+int opus_decoder_dred_output_float(OpusDecoder *st, OpusDRED *dred, int dred_offset, float *pcm, int frame_size)
+{
+ 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);
}
--- a/src/opus_demo.c
+++ b/src/opus_demo.c
@@ -217,6 +217,7 @@
FILE *fout=NULL;
OpusEncoder *enc=NULL;
OpusDecoder *dec=NULL;
+ OpusDRED *dred=NULL;
int args;
int len;
int frame_size, channels;
@@ -629,6 +630,7 @@
opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration));
frame_size = 2*48000;
}
+ dred = opus_dred_create(&err);
while (!stop)
{
if (delayed_celt)
@@ -801,7 +803,7 @@
opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
dred_input = lost_count*output_samples*100/sampling_rate;
/* Only decode the amount we need to fill in the gap. */
- opus_decoder_dred_parse(dec, data, len, IMIN(100, IMAX(0, dred_input)));
+ opus_dred_parse(dred, data, len, IMIN(100, IMAX(0, dred_input))*480, 48000, 0);
}
/* FIXME: Figure out how to trigger the decoder when the last packet of the file is lost. */
for (fr=0;fr<run_decoder;fr++) {
@@ -808,10 +810,13 @@
opus_int32 output_samples=0;
if (fr < lost_count-1) {
opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
- output_samples = opus_decode(dec, NULL, 0, out, output_samples, lost_count-fr);
- } else if (fr == lost_count-1) {
+ output_samples = opus_decoder_dred_output(dec, dred, lost_count-fr, out, output_samples);
+ } else if (fr == lost_count-1 && opus_packet_has_fec(data, len)) {
opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
output_samples = opus_decode(dec, data, len, out, output_samples, 1);
+ } else if (fr == lost_count-1) {
+ opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
+ output_samples = opus_decoder_dred_output(dec, dred, 1, out, output_samples);
} else {
output_samples = max_frame_size;
output_samples = opus_decode(dec, data, len, out, output_samples, 0);
--- a/src/opus_multistream_decoder.c
+++ b/src/opus_multistream_decoder.c
@@ -250,7 +250,7 @@
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;
--- a/src/opus_private.h
+++ b/src/opus_private.h
@@ -155,7 +155,7 @@
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, OpusDRED *dred, opus_int32 dred_offset);
/* Make sure everything is properly aligned. */
static OPUS_INLINE int align(int i)
--
⑨