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
[] = {
50 #if 0 // CONFIG_MUXERS
52 ogg_write_header (AVFormatContext
* avfcontext
)
57 ogg_write_packet (AVFormatContext
* avfcontext
, AVPacket
* pkt
)
63 ogg_write_trailer (AVFormatContext
* avfcontext
)
68 AVOutputFormat ogg_muxer
= {
80 #endif //CONFIG_MUXERS
82 //FIXME We could avoid some structure duplication
84 ogg_save (AVFormatContext
* s
)
86 ogg_t
*ogg
= s
->priv_data
;
88 av_malloc(sizeof (*ost
) + (ogg
->nstreams
-1) * sizeof (*ogg
->streams
));
90 ost
->pos
= url_ftell (&s
->pb
);;
91 ost
->curidx
= ogg
->curidx
;
92 ost
->next
= ogg
->state
;
93 ost
->nstreams
= ogg
->nstreams
;
94 memcpy(ost
->streams
, ogg
->streams
, ogg
->nstreams
* sizeof(*ogg
->streams
));
96 for (i
= 0; i
< ogg
->nstreams
; i
++){
97 ogg_stream_t
*os
= ogg
->streams
+ i
;
98 os
->buf
= av_malloc (os
->bufsize
);
99 memset (os
->buf
, 0, os
->bufsize
);
100 memcpy (os
->buf
, ost
->streams
[i
].buf
, os
->bufpos
);
109 ogg_restore (AVFormatContext
* s
, int discard
)
111 ogg_t
*ogg
= s
->priv_data
;
112 ByteIOContext
*bc
= &s
->pb
;
113 ogg_state_t
*ost
= ogg
->state
;
119 ogg
->state
= ost
->next
;
122 for (i
= 0; i
< ogg
->nstreams
; i
++)
123 av_free (ogg
->streams
[i
].buf
);
125 url_fseek (bc
, ost
->pos
, SEEK_SET
);
126 ogg
->curidx
= ost
->curidx
;
127 ogg
->nstreams
= ost
->nstreams
;
128 memcpy(ogg
->streams
, ost
->streams
,
129 ost
->nstreams
* sizeof(*ogg
->streams
));
138 ogg_reset (ogg_t
* ogg
)
142 for (i
= 0; i
< ogg
->nstreams
; i
++){
143 ogg_stream_t
*os
= ogg
->streams
+ i
;
159 ogg_find_codec (uint8_t * buf
, int size
)
163 for (i
= 0; ogg_codecs
[i
]; i
++)
164 if (size
>= ogg_codecs
[i
]->magicsize
&&
165 !memcmp (buf
, ogg_codecs
[i
]->magic
, ogg_codecs
[i
]->magicsize
))
166 return ogg_codecs
[i
];
172 ogg_find_stream (ogg_t
* ogg
, int serial
)
176 for (i
= 0; i
< ogg
->nstreams
; i
++)
177 if (ogg
->streams
[i
].serial
== serial
)
184 ogg_new_stream (AVFormatContext
* s
, uint32_t serial
)
187 ogg_t
*ogg
= s
->priv_data
;
188 int idx
= ogg
->nstreams
++;
192 ogg
->streams
= av_realloc (ogg
->streams
,
193 ogg
->nstreams
* sizeof (*ogg
->streams
));
194 memset (ogg
->streams
+ idx
, 0, sizeof (*ogg
->streams
));
195 os
= ogg
->streams
+ idx
;
197 os
->bufsize
= DECODER_BUFFER_SIZE
;
198 os
->buf
= av_malloc(os
->bufsize
);
201 st
= av_new_stream (s
, idx
);
203 return AVERROR_NOMEM
;
205 av_set_pts_info(st
, 64, 1, 1000000);
211 ogg_new_buf(ogg_t
*ogg
, int idx
)
213 ogg_stream_t
*os
= ogg
->streams
+ idx
;
214 uint8_t *nb
= av_malloc(os
->bufsize
);
215 int size
= os
->bufpos
- os
->pstart
;
217 memcpy(nb
, os
->buf
+ os
->pstart
, size
);
228 ogg_read_page (AVFormatContext
* s
, int *str
)
230 ByteIOContext
*bc
= &s
->pb
;
231 ogg_t
*ogg
= s
->priv_data
;
243 if (get_buffer (bc
, sync
, 4) < 4)
249 if (sync
[sp
& 3] == 'O' &&
250 sync
[(sp
+ 1) & 3] == 'g' &&
251 sync
[(sp
+ 2) & 3] == 'g' && sync
[(sp
+ 3) & 3] == 'S')
258 }while (i
++ < MAX_PAGE_SIZE
);
260 if (i
>= MAX_PAGE_SIZE
){
261 av_log (s
, AV_LOG_INFO
, "ogg, can't find sync word\n");
265 if (url_fgetc (bc
) != 0) /* version */
268 flags
= url_fgetc (bc
);
270 serial
= get_le32 (bc
);
273 nsegs
= url_fgetc (bc
);
275 idx
= ogg_find_stream (ogg
, serial
);
277 idx
= ogg_new_stream (s
, serial
);
282 os
= ogg
->streams
+ idx
;
285 ogg_new_buf(ogg
, idx
);
287 if (get_buffer (bc
, os
->segments
, nsegs
) < nsegs
)
294 for (i
= 0; i
< nsegs
; i
++)
295 size
+= os
->segments
[i
];
297 if (flags
& OGG_FLAG_CONT
){
299 while (os
->segp
< os
->nsegs
){
300 int seg
= os
->segments
[os
->segp
++];
310 if (os
->bufsize
- os
->bufpos
< size
){
311 uint8_t *nb
= av_malloc (os
->bufsize
*= 2);
312 memcpy (nb
, os
->buf
, os
->bufpos
);
317 if (get_buffer (bc
, os
->buf
+ os
->bufpos
, size
) < size
)
320 os
->lastgp
= os
->granule
;
332 ogg_packet (AVFormatContext
* s
, int *str
, int *dstart
, int *dsize
)
334 ogg_t
*ogg
= s
->priv_data
;
338 int segp
= 0, psize
= 0;
341 av_log (s
, AV_LOG_DEBUG
, "ogg_packet: curidx=%i\n", ogg
->curidx
);
348 if (ogg_read_page (s
, &idx
) < 0)
352 os
= ogg
->streams
+ idx
;
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
);
362 os
->codec
= ogg_find_codec (os
->buf
, os
->bufpos
);
375 while (os
->segp
< os
->nsegs
){
376 int ss
= os
->segments
[os
->segp
++];
384 if (!complete
&& os
->segp
== os
->nsegs
){
390 av_log (s
, AV_LOG_DEBUG
,
391 "ogg_packet: idx %i, frame size %i, start %i\n",
392 idx
, os
->psize
, os
->pstart
);
398 int hdr
= os
->codec
->header (s
, idx
);
400 os
->header
= os
->seq
;
405 os
->pstart
+= os
->psize
;
410 if (os
->header
> -1 && os
->seq
> os
->header
){
411 if (os
->codec
&& os
->codec
->packet
)
412 os
->codec
->packet (s
, idx
);
416 *dstart
= os
->pstart
;
419 os
->pstart
+= os
->psize
;
424 if (os
->segp
== os
->nsegs
)
431 ogg_get_headers (AVFormatContext
* s
)
433 ogg_t
*ogg
= s
->priv_data
;
436 if (ogg_packet (s
, NULL
, NULL
, NULL
) < 0)
438 }while (!ogg
->headers
);
441 av_log (s
, AV_LOG_DEBUG
, "found headers\n");
448 ogg_gptopts (AVFormatContext
* s
, int i
, uint64_t gp
)
450 ogg_t
*ogg
= s
->priv_data
;
451 ogg_stream_t
*os
= ogg
->streams
+ i
;
452 uint64_t pts
= AV_NOPTS_VALUE
;
454 if(os
->codec
->gptopts
){
455 pts
= os
->codec
->gptopts(s
, i
, gp
);
465 ogg_get_length (AVFormatContext
* s
)
467 ogg_t
*ogg
= s
->priv_data
;
471 if(s
->pb
.is_streamed
)
475 if (s
->duration
!= AV_NOPTS_VALUE
)
478 size
= url_fsize(&s
->pb
);
481 end
= size
> MAX_PAGE_SIZE
? size
- MAX_PAGE_SIZE
: size
;
484 url_fseek (&s
->pb
, end
, SEEK_SET
);
486 while (!ogg_read_page (s
, &i
)){
487 if (ogg
->streams
[i
].granule
!= -1 && ogg
->streams
[i
].granule
!= 0 &&
488 ogg
->streams
[i
].codec
)
493 s
->streams
[idx
]->duration
=
494 ogg_gptopts (s
, idx
, ogg
->streams
[idx
].granule
);
500 while (!ogg_read_page (s
, &i
)) {
501 if (i
== idx
&& ogg
->streams
[i
].granule
!= -1 && ogg
->streams
[i
].granule
!= 0)
505 s
->streams
[idx
]->start_time
= ogg_gptopts (s
, idx
, ogg
->streams
[idx
].granule
);
506 s
->streams
[idx
]->duration
-= s
->streams
[idx
]->start_time
;
515 ogg_read_header (AVFormatContext
* s
, AVFormatParameters
* ap
)
517 ogg_t
*ogg
= s
->priv_data
;
519 //linear headers seek from start
520 if (ogg_get_headers (s
) < 0){
524 //linear granulepos seek from end
527 //fill the extradata in the per codec callbacks
533 ogg_read_packet (AVFormatContext
* s
, AVPacket
* pkt
)
542 if (ogg_packet (s
, &idx
, &pstart
, &psize
) < 0)
544 }while (idx
< 0 || !s
->streams
[idx
]);
547 os
= ogg
->streams
+ idx
;
550 if (av_new_packet (pkt
, psize
) < 0)
552 pkt
->stream_index
= idx
;
553 memcpy (pkt
->data
, os
->buf
+ pstart
, psize
);
554 if (os
->lastgp
!= -1LL){
555 pkt
->pts
= ogg_gptopts (s
, idx
, os
->lastgp
);
564 ogg_read_close (AVFormatContext
* s
)
566 ogg_t
*ogg
= s
->priv_data
;
569 for (i
= 0; i
< ogg
->nstreams
; i
++){
570 av_free (ogg
->streams
[i
].buf
);
571 av_free (ogg
->streams
[i
].private);
573 av_free (ogg
->streams
);
579 ogg_read_seek (AVFormatContext
* s
, int stream_index
, int64_t target_ts
,
582 AVStream
*st
= s
->streams
[stream_index
];
583 ogg_t
*ogg
= s
->priv_data
;
584 ByteIOContext
*bc
= &s
->pb
;
585 uint64_t min
= 0, max
= ogg
->size
;
586 uint64_t tmin
= st
->start_time
, tmax
= st
->start_time
+ st
->duration
;
587 int64_t pts
= AV_NOPTS_VALUE
;
591 if ((uint64_t)target_ts
< tmin
|| target_ts
< 0)
593 while (min
<= max
&& tmin
< tmax
){
594 uint64_t p
= min
+ (max
- min
) * (target_ts
- tmin
) / (tmax
- tmin
);
597 url_fseek (bc
, p
, SEEK_SET
);
599 while (!ogg_read_page (s
, &i
)){
600 if (i
== stream_index
&& ogg
->streams
[i
].granule
!= 0 &&
601 ogg
->streams
[i
].granule
!= -1)
608 pts
= ogg_gptopts (s
, i
, ogg
->streams
[i
].granule
);
611 if (FFABS (pts
- target_ts
) * st
->time_base
.num
< st
->time_base
.den
)
614 if (pts
> target_ts
){
615 if (max
== p
&& tmax
== pts
) {
616 // probably our tmin is wrong, causing us to always end up too late in the file
617 tmin
= (target_ts
+ tmin
+ 1) / 2;
618 if (tmin
== target_ts
) {
619 url_fseek(bc
, min
, SEEK_SET
);
626 if (min
== p
&& tmin
== pts
) {
627 // probably our tmax is wrong, causing us to always end up too early in the file
628 tmax
= (target_ts
+ tmax
) / 2;
629 if (tmax
== target_ts
) {
630 url_fseek(bc
, max
, SEEK_SET
);
639 if (FFABS (pts
- target_ts
) * st
->time_base
.num
< st
->time_base
.den
){
644 pts
= AV_NOPTS_VALUE
;
647 av_update_cur_dts(s
, st
, pts
);
653 if (av_seek_frame_binary (s
, stream_index
, target_ts
, flags
) < 0)
655 pos
= url_ftell (&s
->pb
);
656 ogg_read_timestamp (s
, stream_index
, &pos
, pos
- 1);
663 ogg_read_timestamp (AVFormatContext
* s
, int stream_index
, int64_t * pos_arg
,
666 ogg_t
*ogg
= s
->priv_data
;
667 ByteIOContext
*bc
= &s
->pb
;
671 return AV_NOPTS_VALUE
;
677 static int ogg_probe(AVProbeData
*p
)
681 if (p
->buf
[0] == 'O' && p
->buf
[1] == 'g' &&
682 p
->buf
[2] == 'g' && p
->buf
[3] == 'S' &&
683 p
->buf
[4] == 0x0 && p
->buf
[5] <= 0x7 )
684 return AVPROBE_SCORE_MAX
;
689 AVInputFormat ogg_demuxer
= {
698 // ogg_read_timestamp,