summaryrefslogtreecommitdiff
path: root/libavformat/oggdec.c (plain)
blob: 97ad1a27d15ce55bceed94017e316dc618d816ad
1/*
2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
5 */
6
7/*
8 Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
9
10 Permission is hereby granted, free of charge, to any person
11 obtaining a copy of this software and associated documentation
12 files (the "Software"), to deal in the Software without
13 restriction, including without limitation the rights to use, copy,
14 modify, merge, publish, distribute, sublicense, and/or sell copies
15 of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 DEALINGS IN THE SOFTWARE.
29 */
30
31#include <stdio.h>
32#include "libavutil/avassert.h"
33#include "libavutil/intreadwrite.h"
34#include "oggdec.h"
35#include "avformat.h"
36#include "internal.h"
37#include "vorbiscomment.h"
38
39#define MAX_PAGE_SIZE 65307
40#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
41
42static const struct ogg_codec * const ogg_codecs[] = {
43 &ff_skeleton_codec,
44 &ff_daala_codec,
45 &ff_dirac_codec,
46 &ff_speex_codec,
47 &ff_vorbis_codec,
48 &ff_theora_codec,
49 &ff_flac_codec,
50 &ff_celt_codec,
51 &ff_opus_codec,
52 &ff_vp8_codec,
53 &ff_old_dirac_codec,
54 &ff_old_flac_codec,
55 &ff_ogm_video_codec,
56 &ff_ogm_audio_codec,
57 &ff_ogm_text_codec,
58 &ff_ogm_old_codec,
59 NULL
60};
61
62static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
63static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
64static int ogg_restore(AVFormatContext *s);
65
66static void free_stream(AVFormatContext *s, int i)
67{
68 struct ogg *ogg = s->priv_data;
69 struct ogg_stream *stream = &ogg->streams[i];
70
71 av_freep(&stream->buf);
72 if (stream->codec &&
73 stream->codec->cleanup) {
74 stream->codec->cleanup(s, i);
75 }
76
77 av_freep(&stream->private);
78 av_freep(&stream->new_metadata);
79}
80
81//FIXME We could avoid some structure duplication
82static int ogg_save(AVFormatContext *s)
83{
84 struct ogg *ogg = s->priv_data;
85 struct ogg_state *ost =
86 av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
87 int i;
88 int ret = 0;
89
90 if (!ost)
91 return AVERROR(ENOMEM);
92
93 ost->pos = avio_tell(s->pb);
94 ost->curidx = ogg->curidx;
95 ost->next = ogg->state;
96 ost->nstreams = ogg->nstreams;
97 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
98
99 for (i = 0; i < ogg->nstreams; i++) {
100 struct ogg_stream *os = ogg->streams + i;
101 os->buf = av_mallocz(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
102 if (os->buf)
103 memcpy(os->buf, ost->streams[i].buf, os->bufpos);
104 else
105 ret = AVERROR(ENOMEM);
106 os->new_metadata = NULL;
107 os->new_metadata_size = 0;
108 }
109
110 ogg->state = ost;
111
112 if (ret < 0)
113 ogg_restore(s);
114
115 return ret;
116}
117
118static int ogg_restore(AVFormatContext *s)
119{
120 struct ogg *ogg = s->priv_data;
121 AVIOContext *bc = s->pb;
122 struct ogg_state *ost = ogg->state;
123 int i, err;
124
125 if (!ost)
126 return 0;
127
128 ogg->state = ost->next;
129
130 for (i = 0; i < ogg->nstreams; i++) {
131 av_freep(&ogg->streams[i].buf);
132 if (i >= ost->nstreams || !ost->streams[i].private) {
133 free_stream(s, i);
134 }
135 }
136
137 avio_seek(bc, ost->pos, SEEK_SET);
138 ogg->page_pos = -1;
139 ogg->curidx = ost->curidx;
140 ogg->nstreams = ost->nstreams;
141 if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
142 sizeof(*ogg->streams))) < 0) {
143 ogg->nstreams = 0;
144 return err;
145 } else
146 memcpy(ogg->streams, ost->streams,
147 ost->nstreams * sizeof(*ogg->streams));
148
149 av_free(ost);
150
151 return 0;
152}
153
154static int ogg_reset(AVFormatContext *s)
155{
156 struct ogg *ogg = s->priv_data;
157 int i;
158 int64_t start_pos = avio_tell(s->pb);
159
160 for (i = 0; i < ogg->nstreams; i++) {
161 struct ogg_stream *os = ogg->streams + i;
162 os->bufpos = 0;
163 os->pstart = 0;
164 os->psize = 0;
165 os->granule = -1;
166 os->lastpts = AV_NOPTS_VALUE;
167 os->lastdts = AV_NOPTS_VALUE;
168 os->sync_pos = -1;
169 os->page_pos = 0;
170 os->nsegs = 0;
171 os->segp = 0;
172 os->incomplete = 0;
173 os->got_data = 0;
174 if (start_pos <= s->internal->data_offset) {
175 os->lastpts = 0;
176 }
177 os->end_trimming = 0;
178 av_freep(&os->new_metadata);
179 os->new_metadata_size = 0;
180 }
181
182 ogg->page_pos = -1;
183 ogg->curidx = -1;
184
185 return 0;
186}
187
188static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
189{
190 int i;
191
192 for (i = 0; ogg_codecs[i]; i++)
193 if (size >= ogg_codecs[i]->magicsize &&
194 !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
195 return ogg_codecs[i];
196
197 return NULL;
198}
199
200/**
201 * Replace the current stream with a new one. This is a typical webradio
202 * situation where a new audio stream spawn (identified with a new serial) and
203 * must replace the previous one (track switch).
204 */
205static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
206{
207 struct ogg *ogg = s->priv_data;
208 struct ogg_stream *os;
209 const struct ogg_codec *codec;
210 int i = 0;
211
212 if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
213 uint8_t magic[8];
214 int64_t pos = avio_tell(s->pb);
215 avio_skip(s->pb, nsegs);
216 avio_read(s->pb, magic, sizeof(magic));
217 avio_seek(s->pb, pos, SEEK_SET);
218 codec = ogg_find_codec(magic, sizeof(magic));
219 if (!codec) {
220 av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
221 return AVERROR_INVALIDDATA;
222 }
223 for (i = 0; i < ogg->nstreams; i++) {
224 if (ogg->streams[i].codec == codec)
225 break;
226 }
227 if (i >= ogg->nstreams)
228 return ogg_new_stream(s, serial);
229 } else if (ogg->nstreams != 1) {
230 avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
231 return AVERROR_PATCHWELCOME;
232 }
233
234 os = &ogg->streams[i];
235
236 os->serial = serial;
237 return i;
238
239#if 0
240 buf = os->buf;
241 bufsize = os->bufsize;
242 codec = os->codec;
243
244 if (!ogg->state || ogg->state->streams[i].private != os->private)
245 av_freep(&ogg->streams[i].private);
246
247 /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
248 * also re-use the ogg_stream allocated buffer */
249 memset(os, 0, sizeof(*os));
250 os->serial = serial;
251 os->bufsize = bufsize;
252 os->buf = buf;
253 os->header = -1;
254 os->codec = codec;
255
256 return i;
257#endif
258}
259
260static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
261{
262 struct ogg *ogg = s->priv_data;
263 int idx = ogg->nstreams;
264 AVStream *st;
265 struct ogg_stream *os;
266 size_t size;
267
268 if (ogg->state) {
269 av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
270 "in between Ogg context save/restore operations.\n");
271 return AVERROR_BUG;
272 }
273
274 /* Allocate and init a new Ogg Stream */
275 if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
276 !(os = av_realloc(ogg->streams, size)))
277 return AVERROR(ENOMEM);
278 ogg->streams = os;
279 os = ogg->streams + idx;
280 memset(os, 0, sizeof(*os));
281 os->serial = serial;
282 os->bufsize = DECODER_BUFFER_SIZE;
283 os->buf = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
284 os->header = -1;
285 os->start_granule = OGG_NOGRANULE_VALUE;
286 if (!os->buf)
287 return AVERROR(ENOMEM);
288
289 /* Create the associated AVStream */
290 st = avformat_new_stream(s, NULL);
291 if (!st) {
292 av_freep(&os->buf);
293 return AVERROR(ENOMEM);
294 }
295 st->id = idx;
296 avpriv_set_pts_info(st, 64, 1, 1000000);
297
298 ogg->nstreams++;
299 return idx;
300}
301
302static int ogg_new_buf(struct ogg *ogg, int idx)
303{
304 struct ogg_stream *os = ogg->streams + idx;
305 uint8_t *nb = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
306 int size = os->bufpos - os->pstart;
307
308 if (!nb)
309 return AVERROR(ENOMEM);
310
311 if (os->buf) {
312 memcpy(nb, os->buf + os->pstart, size);
313 av_free(os->buf);
314 }
315
316 os->buf = nb;
317 os->bufpos = size;
318 os->pstart = 0;
319
320 return 0;
321}
322
323static int data_packets_seen(const struct ogg *ogg)
324{
325 int i;
326
327 for (i = 0; i < ogg->nstreams; i++)
328 if (ogg->streams[i].got_data)
329 return 1;
330 return 0;
331}
332
333static int ogg_read_page(AVFormatContext *s, int *sid)
334{
335 AVIOContext *bc = s->pb;
336 struct ogg *ogg = s->priv_data;
337 struct ogg_stream *os;
338 int ret, i = 0;
339 int flags, nsegs;
340 uint64_t gp;
341 uint32_t serial;
342 int size, idx;
343 uint8_t sync[4];
344 int sp = 0;
345
346 ret = avio_read(bc, sync, 4);
347 if (ret < 4)
348 return ret < 0 ? ret : AVERROR_EOF;
349
350 do {
351 int c;
352
353 if (sync[sp & 3] == 'O' &&
354 sync[(sp + 1) & 3] == 'g' &&
355 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
356 break;
357
358 if(!i && (bc->seekable & AVIO_SEEKABLE_NORMAL) && ogg->page_pos > 0) {
359 memset(sync, 0, 4);
360 avio_seek(bc, ogg->page_pos+4, SEEK_SET);
361 ogg->page_pos = -1;
362 }
363
364 c = avio_r8(bc);
365
366 if (avio_feof(bc))
367 return AVERROR_EOF;
368
369 sync[sp++ & 3] = c;
370 } while (i++ < MAX_PAGE_SIZE);
371
372 if (i >= MAX_PAGE_SIZE) {
373 av_log(s, AV_LOG_INFO, "cannot find sync word\n");
374 return AVERROR_INVALIDDATA;
375 }
376
377 if (avio_r8(bc) != 0) { /* version */
378 av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
379 return AVERROR_INVALIDDATA;
380 }
381
382 flags = avio_r8(bc);
383 gp = avio_rl64(bc);
384 serial = avio_rl32(bc);
385 avio_skip(bc, 8); /* seq, crc */
386 nsegs = avio_r8(bc);
387
388 idx = ogg_find_stream(ogg, serial);
389 if (idx < 0) {
390 if (data_packets_seen(ogg))
391 idx = ogg_replace_stream(s, serial, nsegs);
392 else
393 idx = ogg_new_stream(s, serial);
394
395 if (idx < 0) {
396 av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
397 return idx;
398 }
399 }
400
401 os = ogg->streams + idx;
402 ogg->page_pos =
403 os->page_pos = avio_tell(bc) - 27;
404
405 if (os->psize > 0) {
406 ret = ogg_new_buf(ogg, idx);
407 if (ret < 0)
408 return ret;
409 }
410
411 ret = avio_read(bc, os->segments, nsegs);
412 if (ret < nsegs)
413 return ret < 0 ? ret : AVERROR_EOF;
414
415 os->nsegs = nsegs;
416 os->segp = 0;
417
418 size = 0;
419 for (i = 0; i < nsegs; i++)
420 size += os->segments[i];
421
422 if (!(flags & OGG_FLAG_BOS))
423 os->got_data = 1;
424
425 if (flags & OGG_FLAG_CONT || os->incomplete) {
426 if (!os->psize) {
427 // If this is the very first segment we started
428 // playback in the middle of a continuation packet.
429 // Discard it since we missed the start of it.
430 while (os->segp < os->nsegs) {
431 int seg = os->segments[os->segp++];
432 os->pstart += seg;
433 if (seg < 255)
434 break;
435 }
436 os->sync_pos = os->page_pos;
437 }
438 } else {
439 os->psize = 0;
440 os->sync_pos = os->page_pos;
441 }
442
443 if (os->bufsize - os->bufpos < size) {
444 uint8_t *nb = av_malloc((os->bufsize *= 2) + AV_INPUT_BUFFER_PADDING_SIZE);
445 if (!nb)
446 return AVERROR(ENOMEM);
447 memcpy(nb, os->buf, os->bufpos);
448 av_free(os->buf);
449 os->buf = nb;
450 }
451
452 ret = avio_read(bc, os->buf + os->bufpos, size);
453 if (ret < size)
454 return ret < 0 ? ret : AVERROR_EOF;
455
456 os->bufpos += size;
457 os->granule = gp;
458 os->flags = flags;
459
460 memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE);
461 if (sid)
462 *sid = idx;
463
464 return 0;
465}
466
467/**
468 * @brief find the next Ogg packet
469 * @param *sid is set to the stream for the packet or -1 if there is
470 * no matching stream, in that case assume all other return
471 * values to be uninitialized.
472 * @return negative value on error or EOF.
473 */
474static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
475 int64_t *fpos)
476{
477 struct ogg *ogg = s->priv_data;
478 int idx, i, ret;
479 struct ogg_stream *os;
480 int complete = 0;
481 int segp = 0, psize = 0;
482
483 av_log(s, AV_LOG_TRACE, "ogg_packet: curidx=%i\n", ogg->curidx);
484 if (sid)
485 *sid = -1;
486
487 do {
488 idx = ogg->curidx;
489
490 while (idx < 0) {
491 ret = ogg_read_page(s, &idx);
492 if (ret < 0)
493 return ret;
494 }
495
496 os = ogg->streams + idx;
497
498 av_log(s, AV_LOG_TRACE, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
499 idx, os->pstart, os->psize, os->segp, os->nsegs);
500
501 if (!os->codec) {
502 if (os->header < 0) {
503 os->codec = ogg_find_codec(os->buf, os->bufpos);
504 if (!os->codec) {
505 av_log(s, AV_LOG_WARNING, "Codec not found\n");
506 os->header = 0;
507 return 0;
508 }
509 } else {
510 return 0;
511 }
512 }
513
514 segp = os->segp;
515 psize = os->psize;
516
517 while (os->segp < os->nsegs) {
518 int ss = os->segments[os->segp++];
519 os->psize += ss;
520 if (ss < 255) {
521 complete = 1;
522 break;
523 }
524 }
525
526 if (!complete && os->segp == os->nsegs) {
527 ogg->curidx = -1;
528 // Do not set incomplete for empty packets.
529 // Together with the code in ogg_read_page
530 // that discards all continuation of empty packets
531 // we would get an infinite loop.
532 os->incomplete = !!os->psize;
533 }
534 } while (!complete);
535
536
537 if (os->granule == -1)
538 av_log(s, AV_LOG_WARNING,
539 "Page at %"PRId64" is missing granule\n",
540 os->page_pos);
541
542 ogg->curidx = idx;
543 os->incomplete = 0;
544
545 if (os->header) {
546 os->header = os->codec->header(s, idx);
547 if (!os->header) {
548 os->segp = segp;
549 os->psize = psize;
550
551 // We have reached the first non-header packet in this stream.
552 // Unfortunately more header packets may still follow for others,
553 // but if we continue with header parsing we may lose data packets.
554 ogg->headers = 1;
555
556 // Update the header state for all streams and
557 // compute the data_offset.
558 if (!s->internal->data_offset)
559 s->internal->data_offset = os->sync_pos;
560
561 for (i = 0; i < ogg->nstreams; i++) {
562 struct ogg_stream *cur_os = ogg->streams + i;
563
564 // if we have a partial non-header packet, its start is
565 // obviously at or after the data start
566 if (cur_os->incomplete)
567 s->internal->data_offset = FFMIN(s->internal->data_offset, cur_os->sync_pos);
568 }
569 } else {
570 os->nb_header++;
571 os->pstart += os->psize;
572 os->psize = 0;
573 }
574 } else {
575 os->pflags = 0;
576 os->pduration = 0;
577 if (os->codec && os->codec->packet)
578 os->codec->packet(s, idx);
579 if (sid)
580 *sid = idx;
581 if (dstart)
582 *dstart = os->pstart;
583 if (dsize)
584 *dsize = os->psize;
585 if (fpos)
586 *fpos = os->sync_pos;
587 os->pstart += os->psize;
588 os->psize = 0;
589 if(os->pstart == os->bufpos)
590 os->bufpos = os->pstart = 0;
591 os->sync_pos = os->page_pos;
592 }
593
594 // determine whether there are more complete packets in this page
595 // if not, the page's granule will apply to this packet
596 os->page_end = 1;
597 for (i = os->segp; i < os->nsegs; i++)
598 if (os->segments[i] < 255) {
599 os->page_end = 0;
600 break;
601 }
602
603 if (os->segp == os->nsegs)
604 ogg->curidx = -1;
605
606 return 0;
607}
608
609static int ogg_get_length(AVFormatContext *s)
610{
611 struct ogg *ogg = s->priv_data;
612 int i, ret;
613 int64_t size, end;
614 int streams_left=0;
615
616 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
617 return 0;
618
619// already set
620 if (s->duration != AV_NOPTS_VALUE)
621 return 0;
622
623 size = avio_size(s->pb);
624 if (size < 0)
625 return 0;
626 end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
627
628 ret = ogg_save(s);
629 if (ret < 0)
630 return ret;
631 avio_seek(s->pb, end, SEEK_SET);
632 ogg->page_pos = -1;
633
634 while (!ogg_read_page(s, &i)) {
635 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
636 ogg->streams[i].codec) {
637 s->streams[i]->duration =
638 ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
639 if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
640 s->streams[i]->duration -= s->streams[i]->start_time;
641 streams_left-= (ogg->streams[i].got_start==-1);
642 ogg->streams[i].got_start= 1;
643 } else if(!ogg->streams[i].got_start) {
644 ogg->streams[i].got_start= -1;
645 streams_left++;
646 }
647 }
648 }
649
650 ogg_restore(s);
651
652 ret = ogg_save(s);
653 if (ret < 0)
654 return ret;
655
656 avio_seek (s->pb, s->internal->data_offset, SEEK_SET);
657 ogg_reset(s);
658 while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
659 int64_t pts;
660 if (i < 0) continue;
661 pts = ogg_calc_pts(s, i, NULL);
662 if (s->streams[i]->duration == AV_NOPTS_VALUE)
663 continue;
664 if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
665 s->streams[i]->duration -= pts;
666 ogg->streams[i].got_start= 1;
667 streams_left--;
668 }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
669 ogg->streams[i].got_start= 1;
670 streams_left--;
671 }
672 }
673 ogg_restore (s);
674
675 return 0;
676}
677
678static int ogg_read_close(AVFormatContext *s)
679{
680 struct ogg *ogg = s->priv_data;
681 int i;
682
683 for (i = 0; i < ogg->nstreams; i++) {
684 free_stream(s, i);
685 }
686
687 ogg->nstreams = 0;
688
689 av_freep(&ogg->streams);
690 return 0;
691}
692
693static int ogg_read_header(AVFormatContext *s)
694{
695 struct ogg *ogg = s->priv_data;
696 int ret, i;
697
698 ogg->curidx = -1;
699
700 //linear headers seek from start
701 do {
702 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
703 if (ret < 0) {
704 ogg_read_close(s);
705 return ret;
706 }
707 } while (!ogg->headers);
708 av_log(s, AV_LOG_TRACE, "found headers\n");
709
710 for (i = 0; i < ogg->nstreams; i++) {
711 struct ogg_stream *os = ogg->streams + i;
712
713 if (ogg->streams[i].header < 0) {
714 av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
715 ogg->streams[i].codec = NULL;
716 av_freep(&ogg->streams[i].private);
717 } else if (os->codec && os->nb_header < os->codec->nb_header) {
718 av_log(s, AV_LOG_WARNING,
719 "Headers mismatch for stream %d: "
720 "expected %d received %d.\n",
721 i, os->codec->nb_header, os->nb_header);
722 if (s->error_recognition & AV_EF_EXPLODE)
723 return AVERROR_INVALIDDATA;
724 }
725 if (os->start_granule != OGG_NOGRANULE_VALUE)
726 os->lastpts = s->streams[i]->start_time =
727 ogg_gptopts(s, i, os->start_granule, NULL);
728 }
729
730 //linear granulepos seek from end
731 ret = ogg_get_length(s);
732 if (ret < 0) {
733 ogg_read_close(s);
734 return ret;
735 }
736
737 return 0;
738}
739
740static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
741{
742 struct ogg *ogg = s->priv_data;
743 struct ogg_stream *os = ogg->streams + idx;
744 int64_t pts = AV_NOPTS_VALUE;
745
746 if (dts)
747 *dts = AV_NOPTS_VALUE;
748
749 if (os->lastpts != AV_NOPTS_VALUE) {
750 pts = os->lastpts;
751 os->lastpts = AV_NOPTS_VALUE;
752 }
753 if (os->lastdts != AV_NOPTS_VALUE) {
754 if (dts)
755 *dts = os->lastdts;
756 os->lastdts = AV_NOPTS_VALUE;
757 }
758 if (os->page_end) {
759 if (os->granule != -1LL) {
760 if (os->codec && os->codec->granule_is_start)
761 pts = ogg_gptopts(s, idx, os->granule, dts);
762 else
763 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
764 os->granule = -1LL;
765 }
766 }
767 return pts;
768}
769
770static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
771{
772 struct ogg *ogg = s->priv_data;
773 struct ogg_stream *os = ogg->streams + idx;
774 int invalid = 0;
775 if (psize) {
776 switch (s->streams[idx]->codecpar->codec_id) {
777 case AV_CODEC_ID_THEORA:
778 invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40);
779 break;
780 case AV_CODEC_ID_VP8:
781 invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1);
782 }
783 if (invalid) {
784 os->pflags ^= AV_PKT_FLAG_KEY;
785 av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
786 (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
787 }
788 }
789}
790
791static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
792{
793 struct ogg *ogg;
794 struct ogg_stream *os;
795 int idx, ret;
796 int pstart, psize;
797 int64_t fpos, pts, dts;
798
799 if (s->io_repositioned) {
800 ogg_reset(s);
801 s->io_repositioned = 0;
802 }
803
804 //Get an ogg packet
805retry:
806 do {
807 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
808 if (ret < 0)
809 return ret;
810 } while (idx < 0 || !s->streams[idx]);
811
812 ogg = s->priv_data;
813 os = ogg->streams + idx;
814
815 // pflags might not be set until after this
816 pts = ogg_calc_pts(s, idx, &dts);
817 ogg_validate_keyframe(s, idx, pstart, psize);
818
819 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
820 goto retry;
821 os->keyframe_seek = 0;
822
823 //Alloc a pkt
824 ret = av_new_packet(pkt, psize);
825 if (ret < 0)
826 return ret;
827 pkt->stream_index = idx;
828 memcpy(pkt->data, os->buf + pstart, psize);
829
830 pkt->pts = pts;
831 pkt->dts = dts;
832 pkt->flags = os->pflags;
833 pkt->duration = os->pduration;
834 pkt->pos = fpos;
835
836 if (os->end_trimming) {
837 uint8_t *side_data = av_packet_new_side_data(pkt,
838 AV_PKT_DATA_SKIP_SAMPLES,
839 10);
840 if(!side_data)
841 goto fail;
842 AV_WL32(side_data + 4, os->end_trimming);
843 os->end_trimming = 0;
844 }
845
846 if (os->new_metadata) {
847 uint8_t *side_data = av_packet_new_side_data(pkt,
848 AV_PKT_DATA_METADATA_UPDATE,
849 os->new_metadata_size);
850 if(!side_data)
851 goto fail;
852
853 memcpy(side_data, os->new_metadata, os->new_metadata_size);
854 av_freep(&os->new_metadata);
855 os->new_metadata_size = 0;
856 }
857
858 return psize;
859fail:
860 av_packet_unref(pkt);
861 return AVERROR(ENOMEM);
862}
863
864static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
865 int64_t *pos_arg, int64_t pos_limit)
866{
867 struct ogg *ogg = s->priv_data;
868 AVIOContext *bc = s->pb;
869 int64_t pts = AV_NOPTS_VALUE;
870 int64_t keypos = -1;
871 int i;
872 int pstart, psize;
873 avio_seek(bc, *pos_arg, SEEK_SET);
874 ogg_reset(s);
875
876 while ( avio_tell(bc) <= pos_limit
877 && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
878 if (i == stream_index) {
879 struct ogg_stream *os = ogg->streams + stream_index;
880 // Do not trust the last timestamps of an ogm video
881 if ( (os->flags & OGG_FLAG_EOS)
882 && !(os->flags & OGG_FLAG_BOS)
883 && os->codec == &ff_ogm_video_codec)
884 continue;
885 pts = ogg_calc_pts(s, i, NULL);
886 ogg_validate_keyframe(s, i, pstart, psize);
887 if (os->pflags & AV_PKT_FLAG_KEY) {
888 keypos = *pos_arg;
889 } else if (os->keyframe_seek) {
890 // if we had a previous keyframe but no pts for it,
891 // return that keyframe with this pts value.
892 if (keypos >= 0)
893 *pos_arg = keypos;
894 else
895 pts = AV_NOPTS_VALUE;
896 }
897 }
898 if (pts != AV_NOPTS_VALUE)
899 break;
900 }
901 ogg_reset(s);
902 return pts;
903}
904
905static int ogg_read_seek(AVFormatContext *s, int stream_index,
906 int64_t timestamp, int flags)
907{
908 struct ogg *ogg = s->priv_data;
909 struct ogg_stream *os = ogg->streams + stream_index;
910 int ret;
911
912 av_assert0(stream_index < ogg->nstreams);
913 // Ensure everything is reset even when seeking via
914 // the generated index.
915 ogg_reset(s);
916
917 // Try seeking to a keyframe first. If this fails (very possible),
918 // av_seek_frame will fall back to ignoring keyframes
919 if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
920 && !(flags & AVSEEK_FLAG_ANY))
921 os->keyframe_seek = 1;
922
923 ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
924 ogg_reset(s);
925 os = ogg->streams + stream_index;
926 if (ret < 0)
927 os->keyframe_seek = 0;
928 return ret;
929}
930
931static int ogg_probe(AVProbeData *p)
932{
933 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
934 return AVPROBE_SCORE_MAX;
935 return 0;
936}
937
938AVInputFormat ff_ogg_demuxer = {
939 .name = "ogg",
940 .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
941 .priv_data_size = sizeof(struct ogg),
942 .read_probe = ogg_probe,
943 .read_header = ogg_read_header,
944 .read_packet = ogg_read_packet,
945 .read_close = ogg_read_close,
946 .read_seek = ogg_read_seek,
947 .read_timestamp = ogg_read_timestamp,
948 .extensions = "ogg",
949 .flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT | AVFMT_NOBINSEARCH,
950};
951