]> git.sesse.net Git - vlc/blob - modules/codec/opus_header.c
avcodec: transmit palette to libavcodec >= 54
[vlc] / modules / codec / opus_header.c
1 /* Copyright (C)2012 Xiph.Org Foundation
2    File: opus_header.c
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 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.
26 */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include "opus_header.h"
33 #include <opus.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 #include <vlc_common.h>
39 #include "../demux/xiph.h"
40
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)
50
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
63 */
64
65 typedef struct {
66     unsigned char *data;
67     int maxlen;
68     int pos;
69 } Packet;
70
71 typedef struct {
72     const unsigned char *data;
73     int maxlen;
74     int pos;
75 } ROPacket;
76
77 static int write_uint32(Packet *p, ogg_uint32_t val)
78 {
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;
87 }
88
89 static int write_uint16(Packet *p, ogg_uint16_t val)
90 {
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;
97 }
98
99 static int write_chars(Packet *p, const unsigned char *str, int nb_chars)
100 {
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;
106 }
107
108 static int read_uint32(ROPacket *p, ogg_uint32_t *val)
109 {
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;
118 }
119
120 static int read_uint16(ROPacket *p, ogg_uint16_t *val)
121 {
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;
128 }
129
130 static int read_chars(ROPacket *p, unsigned char *str, int nb_chars)
131 {
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;
137 }
138
139 int opus_header_parse(const unsigned char *packet, int len, OpusHeader *h)
140 {
141     char str[9];
142     ROPacket p;
143     unsigned char ch;
144     ogg_uint16_t shortval;
145
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;
154
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;
160
161     if (!read_chars(&p, &ch, 1))
162         return 0;
163     h->channels = ch;
164     if (h->channels == 0)
165         return 0;
166
167     if (!read_uint16(&p, &shortval))
168         return 0;
169     h->preskip = shortval;
170
171     if (!read_uint32(&p, &h->input_sample_rate))
172         return 0;
173
174     if (!read_uint16(&p, &shortval))
175         return 0;
176     h->gain = (short)shortval;
177
178     if (!read_chars(&p, &ch, 1))
179         return 0;
180     h->channel_mapping = ch;
181
182     if (h->channel_mapping != 0)
183     {
184         if (!read_chars(&p, &ch, 1))
185             return 0;
186
187         if (ch<1)
188             return 0;
189         h->nb_streams = ch;
190
191         if (!read_chars(&p, &ch, 1))
192             return 0;
193
194         if (ch>h->nb_streams || (ch+h->nb_streams)>255)
195             return 0;
196         h->nb_coupled = ch;
197
198         /* Multi-stream support */
199         for (int i=0;i<h->channels;i++)
200         {
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;
205         }
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;
213     }
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;
219 }
220
221 /*
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
225
226  However, Opus and other non-vorbis formats omit the "framing_bit".
227
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
235   }
236   7) done.
237 */
238
239 static char *comment_init(size_t *length)
240 {
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);
244
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;
250
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);
255
256     *length = len;
257     return p;
258 }
259
260 static int comment_add(char **comments, size_t *length, const char *tag,
261                        const char *val)
262 {
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;
269
270     p = realloc(p, len);
271     if (p == NULL)
272         return 1;
273
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;
281 }
282
283 /* adds padding so that metadata can be updated without rewriting the whole file */
284 static int comment_pad(char **comments, size_t *length)
285 {
286     const unsigned padding = 512; /* default from opus-tools */
287
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;
295
296     memset(p + *length, 0, newlen - *length);
297     *comments = p;
298     *length = newlen;
299     return 0;
300 }
301
302 int opus_prepare_header(unsigned channels, unsigned rate, OpusHeader *header)
303 {
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;
312
313     return 0;
314 }
315
316 int opus_write_header(uint8_t **p_extra, int *i_extra, OpusHeader *header)
317 {
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;
328
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"))
335     {
336         free(comments);
337         return 1;
338     }
339
340     if (comment_pad(&comments, &comments_length))
341     {
342         free(comments);
343         return 1;
344     }
345
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;
352
353     for (unsigned i = 0; i < ARRAY_SIZE(headers); ++i)
354     {
355         if (xiph_AppendHeaders(i_extra, (void **) p_extra,
356                                headers[i].bytes, headers[i].packet))
357         {
358             *i_extra = 0;
359             *p_extra = NULL;
360         }
361     }
362
363     return 0;
364 }
365
366 int opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len)
367 {
368     Packet p;
369     unsigned char ch;
370
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;
381
382     ch = h->channels;
383     if (!write_chars(&p, &ch, 1))
384         return 0;
385
386     if (!write_uint16(&p, h->preskip))
387         return 0;
388
389     if (!write_uint32(&p, h->input_sample_rate))
390         return 0;
391
392     if (!write_uint16(&p, h->gain))
393         return 0;
394
395     ch = h->channel_mapping;
396     if (!write_chars(&p, &ch, 1))
397         return 0;
398
399     if (h->channel_mapping != 0)
400     {
401         ch = h->nb_streams;
402         if (!write_chars(&p, &ch, 1))
403             return 0;
404
405         ch = h->nb_coupled;
406         if (!write_chars(&p, &ch, 1))
407             return 0;
408
409         /* Multi-stream support */
410         for (int i=0;i<h->channels;i++)
411         {
412             if (!write_chars(&p, &h->stream_map[i], 1))
413                 return 0;
414         }
415     }
416
417     return p.pos;
418 }