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
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   {
222      for (i=ptr-data;i<maxlen;i++)
223         data[i] = 0;
224   }
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{
230   return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0);
231}
232
233opus_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
238int 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}
345
346