blob: c80ee7f0014861261b27655a8c6d5aa918b4fbf7 [file] [log] [blame]
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -08001/* 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
61static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited)
62{
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
85 ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL);
86 if(ret<1)return ret;
87
88 rp->nb_frames += curr_nb_frames;
89 return OPUS_OK;
90}
91
92int 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
97int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp)
98{
99 return rp->nb_frames;
100}
101
102opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
103 unsigned char *data, opus_int32 maxlen, int self_delimited, int pad)
104{
105 int i, count;
106 opus_int32 tot_size;
107 opus_int16 *len;
108 const unsigned char **frames;
109 unsigned char * ptr;
110
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
125 ptr = data;
126 if (count==1)
127 {
128 /* Code 0 */
129 tot_size += len[0]+1;
130 if (tot_size > maxlen)
131 return OPUS_BUFFER_TOO_SMALL;
132 *ptr++ = rp->toc&0xFC;
133 } else if (count==2)
134 {
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;
141 *ptr++ = (rp->toc&0xFC) | 0x1;
142 } 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;
147 *ptr++ = (rp->toc&0xFC) | 0x2;
148 ptr += encode_size(len[0], ptr);
149 }
150 }
151 if (count > 2 || (pad && tot_size < maxlen))
152 {
153 /* Code 3 */
154 int vbr;
155 int pad_amount=0;
156
157 /* 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;
163 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;
181 *ptr++ = (rp->toc&0xFC) | 0x3;
182 *ptr++ = count | 0x80;
183 } else {
184 tot_size += count*len[0]+2;
185 if (tot_size > maxlen)
186 return OPUS_BUFFER_TOO_SMALL;
187 *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);
205 }
206 }
207 if (self_delimited) {
208 int sdlen = encode_size(len[count-1], ptr);
209 ptr += sdlen;
210 }
211 /* Copy the actual data */
212 for (i=0;i<count;i++)
213 {
214 /* 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 {
flimc91ee5b2016-01-26 14:33:44 +0100222 /* Fill padding with zeros. */
223 while (ptr<data+maxlen)
224 *ptr++=0;
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800225 }
226 return tot_size;
227}
228
229opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen)
230{
231 return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0);
232}
233
234opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen)
235{
236 return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0);
237}
238
239int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
240{
241 OpusRepacketizer rp;
242 opus_int32 ret;
243 if (len < 1)
244 return OPUS_BAD_ARG;
245 if (len==new_len)
246 return OPUS_OK;
247 else if (len > new_len)
248 return OPUS_BAD_ARG;
249 opus_repacketizer_init(&rp);
250 /* Moving payload to the end of the packet so we can do in-place padding */
251 OPUS_MOVE(data+new_len-len, data, len);
Felicia Limd03c3732016-07-25 20:28:37 +0200252 ret = opus_repacketizer_cat(&rp, data+new_len-len, len);
253 if (ret != OPUS_OK)
254 return ret;
Vignesh Venkatasubramanian2bd8b542014-02-20 10:50:35 -0800255 ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1);
256 if (ret > 0)
257 return OPUS_OK;
258 else
259 return ret;
260}
261
262opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len)
263{
264 OpusRepacketizer rp;
265 opus_int32 ret;
266 if (len < 1)
267 return OPUS_BAD_ARG;
268 opus_repacketizer_init(&rp);
269 ret = opus_repacketizer_cat(&rp, data, len);
270 if (ret < 0)
271 return ret;
272 ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0);
273 celt_assert(ret > 0 && ret <= len);
274 return ret;
275}
276
277int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams)
278{
279 int s;
280 int count;
281 unsigned char toc;
282 opus_int16 size[48];
283 opus_int32 packet_offset;
284 opus_int32 amount;
285
286 if (len < 1)
287 return OPUS_BAD_ARG;
288 if (len==new_len)
289 return OPUS_OK;
290 else if (len > new_len)
291 return OPUS_BAD_ARG;
292 amount = new_len - len;
293 /* Seek to last stream */
294 for (s=0;s<nb_streams-1;s++)
295 {
296 if (len<=0)
297 return OPUS_INVALID_PACKET;
298 count = opus_packet_parse_impl(data, len, 1, &toc, NULL,
299 size, NULL, &packet_offset);
300 if (count<0)
301 return count;
302 data += packet_offset;
303 len -= packet_offset;
304 }
305 return opus_packet_pad(data, len, len+amount);
306}
307
308opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams)
309{
310 int s;
311 unsigned char toc;
312 opus_int16 size[48];
313 opus_int32 packet_offset;
314 OpusRepacketizer rp;
315 unsigned char *dst;
316 opus_int32 dst_len;
317
318 if (len < 1)
319 return OPUS_BAD_ARG;
320 dst = data;
321 dst_len = 0;
322 /* Unpad all frames */
323 for (s=0;s<nb_streams;s++)
324 {
325 opus_int32 ret;
326 int self_delimited = s!=nb_streams-1;
327 if (len<=0)
328 return OPUS_INVALID_PACKET;
329 opus_repacketizer_init(&rp);
330 ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
331 size, NULL, &packet_offset);
332 if (ret<0)
333 return ret;
334 ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited);
335 if (ret < 0)
336 return ret;
337 ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0);
338 if (ret < 0)
339 return ret;
340 else
341 dst_len += ret;
342 dst += ret;
343 data += packet_offset;
344 len -= packet_offset;
345 }
346 return dst_len;
347}
348