1/**
2 *    Copyright (C) 2005  Matthieu CASTET, Alex Beregszaszi
3 *
4 *    Permission is hereby granted, free of charge, to any person
5 *    obtaining a copy of this software and associated documentation
6 *    files (the "Software"), to deal in the Software without
7 *    restriction, including without limitation the rights to use, copy,
8 *    modify, merge, publish, distribute, sublicense, and/or sell copies
9 *    of the Software, and to permit persons to whom the Software is
10 *    furnished to do so, subject to the following conditions:
11 *
12 *    The above copyright notice and this permission notice shall be
13 *    included in all copies or substantial portions of the Software.
14 *
15 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 *    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 *    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 *    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 *    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 *    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 *    DEALINGS IN THE SOFTWARE.
23 **/
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
32typedef struct TheoraParams {
33    int gpshift;
34    int gpmask;
35    unsigned version;
36} TheoraParams;
37
38static int theora_header(AVFormatContext *s, int idx)
39{
40    struct ogg *ogg       = s->priv_data;
41    struct ogg_stream *os = ogg->streams + idx;
42    AVStream *st          = s->streams[idx];
43    TheoraParams *thp     = os->private;
44    int cds               = st->codec->extradata_size + os->psize + 2;
45    int err;
46    uint8_t *cdp;
47
48    if (!(os->buf[os->pstart] & 0x80))
49        return 0;
50
51    if (!thp) {
52        thp = av_mallocz(sizeof(*thp));
53        if (!thp)
54            return AVERROR(ENOMEM);
55        os->private = thp;
56    }
57
58    switch (os->buf[os->pstart]) {
59    case 0x80: {
60        GetBitContext gb;
61        AVRational timebase;
62
63        init_get_bits(&gb, os->buf + os->pstart, os->psize * 8);
64
65        /* 0x80"theora" */
66        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        }
74
75        st->codec->width  = get_bits(&gb, 16) << 4;
76        st->codec->height = get_bits(&gb, 16) << 4;
77
78        if (thp->version >= 0x030400)
79            skip_bits(&gb, 100);
80
81        if (thp->version >= 0x030200) {
82            int width  = get_bits_long(&gb, 24);
83            int height = get_bits_long(&gb, 24);
84            if (width  <= st->codec->width  && width  > st->codec->width  - 16 &&
85                height <= st->codec->height && height > st->codec->height - 16) {
86                st->codec->width  = width;
87                st->codec->height = height;
88            }
89
90            skip_bits(&gb, 16);
91        }
92
93        timebase.den = get_bits_long(&gb, 32);
94        timebase.num = get_bits_long(&gb, 32);
95        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            timebase.num = 1;
98            timebase.den = 25;
99        }
100        avpriv_set_pts_info(st, 64, timebase.num, timebase.den);
101
102        st->sample_aspect_ratio.num = get_bits_long(&gb, 24);
103        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            skip_bits(&gb, 2);
109
110        thp->gpshift = get_bits(&gb, 5);
111        thp->gpmask  = (1 << thp->gpshift) - 1;
112
113        st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
114        st->codec->codec_id   = AV_CODEC_ID_THEORA;
115        st->need_parsing      = AVSTREAM_PARSE_HEADERS;
116    }
117    break;
118    case 0x81:
119        ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7, 1);
120    case 0x82:
121        if (!thp->version)
122            return AVERROR_INVALIDDATA;
123        break;
124    default:
125        av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
126        return AVERROR_INVALIDDATA;
127    }
128
129    if ((err = av_reallocp(&st->codec->extradata,
130                           cds + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) {
131        st->codec->extradata_size = 0;
132        return err;
133    }
134    memset(st->codec->extradata + cds, 0, FF_INPUT_BUFFER_PADDING_SIZE);
135
136    cdp    = st->codec->extradata + st->codec->extradata_size;
137    *cdp++ = os->psize >> 8;
138    *cdp++ = os->psize & 0xff;
139    memcpy(cdp, os->buf + os->pstart, os->psize);
140    st->codec->extradata_size = cds;
141
142    return 1;
143}
144
145static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
146                               int64_t *dts)
147{
148    struct ogg *ogg       = ctx->priv_data;
149    struct ogg_stream *os = ogg->streams + idx;
150    TheoraParams *thp     = os->private;
151    uint64_t iframe, pframe;
152
153    if (!thp)
154        return AV_NOPTS_VALUE;
155
156    iframe = gp >> thp->gpshift;
157    pframe = gp & thp->gpmask;
158
159    if (thp->version < 0x030201)
160        iframe++;
161
162    if (!pframe)
163        os->pflags |= AV_PKT_FLAG_KEY;
164
165    if (dts)
166        *dts = iframe + pframe;
167
168    return iframe + pframe;
169}
170
171static int theora_packet(AVFormatContext *s, int idx)
172{
173    struct ogg *ogg = s->priv_data;
174    struct ogg_stream *os = ogg->streams + idx;
175    int duration;
176
177    /* first packet handling
178       here we parse the duration of each packet in the first page and compare
179       the total duration to the page granule to find the encoder delay and
180       set the first timestamp */
181
182    if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
183        int seg;
184
185        duration = 1;
186        for (seg = os->segp; seg < os->nsegs; seg++) {
187            if (os->segments[seg] < 255)
188                duration ++;
189        }
190
191        os->lastpts = os->lastdts   = theora_gptopts(s, idx, os->granule, NULL) - duration;
192        if(s->streams[idx]->start_time == AV_NOPTS_VALUE) {
193            s->streams[idx]->start_time = os->lastpts;
194            if (s->streams[idx]->duration)
195                s->streams[idx]->duration -= s->streams[idx]->start_time;
196        }
197    }
198
199    /* parse packet duration */
200    if (os->psize > 0) {
201        os->pduration = 1;
202    }
203
204    return 0;
205}
206
207const struct ogg_codec ff_theora_codec = {
208    .magic     = "\200theora",
209    .magicsize = 7,
210    .header    = theora_header,
211    .packet    = theora_packet,
212    .gptopts   = theora_gptopts,
213    .nb_header = 3,
214};
215