xref: /aosp_15_r20/external/libopus/src/extensions.c (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
1 /* Copyright (c) 2022 Amazon */
2 /*
3    Redistribution and use in source and binary forms, with or without
4    modification, are permitted provided that the following conditions
5    are met:
6 
7    - Redistributions of source code must retain the above copyright
8    notice, this list of conditions and the following disclaimer.
9 
10    - Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 
14    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
18    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 
32 #include "opus_types.h"
33 #include "opus_defines.h"
34 #include "arch.h"
35 #include "os_support.h"
36 #include "opus_private.h"
37 
38 
39 /* Given an extension payload, advance data to the next extension and return the
40    length of the remaining extensions. */
skip_extension(const unsigned char ** data,opus_int32 len,opus_int32 * header_size)41 opus_int32 skip_extension(const unsigned char **data, opus_int32 len, opus_int32 *header_size)
42 {
43    int id, L;
44    if (len==0)
45       return 0;
46    id = **data>>1;
47    L = **data&1;
48    if (id == 0 && L == 1)
49    {
50       *header_size = 1;
51       if (len < 1)
52          return -1;
53       (*data)++;
54       len--;
55       return len;
56    } else if (id > 0 && id < 32)
57    {
58       if (len < 1+L)
59          return -1;
60       *data += 1+L;
61       len -= 1+L;
62       *header_size = 1;
63       return len;
64    } else {
65       if (L==0)
66       {
67          *data += len;
68          *header_size = 1;
69          return 0;
70       } else {
71          opus_int32 bytes=0;
72          *header_size = 1;
73          do {
74             (*data)++;
75             len--;
76             if (len == 0)
77                return -1;
78             bytes += **data;
79             (*header_size)++;
80          } while (**data == 255);
81          (*data)++;
82          len--;
83          if (bytes <= len)
84          {
85             len -= bytes;
86             *data += bytes;
87          } else {
88             return -1;
89          }
90          return len;
91       }
92    }
93 }
94 
95 /* Count the number of extensions, excluding real padding and separators. */
opus_packet_extensions_count(const unsigned char * data,opus_int32 len)96 opus_int32 opus_packet_extensions_count(const unsigned char *data, opus_int32 len)
97 {
98    opus_int32 curr_len;
99    opus_int32 count=0;
100    const unsigned char *curr_data = data;
101 
102    celt_assert(len >= 0);
103    celt_assert(data != NULL || len == 0);
104 
105    curr_len = len;
106    while (curr_len > 0)
107    {
108       int id;
109       opus_int32 header_size;
110       id = *curr_data>>1;
111       curr_len = skip_extension(&curr_data, curr_len, &header_size);
112       if (curr_len < 0)
113          return OPUS_INVALID_PACKET;
114       if (id > 1)
115          count++;
116    }
117    return count;
118 }
119 
120 /* Extract extensions from Opus padding (excluding real padding and separators) */
opus_packet_extensions_parse(const unsigned char * data,opus_int32 len,opus_extension_data * extensions,opus_int32 * nb_extensions)121 opus_int32 opus_packet_extensions_parse(const unsigned char *data, opus_int32 len, opus_extension_data *extensions, opus_int32 *nb_extensions)
122 {
123    const unsigned char *curr_data;
124    opus_int32 curr_len;
125    int curr_frame=0;
126    opus_int32 count=0;
127 
128    celt_assert(len >= 0);
129    celt_assert(data != NULL || len == 0);
130    celt_assert(nb_extensions != NULL);
131    celt_assert(extensions != NULL || *nb_extensions == 0);
132 
133    curr_data = data;
134    curr_len = len;
135    while (curr_len > 0)
136    {
137       int id;
138       opus_int32 header_size;
139       opus_extension_data curr_ext;
140       id = *curr_data>>1;
141       if (id > 1)
142       {
143          curr_ext.id = id;
144          curr_ext.frame = curr_frame;
145          curr_ext.data = curr_data;
146       } else if (id == 1)
147       {
148          int L = *curr_data&1;
149          if (L==0)
150             curr_frame++;
151          else {
152             if (curr_len >= 2)
153                curr_frame += curr_data[1];
154             /* Else we're at the end and it doesn't matter. */
155          }
156          if (curr_frame >= 48)
157          {
158             *nb_extensions = count;
159             return OPUS_INVALID_PACKET;
160          }
161       }
162       curr_len = skip_extension(&curr_data, curr_len, &header_size);
163       /* printf("curr_len = %d, header_size = %d\n", curr_len, header_size); */
164       if (curr_len < 0)
165       {
166          *nb_extensions = count;
167          return OPUS_INVALID_PACKET;
168       }
169       celt_assert(curr_data - data == len - curr_len);
170       if (id > 1)
171       {
172          if (count == *nb_extensions)
173          {
174              return OPUS_BUFFER_TOO_SMALL;
175          }
176          curr_ext.len = curr_data - curr_ext.data - header_size;
177          curr_ext.data += header_size;
178          extensions[count++] = curr_ext;
179       }
180    }
181    celt_assert(curr_len == 0);
182    *nb_extensions = count;
183    return OPUS_OK;
184 }
185 
opus_packet_extensions_generate(unsigned char * data,opus_int32 len,const opus_extension_data * extensions,opus_int32 nb_extensions,int pad)186 opus_int32 opus_packet_extensions_generate(unsigned char *data, opus_int32 len, const opus_extension_data  *extensions, opus_int32 nb_extensions, int pad)
187 {
188    int max_frame=0;
189    opus_int32 i;
190    int frame;
191    int curr_frame = 0;
192    opus_int32 pos = 0;
193    opus_int32 written = 0;
194 
195    celt_assert(len >= 0);
196 
197    for (i=0;i<nb_extensions;i++)
198    {
199       max_frame = IMAX(max_frame, extensions[i].frame);
200       if (extensions[i].id < 2 || extensions[i].id > 127)
201          return OPUS_BAD_ARG;
202    }
203    if (max_frame >= 48) return OPUS_BAD_ARG;
204    for (frame=0;frame<=max_frame;frame++)
205    {
206       for (i=0;i<nb_extensions;i++)
207       {
208          if (extensions[i].frame == frame)
209          {
210             /* Insert separator when needed. */
211             if (frame != curr_frame) {
212                int diff = frame - curr_frame;
213                if (len-pos < 2)
214                   return OPUS_BUFFER_TOO_SMALL;
215                if (diff == 1) {
216                   if (data) data[pos] = 0x02;
217                   pos++;
218                } else {
219                   if (data) data[pos] = 0x03;
220                   pos++;
221                   if (data) data[pos] = diff;
222                   pos++;
223                }
224                curr_frame = frame;
225             }
226             if (extensions[i].id < 32)
227             {
228                if (extensions[i].len < 0 || extensions[i].len > 1)
229                   return OPUS_BAD_ARG;
230                if (len-pos < extensions[i].len+1)
231                   return OPUS_BUFFER_TOO_SMALL;
232                if (data) data[pos] = (extensions[i].id<<1) + extensions[i].len;
233                pos++;
234                if (extensions[i].len > 0) {
235                   if (data) data[pos] = extensions[i].data[0];
236                   pos++;
237                }
238             } else {
239                int last;
240                opus_int32 length_bytes;
241                if (extensions[i].len < 0)
242                   return OPUS_BAD_ARG;
243                last = (written == nb_extensions - 1);
244                length_bytes = 1 + extensions[i].len/255;
245                if (last)
246                   length_bytes = 0;
247                if (len-pos < 1 + length_bytes + extensions[i].len)
248                   return OPUS_BUFFER_TOO_SMALL;
249                if (data) data[pos] = (extensions[i].id<<1) + !last;
250                pos++;
251                if (!last)
252                {
253                   opus_int32 j;
254                   for (j=0;j<extensions[i].len/255;j++) {
255                      if (data) data[pos] = 255;
256                      pos++;
257                   }
258                   if (data) data[pos] = extensions[i].len % 255;
259                   pos++;
260                }
261                if (data) OPUS_COPY(&data[pos], extensions[i].data, extensions[i].len);
262                pos += extensions[i].len;
263             }
264             written++;
265          }
266       }
267    }
268    /* If we need to pad, just prepend 0x01 bytes. Even better would be to fill the
269       end with zeros, but that requires checking that turning the last extesion into
270       an L=1 case still fits. */
271    if (pad && pos < len)
272    {
273       opus_int32 padding = len - pos;
274       if (data) {
275          OPUS_MOVE(data+padding, data, pos);
276          for (i=0;i<padding;i++)
277             data[i] = 0x01;
278       }
279       pos += padding;
280    }
281    return pos;
282 }
283 
284 #if 0
285 #include <stdio.h>
286 int main()
287 {
288    opus_extension_data ext[] = {{2, 0, (const unsigned char *)"a", 1},
289    {32, 10, (const unsigned char *)"DRED", 4},
290    {33, 1, (const unsigned char *)"NOT DRED", 8},
291    {3, 4, (const unsigned char *)NULL, 0}
292    };
293    opus_extension_data ext2[10];
294    int i, len;
295    int nb_ext = 10;
296    unsigned char packet[10000];
297    len = opus_packet_extensions_generate(packet, 32, ext, 4, 1);
298    for (i=0;i<len;i++)
299    {
300       printf("%#04x ", packet[i]);
301       if (i%16 == 15)
302          printf("\n");
303    }
304    printf("\n");
305    printf("count = %d\n", opus_packet_extensions_count(packet, len));
306    opus_packet_extensions_parse(packet, len, ext2, &nb_ext);
307    for (i=0;i<nb_ext;i++)
308    {
309       int j;
310       printf("%d %d {", ext2[i].id, ext2[i].frame);
311       for (j=0;j<ext2[i].len;j++) printf("%#04x ", ext2[i].data[j]);
312       printf("} %d\n", ext2[i].len);
313    }
314 }
315 #endif
316