FFmpeg coverage


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