Statistics
| Branch: | Revision:

ffmpeg / libavformat / oggdec.c @ e63a3628

History | View | Annotate | Download (16.1 KB)

1 9146ca37 Måns Rullgård
/*
2
 * Ogg bitstream support
3
 * Luca Barbato <lu_zero@gentoo.org>
4
 * Based on tcvp implementation
5 115329f1 Diego Biurrun
 *
6 9146ca37 Måns Rullgård
 */
7
8
/**
9
    Copyright (C) 2005  Michael Ahlberg, Måns Rullgård
10

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

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

22
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29
    DEALINGS IN THE SOFTWARE.
30
**/
31
32
33
#include <stdio.h>
34 a0ddef24 Diego Biurrun
#include "oggdec.h"
35 9146ca37 Måns Rullgård
#include "avformat.h"
36 66061a12 James Darnley
#include "vorbiscomment.h"
37 9146ca37 Måns Rullgård
38
#define MAX_PAGE_SIZE 65307
39
#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40
41 77be08ee Måns Rullgård
static const struct ogg_codec * const ogg_codecs[] = {
42 32ad8692 David Conrad
    &ff_skeleton_codec,
43 24ca518b David Conrad
    &ff_dirac_codec,
44 547ea47d Reimar Döffinger
    &ff_speex_codec,
45
    &ff_vorbis_codec,
46
    &ff_theora_codec,
47
    &ff_flac_codec,
48 24ca518b David Conrad
    &ff_old_dirac_codec,
49 547ea47d Reimar Döffinger
    &ff_old_flac_codec,
50
    &ff_ogm_video_codec,
51
    &ff_ogm_audio_codec,
52
    &ff_ogm_text_codec,
53
    &ff_ogm_old_codec,
54 9146ca37 Måns Rullgård
    NULL
55
};
56
57
//FIXME We could avoid some structure duplication
58
static int
59
ogg_save (AVFormatContext * s)
60
{
61 77be08ee Måns Rullgård
    struct ogg *ogg = s->priv_data;
62
    struct ogg_state *ost =
63 ad3aa874 Måns Rullgård
        av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
64 9146ca37 Måns Rullgård
    int i;
65 899681cd Björn Axelsson
    ost->pos = url_ftell (s->pb);
66 9146ca37 Måns Rullgård
    ost->curidx = ogg->curidx;
67
    ost->next = ogg->state;
68 20be72c8 Måns Rullgård
    ost->nstreams = ogg->nstreams;
69 9146ca37 Måns Rullgård
    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
70
71
    for (i = 0; i < ogg->nstreams; i++){
72 77be08ee Måns Rullgård
        struct ogg_stream *os = ogg->streams + i;
73 9146ca37 Måns Rullgård
        os->buf = av_malloc (os->bufsize);
74
        memset (os->buf, 0, os->bufsize);
75
        memcpy (os->buf, ost->streams[i].buf, os->bufpos);
76
    }
77
78
    ogg->state = ost;
79
80
    return 0;
81
}
82
83
static int
84
ogg_restore (AVFormatContext * s, int discard)
85
{
86 77be08ee Måns Rullgård
    struct ogg *ogg = s->priv_data;
87 471fe57e Anton Khirnov
    AVIOContext *bc = s->pb;
88 77be08ee Måns Rullgård
    struct ogg_state *ost = ogg->state;
89 9146ca37 Måns Rullgård
    int i;
90
91
    if (!ost)
92
        return 0;
93
94
    ogg->state = ost->next;
95
96
    if (!discard){
97
        for (i = 0; i < ogg->nstreams; i++)
98
            av_free (ogg->streams[i].buf);
99
100
        url_fseek (bc, ost->pos, SEEK_SET);
101
        ogg->curidx = ost->curidx;
102 20be72c8 Måns Rullgård
        ogg->nstreams = ost->nstreams;
103
        memcpy(ogg->streams, ost->streams,
104
               ost->nstreams * sizeof(*ogg->streams));
105 9146ca37 Måns Rullgård
    }
106
107
    av_free (ost);
108
109
    return 0;
110
}
111
112
static int
113 77be08ee Måns Rullgård
ogg_reset (struct ogg * ogg)
114 9146ca37 Måns Rullgård
{
115
    int i;
116
117
    for (i = 0; i < ogg->nstreams; i++){
118 77be08ee Måns Rullgård
        struct ogg_stream *os = ogg->streams + i;
119 9146ca37 Måns Rullgård
        os->bufpos = 0;
120
        os->pstart = 0;
121
        os->psize = 0;
122
        os->granule = -1;
123 5e15c7d9 David Conrad
        os->lastpts = AV_NOPTS_VALUE;
124 2d4970d8 David Conrad
        os->lastdts = AV_NOPTS_VALUE;
125 73823cb9 David Conrad
        os->sync_pos = -1;
126
        os->page_pos = 0;
127 9146ca37 Måns Rullgård
        os->nsegs = 0;
128
        os->segp = 0;
129 ecc0027b David Conrad
        os->incomplete = 0;
130 9146ca37 Måns Rullgård
    }
131
132
    ogg->curidx = -1;
133
134
    return 0;
135
}
136
137 77be08ee Måns Rullgård
static const struct ogg_codec *
138 2d2f443d Måns Rullgård
ogg_find_codec (uint8_t * buf, int size)
139 9146ca37 Måns Rullgård
{
140
    int i;
141
142
    for (i = 0; ogg_codecs[i]; i++)
143
        if (size >= ogg_codecs[i]->magicsize &&
144
            !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
145
            return ogg_codecs[i];
146
147
    return NULL;
148
}
149
150
static int
151
ogg_new_stream (AVFormatContext * s, uint32_t serial)
152
{
153
154 77be08ee Måns Rullgård
    struct ogg *ogg = s->priv_data;
155 9146ca37 Måns Rullgård
    int idx = ogg->nstreams++;
156
    AVStream *st;
157 77be08ee Måns Rullgård
    struct ogg_stream *os;
158 9146ca37 Måns Rullgård
159
    ogg->streams = av_realloc (ogg->streams,
160
                               ogg->nstreams * sizeof (*ogg->streams));
161
    memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
162
    os = ogg->streams + idx;
163
    os->serial = serial;
164
    os->bufsize = DECODER_BUFFER_SIZE;
165 40c5e1fa Måns Rullgård
    os->buf = av_malloc(os->bufsize);
166 9146ca37 Måns Rullgård
    os->header = -1;
167
168
    st = av_new_stream (s, idx);
169
    if (!st)
170 769e10f0 Panagiotis Issaris
        return AVERROR(ENOMEM);
171 9146ca37 Måns Rullgård
172
    av_set_pts_info(st, 64, 1, 1000000);
173
174
    return idx;
175
}
176
177
static int
178 77be08ee Måns Rullgård
ogg_new_buf(struct ogg *ogg, int idx)
179 12a195e3 Måns Rullgård
{
180 77be08ee Måns Rullgård
    struct ogg_stream *os = ogg->streams + idx;
181 ea02862a Måns Rullgård
    uint8_t *nb = av_malloc(os->bufsize);
182 12a195e3 Måns Rullgård
    int size = os->bufpos - os->pstart;
183
    if(os->buf){
184
        memcpy(nb, os->buf + os->pstart, size);
185
        av_free(os->buf);
186
    }
187
    os->buf = nb;
188
    os->bufpos = size;
189
    os->pstart = 0;
190
191
    return 0;
192
}
193
194
static int
195 9146ca37 Måns Rullgård
ogg_read_page (AVFormatContext * s, int *str)
196
{
197 471fe57e Anton Khirnov
    AVIOContext *bc = s->pb;
198 77be08ee Måns Rullgård
    struct ogg *ogg = s->priv_data;
199
    struct ogg_stream *os;
200 9146ca37 Måns Rullgård
    int i = 0;
201
    int flags, nsegs;
202
    uint64_t gp;
203
    uint32_t serial;
204
    uint32_t seq;
205
    uint32_t crc;
206
    int size, idx;
207 191e8ca7 Måns Rullgård
    uint8_t sync[4];
208 9146ca37 Måns Rullgård
    int sp = 0;
209
210 e63a3628 Anton Khirnov
    if (avio_read (bc, sync, 4) < 4)
211 9146ca37 Måns Rullgård
        return -1;
212
213
    do{
214
        int c;
215
216
        if (sync[sp & 3] == 'O' &&
217
            sync[(sp + 1) & 3] == 'g' &&
218
            sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
219
            break;
220
221
        c = url_fgetc (bc);
222
        if (c < 0)
223
            return -1;
224
        sync[sp++ & 3] = c;
225
    }while (i++ < MAX_PAGE_SIZE);
226
227
    if (i >= MAX_PAGE_SIZE){
228
        av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
229
        return -1;
230
    }
231
232
    if (url_fgetc (bc) != 0)      /* version */
233
        return -1;
234
235
    flags = url_fgetc (bc);
236 e63a3628 Anton Khirnov
    gp = avio_rl64 (bc);
237
    serial = avio_rl32 (bc);
238
    seq = avio_rl32 (bc);
239
    crc = avio_rl32 (bc);
240 9146ca37 Måns Rullgård
    nsegs = url_fgetc (bc);
241
242
    idx = ogg_find_stream (ogg, serial);
243
    if (idx < 0){
244
        idx = ogg_new_stream (s, serial);
245
        if (idx < 0)
246
            return -1;
247
    }
248
249
    os = ogg->streams + idx;
250 73823cb9 David Conrad
    os->page_pos = url_ftell(bc) - 27;
251 9146ca37 Måns Rullgård
252 40c5e1fa Måns Rullgård
    if(os->psize > 0)
253 12a195e3 Måns Rullgård
        ogg_new_buf(ogg, idx);
254
255 e63a3628 Anton Khirnov
    if (avio_read (bc, os->segments, nsegs) < nsegs)
256 9146ca37 Måns Rullgård
        return -1;
257
258
    os->nsegs = nsegs;
259
    os->segp = 0;
260
261
    size = 0;
262
    for (i = 0; i < nsegs; i++)
263
        size += os->segments[i];
264
265 ecc0027b David Conrad
    if (flags & OGG_FLAG_CONT || os->incomplete){
266 9146ca37 Måns Rullgård
        if (!os->psize){
267
            while (os->segp < os->nsegs){
268
                int seg = os->segments[os->segp++];
269
                os->pstart += seg;
270
                if (seg < 255)
271 bad4a6bb Peter Ross
                    break;
272 9146ca37 Måns Rullgård
            }
273 73823cb9 David Conrad
            os->sync_pos = os->page_pos;
274 9146ca37 Måns Rullgård
        }
275
    }else{
276 bad4a6bb Peter Ross
        os->psize = 0;
277 73823cb9 David Conrad
        os->sync_pos = os->page_pos;
278 9146ca37 Måns Rullgård
    }
279
280
    if (os->bufsize - os->bufpos < size){
281 2d2f443d Måns Rullgård
        uint8_t *nb = av_malloc (os->bufsize *= 2);
282 9146ca37 Måns Rullgård
        memcpy (nb, os->buf, os->bufpos);
283
        av_free (os->buf);
284
        os->buf = nb;
285
    }
286
287 e63a3628 Anton Khirnov
    if (avio_read (bc, os->buf + os->bufpos, size) < size)
288 9146ca37 Måns Rullgård
        return -1;
289
290
    os->bufpos += size;
291
    os->granule = gp;
292
    os->flags = flags;
293
294
    if (str)
295
        *str = idx;
296
297
    return 0;
298
}
299
300
static int
301 73823cb9 David Conrad
ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
302 9146ca37 Måns Rullgård
{
303 77be08ee Måns Rullgård
    struct ogg *ogg = s->priv_data;
304 5e15c7d9 David Conrad
    int idx, i;
305 77be08ee Måns Rullgård
    struct ogg_stream *os;
306 9146ca37 Måns Rullgård
    int complete = 0;
307
    int segp = 0, psize = 0;
308
309
#if 0
310
    av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
311
#endif
312
313
    do{
314
        idx = ogg->curidx;
315
316
        while (idx < 0){
317
            if (ogg_read_page (s, &idx) < 0)
318
                return -1;
319
        }
320
321
        os = ogg->streams + idx;
322
323
#if 0
324
        av_log (s, AV_LOG_DEBUG,
325
                "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
326
                idx, os->pstart, os->psize, os->segp, os->nsegs);
327
#endif
328
329
        if (!os->codec){
330
            if (os->header < 0){
331
                os->codec = ogg_find_codec (os->buf, os->bufpos);
332
                if (!os->codec){
333
                    os->header = 0;
334
                    return 0;
335
                }
336
            }else{
337
                return 0;
338
            }
339
        }
340
341
        segp = os->segp;
342
        psize = os->psize;
343
344
        while (os->segp < os->nsegs){
345
            int ss = os->segments[os->segp++];
346
            os->psize += ss;
347
            if (ss < 255){
348
                complete = 1;
349
                break;
350
            }
351
        }
352
353
        if (!complete && os->segp == os->nsegs){
354
            ogg->curidx = -1;
355 ecc0027b David Conrad
            os->incomplete = 1;
356 9146ca37 Måns Rullgård
        }
357
    }while (!complete);
358
359
#if 0
360
    av_log (s, AV_LOG_DEBUG,
361
            "ogg_packet: idx %i, frame size %i, start %i\n",
362
            idx, os->psize, os->pstart);
363
#endif
364
365 adc725b5 David Conrad
    if (os->granule == -1)
366 461628c6 Eli Friedman
        av_log(s, AV_LOG_WARNING, "Page at %"PRId64" is missing granule\n", os->page_pos);
367 adc725b5 David Conrad
368 9146ca37 Måns Rullgård
    ogg->curidx = idx;
369 ecc0027b David Conrad
    os->incomplete = 0;
370 9146ca37 Måns Rullgård
371 81b743eb David Conrad
    if (os->header) {
372
        os->header = os->codec->header (s, idx);
373
        if (!os->header){
374 bad4a6bb Peter Ross
            os->segp = segp;
375
            os->psize = psize;
376 365d8e47 Aaron Colwell
377 94dfea71 Reimar Döffinger
            // We have reached the first non-header packet in this stream.
378
            // Unfortunately more header packets may still follow for others,
379
            // so we reset this later unless we are done with the headers
380
            // for all streams.
381 bad4a6bb Peter Ross
            ogg->headers = 1;
382 365d8e47 Aaron Colwell
383
            // Update the header state for all streams and
384
            // compute the data_offset.
385 94dfea71 Reimar Döffinger
            if (!s->data_offset)
386
                s->data_offset = os->sync_pos;
387 365d8e47 Aaron Colwell
            for (i = 0; i < ogg->nstreams; i++) {
388
                struct ogg_stream *cur_os = ogg->streams + i;
389
                if (cur_os->header > 0)
390 94dfea71 Reimar Döffinger
                    ogg->headers = 0;
391 365d8e47 Aaron Colwell
392
                // if we have a partial non-header packet, its start is
393
                // obviously at or after the data start
394
                if (cur_os->incomplete)
395
                    s->data_offset = FFMIN(s->data_offset, cur_os->sync_pos);
396
            }
397 9146ca37 Måns Rullgård
        }else{
398 bad4a6bb Peter Ross
            os->pstart += os->psize;
399
            os->psize = 0;
400 9146ca37 Måns Rullgård
        }
401 81b743eb David Conrad
    } else {
402 e1a794b2 Måns Rullgård
        os->pflags = 0;
403 15299b38 Justin Ruggles
        os->pduration = 0;
404 9146ca37 Måns Rullgård
        if (os->codec && os->codec->packet)
405
            os->codec->packet (s, idx);
406
        if (str)
407
            *str = idx;
408 12a195e3 Måns Rullgård
        if (dstart)
409
            *dstart = os->pstart;
410
        if (dsize)
411
            *dsize = os->psize;
412 73823cb9 David Conrad
        if (fpos)
413
            *fpos = os->sync_pos;
414 12a195e3 Måns Rullgård
        os->pstart += os->psize;
415
        os->psize = 0;
416 73823cb9 David Conrad
        os->sync_pos = os->page_pos;
417 9146ca37 Måns Rullgård
    }
418
419 5e15c7d9 David Conrad
    // determine whether there are more complete packets in this page
420
    // if not, the page's granule will apply to this packet
421
    os->page_end = 1;
422
    for (i = os->segp; i < os->nsegs; i++)
423
        if (os->segments[i] < 255) {
424
            os->page_end = 0;
425
            break;
426
        }
427
428 9146ca37 Måns Rullgård
    if (os->segp == os->nsegs)
429
        ogg->curidx = -1;
430
431
    return 0;
432
}
433
434
static int
435
ogg_get_headers (AVFormatContext * s)
436
{
437 77be08ee Måns Rullgård
    struct ogg *ogg = s->priv_data;
438 9146ca37 Måns Rullgård
439
    do{
440 73823cb9 David Conrad
        if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
441 9146ca37 Måns Rullgård
            return -1;
442
    }while (!ogg->headers);
443
444
#if 0
445
    av_log (s, AV_LOG_DEBUG, "found headers\n");
446
#endif
447
448
    return 0;
449
}
450
451
static int
452
ogg_get_length (AVFormatContext * s)
453
{
454 77be08ee Måns Rullgård
    struct ogg *ogg = s->priv_data;
455 44a088ea David Conrad
    int i;
456 bc5c918e Diego Biurrun
    int64_t size, end;
457 69599eea Måns Rullgård
458 ceeacce6 Aurelien Jacobs
    if(url_is_streamed(s->pb))
459 69599eea Måns Rullgård
        return 0;
460 9146ca37 Måns Rullgård
461
// already set
462
    if (s->duration != AV_NOPTS_VALUE)
463
        return 0;
464
465 899681cd Björn Axelsson
    size = url_fsize(s->pb);
466 56466d7b Måns Rullgård
    if(size < 0)
467
        return 0;
468 ddd94932 David Conrad
    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
469 56466d7b Måns Rullgård
470 9146ca37 Måns Rullgård
    ogg_save (s);
471 899681cd Björn Axelsson
    url_fseek (s->pb, end, SEEK_SET);
472 9146ca37 Måns Rullgård
473
    while (!ogg_read_page (s, &i)){
474 e22f2aaf Måns Rullgård
        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
475 44a088ea David Conrad
            ogg->streams[i].codec) {
476
            s->streams[i]->duration =
477
                ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
478
            if (s->streams[i]->start_time != AV_NOPTS_VALUE)
479
                s->streams[i]->duration -= s->streams[i]->start_time;
480
        }
481 9146ca37 Måns Rullgård
    }
482
483
    ogg_restore (s, 0);
484
485
    return 0;
486
}
487
488
489
static int
490
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
491
{
492 77be08ee Måns Rullgård
    struct ogg *ogg = s->priv_data;
493 c9da676d Reimar Döffinger
    int i;
494 9146ca37 Måns Rullgård
    ogg->curidx = -1;
495
    //linear headers seek from start
496
    if (ogg_get_headers (s) < 0){
497 bad4a6bb Peter Ross
        return -1;
498 9146ca37 Måns Rullgård
    }
499
500 c9da676d Reimar Döffinger
    for (i = 0; i < ogg->nstreams; i++)
501
        if (ogg->streams[i].header < 0)
502
            ogg->streams[i].codec = NULL;
503
504 9146ca37 Måns Rullgård
    //linear granulepos seek from end
505
    ogg_get_length (s);
506
507
    //fill the extradata in the per codec callbacks
508
    return 0;
509
}
510
511 6abaa272 David Conrad
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
512
{
513
    struct ogg *ogg = s->priv_data;
514
    struct ogg_stream *os = ogg->streams + idx;
515
    int64_t pts = AV_NOPTS_VALUE;
516
517
    if (dts)
518
        *dts = AV_NOPTS_VALUE;
519
520
    if (os->lastpts != AV_NOPTS_VALUE) {
521
        pts = os->lastpts;
522
        os->lastpts = AV_NOPTS_VALUE;
523
    }
524
    if (os->lastdts != AV_NOPTS_VALUE) {
525
        if (dts)
526
            *dts = os->lastdts;
527
        os->lastdts = AV_NOPTS_VALUE;
528
    }
529
    if (os->page_end) {
530
        if (os->granule != -1LL) {
531
            if (os->codec && os->codec->granule_is_start)
532
                pts = ogg_gptopts(s, idx, os->granule, dts);
533
            else
534
                os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
535
            os->granule = -1LL;
536 adc725b5 David Conrad
        }
537 6abaa272 David Conrad
    }
538
    return pts;
539
}
540 9146ca37 Måns Rullgård
541
static int
542
ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
543
{
544 77be08ee Måns Rullgård
    struct ogg *ogg;
545
    struct ogg_stream *os;
546 9146ca37 Måns Rullgård
    int idx = -1;
547 12a195e3 Måns Rullgård
    int pstart, psize;
548 d8b91fae David Conrad
    int64_t fpos, pts, dts;
549 9146ca37 Måns Rullgård
550 115329f1 Diego Biurrun
    //Get an ogg packet
551 d8b91fae David Conrad
retry:
552 9146ca37 Måns Rullgård
    do{
553 73823cb9 David Conrad
        if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
554 6f3e0b21 Panagiotis Issaris
            return AVERROR(EIO);
555 9146ca37 Måns Rullgård
    }while (idx < 0 || !s->streams[idx]);
556
557
    ogg = s->priv_data;
558
    os = ogg->streams + idx;
559
560 d8b91fae David Conrad
    // pflags might not be set until after this
561
    pts = ogg_calc_pts(s, idx, &dts);
562
563 cc947f04 Jean-Daniel Dupas
    if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
564 d8b91fae David Conrad
        goto retry;
565
    os->keyframe_seek = 0;
566
567 9146ca37 Måns Rullgård
    //Alloc a pkt
568 12a195e3 Måns Rullgård
    if (av_new_packet (pkt, psize) < 0)
569 6f3e0b21 Panagiotis Issaris
        return AVERROR(EIO);
570 9146ca37 Måns Rullgård
    pkt->stream_index = idx;
571 12a195e3 Måns Rullgård
    memcpy (pkt->data, os->buf + pstart, psize);
572 5e15c7d9 David Conrad
573 d8b91fae David Conrad
    pkt->pts = pts;
574
    pkt->dts = dts;
575 e1a794b2 Måns Rullgård
    pkt->flags = os->pflags;
576 15299b38 Justin Ruggles
    pkt->duration = os->pduration;
577 73823cb9 David Conrad
    pkt->pos = fpos;
578 e1a794b2 Måns Rullgård
579 12a195e3 Måns Rullgård
    return psize;
580 9146ca37 Måns Rullgård
}
581
582
583
static int
584
ogg_read_close (AVFormatContext * s)
585
{
586 77be08ee Måns Rullgård
    struct ogg *ogg = s->priv_data;
587 9146ca37 Måns Rullgård
    int i;
588
589
    for (i = 0; i < ogg->nstreams; i++){
590
        av_free (ogg->streams[i].buf);
591 1ed923ea Måns Rullgård
        av_free (ogg->streams[i].private);
592 9146ca37 Måns Rullgård
    }
593
    av_free (ogg->streams);
594
    return 0;
595
}
596
597
598
static int64_t
599
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
600
                    int64_t pos_limit)
