Commit | Line | Data |
---|---|---|
49fe9c05 VG |
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 | */ | |
9146ca37 MR |
24 | |
25 | #include <stdlib.h> | |
49fe9c05 | 26 | |
245976da | 27 | #include "libavutil/avstring.h" |
c18375ec | 28 | #include "libavutil/base64.h" |
245976da | 29 | #include "libavutil/bswap.h" |
d2d67e42 | 30 | #include "libavutil/dict.h" |
245976da | 31 | #include "libavcodec/bytestream.h" |
49fe9c05 | 32 | #include "libavcodec/get_bits.h" |
f63412fc | 33 | #include "libavcodec/vorbis_parser.h" |
9146ca37 | 34 | #include "avformat.h" |
c18375ec | 35 | #include "flac_picture.h" |
19711af5 | 36 | #include "internal.h" |
a0ddef24 | 37 | #include "oggdec.h" |
fb66c31d | 38 | #include "vorbiscomment.h" |
9146ca37 | 39 | |
8730fad5 DC |
40 | static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) |
41 | { | |
42 | int i, cnum, h, m, s, ms, keylen = strlen(key); | |
43 | AVChapter *chapter = NULL; | |
44 | ||
9c15ef35 | 45 | if (keylen < 9 || sscanf(key, "CHAPTER%03d", &cnum) != 1) |
8730fad5 DC |
46 | return 0; |
47 | ||
9c15ef35 | 48 | if (keylen <= 10) { |
8730fad5 DC |
49 | if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4) |
50 | return 0; | |
51 | ||
49fe9c05 VG |
52 | avpriv_new_chapter(as, cnum, (AVRational) { 1, 1000 }, |
53 | ms + 1000 * (s + 60 * (m + 60 * h)), | |
54 | AV_NOPTS_VALUE, NULL); | |
8730fad5 | 55 | av_free(val); |
9c15ef35 | 56 | } else if (!strcmp(key + keylen - 4, "NAME")) { |
49fe9c05 | 57 | for (i = 0; i < as->nb_chapters; i++) |
8730fad5 DC |
58 | if (as->chapters[i]->id == cnum) { |
59 | chapter = as->chapters[i]; | |
60 | break; | |
61 | } | |
62 | if (!chapter) | |
63 | return 0; | |
64 | ||
49fe9c05 | 65 | av_dict_set(&chapter->metadata, "title", val, AV_DICT_DONT_STRDUP_VAL); |
8730fad5 DC |
66 | } else |
67 | return 0; | |
68 | ||
69 | av_free(key); | |
70 | return 1; | |
71 | } | |
72 | ||
49fe9c05 VG |
73 | int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, |
74 | const uint8_t *buf, int size) | |
9146ca37 | 75 | { |
49fe9c05 | 76 | const uint8_t *p = buf; |
47a0513b | 77 | const uint8_t *end = buf + size; |
98422c44 RD |
78 | unsigned n, j; |
79 | int s; | |
9146ca37 | 80 | |
49fe9c05 VG |
81 | /* must have vendor_length and user_comment_list_length */ |
82 | if (size < 8) | |
90e15e34 | 83 | return AVERROR_INVALIDDATA; |
9146ca37 | 84 | |
0a770ae7 | 85 | s = bytestream_get_le32(&p); |
9146ca37 | 86 | |
98422c44 | 87 | if (end - p - 4 < s || s < 0) |
90e15e34 | 88 | return AVERROR_INVALIDDATA; |
9146ca37 MR |
89 | |
90 | p += s; | |
9146ca37 | 91 | |
0a770ae7 | 92 | n = bytestream_get_le32(&p); |
9146ca37 | 93 | |
98422c44 | 94 | while (end - p >= 4 && n > 0) { |
47a0513b | 95 | const char *t, *v; |
9146ca37 MR |
96 | int tl, vl; |
97 | ||
0a770ae7 | 98 | s = bytestream_get_le32(&p); |
9146ca37 | 99 | |
98422c44 | 100 | if (end - p < s || s < 0) |
9146ca37 MR |
101 | break; |
102 | ||
49fe9c05 | 103 | t = p; |
9146ca37 | 104 | p += s; |
9146ca37 MR |
105 | n--; |
106 | ||
4bd684bc | 107 | v = memchr(t, '=', s); |
9146ca37 MR |
108 | if (!v) |
109 | continue; | |
110 | ||
111 | tl = v - t; | |
112 | vl = s - tl - 1; | |
113 | v++; | |
114 | ||
4bd684bc | 115 | if (tl && vl) { |
e3b44649 JR |
116 | char *tt, *ct; |
117 | ||
118 | tt = av_malloc(tl + 1); | |
119 | ct = av_malloc(vl + 1); | |
120 | if (!tt || !ct) { | |
121 | av_freep(&tt); | |
122 | av_freep(&ct); | |
fd2384f0 | 123 | return AVERROR(ENOMEM); |
e3b44649 | 124 | } |
9146ca37 MR |
125 | |
126 | for (j = 0; j < tl; j++) | |
efa7f420 | 127 | tt[j] = av_toupper(t[j]); |
9146ca37 MR |
128 | tt[tl] = 0; |
129 | ||
4bd684bc | 130 | memcpy(ct, v, vl); |
9146ca37 MR |
131 | ct[vl] = 0; |
132 | ||
c18375ec JA |
133 | /* The format in which the pictures are stored is the FLAC format. |
134 | * Xiph says: "The binary FLAC picture structure is base64 encoded | |
135 | * and placed within a VorbisComment with the tag name | |
136 | * 'METADATA_BLOCK_PICTURE'. This is the preferred and | |
137 | * recommended way of embedding cover art within VorbisComments." | |
138 | */ | |
139 | if (!strcmp(tt, "METADATA_BLOCK_PICTURE")) { | |
140 | int ret; | |
141 | char *pict = av_malloc(vl); | |
142 | ||
143 | if (!pict) { | |
144 | av_freep(&tt); | |
145 | av_freep(&ct); | |
146 | return AVERROR(ENOMEM); | |
147 | } | |
148 | if ((ret = av_base64_decode(pict, ct, vl)) > 0) | |
149 | ret = ff_flac_parse_picture(as, pict, ret); | |
150 | av_freep(&tt); | |
151 | av_freep(&ct); | |
152 | av_freep(&pict); | |
153 | if (ret < 0) { | |
154 | av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n"); | |
155 | continue; | |
156 | } | |
157 | } else if (!ogm_chapter(as, tt, ct)) | |
d2d67e42 | 158 | av_dict_set(m, tt, ct, |
49fe9c05 VG |
159 | AV_DICT_DONT_STRDUP_KEY | |
160 | AV_DICT_DONT_STRDUP_VAL); | |
9146ca37 MR |
161 | } |
162 | } | |
163 | ||
972c5f9e | 164 | if (p != end) |
49fe9c05 VG |
165 | av_log(as, AV_LOG_INFO, |
166 | "%ti bytes of comment header remain\n", end - p); | |
9146ca37 | 167 | if (n > 0) |
4bd684bc MR |
168 | av_log(as, AV_LOG_INFO, |
169 | "truncated comment header, %i comments not found\n", n); | |
9146ca37 | 170 | |
ad7768f4 | 171 | ff_metadata_conv(m, NULL, ff_vorbiscomment_metadata_conv); |
03700d39 | 172 | |
9146ca37 MR |
173 | return 0; |
174 | } | |
175 | ||
49fe9c05 VG |
176 | /* |
177 | * Parse the vorbis header | |
178 | * | |
9146ca37 MR |
179 | * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec |
180 | * [vorbis_version] = read 32 bits as unsigned integer | Not used | |
181 | * [audio_channels] = read 8 bit integer as unsigned | Used | |
115329f1 | 182 | * [audio_sample_rate] = read 32 bits as unsigned integer | Used |
9146ca37 MR |
183 | * [bitrate_maximum] = read 32 bits as signed integer | Not used yet |
184 | * [bitrate_nominal] = read 32 bits as signed integer | Not used yet | |
185 | * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate | |
186 | * [blocksize_0] = read 4 bits as unsigned integer | Not Used | |
187 | * [blocksize_1] = read 4 bits as unsigned integer | Not Used | |
188 | * [framing_flag] = read one bit | Not Used | |
49fe9c05 | 189 | */ |
9146ca37 | 190 | |
77be08ee | 191 | struct oggvorbis_private { |
ad2b531d MR |
192 | unsigned int len[3]; |
193 | unsigned char *packet[3]; | |
f63412fc JR |
194 | VorbisParseContext vp; |
195 | int64_t final_pts; | |
196 | int final_duration; | |
77be08ee | 197 | }; |
ad2b531d | 198 | |
ed9245db VG |
199 | static int fixup_vorbis_headers(AVFormatContext *as, |
200 | struct oggvorbis_private *priv, | |
201 | uint8_t **buf) | |
ad2b531d | 202 | { |
5626f994 | 203 | int i, offset, len, err; |
ad2b531d MR |
204 | unsigned char *ptr; |
205 | ||
206 | len = priv->len[0] + priv->len[1] + priv->len[2]; | |
49fe9c05 | 207 | ptr = *buf = av_mallocz(len + len / 255 + 64); |
ed9245db VG |
208 | if (!ptr) |
209 | return AVERROR(ENOMEM); | |
ad2b531d | 210 | |
49fe9c05 VG |
211 | ptr[0] = 2; |
212 | offset = 1; | |
ad2b531d MR |
213 | offset += av_xiphlacing(&ptr[offset], priv->len[0]); |
214 | offset += av_xiphlacing(&ptr[offset], priv->len[1]); | |
4bd684bc | 215 | for (i = 0; i < 3; i++) { |
ad2b531d MR |
216 | memcpy(&ptr[offset], priv->packet[i], priv->len[i]); |
217 | offset += priv->len[i]; | |
2ac41150 | 218 | av_freep(&priv->packet[i]); |
ad2b531d | 219 | } |
5626f994 AK |
220 | if ((err = av_reallocp(buf, offset + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) |
221 | return err; | |
ad2b531d MR |
222 | return offset; |
223 | } | |
224 | ||
fba8e5b6 | 225 | static void vorbis_cleanup(AVFormatContext *s, int idx) |
d894f747 LB |
226 | { |
227 | struct ogg *ogg = s->priv_data; | |
228 | struct ogg_stream *os = ogg->streams + idx; | |
229 | struct oggvorbis_private *priv = os->private; | |
230 | int i; | |
231 | if (os->private) | |
232 | for (i = 0; i < 3; i++) | |
233 | av_freep(&priv->packet[i]); | |
234 | } | |
ad2b531d | 235 | |
49fe9c05 | 236 | static int vorbis_header(AVFormatContext *s, int idx) |
9146ca37 | 237 | { |
77be08ee | 238 | struct ogg *ogg = s->priv_data; |
49fe9c05 | 239 | AVStream *st = s->streams[idx]; |
77be08ee | 240 | struct ogg_stream *os = ogg->streams + idx; |
77be08ee | 241 | struct oggvorbis_private *priv; |
8f8320d7 | 242 | int pkt_type = os->buf[os->pstart]; |
9146ca37 | 243 | |
8f8320d7 | 244 | if (!os->private) { |
77be08ee | 245 | os->private = av_mallocz(sizeof(struct oggvorbis_private)); |
4bd684bc | 246 | if (!os->private) |
90e15e34 | 247 | return AVERROR(ENOMEM); |
ad2b531d | 248 | } |
9146ca37 | 249 | |
3562684d LB |
250 | if (!(pkt_type & 1)) |
251 | return 0; | |
252 | ||
8f8320d7 | 253 | if (os->psize < 1 || pkt_type > 5) |
90e15e34 | 254 | return AVERROR_INVALIDDATA; |
f5475e1b | 255 | |
ad2b531d | 256 | priv = os->private; |
73c44cb2 | 257 | |
49fe9c05 | 258 | if (priv->packet[pkt_type >> 1]) |
90e15e34 | 259 | return AVERROR_INVALIDDATA; |
73c44cb2 | 260 | if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1]) |
90e15e34 | 261 | return AVERROR_INVALIDDATA; |
73c44cb2 | 262 | |
49fe9c05 | 263 | priv->len[pkt_type >> 1] = os->psize; |
8f8320d7 | 264 | priv->packet[pkt_type >> 1] = av_mallocz(os->psize); |
ed9245db VG |
265 | if (!priv->packet[pkt_type >> 1]) |
266 | return AVERROR(ENOMEM); | |
8f8320d7 | 267 | memcpy(priv->packet[pkt_type >> 1], os->buf + os->pstart, os->psize); |
9146ca37 | 268 | if (os->buf[os->pstart] == 1) { |
47a0513b | 269 | const uint8_t *p = os->buf + os->pstart + 7; /* skip "\001vorbis" tag */ |
736e63ed | 270 | unsigned blocksize, bs0, bs1; |
ce20edb7 | 271 | int srate; |
f5475e1b MR |
272 | |
273 | if (os->psize != 30) | |
90e15e34 | 274 | return AVERROR_INVALIDDATA; |
f5475e1b | 275 | |
736e63ed | 276 | if (bytestream_get_le32(&p) != 0) /* vorbis_version */ |
90e15e34 | 277 | return AVERROR_INVALIDDATA; |
736e63ed | 278 | |
739587bf | 279 | st->codec->channels = bytestream_get_byte(&p); |
49fe9c05 | 280 | srate = bytestream_get_le32(&p); |
739587bf MR |
281 | p += 4; // skip maximum bitrate |
282 | st->codec->bit_rate = bytestream_get_le32(&p); // nominal bitrate | |
736e63ed MR |
283 | p += 4; // skip minimum bitrate |
284 | ||
285 | blocksize = bytestream_get_byte(&p); | |
49fe9c05 VG |
286 | bs0 = blocksize & 15; |
287 | bs1 = blocksize >> 4; | |
736e63ed MR |
288 | |
289 | if (bs0 > bs1) | |
90e15e34 | 290 | return AVERROR_INVALIDDATA; |
736e63ed | 291 | if (bs0 < 6 || bs1 > 13) |
90e15e34 | 292 | return AVERROR_INVALIDDATA; |
736e63ed MR |
293 | |
294 | if (bytestream_get_byte(&p) != 1) /* framing_flag */ | |
90e15e34 | 295 | return AVERROR_INVALIDDATA; |
9146ca37 | 296 | |
72415b2a | 297 | st->codec->codec_type = AVMEDIA_TYPE_AUDIO; |
49fe9c05 | 298 | st->codec->codec_id = AV_CODEC_ID_VORBIS; |
9146ca37 | 299 | |
ce20edb7 RD |
300 | if (srate > 0) { |
301 | st->codec->sample_rate = srate; | |
c3f9ebf7 | 302 | avpriv_set_pts_info(st, 64, 1, srate); |
ce20edb7 | 303 | } |
9146ca37 | 304 | } else if (os->buf[os->pstart] == 3) { |
8cb3c557 | 305 | if (os->psize > 8 && |
49fe9c05 VG |
306 | ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, |
307 | os->psize - 8) >= 0) { | |
8cb3c557 RD |
308 | // drop all metadata we parsed and which is not required by libvorbis |
309 | unsigned new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1; | |
310 | if (new_len >= 16 && new_len < os->psize) { | |
311 | AV_WL32(priv->packet[1] + new_len - 5, 0); | |
312 | priv->packet[1][new_len - 1] = 1; | |
49fe9c05 | 313 | priv->len[1] = new_len; |
8cb3c557 RD |
314 | } |
315 | } | |
ad2b531d | 316 | } else { |
d872fb0f MS |
317 | int ret = fixup_vorbis_headers(s, priv, &st->codec->extradata); |
318 | if (ret < 0) { | |
319 | st->codec->extradata_size = 0; | |
320 | return ret; | |
321 | } | |
322 | st->codec->extradata_size = ret; | |
f63412fc JR |
323 | if ((ret = avpriv_vorbis_parse_extradata(st->codec, &priv->vp))) { |
324 | av_freep(&st->codec->extradata); | |
325 | st->codec->extradata_size = 0; | |
326 | return ret; | |
327 | } | |
9146ca37 MR |
328 | } |
329 | ||
8f8320d7 | 330 | return 1; |
9146ca37 MR |
331 | } |
332 | ||
f63412fc JR |
333 | static int vorbis_packet(AVFormatContext *s, int idx) |
334 | { | |
335 | struct ogg *ogg = s->priv_data; | |
336 | struct ogg_stream *os = ogg->streams + idx; | |
337 | struct oggvorbis_private *priv = os->private; | |
338 | int duration; | |
339 | ||
340 | /* first packet handling | |
49fe9c05 VG |
341 | * here we parse the duration of each packet in the first page and compare |
342 | * the total duration to the page granule to find the encoder delay and | |
343 | * set the first timestamp */ | |
f63412fc JR |
344 | if (!os->lastpts) { |
345 | int seg; | |
49fe9c05 VG |
346 | uint8_t *last_pkt = os->buf + os->pstart; |
347 | uint8_t *next_pkt = last_pkt; | |
f63412fc JR |
348 | int first_duration = 0; |
349 | ||
350 | avpriv_vorbis_parse_reset(&priv->vp); | |
351 | duration = 0; | |
352 | for (seg = 0; seg < os->nsegs; seg++) { | |
353 | if (os->segments[seg] < 255) { | |
354 | int d = avpriv_vorbis_parse_frame(&priv->vp, last_pkt, 1); | |
355 | if (d < 0) { | |
356 | duration = os->granule; | |
357 | break; | |
358 | } | |
359 | if (!duration) | |
360 | first_duration = d; | |
361 | duration += d; | |
49fe9c05 | 362 | last_pkt = next_pkt + os->segments[seg]; |
f63412fc JR |
363 | } |
364 | next_pkt += os->segments[seg]; | |
365 | } | |
49fe9c05 VG |
366 | os->lastpts = |
367 | os->lastdts = os->granule - duration; | |
f63412fc JR |
368 | s->streams[idx]->start_time = os->lastpts + first_duration; |
369 | if (s->streams[idx]->duration) | |
370 | s->streams[idx]->duration -= s->streams[idx]->start_time; | |
49fe9c05 VG |
371 | s->streams[idx]->cur_dts = AV_NOPTS_VALUE; |
372 | priv->final_pts = AV_NOPTS_VALUE; | |
f63412fc JR |
373 | avpriv_vorbis_parse_reset(&priv->vp); |
374 | } | |
375 | ||
376 | /* parse packet duration */ | |
377 | if (os->psize > 0) { | |
378 | duration = avpriv_vorbis_parse_frame(&priv->vp, os->buf + os->pstart, 1); | |
379 | if (duration <= 0) { | |
380 | os->pflags |= AV_PKT_FLAG_CORRUPT; | |
381 | return 0; | |
382 | } | |
383 | os->pduration = duration; | |
384 | } | |
385 | ||
386 | /* final packet handling | |
49fe9c05 VG |
387 | * here we save the pts of the first packet in the final page, sum up all |
388 | * packet durations in the final page except for the last one, and compare | |
389 | * to the page granule to find the duration of the final packet */ | |
f63412fc JR |
390 | if (os->flags & OGG_FLAG_EOS) { |
391 | if (os->lastpts != AV_NOPTS_VALUE) { | |
49fe9c05 | 392 | priv->final_pts = os->lastpts; |
f63412fc JR |
393 | priv->final_duration = 0; |
394 | } | |
395 | if (os->segp == os->nsegs) | |
396 | os->pduration = os->granule - priv->final_pts - priv->final_duration; | |
397 | priv->final_duration += os->pduration; | |
398 | } | |
399 | ||
400 | return 0; | |
401 | } | |
402 | ||
77be08ee | 403 | const struct ogg_codec ff_vorbis_codec = { |
49fe9c05 | 404 | .magic = "\001vorbis", |
9146ca37 | 405 | .magicsize = 7, |
49fe9c05 VG |
406 | .header = vorbis_header, |
407 | .packet = vorbis_packet, | |
408 | .cleanup = vorbis_cleanup, | |
7751e469 | 409 | .nb_header = 3, |
9146ca37 | 410 | }; |