Vout: move the AndroidSurface vout to a subdirectory
[vlc.git] / modules / codec / opus_header.c
blob7d48331a16179941eb31dd9511aac26ebc294af4
1 /* Copyright (C)2012 Xiph.Org Foundation
2 File: opus_header.c
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
8 - Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
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.
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 FOUNDATION OR
19 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.
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include "opus_header.h"
33 #include <opus.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <stdlib.h>
38 #include <vlc_common.h>
39 #include "../demux/xiph.h"
41 /* Header contents:
42 - "OpusHead" (64 bits)
43 - version number (8 bits)
44 - Channels C (8 bits)
45 - Pre-skip (16 bits)
46 - Sampling rate (32 bits)
47 - Gain in dB (16 bits, S7.8)
48 - Mapping (8 bits, 0=single stream (mono/stereo) 1=Vorbis mapping,
49 2..254: reserved, 255: multistream with no mapping)
51 - if (mapping != 0)
52 - N = totel number of streams (8 bits)
53 - M = number of paired streams (8 bits)
54 - C times channel origin
55 - if (C<2*M)
56 - stream = byte/2
57 - if (byte&0x1 == 0)
58 - left
59 else
60 - right
61 - else
62 - stream = byte-M
65 typedef struct {
66 unsigned char *data;
67 int maxlen;
68 int pos;
69 } Packet;
71 typedef struct {
72 const unsigned char *data;
73 int maxlen;
74 int pos;
75 } ROPacket;
77 static int write_uint32(Packet *p, ogg_uint32_t val)
79 if (p->pos>p->maxlen-4)
80 return 0;
81 p->data[p->pos ] = (val ) & 0xFF;
82 p->data[p->pos+1] = (val>> 8) & 0xFF;
83 p->data[p->pos+2] = (val>>16) & 0xFF;
84 p->data[p->pos+3] = (val>>24) & 0xFF;
85 p->pos += 4;
86 return 1;
89 static int write_uint16(Packet *p, ogg_uint16_t val)
91 if (p->pos>p->maxlen-2)
92 return 0;
93 p->data[p->pos ] = (val ) & 0xFF;
94 p->data[p->pos+1] = (val>> 8) & 0xFF;
95 p->pos += 2;
96 return 1;
99 static int write_chars(Packet *p, const unsigned char *str, int nb_chars)
101 if (p->pos>p->maxlen-nb_chars)
102 return 0;
103 for (int i=0;i<nb_chars;i++)
104 p->data[p->pos++] = str[i];
105 return 1;
108 static int read_uint32(ROPacket *p, ogg_uint32_t *val)
110 if (p->pos>p->maxlen-4)
111 return 0;
112 *val = (ogg_uint32_t)p->data[p->pos ];
113 *val |= (ogg_uint32_t)p->data[p->pos+1]<< 8;
114 *val |= (ogg_uint32_t)p->data[p->pos+2]<<16;
115 *val |= (ogg_uint32_t)p->data[p->pos+3]<<24;
116 p->pos += 4;
117 return 1;
120 static int read_uint16(ROPacket *p, ogg_uint16_t *val)
122 if (p->pos>p->maxlen-2)
123 return 0;
124 *val = (ogg_uint16_t)p->data[p->pos ];
125 *val |= (ogg_uint16_t)p->data[p->pos+1]<<8;
126 p->pos += 2;
127 return 1;
130 static int read_chars(ROPacket *p, unsigned char *str, int nb_chars)
132 if (p->pos>p->maxlen-nb_chars)
133 return 0;
134 for (int i=0;i<nb_chars;i++)
135 str[i] = p->data[p->pos++];
136 return 1;
139 int opus_header_parse(const unsigned char *packet, int len, OpusHeader *h)
141 char str[9];
142 ROPacket p;
143 unsigned char ch;
144 ogg_uint16_t shortval;
146 p.data = packet;
147 p.maxlen = len;
148 p.pos = 0;
149 str[8] = 0;
150 if (len<19)return 0;
151 read_chars(&p, (unsigned char*)str, 8);
152 if (memcmp(str, "OpusHead", 8)!=0)
153 return 0;
155 if (!read_chars(&p, &ch, 1))
156 return 0;
157 h->version = ch;
158 if((h->version&240) != 0) /* Only major version 0 supported. */
159 return 0;
161 if (!read_chars(&p, &ch, 1))
162 return 0;
163 h->channels = ch;
164 if (h->channels == 0)
165 return 0;
167 if (!read_uint16(&p, &shortval))
168 return 0;
169 h->preskip = shortval;
171 if (!read_uint32(&p, &h->input_sample_rate))
172 return 0;
174 if (!read_uint16(&p, &shortval))
175 return 0;
176 h->gain = (short)shortval;
178 if (!read_chars(&p, &ch, 1))
179 return 0;
180 h->channel_mapping = ch;
182 if (h->channel_mapping != 0)
184 if (!read_chars(&p, &ch, 1))
185 return 0;
187 if (ch<1)
188 return 0;
189 h->nb_streams = ch;
191 if (!read_chars(&p, &ch, 1))
192 return 0;
194 if (ch>h->nb_streams || (ch+h->nb_streams)>255)
195 return 0;
196 h->nb_coupled = ch;
198 /* Multi-stream support */
199 for (int i=0;i<h->channels;i++)
201 if (!read_chars(&p, &h->stream_map[i], 1))
202 return 0;
203 if (h->stream_map[i]>(h->nb_streams+h->nb_coupled) && h->stream_map[i]!=255)
204 return 0;
206 } else {
207 if(h->channels>2)
208 return 0;
209 h->nb_streams = 1;
210 h->nb_coupled = h->channels>1;
211 h->stream_map[0]=0;
212 h->stream_map[1]=1;
214 /*For version 0/1 we know there won't be any more data
215 so reject any that have data past the end.*/
216 if ((h->version==0 || h->version==1) && p.pos != len)
217 return 0;
218 return 1;
222 Comments will be stored in the Vorbis style.
223 It is described in the "Structure" section of
224 http://www.xiph.org/ogg/vorbis/doc/v-comment.html
226 However, Opus and other non-vorbis formats omit the "framing_bit".
228 The comment header is decoded as follows:
229 1) [vendor_length] = unsigned little endian 32 bits integer
230 2) [vendor_string] = UTF-8 vector as [vendor_length] octets
231 3) [user_comment_list_length] = unsigned little endian 32 bits integer
232 4) iterate [user_comment_list_length] times {
233 5) [length] = unsigned little endian 32 bits integer
234 6) this iteration's user comment = UTF-8 vector as [length] octets
236 7) done.
239 static char *comment_init(size_t *length)
241 /*The 'vendor' field should be the actual encoding library used.*/
242 const char *vendor_string = opus_get_version_string();
243 int vendor_length = strlen(vendor_string);
245 int user_comment_list_length = 0;
246 int len = 8 + 4 + vendor_length + 4;
247 char *p = malloc(len);
248 if (p == NULL)
249 return NULL;
251 memcpy(p, "OpusTags", 8);
252 SetDWLE(p + 8, vendor_length);
253 memcpy(p + 12, vendor_string, vendor_length);
254 SetDWLE(p + 12 + vendor_length, user_comment_list_length);
256 *length = len;
257 return p;
260 static int comment_add(char **comments, size_t *length, const char *tag,
261 const char *val)
263 char *p = *comments;
264 int vendor_length = GetDWLE(p + 8);
265 size_t user_comment_list_length = GetDWLE(p + 8 + 4 + vendor_length);
266 size_t tag_len = (tag ? strlen(tag) : 0);
267 size_t val_len = strlen(val);
268 size_t len = (*length) + 4 + tag_len + val_len;
270 p = realloc(p, len);
271 if (p == NULL)
272 return 1;
274 SetDWLE(p + *length, tag_len + val_len); /* length of comment */
275 if (tag) memcpy(p + *length + 4, tag, tag_len); /* comment */
276 memcpy(p + *length + 4 + tag_len, val, val_len); /* comment */
277 SetDWLE(p + 8 + 4 + vendor_length, user_comment_list_length + 1);
278 *comments = p;
279 *length = len;
280 return 0;
283 /* adds padding so that metadata can be updated without rewriting the whole file */
284 static int comment_pad(char **comments, size_t *length)
286 const unsigned padding = 512; /* default from opus-tools */
288 char *p = *comments;
289 /* Make sure there is at least "padding" worth of padding free, and
290 round up to the maximum that fits in the current ogg segments. */
291 size_t newlen = ((*length + padding) / 255 + 1) * 255 - 1;
292 p = realloc(p, newlen);
293 if (p == NULL)
294 return 1;
296 memset(p + *length, 0, newlen - *length);
297 *comments = p;
298 *length = newlen;
299 return 0;
302 int opus_prepare_header(unsigned channels, unsigned rate, OpusHeader *header)
304 header->version = 1;
305 header->channels = channels;
306 header->nb_streams = header->channels;
307 header->nb_coupled = 0;
308 header->input_sample_rate = rate;
309 header->gain = 0; // 0dB
310 header->channel_mapping = header->channels > 8 ? 255 :
311 header->channels > 2;
313 return 0;
316 int opus_write_header(uint8_t **p_extra, int *i_extra, OpusHeader *header)
318 unsigned char header_data[100];
319 const int packet_size = opus_header_to_packet(header, header_data,
320 sizeof(header_data));
321 ogg_packet headers[2];
322 headers[0].packet = header_data;
323 headers[0].bytes = packet_size;
324 headers[0].b_o_s = 1;
325 headers[0].e_o_s = 0;
326 headers[0].granulepos = 0;
327 headers[0].packetno = 0;
329 size_t comments_length;
330 char *comments = comment_init(&comments_length);
331 if (!comments)
332 return 1;
333 if (comment_add(&comments, &comments_length, "ENCODER=",
334 "VLC media player"))
336 free(comments);
337 return 1;
340 if (comment_pad(&comments, &comments_length))
342 free(comments);
343 return 1;
346 headers[1].packet = (unsigned char *) comments;
347 headers[1].bytes = comments_length;
348 headers[1].b_o_s = 0;
349 headers[1].e_o_s = 0;
350 headers[1].granulepos = 0;
351 headers[1].packetno = 1;
353 for (unsigned i = 0; i < ARRAY_SIZE(headers); ++i)
355 if (xiph_AppendHeaders(i_extra, (void **) p_extra,
356 headers[i].bytes, headers[i].packet))
358 *i_extra = 0;
359 *p_extra = NULL;
363 return 0;
366 int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len)
368 Packet p;
369 unsigned char ch;
371 p.data = packet;
372 p.maxlen = len;
373 p.pos = 0;
374 if (len<19)return 0;
375 if (!write_chars(&p, (const unsigned char*)"OpusHead", 8))
376 return 0;
377 /* Version is 1 */
378 ch = 1;
379 if (!write_chars(&p, &ch, 1))
380 return 0;
382 ch = h->channels;
383 if (!write_chars(&p, &ch, 1))
384 return 0;
386 if (!write_uint16(&p, h->preskip))
387 return 0;
389 if (!write_uint32(&p, h->input_sample_rate))
390 return 0;
392 if (!write_uint16(&p, h->gain))
393 return 0;
395 ch = h->channel_mapping;
396 if (!write_chars(&p, &ch, 1))
397 return 0;
399 if (h->channel_mapping != 0)
401 ch = h->nb_streams;
402 if (!write_chars(&p, &ch, 1))
403 return 0;
405 ch = h->nb_coupled;
406 if (!write_chars(&p, &ch, 1))
407 return 0;
409 /* Multi-stream support */
410 for (int i=0;i<h->channels;i++)
412 if (!write_chars(&p, &h->stream_map[i], 1))
413 return 0;
417 return p.pos;