blob: a62675ce940e8b2421dc547f242c51de282f8ee2 [file] [log] [blame]
Alexandre Lision744f7422013-09-25 11:39:37 -04001/* 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
36
37int opus_repacketizer_get_size(void)
38{
39 return sizeof(OpusRepacketizer);
40}
41
42OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp)
43{
44 rp->nb_frames = 0;
45 return rp;
46}
47
48OpusRepacketizer *opus_repacketizer_create(void)
49{
50 OpusRepacketizer *rp;
51 rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size());
52 if(rp==NULL)return NULL;
53 return opus_repacketizer_init(rp);
54}
55
56void opus_repacketizer_destroy(OpusRepacketizer *rp)
57{
58 opus_free(rp);
59}
60
Alexandre Lision85382382014-01-27 15:54:16 -050061static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited)
Alexandre Lision744f7422013-09-25 11:39:37 -040062{
63 unsigned char tmp_toc;
64 int curr_nb_frames,ret;
65 /* Set of check ToC */
66 if (len<1) return OPUS_INVALID_PACKET;
67 if (rp->nb_frames == 0)
68 {
69 rp->toc = data[0];
70 rp->framesize = opus_packet_get_samples_per_frame(data, 8000);
71 } else if ((rp->toc&0xFC) != (data[0]&0xFC))
72 {
73 /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/
74 return OPUS_INVALID_PACKET;
75 }
76 curr_nb_frames = opus_packet_get_nb_frames(data, len);
77 if(curr_nb_frames<1) return OPUS_INVALID_PACKET;
78
79 /* Check the 120 ms maximum packet size */
80 if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960)
81 {
82 return OPUS_INVALID_PACKET;
83 }
84
Alexandre Lision85382382014-01-27 15:54:16 -050085 ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL);
Alexandre Lision744f7422013-09-25 11:39:37 -040086 if(ret<1)return ret;
87
88 rp->nb_frames += curr_nb_frames;
89 return OPUS_OK;
90}
91
Alexandre Lision85382382014-01-27 15:54:16 -050092int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len)
93{
94 return opus_repacketizer_cat_impl(rp, data, len, 0);
95}
96
Alexandre Lision744f7422013-09-25 11:39:37 -040097int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp)
98{
99 return rp->nb_frames;
100}
101
Alexandre Lision85382382014-01-27 15:54:16 -0500102opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
103 unsigned char *data, opus_int32 maxlen, int self_delimited, int pad)
Alexandre Lision744f7422013-09-25 11:39:37 -0400104{
105 int i, count;
106 opus_int32 tot_size;
107 opus_int16 *len;
108 const unsigned char **frames;
Alexandre Lision85382382014-01-27 15:54:16 -0500109 unsigned char * ptr;
Alexandre Lision744f7422013-09-25 11:39:37 -0400110
111 if (begin<0 || begin>=end || end>rp->nb_frames)
112 {
113 /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/
114 return OPUS_BAD_ARG;
115 }
116 count = end-begin;
117
118 len = rp->len+begin;
119 frames = rp->frames+begin;
120 if (self_delimited)
121 tot_size = 1 + (len[count-1]>=252);
122 else
123 tot_size = 0;
124
Alexandre Lision85382382014-01-27 15:54:16 -0500125 ptr = data;
126 if (count==1)
Alexandre Lision744f7422013-09-25 11:39:37 -0400127 {
128 /* Code 0 */
129 tot_size += len[0]+1;
130 if (tot_size > maxlen)
131 return OPUS_BUFFER_TOO_SMALL;
Alexandre Lision85382382014-01-27 15:54:16 -0500132 *ptr++ = rp->toc&0xFC;
133 } else if (count==2)
Alexandre Lision744f7422013-09-25 11:39:37 -0400134 {
135 if (len[1] == len[0])
136 {
137 /* Code 1 */
138 tot_size += 2*len[0]+1;
139 if (tot_size > maxlen)
140 return OPUS_BUFFER_TOO_SMALL;
Alexandre Lision85382382014-01-27 15:54:16 -0500141 *ptr++ = (rp->toc&0xFC) | 0x1;
Alexandre Lision744f7422013-09-25 11:39:37 -0400142 } else {
143 /* Code 2 */
144 tot_size += len[0]+len[1]+2+(len[0]>=252);
145 if (tot_size > maxlen)
146 return OPUS_BUFFER_TOO_SMALL;
Alexandre Lision85382382014-01-27 15:54:16 -0500147 *ptr++ = (rp->toc&0xFC) | 0x2;
148 ptr += encode_size(len[0], ptr);
Alexandre Lision744f7422013-09-25 11:39:37 -0400149 }
150 }
Alexandre Lision85382382014-01-27 15:54:16 -0500151 if (count > 2 || (pad && tot_size < maxlen))
Alexandre Lision744f7422013-09-25 11:39:37 -0400152 {
153 /* Code 3 */
154 int vbr;
Alexandre Lision85382382014-01-27 15:54:16 -0500155 int pad_amount=0;
Alexandre Lision744f7422013-09-25 11:39:37 -0400156
Alexandre Lision85382382014-01-27 15:54:16 -0500157 /* Restart the process for the padding case */
158 ptr = data;
159 if (self_delimited)
160 tot_size = 1 + (len[count-1]>=252);
161 else
162 tot_size = 0;
Alexandre Lision744f7422013-09-25 11:39:37 -0400163 vbr = 0;
164 for (i=1;i<count;i++)
165 {
166 if (len[i] != len[0])
167 {
168 vbr=1;
169 break;
170 }
171 }
172 if (vbr)
173 {
174 tot_size += 2;
175 for (i=0;i<count-1;i++)
176 tot_size += 1 + (len[i]>=252) + len[i];
177 tot_size += len[count-1];
178
179 if (tot_size > maxlen)
180 return OPUS_BUFFER_TOO_SMALL;
Alexandre Lision85382382014-01-27 15:54:16 -0500181 *ptr++ = (rp->toc&0xFC) | 0x3;
182 *ptr++ = count | 0x80;
Alexandre Lision744f7422013-09-25 11:39:37 -0400183 } else {
184 tot_size += count*len[0]+2;
185 if (tot_size > maxlen)
186 return OPUS_BUFFER_TOO_SMALL;
Alexandre Lision85382382014-01-27 15:54:16 -0500187 *ptr++ = (rp->toc&0xFC) | 0x3;
188 *ptr++ = count;
189 }
190 pad_amount = pad ? (maxlen-tot_size) : 0;
191 if (pad_amount != 0)
192 {
193 int nb_255s;
194 data[1] |= 0x40;
195 nb_255s = (pad_amount-1)/255;
196 for (i=0;i<nb_255s;i++)
197 *ptr++ = 255;
198 *ptr++ = pad_amount-255*nb_255s-1;
199 tot_size += pad_amount;
200 }
201 if (vbr)
202 {
203 for (i=0;i<count-1;i++)
204 ptr += encode_size(len[i], ptr);
Alexandre Lision744f7422013-09-25 11:39:37 -0400205 }
206 }
Alexandre Lision744f7422013-09-25 11:39:37 -0400207 if (self_delimited) {
Alexandre Lision85382382014-01-27 15:54:16 -0500208 int sdlen = encode_size(len[count-1], ptr);
209 ptr += sdlen;
Alexandre Lision744f7422013-09-25 11:39:37 -0400210 }
211 /* Copy the actual data */
212 for (i=0;i<count;i++)
213 {
Alexandre Lision85382382014-01-27 15:54:16 -0500214 /* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place
215 padding from opus_packet_pad or opus_packet_unpad(). */
216 celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]);
217 OPUS_MOVE(ptr, frames[i], len[i]);
218 ptr += len[i];
219 }
220 if (pad)
221 {
222 for (i=ptr-data;i<maxlen;i++)
223 data[i] = 0;
Alexandre Lision744f7422013-09-25 11:39:37 -0400224 }
225 return tot_size;
226}
227
228opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen)
229{
Alexandre Lision85382382014-01-27 15:54:16 -0500230 return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0);
Alexandre Lision744f7422013-09-25 11:39:37 -0400231}
232
233opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen)
234{
Alexandre Lision85382382014-01-27 15:54:16 -0500235 return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0);
Alexandre Lision744f7422013-09-25 11:39:37 -0400236}
237
Alexandre Lision85382382014-01-27 15:54:16 -0500238int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
239{
240 OpusRepacketizer rp;
241 opus_int32 ret;
242 if (len < 1)
243 return OPUS_BAD_ARG;
244 if (len==new_len)
245 return OPUS_OK;
246 else if (len > new_len)
247 return OPUS_BAD_ARG;
248 opus_repacketizer_init(&rp);
249 /* Moving payload to the end of the packet so we can do in-place padding */
250 OPUS_MOVE(data+new_len-len, data, len);
251 opus_repacketizer_cat(&rp, data+new_len-len, len);
252 ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1);
253 if (ret > 0)
254 return OPUS_OK;
255 else
256 return ret;
257}
258
259opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len)
260{
261 OpusRepacketizer rp;
262 opus_int32 ret;
263 if (len < 1)
264 return OPUS_BAD_ARG;
265 opus_repacketizer_init(&rp);
266 ret = opus_repacketizer_cat(&rp, data, len);
267 if (ret < 0)
268 return ret;
269 ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0);
270 celt_assert(ret > 0 && ret <= len);
271 return ret;
272}
273
274int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams)
275{
276 int s;
277 int count;
278 unsigned char toc;
279 opus_int16 size[48];
280 opus_int32 packet_offset;
281 opus_int32 amount;
282
283 if (len < 1)
284 return OPUS_BAD_ARG;
285 if (len==new_len)
286 return OPUS_OK;
287 else if (len > new_len)
288 return OPUS_BAD_ARG;
289 amount = new_len - len;
290 /* Seek to last stream */
291 for (s=0;s<nb_streams-1;s++)
292 {
293 if (len<=0)
294 return OPUS_INVALID_PACKET;
295 count = opus_packet_parse_impl(data, len, 1, &toc, NULL,
296 size, NULL, &packet_offset);
297 if (count<0)
298 return count;
299 data += packet_offset;
300 len -= packet_offset;
301 }
302 return opus_packet_pad(data, len, len+amount);
303}
304
305opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams)
306{
307 int s;
308 unsigned char toc;
309 opus_int16 size[48];
310 opus_int32 packet_offset;
311 OpusRepacketizer rp;
312 unsigned char *dst;
313 opus_int32 dst_len;
314
315 if (len < 1)
316 return OPUS_BAD_ARG;
317 dst = data;
318 dst_len = 0;
319 /* Unpad all frames */
320 for (s=0;s<nb_streams;s++)
321 {
322 opus_int32 ret;
323 int self_delimited = s!=nb_streams-1;
324 if (len<=0)
325 return OPUS_INVALID_PACKET;
326 opus_repacketizer_init(&rp);
327 ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
328 size, NULL, &packet_offset);
329 if (ret<0)
330 return ret;
331 ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited);
332 if (ret < 0)
333 return ret;
334 ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0);
335 if (ret < 0)
336 return ret;
337 else
338 dst_len += ret;
339 dst += ret;
340 data += packet_offset;
341 len -= packet_offset;
342 }
343 return dst_len;
344}
Alexandre Lision744f7422013-09-25 11:39:37 -0400345