shithub: opus

Download patch

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);
--