Coverage Report

Created: 2026-05-30 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opus/src/opus.c
Line
Count
Source
1
/* Copyright (c) 2011 Xiph.Org Foundation, Skype Limited
2
   Copyright (c) 2024 Arm Limited
3
   Written by Jean-Marc Valin and Koen Vos */
4
/*
5
   Redistribution and use in source and binary forms, with or without
6
   modification, are permitted provided that the following conditions
7
   are met:
8
9
   - Redistributions of source code must retain the above copyright
10
   notice, this list of conditions and the following disclaimer.
11
12
   - Redistributions in binary form must reproduce the above copyright
13
   notice, this list of conditions and the following disclaimer in the
14
   documentation and/or other materials provided with the distribution.
15
16
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20
   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
*/
28
29
#ifdef HAVE_CONFIG_H
30
#include "config.h"
31
#endif
32
33
#include "opus.h"
34
#include "mathops.h"
35
#include "opus_private.h"
36
37
#ifndef DISABLE_FLOAT_API
38
39
void opus_pcm_soft_clip_impl(float *_x, int N, int C, float *declip_mem, int arch)
40
0
{
41
0
   int c;
42
0
   int i;
43
0
   float *x;
44
0
   int all_within_neg1pos1;
45
46
0
   if (C<1 || N<1 || !_x || !declip_mem) return;
47
48
   /* Clamp everything within the range [-2, +2] which is the domain of the soft
49
      clipping non-linearity. Outside the defined range the derivative will be zero,
50
      therefore there is no discontinuity introduced here. The implementation
51
      might provide a hint if all input samples are within the [-1, +1] range.
52
53
   `opus_limit2_checkwithin1()`:
54
      - Clamps all samples within the valid range [-2, +2].
55
      - Generic C implementation:
56
         * Does not attempt early detection whether samples are within hinted range.
57
         * Always returns 0.
58
      - Architecture specific implementation:
59
         * Uses SIMD instructions to efficiently detect if all samples are
60
           within the hinted range [-1, +1].
61
         * Returns 1 if no samples exceed the hinted range, 0 otherwise.
62
63
   `all_within_neg1pos1`:
64
      - Optimization hint to skip per-sample out-of-bound checks.
65
        If true, the check can be skipped. */
66
0
   all_within_neg1pos1 = opus_limit2_checkwithin1(_x, N*C, arch);
67
68
0
   for (c=0;c<C;c++)
69
0
   {
70
0
      float a;
71
0
      float x0;
72
0
      int curr;
73
74
0
      x = _x+c;
75
0
      a = declip_mem[c];
76
      /* Continue applying the non-linearity from the previous frame to avoid
77
         any discontinuity. */
78
0
      for (i=0;i<N;i++)
79
0
      {
80
0
         if (x[i*C]*a>=0)
81
0
            break;
82
0
         x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
83
0
      }
84
85
0
      curr=0;
86
0
      x0 = x[0];
87
0
      while(1)
88
0
      {
89
0
         int start, end;
90
0
         float maxval;
91
0
         int special=0;
92
0
         int peak_pos;
93
         /* Detection for early exit can be skipped if hinted by `all_within_neg1pos1` */
94
0
         if (all_within_neg1pos1)
95
0
         {
96
0
            i = N;
97
0
         } else {
98
0
            for (i=curr;i<N;i++)
99
0
            {
100
0
               if (x[i*C]>1 || x[i*C]<-1)
101
0
                  break;
102
0
            }
103
0
         }
104
0
         if (i==N)
105
0
         {
106
0
            a=0;
107
0
            break;
108
0
         }
109
0
         peak_pos = i;
110
0
         start=end=i;
111
0
         maxval=ABS16(x[i*C]);
112
         /* Look for first zero crossing before clipping */
113
0
         while (start>0 && x[i*C]*x[(start-1)*C]>=0)
114
0
            start--;
115
         /* Look for first zero crossing after clipping */
116
0
         while (end<N && x[i*C]*x[end*C]>=0)
117
0
         {
118
            /* Look for other peaks until the next zero-crossing. */
119
0
            if (ABS16(x[end*C])>maxval)
120
0
            {
121
0
               maxval = ABS16(x[end*C]);
122
0
               peak_pos = end;
123
0
            }
124
0
            end++;
125
0
         }
126
         /* Detect the special case where we clip before the first zero crossing */
127
0
         special = (start==0 && x[i*C]*x[0]>=0);
128
129
         /* Compute a such that maxval + a*maxval^2 = 1 */
130
0
         a=(maxval-1)/(maxval*maxval);
131
         /* Slightly boost "a" by 2^-22. This is just enough to ensure -ffast-math
132
            does not cause output values larger than +/-1, but small enough not
133
            to matter even for 24-bit output.  */
134
0
         a += a*2.4e-7f;
135
0
         if (x[i*C]>0)
136
0
            a = -a;
137
         /* Apply soft clipping */
138
0
         for (i=start;i<end;i++)
139
0
            x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
140
141
0
         if (special && peak_pos>=2)
142
0
         {
143
            /* Add a linear ramp from the first sample to the signal peak.
144
               This avoids a discontinuity at the beginning of the frame. */
145
0
            float delta;
146
0
            float offset = x0-x[0];
147
0
            delta = offset / peak_pos;
148
0
            for (i=curr;i<peak_pos;i++)
149
0
            {
150
0
               offset -= delta;
151
0
               x[i*C] += offset;
152
0
               x[i*C] = MAX16(-1.f, MIN16(1.f, x[i*C]));
153
0
            }
154
0
         }
155
0
         curr = end;
156
0
         if (curr==N)
157
0
            break;
158
0
      }
159
0
      declip_mem[c] = a;
160
0
   }
161
0
}
162
163
OPUS_EXPORT void opus_pcm_soft_clip(float *_x, int N, int C, float *declip_mem)
164
0
{
165
0
   opus_pcm_soft_clip_impl(_x, N, C, declip_mem, 0);
166
0
}
167
168
#endif
169
170
int encode_size(int size, unsigned char *data)
171
1.34k
{
172
1.34k
   if (size < 252)
173
1.22k
   {
174
1.22k
      data[0] = size;
175
1.22k
      return 1;
176
1.22k
   } else {
177
123
      data[0] = 252+(size&0x3);
178
123
      data[1] = (size-(int)data[0])>>2;
179
123
      return 2;
180
123
   }
181
1.34k
}
182
183
static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size)
184
2.30k
{
185
2.30k
   if (len<1)
186
379
   {
187
379
      *size = -1;
188
379
      return -1;
189
1.92k
   } else if (data[0]<252)
190
1.39k
   {
191
1.39k
      *size = data[0];
192
1.39k
      return 1;
193
1.39k
   } else if (len<2)
194
134
   {
195
134
      *size = -1;
196
134
      return -1;
197
393
   } else {
198
393
      *size = 4*data[1] + data[0];
199
393
      return 2;
200
393
   }
201
2.30k
}
202
203
int opus_packet_get_samples_per_frame(const unsigned char *data,
204
      opus_int32 Fs)
