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