601
{
602 77be08ee Måns Rullgård
    struct ogg *ogg = s->priv_data;
603 d8b91fae David Conrad
    struct ogg_stream *os = ogg->streams + stream_index;
604 471fe57e Anton Khirnov
    AVIOContext *bc = s->pb;
605 a1f29b95 Reimar Döffinger
    int64_t pts = AV_NOPTS_VALUE;
606
    int i;
607
    url_fseek(bc, *pos_arg, SEEK_SET);
608 873d117e David Conrad
    ogg_reset(ogg);
609
610
    while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
611
        if (i == stream_index) {
612
            pts = ogg_calc_pts(s, i, NULL);
613 cc947f04 Jean-Daniel Dupas
            if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
614 d8b91fae David Conrad
                pts = AV_NOPTS_VALUE;
615 a1f29b95 Reimar Döffinger
        }
616 873d117e David Conrad
        if (pts != AV_NOPTS_VALUE)
617
            break;
618 a1f29b95 Reimar Döffinger
    }
619
    ogg_reset(ogg);
620
    return pts;
621 9146ca37 Måns Rullgård
}
622
623 d8b91fae David Conrad
static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
624
{
625
    struct ogg *ogg = s->priv_data;
626
    struct ogg_stream *os = ogg->streams + stream_index;
627
    int ret;
628
629
    // Try seeking to a keyframe first. If this fails (very possible),
630
    // av_seek_frame will fall back to ignoring keyframes
631 72415b2a Stefano Sabatini
    if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
632 d8b91fae David Conrad
        && !(flags & AVSEEK_FLAG_ANY))
