oggdec.c 17.1 KB
Newer Older
1 2 3 4
/*
 * Ogg bitstream support
 * Luca Barbato <lu_zero@gentoo.org>
 * Based on tcvp implementation
5
 *
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 */

/**
    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.
**/


#include <stdio.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_old_dirac_codec,
51 52 53 54 55
    &ff_old_flac_codec,
    &ff_ogm_video_codec,
    &ff_ogm_audio_codec,
    &ff_ogm_text_codec,
    &ff_ogm_old_codec,
56 57 58 59
    NULL
};

//FIXME We could avoid some structure duplication
60
static int ogg_save(AVFormatContext *s)
61
{
62 63
    struct ogg *ogg = s->priv_data;
    struct ogg_state *ost =
Måns Rullgård's avatar
Måns Rullgård committed
64
        av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
65
    int i;
66
    ost->pos = avio_tell (s->pb);
67 68
    ost->curidx = ogg->curidx;
    ost->next = ogg->state;
69
    ost->nstreams = ogg->nstreams;
70 71 72
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));

    for (i = 0; i < ogg->nstreams; i++){
73
        struct ogg_stream *os = ogg->streams + i;
74 75 76 77 78 79 80 81 82 83
        os->buf = av_malloc (os->bufsize);
        memset (os->buf, 0, os->bufsize);
        memcpy (os->buf, ost->streams[i].buf, os->bufpos);
    }

    ogg->state = ost;

    return 0;
}

84
static int ogg_restore(AVFormatContext *s, int discard)
85
{
86
    struct ogg *ogg = s->priv_data;
87
    AVIOContext *bc = s->pb;
88
    struct ogg_state *ost = ogg->state;
89 90 91 92 93 94 95 96
    int i;

    if (!ost)
        return 0;

    ogg->state = ost->next;

    if (!discard){
97 98
        struct ogg_stream *old_streams = ogg->streams;

99 100 101
        for (i = 0; i < ogg->nstreams; i++)
            av_free (ogg->streams[i].buf);

102
        avio_seek (bc, ost->pos, SEEK_SET);
103
        ogg->curidx = ost->curidx;
104
        ogg->nstreams = ost->nstreams;
105 106 107 108 109 110 111 112 113 114
        ogg->streams = av_realloc (ogg->streams,
                                   ogg->nstreams * sizeof (*ogg->streams));

        if (ogg->streams) {
            memcpy(ogg->streams, ost->streams,
                   ost->nstreams * sizeof(*ogg->streams));
        } else {
            av_free(old_streams);
            ogg->nstreams = 0;
        }
115 116 117 118 119 120 121
    }

    av_free (ost);

    return 0;
}

122
static int ogg_reset(struct ogg *ogg)
123 124 125 126
{
    int i;

    for (i = 0; i < ogg->nstreams; i++){
127
        struct ogg_stream *os = ogg->streams + i;
128 129 130 131
        os->bufpos = 0;
        os->pstart = 0;
        os->psize = 0;
        os->granule = -1;
David Conrad's avatar
David Conrad committed
132
        os->lastpts = AV_NOPTS_VALUE;
133
        os->lastdts = AV_NOPTS_VALUE;
134 135
        os->sync_pos = -1;
        os->page_pos = 0;
136 137
        os->nsegs = 0;
        os->segp = 0;
138
        os->incomplete = 0;
139 140 141 142 143 144 145
    }

    ogg->curidx = -1;

    return 0;
}

