2 * Ogg bitstream support
3 * Mark Hills <mark@pogo.org.uk>
5 * Uses libogg, but requires libvorbisenc to construct correct headers
6 * when containing Vorbis stream -- currently the only format supported
18 #define DECODER_BUFFER_SIZE 4096
21 typedef struct OggContext
{
33 static int ogg_write_header(AVFormatContext
*avfcontext
)
35 OggContext
*context
= avfcontext
->priv_data
;
36 ogg_packet
*op
= &context
->op
;
39 ogg_stream_init(&context
->os
, 31415);
41 for(n
= 0 ; n
< avfcontext
->nb_streams
; n
++) {
42 AVCodecContext
*codec
= avfcontext
->streams
[n
]->codec
;
43 uint8_t *headers
= codec
->extradata
;
44 int headers_len
= codec
->extradata_size
;
45 uint8_t *header_start
[3];
49 av_set_pts_info(avfcontext
->streams
[n
], 60, 1, AV_TIME_BASE
);
51 for(j
=1,i
=0;i
<2;++i
, ++j
) {
53 while(j
<headers_len
&& headers
[j
]==0xff) {
57 header_len
[i
]+=headers
[j
];
59 header_len
[2]=headers_len
-header_len
[0]-header_len
[1]-j
;
61 header_start
[0] = headers
;
62 header_start
[1] = header_start
[0] + header_len
[0];
63 header_start
[2] = header_start
[1] + header_len
[1];
66 op
->bytes
= header_len
[i
];
68 op
->packet
= header_start
[i
];
69 op
->b_o_s
= op
->packetno
==0;
71 ogg_stream_packetin(&context
->os
, op
);
73 op
->packetno
++; //FIXME multiple streams
76 context
->header_handled
= 0 ;
82 static int ogg_write_packet(AVFormatContext
*avfcontext
, AVPacket
*pkt
)
84 OggContext
*context
= avfcontext
->priv_data
;
85 AVCodecContext
*avctx
= avfcontext
->streams
[pkt
->stream_index
]->codec
;
86 ogg_packet
*op
= &context
->op
;
90 pts
= av_rescale(pkt
->pts
, avctx
->sample_rate
, AV_TIME_BASE
);
92 // av_log(avfcontext, AV_LOG_DEBUG, "M%d\n", size);
94 /* flush header packets so audio starts on a new page */
96 if(!context
->header_handled
) {
97 while(ogg_stream_flush(&context
->os
, &og
)) {
98 put_buffer(&avfcontext
->pb
, og
.header
, og
.header_len
) ;
99 put_buffer(&avfcontext
->pb
, og
.body
, og
.body_len
) ;
100 put_flush_packet(&avfcontext
->pb
);
102 context
->header_handled
= 1 ;
105 op
->packet
= (uint8_t*) pkt
->data
;
106 op
->bytes
= pkt
->size
;
107 op
->b_o_s
= op
->packetno
== 0;
110 /* correct the fields in the packet -- essential for streaming */
112 ogg_stream_packetin(&context
->os
, op
);
114 while(ogg_stream_pageout(&context
->os
, &og
)) {
115 put_buffer(&avfcontext
->pb
, og
.header
, og
.header_len
);
116 put_buffer(&avfcontext
->pb
, og
.body
, og
.body_len
);
117 put_flush_packet(&avfcontext
->pb
);
125 static int ogg_write_trailer(AVFormatContext
*avfcontext
) {
126 OggContext
*context
= avfcontext
->priv_data
;
129 while(ogg_stream_flush(&context
->os
, &og
)) {
130 put_buffer(&avfcontext
->pb
, og
.header
, og
.header_len
) ;
131 put_buffer(&avfcontext
->pb
, og
.body
, og
.body_len
) ;
132 put_flush_packet(&avfcontext
->pb
);
135 ogg_stream_clear(&context
->os
) ;
140 AVOutputFormat ogg_muxer
= {
152 #endif //CONFIG_MUXERS
155 static int next_packet(AVFormatContext
*avfcontext
, ogg_packet
*op
) {
156 OggContext
*context
= avfcontext
->priv_data
;
160 while(ogg_stream_packetout(&context
->os
, op
) != 1) {
162 /* while no pages are available, read in more data to the sync */
163 while(ogg_sync_pageout(&context
->oy
, &og
) != 1) {
164 buf
= ogg_sync_buffer(&context
->oy
, DECODER_BUFFER_SIZE
) ;
165 if(get_buffer(&avfcontext
->pb
, buf
, DECODER_BUFFER_SIZE
) <= 0)
167 ogg_sync_wrote(&context
->oy
, DECODER_BUFFER_SIZE
) ;
170 /* got a page. Feed it into the stream and get the packet */
171 if(ogg_stream_pagein(&context
->os
, &og
) != 0)
179 static int ogg_read_header(AVFormatContext
*avfcontext
, AVFormatParameters
*ap
)
181 OggContext
*context
= avfcontext
->priv_data
;
186 AVCodecContext
*codec
;
190 ogg_sync_init(&context
->oy
) ;
191 buf
= ogg_sync_buffer(&context
->oy
, DECODER_BUFFER_SIZE
) ;
193 if(get_buffer(&avfcontext
->pb
, buf
, DECODER_BUFFER_SIZE
) <= 0)
196 ogg_sync_wrote(&context
->oy
, DECODER_BUFFER_SIZE
) ;
197 ogg_sync_pageout(&context
->oy
, &og
) ;
198 ogg_stream_init(&context
->os
, ogg_page_serialno(&og
)) ;
199 ogg_stream_pagein(&context
->os
, &og
) ;
201 /* currently only one vorbis stream supported */
203 ast
= av_new_stream(avfcontext
, 0) ;
205 return AVERROR_NOMEM
;
206 av_set_pts_info(ast
, 60, 1, AV_TIME_BASE
);
209 codec
->codec_type
= CODEC_TYPE_AUDIO
;
210 codec
->codec_id
= CODEC_ID_VORBIS
;
212 if(next_packet(avfcontext
, &op
)){
215 if(op
.bytes
>= (1<<16) || op
.bytes
< 0)
217 codec
->extradata_size
+= 2 + op
.bytes
;
218 codec
->extradata
= av_realloc(codec
->extradata
, codec
->extradata_size
+ FF_INPUT_BUFFER_PADDING_SIZE
);
219 memset(codec
->extradata
+ codec
->extradata_size
, 0, FF_INPUT_BUFFER_PADDING_SIZE
);
220 p
= codec
->extradata
+ codec
->extradata_size
- 2 - op
.bytes
;
222 *(p
++)= op
.bytes
&0xFF;
223 memcpy(p
, op
.packet
, op
.bytes
);
230 static int ogg_read_packet(AVFormatContext
*avfcontext
, AVPacket
*pkt
) {
233 if(next_packet(avfcontext
, &op
))
235 if(av_new_packet(pkt
, op
.bytes
) < 0)
237 pkt
->stream_index
= 0 ;
238 memcpy(pkt
->data
, op
.packet
, op
.bytes
);
239 if(avfcontext
->streams
[0]->codec
.sample_rate
&& op
.granulepos
!=-1)
240 pkt
->pts
= av_rescale(op
.granulepos
, AV_TIME_BASE
, avfcontext
->streams
[0]->codec
.sample_rate
);
241 // printf("%lld %d %d\n", pkt->pts, (int)op.granulepos, avfcontext->streams[0]->codec.sample_rate);
247 static int ogg_read_close(AVFormatContext
*avfcontext
) {
248 OggContext
*context
= avfcontext
->priv_data
;
250 ogg_stream_clear(&context
->os
) ;
251 ogg_sync_clear(&context
->oy
) ;
257 static AVInputFormat ogg_iformat
= {