oggdec.c 26.8 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_daala_codec,
45
    &ff_dirac_codec,
46 47 48 49
    &ff_speex_codec,
    &ff_vorbis_codec,
    &ff_theora_codec,
    &ff_flac_codec,
50
    &ff_celt_codec,
51
    &ff_opus_codec,
52
    &ff_vp8_codec,
53
    &ff_old_dirac_codec,
54 55 56 57 58
    &ff_old_flac_codec,
    &ff_ogm_video_codec,
    &ff_ogm_audio_codec,
    &ff_ogm_text_codec,
    &ff_ogm_old_codec,
59 60 61
    NULL
};

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

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
static void free_stream(AVFormatContext *s, int i)
{
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *stream = &ogg->streams[i];

    av_freep(&stream->buf);
    if (stream->codec &&
        stream->codec->cleanup) {
        stream->codec->cleanup(s, i);
    }

    av_freep(&stream->private);
    av_freep(&stream->new_metadata);
}

81
//FIXME We could avoid some structure duplication
82
static int ogg_save(AVFormatContext *s)
83
{
84 85
    struct ogg *ogg = s->priv_data;
    struct ogg_state *ost =
86
        av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
87
    int i;
88
    int ret = 0;
89 90 91 92

    if (!ost)
        return AVERROR(ENOMEM);

93 94 95
    ost->pos      = avio_tell(s->pb);
    ost->curidx   = ogg->curidx;
    ost->next     = ogg->state;
96
    ost->nstreams = ogg->nstreams;
97 98
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));

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 103 104 105
        if (os->buf)
            memcpy(os->buf, ost->streams[i].buf, os->bufpos);
        else
            ret = AVERROR(ENOMEM);
106 107
        os->new_metadata      = NULL;
        os->new_metadata_size = 0;
108 109 110 111
    }

    ogg->state = ost;

112
    if (ret < 0)
113
        ogg_restore(s);
114 115

    return ret;
116 117
}

118
static 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 126 127 128 129

    if (!ost)
        return 0;

    ogg->state = ost->next;

130
        for (i = 0; i < ogg->nstreams; i++) {
131 132 133 134
            struct ogg_stream *stream = &ogg->streams[i];
            av_freep(&stream->buf);
            av_freep(&stream->new_metadata);

135 136 137 138
            if (i >= ost->nstreams || !ost->streams[i].private) {
                free_stream(s, i);
            }
        }
139

140
        avio_seek(bc, ost->pos, SEEK_SET);
141
        ogg->page_pos = -1;
142
        ogg->curidx   = ost->curidx;
143
        ogg->nstreams = ost->nstreams;
144 145 146 147 148
        if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
                                     sizeof(*ogg->streams))) < 0) {
            ogg->nstreams = 0;
            return err;
        } else
149 150
            memcpy(ogg->streams, ost->streams,
                   ost->nstreams * sizeof(*ogg->streams));
151

152
    av_free(ost);
153 154 155 156

    return 0;
}

157
static int ogg_reset(AVFormatContext *s)
158
{
159
    struct ogg *ogg = s->priv_data;
160
    int i;
161
    int64_t start_pos = avio_tell(s->pb);
162

163
    for (i = 0; i < ogg->nstreams; i++) {
164
        struct ogg_stream *os = ogg->streams + i;
165 166 167 168 169 170 171 172 173 174
        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;
175
        os->incomplete = 0;
176
        os->got_data = 0;
177
        if (start_pos <= s->internal->data_offset) {
178 179
            os->lastpts = 0;
        }
180
        os->end_trimming = 0;
181 182
        av_freep(&os->new_metadata);
        os->new_metadata_size = 0;
183 184
    }

185
    ogg->page_pos = -1;
186 187 188 189 190
    ogg->curidx = -1;

    return 0;
}

191
static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
192 193 194 195 196
{
    int i;

    for (i = 0; ogg_codecs[i]; i++)
        if (size >= ogg_codecs[i]->magicsize &&
197
            !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
198 199 200 201 202
            return ogg_codecs[i];

    return NULL;
}

203 204 205 206 207
/**
 * 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).
 */
208
static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int nsegs)
209
{
210 211
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os;
212
    const struct ogg_codec *codec;
213 214
    int i = 0;

James Almer's avatar
James Almer committed
215
    if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) {
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
        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) {
233
        avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
234 235 236
        return AVERROR_PATCHWELCOME;
    }

