Coverage Report

Created: 2024-09-06 07:53

/src/ffmpeg/libavformat/oggparsetheora.c
Line
Count
Source (jump to first uncovered line)
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/mem.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
    int gpshift;
34
    int gpmask;
35
    unsigned version;
36
} TheoraParams;
37
38
static int theora_header(AVFormatContext *s, int idx)
39
9.44k
{
40
9.44k
    struct ogg *ogg       = s->priv_data;
41
9.44k
    struct ogg_stream *os = ogg->streams + idx;
42
9.44k
    AVStream *st          = s->streams[idx];
43
9.44k
    TheoraParams *thp     = os->private;
44
9.44k
    int cds               = st->codecpar->extradata_size + os->psize + 2;
45
9.44k
    int err;
46
9.44k
    uint8_t *cdp;
47
48
9.44k
    if (!(os->buf[os->pstart] & 0x80))
49
2.56k
        return 0;
50
51
6.87k
    if (!thp) {
52
2.53k
        thp = av_mallocz(sizeof(*thp));
53
2.53k
        if (!thp)
54
0
            return AVERROR(ENOMEM);
55
2.53k
        os->private = thp;
56
2.53k
    }
57
58
6.87k
    switch (os->buf[os->pstart]) {
59
5.56k
    case 0x80: {
60
5.56k
        GetBitContext gb;
61
5.56k
        AVRational timebase;
62
63
5.56k
        init_get_bits(&gb, os->buf + os->pstart, os->psize * 8);
64
65
        /* 0x80"theora" */
66
5.56k
        skip_bits_long(&gb, 7 * 8);
67
68
5.56k
        thp->version = get_bits(&gb, 24);
69
5.56k
        if (thp->version < 0x030100) {
70
6
            av_log(s, AV_LOG_ERROR,
71
6
                   "Too old or unsupported Theora (%x)\n", thp->version);
72
6
            return AVERROR(ENOSYS);
73
6
        }
74
75
5.55k
        st->codecpar->width  = get_bits(&gb, 16) << 4;
76
5.55k
        st->codecpar->height = get_bits(&gb, 16) << 4;
77
78
5.55k
        if (thp->version >= 0x030400)
79
615
            skip_bits(&gb, 100);
80
81
5.55k
        if (thp->version >= 0x030200) {
82
5.08k
            int width  = get_bits(&gb, 24);
83
5.08k
            int height = get_bits(&gb, 24);
84
5.08k
            if (width  <= st->codecpar->width  && width  > st->codecpar->width  - 16 &&
85
5.08k
                height <= st->codecpar->height && height > st->codecpar->height - 16) {
86
1.46k
                st->codecpar->width  = width;
87
1.46k
                st->codecpar->height = height;
88
1.46k
            }
89
90
5.08k
            skip_bits(&gb, 16);
91
5.08k
        }
92
93
5.55k
        timebase.den = get_bits_long(&gb, 32);
94
5.55k
        timebase.num = get_bits_long(&gb, 32);
95
5.55k
        if (!(timebase.num > 0 && timebase.den > 0)) {
96
1.56k
            av_log(s, AV_LOG_WARNING, "Invalid time base in theora stream, assuming 25 FPS\n");
97
1.56k
            timebase.num = 1;
98
1.56k
            timebase.den = 25;
99
1.56k
        }
100
5.55k
        avpriv_set_pts_info(st, 64, timebase.num, timebase.den);
101
102
5.55k
        st->sample_aspect_ratio.num = get_bits(&gb, 24);
103
5.55k
        st->sample_aspect_ratio.den = get_bits(&gb, 24);
104
105
5.55k
        if (thp->version >= 0x030200)
106
5.08k
            skip_bits_long(&gb, 38);
107
5.55k
        if (thp->version >= 0x304000)
108
601
            skip_bits(&gb, 2);
109
110
5.55k
        thp->gpshift = get_bits(&gb, 5);
111
5.55k
        thp->gpmask  = (1U << thp->gpshift) - 1;
112
113
5.55k
        st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
114
5.55k
        st->codecpar->codec_id   = AV_CODEC_ID_THEORA;
115
5.55k
        ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS;
116
5.55k
    }
117
0
    break;
118
654
    case 0x81:
119
654
        ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7, os->psize - 7);
120
1.30k
    case 0x82:
121
1.30k
        if (!thp->version)
122
0
            return AVERROR_INVALIDDATA;
123
1.30k
        break;
124
1.30k
    default:
125
6
        av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
126
6
        return AVERROR_INVALIDDATA;
127
6.87k
    }
