oggdec.c 25.3 KB
Newer Older
1 2 3 4 5 6
/*
 * Ogg bitstream support
 * Luca Barbato <lu_zero@gentoo.org>
 * Based on tcvp implementation
 */

7
/*
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
    Copyright (C) 2005  Michael Ahlberg, Måns Rullgård

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use, copy,
    modify, merge, publish, distribute, sublicense, and/or sell copies
    of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    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 40 41

#define MAX_PAGE_SIZE 65307
#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE

42
static const struct ogg_codec * const ogg_codecs[] = {
43
    &ff_skeleton_codec,
44
    &ff_dirac_codec,
45 46 47 48
    &ff_speex_codec,
    &ff_vorbis_codec,
    &ff_theora_codec,
    &ff_flac_codec,
49
    &ff_celt_codec,
50
    &ff_opus_codec,
51
    &ff_vp8_codec,
52
    &ff_old_dirac_codec,
53 54 55 56 57
    &ff_old_flac_codec,
    &ff_ogm_video_codec,
    &ff_ogm_audio_codec,
    &ff_ogm_text_codec,
    &ff_ogm_old_codec,
58 59 60
    NULL
};

61
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
62
static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
63

64
//FIXME We could avoid some structure duplication
65
static int ogg_save(AVFormatContext *s)
66
{
67 68
    struct ogg *ogg = s->priv_data;
    struct ogg_state *ost =
69
        av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
70
    int i;
71 72 73
    ost->pos      = avio_tell(s->pb);
    ost->curidx   = ogg->curidx;
    ost->next     = ogg->state;
74
    ost->nstreams = ogg->nstreams;
75 76
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));

77
    for (i = 0; i < ogg->nstreams; i++) {
78
        struct ogg_stream *os = ogg->streams + i;
79 80
        os->buf = av_mallocz(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
        memcpy(os->buf, ost->streams[i].buf, os->bufpos);
81 82
        os->new_metadata      = NULL;
        os->new_metadata_size = 0;
83 84 85 86 87 88 89
    }

    ogg->state = ost;

    return 0;
}

90
static 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 98 99 100 101

    if (!ost)
        return 0;

    ogg->state = ost->next;

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 112 113 114 115
        if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
                                     sizeof(*ogg->streams))) < 0) {
            ogg->nstreams = 0;
            return err;
        } else
116 117
            memcpy(ogg->streams, ost->streams,
                   ost->nstreams * sizeof(*ogg->streams));
118 119
    }

120
    av_free(ost);
121 122 123 124

    return 0;
}

125
static 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 134 135 136 137 138 139 140 141 142
        os->bufpos     = 0;
        os->pstart     = 0;
        os->psize      = 0;
        os->granule    = -1;
        os->lastpts    = AV_NOPTS_VALUE;
        os->lastdts    = AV_NOPTS_VALUE;
        os->sync_pos   = -1;
        os->page_pos   = 0;
        os->nsegs      = 0;
        os->segp       = 0;
143
        os->incomplete = 0;
144
        os->got_data = 0;
145 146 147
        if (start_pos <= s->data_offset) {
            os->lastpts = 0;
        }
148
        os->end_trimming = 0;
149 150
        av_freep(&os->new_metadata);
        os->new_metadata_size = 0;
151 152
    }

153
    ogg->page_pos = -1;
154 155 156 157 158
    ogg->curidx = -1;

    return 0;
}

159
static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
160 161 162 163 164
{
    int i;

    for (i = 0; ogg_codecs[i]; i++)
        if (size >= ogg_codecs[i]->magicsize &&
165
            !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
166 167 168 169 170
            return ogg_codecs[i];

    return NULL;
}

171 172 173 174 175
/**
 * Replace the current stream with a new one. This is a typical webradio
 * situation where a new audio stream spawn (identified with a new serial) and
 * must replace the previous one (track switch).
 */
