1 | /*
|
---|
2 | * Ogg bitstream support
|
---|
3 | * Luca Barbato <[email protected]>
|
---|
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 "ogg2.h"
|
---|
35 | #include "avformat.h"
|
---|
36 |
|
---|
37 | #define MAX_PAGE_SIZE 65307
|
---|
38 | #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
|
---|
39 |
|
---|
40 | static ogg_codec_t *ogg_codecs[] = {
|
---|
41 | &vorbis_codec,
|
---|
42 | &theora_codec,
|
---|
43 | &flac_codec,
|
---|
44 | &ogm_video_codec,
|
---|
45 | &ogm_audio_codec,
|
---|
46 | &ogm_old_codec,
|
---|
47 | NULL
|
---|
48 | };
|
---|
49 |
|
---|
50 | #if 0 // CONFIG_MUXERS
|
---|
51 | static int
|
---|
52 | ogg_write_header (AVFormatContext * avfcontext)
|
---|
53 | {
|
---|
54 | }
|
---|
55 |
|
---|
56 | static int
|
---|
57 | ogg_write_packet (AVFormatContext * avfcontext, AVPacket * pkt)
|
---|
58 | {
|
---|
59 | }
|
---|
60 |
|
---|
61 |
|
---|
62 | static int
|
---|
63 | ogg_write_trailer (AVFormatContext * avfcontext)
|
---|
64 | {
|
---|
65 | }
|
---|
66 |
|
---|
67 |
|
---|
68 | static AVOutputFormat ogg_muxer = {
|
---|
69 | "ogg",
|
---|
70 | "Ogg Vorbis",
|
---|
71 | "audio/x-vorbis",
|
---|
72 | "ogg",
|
---|
73 | sizeof (OggContext),
|
---|
74 | CODEC_ID_VORBIS,
|
---|
75 | 0,
|
---|
76 | ogg_write_header,
|
---|
77 | ogg_write_packet,
|
---|
78 | ogg_write_trailer,
|
---|
79 | };
|
---|
80 | #endif //CONFIG_MUXERS
|
---|
81 |
|
---|
82 | //FIXME We could avoid some structure duplication
|
---|
83 | static int
|
---|
84 | ogg_save (AVFormatContext * s)
|
---|
85 | {
|
---|
86 | ogg_t *ogg = s->priv_data;
|
---|
87 | ogg_state_t *ost =
|
---|
88 | av_malloc(sizeof (*ost) + (ogg->nstreams-1) * sizeof (*ogg->streams));
|
---|
89 | int i;
|
---|
90 | ost->pos = url_ftell (&s->pb);;
|
---|
91 | ost->curidx = ogg->curidx;
|
---|
92 | ost->next = ogg->state;
|
---|
93 | memcpy(ost->streams, ogg->streams, ogg->nstreams * sizeof(*ogg->streams));
|
---|
94 |
|
---|
95 | for (i = 0; i < ogg->nstreams; i++){
|
---|
96 | ogg_stream_t *os = ogg->streams + i;
|
---|
97 | os->buf = av_malloc (os->bufsize);
|
---|
98 | memset (os->buf, 0, os->bufsize);
|
---|
99 | memcpy (os->buf, ost->streams[i].buf, os->bufpos);
|
---|
100 | }
|
---|
101 |
|
---|
102 | ogg->state = ost;
|
---|
103 |
|
---|
104 | return 0;
|
---|
105 | }
|
---|
106 |
|
---|
107 | static int
|
---|
108 | ogg_restore (AVFormatContext * s, int discard)
|
---|
109 | {
|
---|
110 | ogg_t *ogg = s->priv_data;
|
---|
111 | ByteIOContext *bc = &s->pb;
|
---|
112 | ogg_state_t *ost = ogg->state;
|
---|
113 | int i;
|
---|
114 |
|
---|
115 | if (!ost)
|
---|
116 | return 0;
|
---|
117 |
|
---|
118 | ogg->state = ost->next;
|
---|
119 |
|
---|
120 | if (!discard){
|
---|
121 | for (i = 0; i < ogg->nstreams; i++)
|
---|
122 | av_free (ogg->streams[i].buf);
|
---|
123 |
|
---|
124 | url_fseek (bc, ost->pos, SEEK_SET);
|
---|
125 | ogg->curidx = ost->curidx;
|
---|
126 | memcpy (ogg->streams, ost->streams,
|
---|
127 | ogg->nstreams * sizeof (*ogg->streams));
|
---|
128 | }
|
---|
129 |
|
---|
130 | av_free (ost);
|
---|
131 |
|
---|
132 | return 0;
|
---|
133 | }
|
---|
134 |
|
---|
135 | static int
|
---|
136 | ogg_reset (ogg_t * ogg)
|
---|
137 | {
|
---|
138 | int i;
|
---|
139 |
|
---|
140 | for (i = 0; i < ogg->nstreams; i++){
|
---|
141 | ogg_stream_t *os = ogg->streams + i;
|
---|
142 | os->bufpos = 0;
|
---|
143 | os->pstart = 0;
|
---|
144 | os->psize = 0;
|
---|
145 | os->granule = -1;
|
---|
146 | os->lastgp = -1;
|
---|
147 | os->nsegs = 0;
|
---|
148 | os->segp = 0;
|
---|
149 | }
|
---|
150 |
|
---|
151 | ogg->curidx = -1;
|
---|
152 |
|
---|
153 | return 0;
|
---|
154 | }
|
---|
155 |
|
---|
156 | static ogg_codec_t *
|
---|
157 | ogg_find_codec (uint8_t * buf, int size)
|
---|
158 | {
|
---|
159 | int i;
|
---|
160 |
|
---|
161 | for (i = 0; ogg_codecs[i]; i++)
|
---|
162 | if (size >= ogg_codecs[i]->magicsize &&
|
---|
163 | !memcmp (buf, ogg_codecs[i]->magic, ogg_codecs[i]->magicsize))
|
---|
164 | return ogg_codecs[i];
|
---|
165 |
|
---|
166 | return NULL;
|
---|
167 | }
|
---|
168 |
|
---|
169 | static int
|
---|
170 | ogg_find_stream (ogg_t * ogg, int serial)
|
---|
171 | {
|
---|
172 | int i;
|
---|
173 |
|
---|
174 | for (i = 0; i < ogg->nstreams; i++)
|
---|
175 | if (ogg->streams[i].serial == serial)
|
---|
176 | return i;
|
---|
177 |
|
---|
178 | return -1;
|
---|
179 | }
|
---|
180 |
|
---|
181 | static int
|
---|
182 | ogg_new_stream (AVFormatContext * s, uint32_t serial)
|
---|
183 | {
|
---|
184 |
|
---|
185 | ogg_t *ogg = s->priv_data;
|
---|
186 | int idx = ogg->nstreams++;
|
---|
187 | AVStream *st;
|
---|
188 | ogg_stream_t *os;
|
---|
189 |
|
---|
190 | ogg->streams = av_realloc (ogg->streams,
|
---|
191 | ogg->nstreams * sizeof (*ogg->streams));
|
---|
192 | memset (ogg->streams + idx, 0, sizeof (*ogg->streams));
|
---|
193 | os = ogg->streams + idx;
|
---|
194 | os->serial = serial;
|
---|
195 | os->bufsize = DECODER_BUFFER_SIZE;
|
---|
196 | os->buf = av_malloc(os->bufsize);
|
---|
197 | os->header = -1;
|
---|
198 |
|
---|
199 | st = av_new_stream (s, idx);
|
---|
200 | if (!st)
|
---|
201 | return AVERROR_NOMEM;
|
---|
202 |
|
---|
203 | av_set_pts_info(st, 64, 1, 1000000);
|
---|
204 | st->start_time = 0;
|
---|
205 |
|
---|
206 | return idx;
|
---|
207 | }
|
---|
208 |
|
---|
209 | static int
|
---|
210 | ogg_new_buf(ogg_t *ogg, int idx)
|
---|
211 | {
|
---|
212 | ogg_stream_t *os = ogg->streams + idx;
|
---|
213 | uint8_t *nb = av_malloc(os->bufsize);
|
---|
214 | int size = os->bufpos - os->pstart;
|
---|
215 | if(os->buf){
|
---|
216 | memcpy(nb, os->buf + os->pstart, size);
|
---|
217 | av_free(os->buf);
|
---|
218 | }
|
---|
219 | os->buf = nb;
|
---|
220 | os->bufpos = size;
|
---|
221 | os->pstart = 0;
|
---|
222 |
|
---|
223 | return 0;
|
---|
224 | }
|
---|
225 |
|
---|
226 | static int
|
---|
227 | ogg_read_page (AVFormatContext * s, int *str)
|
---|
228 | {
|
---|
229 | ByteIOContext *bc = &s->pb;
|
---|
230 | ogg_t *ogg = s->priv_data;
|
---|
231 | ogg_stream_t *os;
|
---|
232 | int i = 0;
|
---|
233 | int flags, nsegs;
|
---|
234 | uint64_t gp;
|
---|
235 | uint32_t serial;
|
---|
236 | uint32_t seq;
|
---|
237 | uint32_t crc;
|
---|
238 | int size, idx;
|
---|
239 | char sync[4];
|
---|
240 | int sp = 0;
|
---|
241 |
|
---|
242 | if (get_buffer (bc, sync, 4) < 4)
|
---|
243 | return -1;
|
---|
244 |
|
---|
245 | do{
|
---|
246 | int c;
|
---|
247 |
|
---|
248 | if (sync[sp & 3] == 'O' &&
|
---|
249 | sync[(sp + 1) & 3] == 'g' &&
|
---|
250 | sync[(sp + 2) & 3] == 'g' && sync[(sp + 3) & 3] == 'S')
|
---|
251 | break;
|
---|
252 |
|
---|
253 | c = url_fgetc (bc);
|
---|
254 | if (c < 0)
|
---|
255 | return -1;
|
---|
256 | sync[sp++ & 3] = c;
|
---|
257 | }while (i++ < MAX_PAGE_SIZE);
|
---|
258 |
|
---|
259 | if (i >= MAX_PAGE_SIZE){
|
---|
260 | av_log (s, AV_LOG_INFO, "ogg, can't find sync word\n");
|
---|
261 | return -1;
|
---|
262 | }
|
---|
263 |
|
---|
264 | if (url_fgetc (bc) != 0) /* version */
|
---|
265 | return -1;
|
---|
266 |
|
---|
267 | flags = url_fgetc (bc);
|
---|
268 | gp = get_le64 (bc);
|
---|
269 | serial = get_le32 (bc);
|
---|
270 | seq = get_le32 (bc);
|
---|
271 | crc = get_le32 (bc);
|
---|
272 | nsegs = url_fgetc (bc);
|
---|
273 |
|
---|
274 | idx = ogg_find_stream (ogg, serial);
|
---|
275 | if (idx < 0){
|
---|
276 | idx = ogg_new_stream (s, serial);
|
---|
277 | if (idx < 0)
|
---|
278 | return -1;
|
---|
279 | }
|
---|
280 |
|
---|
281 | os = ogg->streams + idx;
|
---|
282 |
|
---|
283 | if(os->psize > 0)
|
---|
284 | ogg_new_buf(ogg, idx);
|
---|
285 |
|
---|
286 | if (get_buffer (bc, os->segments, nsegs) < nsegs)
|
---|
287 | return -1;
|
---|
288 |
|
---|
289 | os->nsegs = nsegs;
|
---|
290 | os->segp = 0;
|
---|
291 |
|
---|
292 | size = 0;
|
---|
293 | for (i = 0; i < nsegs; i++)
|
---|
294 | size += os->segments[i];
|
---|
295 |
|
---|
296 | if (flags & OGG_FLAG_CONT){
|
---|
297 | if (!os->psize){
|
---|
298 | while (os->segp < os->nsegs){
|
---|
299 | int seg = os->segments[os->segp++];
|
---|
300 | os->pstart += seg;
|
---|
301 | if (seg < 255)
|
---|
302 | break;
|
---|
303 | }
|
---|
304 | }
|
---|
305 | }else{
|
---|
306 | os->psize = 0;
|
---|
307 | }
|
---|
308 |
|
---|
309 | if (os->bufsize - os->bufpos < size){
|
---|
310 | uint8_t *nb = av_malloc (os->bufsize *= 2);
|
---|
311 | memset (nb, 0, os->bufsize);
|
---|
312 | memcpy (nb, os->buf, os->bufpos);
|
---|
313 | av_free (os->buf);
|
---|
314 | os->buf = nb;
|
---|
315 | }
|
---|
316 |
|
---|
317 | if (get_buffer (bc, os->buf + os->bufpos, size) < size)
|
---|
318 | return -1;
|
---|
319 |
|
---|
320 | os->lastgp = os->granule;
|
---|
321 | os->bufpos += size;
|
---|
322 | os->granule = gp;
|
---|
323 | os->flags = flags;
|
---|
324 |
|
---|
325 | if (str)
|
---|
326 | *str = idx;
|
---|
327 |
|
---|
328 | return 0;
|
---|
329 | }
|
---|
330 |
|
---|
331 | static int
|
---|
332 | ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
|
---|
333 | {
|
---|
334 | ogg_t *ogg = s->priv_data;
|
---|
335 | int idx;
|
---|
336 | ogg_stream_t *os;
|
---|
337 | int complete = 0;
|
---|
338 | int segp = 0, psize = 0;
|
---|
339 |
|
---|
340 | #if 0
|
---|
341 | av_log (s, AV_LOG_DEBUG, "ogg_packet: curidx=%i\n", ogg->curidx);
|
---|
342 | #endif
|
---|
343 |
|
---|
344 | do{
|
---|
345 | idx = ogg->curidx;
|
---|
346 |
|
---|
347 | while (idx < 0){
|
---|
348 | if (ogg_read_page (s, &idx) < 0)
|
---|
349 | return -1;
|
---|
350 | }
|
---|
351 |
|
---|
352 | os = ogg->streams + idx;
|
---|
353 |
|
---|
354 | #if 0
|
---|
355 | av_log (s, AV_LOG_DEBUG,
|
---|
356 | "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
|
---|
357 | idx, os->pstart, os->psize, os->segp, os->nsegs);
|
---|
358 | #endif
|
---|
359 |
|
---|
360 | if (!os->codec){
|
---|
361 | if (os->header < 0){
|
---|
362 | os->codec = ogg_find_codec (os->buf, os->bufpos);
|
---|
363 | if (!os->codec){
|
---|
364 | os->header = 0;
|
---|
365 | return 0;
|
---|
366 | }
|
---|
367 | }else{
|
---|
368 | return 0;
|
---|
369 | }
|
---|
370 | }
|
---|
371 |
|
---|
372 | segp = os->segp;
|
---|
373 | psize = os->psize;
|
---|
374 |
|
---|
375 | while (os->segp < os->nsegs){
|
---|
376 | int ss = os->segments[os->segp++];
|
---|
377 | os->psize += ss;
|
---|
378 | if (ss < 255){
|
---|
379 | complete = 1;
|
---|
380 | break;
|
---|
381 | }
|
---|
382 | }
|
---|
383 |
|
---|
384 | if (!complete && os->segp == os->nsegs){
|
---|
385 | ogg->curidx = -1;
|
---|
386 | }
|
---|
387 | }while (!complete);
|
---|
388 |
|
---|
389 | #if 0
|
---|
390 | av_log (s, AV_LOG_DEBUG,
|
---|
391 | "ogg_packet: idx %i, frame size %i, start %i\n",
|
---|
392 | idx, os->psize, os->pstart);
|
---|
393 | #endif
|
---|
394 |
|
---|
395 | ogg->curidx = idx;
|
---|
396 |
|
---|
397 | if (os->header < 0){
|
---|
398 | int hdr = os->codec->header (s, idx);
|
---|
399 | if (!hdr){
|
---|
400 | os->header = os->seq;
|
---|
401 | os->segp = segp;
|
---|
402 | os->psize = psize;
|
---|
403 | ogg->headers = 1;
|
---|
404 | }else{
|
---|
405 | os->pstart += os->psize;
|
---|
406 | os->psize = 0;
|
---|
407 | }
|
---|
408 | }
|
---|
409 |
|
---|
410 | if (os->header > -1 && os->seq > os->header){
|
---|
411 | if (os->codec && os->codec->packet)
|
---|
412 | os->codec->packet (s, idx);
|
---|
413 | if (str)
|
---|
414 | *str = idx;
|
---|
415 | if (dstart)
|
---|
416 | *dstart = os->pstart;
|
---|
417 | if (dsize)
|
---|
418 | *dsize = os->psize;
|
---|
419 | os->pstart += os->psize;
|
---|
420 | os->psize = 0;
|
---|
421 | }
|
---|
422 |
|
---|
423 | os->seq++;
|
---|
424 | if (os->segp == os->nsegs)
|
---|
425 | ogg->curidx = -1;
|
---|
426 |
|
---|
427 | return 0;
|
---|
428 | }
|
---|
429 |
|
---|
430 | static int
|
---|
431 | ogg_get_headers (AVFormatContext * s)
|
---|
432 | {
|
---|
433 | ogg_t *ogg = s->priv_data;
|
---|
434 |
|
---|
435 | do{
|
---|
436 | if (ogg_packet (s, NULL, NULL, NULL) < 0)
|
---|
437 | return -1;
|
---|
438 | }while (!ogg->headers);
|
---|
439 |
|
---|
440 | #if 0
|
---|
441 | av_log (s, AV_LOG_DEBUG, "found headers\n");
|
---|
442 | #endif
|
---|
443 |
|
---|
444 | return 0;
|
---|
445 | }
|
---|
446 |
|
---|
447 | static uint64_t
|
---|
448 | ogg_gptopts (AVFormatContext * s, int i, uint64_t gp)
|
---|
449 | {
|
---|
450 | ogg_t *ogg = s->priv_data;
|
---|
451 | ogg_stream_t *os = ogg->streams + i;
|
---|
452 | uint64_t pts = AV_NOPTS_VALUE;
|
---|
453 |
|
---|
454 | if(os->codec->gptopts){
|
---|
455 | pts = os->codec->gptopts(s, i, gp);
|
---|
456 | } else {
|
---|
457 | pts = gp;
|
---|
458 | }
|
---|
459 |
|
---|
460 | return pts;
|
---|
461 | }
|
---|
462 |
|
---|
463 |
|
---|
464 | static int
|
---|
465 | ogg_get_length (AVFormatContext * s)
|
---|
466 | {
|
---|
467 | ogg_t *ogg = s->priv_data;
|
---|
468 | int idx = -1, i;
|
---|
469 | offset_t size, end;
|
---|
470 |
|
---|
471 | if(s->pb.is_streamed)
|
---|
472 | return 0;
|
---|
473 |
|
---|
474 | // already set
|
---|
475 | if (s->duration != AV_NOPTS_VALUE)
|
---|
476 | return 0;
|
---|
477 |
|
---|
478 | size = url_fsize(&s->pb);
|
---|
479 | if(size < 0)
|
---|
480 | return 0;
|
---|
481 | end = size > MAX_PAGE_SIZE? size - MAX_PAGE_SIZE: size;
|
---|
482 |
|
---|
483 | ogg_save (s);
|
---|
484 | url_fseek (&s->pb, end, SEEK_SET);
|
---|
485 |
|
---|
486 | while (!ogg_read_page (s, &i)){
|
---|
487 | if (ogg->streams[i].granule != -1 && ogg->streams[i].granule != 0)
|
---|
488 | idx = i;
|
---|
489 | }
|
---|
490 |
|
---|
491 | if (idx != -1){
|
---|
492 | s->streams[idx]->duration =
|
---|
493 | ogg_gptopts (s, idx, ogg->streams[idx].granule);
|
---|
494 | }
|
---|
495 |
|
---|
496 | ogg->size = size;
|
---|
497 | ogg_restore (s, 0);
|
---|
498 |
|
---|
499 | return 0;
|
---|
500 | }
|
---|
501 |
|
---|
502 |
|
---|
503 | static int
|
---|
504 | ogg_read_header (AVFormatContext * s, AVFormatParameters * ap)
|
---|
505 | {
|
---|
506 | ogg_t *ogg = s->priv_data;
|
---|
507 | ogg->curidx = -1;
|
---|
508 | //linear headers seek from start
|
---|
509 | if (ogg_get_headers (s) < 0){
|
---|
510 | return -1;
|
---|
511 | }
|
---|
512 |
|
---|
513 | //linear granulepos seek from end
|
---|
514 | ogg_get_length (s);
|
---|
515 |
|
---|
516 | //fill the extradata in the per codec callbacks
|
---|
517 | return 0;
|
---|
518 | }
|
---|
519 |
|
---|
520 |
|
---|
521 | static int
|
---|
522 | ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
|
---|
523 | {
|
---|
524 | ogg_t *ogg;
|
---|
525 | ogg_stream_t *os;
|
---|
526 | int idx = -1;
|
---|
527 | int pstart, psize;
|
---|
528 |
|
---|
529 | //Get an ogg packet
|
---|
530 | do{
|
---|
531 | if (ogg_packet (s, &idx, &pstart, &psize) < 0)
|
---|
532 | return AVERROR_IO;
|
---|
533 | }while (idx < 0 || !s->streams[idx]);
|
---|
534 |
|
---|
535 | ogg = s->priv_data;
|
---|
536 | os = ogg->streams + idx;
|
---|
537 |
|
---|
538 | //Alloc a pkt
|
---|
539 | if (av_new_packet (pkt, psize) < 0)
|
---|
540 | return AVERROR_IO;
|
---|
541 | pkt->stream_index = idx;
|
---|
542 | memcpy (pkt->data, os->buf + pstart, psize);
|
---|
543 | if (os->lastgp != -1LL){
|
---|
544 | pkt->pts = ogg_gptopts (s, idx, os->lastgp);
|
---|
545 | os->lastgp = -1;
|
---|
546 | }
|
---|
547 |
|
---|
548 | return psize;
|
---|
549 | }
|
---|
550 |
|
---|
551 |
|
---|
552 | static int
|
---|
553 | ogg_read_close (AVFormatContext * s)
|
---|
554 | {
|
---|
555 | ogg_t *ogg = s->priv_data;
|
---|
556 | int i;
|
---|
557 |
|
---|
558 | for (i = 0; i < ogg->nstreams; i++){
|
---|
559 | av_free (ogg->streams[i].buf);
|
---|
560 | av_free (ogg->streams[i].private);
|
---|
561 | }
|
---|
562 | av_free (ogg->streams);
|
---|
563 | return 0;
|
---|
564 | }
|
---|
565 |
|
---|
566 |
|
---|
567 | static int
|
---|
568 | ogg_read_seek (AVFormatContext * s, int stream_index, int64_t target_ts,
|
---|
569 | int flags)
|
---|
570 | {
|
---|
571 | AVStream *st = s->streams[stream_index];
|
---|
572 | ogg_t *ogg = s->priv_data;
|
---|
573 | ByteIOContext *bc = &s->pb;
|
---|
574 | uint64_t min = 0, max = ogg->size;
|
---|
575 | uint64_t tmin = 0, tmax = st->duration;
|
---|
576 | int64_t pts = AV_NOPTS_VALUE;
|
---|
577 |
|
---|
578 | ogg_save (s);
|
---|
579 |
|
---|
580 | while (min <= max){
|
---|
581 | uint64_t p = min + (max - min) * (target_ts - tmin) / (tmax - tmin);
|
---|
582 | int i = -1;
|
---|
583 |
|
---|
584 | url_fseek (bc, p, SEEK_SET);
|
---|
585 |
|
---|
586 | while (!ogg_read_page (s, &i)){
|
---|
587 | if (i == stream_index && ogg->streams[i].granule != 0 &&
|
---|
588 | ogg->streams[i].granule != -1)
|
---|
589 | break;
|
---|
590 | }
|
---|
591 |
|
---|
592 | if (i == -1)
|
---|
593 | break;
|
---|
594 |
|
---|
595 | pts = ogg_gptopts (s, i, ogg->streams[i].granule);
|
---|
596 | p = url_ftell (bc);
|
---|
597 |
|
---|
598 | if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den)
|
---|
599 | break;
|
---|
600 |
|
---|
601 | if (pts > target_ts){
|
---|
602 | max = p;
|
---|
603 | tmax = pts;
|
---|
604 | }else{
|
---|
605 | min = p;
|
---|
606 | tmin = pts;
|
---|
607 | }
|
---|
608 | }
|
---|
609 |
|
---|
610 | if (ABS (pts - target_ts) * st->time_base.num < st->time_base.den){
|
---|
611 | ogg_restore (s, 1);
|
---|
612 | ogg_reset (ogg);
|
---|
613 | }else{
|
---|
614 | ogg_restore (s, 0);
|
---|
615 | pts = AV_NOPTS_VALUE;
|
---|
616 | }
|
---|
617 |
|
---|
618 | return pts;
|
---|
619 |
|
---|
620 | #if 0
|
---|
621 | //later...
|
---|
622 | int64_t pos;
|
---|
623 | if (av_seek_frame_binary (s, stream_index, target_ts, flags) < 0)
|
---|
624 | return -1;
|
---|
625 | pos = url_ftell (&s->pb);
|
---|
626 | ogg_read_timestamp (s, stream_index, &pos, pos - 1);
|
---|
627 | #endif
|
---|
628 |
|
---|
629 | }
|
---|
630 |
|
---|
631 | #if 0
|
---|
632 | static int64_t
|
---|
633 | ogg_read_timestamp (AVFormatContext * s, int stream_index, int64_t * pos_arg,
|
---|
634 | int64_t pos_limit)
|
---|
635 | {
|
---|
636 | ogg_t *ogg = s->priv_data;
|
---|
637 | ByteIOContext *bc = &s->pb;
|
---|
638 | int64_t pos, pts;
|
---|
639 |
|
---|
640 | if (*pos_arg < 0)
|
---|
641 | return AV_NOPTS_VALUE;
|
---|
642 |
|
---|
643 | pos = *pos_arg;
|
---|
644 | }
|
---|
645 | #endif
|
---|
646 |
|
---|
647 | static int ogg_probe(AVProbeData *p)
|
---|
648 | {
|
---|
649 | if (p->buf_size < 6)
|
---|
650 | return 0;
|
---|
651 | if (p->buf[0] == 'O' && p->buf[1] == 'g' &&
|
---|
652 | p->buf[2] == 'g' && p->buf[3] == 'S' &&
|
---|
653 | p->buf[4] == 0x0 && p->buf[5] <= 0x7 )
|
---|
654 | return AVPROBE_SCORE_MAX;
|
---|
655 | else
|
---|
656 | return 0;
|
---|
657 | }
|
---|
658 |
|
---|
659 | static AVInputFormat ogg_demuxer = {
|
---|
660 | "ogg",
|
---|
661 | "Ogg",
|
---|
662 | sizeof (ogg_t),
|
---|
663 | ogg_probe,
|
---|
664 | ogg_read_header,
|
---|
665 | ogg_read_packet,
|
---|
666 | ogg_read_close,
|
---|
667 | ogg_read_seek,
|
---|
668 | // ogg_read_timestamp,
|
---|
669 | .extensions = "ogg",
|
---|
670 | };
|
---|
671 |
|
---|
672 | int
|
---|
673 | ogg_init (void)
|
---|
674 | {
|
---|
675 | #if 0 // CONFIG_MUXERS
|
---|
676 | av_register_output_format (&ogg_muxer);
|
---|
677 | #endif
|
---|
678 | av_register_input_format (&ogg_demuxer);
|
---|
679 | return 0;
|
---|
680 | }
|
---|