Mercurial > libavformat.hg
annotate ogg.c @ 358:d18a2b1fc182 libavformat
initial commit for Quicktime Animation (RLE) video decoder; bit depths
32, 24, and 16 are working; 8bpp is partially working; 4, 2, and 1 bpp
are not supported yet
author | melanson |
---|---|
date | Thu, 05 Feb 2004 05:22:44 +0000 |
parents | 741c56c608bb |
children | 6579fe3ade40 |
rev | line source |
---|---|
0 | 1 /* |
2 * Ogg bitstream support | |
3 * Mark Hills <mark@pogo.org.uk> | |
4 * | |
5 * Uses libogg, but requires libvorbisenc to construct correct headers | |
6 * when containing Vorbis stream -- currently the only format supported | |
7 */ | |
8 | |
9 #include <stdio.h> | |
10 #include <time.h> | |
11 | |
12 #include <ogg/ogg.h> | |
13 #include <vorbis/vorbisenc.h> | |
14 | |
15 #include "avformat.h" | |
16 #include "oggvorbis.h" | |
17 | |
18 #define DECODER_BUFFER_SIZE 4096 | |
19 | |
20 | |
21 typedef struct OggContext { | |
22 /* output */ | |
23 ogg_stream_state os ; | |
24 int header_handled ; | |
25 ogg_int64_t base_packet_no ; | |
26 ogg_int64_t base_granule_pos ; | |
27 | |
28 /* input */ | |
29 ogg_sync_state oy ; | |
30 } OggContext ; | |
31 | |
32 | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
68
diff
changeset
|
33 #ifdef CONFIG_ENCODERS |
35 | 34 static int ogg_write_header(AVFormatContext *avfcontext) |
35 { | |
36 OggContext *context = avfcontext->priv_data; | |
0 | 37 AVCodecContext *avccontext ; |
38 vorbis_info vi ; | |
39 vorbis_dsp_state vd ; | |
40 vorbis_comment vc ; | |
41 vorbis_block vb ; | |
42 ogg_packet header, header_comm, header_code ; | |
43 int n ; | |
44 | |
45 srand(time(NULL)); | |
46 ogg_stream_init(&context->os, rand()); | |
47 | |
48 for(n = 0 ; n < avfcontext->nb_streams ; n++) { | |
49 avccontext = &avfcontext->streams[n]->codec ; | |
50 | |
51 /* begin vorbis specific code */ | |
52 | |
53 vorbis_info_init(&vi) ; | |
54 | |
55 /* code copied from libavcodec/oggvorbis.c */ | |
56 | |
57 if(oggvorbis_init_encoder(&vi, avccontext) < 0) { | |
58 fprintf(stderr, "ogg_write_header: init_encoder failed") ; | |
59 return -1 ; | |
60 } | |
61 | |
62 vorbis_analysis_init(&vd, &vi) ; | |
63 vorbis_block_init(&vd, &vb) ; | |
64 | |
65 vorbis_comment_init(&vc) ; | |
327 | 66 vorbis_comment_add_tag(&vc, "encoder", LIBAVFORMAT_IDENT) ; |
0 | 67 if(*avfcontext->title) |
68 vorbis_comment_add_tag(&vc, "title", avfcontext->title) ; | |
69 | |
70 vorbis_analysis_headerout(&vd, &vc, &header, | |
71 &header_comm, &header_code) ; | |
72 ogg_stream_packetin(&context->os, &header) ; | |
73 ogg_stream_packetin(&context->os, &header_comm) ; | |
74 ogg_stream_packetin(&context->os, &header_code) ; | |
75 | |
68
1e2f55eced38
ogg deallocate patch by (Mark Hills <mark at pogo dot org dot uk>)
michaelni
parents:
35
diff
changeset
|
76 vorbis_block_clear(&vb) ; |
1e2f55eced38
ogg deallocate patch by (Mark Hills <mark at pogo dot org dot uk>)
michaelni
parents:
35
diff
changeset
|
77 vorbis_dsp_clear(&vd) ; |
1e2f55eced38
ogg deallocate patch by (Mark Hills <mark at pogo dot org dot uk>)
michaelni
parents:
35
diff
changeset
|
78 vorbis_info_clear(&vi) ; |
0 | 79 vorbis_comment_clear(&vc) ; |
68
1e2f55eced38
ogg deallocate patch by (Mark Hills <mark at pogo dot org dot uk>)
michaelni
parents:
35
diff
changeset
|
80 |
0 | 81 /* end of vorbis specific code */ |
82 | |
83 context->header_handled = 0 ; | |
84 context->base_packet_no = 0 ; | |
85 } | |
86 | |
87 return 0 ; | |
88 } | |
89 | |
90 | |
91 static int ogg_write_packet(AVFormatContext *avfcontext, | |
92 int stream_index, | |
290
7a3ed84008ec
GCC 3.3.2 warnings patch by (Panagiotis Issaris <takis at lumumba dot luc dot ac dot be>)
michael
parents:
277
diff
changeset
|
93 const uint8_t *buf, int size, int64_t force_pts) |
0 | 94 { |
95 OggContext *context = avfcontext->priv_data ; | |
96 ogg_packet *op ; | |
97 ogg_page og ; | |
98 int l = 0 ; | |
99 | |
100 /* flush header packets so audio starts on a new page */ | |
101 | |
102 if(!context->header_handled) { | |
103 while(ogg_stream_flush(&context->os, &og)) { | |
104 put_buffer(&avfcontext->pb, og.header, og.header_len) ; | |
105 put_buffer(&avfcontext->pb, og.body, og.body_len) ; | |
106 put_flush_packet(&avfcontext->pb); | |
107 } | |
108 context->header_handled = 1 ; | |
109 } | |
110 | |
111 while(l < size) { | |
112 op = (ogg_packet*)(buf + l) ; | |
290
7a3ed84008ec
GCC 3.3.2 warnings patch by (Panagiotis Issaris <takis at lumumba dot luc dot ac dot be>)
michael
parents:
277
diff
changeset
|
113 op->packet = (uint8_t*) buf + l + sizeof( ogg_packet) ; /* fix data pointer */ |
0 | 114 |
115 if(!context->base_packet_no) { /* this is the first packet */ | |
116 context->base_packet_no = op->packetno ; | |
117 context->base_granule_pos = op->granulepos ; | |
118 } | |
119 | |
120 /* correct the fields in the packet -- essential for streaming */ | |
121 | |
122 op->packetno -= context->base_packet_no ; | |
123 op->granulepos -= context->base_granule_pos ; | |
124 | |
125 ogg_stream_packetin(&context->os, op) ; | |
126 l += sizeof(ogg_packet) + op->bytes ; | |
127 | |
128 while(ogg_stream_pageout(&context->os, &og)) { | |
129 put_buffer(&avfcontext->pb, og.header, og.header_len) ; | |
130 put_buffer(&avfcontext->pb, og.body, og.body_len) ; | |
131 put_flush_packet(&avfcontext->pb); | |
132 } | |
133 } | |
134 | |
135 return 0; | |
136 } | |
137 | |
138 | |
139 static int ogg_write_trailer(AVFormatContext *avfcontext) { | |
140 OggContext *context = avfcontext->priv_data ; | |
141 ogg_page og ; | |
142 | |
143 while(ogg_stream_flush(&context->os, &og)) { | |
144 put_buffer(&avfcontext->pb, og.header, og.header_len) ; | |
145 put_buffer(&avfcontext->pb, og.body, og.body_len) ; | |
146 put_flush_packet(&avfcontext->pb); | |
147 } | |
148 | |
149 ogg_stream_clear(&context->os) ; | |
150 return 0 ; | |
151 } | |
152 | |
153 | |
154 static AVOutputFormat ogg_oformat = { | |
155 "ogg", | |
156 "Ogg Vorbis", | |
157 "audio/x-vorbis", | |
158 "ogg", | |
159 sizeof(OggContext), | |
160 CODEC_ID_VORBIS, | |
161 0, | |
162 ogg_write_header, | |
163 ogg_write_packet, | |
164 ogg_write_trailer, | |
165 } ; | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
68
diff
changeset
|
166 #endif //CONFIG_ENCODERS |
0 | 167 |
168 | |
169 static int next_packet(AVFormatContext *avfcontext, ogg_packet *op) { | |
170 OggContext *context = avfcontext->priv_data ; | |
171 ogg_page og ; | |
172 char *buf ; | |
173 | |
174 while(ogg_stream_packetout(&context->os, op) != 1) { | |
175 | |
176 /* while no pages are available, read in more data to the sync */ | |
177 while(ogg_sync_pageout(&context->oy, &og) != 1) { | |
178 buf = ogg_sync_buffer(&context->oy, DECODER_BUFFER_SIZE) ; | |
179 if(get_buffer(&avfcontext->pb, buf, DECODER_BUFFER_SIZE) <= 0) | |
180 return 1 ; | |
181 ogg_sync_wrote(&context->oy, DECODER_BUFFER_SIZE) ; | |
182 } | |
183 | |
184 /* got a page. Feed it into the stream and get the packet */ | |
185 if(ogg_stream_pagein(&context->os, &og) != 0) | |
186 return 1 ; | |
187 } | |
188 | |
189 return 0 ; | |
190 } | |
191 | |
192 | |
193 static int ogg_read_header(AVFormatContext *avfcontext, AVFormatParameters *ap) | |
194 { | |
35 | 195 OggContext *context = avfcontext->priv_data; |
0 | 196 char *buf ; |
197 ogg_page og ; | |
198 AVStream *ast ; | |
199 | |
200 ogg_sync_init(&context->oy) ; | |
201 buf = ogg_sync_buffer(&context->oy, DECODER_BUFFER_SIZE) ; | |
202 | |
203 if(get_buffer(&avfcontext->pb, buf, DECODER_BUFFER_SIZE) <= 0) | |
204 return -EIO ; | |
205 | |
206 ogg_sync_wrote(&context->oy, DECODER_BUFFER_SIZE) ; | |
207 ogg_sync_pageout(&context->oy, &og) ; | |
208 ogg_stream_init(&context->os, ogg_page_serialno(&og)) ; | |
209 ogg_stream_pagein(&context->os, &og) ; | |
210 | |
211 /* currently only one vorbis stream supported */ | |
212 | |
213 ast = av_new_stream(avfcontext, 0) ; | |
214 if(!ast) | |
215 return AVERROR_NOMEM ; | |
216 | |
217 ast->codec.codec_type = CODEC_TYPE_AUDIO ; | |
218 ast->codec.codec_id = CODEC_ID_VORBIS ; | |
219 | |
220 return 0 ; | |
221 } | |
222 | |
223 | |
224 static int ogg_read_packet(AVFormatContext *avfcontext, AVPacket *pkt) { | |
225 ogg_packet op ; | |
226 | |
227 if(next_packet(avfcontext, &op)) | |
228 return -EIO ; | |
229 if(av_new_packet(pkt, sizeof(ogg_packet) + op.bytes) < 0) | |
230 return -EIO ; | |
231 pkt->stream_index = 0 ; | |
232 memcpy(pkt->data, &op, sizeof(ogg_packet)) ; | |
233 memcpy(pkt->data + sizeof(ogg_packet), op.packet, op.bytes) ; | |
234 | |
235 return sizeof(ogg_packet) + op.bytes ; | |
236 } | |
237 | |
238 | |
239 static int ogg_read_close(AVFormatContext *avfcontext) { | |
240 OggContext *context = avfcontext->priv_data ; | |
241 | |
242 ogg_stream_clear(&context->os) ; | |
243 ogg_sync_clear(&context->oy) ; | |
244 | |
245 return 0 ; | |
246 } | |
247 | |
248 | |
249 static AVInputFormat ogg_iformat = { | |
250 "ogg", | |
251 "Ogg Vorbis", | |
252 sizeof(OggContext), | |
253 NULL, | |
254 ogg_read_header, | |
255 ogg_read_packet, | |
256 ogg_read_close, | |
257 .extensions = "ogg", | |
258 } ; | |
259 | |
260 | |
261 int ogg_init(void) { | |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
68
diff
changeset
|
262 #ifdef CONFIG_ENCODERS |
0 | 263 av_register_output_format(&ogg_oformat) ; |
277
a313e1080322
disable encoders where appropriate (patch courtesy of BERO
melanson
parents:
68
diff
changeset
|
264 #endif |
0 | 265 av_register_input_format(&ogg_iformat); |
266 return 0 ; | |
267 } |