demux: mp4: avoid audio cuts on seek
[vlc.git] / modules / codec / opus_header.c
blob08dd5dbef587b6b87e3f87bbd30d689f19cba2bc
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 <string.h>
34 #include <stdio.h>
35 #include <stdlib.h>
37 #include <vlc_common.h>
38 #include "../demux/xiph.h"
40 /* Header contents:
41 - "OpusHead" (64 bits)
42 - version number (8 bits)
43 - Channels C (8 bits)
44 - Pre-skip (16 bits)
45 - Sampling rate (32 bits)
46 - Gain in dB (16 bits, S7.8)
47 - Mapping (8 bits, 0=single stream (mono/stereo) 1=Vorbis mapping,
48 2..254: reserved, 255: multistream with no mapping)
50 - if (mapping != 0)
51 - N = totel number of streams (8 bits)
52 - M = number of paired streams (8 bits)
53 - C times channel origin
54 - if (C<2*M)
55 - stream = byte/2
56 - if (byte&0x1 == 0)
57 - left
58 else
59 - right
60 - else
61 - stream = byte-M
64 typedef struct {
65 unsigned char *data;
66 int maxlen;
67 int pos;
68 } Packet;
70 typedef struct {
71 const unsigned char *data;
72 int maxlen;
73 int pos;
74 } ROPacket;
76 static int write_uint32(Packet *p, uint32_t val)
78 if (p->pos>p->maxlen-4)
79 return 0;
80 p->data[p->pos ] = (val ) & 0xFF;
81 p->data[p->pos+1] = (val>> 8) & 0xFF;
82 p->data[p->pos+2] = (val>>16) & 0xFF;
83 p->data[p->pos+3] = (val>>24) & 0xFF;
84 p->pos += 4;
85 return 1;
88 static int write_uint16(Packet *p, uint16_t val)
90 if (p->pos>p->maxlen-2)
91 return 0;
92 p->data[p->pos ] = (val ) & 0xFF;
93 p->data[p->pos+1] = (val>> 8) & 0xFF;
94 p->pos += 2;
95 return 1;
98 static int write_chars(Packet *p, const unsigned char *str, int nb_chars)
100 if (p->pos>p->maxlen-nb_chars)
101 return 0;
102 for (int i=0;i<nb_chars;i++)
103 p->data[p->pos++] = str[i];
104 return 1;
107 static int read_uint32(ROPacket *p, uint32_t *val)
109 if (p->pos>p->maxlen-4)
110 return 0;
111 *val = (uint32_t)p->data[p->pos ];
112 *val |= (uint32_t)p->data[p->pos+1]<< 8;
113 *val |= (uint32_t)p->data[p->pos+2]<<16;
114 *val |= (uint32_t)p->data[p->pos+3]<<24;
115 p->pos += 4;
116 return 1;
119 static int read_uint16(ROPacket *p, uint16_t *val)
121 if (p->pos>p->maxlen-2)
122 return 0;
123 *val = (uint16_t)p->data[p->pos ];
124 *val |= (uint16_t)p->data[p->pos+1]<<8;
125 p->pos += 2;
126 return 1;
129 static int read_chars(ROPacket *p, unsigned char *str, int nb_chars)
131 if (p->pos>p->maxlen-nb_chars)
132 return 0;
133 for (int i=0;i<nb_chars;i++)
134 str[i] = p->data[p->pos++];
135 return 1;
138 int opus_header_parse(const unsigned char *packet, int len, OpusHeader *h)
140 char str[9];
141 ROPacket p;
142 unsigned char ch;
143 uint16_t shortval;
145 p.data = packet;
146 p.maxlen = len;
147 p.pos = 0;
148 str[8] = 0;
149 if (len<19)return 0;
150 read_chars(&p, (unsigned char*)str, 8);
151 if (memcmp(str, "OpusHead", 8)!=0)
152 return 0;
154 if (!read_chars(&p, &ch, 1))
155 return 0;
156 h->version = ch;
157 if((h->version&240) != 0) /* Only major version 0 supported. */
158 return 0;
160 if (!read_chars(&p, &ch, 1))
161 return 0;
162 h->channels = ch;
163 if (h->channels == 0)
164 return 0;
166 if (!read_uint16(&p, &shortval))
167 return 0;
168 h->preskip = shortval;
170 if (!read_uint32(&p, &h->input_sample_rate))
171 return 0;
173 if (!read_uint16(&p, &shortval))
174 return 0;
175 h->gain = (short)shortval;
177 if (!read_chars(&p, &ch, 1))
178 return 0;
179 h->channel_mapping = ch;
181 if (h->channel_mapping != 0)
183 if (!read_chars(&p, &ch, 1))
184 return 0;
186 if (ch<1)
187 return 0;
188 h->nb_streams = ch;
190 if (!read_chars(&p, &ch, 1))
191 return 0;
193 if (ch>h->nb_streams || (ch+h->nb_streams)>255)
194 return 0;
195 h->nb_coupled = ch;
197 /* Multi-stream support */
198 for (int i=0;i<h->channels;i++)
200 if (!read_chars(&p, &h->stream_map[i], 1))
201 return 0;
202 if (h->stream_map[i]>(h->nb_streams+h->nb_coupled) && h->stream_map[i]!=255)
203 return 0;
205 } else {
206 if(h->channels>2)
207 return 0;
208 h->nb_streams = 1;
209 h->nb_coupled = h->channels>1;
210 h->stream_map[0]=0;
211 h->stream_map[1]=1;
213 /*For version 0/1 we know there won't be any more data
214 so reject any that have data past the end.*/
215 if ((h->version==0 || h->version==1) && p.pos != len)
216 return 0;
217 return 1;
221 Comments will be stored in the Vorbis style.
222 It is described in the "Structure" section of
223 http://www.xiph.org/ogg/vorbis/doc/v-comment.html
225 However, Opus and other non-vorbis formats omit the "framing_bit".
227 The comment header is decoded as follows:
228 1) [vendor_length] = unsigned little endian 32 bits integer
229 2) [vendor_string] = UTF-8 vector as [vendor_length] octets
230 3) [user_comment_list_length] = unsigned little endian 32 bits integer
231 4) iterate [user_comment_list_length] times {
232 5) [length] = unsigned little endian 32 bits integer
233 6) this iteration's user comment = UTF-8 vector as [length] octets
235 7) done.
238 static char *comment_init(size_t *length, const char *vendor)
240 /*The 'vendor' field should be the actual encoding library used.*/
241 if (!vendor)
242 vendor = "unknown";
243 size_t vendor_length = strlen(vendor);
245 size_t user_comment_list_length = 0;
246 size_t 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, 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 uint32_t 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 char *reaced = realloc(p, len);
271 if (reaced == NULL)
272 return 1;
273 p = reaced;
275 SetDWLE(p + *length, tag_len + val_len); /* length of comment */
276 if (tag) memcpy(p + *length + 4, tag, tag_len); /* comment */
277 memcpy(p + *length + 4 + tag_len, val, val_len); /* comment */
278 SetDWLE(p + 8 + 4 + vendor_length, user_comment_list_length + 1);
279 *comments = p;
280 *length = len;
281 return 0;
284 /* adds padding so that metadata can be updated without rewriting the whole file */
285 static int comment_pad(char **comments, size_t *length)
287 const unsigned padding = 512; /* default from opus-tools */
289 if(SIZE_MAX - *length < padding + 255)
290 return 1;
292 char *p = *comments;
293 /* Make sure there is at least "padding" worth of padding free, and
294 round up to the maximum that fits in the current ogg segments. */
295 size_t newlen = ((*length + padding) / 255 + 1) * 255 - 1;
296 char *reaced = realloc(p, newlen);
297 if (reaced == NULL)
298 return 1;
299 p = reaced;
301 memset(p + *length, 0, newlen - *length);
302 *comments = p;
303 *length = newlen;
304 return 0;
307 void opus_prepare_header(unsigned channels, unsigned rate, OpusHeader *header)
309 header->version = 1;
310 header->channels = channels;
311 header->nb_streams = header->channels;
312 header->nb_coupled = 0;
313 header->input_sample_rate = rate;
314 header->gain = 0; // 0dB
315 header->channel_mapping = header->channels > 8 ? 255 :
316 header->channels > 2;
319 static int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len)
321 Packet p;
322 unsigned char ch;
324 p.data = packet;
325 p.maxlen = len;
326 p.pos = 0;
327 if (len<19)return 0;
328 if (!write_chars(&p, (const unsigned char*)"OpusHead", 8))
329 return 0;
330 /* Version is 1 */
331 ch = 1;
332 if (!write_chars(&p, &ch, 1))
333 return 0;
335 ch = h->channels;
336 if (!write_chars(&p, &ch, 1))
337 return 0;
339 if (!write_uint16(&p, h->preskip))
340 return 0;
342 if (!write_uint32(&p, h->input_sample_rate))
343 return 0;
345 if (!write_uint16(&p, h->gain))
346 return 0;
348 ch = h->channel_mapping;
349 if (!write_chars(&p, &ch, 1))
350 return 0;
352 if (h->channel_mapping != 0)
354 ch = h->nb_streams;
355 if (!write_chars(&p, &ch, 1))
356 return 0;
358 ch = h->nb_coupled;
359 if (!write_chars(&p, &ch, 1))
360 return 0;
362 /* Multi-stream support */
363 for (int i=0;i<h->channels;i++)
365 if (!write_chars(&p, &h->stream_map[i], 1))
366 return 0;
370 return p.pos;
373 int opus_write_header(uint8_t **p_extra, int *i_extra, OpusHeader *header, const char *vendor)
375 unsigned char header_data[100];
376 const int packet_size = opus_header_to_packet(header, header_data,
377 sizeof(header_data));
379 const unsigned char *data[2];
380 size_t size[2];
382 data[0] = header_data;
383 size[0] = packet_size;
385 size_t comments_length;
386 char *comments = comment_init(&comments_length, vendor);
387 if (!comments)
388 return 1;
389 if (comment_add(&comments, &comments_length, "ENCODER=",
390 "VLC media player"))
392 free(comments);
393 return 1;
396 if (comment_pad(&comments, &comments_length))
398 free(comments);
399 return 1;
402 data[1] = (unsigned char *) comments;
403 size[1] = comments_length;
405 *i_extra = 0;
406 *p_extra = NULL;
408 for (unsigned i = 0; i < ARRAY_SIZE(data); ++i)
410 if (xiph_AppendHeaders(i_extra, (void **) p_extra, size[i], data[i]))
412 *i_extra = 0;
413 free(*p_extra);
414 *p_extra = NULL;
418 free(comments);
420 return 0;