176
static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
177
{
178 179
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os;
180
    const struct ogg_codec *codec;
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
    int i = 0;

    if (s->pb->seekable) {
        uint8_t magic[8];
        int64_t pos = avio_tell(s->pb);
        avio_skip(s->pb, nsegs);
        avio_read(s->pb, magic, sizeof(magic));
        avio_seek(s->pb, pos, SEEK_SET);
        codec = ogg_find_codec(magic, sizeof(magic));
        if (!codec) {
            av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
            return AVERROR_INVALIDDATA;
        }
        for (i = 0; i < ogg->nstreams; i++) {
            if (ogg->streams[i].codec == codec)
                break;
        }
        if (i >= ogg->nstreams)
            return ogg_new_stream(s, serial);
    } else if (ogg->nstreams != 1) {
201
        avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
202 203 204
        return AVERROR_PATCHWELCOME;
    }

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 216
    if (!ogg->state || ogg->state->streams[i].private != os->private)
        av_freep(&ogg->streams[i].private);
217 218 219 220

    /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We
     * also re-use the ogg_stream allocated buffer */
    memset(os, 0, sizeof(*os));
221
    os->serial  = serial;
222
    os->bufsize = bufsize;
223 224 225
    os->buf     = buf;
    os->header  = -1;
    os->codec   = codec;
226

227
    return i;
228
#endif
229
}
230

231 232
static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
{
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 240 241 242 243 244
    if (ogg->state) {
        av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
               "in between Ogg context save/restore operations.\n");
        return AVERROR_BUG;
    }

245
    /* Allocate and init a new Ogg Stream */
246 247 248
    if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
        !(os = av_realloc(ogg->streams, size)))
        return AVERROR(ENOMEM);
249 250
    ogg->streams = os;
    os           = ogg->streams + idx;
251
    memset(os, 0, sizeof(*os));
252 253 254 255
    os->serial        = serial;
    os->bufsize       = DECODER_BUFFER_SIZE;
    os->buf           = av_malloc(os->bufsize + FF_INPUT_BUFFER_PADDING_SIZE);
    os->header        = -1;
256
    os->start_granule = OGG_NOGRANULE_VALUE;
257 258
    if (!os->buf)
        return AVERROR(ENOMEM);
259

260 261 262 263 264 265 266 267
    /* Create the associated AVStream */
    st = avformat_new_stream(s, NULL);
    if (!st) {
        av_freep(&os->buf);
        return AVERROR(ENOMEM);
    }
    st->id = idx;
    avpriv_set_pts_info(st, 64, 1, 1000000);
268

269
    ogg->nstreams++;
270 271 272
    return idx;
}

273
static 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 281 282
        memcpy(nb, os->buf + os->pstart, size);
        av_free(os->buf);
    }
283 284

    os->buf    = nb;
285 286 287 288 289 290
    os->bufpos = size;
    os->pstart = 0;

    return 0;
}

291 292 293 294 295 296 297 298 299 300
static int data_packets_seen(const struct ogg *ogg)
{
    int i;

    for (i = 0; i < ogg->nstreams; i++)
        if (ogg->streams[i].got_data)
            return 1;
    return 0;
}

