Coverage Report

Created: 2026-02-26 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opus/src/repacketizer.c
Line
Count
Source
1
/* Copyright (c) 2011 Xiph.Org Foundation
2
   Written by Jean-Marc Valin */
3
/*
4
   Redistribution and use in source and binary forms, with or without
5
   modification, are permitted provided that the following conditions
6
   are met:
7
8
   - Redistributions of source code must retain the above copyright
9
   notice, this list of conditions and the following disclaimer.
10
11
   - Redistributions in binary form must reproduce the above copyright
12
   notice, this list of conditions and the following disclaimer in the
13
   documentation and/or other materials provided with the distribution.
14
15
   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18
   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19
   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
*/
27
28
#ifdef HAVE_CONFIG_H
29
#include "config.h"
30
#endif
31
32
#include "opus.h"
33
#include "opus_private.h"
34
#include "os_support.h"
35
#include "stack_alloc.h"
36
37
38
int opus_repacketizer_get_size(void)
39
1.44k
{
40
1.44k
   return sizeof(OpusRepacketizer);
41
1.44k
}
42
43
OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp)
44
2.88k
{
45
2.88k
   rp->nb_frames = 0;
46
2.88k
   return rp;
47
2.88k
}
48
49
OpusRepacketizer *opus_repacketizer_create(void)
50
1.44k
{
51
1.44k
   OpusRepacketizer *rp;
52
1.44k
   rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size());
53
1.44k
   if(rp==NULL)return NULL;
54
1.44k
   return opus_repacketizer_init(rp);
55
1.44k
}
56
57
void opus_repacketizer_destroy(OpusRepacketizer *rp)
58
1.44k
{
59
1.44k
   opus_free(rp);
60
1.44k
}
61
62
static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited)
63
5.49k
{
64
5.49k
   unsigned char tmp_toc;
65
5.49k
   int curr_nb_frames,ret;
66
   /* Set of check ToC */
67
5.49k
   if (len<1) return OPUS_INVALID_PACKET;
68
5.11k
   if (rp->nb_frames == 0)
69
2.71k
   {
70
2.71k
      rp->toc = data[0];
71
2.71k
      rp->framesize = opus_packet_get_samples_per_frame(data, 8000);
72
2.71k
   } else if ((rp->toc&0xFC) != (data[0]&0xFC))
73
92
   {
74
      /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/
75
92
      return OPUS_INVALID_PACKET;
76
92
   }
77
5.02k
   curr_nb_frames = opus_packet_get_nb_frames(data, len);
78
5.02k
   if(curr_nb_frames<1) return OPUS_INVALID_PACKET;
79
80
   /* Check the 120 ms maximum packet size */
81
4.92k
   if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960)
82
72
   {
83
72
      return OPUS_INVALID_PACKET;
84
72
   }
85
86
4.85k
   ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames],
87
4.85k
       NULL, NULL, &rp->paddings[rp->nb_frames], &rp->padding_len[rp->nb_frames]);
88
4.85k
   if(ret<1)return ret;
89
3.30k
   rp->padding_nb_frames[rp->nb_frames]=ret;
90
91
   /* set padding length to zero for all but the first frame */
92
21.2k
   while (curr_nb_frames > 1)
93
17.9k
   {
94
17.9k
      rp->nb_frames++;
95
17.9k
      rp->padding_len[rp->nb_frames] = 0;
96
17.9k
      rp->padding_nb_frames[rp->nb_frames] = 0;
97
17.9k
      rp->paddings[rp->nb_frames] = NULL;
98
17.9k
      curr_nb_frames--;
99
17.9k
   }
100
3.30k
   rp->nb_frames++;
101
3.30k
   return OPUS_OK;
102
4.85k
}
103
104
int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len)
105
5.49k
{
106
5.49k
   return opus_repacketizer_cat_impl(rp, data, len, 0);
107
5.49k
}
108
109
int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp)
110
0
{
111
0
   return rp->nb_frames;
112
0
}
113
114
opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
115
      unsigned char *data, opus_int32 maxlen, int self_delimited, int pad, const opus_extension_data *extensions, int nb_extensions)
