2f6fce400cd75b96b9dc1b2aff870a86f66780d5
[opus-tools.git] / src / diag_range.c
1 /* Copyright (C)2012 Xiph.Org Foundation
2    Copyright (C)2012 Gregory Maxwell
3    Copyright (C)2012 Jean-Marc Valin
4    File: diag_range.c
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
10    - Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12
13    - Redistributions in binary form must reproduce the above copyright
14    notice, this list of conditions and the following disclaimer in the
15    documentation and/or other materials provided with the distribution.
16
17    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
21    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #ifdef _WIN32
35 #define I64FORMAT "I64d"
36 #define I64uFORMAT "I64u"
37 #else
38 #define I64FORMAT "lld"
39 #define I64uFORMAT "llu"
40 #endif
41
42 #include <stdio.h>
43 #include <opus.h>
44 #include "diag_range.h"
45
46 /*This is some non-exported code copied wholesale from libopus.
47  *Normal programs shouldn't need these functions, but we use them here
48  *to parse deep inside multichannel packets in order to get diagnostic
49  *data for save-range. If you're thinking about copying it and you aren't
50  *making an opus stream diagnostic tool, you're probably doing something
51  *wrong.*/
52 static int parse_size(const unsigned char *data, opus_int32 len, short *size)
53 {
54    if (len<1)
55    {
56       *size = -1;
57       return -1;
58    } else if (data[0]<252)
59    {
60       *size = data[0];
61       return 1;
62    } else if (len<2)
63    {
64       *size = -1;
65       return -1;
66    } else {
67       *size = 4*data[1] + data[0];
68       return 2;
69    }
70 }
71
72 static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
73       int self_delimited, unsigned char *out_toc,
74       const unsigned char *frames[48], short size[48], int *payload_offset)
75 {
76    int i, bytes;
77    int count;
78    int cbr;
79    unsigned char ch, toc;
80    int framesize;
81    int last_size;
82    const unsigned char *data0 = data;
83
84    if (size==NULL)
85       return OPUS_BAD_ARG;
86
87    framesize = opus_packet_get_samples_per_frame(data, 48000);
88
89    cbr = 0;
90    toc = *data++;
91    len--;
92    last_size = len;
93    switch (toc&0x3)
94    {
95    /* One frame */
96    case 0:
97       count=1;
98       break;
99    /* Two CBR frames */
100    case 1:
101       count=2;
102       cbr = 1;
103       if (!self_delimited)
104       {
105          if (len&0x1)
106             return OPUS_INVALID_PACKET;
107          size[0] = last_size = len/2;
108       }
109       break;
110    /* Two VBR frames */
111    case 2:
112       count = 2;
113       bytes = parse_size(data, len, size);
114       len -= bytes;
115       if (size[0]<0 || size[0] > len)
116          return OPUS_INVALID_PACKET;
117       data += bytes;
118       last_size = len-size[0];
119       break;
120    /* Multiple CBR/VBR frames (from 0 to 120 ms) */
121    case 3:
122       if (len<1)
123          return OPUS_INVALID_PACKET;
124       /* Number of frames encoded in bits 0 to 5 */
125       ch = *data++;
126       count = ch&0x3F;
127       if (count <= 0 || framesize*count > 5760)
128          return OPUS_INVALID_PACKET;
129       len--;
130       /* Padding flag is bit 6 */
131       if (ch&0x40)
132       {
133          int padding=0;
134          int p;
135          do {
136             if (len<=0)
137                return OPUS_INVALID_PACKET;
138             p = *data++;
139             len--;
140             padding += p==255 ? 254: p;
141          } while (p==255);
142          len -= padding;
143       }
144       if (len<0)
145          return OPUS_INVALID_PACKET;
146       /* VBR flag is bit 7 */
147       cbr = !(ch&0x80);
148       if (!cbr)
149       {
150          /* VBR case */
151          last_size = len;
152          for (i=0;i<count-1;i++)
153          {
154             bytes = parse_size(data, len, size+i);
155             len -= bytes;
156             if (size[i]<0 || size[i] > len)
157                return OPUS_INVALID_PACKET;
158             data += bytes;
159             last_size -= bytes+size[i];
160          }
161          if (last_size<0)
162             return OPUS_INVALID_PACKET;
163       } else if (!self_delimited)
164       {
165          /* CBR case */
166          last_size = len/count;
167          if (last_size*count!=len)
168             return OPUS_INVALID_PACKET;
169          for (i=0;i<count-1;i++)
170             size[i] = last_size;
171       }
172       break;
173    }
174    /* Self-delimited framing has an extra size for the last frame. */
175    if (self_delimited)
176    {
177       bytes = parse_size(data, len, size+count-1);
178       len -= bytes;
179       if (size[count-1]<0 || size[count-1] > len)
180          return OPUS_INVALID_PACKET;
181       data += bytes;
182       /* For CBR packets, apply the size to all the frames. */
183       if (cbr)
184       {
185          if (size[count-1]*count > len)
186             return OPUS_INVALID_PACKET;
187          for (i=0;i<count-1;i++)
188             size[i] = size[count-1];
189       } else if(size[count-1] > last_size)
190          return OPUS_INVALID_PACKET;
191    } else
192    {
193       /* Because it's not encoded explicitly, it's possible the size of the
194          last packet (or all the packets, for the CBR case) is larger than
195          1275. Reject them here.*/
196       if (last_size > 1275)
197          return OPUS_INVALID_PACKET;
198       size[count-1] = last_size;
199    }
200
201    if (frames)
202    {
203       for (i=0;i<count;i++)
204       {
205          frames[i] = data;
206          data += size[i];
207       }
208    }
209
210    if (out_toc)
211       *out_toc = toc;
212
213    if (payload_offset)
214       *payload_offset = data-data0;
215
216    return count;
217 }
218
219 void save_range(FILE *frange, int frame_size, unsigned char *packet, int nbBytes, opus_uint32 *rngs, int nb_streams){
220   int i, parsed_size;
221   const unsigned char *subpkt;
222   static const char *bw_strings[5]={"NB","MB","WB","SWB","FB"};
223   static const char *mode_strings[3]={"LP","HYB","MDCT"};
224   fprintf(frange,"%d, %d, ",frame_size,nbBytes);
225   subpkt=packet;
226   parsed_size=nbBytes;
227   for(i=0;i<nb_streams;i++){
228     int j,payload_offset,nf;
229     const unsigned char *frames[48];
230     unsigned char toc;
231     short size[48];
232     payload_offset=0;
233     nf=opus_packet_parse_impl(subpkt,parsed_size,i+1!=nb_streams,
234       &toc,frames,size,&payload_offset);
235     fprintf(frange,"[[%d",(int)(frames[0]-subpkt));
236     for(j=0;j<nf;j++)fprintf(frange,", %d",size[j]);
237     fprintf(frange,"], %s, %s, %c, %d",
238        mode_strings[((((subpkt[0]>>3)+48)&92)+4)>>5],
239        bw_strings[opus_packet_get_bandwidth(subpkt)-OPUS_BANDWIDTH_NARROWBAND],
240        subpkt[0]&4?'S':'M',opus_packet_get_samples_per_frame(subpkt,48000));
241     fprintf(frange,", %" I64uFORMAT "]%s",(unsigned long long)rngs[i],i+1==nb_streams?"\n":", ");
242     parsed_size-=payload_offset;
243     subpkt+=payload_offset;
244   }
245 }