Coverage Report

Created: 2026-06-10 06:10

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.61k
{
40
1.61k
   return sizeof(OpusRepacketizer);
41
1.61k
}
42
43
OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp)
44
3.22k
{
45
3.22k
   rp->nb_frames = 0;
46
3.22k
   return rp;
47
3.22k
}
48
49
OpusRepacketizer *opus_repacketizer_create(void)
50
1.61k
{
51
1.61k
   OpusRepacketizer *rp;
52
1.61k
   rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size());
53
1.61k
   if(rp==NULL)return NULL;
54
1.61k
   return opus_repacketizer_init(rp);
55
1.61k
}
56
57
void opus_repacketizer_destroy(OpusRepacketizer *rp)
58
1.61k
{
59
1.61k
   opus_free(rp);
60
1.61k
}
61
62
static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited)
63
5.59k
{
64
5.59k
   unsigned char tmp_toc;
65
5.59k
   int curr_nb_frames,ret;
66
   /* Set of check ToC */
67
5.59k
   if (len<1) return OPUS_INVALID_PACKET;
68
5.24k
   if (rp->nb_frames == 0)
69
2.94k
   {
70
2.94k
      rp->toc = data[0];
71
2.94k
      rp->framesize = opus_packet_get_samples_per_frame(data, 8000);
72
2.94k
   } else if ((rp->toc&0xFC) != (data[0]&0xFC))
73
79
   {
74
      /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/
75
79
      return OPUS_INVALID_PACKET;
76
79
   }
77
5.16k
   curr_nb_frames = opus_packet_get_nb_frames(data, len);
78
5.16k
   if(curr_nb_frames<1) return OPUS_INVALID_PACKET;
79
80
   /* Check the 120 ms maximum packet size */
81
4.96k
   if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960)
82
115
   {
83
115
      return OPUS_INVALID_PACKET;
84
115
   }
85
86
4.84k
   ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames],
87
4.84k
       NULL, NULL, &rp->paddings[rp->nb_frames], &rp->padding_len[rp->nb_frames]);
88
4.84k
   if(ret<1)return ret;
89
3.31k
   rp->padding_nb_frames[rp->nb_frames]=ret;
90
91
   /* set padding length to zero for all but the first frame */
92
24.0k
   while (curr_nb_frames > 1)
93
20.7k
   {
94
20.7k
      rp->nb_frames++;
95
20.7k
      rp->padding_len[rp->nb_frames] = 0;
96
20.7k
      rp->padding_nb_frames[rp->nb_frames] = 0;
97
20.7k
      rp->paddings[rp->nb_frames] = NULL;
98
20.7k
      curr_nb_frames--;
99
20.7k
   }
100
3.31k
   rp->nb_frames++;
101
3.31k
   return OPUS_OK;