116
1.44k
{
117
1.44k
   int i, count;
118
1.44k
   opus_int32 tot_size;
119
1.44k
   opus_int16 *len;
120
1.44k
   const unsigned char **frames;
121
1.44k
   unsigned char * ptr;
122
1.44k
   int ones_begin=0, ones_end=0;
123
1.44k
   int ext_begin=0, ext_len=0;
124
1.44k
   int ext_count, total_ext_count;
125
1.44k
   VARDECL(opus_extension_data, all_extensions);
126
1.44k
   SAVE_STACK;
127
128
1.44k
   if (begin<0 || begin>=end || end>rp->nb_frames)
129
380
   {
130
      /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/
131
380
      RESTORE_STACK;
132
380
      return OPUS_BAD_ARG;
133
380
   }
134
1.06k
   count = end-begin;
135
136
1.06k
   len = rp->len+begin;
137
1.06k
   frames = rp->frames+begin;
138
1.06k
   if (self_delimited)
139
0
      tot_size = 1 + (len[count-1]>=252);
140
1.06k
   else
141
1.06k
      tot_size = 0;
142
143
   /* figure out total number of extensions */
144
1.06k
   total_ext_count = nb_extensions;
145
22.2k
   for (i=begin;i<end;i++)
146
21.2k
   {
147
21.2k
      int n = opus_packet_extensions_count(rp->paddings[i], rp->padding_len[i],
148
21.2k
       rp->padding_nb_frames[i]);
149
21.2k
      if (n > 0) total_ext_count += n;
150
21.2k
   }
151
1.06k
   ALLOC(all_extensions, total_ext_count ? total_ext_count : ALLOC_NONE, opus_extension_data);
152
   /* copy over any extensions that were passed in */
153
1.06k
   for (ext_count=0;ext_count<nb_extensions;ext_count++)
154
0
   {
155
0
      all_extensions[ext_count] = extensions[ext_count];
156
0
   }
157
158
   /* incorporate any extensions from the repacketizer padding */
159
19.2k
   for (i=begin;i<end;i++)
160
18.3k
   {
161
18.3k
      int j, ret;
162
18.3k
      opus_int32 frame_ext_count;
163
18.3k
      frame_ext_count = total_ext_count - ext_count;
164
18.3k
      ret = opus_packet_extensions_parse(rp->paddings[i], rp->padding_len[i],
165
18.3k
         &all_extensions[ext_count], &frame_ext_count, rp->padding_nb_frames[i]);
166
18.3k
      if (ret<0)
167
199
      {
168
199
         RESTORE_STACK;
169
199
         return OPUS_INTERNAL_ERROR;
170
199
      }
171
      /* renumber the extension frame numbers */
172
2.70M
      for (j=0;j<frame_ext_count;j++)
173
2.68M
      {
174
2.68M
         all_extensions[ext_count+j].frame += i-begin;
175
2.68M
      }
176
18.1k
      ext_count += frame_ext_count;
177
18.1k
   }
178
179
864
   ptr = data;
180
864
   if (count==1)
181
88
   {
182
      /* Code 0 */
183
88
      tot_size += len[0]+1;
184
88
      if (tot_size > maxlen)
185
0
      {
186
0
         RESTORE_STACK;
187
0
         return OPUS_BUFFER_TOO_SMALL;
188
0
      }
189
88
      *ptr++ = rp->toc&0xFC;
190
776
   } else if (count==2)
191
134
   {
192
134
      if (len[1] == len[0])
193
74
      {
194
         /* Code 1 */
195
74
         tot_size += 2*len[0]+1;
196
74
         if (tot_size > maxlen)
197
0
         {
198
0
            RESTORE_STACK;
199
0
            return OPUS_BUFFER_TOO_SMALL;
200
0
         }
201
74
         *ptr++ = (rp->toc&0xFC) | 0x1;
202
74
      } else {
203
         /* Code 2 */
204
60
         tot_size += len[0]+len[1]+2+(len[0]>=252);
205
60
         if (tot_size > maxlen)
206
0
         {
207
0
            RESTORE_STACK;
208
0
            return OPUS_BUFFER_TOO_SMALL;
209
0
         }
210
60
         *ptr++ = (rp->toc&0xFC) | 0x2;
211
60
         ptr += encode_size(len[0], ptr);
212
60
      }
213
134
   }
214
864
   if (count > 2 || (pad && tot_size < maxlen) || ext_count > 0)
215
714
   {
216
      /* Code 3 */
217
714
      int vbr;
218
714
      int pad_amount=0;
219
220
      /* Restart the process for the padding case */
221
714
      ptr = data;
222
714
      if (self_delimited)
223
0
         tot_size = 1 + (len[count-1]>=252);
224
714
      else
225
714
         tot_size = 0;
226
714
      vbr = 0;
227
16.3k
      for (i=1;i<count;i++)
228
15.8k
      {
229
15.8k
         if (len[i] != len[0])
230
146
         {
231
146
            vbr=1;
232
146
            break;
233
146
         }
234
15.8k
      }
235
714
      if (vbr)
236
146
      {
237
146
         tot_size += 2;
238
3.73k
         for (i=0;i<count-1;i++)
239
3.59k
            tot_size += 1 + (len[i]>=252) + len[i];
240
146
         tot_size += len[count-1];
241
242
146
         if (tot_size > maxlen)
243
16
         {
244
16
            RESTORE_STACK;
245
16
            return OPUS_BUFFER_TOO_SMALL;
246
16
         }
247
130
         *ptr++ = (rp->toc&0xFC) | 0x3;
248
130
         *ptr++ = count | 0x80;
249
568
      } else {
250
568
         tot_size += count*len[0]+2;
251
568
         if (tot_size > maxlen)
252
6
         {
253
6
            RESTORE_STACK;
254
6
            return OPUS_BUFFER_TOO_SMALL;
255
6
         }
256
562
         *ptr++ = (rp->toc&0xFC) | 0x3;
257
562
         *ptr++ = count;
258
562
      }
259
692
      pad_amount = pad ? (maxlen-tot_size) : 0;
260
692
      if (ext_count>0)
261
516
      {
262
         /* figure out how much space we need for the extensions */
263
516
         ext_len = opus_packet_extensions_generate(NULL, maxlen-tot_size,
264
516
          all_extensions, ext_count, count, 0);
265
516
         if (ext_len < 0) return ext_len;
266
493
         if (!pad)
267
493
            pad_amount = ext_len + (ext_len ? (ext_len+253)/254 : 1);
268
493
      }
269
669
      if (pad_amount != 0)
270
493
      {
271
493
         int nb_255s;
272
493
         data[1] |= 0x40;
273
493
         nb_255s = (pad_amount-1)/255;
274
493
         if (tot_size + ext_len + nb_255s + 1 > maxlen)
275
33
         {
276
33
            RESTORE_STACK;
277
33
            return OPUS_BUFFER_TOO_SMALL;
278
33
         }
279
460
         ext_begin = tot_size+pad_amount-ext_len;
280
         /* Prepend 0x01 padding */
281
460
         ones_begin = tot_size+nb_255s+1;
282
460
         ones_end = tot_size+pad_amount-ext_len;
283
1.60k
         for (i=0;i<nb_255s;i++)
284
1.14k
            *ptr++ = 255;
285
460
         *ptr++ = pad_amount-255*nb_255s-1;
286
460
         tot_size += pad_amount;
287
460
      }
288
636
      if (vbr)
289
86
      {
290
1.43k
         for (i=0;i<count-1;i++)
291
1.34k
            ptr += encode_size(len[i], ptr);
292
86
      }
293
636
   }
294
786
   if (self_delimited) {
295
0
      int sdlen = encode_size(len[count-1], ptr);
296
0
      ptr += sdlen;
297
0
   }
298
   /* Copy the actual data */
299
15.9k
   for (i=0;i<count;i++)
300
15.2k
   {
301
      /* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place
302
         padding from opus_packet_pad or opus_packet_unpad(). */
303
      /* assert disabled because it's not valid in C. */
304
      /* celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]); */
305
15.2k
      OPUS_MOVE(ptr, frames[i], len[i]);
306
15.2k
      ptr += len[i];
307
15.2k
   }
308
786
   if (ext_len > 0) {
309
460
      int ret = opus_packet_extensions_generate(&data[ext_begin], ext_len,
310
460
       all_extensions, ext_count, count, 0);
311
460
      celt_assert(ret == ext_len);
312
460
   }
313
786
   for (i=ones_begin;i<ones_end;i++)
314
0
      data[i] = 0x01;
315
786
   if (pad && ext_count==0)
316
0
   {
317
      /* Fill padding with zeros. */
318
0
      while (ptr<data+maxlen)
319
0
         *ptr++=0;
320
0
   }
321
786
   RESTORE_STACK;
322
786
   return tot_size;
323
786
}
324
325
opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen)
326
0
{
327
0
   return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0, NULL, 0);
