• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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       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       /* Fill padding with zeros. */
223       while (ptr<data+maxlen)
224          *ptr++=0;
225    }
226    return tot_size;
227 }
228 
opus_repacketizer_out_range(OpusRepacketizer * rp,int begin,int end,unsigned char * data,opus_int32 maxlen)229 opus_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 
opus_repacketizer_out(OpusRepacketizer * rp,unsigned char * data,opus_int32 maxlen)234 opus_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 
opus_packet_pad(unsigned char * data,opus_int32 len,opus_int32 new_len)239 int 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);
252    ret = opus_repacketizer_cat(&rp, data+new_len-len, len);
253    if (ret != OPUS_OK)
254       return ret;
255    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 
opus_packet_unpad(unsigned char * data,opus_int32 len)262 opus_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 
opus_multistream_packet_pad(unsigned char * data,opus_int32 len,opus_int32 new_len,int nb_streams)277 int 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 
opus_multistream_packet_unpad(unsigned char * data,opus_int32 len,int nb_streams)308 opus_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 
349