|
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 |
|
36 |
|
37 int opus_repacketizer_get_size(void) |
|
38 { |
|
39 return sizeof(OpusRepacketizer); |
|
40 } |
|
41 |
|
42 OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) |
|
43 { |
|
44 rp->nb_frames = 0; |
|
45 return rp; |
|
46 } |
|
47 |
|
48 OpusRepacketizer *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 |
|
56 void opus_repacketizer_destroy(OpusRepacketizer *rp) |
|
57 { |
|
58 opus_free(rp); |
|
59 } |
|
60 |
|
61 static 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 |
|
92 int 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 |
|
97 int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) |
|
98 { |
|
99 return rp->nb_frames; |
|
100 } |
|
101 |
|
102 opus_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 { |
|
222 for (i=ptr-data;i<maxlen;i++) |
|
223 data[i] = 0; |
|
224 } |
|
225 return tot_size; |
|
226 } |
|
227 |
|
228 opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) |
|
229 { |
|
230 return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0); |
|
231 } |
|
232 |
|
233 opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) |
|
234 { |
|
235 return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0); |
|
236 } |
|
237 |
|
238 int 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 |
|
259 opus_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 |
|
274 int 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 |
|
305 opus_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 } |
|
345 |