328
0
}
329
330
opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen)
331
1.44k
{
332
1.44k
   return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0, NULL, 0);
333
1.44k
}
334
335
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)
336
0
{
337
0
   OpusRepacketizer rp;
338
0
   opus_int32 ret;
339
0
   VARDECL(unsigned char, copy);
340
0
   SAVE_STACK;
341
0
   if (len < 1)
342
0
      return OPUS_BAD_ARG;
343
0
   if (len==new_len)
344
0
      return OPUS_OK;
345
0
   else if (len > new_len)
346
0
      return OPUS_BAD_ARG;
347
0
   ALLOC(copy, len, unsigned char);
348
0
   opus_repacketizer_init(&rp);
349
   /* Moving payload to the end of the packet so we can do in-place padding */
350
0
   OPUS_COPY(copy, data, len);
351
0
   ret = opus_repacketizer_cat(&rp, copy, len);
352
0
   if (ret != OPUS_OK)
353
0
      return ret;
354
0
   ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, pad, extensions, nb_extensions);
355
0
   RESTORE_STACK;
356
0
   return ret;
357
0
}
358
359
int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
360
0
{
361
0
   opus_int32 ret;
362
0
   ALLOC_STACK;
363
0
   ret = opus_packet_pad_impl(data, len, new_len, 1, NULL, 0);
364
0
   RESTORE_STACK;
365
0
   if (ret > 0)
366
0
      return OPUS_OK;
367
0
   else
368
0
      return ret;
369
0
}
370
371
opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len)
372
0
{
373
0
   OpusRepacketizer rp;
374
0
   opus_int32 ret;
375
0
   int i;
376
0
   if (len < 1)
377
0
      return OPUS_BAD_ARG;
378
0
   opus_repacketizer_init(&rp);
379
0
   ret = opus_repacketizer_cat(&rp, data, len);
380
0
   if (ret < 0)
381
0
      return ret;
382
   /* Discard all padding and extensions. */
383
0
   for (i=0;i<rp.nb_frames;i++) {
384
0
      rp.padding_len[i] = 0;
385
0
      rp.paddings[i] = NULL;
386
0
   }
387
0
   ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0, NULL, 0);
