/src/opus/src/repacketizer.c
Line | Count | Source (jump to first uncovered line) |
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 | 2.98k | { |
40 | 2.98k | return sizeof(OpusRepacketizer); |
41 | 2.98k | } |
42 | | |
43 | | OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) |
44 | 321k | { |
45 | 321k | rp->nb_frames = 0; |
46 | 321k | return rp; |
47 | 321k | } |
48 | | |
49 | | OpusRepacketizer *opus_repacketizer_create(void) |
50 | 2.98k | { |
51 | 2.98k | OpusRepacketizer *rp; |
52 | 2.98k | rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size()); |
53 | 2.98k | if(rp==NULL)return NULL; |
54 | 2.98k | return opus_repacketizer_init(rp); |
55 | 2.98k | } |
56 | | |
57 | | void opus_repacketizer_destroy(OpusRepacketizer *rp) |
58 | 2.98k | { |
59 | 2.98k | opus_free(rp); |
60 | 2.98k | } |
61 | | |
62 | | static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited) |
63 | 413k | { |
64 | 413k | unsigned char tmp_toc; |
65 | 413k | int curr_nb_frames,ret; |
66 | | /* Set of check ToC */ |
67 | 413k | if (len<1) return OPUS_INVALID_PACKET; |
68 | 412k | if (rp->nb_frames == 0) |
69 | 321k | { |
70 | 321k | rp->toc = data[0]; |
71 | 321k | rp->framesize = opus_packet_get_samples_per_frame(data, 8000); |
72 | 321k | } else if ((rp->toc&0xFC) != (data[0]&0xFC)) |
73 | 164 | { |
74 | | /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/ |
75 | 164 | return OPUS_INVALID_PACKET; |
76 | 164 | } |
77 | 412k | curr_nb_frames = opus_packet_get_nb_frames(data, len); |
78 | 412k | if(curr_nb_frames<1) return OPUS_INVALID_PACKET; |
79 | | |
80 | | /* Check the 120 ms maximum packet size */ |
81 | 411k | if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960) |
82 | 186 | { |
83 | 186 | return OPUS_INVALID_PACKET; |
84 | 186 | } |
85 | | |
86 | 411k | ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], |
87 | 411k | NULL, NULL, &rp->paddings[rp->nb_frames], &rp->padding_len[rp->nb_frames]); |
88 | 411k | if(ret<1)return ret; |
89 | 408k | rp->padding_nb_frames[rp->nb_frames]=ret; |
90 | | |
91 | | /* set padding length to zero for all but the first frame */ |
92 | 572k | while (curr_nb_frames > 1) |
93 | 163k | { |
94 | 163k | rp->nb_frames++; |
95 | 163k | rp->padding_len[rp->nb_frames] = 0; |
96 | 163k | rp->padding_nb_frames[rp->nb_frames] = 0; |
97 | 163k | rp->paddings[rp->nb_frames] = NULL; |
98 | 163k | curr_nb_frames--; |
99 | 163k | } |
100 | 408k | rp->nb_frames++; |
101 | 408k | return OPUS_OK; |
102 | 411k | } |
103 | | |
104 | | int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) |
105 | 413k | { |
106 | 413k | return opus_repacketizer_cat_impl(rp, data, len, 0); |
107 | 413k | } |
108 | | |
109 | | int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) |
110 | 220k | { |
111 | 220k | return rp->nb_frames; |
112 | 220k | } |
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 | 318k | { |
117 | 318k | int i, count; |
118 | 318k | opus_int32 tot_size; |
119 | 318k | opus_int16 *len; |
120 | 318k | const unsigned char **frames; |
121 | 318k | unsigned char * ptr; |
122 | 318k | int ones_begin=0, ones_end=0; |
123 | 318k | int ext_begin=0, ext_len=0; |
124 | 318k | int ext_count, total_ext_count; |
125 | 318k | VARDECL(opus_extension_data, all_extensions); |
126 | 318k | SAVE_STACK; |
127 | | |
128 | 318k | if (begin<0 || begin>=end || end>rp->nb_frames) |
129 | 731 | { |
130 | | /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/ |
131 | 731 | RESTORE_STACK; |
132 | 731 | return OPUS_BAD_ARG; |
133 | 731 | } |
134 | 318k | count = end-begin; |
135 | | |
136 | 318k | len = rp->len+begin; |
137 | 318k | frames = rp->frames+begin; |
138 | 318k | if (self_delimited) |
139 | 187k | tot_size = 1 + (len[count-1]>=252); |
140 | 130k | else |
141 | 130k | tot_size = 0; |
142 | | |
143 | | /* figure out total number of extensions */ |
144 | 318k | total_ext_count = nb_extensions; |
145 | 890k | for (i=begin;i<end;i++) |
146 | 572k | { |
147 | 572k | int n = opus_packet_extensions_count(rp->paddings[i], rp->padding_len[i], |
148 | 572k | rp->padding_nb_frames[i]); |
149 | 572k | if (n > 0) total_ext_count += n; |
150 | 572k | } |
151 | 318k | ALLOC(all_extensions, total_ext_count ? total_ext_count : ALLOC_NONE, opus_extension_data); |
152 | | /* copy over any extensions that were passed in */ |
153 | 318k | 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 | 884k | for (i=begin;i<end;i++) |
160 | 566k | { |
161 | 566k | int j, ret; |
162 | 566k | opus_int32 frame_ext_count; |
163 | 566k | frame_ext_count = total_ext_count - ext_count; |
164 | 566k | ret = opus_packet_extensions_parse(rp->paddings[i], rp->padding_len[i], |
165 | 566k | &all_extensions[ext_count], &frame_ext_count, rp->padding_nb_frames[i]); |
166 | 566k | if (ret<0) |
167 | 438 | { |
168 | 438 | RESTORE_STACK; |
169 | 438 | return OPUS_INTERNAL_ERROR; |
170 | 438 | } |
171 | | /* renumber the extension frame numbers */ |
172 | 6.63M | for (j=0;j<frame_ext_count;j++) |
173 | 6.07M | { |
174 | 6.07M | all_extensions[ext_count+j].frame += i-begin; |
175 | 6.07M | } |
176 | 566k | ext_count += frame_ext_count; |
177 | 566k | } |
178 | | |
179 | 317k | ptr = data; |
180 | 317k | if (count==1) |
181 | 233k | { |
182 | | /* Code 0 */ |
183 | 233k | tot_size += len[0]+1; |
184 | 233k | if (tot_size > maxlen) |
185 | 0 | { |
186 | 0 | RESTORE_STACK; |
187 | 0 | return OPUS_BUFFER_TOO_SMALL; |
188 | 0 | } |
189 | 233k | *ptr++ = rp->toc&0xFC; |
190 | 233k | } else if (count==2) |
191 | 34.1k | { |
192 | 34.1k | if (len[1] == len[0]) |
193 | 13.6k | { |
194 | | /* Code 1 */ |
195 | 13.6k | tot_size += 2*len[0]+1; |
196 | 13.6k | if (tot_size > maxlen) |
197 | 0 | { |
198 | 0 | RESTORE_STACK; |
199 | 0 | return OPUS_BUFFER_TOO_SMALL; |
200 | 0 | } |
201 | 13.6k | *ptr++ = (rp->toc&0xFC) | 0x1; |
202 | 20.4k | } else { |
203 | | /* Code 2 */ |
204 | 20.4k | tot_size += len[0]+len[1]+2+(len[0]>=252); |
205 | 20.4k | if (tot_size > maxlen) |
206 | 0 | { |
207 | 0 | RESTORE_STACK; |
208 | 0 | return OPUS_BUFFER_TOO_SMALL; |
209 | 0 | } |
210 | 20.4k | *ptr++ = (rp->toc&0xFC) | 0x2; |
211 | 20.4k | ptr += encode_size(len[0], ptr); |
212 | 20.4k | } |
213 | 34.1k | } |
214 | 317k | if (count > 2 || (pad && tot_size < maxlen) || ext_count > 0) |
215 | 125k | { |
216 | | /* Code 3 */ |
217 | 125k | int vbr; |
218 | 125k | int pad_amount=0; |
219 | | |
220 | | /* Restart the process for the padding case */ |
221 | 125k | ptr = data; |
222 | 125k | if (self_delimited) |
223 | 21.8k | tot_size = 1 + (len[count-1]>=252); |
224 | 103k | else |
225 | 103k | tot_size = 0; |
226 | 125k | vbr = 0; |
227 | 241k | for (i=1;i<count;i++) |
228 | 149k | { |
229 | 149k | if (len[i] != len[0]) |
230 | 33.6k | { |
231 | 33.6k | vbr=1; |
232 | 33.6k | break; |
233 | 33.6k | } |
234 | 149k | } |
235 | 125k | if (vbr) |
236 | 33.6k | { |
237 | 33.6k | tot_size += 2; |
238 | 153k | for (i=0;i<count-1;i++) |
239 | 119k | tot_size += 1 + (len[i]>=252) + len[i]; |
240 | 33.6k | tot_size += len[count-1]; |
241 | | |
242 | 33.6k | if (tot_size > maxlen) |
243 | 31 | { |
244 | 31 | RESTORE_STACK; |
245 | 31 | return OPUS_BUFFER_TOO_SMALL; |
246 | 31 | } |
247 | 33.5k | *ptr++ = (rp->toc&0xFC) | 0x3; |
248 | 33.5k | *ptr++ = count | 0x80; |
249 | 91.8k | } else { |
250 | 91.8k | tot_size += count*len[0]+2; |
251 | 91.8k | if (tot_size > maxlen) |
252 | 12 | { |
253 | 12 | RESTORE_STACK; |
254 | 12 | return OPUS_BUFFER_TOO_SMALL; |
255 | 12 | } |
256 | 91.8k | *ptr++ = (rp->toc&0xFC) | 0x3; |
257 | 91.8k | *ptr++ = count; |
258 | 91.8k | } |
259 | 125k | pad_amount = pad ? (maxlen-tot_size) : 0; |
260 | 125k | if (ext_count>0) |
261 | 1.09k | { |
262 | | /* figure out how much space we need for the extensions */ |
263 | 1.09k | ext_len = opus_packet_extensions_generate(NULL, maxlen-tot_size, |
264 | 1.09k | all_extensions, ext_count, count, 0); |
265 | 1.09k | if (ext_len < 0) return ext_len; |
266 | 1.04k | if (!pad) |
267 | 1.04k | pad_amount = ext_len + ext_len/254 + 1; |
268 | 1.04k | } |
269 | 125k | if (pad_amount != 0) |
270 | 77.6k | { |
271 | 77.6k | int nb_255s; |
272 | 77.6k | data[1] |= 0x40; |
273 | 77.6k | nb_255s = (pad_amount-1)/255; |
274 | 77.6k | if (tot_size + ext_len + nb_255s + 1 > maxlen) |
275 | 70 | { |
276 | 70 | RESTORE_STACK; |
277 | 70 | return OPUS_BUFFER_TOO_SMALL; |
278 | 70 | } |
279 | 77.5k | ext_begin = tot_size+pad_amount-ext_len; |
280 | | /* Prepend 0x01 padding */ |
281 | 77.5k | ones_begin = tot_size+nb_255s+1; |
282 | 77.5k | ones_end = tot_size+pad_amount-ext_len; |
283 | 85.4k | for (i=0;i<nb_255s;i++) |
284 | 7.87k | *ptr++ = 255; |
285 | 77.5k | *ptr++ = pad_amount-255*nb_255s-1; |
286 | 77.5k | tot_size += pad_amount; |
287 | 77.5k | } |
288 | 125k | if (vbr) |
289 | 33.4k | { |
290 | 147k | for (i=0;i<count-1;i++) |
291 | 113k | ptr += encode_size(len[i], ptr); |
292 | 33.4k | } |
293 | 125k | } |
294 | 317k | if (self_delimited) { |
295 | 187k | int sdlen = encode_size(len[count-1], ptr); |
296 | 187k | ptr += sdlen; |
297 | 187k | } |
298 | | /* Copy the actual data */ |
299 | 877k | for (i=0;i<count;i++) |
300 | 559k | { |
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 | 559k | OPUS_MOVE(ptr, frames[i], len[i]); |
306 | 559k | ptr += len[i]; |
307 | 559k | } |
308 | 317k | if (ext_len > 0) { |
309 | 977 | int ret = opus_packet_extensions_generate(&data[ext_begin], ext_len, |
310 | 977 | all_extensions, ext_count, count, 0); |
311 | 977 | celt_assert(ret == ext_len); |
312 | 977 | } |
313 | 5.09M | for (i=ones_begin;i<ones_end;i++) |
314 | 4.77M | data[i] = 0x01; |
315 | 317k | if (pad && ext_count==0) |
316 | 90.8k | { |
317 | | /* Fill padding with zeros. */ |
318 | 4.86M | while (ptr<data+maxlen) |
319 | 4.77M | *ptr++=0; |
320 | 90.8k | } |
321 | 317k | RESTORE_STACK; |
322 | 317k | return tot_size; |
323 | 317k | } |
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 | 2.98k | { |
332 | 2.98k | return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0, NULL, 0); |
333 | 2.98k | } |
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 | 109k | { |
337 | 109k | OpusRepacketizer rp; |
338 | 109k | opus_int32 ret; |
339 | 109k | VARDECL(unsigned char, copy); |
340 | 109k | SAVE_STACK; |
341 | 109k | if (len < 1) |
342 | 0 | return OPUS_BAD_ARG; |
343 | 109k | if (len==new_len) |
344 | 48.3k | return OPUS_OK; |
345 | 61.3k | else if (len > new_len) |
346 | 0 | return OPUS_BAD_ARG; |
347 | 61.3k | ALLOC(copy, len, unsigned char); |
348 | 61.3k | opus_repacketizer_init(&rp); |
349 | | /* Moving payload to the end of the packet so we can do in-place padding */ |
350 | 61.3k | OPUS_COPY(copy, data, len); |
351 | 61.3k | ret = opus_repacketizer_cat(&rp, copy, len); |
352 | 61.3k | if (ret != OPUS_OK) |
353 | 0 | return ret; |
354 | 61.3k | ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, pad, extensions, nb_extensions); |
355 | 61.3k | RESTORE_STACK; |
356 | 61.3k | return ret; |
357 | 61.3k | } |
358 | | |
359 | | int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len) |
360 | 109k | { |
361 | 109k | opus_int32 ret; |
362 | 109k | ALLOC_STACK; |
363 | 109k | ret = opus_packet_pad_impl(data, len, new_len, 1, NULL, 0); |
364 | 109k | RESTORE_STACK; |
365 | 109k | if (ret > 0) |
366 | 61.3k | return OPUS_OK; |
367 | 48.3k | else |
368 | 48.3k | return ret; |
369 | 109k | } |
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 | } |
469 | | |