/src/ffmpeg/libavformat/oggparsevorbis.c
Line | Count | Source |
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 | | |
27 | | #include "libavutil/avstring.h" |
28 | | #include "libavutil/base64.h" |
29 | | #include "libavutil/dict.h" |
30 | | #include "libavutil/mem.h" |
31 | | |
32 | | #include "libavcodec/bytestream.h" |
33 | | #include "libavcodec/vorbis_parser.h" |
34 | | |
35 | | #include "avformat.h" |
36 | | #include "demux.h" |
37 | | #include "flac_picture.h" |
38 | | #include "internal.h" |
39 | | #include "oggdec.h" |
40 | | #include "vorbiscomment.h" |
41 | | #include "replaygain.h" |
42 | | |
43 | | static int ogm_chapter(AVFormatContext *as, const uint8_t *key, const uint8_t *val) |
44 | 42.9k | { |
45 | 42.9k | int i, cnum, h, m, s, ms, keylen = strlen(key); |
46 | 42.9k | AVChapter *chapter = NULL; |
47 | | |
48 | 42.9k | if (keylen < 9 || av_strncasecmp(key, "CHAPTER", 7) || sscanf(key+7, "%03d", &cnum) != 1) |
49 | 33.5k | return 0; |
50 | | |
51 | 9.45k | if (keylen <= 10) { |
52 | 4.95k | if (sscanf(val, "%02d:%02d:%02d.%03d", &h, &m, &s, &ms) < 4) |
53 | 542 | return 0; |
54 | | |
55 | 4.41k | avpriv_new_chapter(as, cnum, (AVRational) { 1, 1000 }, |
56 | 4.41k | ms + 1000 * (s + 60 * (m + 60 * h)), |
57 | 4.41k | AV_NOPTS_VALUE, NULL); |
58 | 4.49k | } else if (!av_strcasecmp(key + keylen - 4, "NAME")) { |
59 | 11.0k | for (i = 0; i < as->nb_chapters; i++) |
60 | 11.0k | if (as->chapters[i]->id == cnum) { |
61 | 4.41k | chapter = as->chapters[i]; |
62 | 4.41k | break; |
63 | 4.41k | } |
64 | 4.41k | if (!chapter) |
65 | 0 | return 0; |
66 | | |
67 | 4.41k | av_dict_set(&chapter->metadata, "title", val, 0); |
68 | 4.41k | } else |
69 | 77 | return 0; |
70 | | |
71 | 8.83k | return 1; |
72 | 9.45k | } |
73 | | |
74 | | int ff_vorbis_stream_comment(AVFormatContext *as, AVStream *st, |
75 | | const uint8_t *buf, int size) |
76 | 14.1k | { |
77 | 14.1k | int updates = ff_vorbis_comment(as, &st->metadata, buf, size, 1); |
78 | | |
79 | 14.1k | if (updates > 0) { |
80 | 12.4k | st->event_flags |= AVSTREAM_EVENT_FLAG_METADATA_UPDATED; |
81 | 12.4k | } |
82 | | |
83 | 14.1k | return updates; |
84 | 14.1k | } |
85 | | |
86 | | /** |
87 | | * This function temporarily modifies the (const qualified) input buffer |
88 | | * and reverts its changes before return. The input buffer needs to have |
89 | | * at least one byte of padding. |
90 | | */ |
91 | | static int vorbis_parse_single_comment(AVFormatContext *as, AVDictionary **m, |
92 | | const uint8_t *buf, uint32_t size, |
93 | | int *updates, int parse_picture) |
94 | 49.2k | { |
95 | 49.2k | char *t = (char*)buf, *v = memchr(t, '=', size); |
96 | 49.2k | int tl, vl; |
97 | 49.2k | char backup; |
98 | | |
99 | 49.2k | if (!v) |
100 | 4.72k | return 0; |
101 | | |
102 | 44.5k | tl = v - t; |
103 | 44.5k | vl = size - tl - 1; |
104 | 44.5k | v++; |
105 | | |
106 | 44.5k | if (!tl || !vl) |
107 | 1.54k | return 0; |
108 | | |
109 | 42.9k | t[tl] = 0; |
110 | | |
111 | 42.9k | backup = v[vl]; |
112 | 42.9k | v[vl] = 0; |
113 | | |
114 | | /* The format in which the pictures are stored is the FLAC format. |
115 | | * Xiph says: "The binary FLAC picture structure is base64 encoded |
116 | | * and placed within a VorbisComment with the tag name |
117 | | * 'METADATA_BLOCK_PICTURE'. This is the preferred and |
118 | | * recommended way of embedding cover art within VorbisComments." |
119 | | */ |
120 | 42.9k | if (!av_strcasecmp(t, "METADATA_BLOCK_PICTURE") && parse_picture) { |
121 | 2 | int ret, len = AV_BASE64_DECODE_SIZE(vl); |
122 | 2 | uint8_t *pict = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE); |
123 | | |
124 | 2 | if (!pict) { |
125 | 0 | av_log(as, AV_LOG_WARNING, "out-of-memory error. Skipping cover art block.\n"); |
126 | 0 | goto end; |
127 | 0 | } |
128 | 2 | ret = av_base64_decode(pict, v, len); |
129 | 2 | if (ret > 0) |
130 | 2 | ret = ff_flac_parse_picture(as, &pict, ret, 0); |
131 | 2 | av_freep(&pict); |
132 | 2 | if (ret < 0) { |
133 | 0 | av_log(as, AV_LOG_WARNING, "Failed to parse cover art block.\n"); |
134 | 0 | goto end; |
135 | 0 | } |
136 | 42.9k | } else if (!ogm_chapter(as, t, v)) { |
137 | 34.1k | (*updates)++; |
138 | 34.1k | if (av_dict_get(*m, t, NULL, 0)) |
139 | 5.45k | av_dict_set(m, t, ";", AV_DICT_APPEND); |
140 | 34.1k | av_dict_set(m, t, v, AV_DICT_APPEND); |
141 | 34.1k | } |
142 | 42.9k | end: |
143 | 42.9k | t[tl] = '='; |
144 | 42.9k | v[vl] = backup; |
145 | | |
146 | 42.9k | return 0; |
147 | 42.9k | } |
148 | | |
149 | | int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, |
150 | | const uint8_t *buf, int size, |
151 | | int parse_picture) |
152 | 52.3k | { |
153 | 52.3k | const uint8_t *p = buf; |
154 | 52.3k | const uint8_t *end = buf + size; |
155 | 52.3k | int updates = 0; |
156 | 52.3k | unsigned n; |
157 | 52.3k | int s, ret; |
158 | | |
159 | | /* must have vendor_length and user_comment_list_length */ |
160 | 52.3k | if (size < 8) |
161 | 11.0k | return AVERROR_INVALIDDATA; |
162 | | |
163 | 41.2k | s = bytestream_get_le32(&p); |
164 | | |
165 | 41.2k | if (end - p - 4 < s || s < 0) |
166 | 3.23k | return AVERROR_INVALIDDATA; |
167 | | |
168 | 38.0k | p += s; |
169 | | |
170 | 38.0k | n = bytestream_get_le32(&p); |
171 | | |
172 | 87.2k | while (end - p >= 4 && n > 0) { |
173 | 56.6k | s = bytestream_get_le32(&p); |
174 | | |
175 | 56.6k | if (end - p < s || s < 0) |
176 | 7.42k | break; |
177 | | |
178 | 49.2k | ret = vorbis_parse_single_comment(as, m, p, s, &updates, parse_picture); |
179 | 49.2k | if (ret < 0) |
180 | 0 | return ret; |
181 | 49.2k | p += s; |
182 | 49.2k | n--; |
183 | 49.2k | } |
184 | | |
185 | 38.0k | if (p != end) |
186 | 18.4k | av_log(as, AV_LOG_INFO, |
187 | 18.4k | "%td bytes of comment header remain\n", end - p); |
188 | 38.0k | if (n > 0) |
189 | 17.4k | av_log(as, AV_LOG_INFO, |
190 | 17.4k | "truncated comment header, %i comments not found\n", n); |
191 | | |
192 | 38.0k | ff_metadata_conv(m, NULL, ff_vorbiscomment_metadata_conv); |
193 | | |
194 | 38.0k | return updates; |
195 | 38.0k | } |
196 | | |
197 | | /* |
198 | | * Parse the vorbis header |
199 | | * |
200 | | * Vorbis Identification header from Vorbis_I_spec.html#vorbis-spec-codec |
201 | | * [vorbis_version] = read 32 bits as unsigned integer | Not used |
202 | | * [audio_channels] = read 8 bit integer as unsigned | Used |
203 | | * [audio_sample_rate] = read 32 bits as unsigned integer | Used |
204 | | * [bitrate_maximum] = read 32 bits as signed integer | Not used yet |
205 | | * [bitrate_nominal] = read 32 bits as signed integer | Not used yet |
206 | | * [bitrate_minimum] = read 32 bits as signed integer | Used as bitrate |
207 | | * [blocksize_0] = read 4 bits as unsigned integer | Not Used |
208 | | * [blocksize_1] = read 4 bits as unsigned integer | Not Used |
209 | | * [framing_flag] = read one bit | Not Used |
210 | | */ |
211 | | |
212 | | struct oggvorbis_private { |
213 | | unsigned int len[3]; |
214 | | unsigned char *packet[3]; |
215 | | AVVorbisParseContext *vp; |
216 | | int64_t final_pts; |
217 | | int final_duration; |
218 | | uint8_t *header; |
219 | | int header_size; |
220 | | uint8_t *comment; |
221 | | int comment_size; |
222 | | uint8_t *setup; |
223 | | int setup_size; |
224 | | }; |
225 | | |
226 | | static int fixup_vorbis_headers(AVFormatContext *as, |
227 | | struct oggvorbis_private *priv, |
228 | | uint8_t **buf) |
229 | 931 | { |
230 | 931 | int i, offset, len, err; |
231 | 931 | int buf_len; |
232 | 931 | unsigned char *ptr; |
233 | | |
234 | 931 | len = priv->len[0] + priv->len[1] + priv->len[2]; |
235 | 931 | buf_len = len + len / 255 + 64; |
236 | | |
237 | 931 | if (*buf) |
238 | 0 | return AVERROR_INVALIDDATA; |
239 | | |
240 | 931 | ptr = *buf = av_realloc(NULL, buf_len); |
241 | 931 | if (!ptr) |
242 | 0 | return AVERROR(ENOMEM); |
243 | 931 | memset(*buf, '\0', buf_len); |
244 | | |
245 | 931 | ptr[0] = 2; |
246 | 931 | offset = 1; |
247 | 931 | offset += av_xiphlacing(&ptr[offset], priv->len[0]); |
248 | 931 | offset += av_xiphlacing(&ptr[offset], priv->len[1]); |
249 | 3.72k | for (i = 0; i < 3; i++) { |
250 | 2.79k | memcpy(&ptr[offset], priv->packet[i], priv->len[i]); |
251 | 2.79k | offset += priv->len[i]; |
252 | 2.79k | av_freep(&priv->packet[i]); |
253 | 2.79k | } |
254 | 931 | if ((err = av_reallocp(buf, offset + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) |
255 | 0 | return err; |
256 | 931 | return offset; |
257 | 931 | } |
258 | | |
259 | | static void vorbis_cleanup(AVFormatContext *s, int idx) |
260 | 1.64k | { |
261 | 1.64k | struct ogg *ogg = s->priv_data; |
262 | 1.64k | struct ogg_stream *os = ogg->streams + idx; |
263 | 1.64k | struct oggvorbis_private *priv = os->private; |
264 | 1.64k | int i; |
265 | 1.64k | if (os->private) { |
266 | 1.64k | av_vorbis_parse_free(&priv->vp); |
267 | 6.56k | for (i = 0; i < 3; i++) |
268 | 4.92k | av_freep(&priv->packet[i]); |
269 | | |
270 | 1.64k | av_freep(&priv->header); |
271 | 1.64k | av_freep(&priv->comment); |
272 | 1.64k | av_freep(&priv->setup); |
273 | 1.64k | } |
274 | 1.64k | } |
275 | | |
276 | | int ff_vorbis_update_metadata(AVFormatContext *s, AVStream *st, |
277 | | const uint8_t *buf, int size) |
278 | 10.7k | { |
279 | 10.7k | struct ogg *ogg = s->priv_data; |
280 | 10.7k | struct ogg_stream *os = ogg->streams + st->index; |
281 | 10.7k | int ret; |
282 | | |
283 | | /* New metadata packet; release old data. */ |
284 | 10.7k | av_dict_free(&st->metadata); |
285 | 10.7k | ret = ff_vorbis_stream_comment(s, st, buf, size); |
286 | 10.7k | if (ret < 0) |
287 | 104 | return ret; |
288 | | |
289 | | /* Update the metadata if possible. */ |
290 | 10.6k | av_freep(&os->new_metadata); |
291 | 10.6k | if (st->metadata) { |
292 | 9.82k | os->new_metadata = av_packet_pack_dictionary(st->metadata, &os->new_metadata_size); |
293 | | /* Send an empty dictionary to indicate that metadata has been cleared. */ |
294 | 9.82k | } else { |
295 | 785 | os->new_metadata = av_mallocz(1); |
296 | 785 | os->new_metadata_size = 0; |
297 | 785 | } |
298 | | |
299 | 10.6k | return ret; |
300 | 10.7k | } |
301 | | |
302 | | static int vorbis_parse_header(AVFormatContext *s, AVStream *st, |
303 | | const uint8_t *p, unsigned int psize) |
304 | 3.89k | { |
305 | 3.89k | unsigned blocksize, bs0, bs1; |
306 | 3.89k | int srate; |
307 | 3.89k | int channels; |
308 | | |
309 | 3.89k | if (psize != 30) |
310 | 44 | return AVERROR_INVALIDDATA; |
311 | | |
312 | 3.85k | p += 7; /* skip "\001vorbis" tag */ |
313 | | |
314 | 3.85k | if (bytestream_get_le32(&p) != 0) /* vorbis_version */ |
315 | 9 | return AVERROR_INVALIDDATA; |
316 | | |
317 | 3.84k | channels = bytestream_get_byte(&p); |
318 | 3.84k | if (st->codecpar->ch_layout.nb_channels && |
319 | 2.22k | channels != st->codecpar->ch_layout.nb_channels) { |
320 | 6 | av_log(s, AV_LOG_ERROR, "Channel change is not supported\n"); |
321 | 6 | return AVERROR_PATCHWELCOME; |
322 | 6 | } |
323 | 3.83k | st->codecpar->ch_layout.nb_channels = channels; |
324 | 3.83k | srate = bytestream_get_le32(&p); |
325 | 3.83k | p += 4; // skip maximum bitrate |
326 | 3.83k | st->codecpar->bit_rate = bytestream_get_le32(&p); // nominal bitrate |
327 | 3.83k | p += 4; // skip minimum bitrate |
328 | | |
329 | 3.83k | blocksize = bytestream_get_byte(&p); |
330 | 3.83k | bs0 = blocksize & 15; |
331 | 3.83k | bs1 = blocksize >> 4; |
332 | | |
333 | 3.83k | if (bs0 > bs1) |
334 | 5 | return AVERROR_INVALIDDATA; |
335 | 3.83k | if (bs0 < 6 || bs1 > 13) |
336 | 20 | return AVERROR_INVALIDDATA; |
337 | | |
338 | 3.81k | if (bytestream_get_byte(&p) != 1) /* framing_flag */ |
339 | 1 | return AVERROR_INVALIDDATA; |
340 | | |
341 | 3.81k | st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; |
342 | 3.81k | st->codecpar->codec_id = AV_CODEC_ID_VORBIS; |
343 | | |
344 | 3.81k | if (srate > 0) { |
345 | 3.38k | if (st->codecpar->sample_rate && |
346 | 1.88k | srate != st->codecpar->sample_rate) { |
347 | 7 | av_log(s, AV_LOG_ERROR, "Sample rate change is not supported\n"); |
348 | 7 | return AVERROR_PATCHWELCOME; |
349 | 7 | } |
350 | | |
351 | 3.38k | st->codecpar->sample_rate = srate; |
352 | 3.38k | avpriv_set_pts_info(st, 64, 1, srate); |
353 | 3.38k | } |
354 | | |
355 | 3.80k | return 1; |
356 | 3.81k | } |
357 | | |
358 | | static int vorbis_update_metadata(AVFormatContext *s, int idx) |
359 | 4.64k | { |
360 | 4.64k | struct ogg *ogg = s->priv_data; |
361 | 4.64k | struct ogg_stream *os = ogg->streams + idx; |
362 | 4.64k | AVStream *st = s->streams[idx]; |
363 | | |
364 | 4.64k | if (os->psize <= 8) |
365 | 300 | return 0; |
366 | | |
367 | 4.34k | return ff_vorbis_update_metadata(s, st, os->buf + os->pstart + 7, |
368 | 4.34k | os->psize - 8); |
369 | 4.64k | } |
370 | | |
371 | | static int vorbis_header(AVFormatContext *s, int idx) |
372 | 4.72k | { |
373 | 4.72k | struct ogg *ogg = s->priv_data; |
374 | 4.72k | AVStream *st = s->streams[idx]; |
375 | 4.72k | struct ogg_stream *os = ogg->streams + idx; |
376 | 4.72k | struct oggvorbis_private *priv; |
377 | 4.72k | int pkt_type = os->buf[os->pstart]; |
378 | | |
379 | 4.72k | if (!os->private) { |
380 | 1.64k | os->private = av_mallocz(sizeof(struct oggvorbis_private)); |
381 | 1.64k | if (!os->private) |
382 | 0 | return AVERROR(ENOMEM); |
383 | 1.64k | } |
384 | | |
385 | 4.72k | priv = os->private; |
386 | | |
387 | 4.72k | if (!(pkt_type & 1)) |
388 | 534 | return priv->vp ? 0 : AVERROR_INVALIDDATA; |
389 | | |
390 | 4.18k | if (pkt_type > 5) { |
391 | 278 | av_log(s, AV_LOG_VERBOSE, "Ignoring packet with unknown type %d\n", pkt_type); |
392 | 278 | return 1; |
393 | 278 | } |
394 | | |
395 | 3.91k | if (os->psize < 1) |
396 | 1 | return AVERROR_INVALIDDATA; |
397 | | |
398 | 3.90k | if (priv->packet[pkt_type >> 1]) |
399 | 33 | return AVERROR_INVALIDDATA; |
400 | 3.87k | if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1]) |
401 | 158 | return priv->vp ? 0 : AVERROR_INVALIDDATA; |
402 | | |
403 | 3.71k | priv->len[pkt_type >> 1] = os->psize; |
404 | 3.71k | priv->packet[pkt_type >> 1] = av_memdup(os->buf + os->pstart, os->psize); |
405 | 3.71k | if (!priv->packet[pkt_type >> 1]) |
406 | 0 | return AVERROR(ENOMEM); |
407 | 3.71k | if (pkt_type == 1) |
408 | 1.78k | return vorbis_parse_header(s, st, os->buf + os->pstart, os->psize); |
409 | | |
410 | 1.93k | if (pkt_type == 3) { |
411 | 989 | if (vorbis_update_metadata(s, idx) >= 0 && priv->len[1] > 10) { |
412 | 989 | unsigned new_len; |
413 | | |
414 | 989 | int ret = ff_replaygain_export(st, st->metadata); |
415 | 989 | if (ret < 0) |
416 | 0 | return ret; |
417 | | |
418 | | // drop all metadata we parsed and which is not required by libvorbis |
419 | 989 | new_len = 7 + 4 + AV_RL32(priv->packet[1] + 7) + 4 + 1; |
420 | 989 | if (new_len >= 16 && new_len < os->psize) { |
421 | 743 | AV_WL32(priv->packet[1] + new_len - 5, 0); |
422 | 743 | priv->packet[1][new_len - 1] = 1; |
423 | 743 | priv->len[1] = new_len; |
424 | 743 | } |
425 | 989 | } |
426 | 989 | } else { |
427 | 949 | int ret; |
428 | | |
429 | 949 | if (priv->vp) |
430 | 18 | return AVERROR_INVALIDDATA; |
431 | | |
432 | 931 | ret = fixup_vorbis_headers(s, priv, &st->codecpar->extradata); |
433 | 931 | if (ret < 0) { |
434 | 0 | st->codecpar->extradata_size = 0; |
435 | 0 | return ret; |
436 | 0 | } |
437 | 931 | st->codecpar->extradata_size = ret; |
438 | | |
439 | 931 | priv->vp = av_vorbis_parse_init(st->codecpar->extradata, st->codecpar->extradata_size); |
440 | 931 | if (!priv->vp) { |
441 | 61 | av_freep(&st->codecpar->extradata); |
442 | 61 | st->codecpar->extradata_size = 0; |
443 | 61 | return AVERROR_UNKNOWN; |
444 | 61 | } |
445 | 931 | } |
446 | | |
447 | 1.85k | return 1; |
448 | 1.93k | } |
449 | | |
450 | | static int vorbis_packet(AVFormatContext *s, int idx) |
451 | 272k | { |
452 | 272k | struct ogg *ogg = s->priv_data; |
453 | 272k | struct ogg_stream *os = ogg->streams + idx; |
454 | 272k | struct oggvorbis_private *priv = os->private; |
455 | 272k | int duration, flags = 0; |
456 | 272k | int skip_packet = 0; |
457 | 272k | int ret, new_extradata_size; |
458 | 272k | PutByteContext pb; |
459 | | |
460 | 272k | if (!priv->vp) |
461 | 0 | return AVERROR_INVALIDDATA; |
462 | | |
463 | | /* first packet handling |
464 | | * here we parse the duration of each packet in the first page and compare |
465 | | * the total duration to the page granule to find the encoder delay and |
466 | | * set the first timestamp */ |
467 | 272k | if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS) && (int64_t)os->granule>=0) { |
468 | 193k | int seg, d; |
469 | 193k | uint8_t *last_pkt = os->buf + os->pstart; |
470 | 193k | uint8_t *next_pkt = last_pkt; |
471 | | |
472 | 193k | av_vorbis_parse_reset(priv->vp); |
473 | 193k | duration = 0; |
474 | 193k | seg = os->segp; |
475 | 193k | d = av_vorbis_parse_frame_flags(priv->vp, last_pkt, 1, &flags); |
476 | 193k | if (d < 0) { |
477 | 0 | os->pflags |= AV_PKT_FLAG_CORRUPT; |
478 | 0 | return 0; |
479 | 193k | } else if (flags & VORBIS_FLAG_COMMENT) { |
480 | 1.57k | vorbis_update_metadata(s, idx); |
481 | 1.57k | flags = 0; |
482 | 1.57k | } |
483 | 193k | duration += d; |
484 | 193k | last_pkt = next_pkt = next_pkt + os->psize; |
485 | 4.94M | for (; seg < os->nsegs; seg++) { |
486 | 4.74M | if (os->segments[seg] < 255) { |
487 | 4.61M | int d = av_vorbis_parse_frame_flags(priv->vp, last_pkt, 1, &flags); |
488 | 4.61M | if (d < 0) { |
489 | 0 | duration = os->granule; |
490 | 0 | break; |
491 | 4.61M | } else if (flags & VORBIS_FLAG_COMMENT) { |
492 | 380 | vorbis_update_metadata(s, idx); |
493 | 380 | flags = 0; |
494 | 380 | } |
495 | 4.61M | duration += d; |
496 | 4.61M | last_pkt = next_pkt + os->segments[seg]; |
497 | 4.61M | } |
498 | 4.74M | next_pkt += os->segments[seg]; |
499 | 4.74M | } |
500 | 193k | os->lastpts = |
501 | 193k | os->lastdts = os->granule - duration; |
502 | | |
503 | 193k | if (!os->granule && duration) //hack to deal with broken files (Ticket3710) |
504 | 162k | os->lastpts = os->lastdts = AV_NOPTS_VALUE; |
505 | | |
506 | 193k | if (s->streams[idx]->start_time == AV_NOPTS_VALUE) { |
507 | 529 | s->streams[idx]->start_time = FFMAX(os->lastpts, 0); |
508 | 529 | if (s->streams[idx]->duration != AV_NOPTS_VALUE) |
509 | 161 | s->streams[idx]->duration -= s->streams[idx]->start_time; |
510 | 529 | } |
511 | 193k | priv->final_pts = AV_NOPTS_VALUE; |
512 | 193k | av_vorbis_parse_reset(priv->vp); |
513 | 193k | } |
514 | | |
515 | | /* parse packet duration */ |
516 | 272k | if (os->psize > 0) { |
517 | 115k | duration = av_vorbis_parse_frame_flags(priv->vp, os->buf + os->pstart, 1, &flags); |
518 | 115k | if (duration < 0) { |
519 | 0 | os->pflags |= AV_PKT_FLAG_CORRUPT; |
520 | 0 | return 0; |
521 | 0 | } |
522 | | |
523 | 115k | if (flags & VORBIS_FLAG_HEADER) { |
524 | 2.11k | ret = vorbis_parse_header(s, s->streams[idx], os->buf + os->pstart, os->psize); |
525 | 2.11k | if (ret < 0) |
526 | 53 | return ret; |
527 | | |
528 | 2.06k | ret = av_reallocp(&priv->header, os->psize); |
529 | 2.06k | if (ret < 0) |
530 | 0 | return ret; |
531 | | |
532 | 2.06k | memcpy(priv->header, os->buf + os->pstart, os->psize); |
533 | 2.06k | priv->header_size = os->psize; |
534 | | |
535 | 2.06k | skip_packet = 1; |
536 | 2.06k | } |
537 | | |
538 | 115k | if (flags & VORBIS_FLAG_COMMENT) { |
539 | 1.70k | ret = vorbis_update_metadata(s, idx); |
540 | 1.70k | if (ret < 0) |
541 | 0 | return ret; |
542 | | |
543 | 1.70k | ret = av_reallocp(&priv->comment, os->psize); |
544 | 1.70k | if (ret < 0) |
545 | 0 | return ret; |
546 | | |
547 | 1.70k | memcpy(priv->comment, os->buf + os->pstart, os->psize); |
548 | 1.70k | priv->comment_size = os->psize; |
549 | | |
550 | 1.70k | flags = 0; |
551 | 1.70k | skip_packet = 1; |
552 | 1.70k | } |
553 | | |
554 | 115k | if (flags & VORBIS_FLAG_SETUP) { |
555 | 1.13k | ret = av_reallocp(&priv->setup, os->psize); |
556 | 1.13k | if (ret < 0) |
557 | 0 | return ret; |
558 | | |
559 | 1.13k | memcpy(priv->setup, os->buf + os->pstart, os->psize); |
560 | 1.13k | priv->setup_size = os->psize; |
561 | | |
562 | 1.13k | skip_packet = 1; |
563 | 1.13k | } |
564 | | |
565 | 115k | os->pduration = duration; |
566 | 115k | } |
567 | | |
568 | | /* final packet handling |
569 | | * here we save the pts of the first packet in the final page, sum up all |
570 | | * packet durations in the final page except for the last one, and compare |
571 | | * to the page granule to find the duration of the final packet */ |
572 | 272k | if (os->flags & OGG_FLAG_EOS) { |
573 | 71.1k | if (os->lastpts != AV_NOPTS_VALUE) { |
574 | 1.06k | priv->final_pts = os->lastpts; |
575 | 1.06k | priv->final_duration = 0; |
576 | 1.06k | } |
577 | 71.1k | if (os->segp == os->nsegs) { |
578 | 1.04k | int64_t skip = priv->final_pts + priv->final_duration + os->pduration - os->granule; |
579 | 1.04k | if (skip > 0) |
580 | 1.01k | os->end_trimming = skip; |
581 | 1.04k | os->pduration = os->granule - priv->final_pts - priv->final_duration; |
582 | 1.04k | } |
583 | 71.1k | priv->final_duration += os->pduration; |
584 | 71.1k | } |
585 | | |
586 | 272k | if (priv->header && priv->comment && priv->setup) { |
587 | 688 | new_extradata_size = priv->header_size + priv->comment_size + priv->setup_size + 6; |
588 | | |
589 | 688 | ret = av_reallocp(&os->new_extradata, new_extradata_size); |
590 | 688 | if (ret < 0) |
591 | 0 | return ret; |
592 | | |
593 | 688 | os->new_extradata_size = new_extradata_size; |
594 | 688 | bytestream2_init_writer(&pb, os->new_extradata, new_extradata_size); |
595 | 688 | bytestream2_put_be16(&pb, priv->header_size); |
596 | 688 | bytestream2_put_buffer(&pb, priv->header, priv->header_size); |
597 | 688 | bytestream2_put_be16(&pb, priv->comment_size); |
598 | 688 | bytestream2_put_buffer(&pb, priv->comment, priv->comment_size); |
599 | 688 | bytestream2_put_be16(&pb, priv->setup_size); |
600 | 688 | bytestream2_put_buffer(&pb, priv->setup, priv->setup_size); |
601 | | |
602 | 688 | av_freep(&priv->header); |
603 | 688 | priv->header_size = 0; |
604 | 688 | av_freep(&priv->comment); |
605 | 688 | priv->comment_size = 0; |
606 | 688 | av_freep(&priv->setup); |
607 | 688 | priv->setup_size = 0; |
608 | 688 | } |
609 | | |
610 | 272k | return skip_packet; |
611 | 272k | } |
612 | | |
613 | | const struct ogg_codec ff_vorbis_codec = { |
614 | | .magic = "\001vorbis", |
615 | | .magicsize = 7, |
616 | | .header = vorbis_header, |
617 | | .packet = vorbis_packet, |
618 | | .cleanup = vorbis_cleanup, |
619 | | .nb_header = 3, |
620 | | }; |