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 ogg_codec_t
*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
;
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
);
472 while (!ogg_read_page (s
, &i
)) {
473 if (i
== idx
&& ogg
->streams
[i
].granule
!= -1 && ogg
->streams
[i
].granule
!= 0)
477 s
->streams
[idx
]->start_time
= ogg_gptopts (s
, idx
, ogg
->streams
[idx
].granule
);
478 s
->streams
[idx
]->duration
-= s
->streams
[idx
]->start_time
;
487 ogg_read_header (AVFormatContext
* s
, AVFormatParameters
* ap
)
489 ogg_t
*ogg
= s
->priv_data
;
491 //linear headers seek from start
492 if (ogg_get_headers (s
) < 0){
496 //linear granulepos seek from end
499 //fill the extradata in the per codec callbacks
505 ogg_read_packet (AVFormatContext
* s
, AVPacket
* pkt
)
514 if (ogg_packet (s
, &idx
, &pstart
, &psize
) < 0)
516 }while (idx
< 0 || !s
->streams
[idx
]);
519 os
= ogg
->streams
+ idx
;
522 if (av_new_packet (pkt
, psize
) < 0)
524 pkt
->stream_index
= idx
;
525 memcpy (pkt
->data
, os
->buf
+ pstart
, psize
);
526 if (os
->lastgp
!= -1LL){
527 pkt
->pts
= ogg_gptopts (s
, idx
, os
->lastgp
);
531 pkt
->flags
= os
->pflags
;
538 ogg_read_close (AVFormatContext
* s
)
540 ogg_t
*ogg
= s
->priv_data
;
543 for (i
= 0; i
< ogg
->nstreams
; i
++){
544 av_free (ogg
->streams
[i
].buf
);
545 av_free (ogg
->streams
[i
].private);
547 av_free (ogg
->streams
);
553 ogg_read_timestamp (AVFormatContext
* s
, int stream_index
, int64_t * pos_arg
,
556 ogg_t
*ogg
= s
->priv_data
;
557 ByteIOContext
*bc
= s
->pb
;
558 int64_t pts
= AV_NOPTS_VALUE
;
560 url_fseek(bc
, *pos_arg
, SEEK_SET
);
561 while (url_ftell(bc
) < pos_limit
&& !ogg_read_page (s
, &i
)) {
562 if (ogg
->streams
[i
].granule
!= -1 && ogg
->streams
[i
].granule
!= 0 &&
563 ogg
->streams
[i
].codec
&& i
== stream_index
) {
564 pts
= ogg_gptopts(s
, i
, ogg
->streams
[i
].granule
);
565 // FIXME: this is the position of the packet after the one with above
567 *pos_arg
= url_ftell(bc
);
575 static int ogg_probe(AVProbeData
*p
)
577 if (p
->buf
[0] == 'O' && p
->buf
[1] == 'g' &&
578 p
->buf
[2] == 'g' && p
->buf
[3] == 'S' &&
579 p
->buf
[4] == 0x0 && p
->buf
[5] <= 0x7 )
580 return AVPROBE_SCORE_MAX
;
585 AVInputFormat ogg_demuxer
= {
587 NULL_IF_CONFIG_SMALL("Ogg"),