Coverage Report

Created: 2026-10-17 07:52

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
7.23M
{
172
7.23M
   if (size < 252)
173
7.20M
   {
174
7.20M
      data[0] = size;
175
7.20M
      return 1;
176
7.20M
   } else {
177
28.8k
      data[0] = 252+(size&0x3);
178
28.8k
      data[1] = (size-(int)data[0])>>2;
179
28.8k
      return 2;
180
28.8k
   }
181
7.23M
}
182
183
static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size)
184
1.42M
{
185
1.42M
   if (len<1)
186
1.61k
   {
187
1.61k
      *size = -1;
188
1.61k
      return -1;
189
1.42M
   } else if (data[0]<252)
190
1.40M
   {
191
1.40M
      *size = data[0];
192
1.40M
      return 1;
193
1.40M
   } else if (len<2)
194
620
   {
195
620
      *size = -1;
196
620
      return -1;
197
12.9k
   } else {
198
12.9k
      *size = 4*data[1] + data[0];
199
12.9k
      return 2;
200
12.9k
   }
201
1.42M
}
202
203
int opus_packet_get_samples_per_frame(const unsigned char *data,
204
      opus_int32 Fs)
205
133M
{
206
133M
   int audiosize;
207
133M
   if (data[0]&0x80)
208
40.0M
   {
209
40.0M
      audiosize = ((data[0]>>3)&0x3);
210
40.0M
      audiosize = (Fs<<audiosize)/400;
211
93.5M
   } else if ((data[0]&0x60) == 0x60)
212
2.89M
   {
213
2.89M
      audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;
214
90.6M
   } else {
215
90.6M
      audiosize = ((data[0]>>3)&0x3);
216
90.6M
      if (audiosize == 3)
217
6.59M
         audiosize = Fs*60/1000;
218
84.0M
      else
219
84.0M
         audiosize = (Fs<<audiosize)/100;
220
90.6M
   }
221
133M
   return audiosize;
222
133M
}
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
83.8M
{
230
83.8M
   int i, bytes;
231
83.8M
   int count;
232
83.8M
   int cbr;
233
83.8M
   unsigned char ch, toc;
234
83.8M
   int framesize;
235
83.8M
   opus_int32 last_size;
236
83.8M
   opus_int32 pad = 0;
237
83.8M
   const unsigned char *data0 = data;
238
239
   /* Make sure we return NULL/0 on error. */
240
83.8M
   if (padding != NULL)
241
83.5M
   {
242
83.5M
      *padding = NULL;
243
83.5M
      *padding_len = 0;
244
83.5M
   }
245
246
83.8M
   if (size==NULL || len<0)
247
0
      return OPUS_BAD_ARG;
248
83.8M
   if (len==0)
249
0
      return OPUS_INVALID_PACKET;
250
251
83.8M
   framesize = opus_packet_get_samples_per_frame(data, 48000);
252
253
83.8M
   cbr = 0;
254
83.8M
   toc = *data++;
255
83.8M
   len--;
256
83.8M
   last_size = len;
257
83.8M
   switch (toc&0x3)
258
83.8M
   {
259
   /* One frame */
260
76.2M
   case 0:
261
76.2M
      count=1;
262
76.2M
      break;
263
   /* Two CBR frames */
264
108k
   case 1:
265
108k
      count=2;
266
108k
      cbr = 1;
267
108k
      if (!self_delimited)
268
21.7k
      {
269
21.7k
         if (len&0x1)
270
295
            return OPUS_INVALID_PACKET;
271
21.5k
         last_size = len/2;
272
         /* If last_size doesn't fit in size[0], we'll catch it later */
273
21.5k
         size[0] = (opus_int16)last_size;
274
21.5k
      }
275
108k
      break;
276
   /* Two VBR frames */
277
160k
   case 2:
278
160k
      count = 2;
279
160k
      bytes = parse_size(data, len, size);
280
160k
      len -= bytes;
281
160k
      if (size[0]<0 || size[0] > len)
282
2.19k
         return OPUS_INVALID_PACKET;
283
158k
      data += bytes;
284
158k
      last_size = len-size[0];
285
158k
      break;
286
   /* Multiple CBR/VBR frames (from 0 to 120 ms) */
287
7.26M
   default: /*case 3:*/
288
7.26M
      if (len<1)
289
23
         return OPUS_INVALID_PACKET;
290
      /* Number of frames encoded in bits 0 to 5 */
291
7.26M
      ch = *data++;
292
7.26M
      count = ch&0x3F;
293
7.26M
      if (count <= 0 || framesize*(opus_int32)count > 5760)
294
91
         return OPUS_INVALID_PACKET;
295
7.26M
      len--;
296
      /* Padding flag is bit 6 */
297
7.26M
      if (ch&0x40)
298
7.10M
      {
299
7.10M
         int p;
300
7.34M
         do {
301
7.34M
            int tmp;
302
7.34M
            if (len<=0)
303
908
               return OPUS_INVALID_PACKET;
304
7.34M
            p = *data++;
305
7.34M
            len--;
306
7.34M
            tmp = p==255 ? 254: p;
307
7.34M
            len -= tmp;
308
7.34M
            pad += tmp;
309
7.34M
         } while (p==255);
310
7.10M
      }
311
7.26M
      if (len<0)
312
506
         return OPUS_INVALID_PACKET;
313
      /* VBR flag is bit 7 */
314
7.26M
      cbr = !(ch&0x80);
315
7.26M
      if (!cbr)
316
80.6k
      {
317
         /* VBR case */
318
80.6k
         last_size = len;
319
871k
         for (i=0;i<count-1;i++)
320
792k
         {
321
792k
            bytes = parse_size(data, len, size+i);
322
792k
            len -= bytes;
323
792k
            if (size[i]<0 || size[i] > len)
324
1.57k
               return OPUS_INVALID_PACKET;
325
790k
            data += bytes;
326
790k
            last_size -= bytes+size[i];
327
790k
         }
328
79.1k
         if (last_size<0)
329
521
            return OPUS_INVALID_PACKET;
330
7.18M
      } else if (!self_delimited)
331
7.16M
      {
332
         /* CBR case */
333
7.16M
         last_size = len/count;
334
7.16M
         if (last_size*count!=len)
335
356
            return OPUS_INVALID_PACKET;
336
7.45M
         for (i=0;i<count-1;i++)
337
290k
            size[i] = (opus_int16)last_size;
338
7.16M
      }
339
7.26M
      break;
340
83.8M
   }
341
   /* Self-delimited framing has an extra size for the last frame. */
342
83.8M
   if (self_delimited)
343
471k
   {
344
471k
      bytes = parse_size(data, len, size+count-1);
345
471k
      len -= bytes;
346
471k
      if (size[count-1]<0 || size[count-1] > len)
347
200
         return OPUS_INVALID_PACKET;
348
471k
      data += bytes;
349
      /* For CBR packets, apply the size to all the frames. */
350
471k
      if (cbr)
351
104k
      {
352
104k
         if (size[count-1]*count > len)
353
130
            return OPUS_INVALID_PACKET;
354
242k
         for (i=0;i<count-1;i++)
355
138k
            size[i] = size[count-1];
356
367k
      } else if (bytes+size[count-1] > last_size)
357
54
         return OPUS_INVALID_PACKET;
358
471k
   } else
359
83.3M
   {
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
83.3M
      if (last_size > 1275)
364
677
         return OPUS_INVALID_PACKET;
365
83.3M
      size[count-1] = (opus_int16)last_size;
366
83.3M
   }
367
368
83.8M
   if (payload_offset)
369
283k
      *payload_offset = (int)(data-data0);
370
371
168M
   for (i=0;i<count;i++)
372
85.1M
   {
373
85.1M
      if (frames)
374
83.5M
         frames[i] = data;
375
85.1M
      data += size[i];
376
85.1M
   }
377
378
83.8M
   if (padding != NULL)
379
83.5M
   {
380
83.5M
      *padding = data;
381
83.5M
      *padding_len = pad;
382
83.5M
   }
383
83.8M
   if (packet_offset)
384
573k
      *packet_offset = pad+(opus_int32)(data-data0);
385
386
83.8M
   if (out_toc)
387
83.8M
      *out_toc = toc;
388
389
83.8M
   return count;
390
83.8M
}
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
}