301
static int ogg_read_page(AVFormatContext *s, int *sid)
302
{
303
    AVIOContext *bc = s->pb;
304 305
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os;
306
    int ret, i = 0;
307 308 309 310
    int flags, nsegs;
    uint64_t gp;
    uint32_t serial;
    int size, idx;
311
    uint8_t sync[4];
312 313
    int sp = 0;

314
    ret = avio_read(bc, sync, 4);
315 316
    if (ret < 4)
        return ret < 0 ? ret : AVERROR_EOF;
317

318
    do {
319 320 321 322 323 324 325
        int c;

        if (sync[sp & 3] == 'O' &&
            sync[(sp + 1) & 3] == 'g' &&
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
            break;

326 327 328 329 330 331
        if(!i && bc->seekable && ogg->page_pos > 0) {
            memset(sync, 0, 4);
            avio_seek(bc, ogg->page_pos+4, SEEK_SET);
            ogg->page_pos = -1;
        }

332
        c = avio_r8(bc);
333

334
        if (url_feof(bc))
335
            return AVERROR_EOF;
336

337
        sync[sp++ & 3] = c;
338
    } while (i++ < MAX_PAGE_SIZE);
339

340 341
    if (i >= MAX_PAGE_SIZE) {
        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 351 352
    flags  = avio_r8(bc);
    gp     = avio_rl64(bc);
    serial = avio_rl32(bc);
Mans Rullgard's avatar
Mans Rullgard committed
353
    avio_skip(bc, 8); /* seq, crc */
354
    nsegs  = avio_r8(bc);
355

356 357
    idx = ogg_find_stream(ogg, serial);
    if (idx < 0) {
358
        if (data_packets_seen(ogg))
359
            idx = ogg_replace_stream(s, serial, nsegs);
360 361
        else
            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 375
        ogg_new_buf(ogg, idx);

376
    ret = avio_read(bc, os->segments, nsegs);
377 378
    if (ret < nsegs)
        return ret < 0 ? ret : AVERROR_EOF;
379 380

    os->nsegs = nsegs;
381
    os->segp  = 0;
382 383 384 385 386

    size = 0;
    for (i = 0; i < nsegs; i++)
        size += os->segments[i];

387 388 389
    if (!(flags & OGG_FLAG_BOS))
        os->got_data = 1;

390 391
    if (flags & OGG_FLAG_CONT || os->incomplete) {
        if (!os->psize) {
392 393 394
            // If this is the very first segment we started
            // playback in the middle of a continuation packet.
            // Discard it since we missed the start of it.
395
            while (os->segp < os->nsegs) {
396 397 398
                int seg = os->segments[os->segp++];
                os->pstart += seg;
                if (seg < 255)
399
                    break;
400
            }
401
            os->sync_pos = os->page_pos;
402
        }
403 404
    } else {
        os->psize    = 0;
405
        os->sync_pos = os->page_pos;
406 407
    }

408 409
    if (os->bufsize - os->bufpos < size) {
        uint8_t *nb = av_malloc((os->bufsize *= 2) + FF_INPUT_BUFFER_PADDING_SIZE);
410 411
        if (!nb)
            return AVERROR(ENOMEM);
412 413
        memcpy(nb, os->buf, os->bufpos);
        av_free(os->buf);
414 415 416
        os->buf = nb;
    }

417
    ret = avio_read(bc, os->buf + os->bufpos, size);
418 419
    if (ret < size)
        return ret < 0 ? ret : AVERROR_EOF;
420 421 422

    os->bufpos += size;
    os->granule = gp;
423
    os->flags   = flags;
424

425
    memset(os->buf + os->bufpos, 0, FF_INPUT_BUFFER_PADDING_SIZE);
426 427
    if (sid)
        *sid = idx;
428 429 430 431

    return 0;
}

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 436 437 438
 *             no matching stream, in that case assume all other return
 *             values to be uninitialized.
 * @return negative value on error or EOF.
 */
439
static 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

Stefano Sabatini's avatar
Stefano Sabatini committed
448
    av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
449 450
    if (sid)
        *sid = -1;
451

452
    do {
453 454
        idx = ogg->curidx;

455
        while (idx < 0) {
456
            ret = ogg_read_page(s, &idx);
457 458
            if (ret < 0)
                return ret;
459 460 461 462
        }

        os = ogg->streams + idx;

Stefano Sabatini's avatar
Stefano Sabatini committed
463
        av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
464 465
                idx, os->pstart, os->psize, os->segp, os->nsegs);

466 467 468 469
        if (!os->codec) {
            if (os->header < 0) {
                os->codec = ogg_find_codec(os->buf, os->bufpos);
                if (!os->codec) {
470
                    av_log(s, AV_LOG_WARNING, "Codec not found\n");
471 472 473
                    os->header = 0;
                    return 0;
                }
474
            } else {
475 476 477 478
                return 0;
            }
        }

479
        segp  = os->segp;
480 481
        psize = os->psize;

482
        while (os->segp < os->nsegs) {
483 484
            int ss = os->segments[os->segp++];
            os->psize += ss;
485
            if (ss < 255) {
486 487 488 489 490
                complete = 1;
                break;
            }
        }

491 492
        if (!complete && os->segp == os->nsegs) {
            ogg->curidx    = -1;
493 494 495 496 497
            // Do not set incomplete for empty packets.
            // Together with the code in ogg_read_page
            // that discards all continuation of empty packets
            // we would get an infinite loop.
            os->incomplete = !!os->psize;
498
        }
499
    } while (!complete);
500 501


502
    if (os->granule == -1)
503 504 505
        av_log(s, AV_LOG_WARNING,
               "Page at %"PRId64" is missing granule\n",
               os->page_pos);
506

507
    ogg->curidx    = idx;
508
    os->incomplete = 0;
509

510
    if (os->header) {
511 512 513
        os->header = os->codec->header(s, idx);
        if (!os->header) {
            os->segp  = segp;
514
            os->psize = psize;
515

516 517
            // We have reached the first non-header packet in this stream.
            // 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 522

            // Update the header state for all streams and
            // compute the data_offset.
523 524
            if (!s->data_offset)
                s->data_offset = os->sync_pos;
525

526 527 528 529 530 531 532 533
            for (i = 0; i < ogg->nstreams; i++) {
                struct ogg_stream *cur_os = ogg->streams + i;

                // if we have a partial non-header packet, its start is
                // obviously at or after the data start
                if (cur_os->incomplete)
                    s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
            }
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 545
        if (sid)
            *sid = idx;
546 547 548 549
        if (dstart)
            *dstart = os->pstart;
        if (dsize)
            *dsize = os->psize;
550 551
        if (fpos)
            *fpos = os->sync_pos;
552 553
        os->pstart  += os->psize;
        os->psize    = 0;
554 555
        if(os->pstart == os->bufpos)
            os->bufpos = os->pstart = 0;
556
        os->sync_pos = os->page_pos;
557 558
    }

David Conrad's avatar
David Conrad committed
559 560 561 562 563 564 565 566 567
    // determine whether there are more complete packets in this page
    // if not, the page's granule will apply to this packet
    os->page_end = 1;
    for (i = os->segp; i < os->nsegs; i++)
        if (os->segments[i] < 255) {
            os->page_end = 0;
            break;
        }

568 569 570 571 572 573
    if (os->segp == os->nsegs)
        ogg->curidx = -1;

    return 0;
}

574
static 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 585 586 587

// already set
    if (s->duration != AV_NOPTS_VALUE)
        return 0;

588
    size = avio_size(s->pb);
589
    if (size < 0)
Måns Rullgård's avatar
Måns Rullgård committed
590
        return 0;
591
    end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
Måns Rullgård's avatar
Måns Rullgård committed
592

593 594
    ogg_save(s);
    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 600
            ogg->streams[i].codec) {
            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 605
                streams_left-= (ogg->streams[i].got_start==-1);
                ogg->streams[i].got_start= 1;
606
            } else if(!ogg->streams[i].got_start) {
607 608 609
                ogg->streams[i].got_start= -1;
                streams_left++;
            }
610
        }
