Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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 
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
    int gpshift;
34
    int gpmask;
35
    unsigned version;
36
};
37
 
38
static int
39
theora_header (AVFormatContext * s, int idx)
40
{
41
    struct ogg *ogg = s->priv_data;
42
    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, 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
        os->private = thp;
54
    }
55
 
56
    switch (os->buf[os->pstart]) {
57
    case 0x80: {
58
        GetBitContext gb;
59
        int width, height;
60
        AVRational timebase;
61
 
62
        init_get_bits(&gb, os->buf + os->pstart, os->psize*8);
63
 
64
        skip_bits_long(&gb, 7*8); /* 0x80"theora" */
65
 
66
        thp->version = get_bits_long(&gb, 24);
67
        if (thp->version < 0x030100)
68
        {
69
            av_log(s, AV_LOG_ERROR,
70
                "Too old or unsupported Theora (%x)\n", thp->version);
71
            return -1;
72
        }
73
 
74
        width  = get_bits(&gb, 16) << 4;
75
        height = get_bits(&gb, 16) << 4;
76
        avcodec_set_dimensions(st->codec, width, height);
77
 
78
        if (thp->version >= 0x030400)
79
            skip_bits(&gb, 100);
80
 
81
        if (thp->version >= 0x030200) {
82
            width  = get_bits_long(&gb, 24);
83
            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
                avcodec_set_dimensions(st->codec, width, height);
87
 
88
            skip_bits(&gb, 16);
89
        }
90
        timebase.den = get_bits_long(&gb, 32);
91
        timebase.num = get_bits_long(&gb, 32);
92
        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
            timebase.num = 1;
95
            timebase.den = 25;
96
        }
97
        avpriv_set_pts_info(st, 64, timebase.num, timebase.den);
98
 
99
        st->sample_aspect_ratio.num = get_bits_long(&gb, 24);
100
        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
            skip_bits(&gb, 2);
106
 
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
    break;
115
    case 0x81:
116
        ff_vorbis_comment(s, &st->metadata, os->buf + os->pstart + 7, os->psize - 7);
117
    case 0x82:
118
        if (!thp->version)
119
            return -1;
120
        break;
121
    default:
122
        av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
123
        return -1;
124
    }
125
 
126
    if ((err = av_reallocp(&st->codec->extradata,
127
                           cds + FF_INPUT_BUFFER_PADDING_SIZE)) < 0) {
128
        st->codec->extradata_size = 0;
129
        return err;
130
    }
131
    cdp = st->codec->extradata + st->codec->extradata_size;
132
    *cdp++ = os->psize >> 8;
133
    *cdp++ = os->psize & 0xff;
134
    memcpy (cdp, os->buf + os->pstart, os->psize);
135
    st->codec->extradata_size = cds;
136
 
137
    return 1;
138
}
139
 
140
static uint64_t
141
theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp, int64_t *dts)
142
{
143
    struct ogg *ogg = ctx->priv_data;
144
    struct ogg_stream *os = ogg->streams + idx;
145
    struct theora_params *thp = os->private;
146
    uint64_t iframe, pframe;
147
 
148
    if (!thp)
149
        return AV_NOPTS_VALUE;
150
 
151
    iframe = gp >> thp->gpshift;
152
    pframe = gp & thp->gpmask;
153
 
154
    if (thp->version < 0x030201)
155
        iframe++;
156
 
157
    if(!pframe)
158
        os->pflags |= AV_PKT_FLAG_KEY;
159
 
160
    if (dts)
161
        *dts = iframe + pframe;
162
 
163
    return iframe + pframe;
164
}
165
 
166
static int theora_packet(AVFormatContext *s, int idx)
167
{
168
    struct ogg *ogg = s->priv_data;
169
    struct ogg_stream *os = ogg->streams + idx;
170
    int duration;
171
 
172
    /* first packet handling
173
       here we parse the duration of each packet in the first page and compare
174
       the total duration to the page granule to find the encoder delay and
175
       set the first timestamp */
176
 
177
    if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
178
        int seg;
179
 
180
        duration = 1;
181
        for (seg = os->segp; seg < os->nsegs; seg++) {
182
            if (os->segments[seg] < 255)
183
                duration ++;
184
        }
185
 
186
        os->lastpts = os->lastdts   = theora_gptopts(s, idx, os->granule, NULL) - duration;
187
        if(s->streams[idx]->start_time == AV_NOPTS_VALUE) {
188
            s->streams[idx]->start_time = os->lastpts;
189
            if (s->streams[idx]->duration)
190
                s->streams[idx]->duration -= s->streams[idx]->start_time;
191
        }
192
    }
193
 
194
    /* parse packet duration */
195
    if (os->psize > 0) {
196
        os->pduration = 1;
197
    }
198
 
199
    return 0;
200
}
201
 
202
const struct ogg_codec ff_theora_codec = {
203
    .magic = "\200theora",
204
    .magicsize = 7,
205
    .header = theora_header,
206
    .packet = theora_packet,
207
    .gptopts = theora_gptopts,
208
    .nb_header = 3,
209
};