Mercurial > mplayer.hg
annotate tremor/framing.c @ 21888:b36abbbca01e
DO NOT recommend or even suggest installing codecs.conf.
author | diego |
---|---|
date | Sat, 13 Jan 2007 11:57:40 +0000 |
parents | 052b4ad84883 |
children | e83eef58b30a |
rev | line source |
---|---|
14280 | 1 /******************************************************************** |
2 * * | |
15250 | 3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * |
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |
14280 | 7 * * |
15250 | 8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * |
9 * by the Xiph.Org Foundation http://www.xiph.org/ * | |
14280 | 10 * * |
11 ******************************************************************** | |
12 | |
13 function: code raw [Vorbis] packets into framed OggSquish stream and | |
14 decode Ogg streams back into raw packets | |
15250 | 15 last mod: $Id$ |
14280 | 16 |
17 note: The CRC code is directly derived from public domain code by | |
18 Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html | |
19 for details. | |
20 | |
21 ********************************************************************/ | |
22 | |
23 #include <stdlib.h> | |
24 #include <string.h> | |
25 #include "ogg.h" | |
26 | |
27 /* A complete description of Ogg framing exists in docs/framing.html */ | |
28 | |
29 int ogg_page_version(ogg_page *og){ | |
30 return((int)(og->header[4])); | |
31 } | |
32 | |
33 int ogg_page_continued(ogg_page *og){ | |
34 return((int)(og->header[5]&0x01)); | |
35 } | |
36 | |
37 int ogg_page_bos(ogg_page *og){ | |
38 return((int)(og->header[5]&0x02)); | |
39 } | |
40 | |
41 int ogg_page_eos(ogg_page *og){ | |
42 return((int)(og->header[5]&0x04)); | |
43 } | |
44 | |
45 ogg_int64_t ogg_page_granulepos(ogg_page *og){ | |
46 unsigned char *page=og->header; | |
47 ogg_int64_t granulepos=page[13]&(0xff); | |
48 granulepos= (granulepos<<8)|(page[12]&0xff); | |
49 granulepos= (granulepos<<8)|(page[11]&0xff); | |
50 granulepos= (granulepos<<8)|(page[10]&0xff); | |
51 granulepos= (granulepos<<8)|(page[9]&0xff); | |
52 granulepos= (granulepos<<8)|(page[8]&0xff); | |
53 granulepos= (granulepos<<8)|(page[7]&0xff); | |
54 granulepos= (granulepos<<8)|(page[6]&0xff); | |
55 return(granulepos); | |
56 } | |
57 | |
58 int ogg_page_serialno(ogg_page *og){ | |
59 return(og->header[14] | | |
60 (og->header[15]<<8) | | |
61 (og->header[16]<<16) | | |
62 (og->header[17]<<24)); | |
63 } | |
64 | |
65 long ogg_page_pageno(ogg_page *og){ | |
66 return(og->header[18] | | |
67 (og->header[19]<<8) | | |
68 (og->header[20]<<16) | | |
69 (og->header[21]<<24)); | |
70 } | |
71 | |
72 | |
73 | |
74 /* returns the number of packets that are completed on this page (if | |
75 the leading packet is begun on a previous page, but ends on this | |
76 page, it's counted */ | |
77 | |
78 /* NOTE: | |
79 If a page consists of a packet begun on a previous page, and a new | |
80 packet begun (but not completed) on this page, the return will be: | |
81 ogg_page_packets(page) ==1, | |
82 ogg_page_continued(page) !=0 | |
83 | |
84 If a page happens to be a single packet that was begun on a | |
85 previous page, and spans to the next page (in the case of a three or | |
86 more page packet), the return will be: | |
87 ogg_page_packets(page) ==0, | |
88 ogg_page_continued(page) !=0 | |
89 */ | |
90 | |
91 int ogg_page_packets(ogg_page *og){ | |
92 int i,n=og->header[26],count=0; | |
93 for(i=0;i<n;i++) | |
94 if(og->header[27+i]<255)count++; | |
95 return(count); | |
96 } | |
97 | |
15250 | 98 |
99 #if 0 | |
100 /* helper to initialize lookup for direct-table CRC (illustrative; we | |
101 use the static init below) */ | |
102 | |
103 static ogg_uint32_t _ogg_crc_entry(unsigned long index){ | |
104 int i; | |
105 unsigned long r; | |
106 | |
107 r = index << 24; | |
108 for (i=0; i<8; i++) | |
109 if (r & 0x80000000UL) | |
110 r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator | |
111 polynomial, although we use an | |
112 unreflected alg and an init/final | |
113 of 0, not 0xffffffff */ | |
114 else | |
115 r<<=1; | |
116 return (r & 0xffffffffUL); | |
117 } | |
118 #endif | |
119 | |
120 static const ogg_uint32_t crc_lookup[256]={ | |
14280 | 121 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9, |
122 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, | |
123 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61, | |
124 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, | |
125 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9, | |
126 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, | |
127 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011, | |
128 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, | |
129 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039, | |
130 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, | |
131 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81, | |
132 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, | |
133 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49, | |
134 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, | |
135 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1, | |
136 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, | |
137 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae, | |
138 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, | |
139 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16, | |
140 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, | |
141 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde, | |
142 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, | |
143 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066, | |
144 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, | |
145 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e, | |
146 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, | |
147 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6, | |
148 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, | |
149 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e, | |
150 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, | |
151 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686, | |
152 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, | |
153 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637, | |
154 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, | |
155 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f, | |
156 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, | |
157 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47, | |
158 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, | |
159 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff, | |
160 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, | |
161 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7, | |
162 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, | |
163 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f, | |
164 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, | |
165 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7, | |
166 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, | |
167 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f, | |
168 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, | |
169 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640, | |
170 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, | |
171 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8, | |
172 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, | |
173 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30, | |
174 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, | |
175 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088, | |
176 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, | |
177 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0, | |
178 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, | |
179 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18, | |
180 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, | |
181 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0, | |
182 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, | |
183 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668, | |
184 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4}; | |
185 | |
186 /* init the encode/decode logical stream state */ | |
187 | |
188 int ogg_stream_init(ogg_stream_state *os,int serialno){ | |
189 if(os){ | |
190 memset(os,0,sizeof(*os)); | |
191 os->body_storage=16*1024; | |
15250 | 192 os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data)); |
14280 | 193 |
194 os->lacing_storage=1024; | |
15250 | 195 os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals)); |
196 os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals)); | |
14280 | 197 |
198 os->serialno=serialno; | |
199 | |
200 return(0); | |
201 } | |
202 return(-1); | |
203 } | |
204 | |
205 /* _clear does not free os, only the non-flat storage within */ | |
206 int ogg_stream_clear(ogg_stream_state *os){ | |
207 if(os){ | |
208 if(os->body_data)_ogg_free(os->body_data); | |
209 if(os->lacing_vals)_ogg_free(os->lacing_vals); | |
210 if(os->granule_vals)_ogg_free(os->granule_vals); | |
211 | |
212 memset(os,0,sizeof(*os)); | |
213 } | |
214 return(0); | |
215 } | |
216 | |
217 int ogg_stream_destroy(ogg_stream_state *os){ | |
218 if(os){ | |
219 ogg_stream_clear(os); | |
220 _ogg_free(os); | |
221 } | |
222 return(0); | |
223 } | |
224 | |
225 /* Helpers for ogg_stream_encode; this keeps the structure and | |
226 what's happening fairly clear */ | |
227 | |
228 static void _os_body_expand(ogg_stream_state *os,int needed){ | |
229 if(os->body_storage<=os->body_fill+needed){ | |
230 os->body_storage+=(needed+1024); | |
15250 | 231 os->body_data=_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data)); |
14280 | 232 } |
233 } | |
234 | |
235 static void _os_lacing_expand(ogg_stream_state *os,int needed){ | |
236 if(os->lacing_storage<=os->lacing_fill+needed){ | |
237 os->lacing_storage+=(needed+32); | |
15250 | 238 os->lacing_vals=_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals)); |
239 os->granule_vals=_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals)); | |
14280 | 240 } |
241 } | |
242 | |
243 /* checksum the page */ | |
244 /* Direct table CRC; note that this will be faster in the future if we | |
245 perform the checksum silmultaneously with other copies */ | |
246 | |
247 void ogg_page_checksum_set(ogg_page *og){ | |
248 if(og){ | |
249 ogg_uint32_t crc_reg=0; | |
250 int i; | |
251 | |
252 /* safety; needed for API behavior, but not framing code */ | |
253 og->header[22]=0; | |
254 og->header[23]=0; | |
255 og->header[24]=0; | |
256 og->header[25]=0; | |
257 | |
258 for(i=0;i<og->header_len;i++) | |
259 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]]; | |
260 for(i=0;i<og->body_len;i++) | |
261 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]]; | |
262 | |
15250 | 263 og->header[22]=(unsigned char)(crc_reg&0xff); |
264 og->header[23]=(unsigned char)((crc_reg>>8)&0xff); | |
265 og->header[24]=(unsigned char)((crc_reg>>16)&0xff); | |
266 og->header[25]=(unsigned char)((crc_reg>>24)&0xff); | |
267 } | |
268 } | |
269 | |
270 /* submit data to the internal buffer of the framing engine */ | |
271 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ | |
272 int lacing_vals=op->bytes/255+1,i; | |
273 | |
274 if(os->body_returned){ | |
275 /* advance packet data according to the body_returned pointer. We | |
276 had to keep it around to return a pointer into the buffer last | |
277 call */ | |
278 | |
279 os->body_fill-=os->body_returned; | |
280 if(os->body_fill) | |
281 memmove(os->body_data,os->body_data+os->body_returned, | |
282 os->body_fill); | |
283 os->body_returned=0; | |
284 } | |
285 | |
286 /* make sure we have the buffer storage */ | |
287 _os_body_expand(os,op->bytes); | |
288 _os_lacing_expand(os,lacing_vals); | |
289 | |
290 /* Copy in the submitted packet. Yes, the copy is a waste; this is | |
291 the liability of overly clean abstraction for the time being. It | |
292 will actually be fairly easy to eliminate the extra copy in the | |
293 future */ | |
294 | |
295 memcpy(os->body_data+os->body_fill,op->packet,op->bytes); | |
296 os->body_fill+=op->bytes; | |
297 | |
298 /* Store lacing vals for this packet */ | |
299 for(i=0;i<lacing_vals-1;i++){ | |
300 os->lacing_vals[os->lacing_fill+i]=255; | |
301 os->granule_vals[os->lacing_fill+i]=os->granulepos; | |
302 } | |
303 os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255; | |
304 os->granulepos=os->granule_vals[os->lacing_fill+i]=op->granulepos; | |
305 | |
306 /* flag the first segment as the beginning of the packet */ | |
307 os->lacing_vals[os->lacing_fill]|= 0x100; | |
308 | |
309 os->lacing_fill+=lacing_vals; | |
310 | |
311 /* for the sake of completeness */ | |
312 os->packetno++; | |
313 | |
314 if(op->e_o_s)os->e_o_s=1; | |
315 | |
316 return(0); | |
317 } | |
318 | |
319 /* This will flush remaining packets into a page (returning nonzero), | |
320 even if there is not enough data to trigger a flush normally | |
321 (undersized page). If there are no packets or partial packets to | |
322 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will | |
323 try to flush a normal sized page like ogg_stream_pageout; a call to | |
324 ogg_stream_flush does not guarantee that all packets have flushed. | |
325 Only a return value of 0 from ogg_stream_flush indicates all packet | |
326 data is flushed into pages. | |
327 | |
328 since ogg_stream_flush will flush the last page in a stream even if | |
329 it's undersized, you almost certainly want to use ogg_stream_pageout | |
330 (and *not* ogg_stream_flush) unless you specifically need to flush | |
331 an page regardless of size in the middle of a stream. */ | |
332 | |
333 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ | |
334 int i; | |
335 int vals=0; | |
336 int maxvals=(os->lacing_fill>255?255:os->lacing_fill); | |
337 int bytes=0; | |
338 long acc=0; | |
339 ogg_int64_t granule_pos=os->granule_vals[0]; | |
340 | |
341 if(maxvals==0)return(0); | |
342 | |
343 /* construct a page */ | |
344 /* decide how many segments to include */ | |
345 | |
346 /* If this is the initial header case, the first page must only include | |
347 the initial header packet */ | |
348 if(os->b_o_s==0){ /* 'initial header page' case */ | |
349 granule_pos=0; | |
350 for(vals=0;vals<maxvals;vals++){ | |
351 if((os->lacing_vals[vals]&0x0ff)<255){ | |
352 vals++; | |
353 break; | |
354 } | |
355 } | |
356 }else{ | |
357 for(vals=0;vals<maxvals;vals++){ | |
358 if(acc>4096)break; | |
359 acc+=os->lacing_vals[vals]&0x0ff; | |
360 granule_pos=os->granule_vals[vals]; | |
361 } | |
14280 | 362 } |
15250 | 363 |
364 /* construct the header in temp storage */ | |
365 memcpy(os->header,"OggS",4); | |
366 | |
367 /* stream structure version */ | |
368 os->header[4]=0x00; | |
369 | |
370 /* continued packet flag? */ | |
371 os->header[5]=0x00; | |
372 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; | |
373 /* first page flag? */ | |
374 if(os->b_o_s==0)os->header[5]|=0x02; | |
375 /* last page flag? */ | |
376 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; | |
377 os->b_o_s=1; | |
378 | |
379 /* 64 bits of PCM position */ | |
380 for(i=6;i<14;i++){ | |
381 os->header[i]=(unsigned char)(granule_pos&0xff); | |
382 granule_pos>>=8; | |
383 } | |
384 | |
385 /* 32 bits of stream serial number */ | |
386 { | |
387 long serialno=os->serialno; | |
388 for(i=14;i<18;i++){ | |
389 os->header[i]=(unsigned char)(serialno&0xff); | |
390 serialno>>=8; | |
391 } | |
392 } | |
393 | |
394 /* 32 bits of page counter (we have both counter and page header | |
395 because this val can roll over) */ | |
396 if(os->pageno==-1)os->pageno=0; /* because someone called | |
397 stream_reset; this would be a | |
398 strange thing to do in an | |
399 encode stream, but it has | |
400 plausible uses */ | |
401 { | |
402 long pageno=os->pageno++; | |
403 for(i=18;i<22;i++){ | |
404 os->header[i]=(unsigned char)(pageno&0xff); | |
405 pageno>>=8; | |
406 } | |
407 } | |
408 | |
409 /* zero for computation; filled in later */ | |
410 os->header[22]=0; | |
411 os->header[23]=0; | |
412 os->header[24]=0; | |
413 os->header[25]=0; | |
414 | |
415 /* segment table */ | |
416 os->header[26]=(unsigned char)(vals&0xff); | |
417 for(i=0;i<vals;i++) | |
418 bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff); | |
419 | |
420 /* set pointers in the ogg_page struct */ | |
421 og->header=os->header; | |
422 og->header_len=os->header_fill=vals+27; | |
423 og->body=os->body_data+os->body_returned; | |
424 og->body_len=bytes; | |
425 | |
426 /* advance the lacing data and set the body_returned pointer */ | |
427 | |
428 os->lacing_fill-=vals; | |
429 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals)); | |
430 memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals)); | |
431 os->body_returned+=bytes; | |
432 | |
433 /* calculate the checksum */ | |
434 | |
435 ogg_page_checksum_set(og); | |
436 | |
437 /* done */ | |
438 return(1); | |
439 } | |
440 | |
441 | |
442 /* This constructs pages from buffered packet segments. The pointers | |
443 returned are to static buffers; do not free. The returned buffers are | |
444 good only until the next call (using the same ogg_stream_state) */ | |
445 | |
446 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ | |
447 | |
448 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ | |
449 os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */ | |
450 os->lacing_fill>=255 || /* 'segment table full' case */ | |
451 (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */ | |
452 | |
453 return(ogg_stream_flush(os,og)); | |
454 } | |
455 | |
456 /* not enough data to construct a page and not end of stream */ | |
457 return(0); | |
458 } | |
459 | |
460 int ogg_stream_eos(ogg_stream_state *os){ | |
461 return os->e_o_s; | |
14280 | 462 } |
463 | |
464 /* DECODING PRIMITIVES: packet streaming layer **********************/ | |
465 | |
466 /* This has two layers to place more of the multi-serialno and paging | |
467 control in the application's hands. First, we expose a data buffer | |
468 using ogg_sync_buffer(). The app either copies into the | |
469 buffer, or passes it directly to read(), etc. We then call | |
470 ogg_sync_wrote() to tell how many bytes we just added. | |
471 | |
472 Pages are returned (pointers into the buffer in ogg_sync_state) | |
473 by ogg_sync_pageout(). The page is then submitted to | |
474 ogg_stream_pagein() along with the appropriate | |
475 ogg_stream_state* (ie, matching serialno). We then get raw | |
476 packets out calling ogg_stream_packetout() with a | |
477 ogg_stream_state. See the 'frame-prog.txt' docs for details and | |
478 example code. */ | |
479 | |
480 /* initialize the struct to a known state */ | |
481 int ogg_sync_init(ogg_sync_state *oy){ | |
482 if(oy){ | |
483 memset(oy,0,sizeof(*oy)); | |
484 } | |
485 return(0); | |
486 } | |
487 | |
488 /* clear non-flat storage within */ | |
489 int ogg_sync_clear(ogg_sync_state *oy){ | |
490 if(oy){ | |
491 if(oy->data)_ogg_free(oy->data); | |
492 ogg_sync_init(oy); | |
493 } | |
494 return(0); | |
495 } | |
496 | |
497 int ogg_sync_destroy(ogg_sync_state *oy){ | |
498 if(oy){ | |
499 ogg_sync_clear(oy); | |
500 _ogg_free(oy); | |
501 } | |
502 return(0); | |
503 } | |
504 | |
505 char *ogg_sync_buffer(ogg_sync_state *oy, long size){ | |
506 | |
507 /* first, clear out any space that has been previously returned */ | |
15250 | 508 if(oy->returned){ |
14280 | 509 oy->fill-=oy->returned; |
510 if(oy->fill>0) | |
511 memmove(oy->data,oy->data+oy->returned,oy->fill); | |
512 oy->returned=0; | |
513 } | |
514 | |
515 if(size>oy->storage-oy->fill){ | |
516 /* We need to extend the internal buffer */ | |
517 long newsize=size+oy->fill+4096; /* an extra page to be nice */ | |
518 | |
519 if(oy->data) | |
15250 | 520 oy->data=_ogg_realloc(oy->data,newsize); |
14280 | 521 else |
15250 | 522 oy->data=_ogg_malloc(newsize); |
14280 | 523 oy->storage=newsize; |
524 } | |
525 | |
526 /* expose a segment at least as large as requested at the fill mark */ | |
527 return((char *)oy->data+oy->fill); | |
528 } | |
529 | |
530 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ | |
531 if(oy->fill+bytes>oy->storage)return(-1); | |
532 oy->fill+=bytes; | |
533 return(0); | |
534 } | |
535 | |
536 /* sync the stream. This is meant to be useful for finding page | |
537 boundaries. | |
538 | |
539 return values for this: | |
540 -n) skipped n bytes | |
541 0) page not ready; more data (no bytes skipped) | |
542 n) page synced at current location; page length n bytes | |
543 | |
544 */ | |
545 | |
546 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ | |
547 unsigned char *page=oy->data+oy->returned; | |
548 unsigned char *next; | |
549 long bytes=oy->fill-oy->returned; | |
550 | |
551 if(oy->headerbytes==0){ | |
552 int headerbytes,i; | |
553 if(bytes<27)return(0); /* not enough for a header */ | |
554 | |
555 /* verify capture pattern */ | |
556 if(memcmp(page,"OggS",4))goto sync_fail; | |
557 | |
558 headerbytes=page[26]+27; | |
559 if(bytes<headerbytes)return(0); /* not enough for header + seg table */ | |
560 | |
561 /* count up body length in the segment table */ | |
562 | |
563 for(i=0;i<page[26];i++) | |
564 oy->bodybytes+=page[27+i]; | |
565 oy->headerbytes=headerbytes; | |
566 } | |
567 | |
568 if(oy->bodybytes+oy->headerbytes>bytes)return(0); | |
569 | |
570 /* The whole test page is buffered. Verify the checksum */ | |
571 { | |
572 /* Grab the checksum bytes, set the header field to zero */ | |
573 char chksum[4]; | |
574 ogg_page log; | |
575 | |
576 memcpy(chksum,page+22,4); | |
577 memset(page+22,0,4); | |
578 | |
579 /* set up a temp page struct and recompute the checksum */ | |
580 log.header=page; | |
581 log.header_len=oy->headerbytes; | |
582 log.body=page+oy->headerbytes; | |
583 log.body_len=oy->bodybytes; | |
584 ogg_page_checksum_set(&log); | |
585 | |
586 /* Compare */ | |
587 if(memcmp(chksum,page+22,4)){ | |
588 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page | |
589 at all) */ | |
590 /* replace the computed checksum with the one actually read in */ | |
591 memcpy(page+22,chksum,4); | |
592 | |
593 /* Bad checksum. Lose sync */ | |
594 goto sync_fail; | |
595 } | |
596 } | |
597 | |
598 /* yes, have a whole page all ready to go */ | |
599 { | |
600 unsigned char *page=oy->data+oy->returned; | |
601 long bytes; | |
602 | |
603 if(og){ | |
604 og->header=page; | |
605 og->header_len=oy->headerbytes; | |
606 og->body=page+oy->headerbytes; | |
607 og->body_len=oy->bodybytes; | |
608 } | |
609 | |
610 oy->unsynced=0; | |
611 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); | |
612 oy->headerbytes=0; | |
613 oy->bodybytes=0; | |
614 return(bytes); | |
615 } | |
616 | |
617 sync_fail: | |
618 | |
619 oy->headerbytes=0; | |
620 oy->bodybytes=0; | |
621 | |
622 /* search for possible capture */ | |
15250 | 623 next=memchr(page+1,'O',bytes-1); |
14280 | 624 if(!next) |
625 next=oy->data+oy->fill; | |
626 | |
627 oy->returned=next-oy->data; | |
628 return(-(next-page)); | |
629 } | |
630 | |
631 /* sync the stream and get a page. Keep trying until we find a page. | |
18613
052b4ad84883
Change "Supress" to "Suppress" in a couple comments.
corey
parents:
15250
diff
changeset
|
632 Suppress 'sync errors' after reporting the first. |
14280 | 633 |
634 return values: | |
635 -1) recapture (hole in data) | |
636 0) need more data | |
637 1) page returned | |
638 | |
639 Returns pointers into buffered data; invalidated by next call to | |
640 _stream, _clear, _init, or _buffer */ | |
641 | |
642 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ | |
643 | |
644 /* all we need to do is verify a page at the head of the stream | |
645 buffer. If it doesn't verify, we look for the next potential | |
646 frame */ | |
647 | |
15250 | 648 for(;;){ |
14280 | 649 long ret=ogg_sync_pageseek(oy,og); |
650 if(ret>0){ | |
651 /* have a page */ | |
652 return(1); | |
653 } | |
654 if(ret==0){ | |
655 /* need more data */ | |
656 return(0); | |
657 } | |
658 | |
659 /* head did not start a synced page... skipped some bytes */ | |
660 if(!oy->unsynced){ | |
661 oy->unsynced=1; | |
662 return(-1); | |
663 } | |
664 | |
665 /* loop. keep looking */ | |
666 | |
667 } | |
668 } | |
669 | |
670 /* add the incoming page to the stream state; we decompose the page | |
671 into packet segments here as well. */ | |
672 | |
673 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ | |
674 unsigned char *header=og->header; | |
675 unsigned char *body=og->body; | |
676 long bodysize=og->body_len; | |
677 int segptr=0; | |
678 | |
679 int version=ogg_page_version(og); | |
680 int continued=ogg_page_continued(og); | |
681 int bos=ogg_page_bos(og); | |
682 int eos=ogg_page_eos(og); | |
683 ogg_int64_t granulepos=ogg_page_granulepos(og); | |
684 int serialno=ogg_page_serialno(og); | |
685 long pageno=ogg_page_pageno(og); | |
686 int segments=header[26]; | |
687 | |
688 /* clean up 'returned data' */ | |
689 { | |
690 long lr=os->lacing_returned; | |
691 long br=os->body_returned; | |
692 | |
693 /* body data */ | |
15250 | 694 if(br){ |
14280 | 695 os->body_fill-=br; |
696 if(os->body_fill) | |
697 memmove(os->body_data,os->body_data+br,os->body_fill); | |
698 os->body_returned=0; | |
699 } | |
700 | |
15250 | 701 if(lr){ |
14280 | 702 /* segment table */ |
703 if(os->lacing_fill-lr){ | |
704 memmove(os->lacing_vals,os->lacing_vals+lr, | |
705 (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); | |
706 memmove(os->granule_vals,os->granule_vals+lr, | |
707 (os->lacing_fill-lr)*sizeof(*os->granule_vals)); | |
708 } | |
709 os->lacing_fill-=lr; | |
710 os->lacing_packet-=lr; | |
711 os->lacing_returned=0; | |
712 } | |
713 } | |
714 | |
715 /* check the serial number */ | |
716 if(serialno!=os->serialno)return(-1); | |
717 if(version>0)return(-1); | |
718 | |
719 _os_lacing_expand(os,segments+1); | |
720 | |
721 /* are we in sequence? */ | |
722 if(pageno!=os->pageno){ | |
723 int i; | |
724 | |
725 /* unroll previous partial packet (if any) */ | |
726 for(i=os->lacing_packet;i<os->lacing_fill;i++) | |
727 os->body_fill-=os->lacing_vals[i]&0xff; | |
728 os->lacing_fill=os->lacing_packet; | |
729 | |
730 /* make a note of dropped data in segment table */ | |
731 if(os->pageno!=-1){ | |
732 os->lacing_vals[os->lacing_fill++]=0x400; | |
733 os->lacing_packet++; | |
734 } | |
15250 | 735 } |
14280 | 736 |
15250 | 737 /* are we a 'continued packet' page? If so, we may need to skip |
738 some segments */ | |
739 if(continued){ | |
740 if(os->lacing_fill<1 || | |
741 os->lacing_vals[os->lacing_fill-1]==0x400){ | |
14280 | 742 bos=0; |
743 for(;segptr<segments;segptr++){ | |
744 int val=header[27+segptr]; | |
745 body+=val; | |
746 bodysize-=val; | |
747 if(val<255){ | |
748 segptr++; | |
749 break; | |
750 } | |
751 } | |
752 } | |
753 } | |
754 | |
755 if(bodysize){ | |
756 _os_body_expand(os,bodysize); | |
757 memcpy(os->body_data+os->body_fill,body,bodysize); | |
758 os->body_fill+=bodysize; | |
759 } | |
760 | |
761 { | |
762 int saved=-1; | |
763 while(segptr<segments){ | |
764 int val=header[27+segptr]; | |
765 os->lacing_vals[os->lacing_fill]=val; | |
766 os->granule_vals[os->lacing_fill]=-1; | |
767 | |
768 if(bos){ | |
769 os->lacing_vals[os->lacing_fill]|=0x100; | |
770 bos=0; | |
771 } | |
772 | |
773 if(val<255)saved=os->lacing_fill; | |
774 | |
775 os->lacing_fill++; | |
776 segptr++; | |
777 | |
778 if(val<255)os->lacing_packet=os->lacing_fill; | |
779 } | |
780 | |
781 /* set the granulepos on the last granuleval of the last full packet */ | |
782 if(saved!=-1){ | |
783 os->granule_vals[saved]=granulepos; | |
784 } | |
785 | |
786 } | |
787 | |
788 if(eos){ | |
789 os->e_o_s=1; | |
790 if(os->lacing_fill>0) | |
791 os->lacing_vals[os->lacing_fill-1]|=0x200; | |
792 } | |
793 | |
794 os->pageno=pageno+1; | |
795 | |
796 return(0); | |
797 } | |
798 | |
799 /* clear things to an initial state. Good to call, eg, before seeking */ | |
800 int ogg_sync_reset(ogg_sync_state *oy){ | |
801 oy->fill=0; | |
802 oy->returned=0; | |
803 oy->unsynced=0; | |
804 oy->headerbytes=0; | |
805 oy->bodybytes=0; | |
806 return(0); | |
807 } | |
808 | |
809 int ogg_stream_reset(ogg_stream_state *os){ | |
810 os->body_fill=0; | |
811 os->body_returned=0; | |
812 | |
813 os->lacing_fill=0; | |
814 os->lacing_packet=0; | |
815 os->lacing_returned=0; | |
816 | |
817 os->header_fill=0; | |
818 | |
819 os->e_o_s=0; | |
820 os->b_o_s=0; | |
821 os->pageno=-1; | |
822 os->packetno=0; | |
823 os->granulepos=0; | |
824 | |
825 return(0); | |
826 } | |
827 | |
15250 | 828 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){ |
829 ogg_stream_reset(os); | |
830 os->serialno=serialno; | |
831 return(0); | |
832 } | |
833 | |
14280 | 834 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ |
835 | |
836 /* The last part of decode. We have the stream broken into packet | |
837 segments. Now we need to group them into packets (or return the | |
838 out of sync markers) */ | |
839 | |
840 int ptr=os->lacing_returned; | |
841 | |
842 if(os->lacing_packet<=ptr)return(0); | |
843 | |
844 if(os->lacing_vals[ptr]&0x400){ | |
845 /* we need to tell the codec there's a gap; it might need to | |
846 handle previous packet dependencies. */ | |
847 os->lacing_returned++; | |
848 os->packetno++; | |
849 return(-1); | |
850 } | |
851 | |
852 if(!op && !adv)return(1); /* just using peek as an inexpensive way | |
853 to ask if there's a whole packet | |
854 waiting */ | |
855 | |
856 /* Gather the whole packet. We'll have no holes or a partial packet */ | |
857 { | |
858 int size=os->lacing_vals[ptr]&0xff; | |
859 int bytes=size; | |
860 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ | |
861 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ | |
862 | |
863 while(size==255){ | |
864 int val=os->lacing_vals[++ptr]; | |
865 size=val&0xff; | |
866 if(val&0x200)eos=0x200; | |
867 bytes+=size; | |
868 } | |
869 | |
870 if(op){ | |
871 op->e_o_s=eos; | |
872 op->b_o_s=bos; | |
873 op->packet=os->body_data+os->body_returned; | |
874 op->packetno=os->packetno; | |
875 op->granulepos=os->granule_vals[ptr]; | |
876 op->bytes=bytes; | |
877 } | |
878 | |
879 if(adv){ | |
880 os->body_returned+=bytes; | |
881 os->lacing_returned=ptr+1; | |
882 os->packetno++; | |
883 } | |
884 } | |
885 return(1); | |
886 } | |
887 | |
888 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ | |
889 return _packetout(os,op,1); | |
890 } | |
891 | |
892 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ | |
893 return _packetout(os,op,0); | |
894 } | |
895 | |
896 void ogg_packet_clear(ogg_packet *op) { | |
897 _ogg_free(op->packet); | |
898 memset(op, 0, sizeof(*op)); | |
899 } | |
900 |