/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 | } |