102
4.84k
}
103
104
int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len)
105
5.59k
{
106
5.59k
   return opus_repacketizer_cat_impl(rp, data, len, 0);
107
5.59k
}
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.61k
{
117
1.61k
   int i, count;
118
1.61k
   opus_int32 tot_size;
119
1.61k
   opus_int16 *len;
120
1.61k
   const unsigned char **frames;
121
1.61k
   unsigned char * ptr;
122
1.61k
   int ones_begin=0, ones_end=0;
123
1.61k
   int ext_begin=0, ext_len=0;
124
1.61k
   int ext_count, total_ext_count;
125
1.61k
   VARDECL(opus_extension_data, all_extensions);
126
1.61k
   SAVE_STACK;
127
128
1.61k
   if (begin<0 || begin>=end || end>rp->nb_frames)
129
426
   {
130
      /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/
131
426
      RESTORE_STACK;
132
426
      return OPUS_BAD_ARG;
133
426
   }
134
1.18k
   count = end-begin;
135
136
1.18k
   len = rp->len+begin;
137
1.18k
   frames = rp->frames+begin;
138
1.18k
   if (self_delimited)
139
0
      tot_size = 1 + (len[count-1]>=252);
140
1.18k
   else
141
1.18k
      tot_size = 0;
142
143
   /* figure out total number of extensions */
144
1.18k
   total_ext_count = nb_extensions;
145
25.2k
   for (i=begin;i<end;i++)
146
24.0k
   {
147
24.0k
      int n = opus_packet_extensions_count(rp->paddings[i], rp->padding_len[i],
148
24.0k
       rp->padding_nb_frames[i]);
149
24.0k
      if (n > 0) total_ext_count += n;
150
24.0k
   }
151
1.18k
   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.18k
   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
21.9k
   for (i=begin;i<end;i++)
160
20.9k
   {
161
20.9k
      int j, ret;
162
20.9k
      opus_int32 frame_ext_count;
163
20.9k
      frame_ext_count = total_ext_count - ext_count;
164
20.9k
      ret = opus_packet_extensions_parse(rp->paddings[i], rp->padding_len[i],
165
20.9k
         &all_extensions[ext_count], &frame_ext_count, rp->padding_nb_frames[i]);
166
20.9k
      if (ret<0)
167
223
      {
168
223
         RESTORE_STACK;
169
223
         return OPUS_INTERNAL_ERROR;
170
223
      }
171
      /* renumber the extension frame numbers */
172
3.12M
      for (j=0;j<frame_ext_count;j++)
173
3.10M
      {
174
3.10M
         all_extensions[ext_count+j].frame += i-begin;
175
3.10M
      }
176
20.7k
      ext_count += frame_ext_count;
177
20.7k
   }
178
179
964
   ptr = data;
180
964
   if (count==1)
181
96
   {
182
      /* Code 0 */
183
96
      tot_size += len[0]+1;
184
96
      if (tot_size > maxlen)
185
0
      {
186
0
         RESTORE_STACK;
187
0
         return OPUS_BUFFER_TOO_SMALL;
188
0
      }
189
96
      *ptr++ = rp->toc&0xFC;
190
868
   } else if (count==2)
191
138
   {
192
138
      if (len[1] == len[0])
193
72
      {
194
         /* Code 1 */
195
72
         tot_size += 2*len[0]+1;
196
72
         if (tot_size > maxlen)
197
0
         {
198
0
            RESTORE_STACK;
199
0
            return OPUS_BUFFER_TOO_SMALL;
200
0
         }
201
72
         *ptr++ = (rp->toc&0xFC) | 0x1;
202
72
      } else {
203
         /* Code 2 */
204
66
         tot_size += len[0]+len[1]+2+(len[0]>=252);
205
66
         if (tot_size > maxlen)
206
0
         {
207
0
            RESTORE_STACK;
208
0
            return OPUS_BUFFER_TOO_SMALL;
209
0
         }
210
66
         *ptr++ = (rp->toc&0xFC) | 0x2;
211
66
         ptr += encode_size(len[0], ptr);
212
66
      }
213
138
   }
214
964
   if (count > 2 || (pad && tot_size < maxlen) || ext_count > 0)
215
810
   {
216
      /* Code 3 */
217
810
      int vbr;
218
810
      int pad_amount=0;
219
220
      /* Restart the process for the padding case */
221
810
      ptr = data;
222
810
      if (self_delimited)
223
0
         tot_size = 1 + (len[count-1]>=252);
224
810
      else
225
810
         tot_size = 0;
226
810
      vbr = 0;
227
19.0k
      for (i=1;i<count;i++)
228
18.3k
      {
229
18.3k
         if (len[i] != len[0])
230
156
         {
231
156
            vbr=1;
232
156
            break;
233
156
         }
234
18.3k
      }
235
810
      if (vbr)
236
156
      {
237
156
         tot_size += 2;
238
3.77k
         for (i=0;i<count-1;i++)
239
3.62k
            tot_size += 1 + (len[i]>=252) + len[i];
240
156
         tot_size += len[count-1];
241
242
156
         if (tot_size > maxlen)
243
16
         {
244
16
            RESTORE_STACK;
245
16
            return OPUS_BUFFER_TOO_SMALL;
246
16
         }
247
140
         *ptr++ = (rp->toc&0xFC) | 0x3;
248
140
         *ptr++ = count | 0x80;
249
654
      } else {
250
654
         tot_size += count*len[0]+2;
251
654
         if (tot_size > maxlen)
252
6
         {
253
6
            RESTORE_STACK;
254
6
            return OPUS_BUFFER_TOO_SMALL;
255
6
         }
256
648
         *ptr++ = (rp->toc&0xFC) | 0x3;
257
648
         *ptr++ = count;
258
648
      }
259
788
      pad_amount = pad ? (maxlen-tot_size) : 0;
260
788
      if (ext_count>0)
261
596
      {
262
         /* figure out how much space we need for the extensions */
263
596
         ext_len = opus_packet_extensions_generate(NULL, maxlen-tot_size,
264
596
          all_extensions, ext_count, count, 0);
265
596
         if (ext_len < 0) return ext_len;
266
579
         if (!pad)
267
579
            pad_amount = ext_len + (ext_len ? (ext_len+253)/254 : 1);
268
579
      }
269
771
      if (pad_amount != 0)
270
579
      {
271
579
         int nb_255s;
272
579
         data[1] |= 0x40;
273
579
         nb_255s = (pad_amount-1)/255;
274
579
         if (tot_size + ext_len + nb_255s + 1 > maxlen)
275
46
         {
276
46
            RESTORE_STACK;
277
46
            return OPUS_BUFFER_TOO_SMALL;
278
46
         }
279
533
         ext_begin = tot_size+pad_amount-ext_len;
280
         /* Prepend 0x01 padding */
281
533
         ones_begin = tot_size+nb_255s+1;
282
533
         ones_end = tot_size+pad_amount-ext_len;
283
1.70k
         for (i=0;i<nb_255s;i++)
284
1.17k
            *ptr++ = 255;
285
533
         *ptr++ = pad_amount-255*nb_255s-1;
286
533
         tot_size += pad_amount;
287
533
      }
288
725
      if (vbr)
289
92
      {
290
1.33k
         for (i=0;i<count-1;i++)
291
1.24k
            ptr += encode_size(len[i], ptr);
292
92
      }
293
725
   }
294
879
   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
18.4k
   for (i=0;i<count;i++)
300
17.5k
   {
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
17.5k
      OPUS_MOVE(ptr, frames[i], len[i]);
306
17.5k
      ptr += len[i];
307
17.5k
   }
308
879
   if (ext_len > 0) {
309
533
      int ret = opus_packet_extensions_generate(&data[ext_begin], ext_len,
310
533
       all_extensions, ext_count, count, 0);
311
533
      celt_assert(ret == ext_len);
312
533
   }
313
879
   for (i=ones_begin;i<ones_end;i++)
314
0
      data[i] = 0x01;
315
879
   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
879
   RESTORE_STACK;
322
879
   return tot_size;
323
879
}
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.61k
{
332
1.61k
   return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0, NULL, 0);
333
1.61k
}
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
}