205
7.67k
{
206
7.67k
   int audiosize;
207
7.67k
   if (data[0]&0x80)
208
5.19k
   {
209
5.19k
      audiosize = ((data[0]>>3)&0x3);
210
5.19k
      audiosize = (Fs<<audiosize)/400;
211
5.19k
   } else if ((data[0]&0x60) == 0x60)
212
873
   {
213
873
      audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;
214
1.60k
   } else {
215
1.60k
      audiosize = ((data[0]>>3)&0x3);
216
1.60k
      if (audiosize == 3)
217
406
         audiosize = Fs*60/1000;
218
1.19k
      else
219
1.19k
         audiosize = (Fs<<audiosize)/100;
220
1.60k
   }
221
7.67k
   return audiosize;
222
7.67k
}
223
224
int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
225
      int self_delimited, unsigned char *out_toc,
226
      const unsigned char *frames[48], opus_int16 size[48],
227
      int *payload_offset, opus_int32 *packet_offset,
228
      const unsigned char **padding, opus_int32 *padding_len)
229
4.84k
{
230
4.84k
   int i, bytes;
231
4.84k
   int count;
232
4.84k
   int cbr;
233
4.84k
   unsigned char ch, toc;
234
4.84k
   int framesize;
235
4.84k
   opus_int32 last_size;
236
4.84k
   opus_int32 pad = 0;
237
4.84k
   const unsigned char *data0 = data;
238
239
   /* Make sure we return NULL/0 on error. */
240
4.84k
   if (padding != NULL)
241
4.84k
   {
242
4.84k
      *padding = NULL;
243
4.84k
      *padding_len = 0;
244
4.84k
   }
245
246
4.84k
   if (size==NULL || len<0)
247
0
      return OPUS_BAD_ARG;
248
4.84k
   if (len==0)
249
0
      return OPUS_INVALID_PACKET;
250
251
4.84k
   framesize = opus_packet_get_samples_per_frame(data, 48000);
252
253
4.84k
   cbr = 0;
254
4.84k
   toc = *data++;
255
4.84k
   len--;
256
4.84k
   last_size = len;
257
4.84k
   switch (toc&0x3)
258
4.84k
   {
259
   /* One frame */
260
326
   case 0:
261
326
      count=1;
262
326
      break;
263
   /* Two CBR frames */
264
300
   case 1:
265
300
      count=2;
266
300
      cbr = 1;
267
300
      if (!self_delimited)
268
300
      {
269
300
         if (len&0x1)
270
73
            return OPUS_INVALID_PACKET;
271
227
         last_size = len/2;
272
         /* If last_size doesn't fit in size[0], we'll catch it later */
273
227
         size[0] = (opus_int16)last_size;
274
227
      }
275
227
      break;
276
   /* Two VBR frames */
277
716
   case 2:
278
716
      count = 2;
279
716
      bytes = parse_size(data, len, size);
280
716
      len -= bytes;
281
716
      if (size[0]<0 || size[0] > len)
282
522
         return OPUS_INVALID_PACKET;
283
194
      data += bytes;
284
194
      last_size = len-size[0];
285
194
      break;
286
   /* Multiple CBR/VBR frames (from 0 to 120 ms) */
287
3.50k
   default: /*case 3:*/
288
3.50k
      if (len<1)
289
0
         return OPUS_INVALID_PACKET;
290
      /* Number of frames encoded in bits 0 to 5 */
291
3.50k
      ch = *data++;
292
3.50k
      count = ch&0x3F;
293
3.50k
      if (count <= 0 || framesize*(opus_int32)count > 5760)
294
0
         return OPUS_INVALID_PACKET;
295
3.50k
      len--;
296
      /* Padding flag is bit 6 */
297
3.50k
      if (ch&0x40)
298
2.00k
      {
299
2.00k
         int p;
300
3.11k
         do {
301
3.11k
            int tmp;
302
3.11k
            if (len<=0)
303
200
               return OPUS_INVALID_PACKET;
304
2.91k
            p = *data++;
305
2.91k
            len--;
306
2.91k
            tmp = p==255 ? 254: p;
307
2.91k
            len -= tmp;
308
2.91k
            pad += tmp;
309
2.91k
         } while (p==255);
310
2.00k
      }
311
3.30k
      if (len<0)
312
88
         return OPUS_INVALID_PACKET;
313
      /* VBR flag is bit 7 */
314
3.21k
      cbr = !(ch&0x80);
315
3.21k
      if (!cbr)
316
1.02k
      {
317
         /* VBR case */
318
1.02k
         last_size = len;
319
2.29k
         for (i=0;i<count-1;i++)
320
1.58k
         {
321
1.58k
            bytes = parse_size(data, len, size+i);
322
1.58k
            len -= bytes;
323
1.58k
            if (size[i]<0 || size[i] > len)
324
317
               return OPUS_INVALID_PACKET;
325
1.27k
            data += bytes;
326
1.27k
            last_size -= bytes+size[i];
327
1.27k
         }
328
708
         if (last_size<0)
329
96
            return OPUS_INVALID_PACKET;
330
2.18k
      } else if (!self_delimited)
331
2.18k
      {
332
         /* CBR case */
333
2.18k
         last_size = len/count;
334
2.18k
         if (last_size*count!=len)
335
118
            return OPUS_INVALID_PACKET;
336
21.9k
         for (i=0;i<count-1;i++)
337
19.8k
            size[i] = (opus_int16)last_size;
338
2.07k
      }
339
2.68k
      break;
340
4.84k
   }
341
   /* Self-delimited framing has an extra size for the last frame. */
342
3.43k
   if (self_delimited)
343
0
   {
344
0
      bytes = parse_size(data, len, size+count-1);
345
0
      len -= bytes;
346
0
      if (size[count-1]<0 || size[count-1] > len)
347
0
         return OPUS_INVALID_PACKET;
348
0
      data += bytes;
349
      /* For CBR packets, apply the size to all the frames. */
350
0
      if (cbr)
351
0
      {
352
0
         if (size[count-1]*count > len)
353
0
            return OPUS_INVALID_PACKET;
354
0
         for (i=0;i<count-1;i++)
355
0
            size[i] = size[count-1];
356
0
      } else if (bytes+size[count-1] > last_size)
357
0
         return OPUS_INVALID_PACKET;
358
0
   } else
359
3.43k
   {
360
      /* Because it's not encoded explicitly, it's possible the size of the
361
         last packet (or all the packets, for the CBR case) is larger than
362
         1275. Reject them here.*/
363
3.43k
      if (last_size > 1275)
364
79
         return OPUS_INVALID_PACKET;
365
3.35k
      size[count-1] = (opus_int16)last_size;
366
3.35k
   }
367
368
3.35k
   if (payload_offset)
369
0
      *payload_offset = (int)(data-data0);
370
371
27.2k
   for (i=0;i<count;i++)
372
23.8k
   {
373
23.8k
      if (frames)
374
23.8k
         frames[i] = data;
375
23.8k
      data += size[i];
376
23.8k
   }
377
378
3.35k
   if (padding != NULL)
379
3.35k
   {
380
3.35k
      *padding = data;
381
3.35k
      *padding_len = pad;
382
3.35k
   }
383
3.35k
   if (packet_offset)
384
0
      *packet_offset = pad+(opus_int32)(data-data0);
385
386
3.35k
   if (out_toc)
387
3.35k
      *out_toc = toc;
388
389
3.35k
   return count;
390
3.43k
}
391
392
int opus_packet_parse(const unsigned char *data, opus_int32 len,
393
      unsigned char *out_toc, const unsigned char *frames[48],
394
      opus_int16 size[48], int *payload_offset)
395
0
{
396
0
   return opus_packet_parse_impl(data, len, 0, out_toc,
397
0
                                 frames, size, payload_offset, NULL, NULL, NULL);
398
0
}