146
static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
147 148 149 150 151 152 153 154 155 156 157
{
    int i;

    for (i = 0; ogg_codecs[i]; i++)
        if (size >= ogg_codecs[i]->magicsize &&
            !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
            return ogg_codecs[i];

    return NULL;
}

158
static int ogg_new_stream(AVFormatContext *s, uint32_t serial, int new_avstream)
159 160
{

161
    struct ogg *ogg = s->priv_data;
162 163
    int idx = ogg->nstreams++;
    AVStream *st;
164
    struct ogg_stream *os;
165 166 167 168 169 170 171

    ogg->streams = av_realloc (ogg->streams,
                               ogg->nstreams * sizeof (*ogg->streams));
    memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
    os = ogg->streams + idx;
    os->serial = serial;
    os->bufsize = DECODER_BUFFER_SIZE;
172
    os->buf = av_malloc(os->bufsize);
173 174
    os->header = -1;

175
    if (new_avstream) {
176
        st = avformat_new_stream(s, NULL);
177 178
        if (!st)
            return AVERROR(ENOMEM);
179

180
        st->id = idx;
181 182
        av_set_pts_info(st, 64, 1, 1000000);
    }
183 184 185 186

    return idx;
}

187
static int ogg_new_buf(struct ogg *ogg, int idx)
188
{
189
    struct ogg_stream *os = ogg->streams + idx;
190
    uint8_t *nb = av_malloc(os->bufsize);
191 192 193 194 195 196 197 198 199 200 201 202
    int size = os->bufpos - os->pstart;
    if(os->buf){
        memcpy(nb, os->buf + os->pstart, size);
        av_free(os->buf);
    }
    os->buf = nb;
    os->bufpos = size;
    os->pstart = 0;

    return 0;
}

203
static int ogg_read_page(AVFormatContext *s, int *str)
204
{
205
    AVIOContext *bc = s->pb;
206 207
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os;
208
    int ret, i = 0;
209 210 211 212
    int flags, nsegs;
    uint64_t gp;
    uint32_t serial;
    int size, idx;
213
    uint8_t sync[4];
214 215
    int sp = 0;

216 217 218
    ret = avio_read(bc, sync, 4);
    if (ret < 4)
        return ret < 0 ? ret : AVERROR_EOF;
219 220 221 222 223 224 225 226 227

    do{
        int c;

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

228
        c = avio_r8(bc);
Anton Khirnov's avatar
Anton Khirnov committed
229
        if (bc->eof_reached)
230
            return AVERROR_EOF;
231 232 233 234 235
        sync[sp++ & 3] = c;
    }while (i++ < MAX_PAGE_SIZE);

    if (i >= MAX_PAGE_SIZE){
        av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
236
        return AVERROR_INVALIDDATA;
237 238
    }

239
    if (avio_r8(bc) != 0)      /* version */
240
        return AVERROR_INVALIDDATA;
241

242
    flags = avio_r8(bc);
243 244
    gp = avio_rl64 (bc);
    serial = avio_rl32 (bc);
Mans Rullgard's avatar
Mans Rullgard committed
245
    avio_skip(bc, 8); /* seq, crc */
246
    nsegs = avio_r8(bc);
247 248 249

    idx = ogg_find_stream (ogg, serial);
    if (idx < 0){
250
        if (ogg->headers) {
251 252 253 254
            int n;

            for (n = 0; n < ogg->nstreams; n++) {
                av_freep(&ogg->streams[n].buf);
255 256
                if (!ogg->state || ogg->state->streams[n].private != ogg->streams[n].private)
                    av_freep(&ogg->streams[n].private);
257 258 259
            }
            ogg->curidx   = -1;
            ogg->nstreams = 0;
260 261 262
            idx = ogg_new_stream(s, serial, 0);
        } else {
            idx = ogg_new_stream(s, serial, 1);
263
        }
264
        if (idx < 0)
265
            return idx;
266 267 268
    }

    os = ogg->streams + idx;
269
    os->page_pos = avio_tell(bc) - 27;
270

271
    if(os->psize > 0)
272 273
        ogg_new_buf(ogg, idx);

274 275 276
    ret = avio_read(bc, os->segments, nsegs);
    if (ret < nsegs)
        return ret < 0 ? ret : AVERROR_EOF;
277 278 279 280 281 282 283 284

    os->nsegs = nsegs;
    os->segp = 0;

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

285
    if (flags & OGG_FLAG_CONT || os->incomplete){
286 287 288 289 290
        if (!os->psize){
            while (os->segp < os->nsegs){
                int seg = os->segments[os->segp++];
                os->pstart += seg;
                if (seg < 255)
291
                    break;
292
            }
293
            os->sync_pos = os->page_pos;
294 295
        }
    }else{
296
        os->psize = 0;
297
        os->sync_pos = os->page_pos;
298 299 300
    }

    if (os->bufsize - os->bufpos < size){
Måns Rullgård's avatar
Måns Rullgård committed
301
        uint8_t *nb = av_malloc (os->bufsize *= 2);
302 303 304 305 306
        memcpy (nb, os->buf, os->bufpos);
        av_free (os->buf);
        os->buf = nb;
    }

307 308 309
    ret = avio_read(bc, os->buf + os->bufpos, size);
    if (ret < size)
        return ret < 0 ? ret : AVERROR_EOF;
310 311 312 313 314 315 316 317 318 319 320

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

    if (str)
        *str = idx;

    return 0;
}

321 322
static int ogg_packet(AVFormatContext *s, int *str, int *dstart, int *dsize,
                      int64_t *fpos)
323
{
324
    struct ogg *ogg = s->priv_data;
325
    int idx, i, ret;
326
    struct ogg_stream *os;
327 328 329
    int complete = 0;
    int segp = 0, psize = 0;

330
    av_dlog(s, "ogg_packet: curidx=%i\n", ogg->curidx);
331 332 333 334 335

    do{
        idx = ogg->curidx;

        while (idx < 0){
336 337 338
            ret = ogg_read_page(s, &idx);
            if (ret < 0)
                return ret;
339 340 341 342
        }

        os = ogg->streams + idx;

343
        av_dlog(s, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
344 345 346 347 348 349
                idx, os->pstart, os->psize, os->segp, os->nsegs);

        if (!os->codec){
            if (os->header < 0){
                os->codec = ogg_find_codec (os->buf, os->bufpos);
                if (!os->codec){
350
                    av_log(s, AV_LOG_WARNING, "Codec not found\n");
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
                    os->header = 0;
                    return 0;
                }
            }else{
                return 0;
            }
        }

        segp = os->segp;
        psize = os->psize;

        while (os->segp < os->nsegs){
            int ss = os->segments[os->segp++];
            os->psize += ss;
            if (ss < 255){
                complete = 1;
                break;
            }
        }

        if (!complete && os->segp == os->nsegs){
            ogg->curidx = -1;
373
            os->incomplete = 1;
374 375 376
        }
    }while (!complete);

377
    av_dlog(s, "ogg_packet: idx %i, frame size %i, start %i\n",
378 379
            idx, os->psize, os->pstart);

380
    if (os->granule == -1)
381
        av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
382

383
    ogg->curidx = idx;
384
    os->incomplete = 0;
385

386 387 388
    if (os->header) {
        os->header = os->codec->header (s, idx);
        if (!os->header){
389 390
            os->segp = segp;
            os->psize = psize;
391

392 393
            // We have reached the first non-header packet in this stream.
            // Unfortunately more header packets may still follow for others,
394
            // but if we continue with header parsing we may lose data packets.
395
            ogg->headers = 1;
396 397 398

            // Update the header state for all streams and
            // compute the data_offset.
399 400
            if (!s->data_offset)
                s->data_offset = os->sync_pos;
401 402 403 404 405 406 407 408
            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);
            }
409
        }else{
410 411
            os->pstart += os->psize;
            os->psize = 0;
412
        }
413
    } else {
414
        os->pflags = 0;
415
        os->pduration = 0;
416 417 418 419
        if (os->codec && os->codec->packet)
            os->codec->packet (s, idx);
        if (str)
            *str = idx;
420 421 422 423
        if (dstart)
            *dstart = os->pstart;
        if (dsize)
            *dsize = os->psize;
424 425
        if (fpos)
            *fpos = os->sync_pos;
426 427
        os->pstart += os->psize;
        os->psize = 0;
428
        os->sync_pos = os->page_pos;
429 430
    }