237
    os = &ogg->streams[i];
238

239
    os->serial  = serial;
240
    return i;
241

242
#if 0
243
    buf     = os->buf;
244
    bufsize = os->bufsize;
245
    codec   = os->codec;
246

247 248
    if (!ogg->state || ogg->state->streams[i].private != os->private)
        av_freep(&ogg->streams[i].private);
249 250 251 252

    /* 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));
253
    os->serial  = serial;
254
    os->bufsize = bufsize;
255 256 257
    os->buf     = buf;
    os->header  = -1;
    os->codec   = codec;
258

259
    return i;
260
#endif
261
}
262

263 264
static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
{
265
    struct ogg *ogg = s->priv_data;
266
    int idx         = ogg->nstreams;
267
    AVStream *st;
268
    struct ogg_stream *os;
269
    size_t size;
270

271 272 273 274 275 276
    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;
    }

277
    /* Allocate and init a new Ogg Stream */
278 279 280
    if (av_size_mult(ogg->nstreams + 1, sizeof(*ogg->streams), &size) < 0 ||
        !(os = av_realloc(ogg->streams, size)))
        return AVERROR(ENOMEM);
281 282
    ogg->streams = os;
    os           = ogg->streams + idx;
283
    memset(os, 0, sizeof(*os));
284 285
    os->serial        = serial;
    os->bufsize       = DECODER_BUFFER_SIZE;
286
    os->buf           = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
287
    os->header        = -1;
288
    os->start_granule = OGG_NOGRANULE_VALUE;
289 290
    if (!os->buf)
        return AVERROR(ENOMEM);
291

292 293 294 295 296 297 298 299
    /* 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);
300

301
    ogg->nstreams++;
302 303 304
    return idx;
}

305
static int ogg_new_buf(struct ogg *ogg, int idx)
306
{
307
    struct ogg_stream *os = ogg->streams + idx;
308
    uint8_t *nb = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
309
    int size = os->bufpos - os->pstart;
310

311 312 313
    if (!nb)
        return AVERROR(ENOMEM);

314
    if (os->buf) {
315 316 317
        memcpy(nb, os->buf + os->pstart, size);
        av_free(os->buf);
    }
318 319

    os->buf    = nb;
320 321 322 323 324 325
    os->bufpos = size;
    os->pstart = 0;

    return 0;
}

326 327 328 329 330 331 332 333 334 335
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;
}

336
static int ogg_read_page(AVFormatContext *s, int *sid)
337
{
338
    AVIOContext *bc = s->pb;
339 340
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os;
341
    int ret, i = 0;
342 343 344 345
    int flags, nsegs;
    uint64_t gp;
    uint32_t serial;
    int size, idx;
346
    uint8_t sync[4];
347 348
    int sp = 0;

349
    ret = avio_read(bc, sync, 4);
350 351
    if (ret < 4)
        return ret < 0 ? ret : AVERROR_EOF;
352

353
    do {
354 355 356 357 358 359 360
        int c;

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

James Almer's avatar
James Almer committed
361
        if(!i && (bc->seekable & AVIO_SEEKABLE_NORMAL) && ogg->page_pos > 0) {
362 363 364 365 366
            memset(sync, 0, 4);
            avio_seek(bc, ogg->page_pos+4, SEEK_SET);
            ogg->page_pos = -1;
        }

367
        c = avio_r8(bc);
368

369
        if (avio_feof(bc))
370
            return AVERROR_EOF;
371

372
        sync[sp++ & 3] = c;
373
    } while (i++ < MAX_PAGE_SIZE);
374

375 376
    if (i >= MAX_PAGE_SIZE) {
        av_log(s, AV_LOG_INFO, "cannot find sync word\n");
377
        return AVERROR_INVALIDDATA;
378 379
    }

380
    if (avio_r8(bc) != 0) {      /* version */
381
        av_log (s, AV_LOG_ERROR, "ogg page, unsupported version\n");
382
        return AVERROR_INVALIDDATA;
383
    }
384

385 386 387
    flags  = avio_r8(bc);
    gp     = avio_rl64(bc);
    serial = avio_rl32(bc);
Mans Rullgard's avatar
Mans Rullgard committed
388
    avio_skip(bc, 8); /* seq, crc */