128
129
6.86k
    if ((err = av_reallocp(&st->codecpar->extradata,
130
6.86k
                           cds + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) {
131
0
        st->codecpar->extradata_size = 0;
132
0
        return err;
133
0
    }
134
6.86k
    memset(st->codecpar->extradata + cds, 0, AV_INPUT_BUFFER_PADDING_SIZE);
135
136
6.86k
    cdp    = st->codecpar->extradata + st->codecpar->extradata_size;
137
6.86k
    *cdp++ = os->psize >> 8;
138
6.86k
    *cdp++ = os->psize & 0xff;
139
6.86k
    memcpy(cdp, os->buf + os->pstart, os->psize);
140
6.86k
    st->codecpar->extradata_size = cds;
141
142
6.86k
    return 1;
143
6.86k
}
144
145
static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
146
                               int64_t *dts)
147
1.26M
{
148
1.26M
    struct ogg *ogg       = ctx->priv_data;
149
1.26M
    struct ogg_stream *os = ogg->streams + idx;
150
1.26M
    TheoraParams *thp     = os->private;
151
1.26M
    uint64_t iframe, pframe;
152
153
1.26M
    if (!thp)
154
411k
        return AV_NOPTS_VALUE;
155
156
858k
    iframe = gp >> thp->gpshift;
157
858k
    pframe = gp & thp->gpmask;
158
159
858k
    if (thp->version < 0x030201)
160
6.31k
        iframe++;
161
162
858k
    if (!pframe)
163
856k
        os->pflags |= AV_PKT_FLAG_KEY;
164
165
858k
    if (dts)
166
120k
        *dts = iframe + pframe;
167
168
858k
    return iframe + pframe;
169
1.26M
}
170
171
static int theora_packet(AVFormatContext *s, int idx)
172
1.11M
{
173
1.11M
    struct ogg *ogg = s->priv_data;
174
1.11M
    struct ogg_stream *os = ogg->streams + idx;
175
1.11M
    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
1.11M
    if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
183
1.07M
        int seg;
184
1.07M
        int64_t pts;
185
186
1.07M
        duration = 1;
187
4.32M
        for (seg = os->segp; seg < os->nsegs; seg++) {
188
3.24M
            if (os->segments[seg] < 255)
189
3.24M
                duration ++;
190
3.24M
        }
191
192
1.07M
        pts = theora_gptopts(s, idx, os->granule, NULL);
193
1.07M
        if (pts != AV_NOPTS_VALUE)
194
737k
            pts = av_sat_sub64(pts, duration);
195
1.07M
        os->lastpts = os->lastdts = pts;
196
1.07M
        if(s->streams[idx]->start_time == AV_NOPTS_VALUE && os->lastpts != AV_NOPTS_VALUE) {
197
1.91k
            s->streams[idx]->start_time = os->lastpts;
198
1.91k
            if (s->streams[idx]->duration > 0)
199
397
                s->streams[idx]->duration = av_sat_sub64(s->streams[idx]->duration, s->streams[idx]->start_time);
200
1.91k
        }
201
1.07M
    }
202
203
    /* parse packet duration */
204
1.11M
    if (os->psize > 0) {
205
204k
        os->pduration = 1;
206
204k
    }
207
208
1.11M
    return 0;
209
1.11M
}
210
211
const struct ogg_codec ff_theora_codec = {
212
    .magic     = "\200theora",
213
    .magicsize = 7,
214
    .header    = theora_header,
215
    .packet    = theora_packet,
216
    .gptopts   = theora_gptopts,
217
    .nb_header = 3,
218
};