611 612
    }

613
    ogg_restore(s, 0);
614

jan gerber's avatar
jan gerber committed
615
    ogg_save (s);
616
    avio_seek (s->pb, s->data_offset, SEEK_SET);
617
    ogg_reset(s);
618 619 620 621
    while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
        int64_t pts;
        if (i < 0) continue;
        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 624 625
            s->streams[i]->duration -= pts;
            ogg->streams[i].got_start= 1;
            streams_left--;
626
        }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
627 628
            ogg->streams[i].got_start= 1;
            streams_left--;
629
        }
jan gerber's avatar
jan gerber committed
630 631 632
    }
    ogg_restore (s, 0);

633 634 635
    return 0;
}

636 637 638 639 640 641
static int ogg_read_close(AVFormatContext *s)
{
    struct ogg *ogg = s->priv_data;
    int i;

    for (i = 0; i < ogg->nstreams; i++) {
642
        av_freep(&ogg->streams[i].buf);
643 644 645 646
        if (ogg->streams[i].codec &&
            ogg->streams[i].codec->cleanup) {
            ogg->streams[i].codec->cleanup(s, i);
        }
647
        av_freep(&ogg->streams[i].private);
648
        av_freep(&ogg->streams[i].new_metadata);
649
    }
650
    av_freep(&ogg->streams);
651 652 653
    return 0;
}

