FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/oggparsetheora.c
Date: 2026-10-30 17:37:53
Exec Total Coverage
Lines: 90 106 84.9%
Functions: 3 3 100.0%
Branches: 44 64 68.8%

Line Branch Exec 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/attributes.h"
27 #include "libavutil/mem.h"
28 #include "libavcodec/get_bits.h"
29 #include "avformat.h"
30 #include "internal.h"
31 #include "oggdec.h"
32
33 typedef struct TheoraParams {
34 int gpshift;
35 int gpmask;
36 unsigned version;
37 } TheoraParams;
38
39 25 static int theora_header(AVFormatContext *s, int idx)
40 {
41 25 struct ogg *ogg = s->priv_data;
42 25 struct ogg_stream *os = ogg->streams + idx;
43 25 AVStream *st = s->streams[idx];
44 25 TheoraParams *thp = os->private;
45 25 int cds = st->codecpar->extradata_size + os->psize + 2;
46 int err;
47 uint8_t *cdp;
48
49
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18 times.
25 if (!(os->buf[os->pstart] & 0x80))
50 7 return 0;
51
52
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
18 if (!thp) {
53 6 thp = av_mallocz(sizeof(*thp));
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!thp)
55 ✗ return AVERROR(ENOMEM);
56 6 os->private = thp;
57 }
58
59
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
18 switch (os->buf[os->pstart]) {
60 6 case 0x80: {
61 GetBitContext gb;
62 AVRational timebase;
63
64 6 init_get_bits(&gb, os->buf + os->pstart, os->psize * 8);
65
66 /* 0x80"theora" */
67 6 skip_bits_long(&gb, 7 * 8);
68
69 6 thp->version = get_bits(&gb, 24);
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (thp->version < 0x030100) {
71 ✗ av_log(s, AV_LOG_ERROR,
72 "Too old or unsupported Theora (%x)\n", thp->version);
73 ✗ return AVERROR(ENOSYS);
74 }
75
76 6 st->codecpar->width = get_bits(&gb, 16) << 4;
77 6 st->codecpar->height = get_bits(&gb, 16) << 4;
78
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (thp->version >= 0x030400)
80 ✗ skip_bits(&gb, 100);
81
82
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (thp->version >= 0x030200) {
83 6 int width = get_bits(&gb, 24);
84 6 int height = get_bits(&gb, 24);
85
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
6 if (width <= st->codecpar->width && width > st->codecpar->width - 16 &&
86
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 height <= st->codecpar->height && height > st->codecpar->height - 16) {
87 4 st->codecpar->width = width;
88 4 st->codecpar->height = height;
89 }
90
91 6 skip_bits(&gb, 16);
92 }
93
94 6 timebase.den = get_bits_long(&gb, 32);
95 6 timebase.num = get_bits_long(&gb, 32);
96
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!(timebase.num > 0 && timebase.den > 0)) {
97 ✗ av_log(s, AV_LOG_WARNING, "Invalid time base in theora stream, assuming 25 FPS\n");
98 ✗ timebase.num = 1;
99 ✗ timebase.den = 25;
100 }
101 6 avpriv_set_pts_info(st, 64, timebase.num, timebase.den);
102
103 6 st->sample_aspect_ratio.num = get_bits(&gb, 24);
104 6 st->sample_aspect_ratio.den = get_bits(&gb, 24);
105
106
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (thp->version >= 0x030200)
107 6 skip_bits_long(&gb, 38);
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (thp->version >= 0x304000)
109 ✗ skip_bits(&gb, 2);
110
111 6 thp->gpshift = get_bits(&gb, 5);
112 6 thp->gpmask = (1U << thp->gpshift) - 1;
113
114 6 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
115 6 st->codecpar->codec_id = AV_CODEC_ID_THEORA;
116 6 ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS;
117 }
118 6 break;
119 6 case 0x81:
120 6 ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7, os->psize - 7);
121 av_fallthrough;
122 12 case 0x82:
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!thp->version)
124 ✗ return AVERROR_INVALIDDATA;
125 12 break;
126 ✗ default:
127 ✗ av_log(s, AV_LOG_ERROR, "Unknown header type %X\n", os->buf[os->pstart]);
128 ✗ return AVERROR_INVALIDDATA;
129 }
130
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if ((err = av_reallocp(&st->codecpar->extradata,
132 18 cds + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) {
133 ✗ st->codecpar->extradata_size = 0;
134 ✗ return err;
135 }
136 18 memset(st->codecpar->extradata + cds, 0, AV_INPUT_BUFFER_PADDING_SIZE);
137
138 18 cdp = st->codecpar->extradata + st->codecpar->extradata_size;
139 18 *cdp++ = os->psize >> 8;
140 18 *cdp++ = os->psize & 0xff;
141 18 memcpy(cdp, os->buf + os->pstart, os->psize);
142 18 st->codecpar->extradata_size = cds;
143
144 18 return 1;
145 }
146
147 384 static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
148 int64_t *dts)
149 {
150 384 struct ogg *ogg = ctx->priv_data;
151 384 struct ogg_stream *os = ogg->streams + idx;
152 384 TheoraParams *thp = os->private;
153 uint64_t iframe, pframe;
154
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 384 times.
384 if (!thp)
156 ✗ return AV_NOPTS_VALUE;
157
158 384 iframe = gp >> thp->gpshift;
159 384 pframe = gp & thp->gpmask;
160
161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 384 times.
384 if (thp->version < 0x030201)
162 ✗ iframe++;
163
164
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 302 times.
384 if (!pframe)
165 82 os->pflags |= AV_PKT_FLAG_KEY;
166
167
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 329 times.
384 if (dts)
168 55 *dts = iframe + pframe;
169
170 384 return iframe + pframe;
171 }
172
173 351 static int theora_packet(AVFormatContext *s, int idx)
174 {
175 351 struct ogg *ogg = s->priv_data;
176 351 struct ogg_stream *os = ogg->streams + idx;
177 int duration;
178
179 /* first packet handling
180 here we parse the duration of each packet in the first page and compare
181 the total duration to the page granule to find the encoder delay and
182 set the first timestamp */
183
184
6/6
✓ Branch 0 taken 339 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 294 times.
✓ Branch 3 taken 45 times.
✓ Branch 4 taken 252 times.
✓ Branch 5 taken 54 times.
351 if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
185 int seg;
186 int64_t pts;
187
188 252 duration = 1;
189
2/2
✓ Branch 0 taken 2292 times.
✓ Branch 1 taken 252 times.
2544 for (seg = os->segp; seg < os->nsegs; seg++) {
190
1/2
✓ Branch 0 taken 2292 times.
✗ Branch 1 not taken.
2292 if (os->segments[seg] < 255)
191 2292 duration ++;
192 }
193
194 252 pts = theora_gptopts(s, idx, os->granule, NULL);
195
1/2
✓ Branch 0 taken 252 times.
✗ Branch 1 not taken.
252 if (pts != AV_NOPTS_VALUE)
196 252 pts = av_sat_sub64(pts, duration);
197 252 os->lastpts = os->lastdts = pts;
198
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 248 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
252 if(s->streams[idx]->start_time == AV_NOPTS_VALUE && os->lastpts != AV_NOPTS_VALUE) {
199 4 s->streams[idx]->start_time = os->lastpts;
200
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (s->streams[idx]->duration > 0)
201 4 s->streams[idx]->duration = av_sat_sub64(s->streams[idx]->duration, s->streams[idx]->start_time);
202 }
203 }
204
205 /* parse packet duration */
206
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 296 times.
351 if (os->psize > 0) {
207 55 os->pduration = 1;
208 }
209
210 351 return 0;
211 }
212
213 const struct ogg_codec ff_theora_codec = {
214 .magic = "\200theora",
215 .magicsize = 7,
216 .header = theora_header,
217 .packet = theora_packet,
218 .gptopts = theora_gptopts,
219 .nb_header = 3,
220 };
221