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.
36 #include "vorbiscomment.h"
38 #define MAX_PAGE_SIZE 65307
39 #define DECODER_BUFFER_SIZE MAX_PAGE_SIZE
41 static const struct ogg_codec
* const ogg_codecs
[] = {
57 //FIXME We could avoid some structure duplication
59 ogg_save (AVFormatContext
* s
)
61 struct ogg
*ogg
= s
->priv_data
;
62 struct ogg_state
*ost
=
63 av_malloc(sizeof (*ost
) + (ogg
->nstreams
-1) * sizeof (*ogg
->streams
));
65 ost
->pos
= url_ftell (s
->pb
);
66 ost
->curidx
= ogg
->curidx
;
67 ost
->next
= ogg
->state
;
68 ost
->nstreams
= ogg
->nstreams
;
69 memcpy(ost
->streams
, ogg
->streams
, ogg
->nstreams
* sizeof(*ogg
->streams
));
71 for (i
= 0; i
< ogg
->nstreams
; i
++){
72 struct ogg_stream
*os
= ogg
->streams
+ i
;
73 os
->buf
= av_malloc (os
->bufsize
);
74 memset (os
->buf
, 0, os
->bufsize
);
75 memcpy (os
->buf
, ost
->streams
[i
].buf
, os
->bufpos
);
84 ogg_restore (AVFormatContext
* s
, int discard
)
86 struct ogg
*ogg
= s
->priv_data
;
87 ByteIOContext
*bc
= s
->pb
;
88 struct ogg_state
*ost
= ogg
->state
;
94 ogg
->state
= ost
->next
;
97 for (i
= 0; i
< ogg
->nstreams
; i
++)
98 av_free (ogg
->streams
[i
].buf
);
100 url_fseek (bc
, ost
->pos
, SEEK_SET
);
101 ogg
->curidx
= ost
->curidx
;
102 ogg
->nstreams
= ost
->nstreams
;
103 memcpy(ogg
->streams
, ost
->streams
,
104 ost
->nstreams
* sizeof(*ogg
->streams
));
113 ogg_reset (struct ogg
* ogg
)
117 for (i
= 0; i
< ogg
->nstreams
; i
++){
118 struct ogg_stream
*os
= ogg
->streams
+ i
;
123 os
->lastpts
= AV_NOPTS_VALUE
;
124 os
->lastdts
= AV_NOPTS_VALUE
;
137 static const struct ogg_codec
*
138 ogg_find_codec (uint8_t * buf
, int size
)
142 for (i
= 0; ogg_codecs
[i
]; i
++)
143 if (size
>= ogg_codecs
[i
]->magicsize
&&
144 !memcmp (buf
, ogg_codecs
[i
]->magic
, ogg_codecs
[i
]->magicsize
))
145 return ogg_codecs
[i
];
151 ogg_new_stream (AVFormatContext
* s
, uint32_t serial
)
154 struct ogg
*ogg
= s
->priv_data
;
155 int idx
= ogg
->nstreams
++;
157 struct ogg_stream
*os
;
159 ogg
->streams
= av_realloc (ogg
->streams
,
160 ogg
->nstreams
* sizeof (*ogg
->streams
));
161 memset (ogg
->streams
+ idx
, 0, sizeof (*ogg
->streams
));
162 os
= ogg
->streams
+ idx
;
164 os
->bufsize
= DECODER_BUFFER_SIZE
;
165 os
->buf
= av_malloc(os
->bufsize
);
168 st
= av_new_stream (s
, idx
);
170 return AVERROR(ENOMEM
);
172 av_set_pts_info(st
, 64, 1, 1000000);
178 ogg_new_buf(struct ogg
*ogg
, int idx
)
180 struct ogg_stream
*os
= ogg
->streams
+ idx
;
181 uint8_t *nb
= av_malloc(os
->bufsize
);
182 int size
= os
->bufpos
- os
->pstart
;
184 memcpy(nb
, os
->buf
+ os
->pstart
, size
);
195 ogg_read_page (AVFormatContext
* s
, int *str
)
197 ByteIOContext
*bc
= s
->pb
;
198 struct ogg
*ogg
= s
->priv_data
;
199 struct ogg_stream
*os
;
210 if (get_buffer (bc
, sync
, 4) < 4)
216 if (sync
[sp
& 3] == 'O' &&
217 sync
[(sp
+ 1) & 3] == 'g' &&
218 sync
[(sp
+ 2) & 3] == 'g' && sync
[(sp
+ 3) & 3] == 'S')
225 }while (i
++ < MAX_PAGE_SIZE
);
227 if (i
>= MAX_PAGE_SIZE
){
228 av_log (s
, AV_LOG_INFO
, "ogg, can't find sync word\n");
232 if (url_fgetc (bc
) != 0) /* version */
235 flags
= url_fgetc (bc
);
237 serial
= get_le32 (bc
);
240 nsegs
= url_fgetc (bc
);
242 idx
= ogg_find_stream (ogg
, serial
);
244 idx
= ogg_new_stream (s
, serial
);
249 os
= ogg
->streams
+ idx
;
250 os
->page_pos
= url_ftell(bc
) - 27;
253 ogg_new_buf(ogg
, idx
);
255 if (get_buffer (bc
, os
->segments
, nsegs
) < nsegs
)
262 for (i
= 0; i
< nsegs
; i
++)
263 size
+= os
->segments
[i
];
265 if (flags
& OGG_FLAG_CONT
|| os
->incomplete
){
267 while (os
->segp
< os
->nsegs
){
268 int seg
= os
->segments
[os
->segp
++];
273 os
->sync_pos
= os
->page_pos
;
277 os
->sync_pos
= os
->page_pos
;
280 if (os
->bufsize
- os
->bufpos
< size
){
281 uint8_t *nb
= av_malloc (os
->bufsize
*= 2);
282 memcpy (nb
, os
->buf
, os
->bufpos
);
287 if (get_buffer (bc
, os
->buf
+ os
->bufpos
, size
) < size
)
301 ogg_packet (AVFormatContext
* s
, int *str
, int *dstart
, int *dsize
, int64_t *fpos
)
303 struct ogg
*ogg
= s
->priv_data
;
305 struct ogg_stream
*os
;
307 int segp
= 0, psize
= 0;
310 av_log (s
, AV_LOG_DEBUG
, "ogg_packet: curidx=%i\n", ogg
->curidx
);
317 if (ogg_read_page (s
, &idx
) < 0)
321 os
= ogg
->streams
+ idx
;
324 av_log (s
, AV_LOG_DEBUG
,
325 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
326 idx
, os
->pstart
, os
->psize
, os
->segp
, os
->nsegs
);
331 os
->codec
= ogg_find_codec (os
->buf
, os
->bufpos
);
344 while (os
->segp
< os
->nsegs
){
345 int ss
= os
->segments
[os
->segp
++];
353 if (!complete
&& os
->segp
== os
->nsegs
){
360 av_log (s
, AV_LOG_DEBUG
,
361 "ogg_packet: idx %i, frame size %i, start %i\n",
362 idx
, os
->psize
, os
->pstart
);
369 os
->header
= os
->codec
->header (s
, idx
);
374 s
->data_offset
= os
->sync_pos
;
377 os
->pstart
+= os
->psize
;
383 if (os
->codec
&& os
->codec
->packet
)
384 os
->codec
->packet (s
, idx
);
388 *dstart
= os
->pstart
;
392 *fpos
= os
->sync_pos
;
393 os
->pstart
+= os
->psize
;
395 os
->sync_pos
= os
->page_pos
;
398 // determine whether there are more complete packets in this page
399 // if not, the page's granule will apply to this packet
401 for (i
= os
->segp
; i
< os
->nsegs
; i
++)
402 if (os
->segments
[i
] < 255) {
407 if (os
->segp
== os
->nsegs
)
414 ogg_get_headers (AVFormatContext
* s
)
416 struct ogg
*ogg
= s
->priv_data
;
419 if (ogg_packet (s
, NULL
, NULL
, NULL
, NULL
) < 0)
421 }while (!ogg
->headers
);
424 av_log (s
, AV_LOG_DEBUG
, "found headers\n");
431 ogg_get_length (AVFormatContext
* s
)
433 struct ogg
*ogg
= s
->priv_data
;
437 if(url_is_streamed(s
->pb
))
441 if (s
->duration
!= AV_NOPTS_VALUE
)
444 size
= url_fsize(s
->pb
);
447 end
= size
> MAX_PAGE_SIZE? size
- MAX_PAGE_SIZE
: 0;
450 url_fseek (s
->pb
, end
, SEEK_SET
);
452 while (!ogg_read_page (s
, &i
)){
453 if (ogg
->streams
[i
].granule
!= -1 && ogg
->streams
[i
].granule
!= 0 &&
454 ogg
->streams
[i
].codec
) {
455 s
->streams
[i
]->duration
=
456 ogg_gptopts (s
, i
, ogg
->streams
[i
].granule
, NULL
);
457 if (s
->streams
[i
]->start_time
!= AV_NOPTS_VALUE
)
458 s
->streams
[i
]->duration
-= s
->streams
[i
]->start_time
;
469 ogg_read_header (AVFormatContext
* s
, AVFormatParameters
* ap
)
471 struct ogg
*ogg
= s
->priv_data
;
474 //linear headers seek from start
475 if (ogg_get_headers (s
) < 0){
479 for (i
= 0; i
< ogg
->nstreams
; i
++)
480 if (ogg
->streams
[i
].header
< 0)
481 ogg
->streams
[i
].codec
= NULL
;
483 //linear granulepos seek from end
486 //fill the extradata in the per codec callbacks
490 static int64_t ogg_calc_pts(AVFormatContext
*s
, int idx
, int64_t *dts
)
492 struct ogg
*ogg
= s
->priv_data
;
493 struct ogg_stream
*os
= ogg
->streams
+ idx
;
494 int64_t pts
= AV_NOPTS_VALUE
;
497 *dts
= AV_NOPTS_VALUE
;
499 if (os
->lastpts
!= AV_NOPTS_VALUE
) {
501 os
->lastpts
= AV_NOPTS_VALUE
;
503 if (os
->lastdts
!= AV_NOPTS_VALUE
) {
506 os
->lastdts
= AV_NOPTS_VALUE
;
509 if (os
->granule
!= -1LL) {
510 if (os
->codec
&& os
->codec
->granule_is_start
)
511 pts
= ogg_gptopts(s
, idx
, os
->granule
, dts
);
513 os
->lastpts
= ogg_gptopts(s
, idx
, os
->granule
, &os
->lastdts
);
516 av_log(s
, AV_LOG_WARNING
, "Packet is missing granule\n");
522 ogg_read_packet (AVFormatContext
* s
, AVPacket
* pkt
)
525 struct ogg_stream
*os
;
528 int64_t fpos
, pts
, dts
;
533 if (ogg_packet (s
, &idx
, &pstart
, &psize
, &fpos
) < 0)
535 }while (idx
< 0 || !s
->streams
[idx
]);
538 os
= ogg
->streams
+ idx
;
540 // pflags might not be set until after this
541 pts
= ogg_calc_pts(s
, idx
, &dts
);
543 if (os
->keyframe_seek
&& !(os
->pflags
& AV_PKT_FLAG_KEY
))
545 os
->keyframe_seek
= 0;
548 if (av_new_packet (pkt
, psize
) < 0)
550 pkt
->stream_index
= idx
;
551 memcpy (pkt
->data
, os
->buf
+ pstart
, psize
);
555 pkt
->flags
= os
->pflags
;
556 pkt
->duration
= os
->pduration
;
564 ogg_read_close (AVFormatContext
* s
)
566 struct ogg
*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_timestamp (AVFormatContext
* s
, int stream_index
, int64_t * pos_arg
,
582 struct ogg
*ogg
= s
->priv_data
;
583 struct ogg_stream
*os
= ogg
->streams
+ stream_index
;
584 ByteIOContext
*bc
= s
->pb
;
585 int64_t pts
= AV_NOPTS_VALUE
;
587 url_fseek(bc
, *pos_arg
, SEEK_SET
);
590 while (url_ftell(bc
) < pos_limit
&& !ogg_packet(s
, &i
, NULL
, NULL
, pos_arg
)) {
591 if (i
== stream_index
) {
592 pts
= ogg_calc_pts(s
, i
, NULL
);
593 if (os
->keyframe_seek
&& !(os
->pflags
& AV_PKT_FLAG_KEY
))
594 pts
= AV_NOPTS_VALUE
;
596 if (pts
!= AV_NOPTS_VALUE
)
603 static int ogg_read_seek(AVFormatContext
*s
, int stream_index
, int64_t timestamp
, int flags
)
605 struct ogg
*ogg
= s
->priv_data
;
606 struct ogg_stream
*os
= ogg
->streams
+ stream_index
;
609 // Try seeking to a keyframe first. If this fails (very possible),
610 // av_seek_frame will fall back to ignoring keyframes
611 if (s
->streams
[stream_index
]->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
612 && !(flags
& AVSEEK_FLAG_ANY
))
613 os
->keyframe_seek
= 1;
615 ret
= av_seek_frame_binary(s
, stream_index
, timestamp
, flags
);
617 os
->keyframe_seek
= 0;
621 static int ogg_probe(AVProbeData
*p
)
623 if (p
->buf
[0] == 'O' && p
->buf
[1] == 'g' &&
624 p
->buf
[2] == 'g' && p
->buf
[3] == 'S' &&
625 p
->buf
[4] == 0x0 && p
->buf
[5] <= 0x7 )
626 return AVPROBE_SCORE_MAX
;
631 AVInputFormat ogg_demuxer
= {
633 NULL_IF_CONFIG_SMALL("Ogg"),
642 .metadata_conv
= ff_vorbiscomment_metadata_conv
,