654
static int ogg_read_header(AVFormatContext *s)
655
{
656
    struct ogg *ogg = s->priv_data;
657
    int ret, i;
658

659
    ogg->curidx = -1;
660

661
    //linear headers seek from start
662 663
    do {
        ret = ogg_packet(s, NULL, NULL, NULL, NULL);
664 665
        if (ret < 0) {
            ogg_read_close(s);
666
            return ret;
667
        }
668 669
    } while (!ogg->headers);
    av_dlog(s, "found headers\n");
670

671 672 673
    for (i = 0; i < ogg->nstreams; i++) {
        struct ogg_stream *os = ogg->streams + i;

674 675
        if (ogg->streams[i].header < 0) {
            av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
676
            ogg->streams[i].codec = NULL;
677
        } else if (os->codec && os->nb_header < os->codec->nb_header) {
678 679 680 681 682 683
            av_log(s, AV_LOG_WARNING,
                   "Headers mismatch for stream %d: "
                   "expected %d received %d.\n",
                   i, os->codec->nb_header, os->nb_header);
            if (s->error_recognition & AV_EF_EXPLODE)
                return AVERROR_INVALIDDATA;
684
        }
685 686 687
        if (os->start_granule != OGG_NOGRANULE_VALUE)
            os->lastpts = s->streams[i]->start_time =
                ogg_gptopts(s, i, os->start_granule, NULL);
688
    }
689

690
    //linear granulepos seek from end
691
    ogg_get_length(s);
692 693 694 695

    return 0;
}

696 697
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
{
698
    struct ogg *ogg       = s->priv_data;
699
    struct ogg_stream *os = ogg->streams + idx;
700
    int64_t pts           = AV_NOPTS_VALUE;
701 702 703 704 705

    if (dts)
        *dts = AV_NOPTS_VALUE;

    if (os->lastpts != AV_NOPTS_VALUE) {
706
        pts         = os->lastpts;
707 708 709 710 711 712 713 714 715 716 717 718 719 720
        os->lastpts = AV_NOPTS_VALUE;
    }
    if (os->lastdts != AV_NOPTS_VALUE) {
        if (dts)
            *dts = os->lastdts;
        os->lastdts = AV_NOPTS_VALUE;
    }
    if (os->page_end) {
        if (os->granule != -1LL) {
            if (os->codec && os->codec->granule_is_start)
                pts = ogg_gptopts(s, idx, os->granule, dts);
            else
                os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
            os->granule = -1LL;
721
        }
722 723 724
    }
    return pts;
}
725

726 727 728 729
static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
{
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os = ogg->streams + idx;
730 731 732 733 734 735 736 737 738 739
    int invalid = 0;
    if (psize) {
        switch (s->streams[idx]->codec->codec_id) {
        case AV_CODEC_ID_THEORA:
            invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40);
        break;
        case AV_CODEC_ID_VP8:
            invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1);
        }
        if (invalid) {
740
            os->pflags ^= AV_PKT_FLAG_KEY;
741 742
            av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
                   (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
743 744 745 746
        }
    }
}

747
static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
748
{
749 750
    struct ogg *ogg;
    struct ogg_stream *os;
751
    int idx, ret;
752
    int pstart, psize;
David Conrad's avatar
David Conrad committed
753
    int64_t fpos, pts, dts;
754

755 756 757 758 759
    if (s->io_repositioned) {
        ogg_reset(s);
        s->io_repositioned = 0;
    }

760
    //Get an ogg packet
David Conrad's avatar
David Conrad committed
761
retry:
762
    do {
763
        ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
764 765
        if (ret < 0)
            return ret;
766
    } while (idx < 0 || !s->streams[idx]);
767 768

    ogg = s->priv_data;
769
    os  = ogg->streams + idx;
770

David Conrad's avatar
David Conrad committed
771 772
    // pflags might not be set until after this
    pts = ogg_calc_pts(s, idx, &dts);
773
    ogg_validate_keyframe(s, idx, pstart, psize);
David Conrad's avatar
David Conrad committed
774

775
    if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
David Conrad's avatar
David Conrad committed
776 777 778
        goto retry;
    os->keyframe_seek = 0;

779
    //Alloc a pkt
780
    ret = av_new_packet(pkt, psize);
781 782
    if (ret < 0)
        return ret;
783
    pkt->stream_index = idx;
784
    memcpy(pkt->data, os->buf + pstart, psize);
David Conrad's avatar
David Conrad committed
785

786 787 788
    pkt->pts      = pts;
    pkt->dts      = dts;
    pkt->flags    = os->pflags;
789
    pkt->duration = os->pduration;
790
    pkt->pos      = fpos;
791

792 793 794 795 796 797 798 799 800 801
    if (os->end_trimming) {
        uint8_t *side_data = av_packet_new_side_data(pkt,
                                                     AV_PKT_DATA_SKIP_SAMPLES,
                                                     10);
        if(side_data == NULL) {
            av_free_packet(pkt);
            av_free(pkt);
            return AVERROR(ENOMEM);
        }
        AV_WL32(side_data + 4, os->end_trimming);
802
        os->end_trimming = 0;
803 804
    }

805 806 807 808 809 810 811 812 813
    if (os->new_metadata) {
        uint8_t *side_data = av_packet_new_side_data(pkt,
                                                     AV_PKT_DATA_METADATA_UPDATE,
                                                     os->new_metadata_size);
        memcpy(side_data, os->new_metadata, os->new_metadata_size);
        av_freep(&os->new_metadata);
        os->new_metadata_size = 0;
    }

814
    return psize;
815 816
}

