oggdec: add support for VP8 demuxing
[libav.git] / libavformat / oggdec.c
CommitLineData
9146ca37
MR
1/*
2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
9146ca37
MR
5 */
6
e873c03a 7/*
9146ca37
MR
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.
e873c03a 29 */
9146ca37
MR
30
31
32#include <stdio.h>
a0ddef24 33#include "oggdec.h"
9146ca37 34#include "avformat.h"
a2faa951 35#include "internal.h"
66061a12 36#include "vorbiscomment.h"
9146ca37
MR
37
38#define MAX_PAGE_SIZE 65307
39#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40
77be08ee 41static const struct ogg_codec * const ogg_codecs[] = {
32ad8692 42 &ff_skeleton_codec,
24ca518b 43 &ff_dirac_codec,
547ea47d
RD
44 &ff_speex_codec,
45 &ff_vorbis_codec,
46 &ff_theora_codec,
47 &ff_flac_codec,
4ca59d19 48 &ff_celt_codec,
ecab1c77 49 &ff_opus_codec,
430a8168 50 &ff_vp8_codec,
24ca518b 51 &ff_old_dirac_codec,
547ea47d
RD
52 &ff_old_flac_codec,
53 &ff_ogm_video_codec,
54 &ff_ogm_audio_codec,
55 &ff_ogm_text_codec,
56 &ff_ogm_old_codec,
9146ca37
MR
57 NULL
58};
59
9146ca37 60//FIXME We could avoid some structure duplication
e575685f 61static int ogg_save(AVFormatContext *s)
9146ca37 62{
77be08ee
MR
63 struct ogg *ogg = s->priv_data;
64 struct ogg_state *ost =
f5f1cf52 65 av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
9146ca37 66 int i;
f5f1cf52
LB
67 ost->pos = avio_tell(s->pb);
68 ost->curidx = ogg->curidx;
69 ost->next = ogg->state;
20be72c8 70 ost->nstreams = ogg->nstreams;
9146ca37
MR
71 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
72
f5f1cf52 73 for (i = 0; i < ogg->nstreams; i++) {
77be08ee 74 struct ogg_stream *os = ogg->streams + i;
f5f1cf52
LB
75 os->buf = av_mallocz(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
76 memcpy(os->buf, ost->streams[i].buf, os->bufpos);
9146ca37
MR
77 }
78
79 ogg->state = ost;
80
81 return 0;
82}
83
e575685f 84static int ogg_restore(AVFormatContext *s, int discard)
9146ca37 85{
77be08ee 86 struct ogg *ogg = s->priv_data;
ae628ec1 87 AVIOContext *bc = s->pb;
77be08ee 88 struct ogg_state *ost = ogg->state;
f369b935 89 int i, err;
9146ca37
MR
90
91 if (!ost)
92 return 0;
93
94 ogg->state = ost->next;
95
f5f1cf52 96 if (!discard) {
0e7efb9d 97
9146ca37 98 for (i = 0; i < ogg->nstreams; i++)
f5f1cf52 99 av_free(ogg->streams[i].buf);
9146ca37 100
f5f1cf52
LB
101 avio_seek(bc, ost->pos, SEEK_SET);
102 ogg->curidx = ost->curidx;
20be72c8 103 ogg->nstreams = ost->nstreams;
f369b935
AK
104 if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
105 sizeof(*ogg->streams))) < 0) {
106 ogg->nstreams = 0;
107 return err;
108 } else
0e7efb9d
LA
109 memcpy(ogg->streams, ost->streams,
110 ost->nstreams * sizeof(*ogg->streams));
9146ca37
MR
111 }
112
f5f1cf52 113 av_free(ost);
9146ca37
MR
114
115 return 0;
116}
117
e575685f 118static int ogg_reset(struct ogg *ogg)
9146ca37
MR
119{
120 int i;
121
f5f1cf52 122 for (i = 0; i < ogg->nstreams; i++) {
77be08ee 123 struct ogg_stream *os = ogg->streams + i;
f5f1cf52
LB
124 os->bufpos = 0;
125 os->pstart = 0;
126 os->psize = 0;
127 os->granule = -1;
128 os->lastpts = AV_NOPTS_VALUE;
129 os->lastdts = AV_NOPTS_VALUE;
130 os->sync_pos = -1;
131 os->page_pos = 0;
132 os->nsegs = 0;
133 os->segp = 0;
ecc0027b 134 os->incomplete = 0;
9146ca37
MR
135 }
136
137 ogg->curidx = -1;
138
139 return 0;
140}
141
e575685f 142static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
9146ca37
MR
143{
144 int i;
145
146 for (i = 0; ogg_codecs[i]; i++)
147 if (size >= ogg_codecs[i]->magicsize &&
f5f1cf52 148 !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
9146ca37
MR
149 return ogg_codecs[i];
150
151 return NULL;
152}
153
e575685f 154static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
9146ca37 155{
77be08ee 156 struct ogg *ogg = s->priv_data;
f5f1cf52 157 int idx = ogg->nstreams++;
9146ca37 158 AVStream *st;
77be08ee 159 struct ogg_stream *os;
9146ca37 160
ba064ebe
LB
161 os = av_realloc(ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
162
163 if (!os)
164 return AVERROR(ENOMEM);
165
166 ogg->streams = os;
167
f5f1cf52
LB
168 memset(ogg->streams + idx, 0, sizeof(*ogg->streams));
169
170 os = ogg->streams + idx;
171 os->serial = serial;
172 os->bufsize = DECODER_BUFFER_SIZE;
173 os->buf = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
174 os->header = -1;
d1f05dd1 175 os->start_granule = OGG_NOGRANULE_VALUE;
9146ca37 176
5780f41a 177 if (new_avstream) {
84ad31ff 178 st = avformat_new_stream(s, NULL);
5780f41a
CB
179 if (!st)
180 return AVERROR(ENOMEM);
9146ca37 181
84ad31ff 182 st->id = idx;
c3f9ebf7 183 avpriv_set_pts_info(st, 64, 1, 1000000);
5780f41a 184 }
9146ca37
MR
185
186 return idx;
187}
188
e575685f 189static int ogg_new_buf(struct ogg *ogg, int idx)
12a195e3 190{
77be08ee 191 struct ogg_stream *os = ogg->streams + idx;
ef0d7797 192 uint8_t *nb = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
12a195e3 193 int size = os->bufpos - os->pstart;
f5f1cf52
LB
194
195 if (os->buf) {
12a195e3
MR
196 memcpy(nb, os->buf + os->pstart, size);
197 av_free(os->buf);
198 }
f5f1cf52
LB
199
200 os->buf = nb;
12a195e3
MR
201 os->bufpos = size;
202 os->pstart = 0;
203
204 return 0;
205}
206
e575685f 207static int ogg_read_page(AVFormatContext *s, int *str)
9146ca37 208{
ae628ec1 209 AVIOContext *bc = s->pb;
77be08ee
MR
210 struct ogg *ogg = s->priv_data;
211 struct ogg_stream *os;
9cec1bbd 212 int ret, i = 0;
9146ca37
MR
213 int flags, nsegs;
214 uint64_t gp;
215 uint32_t serial;
9146ca37 216 int size, idx;
191e8ca7 217 uint8_t sync[4];
9146ca37
MR
218 int sp = 0;
219
9cec1bbd
NG
220 ret = avio_read(bc, sync, 4);
221 if (ret < 4)
222 return ret < 0 ? ret : AVERROR_EOF;
9146ca37 223
f5f1cf52 224 do {
9146ca37
MR
225 int c;
226
227 if (sync[sp & 3] == 'O' &&
228 sync[(sp + 1) & 3] == 'g' &&
229 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
230 break;
231
e5197539 232 c = avio_r8(bc);
f5f1cf52 233
66e5b1df 234 if (bc->eof_reached)
9cec1bbd 235 return AVERROR_EOF;
f5f1cf52 236
9146ca37 237 sync[sp++ & 3] = c;
f5f1cf52 238 } while (i++ < MAX_PAGE_SIZE);
9146ca37 239
f5f1cf52
LB
240 if (i >= MAX_PAGE_SIZE) {
241 av_log(s, AV_LOG_INFO, "cannot find sync word\n");
9cec1bbd 242 return AVERROR_INVALIDDATA;
9146ca37
MR
243 }
244
e5197539 245 if (avio_r8(bc) != 0) /* version */
9cec1bbd 246 return AVERROR_INVALIDDATA;
9146ca37 247
f5f1cf52
LB
248 flags = avio_r8(bc);
249 gp = avio_rl64(bc);
250 serial = avio_rl32(bc);
e65ab9d9 251 avio_skip(bc, 8); /* seq, crc */
f5f1cf52 252 nsegs = avio_r8(bc);
9146ca37 253
f5f1cf52
LB
254 idx = ogg_find_stream(ogg, serial);
255 if (idx < 0) {
8f3eebd6 256 if (ogg->headers) {
dc713546
CB
257 int n;
258
259 for (n = 0; n < ogg->nstreams; n++) {
260 av_freep(&ogg->streams[n].buf);
f5f1cf52
LB
261 if (!ogg->state ||
262 ogg->state->streams[n].private != ogg->streams[n].private)
9ed6cbc3 263 av_freep(&ogg->streams[n].private);
dc713546 264 }
f5f1cf52 265
dc713546
CB
266 ogg->curidx = -1;
267 ogg->nstreams = 0;
f5f1cf52 268
5780f41a
CB
269 idx = ogg_new_stream(s, serial, 0);
270 } else {
271 idx = ogg_new_stream(s, serial, 1);
47dec30e 272 }
9146ca37 273 if (idx < 0)
9cec1bbd 274 return idx;
9146ca37
MR
275 }
276
277 os = ogg->streams + idx;
a2704c97 278 os->page_pos = avio_tell(bc) - 27;
9146ca37 279
f5f1cf52 280 if (os->psize > 0)
12a195e3
MR
281 ogg_new_buf(ogg, idx);
282
9cec1bbd
NG
283 ret = avio_read(bc, os->segments, nsegs);
284 if (ret < nsegs)
285 return ret < 0 ? ret : AVERROR_EOF;
9146ca37
MR
286
287 os->nsegs = nsegs;
f5f1cf52 288 os->segp = 0;
9146ca37
MR
289
290 size = 0;
291 for (i = 0; i < nsegs; i++)
292 size += os->segments[i];
293
f5f1cf52
LB
294 if (flags & OGG_FLAG_CONT || os->incomplete) {
295 if (!os->psize) {
296 while (os->segp < os->nsegs) {
9146ca37
MR
297 int seg = os->segments[os->segp++];
298 os->pstart += seg;
299 if (seg < 255)
bad4a6bb 300 break;
9146ca37 301 }
73823cb9 302 os->sync_pos = os->page_pos;
9146ca37 303 }
f5f1cf52
LB
304 } else {
305 os->psize = 0;
73823cb9 306 os->sync_pos = os->page_pos;
9146ca37
MR
307 }
308
f5f1cf52
LB
309 if (os->bufsize - os->bufpos < size) {
310 uint8_t *nb = av_malloc((os->bufsize *= 2) + FF_INPUT_BUFFER_PADDING_SIZE);
ba064ebe
LB
311 if (!nb)
312 return AVERROR(ENOMEM);
f5f1cf52
LB
313 memcpy(nb, os->buf, os->bufpos);
314 av_free(os->buf);
9146ca37
MR
315 os->buf = nb;
316 }
317
9cec1bbd
NG
318 ret = avio_read(bc, os->buf + os->bufpos, size);
319 if (ret < size)
320 return ret < 0 ? ret : AVERROR_EOF;
9146ca37 321
9146ca37
MR
322 os->bufpos += size;
323 os->granule = gp;
f5f1cf52 324 os->flags = flags;
9146ca37 325
ef0d7797 326 memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
9146ca37
MR
327 if (str)
328 *str = idx;
329
330 return 0;
331}
332
e575685f
CB
333static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
334 int64_t *fpos)
9146ca37 335{
77be08ee 336 struct ogg *ogg = s->priv_data;
9cec1bbd 337 int idx, i, ret;
77be08ee 338 struct ogg_stream *os;
9146ca37 339 int complete = 0;
f5f1cf52 340 int segp = 0, psize = 0;
9146ca37 341
b751f611 342 av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
9146ca37 343
f5f1cf52 344 do {
9146ca37
MR
345 idx = ogg->curidx;
346
f5f1cf52 347 while (idx < 0) {
9cec1bbd
NG
348 ret = ogg_read_page(s, &idx);
349 if (ret < 0)
350 return ret;
9146ca37
MR
351 }
352
353 os = ogg->streams + idx;
354
b751f611 355 av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
9146ca37 356 idx, os->pstart, os->psize, os->segp, os->nsegs);
9146ca37 357
f5f1cf52
LB
358 if (!os->codec) {
359 if (os->header < 0) {
360 os->codec = ogg_find_codec(os->buf, os->bufpos);
361 if (!os->codec) {
9cec1bbd 362 av_log(s, AV_LOG_WARNING, "Codec not found\n");
9146ca37
MR
363 os->header = 0;
364 return 0;
365 }
f5f1cf52 366 } else {
9146ca37
MR
367 return 0;
368 }
369 }
370
f5f1cf52 371 segp = os->segp;
9146ca37
MR
372 psize = os->psize;
373
f5f1cf52 374 while (os->segp < os->nsegs) {
9146ca37
MR
375 int ss = os->segments[os->segp++];
376 os->psize += ss;
f5f1cf52 377 if (ss < 255) {
9146ca37
MR
378 complete = 1;
379 break;
380 }
381 }
382
f5f1cf52
LB
383 if (!complete && os->segp == os->nsegs) {
384 ogg->curidx = -1;
9a27acae
RD
385 // Do not set incomplete for empty packets.
386 // Together with the code in ogg_read_page
387 // that discards all continuation of empty packets
388 // we would get an infinite loop.
389 os->incomplete = !!os->psize;
9146ca37 390 }
f5f1cf52 391 } while (!complete);
9146ca37 392
b751f611 393 av_dlog(s, "ogg_packet: idx %i, frame size %i, start %i\n",
9146ca37 394 idx, os->psize, os->pstart);
9146ca37 395
adc725b5 396 if (os->granule == -1)
f5f1cf52
LB
397 av_log(s, AV_LOG_WARNING,
398 "Page at %"PRId64" is missing granule\n",
399 os->page_pos);
adc725b5 400
f5f1cf52 401 ogg->curidx = idx;
ecc0027b 402 os->incomplete = 0;
9146ca37 403
81b743eb 404 if (os->header) {
f5f1cf52
LB
405 os->header = os->codec->header(s, idx);
406 if (!os->header) {
407 os->segp = segp;
bad4a6bb 408 os->psize = psize;
365d8e47 409
6bd69e6a
RD
410 // We have reached the first non-header packet in this stream.
411 // Unfortunately more header packets may still follow for others,
0a94020b 412 // but if we continue with header parsing we may lose data packets.
bad4a6bb 413 ogg->headers = 1;
365d8e47
AC
414
415 // Update the header state for all streams and
416 // compute the data_offset.
6bd69e6a
RD
417 if (!s->data_offset)
418 s->data_offset = os->sync_pos;
f5f1cf52 419
365d8e47
AC
420 for (i = 0; i < ogg->nstreams; i++) {
421 struct ogg_stream *cur_os = ogg->streams + i;
365d8e47
AC
422
423 // if we have a partial non-header packet, its start is
424 // obviously at or after the data start
425 if (cur_os->incomplete)
426 s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
427 }
f5f1cf52 428 } else {
7751e469 429 os->nb_header++;
bad4a6bb 430 os->pstart += os->psize;
f5f1cf52 431 os->psize = 0;
9146ca37 432 }
81b743eb 433 } else {
f5f1cf52 434 os->pflags = 0;
15299b38 435 os->pduration = 0;
9146ca37 436 if (os->codec && os->codec->packet)
f5f1cf52 437 os->codec->packet(s, idx);
9146ca37
MR
438 if (str)
439 *str = idx;
12a195e3
MR
440 if (dstart)
441 *dstart = os->pstart;
442 if (dsize)
443 *dsize = os->psize;
73823cb9
DC
444 if (fpos)
445 *fpos = os->sync_pos;
f5f1cf52
LB
446 os->pstart += os->psize;
447 os->psize = 0;
73823cb9 448 os->sync_pos = os->page_pos;
9146ca37
MR
449 }
450
5e15c7d9
DC
451 // determine whether there are more complete packets in this page
452 // if not, the page's granule will apply to this packet
453 os->page_end = 1;
454 for (i = os->segp; i < os->nsegs; i++)
455 if (os->segments[i] < 255) {
456 os->page_end = 0;
457 break;
458 }
459
9146ca37
MR
460 if (os->segp == os->nsegs)
461 ogg->curidx = -1;
462
463 return 0;
464}
465
e575685f 466static int ogg_get_headers(AVFormatContext *s)
9146ca37 467{
77be08ee 468 struct ogg *ogg = s->priv_data;
7751e469 469 int ret, i;
9146ca37 470
f5f1cf52 471 do {
9cec1bbd
NG
472 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
473 if (ret < 0)
474 return ret;
f5f1cf52 475 } while (!ogg->headers);
9146ca37 476
7751e469
LB
477 for (i = 0; i < ogg->nstreams; i++) {
478 struct ogg_stream *os = ogg->streams + i;
479
480 if (os->codec && os->codec->nb_header &&
481 os->nb_header < os->codec->nb_header) {
482 av_log(s, AV_LOG_ERROR,
f963f701
LB
483 "Headers mismatch for stream %d: "
484 "expected %d received %d.\n",
485 i, os->codec->nb_header, os->nb_header);
486 if (s->error_recognition & AV_EF_EXPLODE)
487 return AVERROR_INVALIDDATA;
7751e469 488 }
d1f05dd1
LB
489 if (os->start_granule != OGG_NOGRANULE_VALUE)
490 os->lastpts = s->streams[i]->start_time =
491 ogg_gptopts(s, i, os->start_granule, NULL);
7751e469 492 }
b751f611 493 av_dlog(s, "found headers\n");
9146ca37
MR
494
495 return 0;
496}
497
e575685f 498static int ogg_get_length(AVFormatContext *s)
9146ca37 499{
77be08ee 500 struct ogg *ogg = s->priv_data;
44a088ea 501 int i;
bc5c918e 502 int64_t size, end;
69599eea 503
f5f1cf52 504 if (!s->pb->seekable)
69599eea 505 return 0;
9146ca37
MR
506
507// already set
508 if (s->duration != AV_NOPTS_VALUE)
509 return 0;
510
76aa876e 511 size = avio_size(s->pb);
f5f1cf52 512 if (size < 0)
56466d7b 513 return 0;
f5f1cf52 514 end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
56466d7b 515
f5f1cf52
LB
516 ogg_save(s);
517 avio_seek(s->pb, end, SEEK_SET);
9146ca37 518
f5f1cf52 519 while (!ogg_read_page(s, &i)) {
e22f2aaf 520 if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
44a088ea
DC
521 ogg->streams[i].codec) {
522 s->streams[i]->duration =
f5f1cf52 523 ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
44a088ea
DC
524 if (s->streams[i]->start_time != AV_NOPTS_VALUE)
525 s->streams[i]->duration -= s->streams[i]->start_time;
526 }
9146ca37
MR
527 }
528
f5f1cf52 529 ogg_restore(s, 0);
9146ca37
MR
530
531 return 0;
532}
533
89b51b57
LB
534static int ogg_read_close(AVFormatContext *s)
535{
536 struct ogg *ogg = s->priv_data;
537 int i;
538
539 for (i = 0; i < ogg->nstreams; i++) {
540 av_free(ogg->streams[i].buf);
d894f747
LB
541 if (ogg->streams[i].codec &&
542 ogg->streams[i].codec->cleanup) {
543 ogg->streams[i].codec->cleanup(s, i);
544 }
89b51b57
LB
545 av_free(ogg->streams[i].private);
546 }
547 av_free(ogg->streams);
548 return 0;
549}
550
6e9651d1 551static int ogg_read_header(AVFormatContext *s)
9146ca37 552{
77be08ee 553 struct ogg *ogg = s->priv_data;
9cec1bbd 554 int ret, i;
9146ca37
MR
555 ogg->curidx = -1;
556 //linear headers seek from start
9cec1bbd 557 ret = ogg_get_headers(s);
89b51b57
LB
558 if (ret < 0) {
559 ogg_read_close(s);
9cec1bbd 560 return ret;
89b51b57 561 }
9146ca37 562
c9da676d
RD
563 for (i = 0; i < ogg->nstreams; i++)
564 if (ogg->streams[i].header < 0)
565 ogg->streams[i].codec = NULL;
566
9146ca37 567 //linear granulepos seek from end
f5f1cf52 568 ogg_get_length(s);
9146ca37
MR
569
570 //fill the extradata in the per codec callbacks
571 return 0;
572}
573
6abaa272
DC
574static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
575{
f5f1cf52 576 struct ogg *ogg = s->priv_data;
6abaa272 577 struct ogg_stream *os = ogg->streams + idx;
f5f1cf52 578 int64_t pts = AV_NOPTS_VALUE;
6abaa272
DC
579
580 if (dts)
581 *dts = AV_NOPTS_VALUE;
582
583 if (os->lastpts != AV_NOPTS_VALUE) {
f5f1cf52 584 pts = os->lastpts;
6abaa272
DC
585 os->lastpts = AV_NOPTS_VALUE;
586 }
587 if (os->lastdts != AV_NOPTS_VALUE) {
588 if (dts)
589 *dts = os->lastdts;
590 os->lastdts = AV_NOPTS_VALUE;
591 }
592 if (os->page_end) {
593 if (os->granule != -1LL) {
594 if (os->codec && os->codec->granule_is_start)
595 pts = ogg_gptopts(s, idx, os->granule, dts);
596 else
597 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
598 os->granule = -1LL;
adc725b5 599 }
6abaa272
DC
600 }
601 return pts;
602}
9146ca37 603
e575685f 604static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
9146ca37 605{
77be08ee
MR
606 struct ogg *ogg;
607 struct ogg_stream *os;
9cec1bbd 608 int idx = -1, ret;
12a195e3 609 int pstart, psize;
d8b91fae 610 int64_t fpos, pts, dts;
9146ca37 611
115329f1 612 //Get an ogg packet
d8b91fae 613retry:
f5f1cf52 614 do {
9cec1bbd
NG
615 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
616 if (ret < 0)
617 return ret;
f5f1cf52 618 } while (idx < 0 || !s->streams[idx]);
9146ca37
MR
619
620 ogg = s->priv_data;
f5f1cf52 621 os = ogg->streams + idx;
9146ca37 622
d8b91fae
DC
623 // pflags might not be set until after this
624 pts = ogg_calc_pts(s, idx, &dts);
625
cc947f04 626 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
d8b91fae
DC
627 goto retry;
628 os->keyframe_seek = 0;
629
9146ca37 630 //Alloc a pkt
9cec1bbd
NG
631 ret = av_new_packet(pkt, psize);
632 if (ret < 0)
633 return ret;
9146ca37 634 pkt->stream_index = idx;
f5f1cf52 635 memcpy(pkt->data, os->buf + pstart, psize);
5e15c7d9 636
f5f1cf52
LB
637 pkt->pts = pts;
638 pkt->dts = dts;
639 pkt->flags = os->pflags;
15299b38 640 pkt->duration = os->pduration;
f5f1cf52 641 pkt->pos = fpos;
e1a794b2 642
12a195e3 643 return psize;
9146ca37
MR
644}
645
e575685f
CB
646static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
647 int64_t *pos_arg, int64_t pos_limit)
9146ca37 648{
77be08ee 649 struct ogg *ogg = s->priv_data;
ae628ec1 650 AVIOContext *bc = s->pb;
f5f1cf52
LB
651 int64_t pts = AV_NOPTS_VALUE;
652 int i = -1;
6b4aa5da 653 avio_seek(bc, *pos_arg, SEEK_SET);
873d117e
DC
654 ogg_reset(ogg);
655
f5f1cf52
LB
656 while (avio_tell(bc) < pos_limit &&
657 !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
873d117e 658 if (i == stream_index) {
4cc3467e 659 struct ogg_stream *os = ogg->streams + stream_index;
873d117e 660 pts = ogg_calc_pts(s, i, NULL);
cc947f04 661 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
d8b91fae 662 pts = AV_NOPTS_VALUE;
a1f29b95 663 }
873d117e
DC
664 if (pts != AV_NOPTS_VALUE)
665 break;
a1f29b95
RD
666 }
667 ogg_reset(ogg);
668 return pts;
9146ca37 669}
9146ca37 670
e575685f
CB
671static int ogg_read_seek(AVFormatContext *s, int stream_index,
672 int64_t timestamp, int flags)
d8b91fae 673{
f5f1cf52 674 struct ogg *ogg = s->priv_data;
d8b91fae
DC
675 struct ogg_stream *os = ogg->streams + stream_index;
676 int ret;
677
678 // Try seeking to a keyframe first. If this fails (very possible),
679 // av_seek_frame will fall back to ignoring keyframes
72415b2a 680 if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
d8b91fae
DC
681 && !(flags & AVSEEK_FLAG_ANY))
682 os->keyframe_seek = 1;
683
a2faa951 684 ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
f5f1cf52 685 os = ogg->streams + stream_index;
d8b91fae
DC
686 if (ret < 0)
687 os->keyframe_seek = 0;
688 return ret;
689}
690
2e70e4aa
MR
691static int ogg_probe(AVProbeData *p)
692{
f95257d2 693 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
2e70e4aa 694 return AVPROBE_SCORE_MAX;
f95257d2 695 return 0;
2e70e4aa
MR
696}
697
c6610a21 698AVInputFormat ff_ogg_demuxer = {
b3bbc6fd
CB
699 .name = "ogg",
700 .long_name = NULL_IF_CONFIG_SMALL("Ogg"),
701 .priv_data_size = sizeof(struct ogg),
702 .read_probe = ogg_probe,
703 .read_header = ogg_read_header,
704 .read_packet = ogg_read_packet,
705 .read_close = ogg_read_close,
706 .read_seek = ogg_read_seek,
707 .read_timestamp = ogg_read_timestamp,
708 .extensions = "ogg",
8ad3267c 709 .flags = AVFMT_GENERIC_INDEX | AVFMT_NOBINSEARCH,
9146ca37 710};