FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/oggdec.c
Date: 2026-09-04 04:29:05
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 68 static void free_stream(AVFormatContext *s, int i)
67 {
68 68 struct ogg *ogg = s->priv_data;
69 68 struct ogg_stream *stream = &ogg->streams[i];
70
71 68 av_freep(&stream->buf);
72
1/2
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
68 if (stream->codec &&
73
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 34 times.
68 stream->codec->cleanup) {
74 34 stream->codec->cleanup(s, i);
75 }
76
77 68 av_freep(&stream->private);
78 68 av_freep(&stream->new_metadata);
79 68 av_freep(&stream->new_extradata);
80 68 }
81
82 //FIXME We could avoid some structure duplication
83 104 static int ogg_save(AVFormatContext *s)
84 {
85 104 struct ogg *ogg = s->priv_data;
86 struct ogg_state *ost =
87 104 av_malloc(sizeof(*ost) + (ogg->nstreams - 1) * sizeof(*ogg->streams));
88 int i;
89 104 int ret = 0;
90
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 104 times.
104 if (!ost)
92 return AVERROR(ENOMEM);
93
94 104 ost->pos = avio_tell(s->pb);
95 104 ost->curidx = ogg->curidx;
96 104 ost->next = ogg->state;
97 104 ost->nstreams = ogg->nstreams;
98 104 memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
99
100
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 104 times.
212 for (i = 0; i < ogg->nstreams; i++) {
101 108 struct ogg_stream *os = ogg->streams + i;
102 108 os->buf = av_mallocz(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
103
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 if (os->buf)
104 108 memcpy(os->buf, ost->streams[i].buf, os->bufpos);
105 else
106 ret = AVERROR(ENOMEM);
107 108 os->new_metadata = NULL;
108 108 os->new_metadata_size = 0;
109 108 os->new_extradata = NULL;
110 108 os->new_extradata_size = 0;
111 }
112
113 104 ogg->state = ost;
114
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 104 times.
104 if (ret < 0)
116 ogg_restore(s);
117
118 104 return ret;
119 }
120
121 104 static int ogg_restore(AVFormatContext *s)
122 {
123 104 struct ogg *ogg = s->priv_data;
124 104 AVIOContext *bc = s->pb;
125 104 struct ogg_state *ost = ogg->state;
126 int i, err;
127
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 104 times.
104 if (!ost)
129 return 0;
130
131 104 ogg->state = ost->next;
132
133
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 104 times.
212 for (i = 0; i < ogg->nstreams; i++) {
134 108 struct ogg_stream *stream = &ogg->streams[i];
135 108 av_freep(&stream->buf);
136 108 av_freep(&stream->new_metadata);
137 108 av_freep(&stream->new_extradata);
138
139
3/4
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 94 times.
108 if (i >= ost->nstreams || !ost->streams[i].private) {
140 14 free_stream(s, i);
141 }
142 }
143
144 104 avio_seek(bc, ost->pos, SEEK_SET);
145 104 ogg->page_pos = -1;
146 104 ogg->curidx = ost->curidx;
147 104 ogg->nstreams = ost->nstreams;
148
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 104 times.
104 if ((err = av_reallocp_array(&ogg->streams, ogg->nstreams,
149 sizeof(*ogg->streams))) < 0) {
150 ogg->nstreams = 0;
151 return err;
152 } else
153 104 memcpy(ogg->streams, ost->streams,
154 104 ost->nstreams * sizeof(*ogg->streams));
155
156 104 av_free(ost);
157
158 104 return 0;
159 }
160
161 358 static int ogg_reset(AVFormatContext *s)
162 {
163 358 struct ogg *ogg = s->priv_data;
164 int i;
165 358 int64_t start_pos = avio_tell(s->pb);
166
167
2/2
✓ Branch 0 taken 360 times.
✓ Branch 1 taken 358 times.
718 for (i = 0; i < ogg->nstreams; i++) {
168 360 struct ogg_stream *os = ogg->streams + i;
169 360 os->bufpos = 0;
170 360 os->pstart = 0;
171 360 os->psize = 0;
172 360 os->granule = -1;
173 360 os->lastpts = AV_NOPTS_VALUE;
174 360 os->lastdts = AV_NOPTS_VALUE;
175 360 os->sync_pos = -1;
176 360 os->page_pos = 0;
177 360 os->nsegs = 0;
178 360 os->segp = 0;
179 360 os->incomplete = 0;
180 360 os->got_data = 0;
181
2/2
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 254 times.
360 if (start_pos <= ffformatcontext(s)->data_offset) {
182 106 os->lastpts = 0;
183 }
184 360 os->start_trimming = 0;
185 360 os->end_trimming = 0;
186 360 av_freep(&os->new_metadata);
187 360 os->new_metadata_size = 0;
188 360 av_freep(&os->new_extradata);
189 360 os->new_extradata_size = 0;
190 }
191
192 358 ogg->page_pos = -1;
193 358 ogg->curidx = -1;
194
195 358 return 0;
196 }
197
198 74 static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size)
199 {
200 int i;
201
202
1/2
✓ Branch 0 taken 373 times.
✗ Branch 1 not taken.
373 for (i = 0; ogg_codecs[i]; i++)
203
1/2
✓ Branch 0 taken 373 times.
✗ Branch 1 not taken.
373 if (size >= ogg_codecs[i]->magicsize &&
204
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 299 times.
373 !memcmp(buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
205 74 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 54 static int ogg_new_stream(AVFormatContext *s, uint32_t serial)
253 {
254 54 struct ogg *ogg = s->priv_data;
255 54 int idx = ogg->nstreams;
256 AVStream *st;
257 struct ogg_stream *os;
258
259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 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 54 times.
54 if (!(os = av_realloc_array(ogg->streams, ogg->nstreams + 1,
267 sizeof(*ogg->streams))))
268 return AVERROR(ENOMEM);
269 54 ogg->streams = os;
270 54 os = ogg->streams + idx;
271 54 memset(os, 0, sizeof(*os));
272 54 os->serial = serial;
273 54 os->bufsize = DECODER_BUFFER_SIZE;
274 54 os->buf = av_malloc(os->bufsize + AV_INPUT_BUFFER_PADDING_SIZE);
275 54 os->header = -1;
276 54 os->start_granule = OGG_NOGRANULE_VALUE;
277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (!os->buf)
278 return AVERROR(ENOMEM);
279
280 /* Create the associated AVStream */
281 54 st = avformat_new_stream(s, NULL);
282
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (!st) {
283 av_freep(&os->buf);
284 return AVERROR(ENOMEM);
285 }
286 54 st->id = idx;
287 54 avpriv_set_pts_info(st, 64, 1, 1000000);
288
289 54 ogg->nstreams++;
290 54 return idx;
291 }
292
293 74 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 54 times.
76 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 54 return 0;
301 }
302
303 1816 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 1778 times.
1816 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 1816 return 0;
318 }
319
320 1952 static int ogg_read_page(AVFormatContext *s, int *sid, int probing)
321 {
322 1952 AVIOContext *bc = s->pb;
323 1952 struct ogg *ogg = s->priv_data;
324 struct ogg_stream *os;
325 1952 int ret, i = 0;
326 int flags, nsegs;
327 uint64_t gp;
328 uint32_t serial;
329 uint32_t crc, crc_tmp;
330 1952 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 1952 int sp = 0;
337
338 1952 ret = avio_read(bc, sync, 4);
339
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 1894 times.
1952 if (ret < 4)
340
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 return ret < 0 ? ret : AVERROR_EOF;
341
342 do {
343 int c;
344
345
2/2
✓ Branch 0 taken 4606 times.
✓ Branch 1 taken 701661 times.
706267 if (sync[sp & 3] == 'O' &&
346
2/2
✓ Branch 0 taken 1833 times.
✓ Branch 1 taken 2773 times.
4606 sync[(sp + 1) & 3] == 'g' &&
347
3/4
✓ Branch 0 taken 1816 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1816 times.
✗ Branch 3 not taken.
1833 sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
348 1816 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 1816 times.
1816 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 1816 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 1816 ret = ffio_ensure_seekback(bc, MAX_PAGE_SIZE);
374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1816 times.
1816 if (ret < 0)
375 return ret;
376 1816 start_pos = avio_tell(bc);
377
378 1816 version = avio_r8(bc);
379 1816 flags = avio_r8(bc);
380 1816 gp = avio_rl64(bc);
381 1816 serial = avio_rl32(bc);
382 1816 avio_rl32(bc); /* seq */
383
384 1816 crc_tmp = ffio_get_checksum(bc);
385 1816 crc = avio_rb32(bc);
386 1816 crc_tmp = ff_crc04C11DB7_update(crc_tmp, (uint8_t[4]){0}, 4);
387 1816 ffio_init_checksum(bc, ff_crc04C11DB7_update, crc_tmp);
388
389 1816 nsegs = avio_r8(bc);
390 1816 page_pos = avio_tell(bc) - 27;
391
392 1816 ret = avio_read(bc, segments, nsegs);
393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1816 times.
1816 if (ret < nsegs)
394 return ret < 0 ? ret : AVERROR_EOF;
395
396
2/2
✓ Branch 0 taken 47236 times.
✓ Branch 1 taken 1816 times.
49052 for (i = 0; i < nsegs; i++)
397 47236 size += segments[i];
398
399 1816 idx = ogg_find_stream(ogg, serial);
400
2/2
✓ Branch 0 taken 1742 times.
✓ Branch 1 taken 74 times.
1816 if (idx >= 0) {
401 1742 os = ogg->streams + idx;
402
403 1742 ret = buf_realloc(os, size);
404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1742 times.
1742 if (ret < 0)
405 return ret;
406
407 1742 readout_buf = os->buf + os->bufpos;
408 } else {
409 74 readout_buf = av_malloc(size);
410 }
411
412 1816 ret = avio_read(bc, readout_buf, size);
413
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 1772 times.
1816 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 1772 times.
1772 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 1772 times.
1772 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 74 times.
✓ Branch 1 taken 1698 times.
1772 if (idx < 0) {
441
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 54 times.
74 if (data_packets_seen(ogg))
442 20 idx = ogg_replace_stream(s, serial, readout_buf, size, probing);
443 else
444 54 idx = ogg_new_stream(s, serial);
445
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 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 74 os = ogg->streams + idx;
453
454 74 ret = buf_realloc(os, size);
455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (ret < 0) {
456 av_free(readout_buf);
457 return ret;
458 }
459
460 74 memcpy(os->buf + os->bufpos, readout_buf, size);
461 74 av_free(readout_buf);
462 }
463
464 1772 ogg->page_pos = page_pos;
465 1772 os->page_pos = page_pos;
466 1772 os->nsegs = nsegs;
467 1772 os->segp = 0;
468 1772 os->got_data = !(flags & OGG_FLAG_BOS);
469 1772 os->bufpos += size;
470 1772 os->granule = gp;
471 1772 os->flags = flags;
472 1772 memcpy(os->segments, segments, nsegs);
473 1772 memset(os->buf + os->bufpos, 0, AV_INPUT_BUFFER_PADDING_SIZE);
474
475
3/4
✓ Branch 0 taken 1130 times.
✓ Branch 1 taken 642 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1130 times.
1772 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 1130 os->psize = 0;
490 1130 os->sync_pos = os->page_pos;
491 }
492
493 /* This function is always called with sid != NULL */
494 1772 *sid = idx;
495
496 1772 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 13008 static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize,
507 int64_t *fpos)
508 {
509 13008 FFFormatContext *const si = ffformatcontext(s);
510 13008 struct ogg *ogg = s->priv_data;
511 int idx, i, ret;
512 struct ogg_stream *os;
513 13008 int complete = 0;
514 13008 int segp = 0, psize = 0;
515
516 13008 av_log(s, AV_LOG_TRACE, "ogg_packet: curidx=%i\n", ogg->curidx);
517
2/2
✓ Branch 0 taken 12810 times.
✓ Branch 1 taken 198 times.
13008 if (sid)
518 12810 *sid = -1;
519
520 do {
521 13460 idx = ogg->curidx;
522
523
2/2
✓ Branch 0 taken 1268 times.
✓ Branch 1 taken 13332 times.
14600 while (idx < 0) {
524 1268 ret = ogg_read_page(s, &idx, 0);
525
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 1140 times.
1268 if (ret < 0)
526 128 return ret;
527 }
528
529 13332 os = ogg->streams + idx;
530
531 13332 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 54 times.
✓ Branch 1 taken 13278 times.
13332 if (!os->codec) {
535
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (os->header < 0) {
536 54 os->codec = ogg_find_codec(os->buf, os->bufpos);
537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 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 13332 segp = os->segp;
548 13332 psize = os->psize;
549
550
2/2
✓ Branch 0 taken 26990 times.
✓ Branch 1 taken 452 times.
27442 while (os->segp < os->nsegs) {
551 26990 int ss = os->segments[os->segp++];
552 26990 os->psize += ss;
553
2/2
✓ Branch 0 taken 12880 times.
✓ Branch 1 taken 14110 times.
26990 if (ss < 255) {
554 12880 complete = 1;
555 12880 break;
556 }
557 }
558
559
3/4
✓ Branch 0 taken 452 times.
✓ Branch 1 taken 12880 times.
✓ Branch 2 taken 452 times.
✗ Branch 3 not taken.
13332 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 12880 times.
13332 } while (!complete);
568
569
570
2/2
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 12702 times.
12880 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 12880 ogg->curidx = idx;
576 12880 os->incomplete = 0;
577
578 // the packet started at the first segment of the page it completes on
579 12880 os->page_start = segp == 0;
580
581
2/2
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 12678 times.
12880 if (os->header) {
582
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 202 times.
202 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 202 os->header = ret;
587
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 146 times.
202 if (!os->header) {
588 56 os->segp = segp;
589 56 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 56 ogg->headers = 1;
595
596 // Update the header state for all streams and
597 // compute the data_offset.
598
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 4 times.
56 if (!si->data_offset)
599 52 si->data_offset = os->sync_pos;
600
601
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 56 times.
118 for (i = 0; i < ogg->nstreams; i++) {
602 62 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 62 times.
62 if (cur_os->incomplete)
607 si->data_offset = FFMIN(si->data_offset, cur_os->sync_pos);
608 }
609 } else {
610 146 os->nb_header++;
611 146 os->pstart += os->psize;
612 146 os->psize = 0;
613 }
614 } else {
615 12678 os->pflags = 0;
616 12678 os->pduration = 0;
617
618 12678 ret = 0;
619
2/4
✓ Branch 0 taken 12678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12678 times.
✗ Branch 3 not taken.
12678 if (os->codec && os->codec->packet) {
620
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12678 times.
12678 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 12618 times.
✓ Branch 1 taken 60 times.
12678 if (!ret) {
627
1/2
✓ Branch 0 taken 12618 times.
✗ Branch 1 not taken.
12618 if (sid)
628 12618 *sid = idx;
629
2/2
✓ Branch 0 taken 12537 times.
✓ Branch 1 taken 81 times.
12618 if (dstart)
630 12537 *dstart = os->pstart;
631
2/2
✓ Branch 0 taken 12537 times.
✓ Branch 1 taken 81 times.
12618 if (dsize)
632 12537 *dsize = os->psize;
633
2/2
✓ Branch 0 taken 12537 times.
✓ Branch 1 taken 81 times.
12618 if (fpos)
634 12537 *fpos = os->sync_pos;
635 }
636
637 12678 os->pstart += os->psize;
638 12678 os->psize = 0;
639
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 12090 times.
12678 if(os->pstart == os->bufpos)
640 588 os->bufpos = os->pstart = 0;
641 12678 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 12880 os->page_end = 1;
647
2/2
✓ Branch 0 taken 18696 times.
✓ Branch 1 taken 809 times.
19505 for (i = os->segp; i < os->nsegs; i++)
648
2/2
✓ Branch 0 taken 12071 times.
✓ Branch 1 taken 6625 times.
18696 if (os->segments[i] < 255) {
649 12071 os->page_end = 0;
650 12071 break;
651 }
652
653
2/2
✓ Branch 0 taken 563 times.
✓ Branch 1 taken 12317 times.
12880 if (os->segp == os->nsegs)
654 563 ogg->curidx = -1;
655
656 12880 return 0;
657 }
658
659 52 static int ogg_get_length(AVFormatContext *s)
660 {
661 52 struct ogg *ogg = s->priv_data;
662 int i, ret;
663 int64_t size, end;
664 52 int streams_left=0;
665
666
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL))
667 return 0;
668
669 // already set
670
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (s->duration != AV_NOPTS_VALUE)
671 return 0;
672
673 52 size = avio_size(s->pb);
674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (size < 0)
675 return 0;
676 52 end = size > MAX_PAGE_SIZE ? size - MAX_PAGE_SIZE : 0;
677
678 52 ret = ogg_save(s);
679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (ret < 0)
680 return ret;
681 52 avio_seek(s->pb, end, SEEK_SET);
682 52 ogg->page_pos = -1;
683
684
2/2
✓ Branch 1 taken 632 times.
✓ Branch 2 taken 52 times.
684 while (!ogg_read_page(s, &i, 1)) {
685
5/6
✓ Branch 0 taken 632 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 597 times.
✓ Branch 3 taken 35 times.
✓ Branch 4 taken 531 times.
✓ Branch 5 taken 66 times.
632 if (i >= 0 && ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 &&
686
1/2
✓ Branch 0 taken 531 times.
✗ Branch 1 not taken.
531 ogg->streams[i].codec) {
687 531 s->streams[i]->duration =
688 531 ogg_gptopts(s, i, ogg->streams[i].granule, NULL);
689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 531 times.
531 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 54 times.
✓ Branch 1 taken 477 times.
531 } else if(!ogg->streams[i].got_start) {
694 54 ogg->streams[i].got_start= -1;
695 54 streams_left++;
696 }
697 }
698 }
699
700 52 ogg_restore(s);
701
702 52 ret = ogg_save(s);
703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (ret < 0)
704 return ret;
705
706 52 avio_seek (s->pb, ffformatcontext(s)->data_offset, SEEK_SET);
707 52 ogg_reset(s);
708
3/4
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 52 times.
✓ Branch 3 taken 83 times.
✗ Branch 4 not taken.
135 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 81 times.
83 if (i < 0) continue;
711 81 pts = ogg_calc_pts(s, i, NULL);
712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 if (s->streams[i]->duration == AV_NOPTS_VALUE)
713 continue;
714
6/6
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 37 times.
✓ Branch 4 taken 41 times.
✓ Branch 5 taken 1 times.
81 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 37 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 24 times.
40 }else if(s->streams[i]->start_time != AV_NOPTS_VALUE && !ogg->streams[i].got_start) {
719 13 ogg->streams[i].got_start= 1;
720 13 streams_left--;
721 }
722 }
723 52 ogg_restore (s);
724
725 52 return 0;
726 }
727
728 52 static int ogg_read_close(AVFormatContext *s)
729 {
730 52 struct ogg *ogg = s->priv_data;
731 int i;
732
733
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 52 times.
106 for (i = 0; i < ogg->nstreams; i++) {
734 54 free_stream(s, i);
735 }
736
737 52 ogg->nstreams = 0;
738
739 52 av_freep(&ogg->streams);
740 52 return 0;
741 }
742
743 52 static int ogg_read_header(AVFormatContext *s)
744 {
745 52 struct ogg *ogg = s->priv_data;
746 int ret, i;
747
748 52 ogg->curidx = -1;
749
750 //linear headers seek from start
751 do {
752 198 ret = ogg_packet(s, NULL, NULL, NULL, NULL);
753
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 if (ret < 0)
754 return ret;
755
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 52 times.
198 } while (!ogg->headers);
756 52 av_log(s, AV_LOG_TRACE, "found headers\n");
757
758
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 52 times.
106 for (i = 0; i < ogg->nstreams; i++) {
759 54 struct ogg_stream *os = ogg->streams + i;
760
761
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 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 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 } 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 54 times.
54 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 52 ret = ogg_get_length(s);
780
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
52 if (ret < 0)
781 return ret;
782
783 52 return 0;
784 }
785
786 12618 static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts)
787 {
788 12618 struct ogg *ogg = s->priv_data;
789 12618 struct ogg_stream *os = ogg->streams + idx;
790 12618 int64_t pts = AV_NOPTS_VALUE;
791
792
2/2
✓ Branch 0 taken 12192 times.
✓ Branch 1 taken 426 times.
12618 if (dts)
793 12192 *dts = AV_NOPTS_VALUE;
794
795
2/2
✓ Branch 0 taken 1312 times.
✓ Branch 1 taken 11306 times.
12618 if (os->lastpts != AV_NOPTS_VALUE) {
796 1312 pts = os->lastpts;
797 1312 os->lastpts = AV_NOPTS_VALUE;
798 }
799
2/2
✓ Branch 0 taken 1220 times.
✓ Branch 1 taken 11398 times.
12618 if (os->lastdts != AV_NOPTS_VALUE) {
800
2/2
✓ Branch 0 taken 1168 times.
✓ Branch 1 taken 52 times.
1220 if (dts)
801 1168 *dts = os->lastdts;
802 1220 os->lastdts = AV_NOPTS_VALUE;
803 }
804
2/2
✓ Branch 0 taken 630 times.
✓ Branch 1 taken 11988 times.
12618 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 12618 return pts;
814 }
815
816 12537 static void ogg_validate_keyframe(AVFormatContext *s, int idx, int pstart, int psize)
817 {
818 12537 struct ogg *ogg = s->priv_data;
819 12537 struct ogg_stream *os = ogg->streams + idx;
820 12537 int invalid = 0;
821
2/2
✓ Branch 0 taken 12389 times.
✓ Branch 1 taken 148 times.
12537 if (psize) {
822
3/3
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 181 times.
✓ Branch 2 taken 12168 times.
12389 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 12384 times.
12389 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 12537 }
836
837 12238 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 12238 times.
✗ Branch 1 not taken.
12238 if (s->io_repositioned) {
846 ogg_reset(s);
847 s->io_repositioned = 0;
848 }
849
850 //Get an ogg packet
851 12238 retry:
852 do {
853 12264 ret = ogg_packet(s, &idx, &pstart, &psize, &fpos);
854
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 12218 times.
12264 if (ret < 0)
855 46 return ret;
856
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 12192 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12192 times.
12218 } while (idx < 0 || !s->streams[idx]);
857
858 12192 ogg = s->priv_data;
859 12192 os = ogg->streams + idx;
860
861 // pflags might not be set until after this
862 12192 pts = ogg_calc_pts(s, idx, &dts);
863 12192 ogg_validate_keyframe(s, idx, pstart, psize);
864
865
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12192 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12192 if (os->keyframe_seek && !(os->pflags & AV_PKT_FLAG_KEY))
866 goto retry;
867 12192 os->keyframe_seek = 0;
868
869 //Alloc a pkt
870 12192 ret = av_new_packet(pkt, psize);
871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12192 times.
12192 if (ret < 0)
872 return ret;
873 12192 pkt->stream_index = idx;
874 12192 memcpy(pkt->data, os->buf + pstart, psize);
875
876 12192 pkt->pts = pts;
877 12192 pkt->dts = dts;
878 12192 pkt->flags = os->pflags;
879 12192 pkt->duration = os->pduration;
880 12192 pkt->pos = fpos;
881
882
4/4
✓ Branch 0 taken 12181 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 12162 times.
12192 if (os->start_trimming || os->end_trimming) {
883 30 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 30 times.
30 if(!side_data)
887 return AVERROR(ENOMEM);
888 30 AV_WL32(side_data + 0, os->start_trimming);
889 30 AV_WL32(side_data + 4, os->end_trimming);
890 30 os->start_trimming = 0;
891 30 os->end_trimming = 0;
892 }
893
894
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 12182 times.
12192 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 12148 times.
12192 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 12188 times.
12192 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 12192 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 7961 static int ogg_probe(const AVProbeData *p)
990 {
991
3/4
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 7914 times.
✓ Branch 2 taken 47 times.
✗ Branch 3 not taken.
7961 if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7)
992 47 return AVPROBE_SCORE_MAX;
993 7914 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