ref: 4402b00fd303dcff5c3a6bb4ed77b7a85281b397
parent: 75f0dbcad097eceb6bdd35771f53478e01451fc7
author: Jean-Marc Valin <jmvalin@amazon.com>
date: Sat May 13 20:45:30 EDT 2023
Add API doc, change DRED offsets to be samples
--- a/include/opus.h
+++ b/include/opus.h
@@ -399,6 +399,11 @@
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,20 +519,64 @@
*/
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.
* Opus_decode will perform this operation internally so most applications do
* not need to use this function.
@@ -600,7 +649,12 @@
*/
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
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -659,7 +659,7 @@
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 @@
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 @@
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_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 @@
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;
--- a/src/opus_demo.c
+++ b/src/opus_demo.c
@@ -808,15 +808,12 @@
/* 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) {
+ 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_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) {
+ } 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);
--
⑨