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
[] = {
46 #if 0 // CONFIG_ENCODERS
48 ogg_write_header (AVFormatContext
* avfcontext
)
53 ogg_write_packet (AVFormatContext
* avfcontext
, AVPacket
* pkt
)
59 ogg_write_trailer (AVFormatContext
* avfcontext
)
64 static AVOutputFormat ogg_oformat
= {
76 #endif //CONFIG_ENCODERS
78 //FIXME We could avoid some structure duplication
80 ogg_save (AVFormatContext
* s
)
82 ogg_t
*ogg
= s
->priv_data
;
84 av_malloc(sizeof (*ost
) + (ogg
->nstreams
-1) * sizeof (*ogg
->streams
));
86 ost
->pos
= url_ftell (&s
->pb
);;
87 ost
->curidx
= ogg
->curidx
;
88 ost
->next
= ogg
->state
;
89 memcpy(ost
->streams
, ogg
->streams
, ogg
->nstreams
* sizeof(*ogg
->streams
));
91 for (i
= 0; i
< ogg
->nstreams
; i
++){
92 ogg_stream_t
*os
= ogg
->streams
+ i
;
93 os
->buf
= av_malloc (os
->bufsize
);
94 memset (os
->buf
, 0, os
->bufsize
);
95 memcpy (os
->buf
, ost
->streams
[i
].buf
, os
->bufpos
);
104 ogg_restore (AVFormatContext
* s
, int discard
)
106 ogg_t
*ogg
= s
->priv_data
;
107 ByteIOContext
*bc
= &s
->pb
;
108 ogg_state_t
*ost
= ogg
->state
;
114 ogg
->state
= ost
->next
;
117 for (i
= 0; i
< ogg
->nstreams
; i
++)
118 av_free (ogg
->streams
[i
].buf
);
120 url_fseek (bc
, ost
->pos
, SEEK_SET
);
121 ogg
->curidx
= ost
->curidx
;
122 memcpy (ogg
->streams
, ost
->streams
,
123 ogg
->nstreams
* sizeof (*ogg
->streams
));
132 ogg_reset (ogg_t
* ogg
)
136 for (i
= 0; i
< ogg
->nstreams
; i
++){
137 ogg_stream_t
*os
= ogg
->streams
+ i
;
153 ogg_find_codec (uint8_t * buf
, int size
)
157 for (i
= 0; ogg_codecs
[i
]; i
++)
158 if (size
>= ogg_codecs
[i
]->magicsize
&&
159 !memcmp (buf
, ogg_codecs
[i
]->magic
, ogg_codecs
[i
]->magicsize
))
160 return ogg_codecs
[i
];
166 ogg_find_stream (ogg_t
* ogg
, int serial
)
170 for (i
= 0; i
< ogg
->nstreams
; i
++)
171 if (ogg
->streams
[i
].serial
== serial
)
178 ogg_new_stream (AVFormatContext
* s
, uint32_t serial
)
181 ogg_t
*ogg
= s
->priv_data
;
182 int idx
= ogg
->nstreams
++;
186 ogg
->streams
= av_realloc (ogg
->streams
,
187 ogg
->nstreams
* sizeof (*ogg
->streams
));
188 memset (ogg
->streams
+ idx
, 0, sizeof (*ogg
->streams
));
189 os
= ogg
->streams
+ idx
;
191 os
->bufsize
= DECODER_BUFFER_SIZE
;
192 os
->buf
= av_malloc (os
->bufsize
);
193 memset (os
->buf
, 0, os
->bufsize
);
196 st
= av_new_stream (s
, idx
);
198 return AVERROR_NOMEM
;
200 av_set_pts_info(st
, 64, 1, 1000000);
207 ogg_read_page (AVFormatContext
* s
, int *str
)
209 ByteIOContext
*bc
= &s
->pb
;
210 ogg_t
*ogg
= s
->priv_data
;
222 if (get_buffer (bc
, sync
, 4) < 4)
228 if (sync
[sp
& 3] == 'O' &&
229 sync
[(sp
+ 1) & 3] == 'g' &&
230 sync
[(sp
+ 2) & 3] == 'g' && sync
[(sp
+ 3) & 3] == 'S')
237 }while (i
++ < MAX_PAGE_SIZE
);
239 if (i
>= MAX_PAGE_SIZE
){
240 av_log (s
, AV_LOG_INFO
, "ogg, can't find sync word\n");
244 if (url_fgetc (bc
) != 0) /* version */
247 flags
= url_fgetc (bc
);
249 serial
= get_le32 (bc
);
252 nsegs
= url_fgetc (bc
);
254 idx
= ogg_find_stream (ogg
, serial
);
256 idx
= ogg_new_stream (s
, serial
);
261 os
= ogg
->streams
+ idx
;
263 if (get_buffer (bc
, os
->segments
, nsegs
) < nsegs
)
270 for (i
= 0; i
< nsegs
; i
++)
271 size
+= os
->segments
[i
];
273 if (flags
& OGG_FLAG_CONT
){
275 while (os
->segp
< os
->nsegs
){
276 int seg
= os
->segments
[os
->segp
++];
286 if (os
->bufsize
- os
->bufpos
< size
){
287 uint8_t *nb
= av_malloc (os
->bufsize
*= 2);
288 memset (nb
, 0, os
->bufsize
);
289 memcpy (nb
, os
->buf
, os
->bufpos
);
294 if (get_buffer (bc
, os
->buf
+ os
->bufpos
, size
) < size
)
297 os
->lastgp
= os
->granule
;
309 ogg_packet (AVFormatContext
* s
, int *str
)
311 ogg_t
*ogg
= s
->priv_data
;
315 int segp
= 0, psize
= 0;
318 av_log (s
, AV_LOG_DEBUG
, "ogg_packet: curidx=%i\n", ogg
->curidx
);
325 if (ogg_read_page (s
, &idx
) < 0)
329 os
= ogg
->streams
+ idx
;
332 av_log (s
, AV_LOG_DEBUG
,
333 "ogg_packet: idx=%d pstart=%d psize=%d segp=%d nsegs=%d\n",
334 idx
, os
->pstart
, os
->psize
, os
->segp
, os
->nsegs
);
339 os
->codec
= ogg_find_codec (os
->buf
, os
->bufpos
);
352 while (os
->segp
< os
->nsegs
){
353 int ss
= os
->segments
[os
->segp
++];
361 if (!complete
&& os
->segp
== os
->nsegs
){
362 uint8_t *nb
= av_malloc (os
->bufsize
);
363 int size
= os
->bufpos
- os
->pstart
;
364 memset (nb
, 0, os
->bufsize
);
365 memcpy (nb
, os
->buf
+ os
->pstart
, size
);
375 av_log (s
, AV_LOG_DEBUG
,
376 "ogg_packet: idx %i, frame size %i, start %i\n",
377 idx
, os
->psize
, os
->pstart
);
383 int hdr
= os
->codec
->header (s
, idx
);
385 os
->header
= os
->seq
;
390 os
->pstart
+= os
->psize
;
395 if (os
->header
> -1 && os
->seq
> os
->header
){
396 if (os
->codec
&& os
->codec
->packet
)
397 os
->codec
->packet (s
, idx
);
403 if (os
->segp
== os
->nsegs
)
410 ogg_get_headers (AVFormatContext
* s
)
412 ogg_t
*ogg
= s
->priv_data
;
415 if (ogg_packet (s
, NULL
) < 0)
417 }while (!ogg
->headers
);
420 av_log (s
, AV_LOG_DEBUG
, "found headers\n");
427 ogg_gptopts (AVFormatContext
* s
, int i
, uint64_t gp
)
429 ogg_t
*ogg
= s
->priv_data
;
430 ogg_stream_t
*os
= ogg
->streams
+ i
;
431 AVStream
*st
= s
->streams
[i
];
432 AVCodecContext
*codec
= &st
->codec
;
433 uint64_t pts
= AV_NOPTS_VALUE
;
435 if(os
->codec
->gptopts
){
436 pts
= os
->codec
->gptopts(s
, i
, gp
);
437 } else if (codec
->codec_type
== CODEC_TYPE_AUDIO
){
438 pts
= gp
* 1000000LL / codec
->sample_rate
;
439 }else if (codec
->codec_type
== CODEC_TYPE_VIDEO
){
448 ogg_get_length (AVFormatContext
* s
)
450 ogg_t
*ogg
= s
->priv_data
;
451 URLContext
*h
= url_fileno (&s
->pb
);
453 //FIXME: get the right ctx flag to know if is seekable or not
454 // if(ogg->f->flags & URL_FLAG_STREAMED)
458 if (s
->duration
!= AV_NOPTS_VALUE
)
462 url_seek (h
, -MAX_PAGE_SIZE
, SEEK_END
);
464 while (!ogg_read_page (s
, &i
)){
465 if (ogg
->streams
[i
].granule
!= -1 && ogg
->streams
[i
].granule
!= 0)
470 s
->streams
[idx
]->duration
=
471 ogg_gptopts (s
, idx
, ogg
->streams
[idx
].granule
);
474 ogg
->size
= url_filesize(h
);
482 ogg_read_header (AVFormatContext
* s
, AVFormatParameters
* ap
)
484 ogg_t
*ogg
= s
->priv_data
;
486 //linear headers seek from start
487 if (ogg_get_headers (s
) < 0){
491 //linear granulepos seek from end
494 //fill the extradata in the per codec callbacks
500 ogg_read_packet (AVFormatContext
* s
, AVPacket
* pkt
)
508 if (ogg_packet (s
, &idx
) < 0)
510 }while (idx
< 0 || !s
->streams
[idx
]);
513 os
= ogg
->streams
+ idx
;
516 if (av_new_packet (pkt
, os
->psize
) < 0)
518 pkt
->stream_index
= idx
;
519 memcpy (pkt
->data
, os
->buf
+ os
->pstart
, os
->psize
);
520 if (os
->lastgp
!= -1LL){
521 pkt
->pts
= ogg_gptopts (s
, idx
, os
->lastgp
);
525 os
->pstart
+= os
->psize
;
532 ogg_read_close (AVFormatContext
* s
)
534 ogg_t
*ogg
= s
->priv_data
;
537 for (i
= 0; i
< ogg
->nstreams
; i
++){
538 av_free (ogg
->streams
[i
].buf
);
539 av_free (ogg
->streams
[i
].private);
540 av_freep (&s
->streams
[i
]->codec
.extradata
);
542 av_free (ogg
->streams
);
548 ogg_read_seek (AVFormatContext
* s
, int stream_index
, int64_t target_ts
,
551 ogg_t
*ogg
= s
->priv_data
;
552 ByteIOContext
*bc
= &s
->pb
;
553 uint64_t min
= 0, max
= ogg
->size
;
554 uint64_t tmin
= 0, tmax
= s
->duration
;
555 int64_t pts
= AV_NOPTS_VALUE
;
560 uint64_t p
= min
+ (max
- min
) * (target_ts
- tmin
) / (tmax
- tmin
);
563 url_fseek (bc
, p
, SEEK_SET
);
565 while (!ogg_read_page (s
, &i
)){
566 if (ogg
->streams
[i
].granule
!= 0 && ogg
->streams
[i
].granule
!= -1)
573 pts
= ogg_gptopts (s
, i
, ogg
->streams
[i
].granule
);
576 if (ABS (pts
- target_ts
) < 1000000LL)
579 if (pts
> target_ts
){
588 if (ABS (pts
- target_ts
) < 1000000LL){
593 pts
= AV_NOPTS_VALUE
;
601 if (av_seek_frame_binary (s
, stream_index
, target_ts
, flags
) < 0)
603 pos
= url_ftell (&s
->pb
);
604 ogg_read_timestamp (s
, stream_index
, &pos
, pos
- 1);
611 ogg_read_timestamp (AVFormatContext
* s
, int stream_index
, int64_t * pos_arg
,
614 ogg_t
*ogg
= s
->priv_data
;
615 ByteIOContext
*bc
= &s
->pb
;
619 return AV_NOPTS_VALUE
;
625 static AVInputFormat ogg_iformat
= {
634 // ogg_read_timestamp,
641 #if 0 // CONFIG_ENCODERS
642 av_register_output_format (&ogg_oformat
);
644 av_register_input_format (&ogg_iformat
);