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 
opus_repacketizer_get_size(void)37 int opus_repacketizer_get_size(void)
38 {
39    return sizeof(OpusRepacketizer);
40 }
41 
opus_repacketizer_init(OpusRepacketizer * rp)42 OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp)
43 {
44    rp->nb_frames = 0;
45    return rp;
46 }
47 
opus_repacketizer_create(void)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 
opus_repacketizer_destroy(OpusRepacketizer * rp)56 void opus_repacketizer_destroy(OpusRepacketizer *rp)
57 {
58    opus_free(rp);
59 }
60 
opus_repacketizer_cat_impl(OpusRepacketizer * rp,const unsigned char * data,opus_int32 len,int self_delimited)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 
opus_repacketizer_cat(OpusRepacketizer * rp,const unsigned char * data,opus_int32 len)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 
opus_repacketizer_get_nb_frames(OpusRepacketizer * rp)97 int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp)
98 {
99    return rp->nb_frames;
100 }
101 
opus_repacketizer_out_range_impl(OpusRepacketizer * rp,int begin,int end,unsigned char * data,opus_int32 maxlen,int self_delimited,int pad)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       /* assert disabled because it's not valid in C. */
217       /* celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]); */
218       OPUS_MOVE(ptr, frames[i], len[i]);
219       ptr += len[i];
220    }
221    if (pad)
222    {
223       /* Fill padding with zeros. */
224       while (ptr<data+maxlen)
225          *ptr++=0;
226    }
227    return tot_size;
228 }
229 
opus_repacketizer_out_range(OpusRepacketizer * rp,int begin,int end,unsigned char * data,opus_int32 maxlen)230 opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen)
231 {
232    return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0);
233 }
234 
opus_repacketizer_out(OpusRepacketizer * rp,unsigned char * data,opus_int32 maxlen)235 opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen)
236 {
237    return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0);
238 }
239 
opus_packet_pad(unsigned char * data,opus_int32 len,opus_int32 new_len)240 int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
241 {
242    OpusRepacketizer rp;
243    opus_int32 ret;
244    if (len < 1)
245       return OPUS_BAD_ARG;
246    if (len==new_len)
247       return OPUS_OK;
248    else if (len > new_len)
249       return OPUS_BAD_ARG;
250    opus_repacketizer_init(&rp);
251    /* Moving payload to the end of the packet so we can do in-place padding */
252    OPUS_MOVE(data+new_len-len, data, len);
253    ret = opus_repacketizer_cat(&rp, data+new_len-len, len);
254    if (ret != OPUS_OK)
255       return ret;
256    ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1);
257    if (ret > 0)
258       return OPUS_OK;
259    else
260       return ret;
261 }
262 
opus_packet_unpad(unsigned char * data,opus_int32 len)263 opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len)
264 {
265    OpusRepacketizer rp;
266    opus_int32 ret;
267    if (len < 1)
268       return OPUS_BAD_ARG;
269    opus_repacketizer_init(&rp);
270    ret = opus_repacketizer_cat(&rp, data, len);
271    if (ret < 0)
272       return ret;
273    ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0);
274    celt_assert(ret > 0 && ret <= len);
275    return ret;
276 }
277 
opus_multistream_packet_pad(unsigned char * data,opus_int32 len,opus_int32 new_len,int nb_streams)278 int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams)
279 {
280    int s;
281    int count;
282    unsigned char toc;
283    opus_int16 size[48];
284    opus_int32 packet_offset;
285    opus_int32 amount;
286 
287    if (len < 1)
288       return OPUS_BAD_ARG;
289    if (len==new_len)
290       return OPUS_OK;
291    else if (len > new_len)
292       return OPUS_BAD_ARG;
293    amount = new_len - len;
294    /* Seek to last stream */
295    for (s=0;s<nb_streams-1;s++)
296    {
297       if (len<=0)
298          return OPUS_INVALID_PACKET;
299       count = opus_packet_parse_impl(data, len, 1, &toc, NULL,
300                                      size, NULL, &packet_offset);
301       if (count<0)
302          return count;
303       data += packet_offset;
304       len -= packet_offset;
305    }
306    return opus_packet_pad(data, len, len+amount);
307 }
308 
opus_multistream_packet_unpad(unsigned char * data,opus_int32 len,int nb_streams)309 opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams)
310 {
311    int s;
312    unsigned char toc;
313    opus_int16 size[48];
314    opus_int32 packet_offset;
315    OpusRepacketizer rp;
316    unsigned char *dst;
317    opus_int32 dst_len;
318 
319    if (len < 1)
320       return OPUS_BAD_ARG;
321    dst = data;
322    dst_len = 0;
323    /* Unpad all frames */
324    for (s=0;s<nb_streams;s++)
325    {
326       opus_int32 ret;
327       int self_delimited = s!=nb_streams-1;
328       if (len<=0)
329          return OPUS_INVALID_PACKET;
330       opus_repacketizer_init(&rp);
331       ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
332                                      size, NULL, &packet_offset);
333       if (ret<0)
334          return ret;
335       ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited);
336       if (ret < 0)
337          return ret;
338       ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0);
339       if (ret < 0)
340          return ret;
341       else
342          dst_len += ret;
343       dst += ret;
344       data += packet_offset;
345       len -= packet_offset;
346    }
347    return dst_len;
348 }
349 
350