• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/ffmpeg/libavformat/
1/*
2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
5 *
6 */
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#include "oggdec.h"
35#include "avformat.h"
36#include "vorbiscomment.h"
37
38#define MAX_PAGE_SIZE 65307
39#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40
41static const struct ogg_codec * const ogg_codecs[] = {
42    &ff_skeleton_codec,
43    &ff_dirac_codec,
44    &ff_speex_codec,
45    &ff_vorbis_codec,
46    &ff_theora_codec,
47    &ff_flac_codec,
48    &ff_old_dirac_codec,
49    &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    NULL
55};
56
57//FIXME We could avoid some structure duplication
58static int
59ogg_save (AVFormatContext * s)
60{
61    struct ogg *ogg = s->priv_data;
62    struct ogg_state *ost =
63        av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
64    int i;
65    ost->pos = url_ftell (s->pb);
66    ost->curidx = ogg->curidx;
67    ost->next = ogg->state;
68    ost->nstreams = ogg->nstreams;
69    memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
70
71    for (i = 0; i < ogg->nstreams; i++){
72        struct ogg_stream *os = ogg->streams + i;
73        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
83static int
84ogg_restore (AVFormatContext * s, int discard)
85{
86    struct ogg *ogg = s->priv_data;
87    ByteIOContext *bc = s->pb;
88    struct ogg_state *ost = ogg->state;
89    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        ogg->nstreams = ost->nstreams;
103        memcpy(ogg->streams, ost->streams,
104               ost->nstreams * sizeof(*ogg->streams));
105    }
106
107    av_free (ost);
108
109    return 0;
110}
111
112static int
113ogg_reset (struct ogg * ogg)
114{
115    int i;
116
117    for (i = 0; i < ogg->nstreams; i++){
118        struct ogg_stream *os = ogg->streams + i;
119        os->bufpos = 0;
120        os->pstart = 0;
121        os->psize = 0;
122        os->granule = -1;
123        os->lastpts = AV_NOPTS_VALUE;
124        os->lastdts = AV_NOPTS_VALUE;
125        os->sync_pos = -1;
126        os->page_pos = 0;
127        os->nsegs = 0;
128        os->segp = 0;
129        os->incomplete = 0;
130    }
131
132    ogg->curidx = -1;
133
134    return 0;
135}
136
137static const struct ogg_codec *
138ogg_find_codec (uint8_t * buf, int size)
139{
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
150static int
151ogg_new_stream (AVFormatContext * s, uint32_t serial)
152{
153
154    struct ogg *ogg = s->priv_data;
155    int idx = ogg->nstreams++;
156    AVStream *st;
157    struct ogg_stream *os;
158
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    os->buf = av_malloc(os->bufsize);
166    os->header = -1;
167
168    st = av_new_stream (s, idx);
169    if (!st)
170        return AVERROR(ENOMEM);
171
172    av_set_pts_info(st, 64, 1, 1000000);
173
174    return idx;
175}
176
177static int
178ogg_new_buf(struct ogg *ogg, int idx)
179{
180    struct ogg_stream *os = ogg->streams + idx;
181    uint8_t *nb = av_malloc(os->bufsize);
182    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
194static int
195ogg_read_page (AVFormatContext * s, int *str)
196{
197    ByteIOContext *bc = s->pb;
198    struct ogg *ogg = s->priv_data;
199    struct ogg_stream *os;
200    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    uint8_t sync[4];
208    int sp = 0;
209
210    if (get_buffer (bc, sync, 4) < 4)
211        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    gp = get_le64 (bc);
237    serial = get_le32 (bc);
238    seq = get_le32 (bc);
239    crc = get_le32 (bc);
240    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    os->page_pos = url_ftell(bc) - 27;
251
252    if(os->psize > 0)
253        ogg_new_buf(ogg, idx);
254
255    if (get_buffer (bc, os->segments, nsegs) < nsegs)
256        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    if (flags & OGG_FLAG_CONT || os->incomplete){
266        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                    break;
272            }
273            os->sync_pos = os->page_pos;
274        }
275    }else{
276        os->psize = 0;
277        os->sync_pos = os->page_pos;
278    }
279
280    if (os->bufsize - os->bufpos < size){
281        uint8_t *nb = av_malloc (os->bufsize *= 2);
282        memcpy (nb, os->buf, os->bufpos);
283        av_free (os->buf);
284        os->buf = nb;
285    }
286
287    if (get_buffer (bc, os->buf + os->bufpos, size) < size)
288        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
300static int
301ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos)
302{
303    struct ogg *ogg = s->priv_data;
304    int idx, i;
305    struct ogg_stream *os;
306    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            os->incomplete = 1;
356        }
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    if (os->granule == -1)
366        av_log(s, AV_LOG_WARNING, "Page at %lld is missing granule\n", os->page_pos);
367
368    ogg->curidx = idx;
369    os->incomplete = 0;
370
371    if (os->header) {
372        os->header = os->codec->header (s, idx);
373        if (!os->header){
374            os->segp = segp;
375            os->psize = psize;
376            if (!ogg->headers)
377                s->data_offset = os->sync_pos;
378            ogg->headers = 1;
379        }else{
380            os->pstart += os->psize;
381            os->psize = 0;
382        }
383    } else {
384        os->pflags = 0;
385        os->pduration = 0;
386        if (os->codec && os->codec->packet)
387            os->codec->packet (s, idx);
388        if (str)
389            *str = idx;
390        if (dstart)
391            *dstart = os->pstart;
392        if (dsize)
393            *dsize = os->psize;
394        if (fpos)
395            *fpos = os->sync_pos;
396        os->pstart += os->psize;
397        os->psize = 0;
398        os->sync_pos = os->page_pos;
399    }
400
401    // determine whether there are more complete packets in this page
402    // if not, the page's granule will apply to this packet
403    os->page_end = 1;
404    for (i = os->segp; i < os->nsegs; i++)
405        if (os->segments[i] < 255) {
406            os->page_end = 0;
407            break;
408        }
409
410    if (os->segp == os->nsegs)
411        ogg->curidx = -1;
412
413    return 0;
414}
415
416static int
417ogg_get_headers (AVFormatContext * s)
418{
419    struct ogg *ogg = s->priv_data;
420
421    do{
422        if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0)
423            return -1;
424    }while (!ogg->headers);
425
426#if 0
427    av_log (s, AV_LOG_DEBUG, "found headers\n");
428#endif
429
430    return 0;
431}
432
433static int
434ogg_get_length (AVFormatContext * s)
435{
436    struct ogg *ogg = s->priv_data;
437    int i;
438    int64_t size, end;
439
440    if(url_is_streamed(s->pb))
441        return 0;
442
443// already set
444    if (s->duration != AV_NOPTS_VALUE)
445        return 0;
446
447    size = url_fsize(s->pb);
448    if(size < 0)
449        return 0;
450    end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
451
452    ogg_save (s);
453    url_fseek (s->pb, end, SEEK_SET);
454
455    while (!ogg_read_page (s, &i)){
456        if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
457            ogg->streams[i].codec) {
458            s->streams[i]->duration =
459                ogg_gptopts (s, i, ogg->streams[i].granule, NULL);
460            if (s->streams[i]->start_time != AV_NOPTS_VALUE)
461                s->streams[i]->duration -= s->streams[i]->start_time;
462        }
463    }
464
465    ogg_restore (s, 0);
466
467    return 0;
468}
469
470
471static int
472ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
473{
474    struct ogg *ogg = s->priv_data;
475    int i;
476    ogg->curidx = -1;
477    //linear headers seek from start
478    if (ogg_get_headers (s) < 0){
479        return -1;
480    }
481
482    for (i = 0; i < ogg->nstreams; i++)
483        if (ogg->streams[i].header < 0)
484            ogg->streams[i].codec = NULL;
485
486    //linear granulepos seek from end
487    ogg_get_length (s);
488
489    //fill the extradata in the per codec callbacks
490    return 0;
491}
492
493static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
494{
495    struct ogg *ogg = s->priv_data;
496    struct ogg_stream *os = ogg->streams + idx;
497    int64_t pts = AV_NOPTS_VALUE;
498
499    if (dts)
500        *dts = AV_NOPTS_VALUE;
501
502    if (os->lastpts != AV_NOPTS_VALUE) {
503        pts = os->lastpts;
504        os->lastpts = AV_NOPTS_VALUE;
505    }
506    if (os->lastdts != AV_NOPTS_VALUE) {
507        if (dts)
508            *dts = os->lastdts;
509        os->lastdts = AV_NOPTS_VALUE;
510    }
511    if (os->page_end) {
512        if (os->granule != -1LL) {
513            if (os->codec && os->codec->granule_is_start)
514                pts = ogg_gptopts(s, idx, os->granule, dts);
515            else
516                os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
517            os->granule = -1LL;
518        }
519    }
520    return pts;
521}
522
523static int
524ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
525{
526    struct ogg *ogg;
527    struct ogg_stream *os;
528    int idx = -1;
529    int pstart, psize;
530    int64_t fpos, pts, dts;
531
532    //Get an ogg packet
533retry:
534    do{
535        if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0)
536            return AVERROR(EIO);
537    }while (idx < 0 || !s->streams[idx]);
538
539    ogg = s->priv_data;
540    os = ogg->streams + idx;
541
542    // pflags might not be set until after this
543    pts = ogg_calc_pts(s, idx, &dts);
544
545    if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
546        goto retry;
547    os->keyframe_seek = 0;
548
549    //Alloc a pkt
550    if (av_new_packet (pkt, psize) < 0)
551        return AVERROR(EIO);
552    pkt->stream_index = idx;
553    memcpy (pkt->data, os->buf + pstart, psize);
554
555    pkt->pts = pts;
556    pkt->dts = dts;
557    pkt->flags = os->pflags;
558    pkt->duration = os->pduration;
559    pkt->pos = fpos;
560
561    return psize;
562}
563
564
565static int
566ogg_read_close (AVFormatContext * s)
567{
568    struct ogg *ogg = s->priv_data;
569    int i;
570
571    for (i = 0; i < ogg->nstreams; i++){
572        av_free (ogg->streams[i].buf);
573        av_free (ogg->streams[i].private);
574    }
575    av_free (ogg->streams);
576    return 0;
577}
578
579
580static int64_t
581ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
582                    int64_t pos_limit)
583{
584    struct ogg *ogg = s->priv_data;
585    struct ogg_stream *os = ogg->streams + stream_index;
586    ByteIOContext *bc = s->pb;
587    int64_t pts = AV_NOPTS_VALUE;
588    int i;
589    url_fseek(bc, *pos_arg, SEEK_SET);
590    ogg_reset(ogg);
591
592    while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) {
593        if (i == stream_index) {
594            pts = ogg_calc_pts(s, i, NULL);
595            if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
596                pts = AV_NOPTS_VALUE;
597        }
598        if (pts != AV_NOPTS_VALUE)
599            break;
600    }
601    ogg_reset(ogg);
602    return pts;
603}
604
605static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
606{
607    struct ogg *ogg = s->priv_data;
608    struct ogg_stream *os = ogg->streams + stream_index;
609    int ret;
610
611    // Try seeking to a keyframe first. If this fails (very possible),
612    // av_seek_frame will fall back to ignoring keyframes
613    if (s->streams[stream_index]->codec->codec_type == AVMEDIA_TYPE_VIDEO
614        && !(flags & AVSEEK_FLAG_ANY))
615        os->keyframe_seek = 1;
616
617    ret = av_seek_frame_binary(s, stream_index, timestamp, flags);
618    if (ret < 0)
619        os->keyframe_seek = 0;
620    return ret;
621}
622
623static int ogg_probe(AVProbeData *p)
624{
625    if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
626        p->buf[2] == 'g' && p->buf[3] == 'S' &&
627        p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
628        return AVPROBE_SCORE_MAX;
629    else
630        return 0;
631}
632
633AVInputFormat ogg_demuxer = {
634    "ogg",
635    NULL_IF_CONFIG_SMALL("Ogg"),
636    sizeof (struct ogg),
637    ogg_probe,
638    ogg_read_header,
639    ogg_read_packet,
640    ogg_read_close,
641    ogg_read_seek,
642    ogg_read_timestamp,
643    .extensions = "ogg",
644    .metadata_conv = ff_vorbiscomment_metadata_conv,
645    .flags = AVFMT_GENERIC_INDEX,
646};
647