389
    nsegs  = avio_r8(bc);
390

391 392
    idx = ogg_find_stream(ogg, serial);
    if (idx < 0) {
393
        if (data_packets_seen(ogg))
394
            idx = ogg_replace_stream(s, serial, nsegs);
395 396
        else
            idx = ogg_new_stream(s, serial);
397

398
        if (idx < 0) {
399
            av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
400
            return idx;
401
        }
402 403 404
    }

    os = ogg->streams + idx;
405
    ogg->page_pos =
406
    os->page_pos = avio_tell(bc) - 27;
407

408 409 410 411 412
    if (os->psize > 0) {
        ret = ogg_new_buf(ogg, idx);
        if (ret < 0)
            return ret;
    }
413

414
    ret = avio_read(bc, os->segments, nsegs);
415 416
    if (ret < nsegs)
        return ret < 0 ? ret : AVERROR_EOF;
417 418

    os->nsegs = nsegs;
419
    os->segp  = 0;
420 421 422 423 424

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

425 426 427
    if (!(flags & OGG_FLAG_BOS))
        os->got_data = 1;

428 429
    if (flags & OGG_FLAG_CONT || os->incomplete) {
        if (!os->psize) {
430 431 432
            // 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.
433
            while (os->segp < os->nsegs) {
434 435 436
                int seg = os->segments[os->segp++];
                os->pstart += seg;
                if (seg < 255)
437
                    break;
438
            }
439
            os->sync_pos = os->page_pos;
440
        }
441 442
    } else {
        os->psize    = 0;
443
        os->sync_pos = os->page_pos;
444 445
    }

446
    if (os->bufsize - os->bufpos < size) {
447
        uint8_t *nb = av_malloc((os->bufsize *= 2) + AV_INPUT_BUFFER_PADDING_SIZE);
448 449
        if (!nb)
            return AVERROR(ENOMEM);
450 451
        memcpy(nb, os->buf, os->bufpos);
        av_free(os->buf);
452 453 454
        os->buf = nb;
    }

455
    ret = avio_read(bc, os->buf + os->bufpos, size);
456 457
    if (ret < size)
        return ret < 0 ? ret : AVERROR_EOF;
458 459 460

    os->bufpos += size;
    os->granule = gp;
461
    os->flags   = flags;
462

463
    memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE);
464 465
    if (sid)
        *sid = idx;
466 467 468 469

    return 0;
}

470 471
/**
 * @brief find the next Ogg packet
472
 * @param *sid is set to the stream for the packet or -1 if there is
473 474 475 476
 *             no matching stream, in that case assume all other return
 *             values to be uninitialized.
 * @return negative value on error or EOF.
 */
477
static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
478
                      int64_t *fpos)
479
{
480
    struct ogg *ogg = s->priv_data;
481
    int idx, i, ret;
482
    struct ogg_stream *os;
483
    int complete = 0;
484
    int segp     = 0, psize = 0;
485

486
    av_log(s, AV_LOG_TRACE, "ogg_packet: curidx=%i\n", ogg->curidx);
487 488
    if (sid)
        *sid = -1;
489

490
    do {
491 492
        idx = ogg->curidx;

493
        while (idx < 0) {
494
            ret = ogg_read_page(s, &idx);
495 496
            if (ret < 0)
                return ret;
497 498 499 500
        }

        os = ogg->streams + idx;

501
        av_log(s, AV_LOG_TRACE, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
502 503
                idx, os->pstart, os->psize, os->segp, os->nsegs);

504 505 506 507
        if (!os->codec) {
            if (os->header < 0) {
                os->codec = ogg_find_codec(os->buf, os->bufpos);
                if (!os->codec) {
508
                    av_log(s, AV_LOG_WARNING, "Codec not found\n");
509 510 511
                    os->header = 0;
                    return 0;
                }
512
            } else {
513 514 515 516
                return 0;
            }
        }

517
        segp  = os->segp;
518 519
        psize = os->psize;

520
        while (os->segp < os->nsegs) {
521 522
            int ss = os->segments[os->segp++];
            os->psize += ss;
523
            if (ss < 255) {
524 525 526 527 528
                complete = 1;
                break;
            }
        }

529 530
        if (!complete && os->segp == os->nsegs) {
            ogg->curidx    = -1;
531 532 533 534 535
            // 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;
536
        }
537
    } while (!complete);
538 539


540
    if (os->granule == -1)
541 542 543
        av_log(s, AV_LOG_WARNING,
               "Page at %"PRId64" is missing granule\n",
               os->page_pos);
544

545
    ogg->curidx    = idx;
546
    os->incomplete = 0;
547

548
    if (os->header) {
549 550 551 552 553
        if ((ret = os->codec->header(s, idx)) < 0) {
            av_log(s, AV_LOG_ERROR, "Header processing failed: %s\n", av_err2str(ret));
            return ret;
        }
        os->header = ret;
554 555
        if (!os->header) {
            os->segp  = segp;
556
            os->psize = psize;
557

558 559
            // We have reached the first non-header packet in this stream.
            // Unfortunately more header packets may still follow for others,
560
            // but if we continue with header parsing we may lose data packets.
561
            ogg->headers = 1;
562 563 564

            // Update the header state for all streams and
            // compute the data_offset.
565 566
            if (!s->internal->data_offset)
                s->internal->data_offset = os->sync_pos;
567

568 569 570 571 572 573
            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)
574
                    s->internal->data_offset = FFMIN(s->internal->data_offset, cur_os->sync_pos);
575
            }
576
        } else {
577
            os->nb_header++;
578
            os->pstart += os->psize;
579
            os->psize   = 0;
580
        }