388
0
   celt_assert(ret > 0 && ret <= len);
389
0
   return ret;
390
0
}
391
392
int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams)
393
0
{
394
0
   int s;
395
0
   int count;
396
0
   unsigned char toc;
397
0
   opus_int16 size[48];
398
0
   opus_int32 packet_offset;
399
0
   opus_int32 amount;
400
401
0
   if (len < 1)
402
0
      return OPUS_BAD_ARG;
403
0
   if (len==new_len)
404
0
      return OPUS_OK;
405
0
   else if (len > new_len)
406
0
      return OPUS_BAD_ARG;
407
0
   amount = new_len - len;
408
   /* Seek to last stream */
409
0
   for (s=0;s<nb_streams-1;s++)
410
0
   {
411
0
      if (len<=0)
412
0
         return OPUS_INVALID_PACKET;
413
0
      count = opus_packet_parse_impl(data, len, 1, &toc, NULL,
414
0
                                     size, NULL, &packet_offset, NULL, NULL);
415
0
      if (count<0)
416
0
         return count;
417
0
      data += packet_offset;
418
0
      len -= packet_offset;
419
0
   }
420
0
   return opus_packet_pad(data, len, len+amount);
421
0
}
422
423
opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams)
424
0
{
425
0
   int s;
426
0
   unsigned char toc;
427
0
   opus_int16 size[48];
428
0
   opus_int32 packet_offset;
429
0
   OpusRepacketizer rp;
430
0
   unsigned char *dst;
431
0
   opus_int32 dst_len;
432
433
0
   if (len < 1)
434
0
      return OPUS_BAD_ARG;
435
0
   dst = data;
436
0
   dst_len = 0;
437
   /* Unpad all frames */
438
0
   for (s=0;s<nb_streams;s++)
439
0
   {
440
0
      opus_int32 ret;
441
0
      int i;
442
0
      int self_delimited = s!=nb_streams-1;
443
0
      if (len<=0)
444
0
         return OPUS_INVALID_PACKET;
445
0
      opus_repacketizer_init(&rp);
446
0
      ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
447
0
                                     size, NULL, &packet_offset, NULL, NULL);
448
0
      if (ret<0)
449
0
         return ret;
450
0
      ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited);
451
0
      if (ret < 0)
452
0
         return ret;
453
      /* Discard all padding and extensions. */
454
0
      for (i=0;i<rp.nb_frames;i++) {
455
0
         rp.padding_len[i] = 0;
456
0
         rp.paddings[i] = NULL;
457
0
      }
458
0
      ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0, NULL, 0);
459
0
      if (ret < 0)
460
0
         return ret;
461
0
      else
462
0
         dst_len += ret;
463
0
      dst += ret;
464
0
      data += packet_offset;
465
0
      len -= packet_offset;
466
0
   }
467
0
   return dst_len;
468
0
}