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

#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
typedef struct TheoraParams {
33 34
    int gpshift;
    int gpmask;
35
    unsigned version;
36
} TheoraParams;
37

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

48
    if (!(os->buf[os->pstart] & 0x80))
49 50
        return 0;

51
    if (!thp) {
52
        thp = av_mallocz(sizeof(*thp));
53 54
        if (!thp)
            return AVERROR(ENOMEM);
55
        os->private = thp;
56 57
    }

58 59
    switch (os->buf[os->pstart]) {
    case 0x80: {
60
        GetBitContext gb;
61
        AVRational timebase;
62

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

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

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

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

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

81
        if (thp->version >= 0x030200) {
82 83
            int width  = get_bits_long(&gb, 24);
            int height = get_bits_long(&gb, 24);
84 85 86 87
            if (width  <= st->codecpar->width  && width  > st->codecpar->width  - 16 &&
                height <= st->codecpar->height && height > st->codecpar->height - 16) {
                st->codecpar->width  = width;
                st->codecpar->height = height;
88
            }
89 90

            skip_bits(&gb, 16);
91
        }
92

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

102 103
        st->sample_aspect_ratio.num = get_bits_long(&gb, 24);
        st->sample_aspect_ratio.den = get_bits_long(&gb, 24);
104

105
        if (thp->version >= 0x030200)
106
            skip_bits_long(&gb, 38);
107
        if (thp->version >= 0x304000)
108 109
            skip_bits(&gb, 2);

110
        thp->gpshift = get_bits(&gb, 5);
111
        thp->gpmask  = (1 << thp->gpshift) - 1;
112

113 114
        st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
        st->codecpar->codec_id   = AV_CODEC_ID_THEORA;
115
        st->need_parsing      = AVSTREAM_PARSE_HEADERS;
116 117 118
    }
    break;
    case 0x81:
119
        ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7, os->psize - 7);
120 121
    case 0x82:
        if (!thp->version)
122
            return AVERROR_INVALIDDATA;
123 124
        break;
    default:
125
        return AVERROR_INVALIDDATA;
126 127
    }

128
    if ((err = av_reallocp(&st->codecpar->extradata,
129
                           cds + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) {
130
        st->codecpar->extradata_size = 0;
131
        return err;
132
    }
133
    cdp    = st->codecpar->extradata + st->codecpar->extradata_size;
134 135
    *cdp++ = os->psize >> 8;
    *cdp++ = os->psize & 0xff;
136
    memcpy(cdp, os->buf + os->pstart, os->psize);
137
    st->codecpar->extradata_size = cds;
138

Måns Rullgård's avatar
Måns Rullgård committed
139
    return 1;
140 141
}

142 143
static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
                               int64_t *dts)
144
{
145
    struct ogg *ogg       = ctx->priv_data;
146
    struct ogg_stream *os = ogg->streams + idx;
147
    TheoraParams *thp     = os->private;
148 149 150 151 152 153 154
    uint64_t iframe, pframe;

    if (!thp)
        return AV_NOPTS_VALUE;

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

156 157 158
    if (thp->version < 0x030201)
        iframe++;

159
    if (!pframe)
160
        os->pflags |= AV_PKT_FLAG_KEY;
161

162 163 164
    if (dts)
        *dts = iframe + pframe;

165
    return iframe + pframe;
166 167
}

168
const struct ogg_codec ff_theora_codec = {
169
    .magic     = "\200theora",
170
    .magicsize = 7,
171 172
    .header    = theora_header,
    .gptopts   = theora_gptopts,
173
    .nb_header = 3,
174
};