581
    } else {
582
        os->pflags    = 0;
583
        os->pduration = 0;
584 585 586 587 588 589
        if (os->codec && os->codec->packet) {
            if ((ret = os->codec->packet(s, idx)) < 0) {
                av_log(s, AV_LOG_ERROR, "Packet processing failed: %s\n", av_err2str(ret));
                return ret;
            }
        }
590 591
        if (sid)
            *sid = idx;
592 593 594 595
        if (dstart)
            *dstart = os->pstart;
        if (dsize)
            *dsize = os->psize;
596 597
        if (fpos)
            *fpos = os->sync_pos;
598 599
        os->pstart  += os->psize;
        os->psize    = 0;
600 601
        if(os->pstart == os->bufpos)
            os->bufpos = os->pstart = 0;
602
        os->sync_pos = os->page_pos;
603 604
    }

David Conrad's avatar
David Conrad committed
605 606 607 608 609 610 611 612 613
    // 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;
        }

614 615 616 617 618 619
    if (os->segp == os->nsegs)
        ogg->curidx = -1;

    return 0;
}

620
static int ogg_get_length(AVFormatContext *s)
621
{
622
    struct ogg *ogg = s->priv_data;
623
    int i, ret;
624
    int64_t size, end;
625
    int streams_left=0;
626

627
    if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
628
        return 0;
629 630 631 632 633

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

634
    size = avio_size(s->pb);
635
    if (size < 0)
Måns Rullgård's avatar
Måns Rullgård committed
636
        return 0;
637
    end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
Måns Rullgård's avatar
Måns Rullgård committed
638

639 640 641
    ret = ogg_save(s);
    if (ret < 0)
        return ret;
642
    avio_seek(s->pb, end, SEEK_SET);
643
    ogg->page_pos = -1;
644

645
    while (!ogg_read_page(s, &i)) {
646
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
647 648
            ogg->streams[i].codec) {
            s->streams[i]->duration =
649
                ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
650
            if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
651
                s->streams[i]->duration -= s->streams[i]->start_time;
652 653
                streams_left-= (ogg->streams[i].got_start==-1);
                ogg->streams[i].got_start= 1;
654
            } else if(!ogg->streams[i].got_start) {
655 656 657
                ogg->streams[i].got_start= -1;
                streams_left++;
            }
658
        }
659 660
    }

661
    ogg_restore(s);
662

663 664 665 666
    ret = ogg_save(s);
    if (ret < 0)
        return ret;

667
    avio_seek (s->pb, s->internal->data_offset, SEEK_SET);
668
    ogg_reset(s);
669 670 671 672
    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);
673 674
        if (s->streams[i]->duration == AV_NOPTS_VALUE)
            continue;
675
        if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
676 677 678
            s->streams[i]->duration -= pts;
            ogg->streams[i].got_start= 1;
            streams_left--;
679
        }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
680 681
            ogg->streams[i].got_start= 1;
            streams_left--;
