Add VorbisComment writing to FLAC files.
[ffmpeg.git] / libavformat / oggparsevorbis.c
1 /**
2       Copyright (C) 2005  Michael Ahlberg, Måns Rullgård
3
4       Permission is hereby granted, free of charge, to any person
5       obtaining a copy of this software and associated documentation
6       files (the "Software"), to deal in the Software without
7       restriction, including without limitation the rights to use, copy,
8       modify, merge, publish, distribute, sublicense, and/or sell copies
9       of the Software, and to permit persons to whom the Software is
10       furnished to do so, subject to the following conditions:
11
12       The above copyright notice and this permission notice shall be
13       included in all copies or substantial portions of the Software.
14
15       THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16       EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17       MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18       NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19       HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20       WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21       OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22       DEALINGS IN THE SOFTWARE.
23 **/
24
25 #include <stdlib.h>
26 #include "libavutil/avstring.h"
27 #include "libavutil/bswap.h"
28 #include "libavcodec/get_bits.h"
29 #include "libavcodec/bytestream.h"
30 #include "avformat.h"
31 #include "oggdec.h"
32
33 static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val)
34 {
35     int i, cnum, h, m, s, ms, keylen = strlen(key);
36     AVChapter *chapter = NULL;
37
38     if (keylen < 9 || sscanf(key, "CHAPTER%02d", &cnum) != 1)
39         return 0;
40
41     if (keylen == 9) {
42         if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4)
43             return 0;
44
45         ff_new_chapter(as, cnum, (AVRational){1,1000},
46                        ms + 1000*(s + 60*(m + 60*h)),
47                        AV_NOPTS_VALUE, NULL);
48         av_free(val);
49     } else if (!strcmp(key+9, "NAME")) {
50         for(i = 0; i < as->nb_chapters; i++)
51             if (as->chapters[i]->id == cnum) {
52                 chapter = as->chapters[i];
53                 break;
54             }
55         if (!chapter)
56             return 0;
57
58         av_metadata_set2(&chapter->metadata, "title", val,
59                          AV_METADATA_DONT_STRDUP_VAL);
60     } else
61         return 0;
62
63     av_free(key);
64     return 1;
65 }
66
67 int
68 ff_vorbis_comment(AVFormatContext * as, AVMetadata **m, const uint8_t *buf, int size)
69 {
70     const uint8_t *p = buf;
71     const uint8_t *end = buf + size;
72     unsigned n, j;
73     int s;
74
75     if (size < 8) /* must have vendor_length and user_comment_list_length */
76         return -1;
77
78     s = bytestream_get_le32(&p);
79
80     if (end - p - 4 < s || s < 0)
81         return -1;
82
83     p += s;
84
85     n = bytestream_get_le32(&p);
86
87     while (end - p >= 4 && n > 0) {
88         const char *t, *v;
89         int tl, vl;
90
91         s = bytestream_get_le32(&p);
92
93         if (end - p < s || s < 0)
94             break;
95
96         t = p;
97         p += s;
98         n--;
99
100         v = memchr(t, '=', s);
101         if (!v)
102             continue;
103
104         tl = v - t;
105         vl = s - tl - 1;
106         v++;
107
108         if (tl && vl) {
109             char *tt, *ct;
110
111             tt = av_malloc(tl + 1);
112             ct = av_malloc(vl + 1);
113             if (!tt || !ct) {
114                 av_freep(&tt);
115                 av_freep(&ct);
116                 av_log(as, AV_LOG_WARNING, "out-of-memory error. skipping VorbisComment tag.\n");
117                 continue;
118             }
119
120             for (j = 0; j < tl; j++)
121                 tt[j] = toupper(t[j]);
122             tt[tl] = 0;
123
124             memcpy(ct, v, vl);
125             ct[vl] = 0;
126
127             if (!ogm_chapter(as, tt, ct))
128                 av_metadata_set2(m, tt, ct,
129                                    AV_METADATA_DONT_STRDUP_KEY |
130                                    AV_METADATA_DONT_STRDUP_VAL);
131         }
132     }
133
134     if (p != end)
135         av_log(as, AV_LOG_INFO, "%ti bytes of comment header remain\n", end-p);
136     if (n > 0)
137         av_log(as, AV_LOG_INFO,
138                "truncated comment header, %i comments not found\n", n);
139
140     return 0;
141 }
142
143
144 /** Parse the vorbis header
145  * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec
146  * [vorbis_version] = read 32 bits as unsigned integer | Not used
147  * [audio_channels] = read 8 bit integer as unsigned | Used
148  * [audio_sample_rate] = read 32 bits as unsigned integer | Used
149  * [bitrate_maximum] = read 32 bits as signed integer | Not used yet
150  * [bitrate_nominal] = read 32 bits as signed integer | Not used yet
151  * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate
152  * [blocksize_0] = read 4 bits as unsigned integer | Not Used
153  * [blocksize_1] = read 4 bits as unsigned integer | Not Used
154  * [framing_flag] = read one bit | Not Used
155  *    */
156
157 struct oggvorbis_private {
158     unsigned int len[3];
159     unsigned char *packet[3];
160 };
161
162
163 static unsigned int
164 fixup_vorbis_headers(AVFormatContext * as, struct oggvorbis_private *priv,
165                      uint8_t **buf)
166 {
167     int i,offset, len;
168     unsigned char *ptr;
169
170     len = priv->len[0] + priv->len[1] + priv->len[2];
171     ptr = *buf = av_mallocz(len + len/255 + 64);
172
173     ptr[0] = 2;
174     offset = 1;
175     offset += av_xiphlacing(&ptr[offset], priv->len[0]);
176     offset += av_xiphlacing(&ptr[offset], priv->len[1]);
177     for (i = 0; i < 3; i++) {
178         memcpy(&ptr[offset], priv->packet[i], priv->len[i]);
179         offset += priv->len[i];
180         av_freep(&priv->packet[i]);
181     }
182     *buf = av_realloc(*buf, offset + FF_INPUT_BUFFER_PADDING_SIZE);
183     return offset;
184 }
185
186
187 static int
188 vorbis_header (AVFormatContext * s, int idx)
189 {
190     struct ogg *ogg = s->priv_data;
191     struct ogg_stream *os = ogg->streams + idx;
192     AVStream *st = s->streams[idx];
193     struct oggvorbis_private *priv;
194     int pkt_type = os->buf[os->pstart];
195
196     if (!(pkt_type & 1))
197         return 0;
198
199     if (!os->private) {
200         os->private = av_mallocz(sizeof(struct oggvorbis_private));
201         if (!os->private)
202             return 0;
203     }
204
205     if (os->psize < 1 || pkt_type > 5)
206         return -1;
207
208     priv = os->private;
209     priv->len[pkt_type >> 1] = os->psize;
210     priv->packet[pkt_type >> 1] = av_mallocz(os->psize);
211     memcpy(priv->packet[pkt_type >> 1], os->buf + os->pstart, os->psize);
212     if (os->buf[os->pstart] == 1) {
213         const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */
214         unsigned blocksize, bs0, bs1;
215
216         if (os->psize != 30)
217             return -1;
218
219         if (bytestream_get_le32(&p) != 0) /* vorbis_version */
220             return -1;
221
222         st->codec->channels = bytestream_get_byte(&p);
223         st->codec->sample_rate = bytestream_get_le32(&p);
224         p += 4; // skip maximum bitrate
225         st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate
226         p += 4; // skip minimum bitrate
227
228         blocksize = bytestream_get_byte(&p);
229         bs0 = blocksize & 15;
230         bs1 = blocksize >> 4;
231
232         if (bs0 > bs1)
233             return -1;
234         if (bs0 < 6 || bs1 > 13)
235             return -1;
236
237         if (bytestream_get_byte(&p) != 1) /* framing_flag */
238             return -1;
239
240         st->codec->codec_type = CODEC_TYPE_AUDIO;
241         st->codec->codec_id = CODEC_ID_VORBIS;
242
243         st->time_base.num = 1;
244         st->time_base.den = st->codec->sample_rate;
245     } else if (os->buf[os->pstart] == 3) {
246         if (os->psize > 8)
247             ff_vorbis_comment (s, &st->metadata, os->buf + os->pstart + 7, os->psize - 8);
248     } else {
249         st->codec->extradata_size =
250             fixup_vorbis_headers(s, priv, &st->codec->extradata);
251     }
252
253     return 1;
254 }
255
256 const struct ogg_codec ff_vorbis_codec = {
257     .magic = "\001vorbis",
258     .magicsize = 7,
259     .header = vorbis_header
260 };