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