682
        }
jan gerber's avatar
jan gerber committed
683
    }
684
    ogg_restore (s);
jan gerber's avatar
jan gerber committed
685

686 687 688
    return 0;
}

689 690 691 692 693 694
static int ogg_read_close(AVFormatContext *s)
{
    struct ogg *ogg = s->priv_data;
    int i;

    for (i = 0; i < ogg->nstreams; i++) {
695
        free_stream(s, i);
696
    }
697 698 699

    ogg->nstreams = 0;

700
    av_freep(&ogg->streams);
701 702 703
    return 0;
}

704
static int ogg_read_header(AVFormatContext *s)
705
{
706
    struct ogg *ogg = s->priv_data;
707
    int ret, i;
708

709
    ogg->curidx = -1;
710

711
    //linear headers seek from start
712 713
    do {
        ret = ogg_packet(s, NULL, NULL, NULL, NULL);
714 715
        if (ret < 0) {
            ogg_read_close(s);
716
            return ret;
717
        }
718
    } while (!ogg->headers);
719
    av_log(s, AV_LOG_TRACE, "found headers\n");
720

721 722 723
    for (i = 0; i < ogg->nstreams; i++) {
        struct ogg_stream *os = ogg->streams + i;

724 725
        if (ogg->streams[i].header < 0) {
            av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
726
            ogg->streams[i].codec = NULL;
727
            av_freep(&ogg->streams[i].private);
728
        } else if (os->codec && os->nb_header < os->codec->nb_header) {
729 730 731 732
            av_log(s, AV_LOG_WARNING,
                   "Headers mismatch for stream %d: "
                   "expected %d received %d.\n",
                   i, os->codec->nb_header, os->nb_header);
733 734
            if (s->error_recognition & AV_EF_EXPLODE) {
                ogg_read_close(s);
735
                return AVERROR_INVALIDDATA;
736
            }
737
        }
738 739 740
        if (os->start_granule != OGG_NOGRANULE_VALUE)
            os->lastpts = s->streams[i]->start_time =
                ogg_gptopts(s, i, os->start_granule, NULL);
741
    }
742

743
    //linear granulepos seek from end
744 745 746 747 748
    ret = ogg_get_length(s);
    if (ret < 0) {
        ogg_read_close(s);
        return ret;
    }
749 750 751 752

    return 0;
}

753 754
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
{
755
    struct ogg *ogg       = s->priv_data;
756
    struct ogg_stream *os = ogg->streams + idx;
757
    int64_t pts           = AV_NOPTS_VALUE;
758 759 760 761 762

    if (dts)
        *dts = AV_NOPTS_VALUE;

    if (os->lastpts != AV_NOPTS_VALUE) {
763
        pts         = os->lastpts;
764 765 766 767 768 769 770 771 772 773 774 775 776 777
        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;
778
        }
779 780 781
    }
    return pts;
}
782

783 784 785 786
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;
787 788
    int invalid = 0;
    if (psize) {
789
        switch (s->streams[idx]->codecpar->codec_id) {
790 791 792 793 794 795 796
        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) {
797
            os->pflags ^= AV_PKT_FLAG_KEY;
798 799
            av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
                   (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
800 801 802 803
        }
    }
}