David Conrad's avatar
David Conrad committed
431 432 433 434 435 436 437 438 439
    // 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;
        }

440 441 442 443 444 445
    if (os->segp == os->nsegs)
        ogg->curidx = -1;

    return 0;
}

446
static int ogg_get_headers(AVFormatContext *s)
447
{
448
    struct ogg *ogg = s->priv_data;
449
    int ret;
450 451

    do{
452 453 454
        ret = ogg_packet(s, NULL, NULL, NULL, NULL);
        if (ret < 0)
            return ret;
455 456
    }while (!ogg->headers);

457
    av_dlog(s, "found headers\n");
458 459 460 461

    return 0;
}

462
static int ogg_get_length(AVFormatContext *s)
463
{
464
    struct ogg *ogg = s->priv_data;
465
    int i;
466
    int64_t size, end;
467

468
    if(!s->pb->seekable)
469
        return 0;
470 471 472 473 474

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

475
    size = avio_size(s->pb);
Måns Rullgård's avatar
Måns Rullgård committed
476 477
    if(size < 0)
        return 0;
478
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
Måns Rullgård's avatar
Måns Rullgård committed
479

480
    ogg_save (s);
481
    avio_seek (s->pb, end, SEEK_SET);
482 483

    while (!ogg_read_page (s, &i)){
484
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
485 486 487 488 489 490
            ogg->streams[i].codec) {
            s->streams[i]->duration =
                ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
            if (s->streams[i]->start_time != AV_NOPTS_VALUE)
                s->streams[i]->duration -= s->streams[i]->start_time;
        }
491 492 493 494 495 496 497
    }

    ogg_restore (s, 0);

    return 0;
}

