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