804
static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
805
{
806 807
    struct ogg *ogg;
    struct ogg_stream *os;
808
    int idx, ret;
809
    int pstart, psize;
David Conrad's avatar
David Conrad committed
810
    int64_t fpos, pts, dts;
811

812 813 814 815 816
    if (s->io_repositioned) {
        ogg_reset(s);
        s->io_repositioned = 0;
    }

817
    //Get an ogg packet
David Conrad's avatar
David Conrad committed
818
retry:
819
    do {
820
        ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
821 822
        if (ret < 0)
            return ret;
823
    } while (idx < 0 || !s->streams[idx]);
824 825

    ogg = s->priv_data;
826
    os  = ogg->streams + idx;
827

David Conrad's avatar
David Conrad committed
828 829
    // pflags might not be set until after this
    pts = ogg_calc_pts(s, idx, &dts);
830
    ogg_validate_keyframe(s, idx, pstart, psize);
David Conrad's avatar
David Conrad committed
831

832
    if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
David Conrad's avatar
David Conrad committed
833 834 835
        goto retry;
    os->keyframe_seek = 0;

836
    //Alloc a pkt
837
    ret = av_new_packet(pkt, psize);
838 839
    if (ret < 0)
        return ret;
840
    pkt->stream_index = idx;
841
    memcpy(pkt->data, os->buf + pstart, psize);
David Conrad's avatar
David Conrad committed
842

843 844 845
    pkt->pts      = pts;
    pkt->dts      = dts;
    pkt->flags    = os->pflags;
846
    pkt->duration = os->pduration;
847
    pkt->pos      = fpos;
848

849 850 851 852
    if (os->end_trimming) {
        uint8_t *side_data = av_packet_new_side_data(pkt,
                                                     AV_PKT_DATA_SKIP_SAMPLES,
                                                     10);
853
        if(!side_data)
854
            goto fail;
855
        AV_WL32(side_data + 4, os->end_trimming);
856
        os->end_trimming = 0;
857 858
    }

859 860 861 862
    if (os->new_metadata) {
        uint8_t *side_data = av_packet_new_side_data(pkt,
                                                     AV_PKT_DATA_METADATA_UPDATE,
                                                     os->new_metadata_size);
863
        if(!side_data)
864 865
            goto fail;

866 867 868 869 870
        memcpy(side_data, os->new_metadata, os->new_metadata_size);
        av_freep(&os->new_metadata);
        os->new_metadata_size = 0;
    }

871
    return psize;
872
fail:
873
    av_packet_unref(pkt);
874
    return AVERROR(ENOMEM);
875 876
}

877 878
static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
                                  int64_t *pos_arg, int64_t pos_limit)
879
{
880
    struct ogg *ogg = s->priv_data;
881
    AVIOContext *bc = s->pb;
882
    int64_t pts     = AV_NOPTS_VALUE;
883
    int64_t keypos  = -1;
884
    int i;
885
    int pstart, psize;
886
    avio_seek(bc, *pos_arg, SEEK_SET);
887
    ogg_reset(s);
888

889 890
    while (   avio_tell(bc) <= pos_limit
           && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
891
        if (i == stream_index) {
892
            struct ogg_stream *os = ogg->streams + stream_index;
Lou Logan's avatar
Lou Logan committed
893
            // Do not trust the last timestamps of an ogm video
894 895 896 897
            if (    (os->flags & OGG_FLAG_EOS)
                && !(os->flags & OGG_FLAG_BOS)
                && os->codec == &ff_ogm_video_codec)
                continue;
898
            pts = ogg_calc_pts(s, i, NULL);
899
            ogg_validate_keyframe(s, i, pstart, psize);
900 901 902 903 904 905 906 907 908 909
            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;
            }
910
        }
911 912
        if (pts != AV_NOPTS_VALUE)
            break;
913
    }
914
    ogg_reset(s);
915
    return pts;
916 917
}

918 919
static int ogg_read_seek(AVFormatContext *s, int stream_index,
                         int64_t timestamp, int flags)
David Conrad's avatar
David Conrad committed
920
{
921
    struct ogg *ogg       = s->priv_data;
David Conrad's avatar
David Conrad committed
922 923 924
    struct ogg_stream *os = ogg->streams + stream_index;
    int ret;

925
    av_assert0(stream_index < ogg->nstreams);
926 927
    // Ensure everything is reset even when seeking via
    // the generated index.
928
    ogg_reset(s);
929

David Conrad's avatar
David Conrad committed
930 931
    // Try seeking to a keyframe first. If this fails (very possible),
    // av_seek_frame will fall back to ignoring keyframes
932
    if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
David Conrad's avatar
David Conrad committed
933 934 935
        && !(flags & AVSEEK_FLAG_ANY))
        os->keyframe_seek = 1;

936
    ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
937
    ogg_reset(s);
938
    os  = ogg->streams + stream_index;
David Conrad's avatar
David Conrad committed
939 940 941 942 943
    if (ret < 0)
        os->keyframe_seek = 0;
    return ret;
}

944
static int ogg_probe(const AVProbeData *p)
945
{
946
    if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
947
        return AVPROBE_SCORE_MAX;
948
    return 0;
949 950
}

951
AVInputFormat ff_ogg_demuxer = {
952 953 954 955 956 957 958 959 960 961
    .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",
962
    .flags          = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT | AVFMT_NOBINSEARCH,
963
};