Mercurial > mplayer.hg
comparison tremor/framing.c @ 14280:8631a3803289
internal Tremor decoder for Ogg/Vorbis
author | henry |
---|---|
date | Thu, 30 Dec 2004 12:11:32 +0000 |
parents | |
children | e891ff7a7b6c |
comparison
equal
deleted
inserted
replaced
14279:b4b202086260 | 14280:8631a3803289 |
---|---|
1 /******************************************************************** | |
2 * * | |
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * | |
4 * * | |
5 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |
6 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * | |
7 * ALL REDISTRIBUTION RIGHTS RESERVED. * | |
8 * * | |
9 ******************************************************************** | |
10 | |
11 function: code raw [Vorbis] packets into framed OggSquish stream and | |
12 decode Ogg streams back into raw packets | |
13 | |
14 note: The CRC code is directly derived from public domain code by | |
15 Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html | |
16 for details. | |
17 | |
18 ********************************************************************/ | |
19 | |
20 #include <stdlib.h> | |
21 #include <string.h> | |
22 #include "ogg.h" | |
23 | |
24 /* A complete description of Ogg framing exists in docs/framing.html */ | |
25 | |
26 int ogg_page_version(ogg_page *og){ | |
27 return((int)(og->header[4])); | |
28 } | |
29 | |
30 int ogg_page_continued(ogg_page *og){ | |
31 return((int)(og->header[5]&0x01)); | |
32 } | |
33 | |
34 int ogg_page_bos(ogg_page *og){ | |
35 return((int)(og->header[5]&0x02)); | |
36 } | |
37 | |
38 int ogg_page_eos(ogg_page *og){ | |
39 return((int)(og->header[5]&0x04)); | |
40 } | |
41 | |
42 ogg_int64_t ogg_page_granulepos(ogg_page *og){ | |
43 unsigned char *page=og->header; | |
44 ogg_int64_t granulepos=page[13]&(0xff); | |
45 granulepos= (granulepos<<8)|(page[12]&0xff); | |
46 granulepos= (granulepos<<8)|(page[11]&0xff); | |
47 granulepos= (granulepos<<8)|(page[10]&0xff); | |
48 granulepos= (granulepos<<8)|(page[9]&0xff); | |
49 granulepos= (granulepos<<8)|(page[8]&0xff); | |
50 granulepos= (granulepos<<8)|(page[7]&0xff); | |
51 granulepos= (granulepos<<8)|(page[6]&0xff); | |
52 return(granulepos); | |
53 } | |
54 | |
55 int ogg_page_serialno(ogg_page *og){ | |
56 return(og->header[14] | | |
57 (og->header[15]<<8) | | |
58 (og->header[16]<<16) | | |
59 (og->header[17]<<24)); | |
60 } | |
61 | |
62 long ogg_page_pageno(ogg_page *og){ | |
63 return(og->header[18] | | |
64 (og->header[19]<<8) | | |
65 (og->header[20]<<16) | | |
66 (og->header[21]<<24)); | |
67 } | |
68 | |
69 | |
70 | |
71 /* returns the number of packets that are completed on this page (if | |
72 the leading packet is begun on a previous page, but ends on this | |
73 page, it's counted */ | |
74 | |
75 /* NOTE: | |
76 If a page consists of a packet begun on a previous page, and a new | |
77 packet begun (but not completed) on this page, the return will be: | |
78 ogg_page_packets(page) ==1, | |
79 ogg_page_continued(page) !=0 | |
80 | |
81 If a page happens to be a single packet that was begun on a | |
82 previous page, and spans to the next page (in the case of a three or | |
83 more page packet), the return will be: | |
84 ogg_page_packets(page) ==0, | |
85 ogg_page_continued(page) !=0 | |
86 */ | |
87 | |
88 int ogg_page_packets(ogg_page *og){ | |
89 int i,n=og->header[26],count=0; | |
90 for(i=0;i<n;i++) | |
91 if(og->header[27+i]<255)count++; | |
92 return(count); | |
93 } | |
94 | |
95 static ogg_uint32_t crc_lookup[256]={ | |
96 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9, | |
97 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, | |
98 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61, | |
99 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, | |
100 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9, | |
101 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, | |
102 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011, | |
103 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, | |
104 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039, | |
105 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, | |
106 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81, | |
107 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, | |
108 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49, | |
109 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, | |
110 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1, | |
111 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, | |
112 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae, | |
113 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, | |
114 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16, | |
115 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, | |
116 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde, | |
117 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, | |
118 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066, | |
119 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, | |
120 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e, | |
121 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, | |
122 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6, | |
123 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, | |
124 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e, | |
125 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, | |
126 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686, | |
127 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, | |
128 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637, | |
129 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, | |
130 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f, | |
131 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, | |
132 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47, | |
133 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, | |
134 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff, | |
135 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, | |
136 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7, | |
137 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, | |
138 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f, | |
139 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, | |
140 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7, | |
141 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, | |
142 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f, | |
143 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, | |
144 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640, | |
145 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, | |
146 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8, | |
147 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, | |
148 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30, | |
149 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, | |
150 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088, | |
151 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, | |
152 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0, | |
153 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, | |
154 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18, | |
155 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, | |
156 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0, | |
157 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, | |
158 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668, | |
159 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4}; | |
160 | |
161 /* init the encode/decode logical stream state */ | |
162 | |
163 int ogg_stream_init(ogg_stream_state *os,int serialno){ | |
164 if(os){ | |
165 memset(os,0,sizeof(*os)); | |
166 os->body_storage=16*1024; | |
167 os->body_data=(unsigned char *)_ogg_malloc(os->body_storage*sizeof(*os->body_data)); | |
168 | |
169 os->lacing_storage=1024; | |
170 os->lacing_vals=(int *)_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals)); | |
171 os->granule_vals=(ogg_int64_t *)_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals)); | |
172 | |
173 os->serialno=serialno; | |
174 | |
175 return(0); | |
176 } | |
177 return(-1); | |
178 } | |
179 | |
180 /* _clear does not free os, only the non-flat storage within */ | |
181 int ogg_stream_clear(ogg_stream_state *os){ | |
182 if(os){ | |
183 if(os->body_data)_ogg_free(os->body_data); | |
184 if(os->lacing_vals)_ogg_free(os->lacing_vals); | |
185 if(os->granule_vals)_ogg_free(os->granule_vals); | |
186 | |
187 memset(os,0,sizeof(*os)); | |
188 } | |
189 return(0); | |
190 } | |
191 | |
192 int ogg_stream_destroy(ogg_stream_state *os){ | |
193 if(os){ | |
194 ogg_stream_clear(os); | |
195 _ogg_free(os); | |
196 } | |
197 return(0); | |
198 } | |
199 | |
200 /* Helpers for ogg_stream_encode; this keeps the structure and | |
201 what's happening fairly clear */ | |
202 | |
203 static void _os_body_expand(ogg_stream_state *os,int needed){ | |
204 if(os->body_storage<=os->body_fill+needed){ | |
205 os->body_storage+=(needed+1024); | |
206 os->body_data=(unsigned char *)_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data)); | |
207 } | |
208 } | |
209 | |
210 static void _os_lacing_expand(ogg_stream_state *os,int needed){ | |
211 if(os->lacing_storage<=os->lacing_fill+needed){ | |
212 os->lacing_storage+=(needed+32); | |
213 os->lacing_vals=(int *)_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals)); | |
214 os->granule_vals=(ogg_int64_t *)_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals)); | |
215 } | |
216 } | |
217 | |
218 /* checksum the page */ | |
219 /* Direct table CRC; note that this will be faster in the future if we | |
220 perform the checksum silmultaneously with other copies */ | |
221 | |
222 void ogg_page_checksum_set(ogg_page *og){ | |
223 if(og){ | |
224 ogg_uint32_t crc_reg=0; | |
225 int i; | |
226 | |
227 /* safety; needed for API behavior, but not framing code */ | |
228 og->header[22]=0; | |
229 og->header[23]=0; | |
230 og->header[24]=0; | |
231 og->header[25]=0; | |
232 | |
233 for(i=0;i<og->header_len;i++) | |
234 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]]; | |
235 for(i=0;i<og->body_len;i++) | |
236 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]]; | |
237 | |
238 og->header[22]=crc_reg&0xff; | |
239 og->header[23]=(crc_reg>>8)&0xff; | |
240 og->header[24]=(crc_reg>>16)&0xff; | |
241 og->header[25]=(crc_reg>>24)&0xff; | |
242 } | |
243 } | |
244 | |
245 /* DECODING PRIMITIVES: packet streaming layer **********************/ | |
246 | |
247 /* This has two layers to place more of the multi-serialno and paging | |
248 control in the application's hands. First, we expose a data buffer | |
249 using ogg_sync_buffer(). The app either copies into the | |
250 buffer, or passes it directly to read(), etc. We then call | |
251 ogg_sync_wrote() to tell how many bytes we just added. | |
252 | |
253 Pages are returned (pointers into the buffer in ogg_sync_state) | |
254 by ogg_sync_pageout(). The page is then submitted to | |
255 ogg_stream_pagein() along with the appropriate | |
256 ogg_stream_state* (ie, matching serialno). We then get raw | |
257 packets out calling ogg_stream_packetout() with a | |
258 ogg_stream_state. See the 'frame-prog.txt' docs for details and | |
259 example code. */ | |
260 | |
261 /* initialize the struct to a known state */ | |
262 int ogg_sync_init(ogg_sync_state *oy){ | |
263 if(oy){ | |
264 memset(oy,0,sizeof(*oy)); | |
265 } | |
266 return(0); | |
267 } | |
268 | |
269 /* clear non-flat storage within */ | |
270 int ogg_sync_clear(ogg_sync_state *oy){ | |
271 if(oy){ | |
272 if(oy->data)_ogg_free(oy->data); | |
273 ogg_sync_init(oy); | |
274 } | |
275 return(0); | |
276 } | |
277 | |
278 int ogg_sync_destroy(ogg_sync_state *oy){ | |
279 if(oy){ | |
280 ogg_sync_clear(oy); | |
281 _ogg_free(oy); | |
282 } | |
283 return(0); | |
284 } | |
285 | |
286 char *ogg_sync_buffer(ogg_sync_state *oy, long size){ | |
287 | |
288 /* first, clear out any space that has been previously returned */ | |
289 if(oy->returned>8192){ | |
290 oy->fill-=oy->returned; | |
291 if(oy->fill>0) | |
292 memmove(oy->data,oy->data+oy->returned,oy->fill); | |
293 oy->returned=0; | |
294 } | |
295 | |
296 if(size>oy->storage-oy->fill){ | |
297 /* We need to extend the internal buffer */ | |
298 long newsize=size+oy->fill+4096; /* an extra page to be nice */ | |
299 | |
300 if(oy->data) | |
301 oy->data=(unsigned char *)_ogg_realloc(oy->data,newsize); | |
302 else | |
303 oy->data=(unsigned char *)_ogg_malloc(newsize); | |
304 oy->storage=newsize; | |
305 } | |
306 | |
307 /* expose a segment at least as large as requested at the fill mark */ | |
308 return((char *)oy->data+oy->fill); | |
309 } | |
310 | |
311 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ | |
312 if(oy->fill+bytes>oy->storage)return(-1); | |
313 oy->fill+=bytes; | |
314 return(0); | |
315 } | |
316 | |
317 /* sync the stream. This is meant to be useful for finding page | |
318 boundaries. | |
319 | |
320 return values for this: | |
321 -n) skipped n bytes | |
322 0) page not ready; more data (no bytes skipped) | |
323 n) page synced at current location; page length n bytes | |
324 | |
325 */ | |
326 | |
327 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ | |
328 unsigned char *page=oy->data+oy->returned; | |
329 unsigned char *next; | |
330 long bytes=oy->fill-oy->returned; | |
331 | |
332 if(oy->headerbytes==0){ | |
333 int headerbytes,i; | |
334 if(bytes<27)return(0); /* not enough for a header */ | |
335 | |
336 /* verify capture pattern */ | |
337 if(memcmp(page,"OggS",4))goto sync_fail; | |
338 | |
339 headerbytes=page[26]+27; | |
340 if(bytes<headerbytes)return(0); /* not enough for header + seg table */ | |
341 | |
342 /* count up body length in the segment table */ | |
343 | |
344 for(i=0;i<page[26];i++) | |
345 oy->bodybytes+=page[27+i]; | |
346 oy->headerbytes=headerbytes; | |
347 } | |
348 | |
349 if(oy->bodybytes+oy->headerbytes>bytes)return(0); | |
350 | |
351 /* The whole test page is buffered. Verify the checksum */ | |
352 { | |
353 /* Grab the checksum bytes, set the header field to zero */ | |
354 char chksum[4]; | |
355 ogg_page log; | |
356 | |
357 memcpy(chksum,page+22,4); | |
358 memset(page+22,0,4); | |
359 | |
360 /* set up a temp page struct and recompute the checksum */ | |
361 log.header=page; | |
362 log.header_len=oy->headerbytes; | |
363 log.body=page+oy->headerbytes; | |
364 log.body_len=oy->bodybytes; | |
365 ogg_page_checksum_set(&log); | |
366 | |
367 /* Compare */ | |
368 if(memcmp(chksum,page+22,4)){ | |
369 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page | |
370 at all) */ | |
371 /* replace the computed checksum with the one actually read in */ | |
372 memcpy(page+22,chksum,4); | |
373 | |
374 /* Bad checksum. Lose sync */ | |
375 goto sync_fail; | |
376 } | |
377 } | |
378 | |
379 /* yes, have a whole page all ready to go */ | |
380 { | |
381 unsigned char *page=oy->data+oy->returned; | |
382 long bytes; | |
383 | |
384 if(og){ | |
385 og->header=page; | |
386 og->header_len=oy->headerbytes; | |
387 og->body=page+oy->headerbytes; | |
388 og->body_len=oy->bodybytes; | |
389 } | |
390 | |
391 oy->unsynced=0; | |
392 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); | |
393 oy->headerbytes=0; | |
394 oy->bodybytes=0; | |
395 return(bytes); | |
396 } | |
397 | |
398 sync_fail: | |
399 | |
400 oy->headerbytes=0; | |
401 oy->bodybytes=0; | |
402 | |
403 /* search for possible capture */ | |
404 next=(unsigned char *)memchr(page+1,'O',bytes-1); | |
405 if(!next) | |
406 next=oy->data+oy->fill; | |
407 | |
408 oy->returned=next-oy->data; | |
409 return(-(next-page)); | |
410 } | |
411 | |
412 /* sync the stream and get a page. Keep trying until we find a page. | |
413 Supress 'sync errors' after reporting the first. | |
414 | |
415 return values: | |
416 -1) recapture (hole in data) | |
417 0) need more data | |
418 1) page returned | |
419 | |
420 Returns pointers into buffered data; invalidated by next call to | |
421 _stream, _clear, _init, or _buffer */ | |
422 | |
423 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ | |
424 | |
425 /* all we need to do is verify a page at the head of the stream | |
426 buffer. If it doesn't verify, we look for the next potential | |
427 frame */ | |
428 | |
429 while(1){ | |
430 long ret=ogg_sync_pageseek(oy,og); | |
431 if(ret>0){ | |
432 /* have a page */ | |
433 return(1); | |
434 } | |
435 if(ret==0){ | |
436 /* need more data */ | |
437 return(0); | |
438 } | |
439 | |
440 /* head did not start a synced page... skipped some bytes */ | |
441 if(!oy->unsynced){ | |
442 oy->unsynced=1; | |
443 return(-1); | |
444 } | |
445 | |
446 /* loop. keep looking */ | |
447 | |
448 } | |
449 } | |
450 | |
451 /* add the incoming page to the stream state; we decompose the page | |
452 into packet segments here as well. */ | |
453 | |
454 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ | |
455 unsigned char *header=og->header; | |
456 unsigned char *body=og->body; | |
457 long bodysize=og->body_len; | |
458 int segptr=0; | |
459 | |
460 int version=ogg_page_version(og); | |
461 int continued=ogg_page_continued(og); | |
462 int bos=ogg_page_bos(og); | |
463 int eos=ogg_page_eos(og); | |
464 ogg_int64_t granulepos=ogg_page_granulepos(og); | |
465 int serialno=ogg_page_serialno(og); | |
466 long pageno=ogg_page_pageno(og); | |
467 int segments=header[26]; | |
468 | |
469 /* clean up 'returned data' */ | |
470 { | |
471 long lr=os->lacing_returned; | |
472 long br=os->body_returned; | |
473 | |
474 /* body data */ | |
475 if(br>8192){ | |
476 os->body_fill-=br; | |
477 if(os->body_fill) | |
478 memmove(os->body_data,os->body_data+br,os->body_fill); | |
479 os->body_returned=0; | |
480 } | |
481 | |
482 if(lr>8192){ | |
483 /* segment table */ | |
484 if(os->lacing_fill-lr){ | |
485 memmove(os->lacing_vals,os->lacing_vals+lr, | |
486 (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); | |
487 memmove(os->granule_vals,os->granule_vals+lr, | |
488 (os->lacing_fill-lr)*sizeof(*os->granule_vals)); | |
489 } | |
490 os->lacing_fill-=lr; | |
491 os->lacing_packet-=lr; | |
492 os->lacing_returned=0; | |
493 } | |
494 } | |
495 | |
496 /* check the serial number */ | |
497 if(serialno!=os->serialno)return(-1); | |
498 if(version>0)return(-1); | |
499 | |
500 _os_lacing_expand(os,segments+1); | |
501 | |
502 /* are we in sequence? */ | |
503 if(pageno!=os->pageno){ | |
504 int i; | |
505 | |
506 /* unroll previous partial packet (if any) */ | |
507 for(i=os->lacing_packet;i<os->lacing_fill;i++) | |
508 os->body_fill-=os->lacing_vals[i]&0xff; | |
509 os->lacing_fill=os->lacing_packet; | |
510 | |
511 /* make a note of dropped data in segment table */ | |
512 if(os->pageno!=-1){ | |
513 os->lacing_vals[os->lacing_fill++]=0x400; | |
514 os->lacing_packet++; | |
515 } | |
516 | |
517 /* are we a 'continued packet' page? If so, we'll need to skip | |
518 some segments */ | |
519 if(continued){ | |
520 bos=0; | |
521 for(;segptr<segments;segptr++){ | |
522 int val=header[27+segptr]; | |
523 body+=val; | |
524 bodysize-=val; | |
525 if(val<255){ | |
526 segptr++; | |
527 break; | |
528 } | |
529 } | |
530 } | |
531 } | |
532 | |
533 if(bodysize){ | |
534 _os_body_expand(os,bodysize); | |
535 memcpy(os->body_data+os->body_fill,body,bodysize); | |
536 os->body_fill+=bodysize; | |
537 } | |
538 | |
539 { | |
540 int saved=-1; | |
541 while(segptr<segments){ | |
542 int val=header[27+segptr]; | |
543 os->lacing_vals[os->lacing_fill]=val; | |
544 os->granule_vals[os->lacing_fill]=-1; | |
545 | |
546 if(bos){ | |
547 os->lacing_vals[os->lacing_fill]|=0x100; | |
548 bos=0; | |
549 } | |
550 | |
551 if(val<255)saved=os->lacing_fill; | |
552 | |
553 os->lacing_fill++; | |
554 segptr++; | |
555 | |
556 if(val<255)os->lacing_packet=os->lacing_fill; | |
557 } | |
558 | |
559 /* set the granulepos on the last granuleval of the last full packet */ | |
560 if(saved!=-1){ | |
561 os->granule_vals[saved]=granulepos; | |
562 } | |
563 | |
564 } | |
565 | |
566 if(eos){ | |
567 os->e_o_s=1; | |
568 if(os->lacing_fill>0) | |
569 os->lacing_vals[os->lacing_fill-1]|=0x200; | |
570 } | |
571 | |
572 os->pageno=pageno+1; | |
573 | |
574 return(0); | |
575 } | |
576 | |
577 /* clear things to an initial state. Good to call, eg, before seeking */ | |
578 int ogg_sync_reset(ogg_sync_state *oy){ | |
579 oy->fill=0; | |
580 oy->returned=0; | |
581 oy->unsynced=0; | |
582 oy->headerbytes=0; | |
583 oy->bodybytes=0; | |
584 return(0); | |
585 } | |
586 | |
587 int ogg_stream_reset(ogg_stream_state *os){ | |
588 os->body_fill=0; | |
589 os->body_returned=0; | |
590 | |
591 os->lacing_fill=0; | |
592 os->lacing_packet=0; | |
593 os->lacing_returned=0; | |
594 | |
595 os->header_fill=0; | |
596 | |
597 os->e_o_s=0; | |
598 os->b_o_s=0; | |
599 os->pageno=-1; | |
600 os->packetno=0; | |
601 os->granulepos=0; | |
602 | |
603 return(0); | |
604 } | |
605 | |
606 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ | |
607 | |
608 /* The last part of decode. We have the stream broken into packet | |
609 segments. Now we need to group them into packets (or return the | |
610 out of sync markers) */ | |
611 | |
612 int ptr=os->lacing_returned; | |
613 | |
614 if(os->lacing_packet<=ptr)return(0); | |
615 | |
616 if(os->lacing_vals[ptr]&0x400){ | |
617 /* we need to tell the codec there's a gap; it might need to | |
618 handle previous packet dependencies. */ | |
619 os->lacing_returned++; | |
620 os->packetno++; | |
621 return(-1); | |
622 } | |
623 | |
624 if(!op && !adv)return(1); /* just using peek as an inexpensive way | |
625 to ask if there's a whole packet | |
626 waiting */ | |
627 | |
628 /* Gather the whole packet. We'll have no holes or a partial packet */ | |
629 { | |
630 int size=os->lacing_vals[ptr]&0xff; | |
631 int bytes=size; | |
632 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ | |
633 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ | |
634 | |
635 while(size==255){ | |
636 int val=os->lacing_vals[++ptr]; | |
637 size=val&0xff; | |
638 if(val&0x200)eos=0x200; | |
639 bytes+=size; | |
640 } | |
641 | |
642 if(op){ | |
643 op->e_o_s=eos; | |
644 op->b_o_s=bos; | |
645 op->packet=os->body_data+os->body_returned; | |
646 op->packetno=os->packetno; | |
647 op->granulepos=os->granule_vals[ptr]; | |
648 op->bytes=bytes; | |
649 } | |
650 | |
651 if(adv){ | |
652 os->body_returned+=bytes; | |
653 os->lacing_returned=ptr+1; | |
654 os->packetno++; | |
655 } | |
656 } | |
657 return(1); | |
658 } | |
659 | |
660 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ | |
661 return _packetout(os,op,1); | |
662 } | |
663 | |
664 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ | |
665 return _packetout(os,op,0); | |
666 } | |
667 | |
668 void ogg_packet_clear(ogg_packet *op) { | |
669 _ogg_free(op->packet); | |
670 memset(op, 0, sizeof(*op)); | |
671 } | |
672 |