FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/oggdec.c
Date: 2026-09-11 00:35:37
Exec Total Coverage
Lines: 477 568 84.0%
Functions: 20 20 100.0%
Branches: 242 335 72.2%

Line Branch Exec Source
1 /*
2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
5 */
6
7 /*
8 Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
9
10 Permission is hereby granted, free of charge, to any person
11 obtaining a copy of this software and associated documentation
12 files (the "Software"), to deal in the Software without
13 restriction, including without limitation the rights to use, copy,
14 modify, merge, publish, distribute, sublicense, and/or sell copies
15 of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 DEALINGS IN THE SOFTWARE.
29 */
30
31 #include <stdio.h>
32 #include "libavutil/avassert.h"
33 #include "libavutil/intreadwrite.h"
34 #include "libavutil/mem.h"
35 #include "avio_internal.h"
36 #include "demux.h"
37 #include "oggdec.h"
38 #include "avformat.h"
39 #include "internal.h"
40
41 #define MAX_PAGE_SIZE 65307
42 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
43
44 static const struct ogg_codec * const ogg_codecs[] = {
45 &ff_skeleton_codec,
46 &ff_dirac_codec,
47 &ff_speex_codec,
48 &ff_vorbis_codec,
49 &ff_theora_codec,
50 &ff_flac_codec,
51 &ff_opus_codec,
52 &ff_vp8_codec,
53 &ff_old_dirac_codec,
54 &ff_old_flac_codec,
55 &ff_ogm_video_codec,
56 &ff_ogm_audio_codec,
57 &ff_ogm_text_codec,
58 &ff_ogm_old_codec,
59 NULL
60 };
61
62 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts);
63 static int ogg_new_stream(AVFormatContext *s, uint32_t serial);
64 static int ogg_restore(AVFormatContext *s);
65
66 70 static void free_stream(AVFormatContext *s, int i)
67 {
68 70 struct ogg *ogg = s->priv_data;
69 70 struct ogg_stream *stream = &ogg->streams[i];
70
71 70 av_freep(&stream->buf);
72
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 if (stream->codec &&
73
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 36 times.
70 stream->codec->cleanup) {
74 34 stream->codec->cleanup(s, i);
75 }
76
77 70 av_freep(&stream->private);
78 70 av_freep(&stream->new_metadata);
79 70 av_freep(&stream->new_extradata);
80 70 }
81
82 //FIXME We could avoid some structure duplication
83 108 static int ogg_save(AVFormatContext *s)
84 {
85 108 struct ogg *ogg = s->priv_data;
86 struct ogg_state *ost =
87 108 av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
88 int i;
89 108 int ret = 0;
90
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (!ost)
92 return AVERROR(ENOMEM);
93
94 108 ost->pos = avio_tell(s->pb);
95 108 ost->curidx = ogg->curidx;
96 108 ost->next = ogg->state;
97 108 ost->nstreams = ogg->nstreams;
98 108 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
99
100
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 108 times.
220 for (i = 0; i < ogg->nstreams; i++) {
101 112 struct ogg_stream *os = ogg->streams + i;
102 112 os->buf = av_mallocz(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
103
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 if (os->buf)
104 112 memcpy(os->buf, ost->streams[i].buf, os->bufpos);
105 else
106 ret = AVERROR(ENOMEM);
107 112 os->new_metadata = NULL;
108 112 os->new_metadata_size = 0;
109 112 os->new_extradata = NULL;
110 112 os->new_extradata_size = 0;
111 }
112
113 108 ogg->state = ost;
114
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (ret < 0)
116 ogg_restore(s);
117
118 108 return ret;
119 }
120
121 108 static int ogg_restore(AVFormatContext *s)
122 {
123 108 struct ogg *ogg = s->priv_data;
124 108 AVIOContext *bc = s->pb;
125 108 struct ogg_state *ost = ogg->state;
126 int i, err;
127
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (!ost)
129 return 0;
130
131 108 ogg->state = ost->next;
132
133
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 108 times.
220 for (i = 0; i < ogg->nstreams; i++) {
134 112 struct ogg_stream *stream = &ogg->streams[i];
135 112 av_freep(&stream->buf);
136 112 av_freep(&stream->new_metadata);
137 112 av_freep(&stream->new_extradata);
138
139
3/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 98 times.
112 if (i >= ost->nstreams || !ost->streams[i].private) {
140 14 free_stream(s, i);
141 }
142 }
143
144 108 avio_seek(bc, ost->pos, SEEK_SET);
145 108 ogg->page_pos = -1;
146 108 ogg->curidx = ost->curidx;
147 108 ogg->nstreams = ost->nstreams;
148
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
108 if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
149 sizeof(*ogg->streams))) < 0) {
150 ogg->nstreams = 0;
151 return err;
152 } else
153 108 memcpy(ogg->streams, ost->streams,
154 108 ost->nstreams * sizeof(*ogg->streams));
155
156 108 av_free(ost);
157
158 108 return 0;
159 }
160
161 360 static int ogg_reset(AVFormatContext *s)
162 {
163 360 struct ogg *ogg = s->priv_data;
164 int i;
165 360 int64_t start_pos = avio_tell(s->pb);
166
167
2/2
✓ Branch 0 taken 362 times.
✓ Branch 1 taken 360 times.
722 for (i = 0; i < ogg->nstreams; i++) {
168 362 struct ogg_stream *os = ogg->streams + i;
169 362 os->bufpos = 0;
170 362 os->pstart = 0;
171 362 os->psize = 0;
172 362 os->granule = -1;
173 362 os->lastpts = AV_NOPTS_VALUE;
174 362 os->lastdts = AV_NOPTS_VALUE;
175 362 os->sync_pos = -1;
176 362 os->page_pos = 0;
177 362 os->nsegs = 0;
178 362 os->segp = 0;
179 362 os->incomplete = 0;
180 362 os->got_data = 0;
181
2/2
✓ Branch 1 taken 108 times.
✓ Branch 2 taken 254 times.
362 if (start_pos <= ffformatcontext(s)->data_offset) {
182 108 os->lastpts = 0;
183 }
184 362 os->start_trimming = 0;
185 362 os->end_trimming = 0;
186 362 av_freep(&os->new_metadata);
187 362 os->new_metadata_size = 0;
188 362 av_freep(&os->new_extradata);
189 362 os->new_extradata_size = 0;
190 }
191
192 360 ogg->page_pos = -1;
193 360 ogg->curidx = -1;
194
195 360 return 0;
196 }
197
198 76 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
199 {
200 int i;
201
202
1/2
✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
387 for (i = 0; ogg_codecs[i]; i++)
203
1/2
✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
387 if (size >= ogg_codecs[i]->magicsize &&
204
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 311 times.
387 !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
205 76 return ogg_codecs[i];
206
207 return NULL;
208 }
209
210 /**
211 * Replace the current stream with a new one. This is a typical webradio
212 * situation where a new audio stream spawn (identified with a new serial) and
213 * must replace the previous one (track switch).
214 */
215 20 static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, char *magic, int page_size,
216 int probing)
217 {
218 20 struct ogg *ogg = s->priv_data;
219 struct ogg_stream *os;
220 const struct ogg_codec *codec;
221 20 int i = 0;
222
223
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (ogg->nstreams != 1) {
224 avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg");
225 return AVERROR_PATCHWELCOME;
226 }
227
228 /* Check for codecs */
229 20 codec = ogg_find_codec(magic, page_size);
230
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
20 if (!codec && !probing) {
231 av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n");
232 return AVERROR_INVALIDDATA;
233 }
234
235 20 os = &ogg->streams[0];
236
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (os->codec != codec)
237 return AVERROR(EINVAL);
238
239 20 os->serial = serial;
240 20 os->codec = codec;
241 20 os->serial = serial;
242 20 os->lastpts = 0;
243 20 os->lastdts = 0;
244 20 os->flags = 0;
245 20 os->start_trimming = 0;
246 20 os->end_trimming = 0;
247 20 os->replace = 1;
248
249 20 return i;
250 }
251
252 56 static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
253 {
254 56 struct ogg *ogg = s->priv_data;
255 56 int idx = ogg->nstreams;
256 AVStream *st;
257 struct ogg_stream *os;
258
259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (ogg->state) {
260 av_log(s, AV_LOG_ERROR, "New streams are not supposed to be added "
261 "in between Ogg context save/restore operations.\n");
262 return AVERROR_BUG;
263 }
264
265 /* Allocate and init a new Ogg Stream */
266
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
56 if (!(os = av_realloc_array(ogg->streams, ogg->nstreams + 1,
267 sizeof(*ogg->streams))))
268 return AVERROR(ENOMEM);
269 56 ogg->streams = os;
270 56 os = ogg->streams + idx;
271 56 memset(os, 0, sizeof(*os));
272 56 os->serial = serial;
273 56 os->bufsize = DECODER_BUFFER_SIZE;
274 56 os->buf = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
275 56 os->header = -1;
276 56 os->start_granule = OGG_NOGRANULE_VALUE;
277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (!os->buf)
278 return AVERROR(ENOMEM);
279
280 /* Create the associated AVStream */
281 56 st = avformat_new_stream(s, NULL);
282
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (!st) {
283 av_freep(&os->buf);
284 return AVERROR(ENOMEM);
285 }
286 56 st->id = idx;
287 56 avpriv_set_pts_info(st, 64, 1, 1000000);
288
289 56 ogg->nstreams++;
290 56 return idx;
291 }
292
293 76 static int data_packets_seen(const struct ogg *ogg)
294 {
295 int i;
296
297
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 56 times.
78 for (i = 0; i < ogg->nstreams; i++)
298
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
22 if (ogg->streams[i].got_data)
299 20 return 1;
300 56 return 0;
301 }
302
303 1834 static int buf_realloc(struct ogg_stream *os, int size)
304 {
305 /* Even if invalid guarantee there's enough memory to read the page */
306
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 1796 times.
1834 if (os->bufsize - os->bufpos < size) {
307 uint8_t *nb;
308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (os->bufsize > (UINT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) / 2)
309 return AVERROR(ENOMEM);
310 38 nb = av_realloc(os->buf, 2*os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
38 if (!nb)
312 return AVERROR(ENOMEM);
313 38 os->buf = nb;
314 38 os->bufsize *= 2;
315 }
316
317 1834 return 0;
318 }
319
320 1972 static int ogg_read_page(AVFormatContext *s, int *sid, int probing)
321 {
322 1972 AVIOContext *bc = s->pb;
323 1972 struct ogg *ogg = s->priv_data;
324 struct ogg_stream *os;
325 1972 int ret, i = 0;
326 int flags, nsegs;
327 uint64_t gp;
328 uint32_t serial;
329 uint32_t crc, crc_tmp;
330 1972 int size = 0, idx;
331 int64_t version, page_pos;
332 int64_t start_pos;
333 uint8_t sync[4];
334 uint8_t segments[255];
335 uint8_t *readout_buf;
336 1972 int sp = 0;
337
338 1972 ret = avio_read(bc, sync, 4);
339
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 1912 times.
1972 if (ret < 4)
340
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 return ret < 0 ? ret : AVERROR_EOF;
341
342 do {
343 int c;
344
345
2/2
✓ Branch 0 taken 4624 times.
✓ Branch 1 taken 701661 times.
706285 if (sync[sp & 3] == 'O' &&
346
2/2
✓ Branch 0 taken 1851 times.
✓ Branch 1 taken 2773 times.
4624 sync[(sp + 1) & 3] == 'g' &&
347
3/4
✓ Branch 0 taken 1834 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1834 times.
✗ Branch 3 not taken.
1851 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
348 1834 break;
349
350
4/6
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 704320 times.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 131 times.
704451 if(!i && (bc->seekable & AVIO_SEEKABLE_NORMAL) && ogg->page_pos > 0) {
351 memset(sync, 0, 4);
352 avio_seek(bc, ogg->page_pos+4, SEEK_SET);
353 ogg->page_pos = -1;
354 }
355
356 704451 c = avio_r8(bc);
357
358
2/2
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 704373 times.
704451 if (avio_feof(bc))
359 78 return AVERROR_EOF;
360
361 704373 sync[sp++ & 3] = c;
362
1/2
✓ Branch 0 taken 704373 times.
✗ Branch 1 not taken.
704373 } while (i++ < MAX_PAGE_SIZE);
363
364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1834 times.
1834 if (i >= MAX_PAGE_SIZE) {
365 av_log(s, AV_LOG_INFO, "cannot find sync word\n");
366 return AVERROR_INVALIDDATA;
367 }
368
369 /* 0x4fa9b05f = av_crc(AV_CRC_32_IEEE, 0x0, "OggS", 4) */
370 1834 ffio_init_checksum(bc, ff_crc04C11DB7_update, 0x4fa9b05f);
371
372 /* To rewind if checksum is bad/check magic on switches - this is the max packet size */
373 1834 ret = ffio_ensure_seekback(bc, MAX_PAGE_SIZE);
374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1834 times.
1834 if (ret < 0)
375 return ret;
376 1834 start_pos = avio_tell(bc);
377
378 1834 version = avio_r8(bc);
379 1834 flags = avio_r8(bc);
380 1834 gp = avio_rl64(bc);
381 1834 serial = avio_rl32(bc);
382 1834 avio_rl32(bc); /* seq */
383
384 1834 crc_tmp = ffio_get_checksum(bc);
385 1834 crc = avio_rb32(bc);
386 1834 crc_tmp = ff_crc04C11DB7_update(crc_tmp, (uint8_t[4]){0}, 4);
387 1834 ffio_init_checksum(bc, ff_crc04C11DB7_update, crc_tmp);
388
389 1834 nsegs = avio_r8(bc);
390 1834 page_pos = avio_tell(bc) - 27;
391
392 1834 ret = avio_read(bc, segments, nsegs);
393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1834 times.
1834 if (ret < nsegs)
394 return ret < 0 ? ret : AVERROR_EOF;
395
396
2/2
✓ Branch 0 taken 47918 times.
✓ Branch 1 taken 1834 times.
49752 for (i = 0; i < nsegs; i++)
397 47918 size += segments[i];
398
399 1834 idx = ogg_find_stream(ogg, serial);
400
2/2
✓ Branch 0 taken 1758 times.
✓ Branch 1 taken 76 times.
1834 if (idx >= 0) {
401 1758 os = ogg->streams + idx;
402
403 1758 ret = buf_realloc(os, size);
404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1758 times.
1758 if (ret < 0)
405 return ret;
406
407 1758 readout_buf = os->buf + os->bufpos;
408 } else {
409 76 readout_buf = av_malloc(size);
410 }
411
412 1834 ret = avio_read(bc, readout_buf, size);
413
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 1790 times.
1834 if (ret < size) {
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 if (idx < 0)
415 av_free(readout_buf);
416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 return ret < 0 ? ret : AVERROR_EOF;
417 }
418
419
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1790 times.
1790 if (crc ^ ffio_get_checksum(bc)) {
420 av_log(s, AV_LOG_ERROR, "CRC mismatch!\n");
421 if (idx < 0)
422 av_free(readout_buf);
423 avio_seek(bc, start_pos, SEEK_SET);
424 *sid = -1;
425 return 0;
426 }
427
428 /* Since we're almost sure its a valid packet, checking the version after
429 * the checksum lets the demuxer be more tolerant */
430
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1790 times.
1790 if (version) {
431 av_log(s, AV_LOG_ERROR, "Invalid Ogg vers!\n");
432 if (idx < 0)
433 av_free(readout_buf);
434 avio_seek(bc, start_pos, SEEK_SET);
435 *sid = -1;
436 return 0;
437 }
438
439 /* CRC is correct so we can be 99% sure there's an actual change here */
440
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 1714 times.
1790 if (idx < 0) {
441
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 56 times.
76 if (data_packets_seen(ogg))
442 20 idx = ogg_replace_stream(s, serial, readout_buf, size, probing);
443 else
444 56 idx = ogg_new_stream(s, serial);
445
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
76 if (idx < 0) {
447 av_log(s, AV_LOG_ERROR, "failed to create or replace stream\n");
448 av_free(readout_buf);
449 return idx;
450 }
451
452 76 os = ogg->streams + idx;
453
454 76 ret = buf_realloc(os, size);
455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
76 if (ret < 0) {
456 av_free(readout_buf);
457 return ret;
458 }
459
460 76 memcpy(os->buf + os->bufpos, readout_buf, size);
461 76 av_free(readout_buf);
462 }
463
464 1790 ogg->page_pos = page_pos;
465 1790 os->page_pos = page_pos;
466 1790 os->nsegs = nsegs;
467 1790 os->segp = 0;
468 1790 os->got_data = !(flags & OGG_FLAG_BOS);
469 1790 os->bufpos += size;
470 1790 os->granule = gp;
471 1790 os->flags = flags;
472 1790 memcpy(os->segments, segments, nsegs);
473 1790 memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE);
474
475
3/4
✓ Branch 0 taken 1148 times.
✓ Branch 1 taken 642 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1148 times.
1790 if (flags & OGG_FLAG_CONT || os->incomplete) {
476
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 472 times.
642 if (!os->psize) {
477 // If this is the very first segment we started
478 // playback in the middle of a continuation packet.
479 // Discard it since we missed the start of it.
480
1/2
✓ Branch 0 taken 402 times.
✗ Branch 1 not taken.
402 while (os->segp < os->nsegs) {
481 402 int seg = os->segments[os->segp++];
482 402 os->pstart += seg;
483
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 232 times.
402 if (seg < 255)
484 170 break;
485 }
486 170 os->sync_pos = os->page_pos;
487 }
488 } else {
489 1148 os->psize = 0;
490 1148 os->sync_pos = os->page_pos;
491 }
492
493 /* This function is always called with sid != NULL */
494 1790 *sid = idx;
495
496 1790 return 0;
497 }
498
499 /**
500 * @brief find the next Ogg packet
501 * @param *sid is set to the stream for the packet or -1 if there is
502 * no matching stream, in that case assume all other return
503 * values to be uninitialized.
504 * @return negative value on error or EOF.
505 */
506 13039 static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
507 int64_t *fpos)
508 {
509 13039 FFFormatContext *const si = ffformatcontext(s);
510 13039 struct ogg *ogg = s->priv_data;
511 int idx, i, ret;
512 struct ogg_stream *os;
513 13039 int complete = 0;
514 13039 int segp = 0, psize = 0;
515
516 13039 av_log(s, AV_LOG_TRACE, "ogg_packet: curidx=%i\n", ogg->curidx);
517
2/2
✓ Branch 0 taken 12835 times.
✓ Branch 1 taken 204 times.
13039 if (sid)
518 12835 *sid = -1;
519
520 do {
521 13491 idx = ogg->curidx;
522
523
2/2
✓ Branch 0 taken 1276 times.
✓ Branch 1 taken 13363 times.
14639 while (idx < 0) {
524 1276 ret = ogg_read_page(s, &idx, 0);
525
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 1148 times.
1276 if (ret < 0)
526 128 return ret;
527 }
528
529 13363 os = ogg->streams + idx;
530
531 13363 av_log(s, AV_LOG_TRACE, "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
532 idx, os->pstart, os->psize, os->segp, os->nsegs);
533
534
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 13307 times.
13363 if (!os->codec) {
535
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 if (os->header < 0) {
536 56 os->codec = ogg_find_codec(os->buf, os->bufpos);
537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (!os->codec) {
538 av_log(s, AV_LOG_WARNING, "Codec not found\n");
539 os->header = 0;
540 return 0;
541 }
542 } else {
543 return 0;
544 }
545 }
546
547 13363 segp = os->segp;
548 13363 psize = os->psize;
549
550
2/2
✓ Branch 0 taken 27051 times.
✓ Branch 1 taken 452 times.
27503 while (os->segp < os->nsegs) {
551 27051 int ss = os->segments[os->segp++];
552 27051 os->psize += ss;
553
2/2
✓ Branch 0 taken 12911 times.
✓ Branch 1 taken 14140 times.
27051 if (ss < 255) {
554 12911 complete = 1;
555 12911 break;
556 }
557 }
558
559
3/4
✓ Branch 0 taken 452 times.
✓ Branch 1 taken 12911 times.
✓ Branch 2 taken 452 times.
✗ Branch 3 not taken.
13363 if (!complete && os->segp == os->nsegs) {
560 452 ogg->curidx = -1;
561 // Do not set incomplete for empty packets.
562 // Together with the code in ogg_read_page
563 // that discards all continuation of empty packets
564 // we would get an infinite loop.
565 452 os->incomplete = !!os->psize;
566 }
567
2/2
✓ Branch 0 taken 452 times.
✓ Branch 1 taken 12911 times.
13363 } while (!complete);
568
569
570
2/2
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 12733 times.
12911 if (os->granule == -1)
571 178 av_log(s, AV_LOG_WARNING,
572 "Page at %"PRId64" is missing granule\n",
573 os->page_pos);
574
575 12911 ogg->curidx = idx;
576 12911 os->incomplete = 0;
577
578 // the packet started at the first segment of the page it completes on
579 12911 os->page_start = segp == 0;
580
581
2/2
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 12703 times.
12911 if (os->header) {
582
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 208 times.
208 if ((ret = os->codec->header(s, idx)) < 0) {
583 av_log(s, AV_LOG_ERROR, "Header processing failed: %s\n", av_err2str(ret));
584 return ret;
585 }
586 208 os->header = ret;
587
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 150 times.
208 if (!os->header) {
588 58 os->segp = segp;
589 58 os->psize = psize;
590
591 // We have reached the first non-header packet in this stream.
592 // Unfortunately more header packets may still follow for others,
593 // but if we continue with header parsing we may lose data packets.
594 58 ogg->headers = 1;
595
596 // Update the header state for all streams and
597 // compute the data_offset.
598
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 4 times.
58 if (!si->data_offset)
599 54 si->data_offset = os->sync_pos;
600
601
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 58 times.
122 for (i = 0; i < ogg->nstreams; i++) {
602 64 struct ogg_stream *cur_os = ogg->streams + i;
603
604 // if we have a partial non-header packet, its start is
605 // obviously at or after the data start
606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 if (cur_os->incomplete)
607 si->data_offset = FFMIN(si->data_offset, cur_os->sync_pos);
608 }
609 } else {
610 150 os->nb_header++;
611 150 os->pstart += os->psize;
612 150 os->psize = 0;
613 }
614 } else {
615 12703 os->pflags = 0;
616 12703 os->pduration = 0;
617
618 12703 ret = 0;
619
2/4
✓ Branch 0 taken 12703 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12703 times.
✗ Branch 3 not taken.
12703 if (os->codec && os->codec->packet) {
620
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12703 times.
12703 if ((ret = os->codec->packet(s, idx)) < 0) {
621 av_log(s, AV_LOG_ERROR, "Packet processing failed: %s\n", av_err2str(ret));
622 return ret;
623 }
624 }
625
626
2/2
✓ Branch 0 taken 12643 times.
✓ Branch 1 taken 60 times.
12703 if (!ret) {
627
1/2
✓ Branch 0 taken 12643 times.
✗ Branch 1 not taken.
12643 if (sid)
628 12643 *sid = idx;
629
2/2
✓ Branch 0 taken 12560 times.
✓ Branch 1 taken 83 times.
12643 if (dstart)
630 12560 *dstart = os->pstart;
631
2/2
✓ Branch 0 taken 12560 times.
✓ Branch 1 taken 83 times.
12643 if (dsize)
632 12560 *dsize = os->psize;
633
2/2
✓ Branch 0 taken 12560 times.
✓ Branch 1 taken 83 times.
12643 if (fpos)
634 12560 *fpos = os->sync_pos;
635 }
636
637 12703 os->pstart += os->psize;
638 12703 os->psize = 0;
639
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 12115 times.
12703 if(os->pstart == os->bufpos)
640 588 os->bufpos = os->pstart = 0;
641 12703 os->sync_pos = os->page_pos;
642 }
643
644 // determine whether there are more complete packets in this page
645 // if not, the page's granule will apply to this packet
646 12911 os->page_end = 1;
647
2/2
✓ Branch 0 taken 18747 times.
✓ Branch 1 taken 813 times.
19560 for (i = os->segp; i < os->nsegs; i++)
648
2/2
✓ Branch 0 taken 12098 times.
✓ Branch 1 taken 6649 times.
18747 if (os->segments[i] < 255) {
649 12098 os->page_end = 0;
650 12098 break;
651 }
652
653
2/2
✓ Branch 0 taken 567 times.
✓ Branch 1 taken 12344 times.
12911 if (os->segp == os->nsegs)
654 567 ogg->curidx = -1;
655
656 12911 return 0;
657 }
658
659 54 static int ogg_get_length(AVFormatContext *s)
660 {
661 54 struct ogg *ogg = s->priv_data;
662 int i, ret;
663 int64_t size, end;
664 54 int streams_left=0;
665
666
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
667 return 0;
668
669 // already set
670
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (s->duration != AV_NOPTS_VALUE)
671 return 0;
672
673 54 size = avio_size(s->pb);
674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (size < 0)
675 return 0;
676 54 end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
677
678 54 ret = ogg_save(s);
679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ret < 0)
680 return ret;
681 54 avio_seek(s->pb, end, SEEK_SET);
682 54 ogg->page_pos = -1;
683
684
2/2
✓ Branch 1 taken 642 times.
✓ Branch 2 taken 54 times.
696 while (!ogg_read_page(s, &i, 1)) {
685
5/6
✓ Branch 0 taken 642 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 607 times.
✓ Branch 3 taken 35 times.
✓ Branch 4 taken 537 times.
✓ Branch 5 taken 70 times.
642 if (i >= 0 && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
686
1/2
✓ Branch 0 taken 537 times.
✗ Branch 1 not taken.
537 ogg->streams[i].codec) {
687 537 s->streams[i]->duration =
688 537 ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 537 times.
537 if (s->streams[i]->start_time != AV_NOPTS_VALUE) {
690 s->streams[i]->duration -= s->streams[i]->start_time;
691 streams_left-= (ogg->streams[i].got_start==-1);
692 ogg->streams[i].got_start= 1;
693
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 481 times.
537 } else if(!ogg->streams[i].got_start) {
694 56 ogg->streams[i].got_start= -1;
695 56 streams_left++;
696 }
697 }
698 }
699
700 54 ogg_restore(s);
701
702 54 ret = ogg_save(s);
703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ret < 0)
704 return ret;
705
706 54 avio_seek (s->pb, ffformatcontext(s)->data_offset, SEEK_SET);
707 54 ogg_reset(s);
708
3/4
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 54 times.
✓ Branch 3 taken 85 times.
✗ Branch 4 not taken.
139 while (streams_left > 0 && !ogg_packet(s, &i, NULL, NULL, NULL)) {
709 int64_t pts;
710
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 83 times.
85 if (i < 0) continue;
711 83 pts = ogg_calc_pts(s, i, NULL);
712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 if (s->streams[i]->duration == AV_NOPTS_VALUE)
713 continue;
714
6/6
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 39 times.
✓ Branch 4 taken 41 times.
✓ Branch 5 taken 1 times.
83 if (pts != AV_NOPTS_VALUE && s->streams[i]->start_time == AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
715 41 s->streams[i]->duration -= pts;
716 41 ogg->streams[i].got_start= 1;
717 41 streams_left--;
718
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 24 times.
42 }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
719 15 ogg->streams[i].got_start= 1;
720 15 streams_left--;
721 }
722 }
723 54 ogg_restore (s);
724
725 54 return 0;
726 }
727
728 54 static int ogg_read_close(AVFormatContext *s)
729 {
730 54 struct ogg *ogg = s->priv_data;
731 int i;
732
733
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 54 times.
110 for (i = 0; i < ogg->nstreams; i++) {
734 56 free_stream(s, i);
735 }
736
737 54 ogg->nstreams = 0;
738
739 54 av_freep(&ogg->streams);
740 54 return 0;
741 }
742
743 54 static int ogg_read_header(AVFormatContext *s)
744 {
745 54 struct ogg *ogg = s->priv_data;
746 int ret, i;
747
748 54 ogg->curidx = -1;
749
750 //linear headers seek from start
751 do {
752 204 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
753
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
204 if (ret < 0)
754 return ret;
755
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 54 times.
204 } while (!ogg->headers);
756 54 av_log(s, AV_LOG_TRACE, "found headers\n");
757
758
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 54 times.
110 for (i = 0; i < ogg->nstreams; i++) {
759 56 struct ogg_stream *os = ogg->streams + i;
760
761
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (ogg->streams[i].header < 0) {
762 av_log(s, AV_LOG_ERROR, "Header parsing failed for stream %d\n", i);
763 ogg->streams[i].codec = NULL;
764 av_freep(&ogg->streams[i].private);
765
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56 times.
56 } else if (os->codec && os->nb_header < os->codec->nb_header) {
766 av_log(s, AV_LOG_WARNING,
767 "Headers mismatch for stream %d: "
768 "expected %d received %d.\n",
769 i, os->codec->nb_header, os->nb_header);
770 if (s->error_recognition & AV_EF_EXPLODE)
771 return AVERROR_INVALIDDATA;
772 }
773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 if (os->start_granule != OGG_NOGRANULE_VALUE)
774 os->lastpts = s->streams[i]->start_time =
775 ogg_gptopts(s, i, os->start_granule, NULL);
776 }
777
778 //linear granulepos seek from end
779 54 ret = ogg_get_length(s);
780
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ret < 0)
781 return ret;
782
783 54 return 0;
784 }
785
786 12643 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
787 {
788 12643 struct ogg *ogg = s->priv_data;
789 12643 struct ogg_stream *os = ogg->streams + idx;
790 12643 int64_t pts = AV_NOPTS_VALUE;
791
792
2/2
✓ Branch 0 taken 12215 times.
✓ Branch 1 taken 428 times.
12643 if (dts)
793 12215 *dts = AV_NOPTS_VALUE;
794
795
2/2
✓ Branch 0 taken 1337 times.
✓ Branch 1 taken 11306 times.
12643 if (os->lastpts != AV_NOPTS_VALUE) {
796 1337 pts = os->lastpts;
797 1337 os->lastpts = AV_NOPTS_VALUE;
798 }
799
2/2
✓ Branch 0 taken 1245 times.
✓ Branch 1 taken 11398 times.
12643 if (os->lastdts != AV_NOPTS_VALUE) {
800
2/2
✓ Branch 0 taken 1191 times.
✓ Branch 1 taken 54 times.
1245 if (dts)
801 1191 *dts = os->lastdts;
802 1245 os->lastdts = AV_NOPTS_VALUE;
803 }
804
2/2
✓ Branch 0 taken 630 times.
✓ Branch 1 taken 12013 times.
12643 if (os->page_end) {
805
2/2
✓ Branch 0 taken 621 times.
✓ Branch 1 taken 9 times.
630 if (os->granule != -1LL) {
806
2/4
✓ Branch 0 taken 621 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 621 times.
621 if (os->codec && os->codec->granule_is_start)
807 pts = ogg_gptopts(s, idx, os->granule, dts);
808 else
809 621 os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts);
810 621 os->granule = -1LL;
811 }
812 }
813 12643 return pts;
814 }
815
816 12560 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
817 {
818 12560 struct ogg *ogg = s->priv_data;
819 12560 struct ogg_stream *os = ogg->streams + idx;
820 12560 int invalid = 0;
821
2/2
✓ Branch 0 taken 12412 times.
✓ Branch 1 taken 148 times.
12560 if (psize) {
822
3/3
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 181 times.
✓ Branch 2 taken 12191 times.
12412 switch (s->streams[idx]->codecpar->codec_id) {
823 40 case AV_CODEC_ID_THEORA:
824 40 invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 0x40);
825 40 break;
826 181 case AV_CODEC_ID_VP8:
827 181 invalid = !!(os->pflags & AV_PKT_FLAG_KEY) != !(os->buf[pstart] & 1);
828 }
829
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12407 times.
12412 if (invalid) {
830 5 os->pflags ^= AV_PKT_FLAG_KEY;
831 5 av_log(s, AV_LOG_WARNING, "Broken file, %skeyframe not correctly marked.\n",
832
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 (os->pflags & AV_PKT_FLAG_KEY) ? "" : "non-");
833 }
834 }
835 12560 }
836
837 12261 static int ogg_read_packet(AVFormatContext *s, AVPacket *pkt)
838 {
839 struct ogg *ogg;
840 struct ogg_stream *os;
841 int idx, ret;
842 int pstart, psize;
843 int64_t fpos, pts, dts;
844
845
1/2
✓ Branch 0 taken 12261 times.
✗ Branch 1 not taken.
12261 if (s->io_repositioned) {
846 ogg_reset(s);
847 s->io_repositioned = 0;
848 }
849
850 //Get an ogg packet
851 12261 retry:
852 do {
853 12287 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
854
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 12241 times.
12287 if (ret < 0)
855 46 return ret;
856
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12215 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12215 times.
12241 } while (idx < 0 || !s->streams[idx]);
857
858 12215 ogg = s->priv_data;
859 12215 os = ogg->streams + idx;
860
861 // pflags might not be set until after this
862 12215 pts = ogg_calc_pts(s, idx, &dts);
863 12215 ogg_validate_keyframe(s, idx, pstart, psize);
864
865
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12215 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12215 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
866 goto retry;
867 12215 os->keyframe_seek = 0;
868
869 //Alloc a pkt
870 12215 ret = av_new_packet(pkt, psize);
871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12215 times.
12215 if (ret < 0)
872 return ret;
873 12215 pkt->stream_index = idx;
874 12215 memcpy(pkt->data, os->buf + pstart, psize);
875
876 12215 pkt->pts = pts;
877 12215 pkt->dts = dts;
878 12215 pkt->flags = os->pflags;
879 12215 pkt->duration = os->pduration;
880 12215 pkt->pos = fpos;
881
882
4/4
✓ Branch 0 taken 12202 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 12183 times.
12215 if (os->start_trimming || os->end_trimming) {
883 32 uint8_t *side_data = av_packet_new_side_data(pkt,
884 AV_PKT_DATA_SKIP_SAMPLES,
885 10);
886
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if(!side_data)
887 return AVERROR(ENOMEM);
888 32 AV_WL32(side_data + 0, os->start_trimming);
889 32 AV_WL32(side_data + 4, os->end_trimming);
890 32 os->start_trimming = 0;
891 32 os->end_trimming = 0;
892 }
893
894
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 12205 times.
12215 if (os->replace) {
895 10 os->replace = 0;
896 10 pkt->dts = pkt->pts = AV_NOPTS_VALUE;
897 }
898
899
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 12171 times.
12215 if (os->new_metadata) {
900 44 ret = av_packet_add_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA,
901 os->new_metadata, os->new_metadata_size);
902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 if (ret < 0)
903 return ret;
904
905 44 os->new_metadata = NULL;
906 44 os->new_metadata_size = 0;
907 }
908
909
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12211 times.
12215 if (os->new_extradata) {
910 4 ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
911 os->new_extradata, os->new_extradata_size);
912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
913 return ret;
914
915 4 os->new_extradata = NULL;
916 4 os->new_extradata_size = 0;
917 }
918
919 12215 return psize;
920 }
921
922 124 static int64_t ogg_read_timestamp(AVFormatContext *s, int stream_index,
923 int64_t *pos_arg, int64_t pos_limit)
924 {
925 124 struct ogg *ogg = s->priv_data;
926 124 AVIOContext *bc = s->pb;
927 124 int64_t pts = AV_NOPTS_VALUE;
928 124 int64_t keypos = -1;
929 int i;
930 int pstart, psize;
931 124 avio_seek(bc, *pos_arg, SEEK_SET);
932 124 ogg_reset(s);
933
934 466 while ( avio_tell(bc) <= pos_limit
935
4/4
✓ Branch 0 taken 463 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 381 times.
✓ Branch 4 taken 82 times.
466 && !ogg_packet(s, &i, &pstart, &psize, pos_arg)) {
936
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 36 times.
381 if (i == stream_index) {
937 345 struct ogg_stream *os = ogg->streams + stream_index;
938 // Do not trust the last timestamps of an ogm video
939
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 317 times.
345 if ( (os->flags & OGG_FLAG_EOS)
940
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 && !(os->flags & OGG_FLAG_BOS)
941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 && os->codec == &ff_ogm_video_codec)
942 continue;
943 345 pts = ogg_calc_pts(s, i, NULL);
944 345 ogg_validate_keyframe(s, i, pstart, psize);
945
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 345 times.
345 if (os->pflags & AV_PKT_FLAG_KEY) {
946 keypos = *pos_arg;
947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 345 times.
345 } else if (os->keyframe_seek) {
948 // if we had a previous keyframe but no pts for it,
949 // return that keyframe with this pts value.
950 if (keypos >= 0)
951 *pos_arg = keypos;
952 else
953 pts = AV_NOPTS_VALUE;
954 }
955 }
956
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 342 times.
381 if (pts != AV_NOPTS_VALUE)
957 39 break;
958 }
959 124 ogg_reset(s);
960 124 return pts;
961 }
962
963 29 static int ogg_read_seek(AVFormatContext *s, int stream_index,
964 int64_t timestamp, int flags)
965 {
966 29 struct ogg *ogg = s->priv_data;
967 29 struct ogg_stream *os = ogg->streams + stream_index;
968 int ret;
969
970
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 av_assert0(stream_index < ogg->nstreams);
971 // Ensure everything is reset even when seeking via
972 // the generated index.
973 29 ogg_reset(s);
974
975 // Try seeking to a keyframe first. If this fails (very possible),
976 // av_seek_frame will fall back to ignoring keyframes
977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (s->streams[stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
978 && !(flags & AVSEEK_FLAG_ANY))
979 os->keyframe_seek = 1;
980
981 29 ret = ff_seek_frame_binary(s, stream_index, timestamp, flags);
982 29 ogg_reset(s);
983 29 os = ogg->streams + stream_index;
984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (ret < 0)
985 os->keyframe_seek = 0;
986 29 return ret;
987 }
988
989 8025 static int ogg_probe(const AVProbeData *p)
990 {
991
3/4
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 7976 times.
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
8025 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
992 49 return AVPROBE_SCORE_MAX;
993 7976 return 0;
994 }
995
996 const FFInputFormat ff_ogg_demuxer = {
997 .p.name = "ogg",
998 .p.long_name = NULL_IF_CONFIG_SMALL("Ogg"),
999 .p.extensions = "ogg",
1000 .p.flags = AVFMT_GENERIC_INDEX | AVFMT_TS_DISCONT | AVFMT_NOBINSEARCH,
1001 .priv_data_size = sizeof(struct ogg),
1002 .flags_internal = FF_INFMT_FLAG_INIT_CLEANUP,
1003 .read_probe = ogg_probe,
1004 .read_header = ogg_read_header,
1005 .read_packet = ogg_read_packet,
1006 .read_close = ogg_read_close,
1007 .read_seek = ogg_read_seek,
1008 .read_timestamp = ogg_read_timestamp,
1009 };
1010