2 * Ogg bitstream support
3 * Luca Barbato <lu_zero@gentoo.org>
4 * Based on tcvp implementation
9 Copyright (C) 2005 Michael Ahlberg, Måns Rullgård
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:
19 The above copyright notice and this permission notice shall be
20 included in all copies or substantial portions of the Software.
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.
37 #define MAX_PAGE_SIZE 65307
38 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
40 static const ogg_codec_t
* const ogg_codecs
[] = {
53 //FIXME We could avoid some structure duplication
55 ogg_save (AVFormatContext
* s
)
57 ogg_t
*ogg
= s
->priv_data
;
59 av_malloc(sizeof (*ost
) + (ogg
->nstreams
-1) * sizeof (*ogg
->streams
));
61 ost
->pos
= url_ftell (s
->pb
);
62 ost
->curidx
= ogg
->curidx
;
63 ost
->next
= ogg
->state
;
64 ost
->nstreams
= ogg
->nstreams
;
65 memcpy(ost
->streams
, ogg
->streams
, ogg
->nstreams
* sizeof(*ogg
->streams
));
67 for (i
= 0; i
< ogg
->nstreams
; i
++){
68 ogg_stream_t
*os
= ogg
->streams
+ i
;
69 os
->buf
= av_malloc (os
->bufsize
);
70 memset (os
->buf
, 0, os
->bufsize
);
71 memcpy (os
->buf
, ost
->streams
[i
].buf
, os
->bufpos
);
80 ogg_restore (AVFormatContext
* s
, int discard
)
82 ogg_t
*ogg
= s
->priv_data
;
83 ByteIOContext
*bc
= s
->pb
;
84 ogg_state_t
*ost
= ogg
->state
;
90 ogg
->state
= ost
->next
;
93 for (i
= 0; i
< ogg
->nstreams
; i
++)
94 av_free (ogg
->streams
[i
].buf
);
96 url_fseek (bc
, ost
->pos
, SEEK_SET
);
97 ogg
->curidx
= ost
->curidx
;
98 ogg
->nstreams
= ost
->nstreams
;
99 memcpy(ogg
->streams
, ost
->streams
,
100 ost
->nstreams
* sizeof(*ogg
->streams
));
109 ogg_reset (ogg_t
* ogg
)
113 for (i
= 0; i
< ogg
->nstreams
; i
++){
114 ogg_stream_t
*os
= ogg
->streams
+ i
;
129 static const ogg_codec_t
*
130 ogg_find_codec (uint8_t * buf
, int size
)
134 for (i
= 0; ogg_codecs
[i
]; i
++)
135 if (size
>= ogg_codecs
[i
]->magicsize
&&
136 !memcmp (buf
, ogg_codecs
[i
]->magic
, ogg_codecs
[i
]->magicsize
))
137 return ogg_codecs
[i
];
143 ogg_find_stream (ogg_t
* ogg
, int serial
)
147 for (i
= 0; i
< ogg
->nstreams
; i
++)
148 if (ogg
->streams
[i
].serial
== serial
)
155 ogg_new_stream (AVFormatContext
* s
, uint32_t serial
)
158 ogg_t
*ogg
= s
->priv_data
;
159 int idx
= ogg
->nstreams
++;
163 ogg
->streams
= av_realloc (ogg
->streams
,
164 ogg
->nstreams
* sizeof (*ogg
->streams
));
165 memset (ogg
->streams
+ idx
, 0, sizeof (*ogg
->streams
));
166 os
= ogg
->streams
+ idx
;
168 os
->bufsize
= DECODER_BUFFER_SIZE
;
169 os
->buf
= av_malloc(os
->bufsize
);
172 st
= av_new_stream (s
, idx
);
174 return AVERROR(ENOMEM
);
176 av_set_pts_info(st
, 64, 1, 1000000);
182 ogg_new_buf(ogg_t
*ogg
, int idx
)
184 ogg_stream_t
*os
= ogg
->streams
+ idx
;
185 uint8_t *nb
= av_malloc(os
->bufsize
);
186 int size
= os
->bufpos
- os
->pstart
;
188 memcpy(nb
, os
->buf
+ os
->pstart
, size
);
199 ogg_read_page (AVFormatContext
* s
, int *str
)
201 ByteIOContext
*bc
= s
->pb
;
202 ogg_t
*ogg
= s
->priv_data
;
214 if (get_buffer (bc
, sync
, 4) < 4)
220 if (sync
[sp
& 3] == 'O' &&
221 sync
[(sp
+ 1) & 3] == 'g' &&
222 sync
[(sp
+ 2) & 3] == 'g' && sync
[(sp
+ 3) & 3] == 'S')
229 }while (i
++ < MAX_PAGE_SIZE
);
231 if (i
>= MAX_PAGE_SIZE
){
232 av_log (s
, AV_LOG_INFO
, "ogg, can't find sync word\n");
236 if (url_fgetc (bc
) != 0) /* version */
239 flags
= url_fgetc (bc
);
241 serial
= get_le32 (bc
);
244 nsegs
= url_fgetc (bc
);
246 idx
= ogg_find_stream (ogg
, serial
);
248 idx
= ogg_new_stream (s
, serial
);
253 os
= ogg
->streams
+ idx
;
256 ogg_new_buf(ogg
, idx
);
258 if (get_buffer (bc
, os
->segments
, nsegs
) < nsegs
)
265 for (i
= 0; i
< nsegs
; i
++)
266 size
+= os
->segments
[i
];
268 if (flags
& OGG_FLAG_CONT
){
270 while (os
->segp
< os
->nsegs
){
271 int seg
= os
->segments
[os
->segp
++];
281 if (os
->bufsize
- os
->bufpos
< size
){
282 uint8_t *nb
= av_malloc (os
->bufsize
*= 2);
283 memcpy (nb
, os
->buf
, os
->bufpos
);
288 if (get_buffer (bc
, os
->buf
+ os
->bufpos
, size
) < size
)
291 os
->lastgp
= os
->granule
;
303 ogg_packet (AVFormatContext
* s
, int *str
, int *dstart
, int *dsize
)
305 ogg_t
*ogg
= s
->priv_data
;
309 int segp
= 0, psize
= 0;
312 av_log (s
, AV_LOG_DEBUG
, "ogg_packet: curidx=%i\n", ogg
->curidx
);
319 if (ogg_read_page (s
, &idx
) < 0)
323 os
= ogg
->streams
+ idx
;
326 av_log (s
, AV_LOG_DEBUG
,
327 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
328 idx
, os
->pstart
, os
->psize
, os
->segp
, os
->nsegs
);
333 os
->codec
= ogg_find_codec (os
->buf
, os
->bufpos
);
346 while (os
->segp
< os
->nsegs
){
347 int ss
= os
->segments
[os
->segp
++];
355 if (!complete
&& os
->segp
== os
->nsegs
){
361 av_log (s
, AV_LOG_DEBUG
,
362 "ogg_packet: idx %i, frame size %i, start %i\n",
363 idx
, os
->psize
, os
->pstart
);
369 int hdr
= os
->codec
->header (s
, idx
);
371 os
->header
= os
->seq
;
376 os
->pstart
+= os
->psize
;
381 if (os
->header
> -1 && os
->seq
> os
->header
){
383 if (os
->codec
&& os
->codec
->packet
)
384 os
->codec
->packet (s
, idx
);
388 *dstart
= os
->pstart
;
391 os
->pstart
+= os
->psize
;
396 if (os
->segp
== os
->nsegs
)
403 ogg_get_headers (AVFormatContext
* s
)
405 ogg_t
*ogg
= s
->priv_data
;
408 if (ogg_packet (s
, NULL
, NULL
, NULL
) < 0)
410 }while (!ogg
->headers
);
413 av_log (s
, AV_LOG_DEBUG
, "found headers\n");
420 ogg_gptopts (AVFormatContext
* s
, int i
, uint64_t gp
)
422 ogg_t
*ogg
= s
->priv_data
;
423 ogg_stream_t
*os
= ogg
->streams
+ i
;
424 uint64_t pts
= AV_NOPTS_VALUE
;
426 if(os
->codec
->gptopts
){
427 pts
= os
->codec
->gptopts(s
, i
, gp
);
437 ogg_get_length (AVFormatContext
* s
)
439 ogg_t
*ogg
= s
->priv_data
;
443 if(url_is_streamed(s
->pb
))
447 if (s
->duration
!= AV_NOPTS_VALUE
)
450 size
= url_fsize(s
->pb
);
453 end
= size
> MAX_PAGE_SIZE
? size
- MAX_PAGE_SIZE
: size
;
456 url_fseek (s
->pb
, end
, SEEK_SET
);
458 while (!ogg_read_page (s
, &i
)){
459 if (ogg
->streams
[i
].granule
!= -1 && ogg
->streams
[i
].granule
!= 0 &&
460 ogg
->streams
[i
].codec
)
465 s
->streams
[idx
]->duration
=
466 ogg_gptopts (s
, idx
, ogg
->streams
[idx
].granule
);
477 ogg_read_header (AVFormatContext
* s
, AVFormatParameters
* ap
)
479 ogg_t
*ogg
= s
->priv_data
;
481 //linear headers seek from start
482 if (ogg_get_headers (s
) < 0){
486 //linear granulepos seek from end
489 //fill the extradata in the per codec callbacks
495 ogg_read_packet (AVFormatContext
* s
, AVPacket
* pkt
)
504 if (ogg_packet (s
, &idx
, &pstart
, &psize
) < 0)
506 }while (idx
< 0 || !s
->streams
[idx
]);
509 os
= ogg
->streams
+ idx
;
512 if (av_new_packet (pkt
, psize
) < 0)
514 pkt
->stream_index
= idx
;
515 memcpy (pkt
->data
, os
->buf
+ pstart
, psize
);
516 if (os
->lastgp
!= -1LL){
517 pkt
->pts
= ogg_gptopts (s
, idx
, os
->lastgp
);
521 pkt
->flags
= os
->pflags
;
528 ogg_read_close (AVFormatContext
* s
)
530 ogg_t
*ogg
= s
->priv_data
;
533 for (i
= 0; i
< ogg
->nstreams
; i
++){
534 av_free (ogg
->streams
[i
].buf
);
535 av_free (ogg
->streams
[i
].private);
537 av_free (ogg
->streams
);
543 ogg_read_timestamp (AVFormatContext
* s
, int stream_index
, int64_t * pos_arg
,
546 ogg_t
*ogg
= s
->priv_data
;
547 ByteIOContext
*bc
= s
->pb
;
548 int64_t pts
= AV_NOPTS_VALUE
;
550 url_fseek(bc
, *pos_arg
, SEEK_SET
);
551 while (url_ftell(bc
) < pos_limit
&& !ogg_read_page (s
, &i
)) {
552 if (ogg
->streams
[i
].granule
!= -1 && ogg
->streams
[i
].granule
!= 0 &&
553 ogg
->streams
[i
].codec
&& i
== stream_index
) {
554 pts
= ogg_gptopts(s
, i
, ogg
->streams
[i
].granule
);
555 // FIXME: this is the position of the packet after the one with above
557 *pos_arg
= url_ftell(bc
);
565 static int ogg_probe(AVProbeData
*p
)
567 if (p
->buf
[0] == 'O' && p
->buf
[1] == 'g' &&
568 p
->buf
[2] == 'g' && p
->buf
[3] == 'S' &&
569 p
->buf
[4] == 0x0 && p
->buf
[5] <= 0x7 )
570 return AVPROBE_SCORE_MAX
;
575 AVInputFormat ogg_demuxer
= {
577 NULL_IF_CONFIG_SMALL("Ogg"),