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 struct ogg_codec
* const ogg_codecs
[] = {
53 //FIXME We could avoid some structure duplication
55 ogg_save (AVFormatContext
* s
)
57 struct ogg
*ogg
= s
->priv_data
;
58 struct ogg_state
*ost
=
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 struct ogg_stream
*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 struct ogg
*ogg
= s
->priv_data
;
83 ByteIOContext
*bc
= s
->pb
;
84 struct ogg_state
*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 (struct ogg
* ogg
)
113 for (i
= 0; i
< ogg
->nstreams
; i
++){
114 struct ogg_stream
*os
= ogg
->streams
+ i
;
129 static const struct ogg_codec
*
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 (struct ogg
* 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 struct ogg
*ogg
= s
->priv_data
;
159 int idx
= ogg
->nstreams
++;
161 struct ogg_stream
*os
;
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(struct ogg
*ogg
, int idx
)
184 struct ogg_stream
*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 struct ogg
*ogg
= s
->priv_data
;
203 struct ogg_stream
*os
;
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 struct ogg
*ogg
= s
->priv_data
;
307 struct ogg_stream
*os
;
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
){
384 if (os
->codec
&& os
->codec
->packet
)
385 os
->codec
->packet (s
, idx
);
389 *dstart
= os
->pstart
;
392 os
->pstart
+= os
->psize
;
397 if (os
->segp
== os
->nsegs
)
404 ogg_get_headers (AVFormatContext
* s
)
406 struct ogg
*ogg
= s
->priv_data
;
409 if (ogg_packet (s
, NULL
, NULL
, NULL
) < 0)
411 }while (!ogg
->headers
);
414 av_log (s
, AV_LOG_DEBUG
, "found headers\n");
421 ogg_gptopts (AVFormatContext
* s
, int i
, uint64_t gp
)
423 struct ogg
*ogg
= s
->priv_data
;
424 struct ogg_stream
*os
= ogg
->streams
+ i
;
425 uint64_t pts
= AV_NOPTS_VALUE
;
427 if(os
->codec
->gptopts
){
428 pts
= os
->codec
->gptopts(s
, i
, gp
);
438 ogg_get_length (AVFormatContext
* s
)
440 struct ogg
*ogg
= s
->priv_data
;
444 if(url_is_streamed(s
->pb
))
448 if (s
->duration
!= AV_NOPTS_VALUE
)
451 size
= url_fsize(s
->pb
);
454 end
= size
> MAX_PAGE_SIZE
? size
- MAX_PAGE_SIZE
: 0;
457 url_fseek (s
->pb
, end
, SEEK_SET
);
459 while (!ogg_read_page (s
, &i
)){
460 if (ogg
->streams
[i
].granule
!= -1 && ogg
->streams
[i
].granule
!= 0 &&
461 ogg
->streams
[i
].codec
)
466 s
->streams
[idx
]->duration
=
467 ogg_gptopts (s
, idx
, ogg
->streams
[idx
].granule
);
478 ogg_read_header (AVFormatContext
* s
, AVFormatParameters
* ap
)
480 struct ogg
*ogg
= s
->priv_data
;
483 //linear headers seek from start
484 if (ogg_get_headers (s
) < 0){
488 for (i
= 0; i
< ogg
->nstreams
; i
++)
489 if (ogg
->streams
[i
].header
< 0)
490 ogg
->streams
[i
].codec
= NULL
;
492 //linear granulepos seek from end
495 //fill the extradata in the per codec callbacks
501 ogg_read_packet (AVFormatContext
* s
, AVPacket
* pkt
)
504 struct ogg_stream
*os
;
510 if (ogg_packet (s
, &idx
, &pstart
, &psize
) < 0)
512 }while (idx
< 0 || !s
->streams
[idx
]);
515 os
= ogg
->streams
+ idx
;
518 if (av_new_packet (pkt
, psize
) < 0)
520 pkt
->stream_index
= idx
;
521 memcpy (pkt
->data
, os
->buf
+ pstart
, psize
);
522 if (os
->lastgp
!= -1LL){
523 pkt
->pts
= ogg_gptopts (s
, idx
, os
->lastgp
);
527 pkt
->flags
= os
->pflags
;
528 pkt
->duration
= os
->pduration
;
535 ogg_read_close (AVFormatContext
* s
)
537 struct ogg
*ogg
= s
->priv_data
;
540 for (i
= 0; i
< ogg
->nstreams
; i
++){
541 av_free (ogg
->streams
[i
].buf
);
542 av_free (ogg
->streams
[i
].private);
544 av_free (ogg
->streams
);
550 ogg_read_timestamp (AVFormatContext
* s
, int stream_index
, int64_t * pos_arg
,
553 struct ogg
*ogg
= s
->priv_data
;
554 ByteIOContext
*bc
= s
->pb
;
555 int64_t pts
= AV_NOPTS_VALUE
;
557 url_fseek(bc
, *pos_arg
, SEEK_SET
);
558 while (url_ftell(bc
) < pos_limit
&& !ogg_read_page (s
, &i
)) {
559 if (ogg
->streams
[i
].granule
!= -1 && ogg
->streams
[i
].granule
!= 0 &&
560 ogg
->streams
[i
].codec
&& i
== stream_index
) {
561 pts
= ogg_gptopts(s
, i
, ogg
->streams
[i
].granule
);
562 // FIXME: this is the position of the packet after the one with above
564 *pos_arg
= url_ftell(bc
);
572 static int ogg_probe(AVProbeData
*p
)
574 if (p
->buf
[0] == 'O' && p
->buf
[1] == 'g' &&
575 p
->buf
[2] == 'g' && p
->buf
[3] == 'S' &&
576 p
->buf
[4] == 0x0 && p
->buf
[5] <= 0x7 )
577 return AVPROBE_SCORE_MAX
;
582 AVInputFormat ogg_demuxer
= {
584 NULL_IF_CONFIG_SMALL("Ogg"),
593 .metadata_conv
= ff_vorbiscomment_metadata_conv
,