diff options
author | Jean-Marc Valin <jmvalin@amazon.com> | 2023-05-19 09:31:11 +0300 |
---|---|---|
committer | Jean-Marc Valin <jmvalin@amazon.com> | 2023-06-16 20:01:39 +0300 |
commit | e0c6eae8cc789b1d80babe5219d505fbf9d91a88 (patch) | |
tree | 50cbfe185c0524dbbfb77b385b88928b266980c7 | |
parent | a561f120c97f47d12baa56c33d351cbe8b579ddc (diff) |
Update the API to add an OpusDREDDecoder
-rw-r--r-- | include/opus.h | 34 | ||||
-rw-r--r-- | src/opus_decoder.c | 81 | ||||
-rw-r--r-- | src/opus_demo.c | 5 |
3 files changed, 111 insertions, 9 deletions
diff --git a/include/opus.h b/include/opus.h index cde0f20c..01668a8b 100644 --- a/include/opus.h +++ b/include/opus.h @@ -398,6 +398,13 @@ OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NON */ typedef struct OpusDecoder OpusDecoder; +/** Opus DRED decoder. + * This contains the complete state of an Opus DRED decoder. + * It is position independent and can be freely copied. + * @see opus_dred_decoder_create,opus_dred_decoder_init + */ +typedef struct OpusDREDDecoder OpusDREDDecoder; + /** Opus DRED state. * This contains the complete state of an Opus DRED packet. @@ -519,6 +526,28 @@ OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NON */ OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st); +/** Gets the size of an <code>OpusDREDDecoder</code> structure. + * @returns The size in bytes. + */ +OPUS_EXPORT int opus_dred_decoder_get_size(void); + +/** Allocates and initializes an OpusDREDDecoder state. + * @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT OpusDREDDecoder *opus_dred_decoder_create(int *error); + +/** Initializes an <code>OpusDREDDecoder</code> state. + * @param[in] st <tt>OpusDREDDecoder*</tt>: State to be initialized. + * @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_dred_decoder_init(OpusDREDDecoder *dec); + +/** Frees an <code>OpusDREDDecoder</code> allocated by opus_dred_decoder_create(). + * @param[in] st <tt>OpusDREDDecoder*</tt>: State to be freed. + */ +OPUS_EXPORT void opus_dred_decoder_destroy(OpusDREDDecoder *dec); + + /** Gets the size of an <code>OpusDRED</code> structure. * @returns The size in bytes. @@ -544,13 +573,14 @@ OPUS_EXPORT void opus_dred_destroy(OpusDRED *dec); * @param [in] defer_processing <tt>int</tt>: Flag (0 or 1). If set to one, the CPU-intensive part of the DRED decoding is deferred until opus_dred_process() is called. * @returns Number of decoded DRED samples or @ref opus_errorcodes */ -OPUS_EXPORT 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) OPUS_ARG_NONNULL(1); +OPUS_EXPORT 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 defer_processing) OPUS_ARG_NONNULL(1); /** Finish decoding an Opus DRED packet. The function only needs to be called if opus_dred_parse() was called with defer_processing=1. + * The source and destination will often be the same DRED state. * @param [in] dred <tt>OpusDRED*</tt>: DRED state * @returns @ref opus_errorcodes */ -OPUS_EXPORT int opus_dred_process(OpusDRED *dred); +OPUS_EXPORT int opus_dred_process(OpusDREDDecoder *dred_dec, const OpusDRED *src, OpusDRED *dst); /** Decode audio from an Opus DRED packet with floating point output. * @param [in] st <tt>OpusDecoder*</tt>: Decoder state diff --git a/src/opus_decoder.c b/src/opus_decoder.c index d0ef18f2..bf2f38ed 100644 --- a/src/opus_decoder.c +++ b/src/opus_decoder.c @@ -1089,6 +1089,69 @@ int opus_decoder_get_nb_samples(const OpusDecoder *dec, return opus_packet_get_nb_samples(packet, len, dec->Fs); } +struct OpusDREDDecoder { + int arch; + opus_uint32 magic; +}; + +#if 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); +} + +int opus_dred_decoder_init(OpusDREDDecoder *dec) +{ + dec->arch = opus_select_arch(); + /* To make sure nobody forgets to init, use a magic number. */ + dec->magic = 0xD8EDDEC0; + return OPUS_OK; +} + +OpusDREDDecoder *opus_dred_decoder_create(int *error) +{ + int ret; + OpusDREDDecoder *dec; + dec = (OpusDREDDecoder *)opus_alloc(opus_dred_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) +{ + dec->magic = 0xDE57801D; + free(dec); +} + + + #ifdef ENABLE_NEURAL_FEC static int dred_find_payload(const unsigned char *data, opus_int32 len, const unsigned char **payload) { @@ -1144,11 +1207,12 @@ static int dred_find_payload(const unsigned char *data, opus_int32 len, const un } #endif -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) +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 defer_processing) { #ifdef ENABLE_NEURAL_FEC const unsigned char *payload; opus_int32 payload_len; + VALIDATE_DRED_DECODER(dred_dec); payload_len = dred_find_payload(data, len, &payload); if (payload_len < 0) return payload_len; @@ -1160,7 +1224,7 @@ int opus_dred_parse(OpusDRED *dred, const unsigned char *data, opus_int32 len, o 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); + opus_dred_process(dred_dec, dred, dred); return dred->nb_latents*sampling_rate/25 - sampling_rate/50; } return 0; @@ -1175,13 +1239,18 @@ int opus_dred_parse(OpusDRED *dred, const unsigned char *data, opus_int32 len, o #endif } -int opus_dred_process(OpusDRED *dred) +int opus_dred_process(OpusDREDDecoder *dred_dec, const OpusDRED *src, OpusDRED *dst) { #ifdef ENABLE_NEURAL_FEC - if (dred->process_stage == 2) + if (dred_dec == NULL) + return OPUS_BAD_ARG; + VALIDATE_DRED_DECODER(dred_dec); + if (src != dst) + OPUS_COPY(dst, src, 1); + if (dst->process_stage == 2) return OPUS_OK; - DRED_rdovae_decode_all(dred->fec_features, dred->state, dred->latents, dred->nb_latents); - dred->process_stage = 2; + DRED_rdovae_decode_all(dst->fec_features, dst->state, dst->latents, dst->nb_latents); + dst->process_stage = 2; return OPUS_OK; #else (void)dred; diff --git a/src/opus_demo.c b/src/opus_demo.c index 2cad2986..7992050e 100644 --- a/src/opus_demo.c +++ b/src/opus_demo.c @@ -218,6 +218,7 @@ int main(int argc, char *argv[]) OpusEncoder *enc=NULL; OpusDecoder *dec=NULL; OpusDRED *dred=NULL; + OpusDREDDecoder *dred_dec=NULL; int args; int len; int frame_size, channels; @@ -630,6 +631,7 @@ int main(int argc, char *argv[]) opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration)); frame_size = 2*48000; } + dred_dec = opus_dred_decoder_create(&err); dred = opus_dred_create(&err); while (!stop) { @@ -803,7 +805,7 @@ int main(int argc, char *argv[]) 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_dred_parse(dred, data, len, IMIN(100, IMAX(0, dred_input))*480, 48000, 0); + opus_dred_parse(dred_dec, 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++) { @@ -917,6 +919,7 @@ failure: opus_encoder_destroy(enc); opus_decoder_destroy(dec); opus_dred_destroy(dred); + opus_dred_decoder_destroy(dred_dec); free(data); if (fin) fclose(fin); |