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