FFmpeg coverage


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