ffmpeg / libavformat / oggdec.c @ d8b91fae
History | View | Annotate | Download (15.3 KB)
1 |
/*
|
---|---|
2 |
* Ogg bitstream support
|
3 |
* Luca Barbato <lu_zero@gentoo.org>
|
4 |
* Based on tcvp implementation
|
5 |
*
|
6 |
*/
|
7 |
|
8 |
/**
|
9 |
Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
|
10 |
|
11 |
Permission is hereby granted, free of charge, to any person
|
12 |
obtaining a copy of this software and associated documentation
|
13 |
files (the "Software"), to deal in the Software without
|
14 |
restriction, including without limitation the rights to use, copy,
|
15 |
modify, merge, publish, distribute, sublicense, and/or sell copies
|
16 |
of the Software, and to permit persons to whom the Software is
|
17 |
furnished to do so, subject to the following conditions:
|
18 |
|
19 |
The above copyright notice and this permission notice shall be
|
20 |
included in all copies or substantial portions of the Software.
|
21 |
|
22 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
23 |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
24 |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
25 |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
26 |
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
27 |
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
28 |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
29 |
DEALINGS IN THE SOFTWARE.
|
30 |
**/
|
31 |
|
32 |
|
33 |
#include <stdio.h> |
34 |
#include "oggdec.h" |
35 |
#include "avformat.h" |
36 |
|
37 |
#define MAX_PAGE_SIZE 65307 |
38 |
#define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
|
39 |
|
40 |
static const struct ogg_codec * const ogg_codecs[] = { |
41 |
&ff_skeleton_codec, |
42 |
&ff_dirac_codec, |
43 |
&ff_speex_codec, |
44 |
&ff_vorbis_codec, |
45 |
&ff_theora_codec, |
46 |
&ff_flac_codec, |
47 |
&ff_old_dirac_codec, |
48 |
&ff_old_flac_codec, |
49 |
&ff_ogm_video_codec, |
50 |
&ff_ogm_audio_codec, |
51 |
&ff_ogm_text_codec, |
52 |
&ff_ogm_old_codec, |
53 |
NULL
|
54 |
}; |
55 |
|
56 |
//FIXME We could avoid some structure duplication
|
57 |
static int |
58 |
ogg_save (AVFormatContext * s) |
59 |
{ |
60 |
struct ogg *ogg = s->priv_data;
|
61 |
struct ogg_state *ost =
|
62 |
av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams)); |
63 |
int i;
|
64 |
ost->pos = url_ftell (s->pb); |
65 |
ost->curidx = ogg->curidx; |
66 |
ost->next = ogg->state; |
67 |
ost->nstreams = ogg->nstreams; |
68 |
memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
|
69 |
|
70 |
for (i = 0; i < ogg->nstreams; i++){ |
71 |
struct ogg_stream *os = ogg->streams + i;
|
72 |
os->buf = av_malloc (os->bufsize); |
73 |
memset (os->buf, 0, os->bufsize);
|
74 |
memcpy (os->buf, ost->streams[i].buf, os->bufpos); |
75 |
} |
76 |
|
77 |
ogg->state = ost; |
78 |
|
79 |
return 0; |
80 |
} |
81 |
|
82 |
static int |
83 |
ogg_restore (AVFormatContext * s, int discard)
|
84 |
{ |
85 |
struct ogg *ogg = s->priv_data;
|
86 |
ByteIOContext *bc = s->pb; |
87 |
struct ogg_state *ost = ogg->state;
|
88 |
int i;
|
89 |
|
90 |
if (!ost)
|
91 |
return 0; |
92 |
|
93 |
ogg->state = ost->next; |
94 |
|
95 |
if (!discard){
|
96 |
for (i = 0; i < ogg->nstreams; i++) |
97 |
av_free (ogg->streams[i].buf); |
98 |
|
99 |
url_fseek (bc, ost->pos, SEEK_SET); |
100 |
ogg->curidx = ost->curidx; |
101 |
ogg->nstreams = ost->nstreams; |
102 |
memcpy(ogg->streams, ost->streams, |
103 |
ost->nstreams * sizeof(*ogg->streams));
|
104 |
} |
105 |
|
106 |
av_free (ost); |
107 |
|
108 |
return 0; |
109 |
} |
110 |
|
111 |
static int |
112 |
ogg_reset (struct ogg * ogg)
|
113 |
{ |
114 |
int i;
|
115 |
|
116 |
for (i = 0; i < ogg->nstreams; i++){ |
117 |
struct ogg_stream *os = ogg->streams + i;
|
118 |
os->bufpos = 0;
|
119 |
os->pstart = 0;
|
120 |
os->psize = 0;
|
121 |
os->granule = -1;
|
122 |
os->lastpts = AV_NOPTS_VALUE; |
123 |
os->lastdts = AV_NOPTS_VALUE; |
124 |
os->sync_pos = -1;
|
125 |
os->page_pos = 0;
|
126 |
os->nsegs = 0;
|
127 |
os->segp = 0;
|
128 |
os->incomplete = 0;
|
129 |
} |
130 |
|
131 |
ogg->curidx = -1;
|
132 |
|
133 |
return 0; |
134 |
} |
135 |
|
136 |
static const struct ogg_codec * |
137 |
ogg_find_codec (uint8_t * buf, int size)
|
138 |
{ |
139 |
int i;
|
140 |
|
141 |
for (i = 0; ogg_codecs[i]; i++) |
142 |
if (size >= ogg_codecs[i]->magicsize &&
|
143 |
!memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize)) |
144 |
return ogg_codecs[i];
|
145 |
|
146 |
return NULL; |
147 |
} |
148 |
|
149 |
static int |
150 |
ogg_new_stream (AVFormatContext * s, uint32_t serial) |
151 |
{ |
152 |
|
153 |
struct ogg *ogg = s->priv_data;
|
154 |
int idx = ogg->nstreams++;
|
155 |
AVStream *st; |
156 |
struct ogg_stream *os;
|
157 |
|
158 |
ogg->streams = av_realloc (ogg->streams, |
159 |
ogg->nstreams * sizeof (*ogg->streams));
|
160 |
memset (ogg->streams + idx, 0, sizeof (*ogg->streams)); |
161 |
os = ogg->streams + idx; |
162 |
os->serial = serial; |
163 |
os->bufsize = DECODER_BUFFER_SIZE; |
164 |
os->buf = av_malloc(os->bufsize); |
165 |
os->header = -1;
|
166 |
|
167 |
st = av_new_stream (s, idx); |
168 |
if (!st)
|
169 |
return AVERROR(ENOMEM);
|
170 |
|
171 |
av_set_pts_info(st, 64, 1, 1000000); |
172 |
|
173 |
return idx;
|
174 |
} |
175 |
|
176 |
static int |
177 |
ogg_new_buf(struct ogg *ogg, int idx) |
178 |
{ |
179 |
struct ogg_stream *os = ogg->streams + idx;
|
180 |
uint8_t *nb = av_malloc(os->bufsize); |
181 |
int size = os->bufpos - os->pstart;
|
182 |
if(os->buf){
|
183 |
memcpy(nb, os->buf + os->pstart, size); |
184 |
av_free(os->buf); |
185 |
} |
186 |
os->buf = nb; |
187 |
os->bufpos = size; |
188 |
os->pstart = 0;
|
189 |
|
190 |
return 0; |
191 |
} |
192 |
|
193 |
static int |
194 |
ogg_read_page (AVFormatContext * s, int *str)
|
195 |
{ |
196 |
ByteIOContext *bc = s->pb; |
197 |
struct ogg *ogg = s->priv_data;
|
198 |
struct ogg_stream *os;
|
199 |
int i = 0; |
200 |
int flags, nsegs;
|
201 |
uint64_t gp; |
202 |
uint32_t serial; |
203 |
uint32_t seq; |
204 |
uint32_t crc; |
205 |
int size, idx;
|
206 |
uint8_t sync[4];
|
207 |
int sp = 0; |
208 |
|
209 |
if (get_buffer (bc, sync, 4) < 4) |
210 |
return -1; |
211 |
|
212 |
do{
|
213 |
int c;
|
214 |
|
215 |
if (sync[sp & 3] == 'O' && |
216 |
sync[(sp + 1) & 3] == 'g' && |
217 |
sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S') |
218 |
break;
|
219 |
|
220 |
c = url_fgetc (bc); |
221 |
if (c < 0) |
222 |
return -1; |
223 |
sync[sp++ & 3] = c;
|
224 |
}while (i++ < MAX_PAGE_SIZE);
|
225 |
|
226 |
if (i >= MAX_PAGE_SIZE){
|
227 |
av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
|
228 |
return -1; |
229 |
} |
230 |
|
231 |
if (url_fgetc (bc) != 0) /* version */ |
232 |
return -1; |
233 |
|
234 |
flags = url_fgetc (bc); |
235 |
gp = get_le64 (bc); |
236 |
serial = get_le32 (bc); |
237 |
seq = get_le32 (bc); |
238 |
crc = get_le32 (bc); |
239 |
nsegs = url_fgetc (bc); |
240 |
|
241 |
idx = ogg_find_stream (ogg, serial); |
242 |
if (idx < 0){ |
243 |
idx = ogg_new_stream (s, serial); |
244 |
if (idx < 0) |
245 |
return -1; |
246 |
} |
247 |
|
248 |
os = ogg->streams + idx; |
249 |
os->page_pos = url_ftell(bc) - 27;
|
250 |
|
251 |
if(os->psize > 0) |
252 |
ogg_new_buf(ogg, idx); |
253 |
|
254 |
if (get_buffer (bc, os->segments, nsegs) < nsegs)
|
255 |
return -1; |
256 |
|
257 |
os->nsegs = nsegs; |
258 |
os->segp = 0;
|
259 |
|
260 |
size = 0;
|
261 |
for (i = 0; i < nsegs; i++) |
262 |
size += os->segments[i]; |
263 |
|
264 |
if (flags & OGG_FLAG_CONT || os->incomplete){
|
265 |
if (!os->psize){
|
266 |
while (os->segp < os->nsegs){
|
267 |
int seg = os->segments[os->segp++];
|
268 |
os->pstart += seg; |
269 |
if (seg < 255) |
270 |
break;
|
271 |
} |
272 |
os->sync_pos = os->page_pos; |
273 |
} |
274 |
}else{
|
275 |
os->psize = 0;
|
276 |
os->sync_pos = os->page_pos; |
277 |
} |
278 |
|
279 |
if (os->bufsize - os->bufpos < size){
|
280 |
uint8_t *nb = av_malloc (os->bufsize *= 2);
|
281 |
memcpy (nb, os->buf, os->bufpos); |
282 |
av_free (os->buf); |
283 |
os->buf = nb; |
284 |
} |
285 |
|
286 |
if (get_buffer (bc, os->buf + os->bufpos, size) < size)
|
287 |
return -1; |
288 |
|
289 |
os->bufpos += size; |
290 |
os->granule = gp; |
291 |
os->flags = flags; |
292 |
|
293 |
if (str)
|
294 |
*str = idx; |
295 |
|
296 |
return 0; |
297 |
} |
298 |
|
299 |
static int |
300 |
ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize, int64_t *fpos) |
301 |
{ |
302 |
struct ogg *ogg = s->priv_data;
|
303 |
int idx, i;
|
304 |
struct ogg_stream *os;
|
305 |
int complete = 0; |
306 |
int segp = 0, psize = 0; |
307 |
|
308 |
#if 0
|
309 |
av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
|
310 |
#endif
|
311 |
|
312 |
do{
|
313 |
idx = ogg->curidx; |
314 |
|
315 |
while (idx < 0){ |
316 |
if (ogg_read_page (s, &idx) < 0) |
317 |
return -1; |
318 |
} |
319 |
|
320 |
os = ogg->streams + idx; |
321 |
|
322 |
#if 0
|
323 |
av_log (s, AV_LOG_DEBUG,
|
324 |
"ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
|
325 |
idx, os->pstart, os->psize, os->segp, os->nsegs);
|
326 |
#endif
|
327 |
|
328 |
if (!os->codec){
|
329 |
if (os->header < 0){ |
330 |
os->codec = ogg_find_codec (os->buf, os->bufpos); |
331 |
if (!os->codec){
|
332 |
os->header = 0;
|
333 |
return 0; |
334 |
} |
335 |
}else{
|
336 |
return 0; |
337 |
} |
338 |
} |
339 |
|
340 |
segp = os->segp; |
341 |
psize = os->psize; |
342 |
|
343 |
while (os->segp < os->nsegs){
|
344 |
int ss = os->segments[os->segp++];
|
345 |
os->psize += ss; |
346 |
if (ss < 255){ |
347 |
complete = 1;
|
348 |
break;
|
349 |
} |
350 |
} |
351 |
|
352 |
if (!complete && os->segp == os->nsegs){
|
353 |
ogg->curidx = -1;
|
354 |
os->incomplete = 1;
|
355 |
} |
356 |
}while (!complete);
|
357 |
|
358 |
#if 0
|
359 |
av_log (s, AV_LOG_DEBUG,
|
360 |
"ogg_packet: idx %i, frame size %i, start %i\n",
|
361 |
idx, os->psize, os->pstart);
|
362 |
#endif
|
363 |
|
364 |
ogg->curidx = idx; |
365 |
os->incomplete = 0;
|
366 |
|
367 |
if (!ogg->headers){
|
368 |
int hdr = os->codec->header (s, idx);
|
369 |
os->header = os->seq; |
370 |
if (!hdr){
|
371 |
os->segp = segp; |
372 |
os->psize = psize; |
373 |
ogg->headers = 1;
|
374 |
s->data_offset = os->sync_pos; |
375 |
}else{
|
376 |
os->pstart += os->psize; |
377 |
os->psize = 0;
|
378 |
} |
379 |
} |
380 |
|
381 |
if (os->header > -1 && os->seq > os->header){ |
382 |
os->pflags = 0;
|
383 |
os->pduration = 0;
|
384 |
if (os->codec && os->codec->packet)
|
385 |
os->codec->packet (s, idx); |
386 |
if (str)
|
387 |
*str = idx; |
388 |
if (dstart)
|
389 |
*dstart = os->pstart; |
390 |
if (dsize)
|
391 |
*dsize = os->psize; |
392 |
if (fpos)
|
393 |
*fpos = os->sync_pos; |
394 |
os->pstart += os->psize; |
395 |
os->psize = 0;
|
396 |
os->sync_pos = os->page_pos; |
397 |
} |
398 |
|
399 |
// determine whether there are more complete packets in this page
|
400 |
// if not, the page's granule will apply to this packet
|
401 |
os->page_end = 1;
|
402 |
for (i = os->segp; i < os->nsegs; i++)
|
403 |
if (os->segments[i] < 255) { |
404 |
os->page_end = 0;
|
405 |
break;
|
406 |
} |
407 |
|
408 |
os->seq++; |
409 |
if (os->segp == os->nsegs)
|
410 |
ogg->curidx = -1;
|
411 |
|
412 |
return 0; |
413 |
} |
414 |
|
415 |
static int |
416 |
ogg_get_headers (AVFormatContext * s) |
417 |
{ |
418 |
struct ogg *ogg = s->priv_data;
|
419 |
|
420 |
do{
|
421 |
if (ogg_packet (s, NULL, NULL, NULL, NULL) < 0) |
422 |
return -1; |
423 |
}while (!ogg->headers);
|
424 |
|
425 |
#if 0
|
426 |
av_log (s, AV_LOG_DEBUG, "found headers\n");
|
427 |
#endif
|
428 |
|
429 |
return 0; |
430 |
} |
431 |
|
432 |
static int |
433 |
ogg_get_length (AVFormatContext * s) |
434 |
{ |
435 |
struct ogg *ogg = s->priv_data;
|
436 |
int idx = -1, i; |
437 |
int64_t size, end; |
438 |
|
439 |
if(url_is_streamed(s->pb))
|
440 |
return 0; |
441 |
|
442 |
// already set
|
443 |
if (s->duration != AV_NOPTS_VALUE)
|
444 |
return 0; |
445 |
|
446 |
size = url_fsize(s->pb); |
447 |
if(size < 0) |
448 |
return 0; |
449 |
end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: 0;
|
450 |
|
451 |
ogg_save (s); |
452 |
url_fseek (s->pb, end, SEEK_SET); |
453 |
|
454 |
while (!ogg_read_page (s, &i)){
|
455 |
if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0 && |
456 |
ogg->streams[i].codec) |
457 |
idx = i; |
458 |
} |
459 |
|
460 |
if (idx != -1){ |
461 |
s->streams[idx]->duration = |
462 |
ogg_gptopts (s, idx, ogg->streams[idx].granule, NULL);
|
463 |
if (s->streams[idx]->start_time != AV_NOPTS_VALUE)
|
464 |
s->streams[idx]->duration -= s->streams[idx]->start_time; |
465 |
} |
466 |
|
467 |
ogg->size = size; |
468 |
ogg_restore (s, 0);
|
469 |
|
470 |
return 0; |
471 |
} |
472 |
|
473 |
|
474 |
static int |
475 |
ogg_read_header (AVFormatContext * s, AVFormatParameters * ap) |
476 |
{ |
477 |
struct ogg *ogg = s->priv_data;
|
478 |
int i;
|
479 |
ogg->curidx = -1;
|
480 |
//linear headers seek from start
|
481 |
if (ogg_get_headers (s) < 0){ |
482 |
return -1; |
483 |
} |
484 |
|
485 |
for (i = 0; i < ogg->nstreams; i++) |
486 |
if (ogg->streams[i].header < 0) |
487 |
ogg->streams[i].codec = NULL;
|
488 |
|
489 |
//linear granulepos seek from end
|
490 |
ogg_get_length (s); |
491 |
|
492 |
//fill the extradata in the per codec callbacks
|
493 |
return 0; |
494 |
} |
495 |
|
496 |
static int64_t ogg_calc_pts(AVFormatContext *s, int idx, int64_t *dts) |
497 |
{ |
498 |
struct ogg *ogg = s->priv_data;
|
499 |
struct ogg_stream *os = ogg->streams + idx;
|
500 |
int64_t pts = AV_NOPTS_VALUE; |
501 |
|
502 |
if (dts)
|
503 |
*dts = AV_NOPTS_VALUE; |
504 |
|
505 |
if (os->lastpts != AV_NOPTS_VALUE) {
|
506 |
pts = os->lastpts; |
507 |
os->lastpts = AV_NOPTS_VALUE; |
508 |
} |
509 |
if (os->lastdts != AV_NOPTS_VALUE) {
|
510 |
if (dts)
|
511 |
*dts = os->lastdts; |
512 |
os->lastdts = AV_NOPTS_VALUE; |
513 |
} |
514 |
if (os->page_end) {
|
515 |
if (os->granule != -1LL) { |
516 |
if (os->codec && os->codec->granule_is_start)
|
517 |
pts = ogg_gptopts(s, idx, os->granule, dts); |
518 |
else
|
519 |
os->lastpts = ogg_gptopts(s, idx, os->granule, &os->lastdts); |
520 |
os->granule = -1LL;
|
521 |
} else
|
522 |
av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
|
523 |
} |
524 |
return pts;
|
525 |
} |
526 |
|
527 |
static int |
528 |
ogg_read_packet (AVFormatContext * s, AVPacket * pkt) |
529 |
{ |
530 |
struct ogg *ogg;
|
531 |
struct ogg_stream *os;
|
532 |
int idx = -1; |
533 |
int pstart, psize;
|
534 |
int64_t fpos, pts, dts; |
535 |
|
536 |
//Get an ogg packet
|
537 |
retry:
|
538 |
do{
|
539 |
if (ogg_packet (s, &idx, &pstart, &psize, &fpos) < 0) |
540 |
return AVERROR(EIO);
|
541 |
}while (idx < 0 || !s->streams[idx]); |
542 |
|
543 |
ogg = s->priv_data; |
544 |
os = ogg->streams + idx; |
545 |
|
546 |
// pflags might not be set until after this
|
547 |
pts = ogg_calc_pts(s, idx, &dts); |
548 |
|
549 |
if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
|
550 |
goto retry;
|
551 |
os->keyframe_seek = 0;
|
552 |
|
553 |
//Alloc a pkt
|
554 |
if (av_new_packet (pkt, psize) < 0) |
555 |
return AVERROR(EIO);
|
556 |
pkt->stream_index = idx; |
557 |
memcpy (pkt->data, os->buf + pstart, psize); |
558 |
|
559 |
pkt->pts = pts; |
560 |
pkt->dts = dts; |
561 |
pkt->flags = os->pflags; |
562 |
pkt->duration = os->pduration; |
563 |
pkt->pos = fpos; |
564 |
|
565 |
return psize;
|
566 |
} |
567 |
|
568 |
|
569 |
static int |
570 |
ogg_read_close (AVFormatContext * s) |
571 |
{ |
572 |
struct ogg *ogg = s->priv_data;
|
573 |
int i;
|
574 |
|
575 |
for (i = 0; i < ogg->nstreams; i++){ |
576 |
av_free (ogg->streams[i].buf); |
577 |
av_free (ogg->streams[i].private); |
578 |
} |
579 |
av_free (ogg->streams); |
580 |
return 0; |
581 |
} |
582 |
|
583 |
|
584 |
static int64_t
|
585 |
ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
|
586 |
int64_t pos_limit) |
587 |
{ |
588 |
struct ogg *ogg = s->priv_data;
|
589 |
struct ogg_stream *os = ogg->streams + stream_index;
|
590 |
ByteIOContext *bc = s->pb; |
591 |
int64_t pts = AV_NOPTS_VALUE; |
592 |
int i;
|
593 |
url_fseek(bc, *pos_arg, SEEK_SET); |
594 |
ogg_reset(ogg); |
595 |
|
596 |
while (url_ftell(bc) < pos_limit && !ogg_packet(s, &i, NULL, NULL, pos_arg)) { |
597 |
if (i == stream_index) {
|
598 |
pts = ogg_calc_pts(s, i, NULL);
|
599 |
if (os->keyframe_seek && !(os->pflags & PKT_FLAG_KEY))
|
600 |
pts = AV_NOPTS_VALUE; |
601 |
} |
602 |
if (pts != AV_NOPTS_VALUE)
|
603 |
break;
|
604 |
} |
605 |
ogg_reset(ogg); |
606 |
return pts;
|
607 |
} |
608 |
|
609 |
static int ogg_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) |
610 |
{ |
611 |
struct ogg *ogg = s->priv_data;
|
612 |
struct ogg_stream *os = ogg->streams + stream_index;
|
613 |
int ret;
|
614 |
|
615 |
// Try seeking to a keyframe first. If this fails (very possible),
|
616 |
// av_seek_frame will fall back to ignoring keyframes
|
617 |
if (s->streams[stream_index]->codec->codec_type == CODEC_TYPE_VIDEO
|
618 |
&& !(flags & AVSEEK_FLAG_ANY)) |
619 |
os->keyframe_seek = 1;
|
620 |
|
621 |
ret = av_seek_frame_binary(s, stream_index, timestamp, flags); |
622 |
if (ret < 0) |
623 |
os->keyframe_seek = 0;
|
624 |
return ret;
|
625 |
} |
626 |
|
627 |
static int ogg_probe(AVProbeData *p) |
628 |
{ |
629 |
if (p->buf[0] == 'O' && p->buf[1] == 'g' && |
630 |
p->buf[2] == 'g' && p->buf[3] == 'S' && |
631 |
p->buf[4] == 0x0 && p->buf[5] <= 0x7 ) |
632 |
return AVPROBE_SCORE_MAX;
|
633 |
else
|
634 |
return 0; |
635 |
} |
636 |
|
637 |
AVInputFormat ogg_demuxer = { |
638 |
"ogg",
|
639 |
NULL_IF_CONFIG_SMALL("Ogg"),
|
640 |
sizeof (struct ogg), |
641 |
ogg_probe, |
642 |
ogg_read_header, |
643 |
ogg_read_packet, |
644 |
ogg_read_close, |
645 |
ogg_read_seek, |
646 |
ogg_read_timestamp, |
647 |
.extensions = "ogg",
|
648 |
.metadata_conv = ff_vorbiscomment_metadata_conv, |
649 |
}; |