oggparsetheora.c 6.24 KB
Newer Older
1
/**
2
      Copyright (C) 2005  Matthieu CASTET, Alex Beregszaszi
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

      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 <stdlib.h>
26
#include "libavutil/bswap.h"
27
#include "libavcodec/get_bits.h"
28
#include "avformat.h"
29
#include "internal.h"
30
#include "oggdec.h"
31

32
struct theora_params {
33 34
    int gpshift;
    int gpmask;
35
    unsigned version;
36
};
37 38 39 40

static int
theora_header (AVFormatContext * s, int idx)
{
41 42
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os = ogg->streams + idx;
43
    AVStream *st = s->streams[idx];
44
    struct theora_params *thp = os->private;
45
    int cds = st->codec->extradata_size + os->psize + 2;
46 47
    uint8_t *cdp;

Måns Rullgård's avatar
Måns Rullgård committed
48
    if(!(os->buf[os->pstart] & 0x80))
49 50 51
        return 0;

    if(!thp){
52 53
        thp = av_mallocz(sizeof(*thp));
        os->private = thp;
54 55
    }

56 57
    switch (os->buf[os->pstart]) {
    case 0x80: {
58
        GetBitContext gb;
59
        int width, height;
60
        AVRational timebase;
61

62 63
        init_get_bits(&gb, os->buf + os->pstart, os->psize*8);

64
        skip_bits_long(&gb, 7*8); /* 0x80"theora" */
65

66 67
        thp->version = get_bits_long(&gb, 24);
        if (thp->version < 0x030100)
68 69
        {
            av_log(s, AV_LOG_ERROR,
70
                "Too old or unsupported Theora (%x)\n", thp->version);
Måns Rullgård's avatar
Måns Rullgård committed
71
            return -1;
72
        }
Måns Rullgård's avatar
Måns Rullgård committed
73

74 75 76
        width  = get_bits(&gb, 16) << 4;
        height = get_bits(&gb, 16) << 4;
        avcodec_set_dimensions(st->codec, width, height);
77

78
        if (thp->version >= 0x030400)
79 80
            skip_bits(&gb, 100);

81
        if (thp->version >= 0x030200) {
David Conrad's avatar
David Conrad committed
82 83 84 85 86
            width  = get_bits_long(&gb, 24);
            height = get_bits_long(&gb, 24);
            if (   width  <= st->codec->width  && width  > st->codec->width-16
                && height <= st->codec->height && height > st->codec->height-16)
                avcodec_set_dimensions(st->codec, width, height);
87 88

            skip_bits(&gb, 16);
89
        }
90 91 92
        timebase.den = get_bits_long(&gb, 32);
        timebase.num = get_bits_long(&gb, 32);
        if (!(timebase.num > 0 && timebase.den > 0)) {
93
            av_log(s, AV_LOG_WARNING, "Invalid time base in theora stream, assuming 25 FPS\n");
94 95
            timebase.num = 1;
            timebase.den = 25;
96
        }
97
        avpriv_set_pts_info(st, 64, timebase.num, timebase.den);
98

99 100
        st->sample_aspect_ratio.num = get_bits_long(&gb, 24);
        st->sample_aspect_ratio.den = get_bits_long(&gb, 24);
101

102
        if (thp->version >= 0x030200)
103
            skip_bits_long(&gb, 38);
104
        if (thp->version >= 0x304000)
105 106
            skip_bits(&gb, 2);

107
        thp->gpshift = get_bits(&gb, 5);
108
        thp->gpmask = (1 << thp->gpshift) - 1;
109

110
        st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
111
        st->codec->codec_id = AV_CODEC_ID_THEORA;
112
        st->need_parsing = AVSTREAM_PARSE_HEADERS;
113 114 115
    }
    break;
    case 0x81:
116
        ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7);
117 118 119 120 121
    case 0x82:
        if (!thp->version)
            return -1;
        break;
    default:
122
        av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
123
        return -1;
124 125
    }

126 127
    st->codec->extradata = av_realloc (st->codec->extradata,
                                       cds + FF_INPUT_BUFFER_PADDING_SIZE);
128
    cdp = st->codec->extradata + st->codec->extradata_size;
129 130 131
    *cdp++ = os->psize >> 8;
    *cdp++ = os->psize & 0xff;
    memcpy (cdp, os->buf + os->pstart, os->psize);
132
    st->codec->extradata_size = cds;
133

Måns Rullgård's avatar
Måns Rullgård committed
134
    return 1;
135 136 137
}

static uint64_t
138
theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, int64_t *dts)
139
{
140 141 142
    struct ogg *ogg = ctx->priv_data;
    struct ogg_stream *os = ogg->streams + idx;
    struct theora_params *thp = os->private;
143 144 145 146 147 148 149
    uint64_t iframe, pframe;

    if (!thp)
        return AV_NOPTS_VALUE;

    iframe = gp >> thp->gpshift;
    pframe = gp & thp->gpmask;
150

151 152 153
    if (thp->version < 0x030201)
        iframe++;

154
    if(!pframe)
155
        os->pflags |= AV_PKT_FLAG_KEY;
156

157 158 159
    if (dts)
        *dts = iframe + pframe;

160
    return iframe + pframe;
161 162
}

163 164 165 166 167 168 169 170 171 172 173
static int theora_packet(AVFormatContext *s, int idx)
{
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os = ogg->streams + idx;
    int duration;

    /* first packet handling
       here we parse the duration of each packet in the first page and compare
       the total duration to the page granule to find the encoder delay and
       set the first timestamp */

174
    if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
175
        int seg;
176 177 178 179 180

        duration = 1;
        for (seg = os->segp; seg < os->nsegs; seg++) {
            if (os->segments[seg] < 255)
                duration ++;
181
        }
182

183
        os->lastpts = os->lastdts   = theora_gptopts(s, idx, os->granule, NULL) - duration;
184 185 186 187 188
        if(s->streams[idx]->start_time == AV_NOPTS_VALUE) {
            s->streams[idx]->start_time = os->lastpts;
            if (s->streams[idx]->duration)
                s->streams[idx]->duration -= s->streams[idx]->start_time;
        }
189 190 191 192 193 194 195 196 197 198
    }

    /* parse packet duration */
    if (os->psize > 0) {
        os->pduration = 1;
    }

    return 0;
}

199
const struct ogg_codec ff_theora_codec = {
200 201 202
    .magic = "\200theora",
    .magicsize = 7,
    .header = theora_header,
203
    .packet = theora_packet,
204 205
    .gptopts = theora_gptopts,
    .nb_header = 3,
206
};