FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/oggparsetheora.c
Date: 2026-09-25 11:37:27
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 21 static int theora_header(AVFormatContext *s, int idx)
40 {
41 21 struct ogg *ogg = s->priv_data;
42 21 struct ogg_stream *os = ogg->streams + idx;
43 21 AVStream *st = s->streams[idx];
44 21 TheoraParams *thp = os->private;
45 21 int cds = st->codecpar->extradata_size + os->psize + 2;
46 int err;
47 uint8_t *cdp;
48
49
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 15 times.
21 if (!(os->buf[os->pstart] & 0x80))
50 6 return 0;
51
52
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 10 times.
15 if (!thp) {
53 5 thp = av_mallocz(sizeof(*thp));
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!thp)
55 ✗ return AVERROR(ENOMEM);
56 5 os->private = thp;
57 }
58
59
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
15 switch (os->buf[os->pstart]) {
60 5 case 0x80: {
61 GetBitContext gb;
62 AVRational timebase;
63
64 5 init_get_bits(&gb, os->buf + os->pstart, os->psize * 8);
65
66 /* 0x80"theora" */
67 5 skip_bits_long(&gb, 7 * 8);
68
69 5 thp->version = get_bits(&gb, 24);
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 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 5 st->codecpar->width = get_bits(&gb, 16) << 4;
77 5 st->codecpar->height = get_bits(&gb, 16) << 4;
78
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (thp->version >= 0x030400)
80 ✗ skip_bits(&gb, 100);
81
82
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (thp->version >= 0x030200) {
83 5 int width = get_bits(&gb, 24);
84 5 int height = get_bits(&gb, 24);
85
3/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
5 if (width <= st->codecpar->width && width > st->codecpar->width - 16 &&
86
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 height <= st->codecpar->height && height > st->codecpar->height - 16) {
87 3 st->codecpar->width = width;
88 3 st->codecpar->height = height;
89 }
90
91 5 skip_bits(&gb, 16);
92 }
93
94 5 timebase.den = get_bits_long(&gb, 32);
95 5 timebase.num = get_bits_long(&gb, 32);
96
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 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 5 avpriv_set_pts_info(st, 64, timebase.num, timebase.den);
102
103 5 st->sample_aspect_ratio.num = get_bits(&gb, 24);
104 5 st->sample_aspect_ratio.den = get_bits(&gb, 24);
105
106
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (thp->version >= 0x030200)
107 5 skip_bits_long(&gb, 38);
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (thp->version >= 0x304000)
109 ✗ skip_bits(&gb, 2);
110
111 5 thp->gpshift = get_bits(&gb, 5);
112 5 thp->gpmask = (1U << thp->gpshift) - 1;
113
114 5 st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
115 5 st->codecpar->codec_id = AV_CODEC_ID_THEORA;
116 5 ffstream(st)->need_parsing = AVSTREAM_PARSE_HEADERS;
117 }
118 5 break;
119 5 case 0x81:
120 5 ff_vorbis_stream_comment(s, st, os->buf + os->pstart + 7, os->psize - 7);
121 av_fallthrough;
122 10 case 0x82:
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!thp->version)
124 ✗ return AVERROR_INVALIDDATA;
125 10 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 15 times.
15 if ((err = av_reallocp(&st->codecpar->extradata,
132 15 cds + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) {
133 ✗ st->codecpar->extradata_size = 0;
134 ✗ return err;
135 }
136 15 memset(st->codecpar->extradata + cds, 0, AV_INPUT_BUFFER_PADDING_SIZE);
137
138 15 cdp = st->codecpar->extradata + st->codecpar->extradata_size;
139 15 *cdp++ = os->psize >> 8;
140 15 *cdp++ = os->psize & 0xff;
141 15 memcpy(cdp, os->buf + os->pstart, os->psize);
142 15 st->codecpar->extradata_size = cds;
143
144 15 return 1;
145 }
146
147 215 static uint64_t theora_gptopts(AVFormatContext *ctx, int idx, uint64_t gp,
148 int64_t *dts)
149 {
150 215 struct ogg *ogg = ctx->priv_data;
151 215 struct ogg_stream *os = ogg->streams + idx;
152 215 TheoraParams *thp = os->private;
153 uint64_t iframe, pframe;
154
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 215 times.
215 if (!thp)
156 ✗ return AV_NOPTS_VALUE;
157
158 215 iframe = gp >> thp->gpshift;
159 215 pframe = gp & thp->gpmask;
160
161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 215 times.
215 if (thp->version < 0x030201)
162 ✗ iframe++;
163
164
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 154 times.
215 if (!pframe)
165 61 os->pflags |= AV_PKT_FLAG_KEY;
166
167
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 183 times.
215 if (dts)
168 32 *dts = iframe + pframe;
169
170 215 return iframe + pframe;
171 }
172
173 193 static int theora_packet(AVFormatContext *s, int idx)
174 {
175 193 struct ogg *ogg = s->priv_data;
176 193 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 183 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 159 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 128 times.
✓ Branch 5 taken 41 times.
193 if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) {
185 int seg;
186 int64_t pts;
187
188 128 duration = 1;
189
2/2
✓ Branch 0 taken 1146 times.
✓ Branch 1 taken 128 times.
1274 for (seg = os->segp; seg < os->nsegs; seg++) {
190
1/2
✓ Branch 0 taken 1146 times.
✗ Branch 1 not taken.
1146 if (os->segments[seg] < 255)
191 1146 duration ++;
192 }
193
194 128 pts = theora_gptopts(s, idx, os->granule, NULL);
195
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 if (pts != AV_NOPTS_VALUE)
196 128 pts = av_sat_sub64(pts, duration);
197 128 os->lastpts = os->lastdts = pts;
198
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
128 if(s->streams[idx]->start_time == AV_NOPTS_VALUE && os->lastpts != AV_NOPTS_VALUE) {
199 3 s->streams[idx]->start_time = os->lastpts;
200
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (s->streams[idx]->duration > 0)
201 3 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 45 times.
✓ Branch 1 taken 148 times.
193 if (os->psize > 0) {
207 45 os->pduration = 1;
208 }
209
210 193 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