blob: 45bb38480dc1acbccf8c03bcf927d7627098fc73 [file] [log] [blame]
Jean-Marc Valin369553f2011-08-10 08:54:49 -04001/* 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
Jean-Marc Valincb05e7c2012-04-20 16:40:24 -040018 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
Jean-Marc Valin369553f2011-08-10 08:54:49 -040020 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
Jean-Marc Valin369553f2011-08-10 08:54:49 -040032#include "opus.h"
Ralph Gilesbed02c92011-08-24 12:01:16 +120033#include "opus_private.h"
Jean-Marc Valin07f88402011-08-29 15:08:51 -040034#include "os_support.h"
Jean-Marc Valin369553f2011-08-10 08:54:49 -040035
Jean-Marc Valin369553f2011-08-10 08:54:49 -040036
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{
Gregory Maxwell756c7592011-10-09 18:08:06 -040050 OpusRepacketizer *rp;
51 rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size());
52 if(rp==NULL)return NULL;
53 return opus_repacketizer_init(rp);
Jean-Marc Valin369553f2011-08-10 08:54:49 -040054}
55
Jean-Marc Valinc2d86f02011-08-10 14:17:55 -040056void opus_repacketizer_destroy(OpusRepacketizer *rp)
57{
Jean-Marc Valin07f88402011-08-29 15:08:51 -040058 opus_free(rp);
Jean-Marc Valinc2d86f02011-08-10 14:17:55 -040059}
60
Jean-Marc Valin59354a72012-03-08 12:19:07 -050061int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len)
Jean-Marc Valin369553f2011-08-10 08:54:49 -040062{
63 unsigned char tmp_toc;
Gregory Maxwell3346d882011-10-10 01:02:14 -040064 int curr_nb_frames,ret;
Jean-Marc Valin369553f2011-08-10 08:54:49 -040065 /* Set of check ToC */
Gregory Maxwell3346d882011-10-10 01:02:14 -040066 if (len<1) return OPUS_INVALID_PACKET;
Jean-Marc Valin369553f2011-08-10 08:54:49 -040067 if (rp->nb_frames == 0)
68 {
69 rp->toc = data[0];
Gregory Maxwell3346d882011-10-10 01:02:14 -040070 rp->framesize = opus_packet_get_samples_per_frame(data, 8000);
Gregory Maxwelld6335ab2011-08-30 19:50:41 -040071 } else if ((rp->toc&0xFC) != (data[0]&0xFC))
Jean-Marc Valine8dbcb82011-08-10 09:47:30 -040072 {
73 /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/
Jean-Marc Valin331e9fe2011-09-06 14:30:19 -040074 return OPUS_INVALID_PACKET;
Jean-Marc Valine8dbcb82011-08-10 09:47:30 -040075 }
Jean-Marc Valin369553f2011-08-10 08:54:49 -040076 curr_nb_frames = opus_packet_get_nb_frames(data, len);
Gregory Maxwell3346d882011-10-10 01:02:14 -040077 if(curr_nb_frames<1) return OPUS_INVALID_PACKET;
Jean-Marc Valine8dbcb82011-08-10 09:47:30 -040078
Jean-Marc Valin369553f2011-08-10 08:54:49 -040079 /* Check the 120 ms maximum packet size */
Gregory Maxwell3346d882011-10-10 01:02:14 -040080 if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960)
Jean-Marc Valine8dbcb82011-08-10 09:47:30 -040081 {
Jean-Marc Valin331e9fe2011-09-06 14:30:19 -040082 return OPUS_INVALID_PACKET;
Jean-Marc Valine8dbcb82011-08-10 09:47:30 -040083 }
Jean-Marc Valin369553f2011-08-10 08:54:49 -040084
Gregory Maxwell3346d882011-10-10 01:02:14 -040085 ret=opus_packet_parse(data, len, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL);
86 if(ret<1)return ret;
Jean-Marc Valin369553f2011-08-10 08:54:49 -040087
Jean-Marc Valine8dbcb82011-08-10 09:47:30 -040088 rp->nb_frames += curr_nb_frames;
89 return OPUS_OK;
Jean-Marc Valin369553f2011-08-10 08:54:49 -040090}
91
Jean-Marc Valinc2d86f02011-08-10 14:17:55 -040092int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp)
93{
94 return rp->nb_frames;
95}
96
Jean-Marc Valinc5635d22013-11-13 14:08:22 -050097opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
98 unsigned char *data, opus_int32 maxlen, int self_delimited, int pad)
Jean-Marc Valin369553f2011-08-10 08:54:49 -040099{
Gregory Maxwell3346d882011-10-10 01:02:14 -0400100 int i, count;
101 opus_int32 tot_size;
Jean-Marc Valin35930692013-05-18 02:50:40 -0400102 opus_int16 *len;
Jean-Marc Valinc2d86f02011-08-10 14:17:55 -0400103 const unsigned char **frames;
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500104 unsigned char * ptr;
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400105
Jean-Marc Valine8dbcb82011-08-10 09:47:30 -0400106 if (begin<0 || begin>=end || end>rp->nb_frames)
107 {
108 /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400109 return OPUS_BAD_ARG;
Jean-Marc Valine8dbcb82011-08-10 09:47:30 -0400110 }
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400111 count = end-begin;
112
Jean-Marc Valinc2d86f02011-08-10 14:17:55 -0400113 len = rp->len+begin;
114 frames = rp->frames+begin;
Jean-Marc Valin131d8882011-09-09 13:56:09 -0400115 if (self_delimited)
Gregory Maxwell92c896e2011-11-28 23:19:08 -0500116 tot_size = 1 + (len[count-1]>=252);
Jean-Marc Valin131d8882011-09-09 13:56:09 -0400117 else
118 tot_size = 0;
119
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500120 ptr = data;
121 if (count==1)
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400122 {
123 /* Code 0 */
Jean-Marc Valin131d8882011-09-09 13:56:09 -0400124 tot_size += len[0]+1;
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400125 if (tot_size > maxlen)
126 return OPUS_BUFFER_TOO_SMALL;
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500127 *ptr++ = rp->toc&0xFC;
128 } else if (count==2)
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400129 {
Jean-Marc Valinc2d86f02011-08-10 14:17:55 -0400130 if (len[1] == len[0])
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400131 {
132 /* Code 1 */
Jean-Marc Valin131d8882011-09-09 13:56:09 -0400133 tot_size += 2*len[0]+1;
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400134 if (tot_size > maxlen)
135 return OPUS_BUFFER_TOO_SMALL;
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500136 *ptr++ = (rp->toc&0xFC) | 0x1;
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400137 } else {
138 /* Code 2 */
Jean-Marc Valin131d8882011-09-09 13:56:09 -0400139 tot_size += len[0]+len[1]+2+(len[0]>=252);
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400140 if (tot_size > maxlen)
141 return OPUS_BUFFER_TOO_SMALL;
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500142 *ptr++ = (rp->toc&0xFC) | 0x2;
143 ptr += encode_size(len[0], ptr);
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400144 }
145 }
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500146 if (count > 2 || (pad && tot_size < maxlen))
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400147 {
148 /* Code 3 */
149 int vbr;
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500150 int pad_amount=0;
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400151
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500152 /* Restart the process for the padding case */
153 ptr = data;
154 if (self_delimited)
155 tot_size = 1 + (len[count-1]>=252);
156 else
157 tot_size = 0;
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400158 vbr = 0;
Jean-Marc Valinc2d86f02011-08-10 14:17:55 -0400159 for (i=1;i<count;i++)
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400160 {
Jean-Marc Valinc2d86f02011-08-10 14:17:55 -0400161 if (len[i] != len[0])
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400162 {
163 vbr=1;
164 break;
165 }
166 }
167 if (vbr)
168 {
Jean-Marc Valin131d8882011-09-09 13:56:09 -0400169 tot_size += 2;
Jean-Marc Valinc2d86f02011-08-10 14:17:55 -0400170 for (i=0;i<count-1;i++)
171 tot_size += 1 + (len[i]>=252) + len[i];
172 tot_size += len[count-1];
173
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400174 if (tot_size > maxlen)
175 return OPUS_BUFFER_TOO_SMALL;
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500176 *ptr++ = (rp->toc&0xFC) | 0x3;
177 *ptr++ = count | 0x80;
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400178 } else {
Jean-Marc Valin131d8882011-09-09 13:56:09 -0400179 tot_size += count*len[0]+2;
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400180 if (tot_size > maxlen)
181 return OPUS_BUFFER_TOO_SMALL;
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500182 *ptr++ = (rp->toc&0xFC) | 0x3;
183 *ptr++ = count;
184 }
185 pad_amount = pad ? (maxlen-tot_size) : 0;
186 if (pad_amount != 0)
187 {
188 int nb_255s;
189 data[1] |= 0x40;
190 nb_255s = (pad_amount-1)/255;
191 for (i=0;i<nb_255s;i++)
192 *ptr++ = 255;
193 *ptr++ = pad_amount-255*nb_255s-1;
194 tot_size += pad_amount;
195 }
196 if (vbr)
197 {
198 for (i=0;i<count-1;i++)
199 ptr += encode_size(len[i], ptr);
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400200 }
201 }
Gregory Maxwellafd05ac2011-10-30 19:57:22 -0400202 if (self_delimited) {
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500203 int sdlen = encode_size(len[count-1], ptr);
204 ptr += sdlen;
Gregory Maxwellafd05ac2011-10-30 19:57:22 -0400205 }
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400206 /* Copy the actual data */
Jean-Marc Valinc2d86f02011-08-10 14:17:55 -0400207 for (i=0;i<count;i++)
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400208 {
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500209 /* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place
210 padding from opus_packet_pad */
211 OPUS_MOVE(ptr, frames[i], len[i]);
212 ptr += len[i];
213 }
214 if (pad)
215 {
216 for (i=ptr-data;i<maxlen;i++)
217 data[i] = 0;
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400218 }
219 return tot_size;
220}
221
Gregory Maxwell3346d882011-10-10 01:02:14 -0400222opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen)
Jean-Marc Valin131d8882011-09-09 13:56:09 -0400223{
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500224 return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0);
Jean-Marc Valin131d8882011-09-09 13:56:09 -0400225}
226
Gregory Maxwell3346d882011-10-10 01:02:14 -0400227opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen)
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400228{
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500229 return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0);
Jean-Marc Valin369553f2011-08-10 08:54:49 -0400230}
231
Jean-Marc Valinc5635d22013-11-13 14:08:22 -0500232int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
233{
234 OpusRepacketizer rp;
235 opus_int32 ret;
236 if (len==new_len)
237 return OPUS_OK;
238 else if (len > new_len)
239 return OPUS_BAD_ARG;
240 opus_repacketizer_init(&rp);
241 /* Moving payload to the end of the packet so we can do in-place padding */
242 OPUS_MOVE(data+new_len-len, data, len);
243 opus_repacketizer_cat(&rp, data+new_len-len, len);
244 ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1);
245 if (ret > 0)
246 return OPUS_OK;
247 else
248 return ret;
249}