817 818
static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
                                  int64_t *pos_arg, int64_t pos_limit)
819
{
820
    struct ogg *ogg = s->priv_data;
821
    AVIOContext *bc = s->pb;
822
    int64_t pts     = AV_NOPTS_VALUE;
823
    int64_t keypos  = -1;
824
    int i;
825
    int pstart, psize;
826
    avio_seek(bc, *pos_arg, SEEK_SET);
827
    ogg_reset(s);
828

829 830
    while (   avio_tell(bc) <= pos_limit
           && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
831
        if (i == stream_index) {
832
            struct ogg_stream *os = ogg->streams + stream_index;
833 834 835 836 837
            // Dont trust the last timestamps of a ogm video
            if (    (os->flags & OGG_FLAG_EOS)
                && !(os->flags & OGG_FLAG_BOS)
                && os->codec == &ff_ogm_video_codec)
                continue;
838
            pts = ogg_calc_pts(s, i, NULL);
839
            ogg_validate_keyframe(s, i, pstart, psize);
840 841 842 843 844 845 846 847 848 849
            if (os->pflags & AV_PKT_FLAG_KEY) {
                keypos = *pos_arg;
            } else if (os->keyframe_seek) {
                // if we had a previous keyframe but no pts for it,
                // return that keyframe with this pts value.
                if (keypos >= 0)
                    *pos_arg = keypos;
                else
                    pts = AV_NOPTS_VALUE;
            }
850
        }
851 852
        if (pts != AV_NOPTS_VALUE)
            break;
853
    }
854
    ogg_reset(s);
855
    return pts;
856 857
}

858 859
static int ogg_read_seek(AVFormatContext *s, int stream_index,
                         int64_t timestamp, int flags)
David Conrad's avatar
David Conrad committed
860
{
861
    struct ogg *ogg       = s->priv_data;
David Conrad's avatar
David Conrad committed
862 863 864
    struct ogg_stream *os = ogg->streams + stream_index;
    int ret;

865
    av_assert0(stream_index < ogg->nstreams);
866 867
    // Ensure everything is reset even when seeking via
    // the generated index.
868
    ogg_reset(s);
869

David Conrad's avatar
David Conrad committed
870 871
    // Try seeking to a keyframe first. If this fails (very possible),
    // av_seek_frame will fall back to ignoring keyframes
872
    if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
David Conrad's avatar
David Conrad committed
873 874 875
        && !(flags & AVSEEK_FLAG_ANY))
        os->keyframe_seek = 1;

876
    ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
877
    os  = ogg->streams + stream_index;
David Conrad's avatar
David Conrad committed
878 879 880 881 882
    if (ret < 0)
        os->keyframe_seek = 0;
    return ret;
}

883 884
static int ogg_probe(AVProbeData *p)
{
885
    if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
886
        return AVPROBE_SCORE_MAX;
887
    return 0;
888 889
}

890
AVInputFormat ff_ogg_demuxer = {
891 892 893 894 895 896 897 898 899 900
    .name           = "ogg",
    .long_name      = NULL_IF_CONFIG_SMALL("Ogg"),
    .priv_data_size = sizeof(struct ogg),
    .read_probe     = ogg_probe,
    .read_header    = ogg_read_header,
    .read_packet    = ogg_read_packet,
    .read_close     = ogg_read_close,
    .read_seek      = ogg_read_seek,
    .read_timestamp = ogg_read_timestamp,
    .extensions     = "ogg",
901
    .flags          = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT | AVFMT_NOBINSEARCH,
902
};