ref: 5ad2aebd905f92c8d2e737a6a6e0b813bdb7e72e
parent: 3dc9c6eda61e12c35b71780101eaa82d8ca58d03
author: Jean-Marc Valin <jmvalin@amazon.com>
date: Mon Nov 28 11:34:28 EST 2022
Code for inserting/extracting DRED in/from packets
--- a/include/opus.h
+++ b/include/opus.h
@@ -511,6 +511,9 @@
*/
OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
+OPUS_EXPORT int opus_decoder_dred_input(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, int offset) OPUS_ARG_NONNULL(1);
+
/** 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.
--- a/src/extensions.c
+++ b/src/extensions.c
@@ -38,7 +38,7 @@
/* Given an extension payload, advance data to the next extension and return the
length of the remaining extensions. */
-static opus_int32 skip_extension(const unsigned char **data, opus_int32 len, opus_int32 *header_size)
+opus_int32 skip_extension(const unsigned char **data, opus_int32 len, opus_int32 *header_size)
{
int id, L;
if (len==0)
--- a/src/opus.c
+++ b/src/opus.c
@@ -194,7 +194,8 @@
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 @@
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 @@
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);
}
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -672,7 +672,7 @@
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;
@@ -1038,4 +1038,55 @@
const unsigned char packet[], opus_int32 len)
{
return opus_packet_get_nb_samples(packet, len, dec->Fs);
+}
+
+int opus_decoder_dred_input(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, int offset)
+{
+ const unsigned char *data0;
+ int len0;
+ const unsigned char *payload = NULL;
+ opus_int32 payload_len;
+ int frame = 0;
+ int ret;
+ const unsigned char *frames[48];
+ opus_int16 size[48];
+
+ /* Get the padding section of the packet. */
+ ret = opus_packet_parse_impl(data, len, 0, NULL, frames, size, NULL, NULL, &data0, &len0);
+ 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 += data[1];
+ }
+ } else if (id == 127)
+ {
+ payload = data0+header_size;
+ payload_len = (data-data0)-header_size;
+ break;
+ }
+ }
+ if (payload != NULL)
+ {
+ /* Found something -- do the decoding. */
+ return 1;
+ }
+ return 0;
}
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -1003,6 +1003,7 @@
}
}
+ /* FIXME: Handle extensions here. */
ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr, NULL, 0);
if (ret<0)
@@ -2178,7 +2179,15 @@
}
/* Count ToC and redundancy */
ret += 1+redundancy_bytes;
- if (!st->use_vbr)
+ if (0) {
+ opus_extension_data extension = {127, 0, (const unsigned char *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 50};
+ ret = opus_packet_pad_impl(data, ret, max_data_bytes, !st->use_vbr, &extension, 1);
+ if (ret < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ } else if (!st->use_vbr)
{
if (opus_packet_pad(data, ret, max_data_bytes) != OPUS_OK)
{
--- a/src/opus_multistream_decoder.c
+++ b/src/opus_multistream_decoder.c
@@ -162,7 +162,7 @@
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);
--- a/src/opus_private.h
+++ b/src/opus_private.h
@@ -169,10 +169,14 @@
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,
@@ -209,5 +213,7 @@
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_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 */
--- a/src/repacketizer.c
+++ b/src/repacketizer.c
@@ -82,7 +82,7 @@
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, NULL, NULL);
if(ret<1)return ret;
rp->nb_frames += curr_nb_frames;
@@ -251,7 +251,7 @@
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;
@@ -267,7 +267,12 @@
ret = opus_repacketizer_cat(&rp, data+new_len-len, len);
if (ret != OPUS_OK)
return ret;
- ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1, NULL, 0);
+ return opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, pad, extensions, nb_extensions);
+}
+
+int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
+{
+ opus_int32 ret = opus_packet_pad_impl(data, len, new_len, 1, NULL, 0);
if (ret > 0)
return OPUS_OK;
else
@@ -311,7 +316,7 @@
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;
@@ -343,7 +348,7 @@
return OPUS_INVALID_PACKET;
opus_repacketizer_init(&rp);
ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
- size, NULL, &packet_offset);
+ size, NULL, &packet_offset, NULL, NULL);
if (ret<0)
return ret;
ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited);
--
⑨