498
static int ogg_read_header(AVFormatContext *s, AVFormatParameters *ap)
499
{
500
    struct ogg *ogg = s->priv_data;
501
    int ret, i;
502 503
    ogg->curidx = -1;
    //linear headers seek from start
504 505 506
    ret = ogg_get_headers(s);
    if (ret < 0)
        return ret;
507

508 509 510 511
    for (i = 0; i < ogg->nstreams; i++)
        if (ogg->streams[i].header < 0)
            ogg->streams[i].codec = NULL;

512 513 514 515 516 517 518
    //linear granulepos seek from end
    ogg_get_length (s);

    //fill the extradata in the per codec callbacks
    return 0;
}

519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
{
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os = ogg->streams + idx;
    int64_t pts = AV_NOPTS_VALUE;

    if (dts)
        *dts = AV_NOPTS_VALUE;

    if (os->lastpts != AV_NOPTS_VALUE) {
        pts = os->lastpts;
        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;
544
        }
545 546 547
    }
    return pts;
}
548

549
static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
550
{
551 552
    struct ogg *ogg;
    struct ogg_stream *os;
553
    int idx = -1, ret;
554
    int pstart, psize;
David Conrad's avatar
David Conrad committed
555
    int64_t fpos, pts, dts;
556

557
    //Get an ogg packet
David Conrad's avatar
David Conrad committed
558
retry:
559
    do{
560 561 562
        ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
        if (ret < 0)
            return ret;
563 564 565 566 567
    }while (idx < 0 || !s->streams[idx]);

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

David Conrad's avatar
David Conrad committed
568 569 570
    // pflags might not be set until after this
    pts = ogg_calc_pts(s, idx, &dts);

571
    if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
David Conrad's avatar
David Conrad committed
572 573 574
        goto retry;
    os->keyframe_seek = 0;

575
    //Alloc a pkt
576 577 578
    ret = av_new_packet(pkt, psize);
    if (ret < 0)
        return ret;
579
    pkt->stream_index = idx;
580
    memcpy (pkt->data, os->buf + pstart, psize);
David Conrad's avatar
David Conrad committed
581

David Conrad's avatar
David Conrad committed
582 583
    pkt->pts = pts;
    pkt->dts = dts;
584
    pkt->flags = os->pflags;
585
    pkt->duration = os->pduration;
586
    pkt->pos = fpos;
587

588
    return psize;
589 590
}

591
static int ogg_read_close(AVFormatContext *s)
592
{
593
    struct ogg *ogg = s->priv_data;
594 595 596 597
    int i;

    for (i = 0; i < ogg->nstreams; i++){
        av_free (ogg->streams[i].buf);
598
        av_free (ogg->streams[i].private);
599 600 601 602 603
    }
    av_free (ogg->streams);
    return 0;
}

604 605
static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
                                  int64_t *pos_arg, int64_t pos_limit)
606
{
607
    struct ogg *ogg = s->priv_data;
608
    AVIOContext *bc = s->pb;
609
    int64_t pts = AV_NOPTS_VALUE;
610
    int i = -1;
611
    avio_seek(bc, *pos_arg, SEEK_SET);
612 613
    ogg_reset(ogg);

614
    while (avio_tell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
615
        if (i == stream_index) {
616
            struct ogg_stream *os = ogg->streams + stream_index;
617
            pts = ogg_calc_pts(s, i, NULL);
618
            if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
David Conrad's avatar
David Conrad committed
619
                pts = AV_NOPTS_VALUE;
620
        }
621 622
        if (pts != AV_NOPTS_VALUE)
            break;
623 624 625
    }
    ogg_reset(ogg);
    return pts;
626 627
}

628 629
static int ogg_read_seek(AVFormatContext *s, int stream_index,
                         int64_t timestamp, int flags)
David Conrad's avatar
David Conrad committed
630 631 632 633 634 635 636
{
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os = ogg->streams + stream_index;
    int ret;

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

641
    ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
642
    os = ogg->streams + stream_index;
David Conrad's avatar
David Conrad committed
643 644 645 646 647
    if (ret < 0)
        os->keyframe_seek = 0;
    return ret;
}

648 649
static int ogg_probe(AVProbeData *p)
{
650
    if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
651
        return AVPROBE_SCORE_MAX;
652
    return 0;
653 654
}

655
AVInputFormat ff_ogg_demuxer = {
656 657 658 659 660 661 662 663 664 665 666
    .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",
    .flags          = AVFMT_GENERIC_INDEX,
667
};