Coverage Report

Created: 2026-04-01 07:42

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