/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.19k | { |
40 | 2.19k | return sizeof(OpusRepacketizer); |
41 | 2.19k | } |
42 | | |
43 | | OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) |
44 | 297k | { |
45 | 297k | rp->nb_frames = 0; |
46 | 297k | return rp; |
47 | 297k | } |
48 | | |
49 | | OpusRepacketizer *opus_repacketizer_create(void) |
50 | 2.19k | { |
51 | 2.19k | OpusRepacketizer *rp; |
52 | 2.19k | rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size()); |
53 | 2.19k | if(rp==NULL)return NULL; |
54 | 2.19k | return opus_repacketizer_init(rp); |
55 | 2.19k | } |
56 | | |
57 | | void opus_repacketizer_destroy(OpusRepacketizer *rp) |
58 | 2.19k | { |
59 | 2.19k | opus_free(rp); |
60 | 2.19k | } |
61 | | |
62 | | static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited) |
63 | 384k | { |
64 | 384k | unsigned char tmp_toc; |
65 | 384k | int curr_nb_frames,ret; |
66 | | /* Set of check ToC */ |
67 | 384k | if (len<1) return OPUS_INVALID_PACKET; |
68 | 384k | if (rp->nb_frames == 0) |
69 | 297k | { |
70 | 297k | rp->toc = data[0]; |
71 | 297k | rp->framesize = opus_packet_get_samples_per_frame(data, 8000); |
72 | 297k | } else if ((rp->toc&0xFC) != (data[0]&0xFC)) |
73 | 203 | { |
74 | | /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/ |
75 | 203 | return OPUS_INVALID_PACKET; |
76 | 203 | } |
77 | 383k | curr_nb_frames = opus_packet_get_nb_frames(data, len); |
78 | 383k | if(curr_nb_frames<1) return OPUS_INVALID_PACKET; |
79 | | |
80 | | /* Check the 120 ms maximum packet size */ |
81 | 383k | if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960) |
82 | 143 | { |
83 | 143 | return OPUS_INVALID_PACKET; |
84 | 143 | } |
85 | | |
86 | 383k | ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], |
87 | 383k | NULL, NULL, &rp->paddings[rp->nb_frames], &rp->padding_len[rp->nb_frames]); |
88 | 383k | if(ret<1)return ret; |
89 | | |
90 | | /* set padding length to zero for all but the first frame */ |
91 | 499k | while (curr_nb_frames > 1) |
92 | 119k | { |
93 | 119k | rp->nb_frames++; |
94 | 119k | rp->padding_len[rp->nb_frames] = 0; |
95 | 119k | rp->paddings[rp->nb_frames] = NULL; |
96 | 119k | curr_nb_frames--; |
97 | 119k | } |
98 | 380k | rp->nb_frames++; |
99 | 380k | return OPUS_OK; |
100 | 383k | } |
101 | | |
102 | | int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) |
103 | 384k | { |
104 | 384k | return opus_repacketizer_cat_impl(rp, data, len, 0); |
105 | 384k | } |
106 | | |
107 | | int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) |
108 | 203k | { |
109 | 203k | return rp->nb_frames; |
110 | 203k | } |
111 | | |
112 | | opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, |
113 | | unsigned char *data, opus_int32 maxlen, int self_delimited, int pad, const opus_extension_data *extensions, int nb_extensions) |
114 | 295k | { |
115 | 295k | int i, count; |
116 | 295k | opus_int32 tot_size; |
117 | 295k | opus_int16 *len; |
118 | 295k | const unsigned char **frames; |
119 | 295k | unsigned char * ptr; |
120 | 295k | int ones_begin=0, ones_end=0; |
121 | 295k | int ext_begin=0, ext_len=0; |
122 | 295k | int ext_count, total_ext_count; |
123 | 295k | VARDECL(opus_extension_data, all_extensions); |
124 | 295k | ALLOC_STACK; |
125 | | |
126 | 295k | if (begin<0 || begin>=end || end>rp->nb_frames) |
127 | 713 | { |
128 | | /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/ |
129 | 713 | RESTORE_STACK; |
130 | 713 | return OPUS_BAD_ARG; |
131 | 713 | } |
132 | 294k | count = end-begin; |
133 | | |
134 | 294k | len = rp->len+begin; |
135 | 294k | frames = rp->frames+begin; |
136 | 294k | if (self_delimited) |
137 | 172k | tot_size = 1 + (len[count-1]>=252); |
138 | 122k | else |
139 | 122k | tot_size = 0; |
140 | | |
141 | | /* figure out total number of extensions */ |
142 | 294k | total_ext_count = nb_extensions; |
143 | 794k | for (i=begin;i<end;i++) |
144 | 499k | { |
145 | 499k | int n = opus_packet_extensions_count(rp->paddings[i], rp->padding_len[i]); |
146 | 499k | if (n > 0) total_ext_count += n; |
147 | 499k | } |
148 | 294k | ALLOC(all_extensions, total_ext_count ? total_ext_count : ALLOC_NONE, opus_extension_data); |
149 | | /* copy over any extensions that were passed in */ |
150 | 294k | for (ext_count=0;ext_count<nb_extensions;ext_count++) |
151 | 0 | { |
152 | 0 | all_extensions[ext_count] = extensions[ext_count]; |
153 | 0 | } |
154 | | |
155 | | /* incorporate any extensions from the repacketizer padding */ |
156 | 792k | for (i=begin;i<end;i++) |
157 | 498k | { |
158 | 498k | int frame_ext_count, j; |
159 | 498k | frame_ext_count = total_ext_count - ext_count; |
160 | 498k | int ret = opus_packet_extensions_parse(rp->paddings[i], rp->padding_len[i], |
161 | 498k | &all_extensions[ext_count], &frame_ext_count); |
162 | 498k | if (ret<0) |
163 | 180 | { |
164 | 180 | RESTORE_STACK; |
165 | 180 | return OPUS_INTERNAL_ERROR; |
166 | 180 | } |
167 | | /* renumber the extension frame numbers */ |
168 | 805k | for (j=0;j<frame_ext_count;j++) |
169 | 307k | { |
170 | 307k | all_extensions[ext_count+j].frame += i-begin; |
171 | 307k | } |
172 | 498k | ext_count += frame_ext_count; |
173 | 498k | } |
174 | | |
175 | 294k | ptr = data; |
176 | 294k | if (count==1) |
177 | 216k | { |
178 | | /* Code 0 */ |
179 | 216k | tot_size += len[0]+1; |
180 | 216k | if (tot_size > maxlen) |
181 | 0 | { |
182 | 0 | RESTORE_STACK; |
183 | 0 | return OPUS_BUFFER_TOO_SMALL; |
184 | 0 | } |
185 | 216k | *ptr++ = rp->toc&0xFC; |
186 | 216k | } else if (count==2) |
187 | 32.7k | { |
188 | 32.7k | if (len[1] == len[0]) |
189 | 13.0k | { |
190 | | /* Code 1 */ |
191 | 13.0k | tot_size += 2*len[0]+1; |
192 | 13.0k | if (tot_size > maxlen) |
193 | 0 | { |
194 | 0 | RESTORE_STACK; |
195 | 0 | return OPUS_BUFFER_TOO_SMALL; |
196 | 0 | } |
197 | 13.0k | *ptr++ = (rp->toc&0xFC) | 0x1; |
198 | 19.6k | } else { |
199 | | /* Code 2 */ |
200 | 19.6k | tot_size += len[0]+len[1]+2+(len[0]>=252); |
201 | 19.6k | if (tot_size > maxlen) |
202 | 0 | { |
203 | 0 | RESTORE_STACK; |
204 | 0 | return OPUS_BUFFER_TOO_SMALL; |
205 | 0 | } |
206 | 19.6k | *ptr++ = (rp->toc&0xFC) | 0x2; |
207 | 19.6k | ptr += encode_size(len[0], ptr); |
208 | 19.6k | } |
209 | 32.7k | } |
210 | 294k | if (count > 2 || (pad && tot_size < maxlen) || ext_count > 0) |
211 | 116k | { |
212 | | /* Code 3 */ |
213 | 116k | int vbr; |
214 | 116k | int pad_amount=0; |
215 | | |
216 | | /* Restart the process for the padding case */ |
217 | 116k | ptr = data; |
218 | 116k | if (self_delimited) |
219 | 19.1k | tot_size = 1 + (len[count-1]>=252); |
220 | 97.3k | else |
221 | 97.3k | tot_size = 0; |
222 | 116k | vbr = 0; |
223 | 198k | for (i=1;i<count;i++) |
224 | 113k | { |
225 | 113k | if (len[i] != len[0]) |
226 | 31.2k | { |
227 | 31.2k | vbr=1; |
228 | 31.2k | break; |
229 | 31.2k | } |
230 | 113k | } |
231 | 116k | if (vbr) |
232 | 31.2k | { |
233 | 31.2k | tot_size += 2; |
234 | 137k | for (i=0;i<count-1;i++) |
235 | 105k | tot_size += 1 + (len[i]>=252) + len[i]; |
236 | 31.2k | tot_size += len[count-1]; |
237 | | |
238 | 31.2k | if (tot_size > maxlen) |
239 | 31 | { |
240 | 31 | RESTORE_STACK; |
241 | 31 | return OPUS_BUFFER_TOO_SMALL; |
242 | 31 | } |
243 | 31.1k | *ptr++ = (rp->toc&0xFC) | 0x3; |
244 | 31.1k | *ptr++ = count | 0x80; |
245 | 85.2k | } else { |
246 | 85.2k | tot_size += count*len[0]+2; |
247 | 85.2k | if (tot_size > maxlen) |
248 | 13 | { |
249 | 13 | RESTORE_STACK; |
250 | 13 | return OPUS_BUFFER_TOO_SMALL; |
251 | 13 | } |
252 | 85.2k | *ptr++ = (rp->toc&0xFC) | 0x3; |
253 | 85.2k | *ptr++ = count; |
254 | 85.2k | } |
255 | 116k | pad_amount = pad ? (maxlen-tot_size) : 0; |
256 | 116k | if (ext_count>0) |
257 | 636 | { |
258 | | /* figure out how much space we need for the extensions */ |
259 | 636 | ext_len = opus_packet_extensions_generate(NULL, maxlen-tot_size, all_extensions, ext_count, 0); |
260 | 636 | if (ext_len < 0) return ext_len; |
261 | 596 | if (!pad) |
262 | 596 | pad_amount = ext_len + ext_len/254 + 1; |
263 | 596 | } |
264 | 116k | if (pad_amount != 0) |
265 | 72.8k | { |
266 | 72.8k | int nb_255s; |
267 | 72.8k | data[1] |= 0x40; |
268 | 72.8k | nb_255s = (pad_amount-1)/255; |
269 | 72.8k | if (tot_size + ext_len + nb_255s + 1 > maxlen) |
270 | 13 | { |
271 | 13 | RESTORE_STACK; |
272 | 13 | return OPUS_BUFFER_TOO_SMALL; |
273 | 13 | } |
274 | 72.8k | ext_begin = tot_size+pad_amount-ext_len; |
275 | | /* Prepend 0x01 padding */ |
276 | 72.8k | ones_begin = tot_size+nb_255s+1; |
277 | 72.8k | ones_end = tot_size+pad_amount-ext_len; |
278 | 78.7k | for (i=0;i<nb_255s;i++) |
279 | 5.91k | *ptr++ = 255; |
280 | 72.8k | *ptr++ = pad_amount-255*nb_255s-1; |
281 | 72.8k | tot_size += pad_amount; |
282 | 72.8k | } |
283 | 116k | if (vbr) |
284 | 31.1k | { |
285 | 134k | for (i=0;i<count-1;i++) |
286 | 103k | ptr += encode_size(len[i], ptr); |
287 | 31.1k | } |
288 | 116k | } |
289 | 294k | if (self_delimited) { |
290 | 172k | int sdlen = encode_size(len[count-1], ptr); |
291 | 172k | ptr += sdlen; |
292 | 172k | } |
293 | | /* Copy the actual data */ |
294 | 789k | for (i=0;i<count;i++) |
295 | 495k | { |
296 | | /* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place |
297 | | padding from opus_packet_pad or opus_packet_unpad(). */ |
298 | | /* assert disabled because it's not valid in C. */ |
299 | | /* celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]); */ |
300 | 495k | OPUS_MOVE(ptr, frames[i], len[i]); |
301 | 495k | ptr += len[i]; |
302 | 495k | } |
303 | 294k | if (ext_len > 0) { |
304 | 583 | int ret = opus_packet_extensions_generate(&data[ext_begin], ext_len, all_extensions, ext_count, 0); |
305 | 583 | celt_assert(ret == ext_len); |
306 | 583 | } |
307 | 4.34M | for (i=ones_begin;i<ones_end;i++) |
308 | 4.05M | data[i] = 0x01; |
309 | 294k | if (pad && ext_count==0) |
310 | 86.1k | { |
311 | | /* Fill padding with zeros. */ |
312 | 4.13M | while (ptr<data+maxlen) |
313 | 4.05M | *ptr++=0; |
314 | 86.1k | } |
315 | 294k | return tot_size; |
316 | 294k | } |
317 | | |
318 | | opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) |
319 | 0 | { |
320 | 0 | return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0, NULL, 0); |
321 | 0 | } |
322 | | |
323 | | opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) |
324 | 2.19k | { |
325 | 2.19k | return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0, NULL, 0); |
326 | 2.19k | } |
327 | | |
328 | | 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) |
329 | 100k | { |
330 | 100k | OpusRepacketizer rp; |
331 | 100k | opus_int32 ret; |
332 | 100k | if (len < 1) |
333 | 0 | return OPUS_BAD_ARG; |
334 | 100k | if (len==new_len) |
335 | 43.3k | return OPUS_OK; |
336 | 56.9k | else if (len > new_len) |
337 | 0 | return OPUS_BAD_ARG; |
338 | 56.9k | opus_repacketizer_init(&rp); |
339 | | /* Moving payload to the end of the packet so we can do in-place padding */ |
340 | 56.9k | OPUS_MOVE(data+new_len-len, data, len); |
341 | 56.9k | ret = opus_repacketizer_cat(&rp, data+new_len-len, len); |
342 | 56.9k | if (ret != OPUS_OK) |
343 | 0 | return ret; |
344 | 56.9k | return opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, pad, extensions, nb_extensions); |
345 | 56.9k | } |
346 | | |
347 | | int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len) |
348 | 100k | { |
349 | 100k | opus_int32 ret = opus_packet_pad_impl(data, len, new_len, 1, NULL, 0); |
350 | 100k | if (ret > 0) |
351 | 56.9k | return OPUS_OK; |
352 | 43.3k | else |
353 | 43.3k | return ret; |
354 | 100k | } |
355 | | |
356 | | opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len) |
357 | 0 | { |
358 | 0 | OpusRepacketizer rp; |
359 | 0 | opus_int32 ret; |
360 | 0 | int i; |
361 | 0 | if (len < 1) |
362 | 0 | return OPUS_BAD_ARG; |
363 | 0 | opus_repacketizer_init(&rp); |
364 | 0 | ret = opus_repacketizer_cat(&rp, data, len); |
365 | 0 | if (ret < 0) |
366 | 0 | return ret; |
367 | | /* Discard all padding and extensions. */ |
368 | 0 | for (i=0;i<rp.nb_frames;i++) { |
369 | 0 | rp.padding_len[i] = 0; |
370 | 0 | rp.paddings[i] = NULL; |
371 | 0 | } |
372 | 0 | ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0, NULL, 0); |
373 | 0 | celt_assert(ret > 0 && ret <= len); |
374 | 0 | return ret; |
375 | 0 | } |
376 | | |
377 | | int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams) |
378 | 0 | { |
379 | 0 | int s; |
380 | 0 | int count; |
381 | 0 | unsigned char toc; |
382 | 0 | opus_int16 size[48]; |
383 | 0 | opus_int32 packet_offset; |
384 | 0 | opus_int32 amount; |
385 | |
|
386 | 0 | if (len < 1) |
387 | 0 | return OPUS_BAD_ARG; |
388 | 0 | if (len==new_len) |
389 | 0 | return OPUS_OK; |
390 | 0 | else if (len > new_len) |
391 | 0 | return OPUS_BAD_ARG; |
392 | 0 | amount = new_len - len; |
393 | | /* Seek to last stream */ |
394 | 0 | for (s=0;s<nb_streams-1;s++) |
395 | 0 | { |
396 | 0 | if (len<=0) |
397 | 0 | return OPUS_INVALID_PACKET; |
398 | 0 | count = opus_packet_parse_impl(data, len, 1, &toc, NULL, |
399 | 0 | size, NULL, &packet_offset, NULL, NULL); |
400 | 0 | if (count<0) |
401 | 0 | return count; |
402 | 0 | data += packet_offset; |
403 | 0 | len -= packet_offset; |
404 | 0 | } |
405 | 0 | return opus_packet_pad(data, len, len+amount); |
406 | 0 | } |
407 | | |
408 | | opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams) |
409 | 0 | { |
410 | 0 | int s; |
411 | 0 | unsigned char toc; |
412 | 0 | opus_int16 size[48]; |
413 | 0 | opus_int32 packet_offset; |
414 | 0 | OpusRepacketizer rp; |
415 | 0 | unsigned char *dst; |
416 | 0 | opus_int32 dst_len; |
417 | |
|
418 | 0 | if (len < 1) |
419 | 0 | return OPUS_BAD_ARG; |
420 | 0 | dst = data; |
421 | 0 | dst_len = 0; |
422 | | /* Unpad all frames */ |
423 | 0 | for (s=0;s<nb_streams;s++) |
424 | 0 | { |
425 | 0 | opus_int32 ret; |
426 | 0 | int i; |
427 | 0 | int self_delimited = s!=nb_streams-1; |
428 | 0 | if (len<=0) |
429 | 0 | return OPUS_INVALID_PACKET; |
430 | 0 | opus_repacketizer_init(&rp); |
431 | 0 | ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, |
432 | 0 | size, NULL, &packet_offset, NULL, NULL); |
433 | 0 | if (ret<0) |
434 | 0 | return ret; |
435 | 0 | ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited); |
436 | 0 | if (ret < 0) |
437 | 0 | return ret; |
438 | | /* Discard all padding and extensions. */ |
439 | 0 | for (i=0;i<rp.nb_frames;i++) { |
440 | 0 | rp.padding_len[i] = 0; |
441 | 0 | rp.paddings[i] = NULL; |
442 | 0 | } |
443 | 0 | ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0, NULL, 0); |
444 | 0 | if (ret < 0) |
445 | 0 | return ret; |
446 | 0 | else |
447 | 0 | dst_len += ret; |
448 | 0 | dst += ret; |
449 | 0 | data += packet_offset; |
450 | 0 | len -= packet_offset; |
451 | 0 | } |
452 | 0 | return dst_len; |
453 | 0 | } |
454 | | |