633
        os->keyframe_seek = 1;
634
635
    ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
636
    if (ret < 0)
637
        os->keyframe_seek = 0;
638
    return ret;
639
}
640
641 2e70e4aa Måns Rullgård
static int ogg_probe(AVProbeData *p)
642
{
643
    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
644
        p->buf[2] == 'g' && p->buf[3] == 'S' &&
645
        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
646
        return AVPROBE_SCORE_MAX;
647
    else
648
        return 0;
649
}
650
651 66355be3 Diego Elio Pettenò
AVInputFormat ff_ogg_demuxer = {
652 9146ca37 Måns Rullgård
    "ogg",
653 bde15e74 Stefano Sabatini
    NULL_IF_CONFIG_SMALL("Ogg"),
654 77be08ee Måns Rullgård
    sizeof (struct ogg),
655 2e70e4aa Måns Rullgård
    ogg_probe,
656 9146ca37 Måns Rullgård
    ogg_read_header,
657
    ogg_read_packet,
658
    ogg_read_close,
659 d8b91fae David Conrad
    ogg_read_seek,
660 a1f29b95 Reimar Döffinger
    ogg_read_timestamp,
661 9146ca37 Måns Rullgård
    .extensions = "ogg",
662 f1a05185 Reimar Döffinger
    .flags = AVFMT_GENERIC_INDEX,
663 9146ca37 Måns Rullgård
};