diff --git a/include/opus.h b/include/opus.h index f540a55e7e1f25066594876eee0871c9af2a9989..cde0f20cace7dfa9f2ec1b278282b4f7491015cb 100644 --- a/include/opus.h +++ b/include/opus.h @@ -399,6 +399,11 @@ OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NON typedef struct OpusDecoder OpusDecoder; +/** Opus DRED state. + * This contains the complete state of an Opus DRED packet. + * It is position independent and can be freely copied. + * @see opus_dred_create,opus_dred_init + */ typedef struct OpusDRED OpusDRED; /** Gets the size of an <code>OpusDecoder</code> structure. @@ -514,18 +519,62 @@ 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>OpusDRED</code> structure. + * @returns The size in bytes. + */ OPUS_EXPORT int opus_dred_get_size(void); +/** Allocates and initializes a DRED state. + * @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes + */ OPUS_EXPORT OpusDRED *opus_dred_create(int *error); +/** Frees an <code>OpusDRED</code> allocated by opus_dred_create(). + * @param[in] st <tt>OpusDRED*</tt>: State to be freed. + */ OPUS_EXPORT void opus_dred_destroy(OpusDRED *dec); +/** Decode an Opus DRED packet. + * @param [in] dred <tt>OpusDRED*</tt>: DRED state + * @param [in] data <tt>char*</tt>: Input payload + * @param [in] len <tt>opus_int32</tt>: Number of bytes in payload + * @param [in] max_dred_samples <tt>opus_int32</tt>: Maximum number of DRED samples that may be needed (if available in the packet). + * @param [in] sampling_rate <tt>opus_int32</tt>: Sampling rate used for max_dred_samples argument. Needs not match the actual sampling rate of the decoder. + * @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); +/** Finish decoding an Opus DRED packet. The function only needs to be called if opus_dred_parse() was called with defer_processing=1. + * @param [in] dred <tt>OpusDRED*</tt>: DRED state + * @returns @ref opus_errorcodes + */ OPUS_EXPORT int opus_dred_process(OpusDRED *dred); -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); +/** Decode audio from an Opus DRED packet with floating point output. + * @param [in] st <tt>OpusDecoder*</tt>: Decoder state + * @param [in] dred <tt>OpusDRED*</tt>: DRED state + * @param [in] dred_offset <tt>opus_int32</tt>: position of the redundancy to decode (in samples before the beginning of the real audio data in the packet). + * @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel to decode in \a pcm. + * frame_size <b>must</b> be a multiple of 2.5 ms. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, opus_int32 dred_offset, opus_int16 *pcm, opus_int32 frame_size); + +/** Decode audio from an Opus DRED packet with floating point output. + * @param [in] st <tt>OpusDecoder*</tt>: Decoder state + * @param [in] dred <tt>OpusDRED*</tt>: DRED state + * @param [in] dred_offset <tt>opus_int32</tt>: position of the redundancy to decode (in samples before the beginning of the real audio data in the packet). + * @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel to decode in \a pcm. + * frame_size <b>must</b> be a multiple of 2.5 ms. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_decoder_dred_output_float(OpusDecoder *st, OpusDRED *dred, opus_int32 dred_offset, float *pcm, opus_int32 frame_size); /** Parse an opus packet into one or more frames. @@ -600,7 +649,12 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned */ 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); +/** Checks whether an Opus packet has LBRR. + * @param [in] data <tt>char*</tt>: Opus packet + * @returns 1 is LBRR is present, 0 otherwise + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_has_lbrr(const unsigned char packet[], opus_int32 len); /** Gets the number of samples of an Opus packet. * @param [in] dec <tt>OpusDecoder*</tt>: Decoder state diff --git a/src/opus_decoder.c b/src/opus_decoder.c index 93dc403606f61526b816e69e464af1c83b75eb84..8d529ceee532d7952b091d2c2000f5ceb69f9b6f 100644 --- a/src/opus_decoder.c +++ b/src/opus_decoder.c @@ -659,7 +659,7 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data, 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 + (dred_offset-1)*features_per_frame); + int feature_offset = (needed_feature_frames-i-1 + (dred_offset/(st->Fs/100)-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 { @@ -1055,7 +1055,7 @@ int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, return samples; } -int opus_packet_has_fec(const unsigned char packet[], opus_int32 len) +int opus_packet_has_lbrr(const unsigned char packet[], opus_int32 len) { int ret; const unsigned char *frames[48]; @@ -1073,7 +1073,7 @@ int opus_packet_has_fec(const unsigned char packet[], opus_int32 len) packet_stream_channels = opus_packet_get_nb_channels(packet); ret = opus_packet_parse(packet, len, NULL, frames, size, NULL); if (ret <= 0) - return 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); @@ -1165,12 +1165,14 @@ int opus_dred_parse(OpusDRED *dred, const unsigned char *data, opus_int32 len, o int opus_dred_process(OpusDRED *dred) { + if (dred->process_stage == 2) + return OPUS_OK; DRED_rdovae_decode_all(dred->fec_features, dred->state, dred->latents, dred->nb_latents); dred->process_stage = 2; return OPUS_OK; } -int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, int dred_offset, opus_int16 *pcm, int frame_size) +int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, opus_int32 dred_offset, opus_int16 *pcm, opus_int32 frame_size) { VARDECL(float, out); int ret, i; @@ -1195,7 +1197,7 @@ int opus_decoder_dred_output(OpusDecoder *st, OpusDRED *dred, int dred_offset, o return ret; } -int opus_decoder_dred_output_float(OpusDecoder *st, OpusDRED *dred, int dred_offset, float *pcm, int frame_size) +int opus_decoder_dred_output_float(OpusDecoder *st, OpusDRED *dred, opus_int32 dred_offset, float *pcm, opus_int32 frame_size) { if(frame_size<=0) return OPUS_BAD_ARG; diff --git a/src/opus_demo.c b/src/opus_demo.c index e0c8e4d697e626fff993ffca34885993dc590e46..6c45a564a352d8867ff0d37669064bcab0976bfd 100644 --- a/src/opus_demo.c +++ b/src/opus_demo.c @@ -808,15 +808,12 @@ int main(int argc, char *argv[]) /* FIXME: Figure out how to trigger the decoder when the last packet of the file is lost. */ for (fr=0;fr<run_decoder;fr++) { opus_int32 output_samples=0; - if (fr < lost_count-1) { - opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples)); - 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)) { + if (fr == lost_count-1 && opus_packet_has_lbrr(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) { + } else if (fr < lost_count) { opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples)); - output_samples = opus_decoder_dred_output(dec, dred, 1, out, output_samples); + output_samples = opus_decoder_dred_output(dec, dred, (lost_count-fr)*sampling_rate/100, out, output_samples); } else { output_samples = max_frame_size; output_samples = opus_decode(dec, data, len, out, output_samples, 0);