summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libopus/ogg/framing.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libopus/ogg/framing.c')
-rw-r--r--lib/rbcodec/codecs/libopus/ogg/framing.c1025
1 files changed, 1025 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libopus/ogg/framing.c b/lib/rbcodec/codecs/libopus/ogg/framing.c
new file mode 100644
index 0000000000..f007de176a
--- /dev/null
+++ b/lib/rbcodec/codecs/libopus/ogg/framing.c
@@ -0,0 +1,1025 @@
1/********************************************************************
2 * *
3 * THIS FILE IS PART OF THE Ogg CONTAINER 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. *
7 * *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: code raw packets into framed OggSquish stream and
14 decode Ogg streams back into raw packets
15 last mod: $Id: framing.c 18052 2011-08-04 17:57:02Z giles $
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/ogg.h>
26
27/* A complete description of Ogg framing exists in docs/framing.html */
28
29int ogg_page_version(const ogg_page *og){
30 return((int)(og->header[4]));
31}
32
33int ogg_page_continued(const ogg_page *og){
34 return((int)(og->header[5]&0x01));
35}
36
37int ogg_page_bos(const ogg_page *og){
38 return((int)(og->header[5]&0x02));
39}
40
41int ogg_page_eos(const ogg_page *og){
42 return((int)(og->header[5]&0x04));
43}
44
45ogg_int64_t ogg_page_granulepos(const 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
58int ogg_page_serialno(const 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
65long ogg_page_pageno(const 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
91int ogg_page_packets(const 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
98
99#if 0
100/* helper to initialize lookup for direct-table CRC (illustrative; we
101 use the static init below) */
102
103static 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
120static const ogg_uint32_t crc_lookup[256]={
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
188int ogg_stream_init(ogg_stream_state *os,int serialno){
189 if(os){
190 memset(os,0,sizeof(*os));
191 os->body_storage=16*1024;
192 os->lacing_storage=1024;
193
194 os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
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));
197
198 if(!os->body_data || !os->lacing_vals || !os->granule_vals){
199 ogg_stream_clear(os);
200 return -1;
201 }
202
203 os->serialno=serialno;
204
205 return(0);
206 }
207 return(-1);
208}
209
210/* async/delayed error detection for the ogg_stream_state */
211int ogg_stream_check(ogg_stream_state *os){
212 if(!os || !os->body_data) return -1;
213 return 0;
214}
215
216/* _clear does not free os, only the non-flat storage within */
217int ogg_stream_clear(ogg_stream_state *os){
218 if(os){
219 if(os->body_data)_ogg_free(os->body_data);
220 if(os->lacing_vals)_ogg_free(os->lacing_vals);
221 if(os->granule_vals)_ogg_free(os->granule_vals);
222
223 memset(os,0,sizeof(*os));
224 }
225 return(0);
226}
227
228int ogg_stream_destroy(ogg_stream_state *os){
229 if(os){
230 ogg_stream_clear(os);
231 _ogg_free(os);
232 }
233 return(0);
234}
235
236/* Helpers for ogg_stream_encode; this keeps the structure and
237 what's happening fairly clear */
238
239static int _os_body_expand(ogg_stream_state *os,int needed){
240 if(os->body_storage<=os->body_fill+needed){
241 void *ret;
242 ret=_ogg_realloc(os->body_data,(os->body_storage+needed+1024)*
243 sizeof(*os->body_data));
244 if(!ret){
245 ogg_stream_clear(os);
246 return -1;
247 }
248 os->body_storage+=(needed+1024);
249 os->body_data=ret;
250 }
251 return 0;
252}
253
254static int _os_lacing_expand(ogg_stream_state *os,int needed){
255 if(os->lacing_storage<=os->lacing_fill+needed){
256 void *ret;
257 ret=_ogg_realloc(os->lacing_vals,(os->lacing_storage+needed+32)*
258 sizeof(*os->lacing_vals));
259 if(!ret){
260 ogg_stream_clear(os);
261 return -1;
262 }
263 os->lacing_vals=ret;
264 ret=_ogg_realloc(os->granule_vals,(os->lacing_storage+needed+32)*
265 sizeof(*os->granule_vals));
266 if(!ret){
267 ogg_stream_clear(os);
268 return -1;
269 }
270 os->granule_vals=ret;
271 os->lacing_storage+=(needed+32);
272 }
273 return 0;
274}
275
276/* checksum the page */
277/* Direct table CRC; note that this will be faster in the future if we
278 perform the checksum simultaneously with other copies */
279
280void ogg_page_checksum_set(ogg_page *og){
281 if(og){
282 ogg_uint32_t crc_reg=0;
283 int i;
284
285 /* safety; needed for API behavior, but not framing code */
286 og->header[22]=0;
287 og->header[23]=0;
288 og->header[24]=0;
289 og->header[25]=0;
290
291 for(i=0;i<og->header_len;i++)
292 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
293 for(i=0;i<og->body_len;i++)
294 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
295
296 og->header[22]=(unsigned char)(crc_reg&0xff);
297 og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
298 og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
299 og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
300 }
301}
302
303/* submit data to the internal buffer of the framing engine */
304int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
305 long e_o_s, ogg_int64_t granulepos){
306
307 int bytes = 0, lacing_vals, i;
308
309 if(ogg_stream_check(os)) return -1;
310 if(!iov) return 0;
311
312 for (i = 0; i < count; ++i) bytes += (int)iov[i].iov_len;
313 lacing_vals=bytes/255+1;
314
315 if(os->body_returned){
316 /* advance packet data according to the body_returned pointer. We
317 had to keep it around to return a pointer into the buffer last
318 call */
319
320 os->body_fill-=os->body_returned;
321 if(os->body_fill)
322 memmove(os->body_data,os->body_data+os->body_returned,
323 os->body_fill);
324 os->body_returned=0;
325 }
326
327 /* make sure we have the buffer storage */
328 if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
329 return -1;
330
331 /* Copy in the submitted packet. Yes, the copy is a waste; this is
332 the liability of overly clean abstraction for the time being. It
333 will actually be fairly easy to eliminate the extra copy in the
334 future */
335
336 for (i = 0; i < count; ++i) {
337 memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
338 os->body_fill += (int)iov[i].iov_len;
339 }
340
341 /* Store lacing vals for this packet */
342 for(i=0;i<lacing_vals-1;i++){
343 os->lacing_vals[os->lacing_fill+i]=255;
344 os->granule_vals[os->lacing_fill+i]=os->granulepos;
345 }
346 os->lacing_vals[os->lacing_fill+i]=bytes%255;
347 os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
348
349 /* flag the first segment as the beginning of the packet */
350 os->lacing_vals[os->lacing_fill]|= 0x100;
351
352 os->lacing_fill+=lacing_vals;
353
354 /* for the sake of completeness */
355 os->packetno++;
356
357 if(e_o_s)os->e_o_s=1;
358
359 return(0);
360}
361
362int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
363 ogg_iovec_t iov;
364 iov.iov_base = op->packet;
365 iov.iov_len = op->bytes;
366 return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos);
367}
368
369/* Conditionally flush a page; force==0 will only flush nominal-size
370 pages, force==1 forces us to flush a page regardless of page size
371 so long as there's any data available at all. */
372static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){
373 int i;
374 int vals=0;
375 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
376 int bytes=0;
377 long acc=0;
378 ogg_int64_t granule_pos=-1;
379
380 if(ogg_stream_check(os)) return(0);
381 if(maxvals==0) return(0);
382
383 /* construct a page */
384 /* decide how many segments to include */
385
386 /* If this is the initial header case, the first page must only include
387 the initial header packet */
388 if(os->b_o_s==0){ /* 'initial header page' case */
389 granule_pos=0;
390 for(vals=0;vals<maxvals;vals++){
391 if((os->lacing_vals[vals]&0x0ff)<255){
392 vals++;
393 break;
394 }
395 }
396 }else{
397
398 /* The extra packets_done, packet_just_done logic here attempts to do two things:
399 1) Don't unneccessarily span pages.
400 2) Unless necessary, don't flush pages if there are less than four packets on
401 them; this expands page size to reduce unneccessary overhead if incoming packets
402 are large.
403 These are not necessary behaviors, just 'always better than naive flushing'
404 without requiring an application to explicitly request a specific optimized
405 behavior. We'll want an explicit behavior setup pathway eventually as well. */
406
407 int packets_done=0;
408 int packet_just_done=0;
409 for(vals=0;vals<maxvals;vals++){
410 if(acc>nfill && packet_just_done>=4){
411 force=1;
412 break;
413 }
414 acc+=os->lacing_vals[vals]&0x0ff;
415 if((os->lacing_vals[vals]&0xff)<255){
416 granule_pos=os->granule_vals[vals];
417 packet_just_done=++packets_done;
418 }else
419 packet_just_done=0;
420 }
421 if(vals==255)force=1;
422 }
423
424 if(!force) return(0);
425
426 /* construct the header in temp storage */
427 memcpy(os->header,"OggS",4);
428
429 /* stream structure version */
430 os->header[4]=0x00;
431
432 /* continued packet flag? */
433 os->header[5]=0x00;
434 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
435 /* first page flag? */
436 if(os->b_o_s==0)os->header[5]|=0x02;
437 /* last page flag? */
438 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
439 os->b_o_s=1;
440
441 /* 64 bits of PCM position */
442 for(i=6;i<14;i++){
443 os->header[i]=(unsigned char)(granule_pos&0xff);
444 granule_pos>>=8;
445 }
446
447 /* 32 bits of stream serial number */
448 {
449 long serialno=os->serialno;
450 for(i=14;i<18;i++){
451 os->header[i]=(unsigned char)(serialno&0xff);
452 serialno>>=8;
453 }
454 }
455
456 /* 32 bits of page counter (we have both counter and page header
457 because this val can roll over) */
458 if(os->pageno==-1)os->pageno=0; /* because someone called
459 stream_reset; this would be a
460 strange thing to do in an
461 encode stream, but it has
462 plausible uses */
463 {
464 long pageno=os->pageno++;
465 for(i=18;i<22;i++){
466 os->header[i]=(unsigned char)(pageno&0xff);
467 pageno>>=8;
468 }
469 }
470
471 /* zero for computation; filled in later */
472 os->header[22]=0;
473 os->header[23]=0;
474 os->header[24]=0;
475 os->header[25]=0;
476
477 /* segment table */
478 os->header[26]=(unsigned char)(vals&0xff);
479 for(i=0;i<vals;i++)
480 bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
481
482 /* set pointers in the ogg_page struct */
483 og->header=os->header;
484 og->header_len=os->header_fill=vals+27;
485 og->body=os->body_data+os->body_returned;
486 og->body_len=bytes;
487
488 /* advance the lacing data and set the body_returned pointer */
489
490 os->lacing_fill-=vals;
491 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
492 memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
493 os->body_returned+=bytes;
494
495 /* calculate the checksum */
496
497 ogg_page_checksum_set(og);
498
499 /* done */
500 return(1);
501}
502
503/* This will flush remaining packets into a page (returning nonzero),
504 even if there is not enough data to trigger a flush normally
505 (undersized page). If there are no packets or partial packets to
506 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
507 try to flush a normal sized page like ogg_stream_pageout; a call to
508 ogg_stream_flush does not guarantee that all packets have flushed.
509 Only a return value of 0 from ogg_stream_flush indicates all packet
510 data is flushed into pages.
511
512 since ogg_stream_flush will flush the last page in a stream even if
513 it's undersized, you almost certainly want to use ogg_stream_pageout
514 (and *not* ogg_stream_flush) unless you specifically need to flush
515 a page regardless of size in the middle of a stream. */
516
517int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
518 return ogg_stream_flush_i(os,og,1,4096);
519}
520
521/* Like the above, but an argument is provided to adjust the nominal
522 page size for applications which are smart enough to provide their
523 own delay based flushing */
524
525int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){
526 return ogg_stream_flush_i(os,og,1,nfill);
527}
528
529/* This constructs pages from buffered packet segments. The pointers
530returned are to static buffers; do not free. The returned buffers are
531good only until the next call (using the same ogg_stream_state) */
532
533int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
534 int force=0;
535 if(ogg_stream_check(os)) return 0;
536
537 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
538 (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
539 force=1;
540
541 return(ogg_stream_flush_i(os,og,force,4096));
542}
543
544/* Like the above, but an argument is provided to adjust the nominal
545page size for applications which are smart enough to provide their
546own delay based flushing */
547
548int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
549 int force=0;
550 if(ogg_stream_check(os)) return 0;
551
552 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
553 (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
554 force=1;
555
556 return(ogg_stream_flush_i(os,og,force,nfill));
557}
558
559int ogg_stream_eos(ogg_stream_state *os){
560 if(ogg_stream_check(os)) return 1;
561 return os->e_o_s;
562}
563
564/* DECODING PRIMITIVES: packet streaming layer **********************/
565
566/* This has two layers to place more of the multi-serialno and paging
567 control in the application's hands. First, we expose a data buffer
568 using ogg_sync_buffer(). The app either copies into the
569 buffer, or passes it directly to read(), etc. We then call
570 ogg_sync_wrote() to tell how many bytes we just added.
571
572 Pages are returned (pointers into the buffer in ogg_sync_state)
573 by ogg_sync_pageout(). The page is then submitted to
574 ogg_stream_pagein() along with the appropriate
575 ogg_stream_state* (ie, matching serialno). We then get raw
576 packets out calling ogg_stream_packetout() with a
577 ogg_stream_state. */
578
579/* initialize the struct to a known state */
580int ogg_sync_init(ogg_sync_state *oy){
581 if(oy){
582 oy->storage = -1; /* used as a readiness flag */
583 memset(oy,0,sizeof(*oy));
584 }
585 return(0);
586}
587
588/* clear non-flat storage within */
589int ogg_sync_clear(ogg_sync_state *oy){
590 if(oy){
591 if(oy->data)_ogg_free(oy->data);
592 memset(oy,0,sizeof(*oy));
593 }
594 return(0);
595}
596
597int ogg_sync_destroy(ogg_sync_state *oy){
598 if(oy){
599 ogg_sync_clear(oy);
600 _ogg_free(oy);
601 }
602 return(0);
603}
604
605int ogg_sync_check(ogg_sync_state *oy){
606 if(oy->storage<0) return -1;
607 return 0;
608}
609
610char *ogg_sync_buffer(ogg_sync_state *oy, long size){
611 if(ogg_sync_check(oy)) return NULL;
612
613 /* first, clear out any space that has been previously returned */
614 if(oy->returned){
615 oy->fill-=oy->returned;
616 if(oy->fill>0)
617 memmove(oy->data,oy->data+oy->returned,oy->fill);
618 oy->returned=0;
619 }
620
621 if(size>oy->storage-oy->fill){
622 /* We need to extend the internal buffer */
623 long newsize=size+oy->fill+4096; /* an extra page to be nice */
624 void *ret;
625
626 if(oy->data)
627 ret=_ogg_realloc(oy->data,newsize);
628 else
629 ret=_ogg_malloc(newsize);
630 if(!ret){
631 ogg_sync_clear(oy);
632 return NULL;
633 }
634 oy->data=ret;
635 oy->storage=newsize;
636 }
637
638 /* expose a segment at least as large as requested at the fill mark */
639 return((char *)oy->data+oy->fill);
640}
641
642int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
643 if(ogg_sync_check(oy))return -1;
644 if(oy->fill+bytes>oy->storage)return -1;
645 oy->fill+=bytes;
646 return(0);
647}
648
649/* sync the stream. This is meant to be useful for finding page
650 boundaries.
651
652 return values for this:
653 -n) skipped n bytes
654 0) page not ready; more data (no bytes skipped)
655 n) page synced at current location; page length n bytes
656
657*/
658
659long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
660 unsigned char *page=oy->data+oy->returned;
661 unsigned char *next;
662 long bytes=oy->fill-oy->returned;
663
664 if(ogg_sync_check(oy))return 0;
665
666 if(oy->headerbytes==0){
667 int headerbytes,i;
668 if(bytes<27)return(0); /* not enough for a header */
669
670 /* verify capture pattern */
671 if(memcmp(page,"OggS",4))goto sync_fail;
672
673 headerbytes=page[26]+27;
674 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
675
676 /* count up body length in the segment table */
677
678 for(i=0;i<page[26];i++)
679 oy->bodybytes+=page[27+i];
680 oy->headerbytes=headerbytes;
681 }
682
683 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
684
685 /* The whole test page is buffered. Verify the checksum */
686 if (0) {
687 /* Grab the checksum bytes, set the header field to zero */
688 char chksum[4];
689 ogg_page log;
690
691 memcpy(chksum,page+22,4);
692 memset(page+22,0,4);
693
694 /* set up a temp page struct and recompute the checksum */
695 log.header=page;
696 log.header_len=oy->headerbytes;
697 log.body=page+oy->headerbytes;
698 log.body_len=oy->bodybytes;
699 ogg_page_checksum_set(&log);
700
701 /* Compare */
702 if(memcmp(chksum,page+22,4)){
703 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
704 at all) */
705 /* replace the computed checksum with the one actually read in */
706 memcpy(page+22,chksum,4);
707
708 /* Bad checksum. Lose sync */
709 goto sync_fail;
710 }
711 }
712
713 /* yes, have a whole page all ready to go */
714 {
715 unsigned char *page=oy->data+oy->returned;
716 long bytes;
717
718 if(og){
719 og->header=page;
720 og->header_len=oy->headerbytes;
721 og->body=page+oy->headerbytes;
722 og->body_len=oy->bodybytes;
723 }
724
725 oy->unsynced=0;
726 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
727 oy->headerbytes=0;
728 oy->bodybytes=0;
729 return(bytes);
730 }
731
732 sync_fail:
733
734 oy->headerbytes=0;
735 oy->bodybytes=0;
736
737 /* search for possible capture */
738 next=memchr(page+1,'O',bytes-1);
739 if(!next)
740 next=oy->data+oy->fill;
741
742 oy->returned=(int)(next-oy->data);
743 return((long)-(next-page));
744}
745
746/* sync the stream and get a page. Keep trying until we find a page.
747 Suppress 'sync errors' after reporting the first.
748
749 return values:
750 -1) recapture (hole in data)
751 0) need more data
752 1) page returned
753
754 Returns pointers into buffered data; invalidated by next call to
755 _stream, _clear, _init, or _buffer */
756
757int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
758
759 if(ogg_sync_check(oy))return 0;
760
761 /* all we need to do is verify a page at the head of the stream
762 buffer. If it doesn't verify, we look for the next potential
763 frame */
764
765 for(;;){
766 long ret=ogg_sync_pageseek(oy,og);
767 if(ret>0){
768 /* have a page */
769 return(1);
770 }
771 if(ret==0){
772 /* need more data */
773 return(0);
774 }
775
776 /* head did not start a synced page... skipped some bytes */
777 if(!oy->unsynced){
778 oy->unsynced=1;
779 return(-1);
780 }
781
782 /* loop. keep looking */
783 }
784}
785
786/* add the incoming page to the stream state; we decompose the page
787 into packet segments here as well. */
788
789int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
790 unsigned char *header=og->header;
791 unsigned char *body=og->body;
792 long bodysize=og->body_len;
793 int segptr=0;
794
795 int version=ogg_page_version(og);
796 int continued=ogg_page_continued(og);
797 int bos=ogg_page_bos(og);
798 int eos=ogg_page_eos(og);
799 ogg_int64_t granulepos=ogg_page_granulepos(og);
800 int serialno=ogg_page_serialno(og);
801 long pageno=ogg_page_pageno(og);
802 int segments=header[26];
803
804 if(ogg_stream_check(os)) return -1;
805
806 /* clean up 'returned data' */
807 {
808 long lr=os->lacing_returned;
809 long br=os->body_returned;
810
811 /* body data */
812 if(br){
813 os->body_fill-=br;
814 if(os->body_fill)
815 memmove(os->body_data,os->body_data+br,os->body_fill);
816 os->body_returned=0;
817 }
818
819 if(lr){
820 /* segment table */
821 if(os->lacing_fill-lr){
822 memmove(os->lacing_vals,os->lacing_vals+lr,
823 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
824 memmove(os->granule_vals,os->granule_vals+lr,
825 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
826 }
827 os->lacing_fill-=lr;
828 os->lacing_packet-=lr;
829 os->lacing_returned=0;
830 }
831 }
832
833 /* check the serial number */
834 if(serialno!=os->serialno)return(-1);
835 if(version>0)return(-1);
836
837 if(_os_lacing_expand(os,segments+1)) return -1;
838
839 /* are we in sequence? */
840 if(pageno!=os->pageno){
841 int i;
842
843 /* unroll previous partial packet (if any) */
844 for(i=os->lacing_packet;i<os->lacing_fill;i++)
845 os->body_fill-=os->lacing_vals[i]&0xff;
846 os->lacing_fill=os->lacing_packet;
847
848 /* make a note of dropped data in segment table */
849 if(os->pageno!=-1){
850 os->lacing_vals[os->lacing_fill++]=0x400;
851 os->lacing_packet++;
852 }
853 }
854
855 /* are we a 'continued packet' page? If so, we may need to skip
856 some segments */
857 if(continued){
858 if(os->lacing_fill<1 ||
859 os->lacing_vals[os->lacing_fill-1]==0x400){
860 bos=0;
861 for(;segptr<segments;segptr++){
862 int val=header[27+segptr];
863 body+=val;
864 bodysize-=val;
865 if(val<255){
866 segptr++;
867 break;
868 }
869 }
870 }
871 }
872
873 if(bodysize){
874 if(_os_body_expand(os,bodysize)) return -1;
875 memcpy(os->body_data+os->body_fill,body,bodysize);
876 os->body_fill+=bodysize;
877 }
878
879 {
880 int saved=-1;
881 while(segptr<segments){
882 int val=header[27+segptr];
883 os->lacing_vals[os->lacing_fill]=val;
884 os->granule_vals[os->lacing_fill]=-1;
885
886 if(bos){
887 os->lacing_vals[os->lacing_fill]|=0x100;
888 bos=0;
889 }
890
891 if(val<255)saved=os->lacing_fill;
892
893 os->lacing_fill++;
894 segptr++;
895
896 if(val<255)os->lacing_packet=os->lacing_fill;
897 }
898
899 /* set the granulepos on the last granuleval of the last full packet */
900 if(saved!=-1){
901 os->granule_vals[saved]=granulepos;
902 }
903
904 }
905
906 if(eos){
907 os->e_o_s=1;
908 if(os->lacing_fill>0)
909 os->lacing_vals[os->lacing_fill-1]|=0x200;
910 }
911
912 os->pageno=pageno+1;
913
914 return(0);
915}
916
917/* clear things to an initial state. Good to call, eg, before seeking */
918int ogg_sync_reset(ogg_sync_state *oy){
919 if(ogg_sync_check(oy))return -1;
920
921 oy->fill=0;
922 oy->returned=0;
923 oy->unsynced=0;
924 oy->headerbytes=0;
925 oy->bodybytes=0;
926 return(0);
927}
928
929int ogg_stream_reset(ogg_stream_state *os){
930 if(ogg_stream_check(os)) return -1;
931
932 os->body_fill=0;
933 os->body_returned=0;
934
935 os->lacing_fill=0;
936 os->lacing_packet=0;
937 os->lacing_returned=0;
938
939 os->header_fill=0;
940
941 os->e_o_s=0;
942 os->b_o_s=0;
943 os->pageno=-1;
944 os->packetno=0;
945 os->granulepos=0;
946
947 return(0);
948}
949
950int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
951 if(ogg_stream_check(os)) return -1;
952 ogg_stream_reset(os);
953 os->serialno=serialno;
954 return(0);
955}
956
957static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
958
959 /* The last part of decode. We have the stream broken into packet
960 segments. Now we need to group them into packets (or return the
961 out of sync markers) */
962
963 int ptr=os->lacing_returned;
964
965 if(os->lacing_packet<=ptr)return(0);
966
967 if(os->lacing_vals[ptr]&0x400){
968 /* we need to tell the codec there's a gap; it might need to
969 handle previous packet dependencies. */
970 os->lacing_returned++;
971 os->packetno++;
972 return(-1);
973 }
974
975 if(!op && !adv)return(1); /* just using peek as an inexpensive way
976 to ask if there's a whole packet
977 waiting */
978
979 /* Gather the whole packet. We'll have no holes or a partial packet */
980 {
981 int size=os->lacing_vals[ptr]&0xff;
982 long bytes=size;
983 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
984 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
985
986 while(size==255){
987 int val=os->lacing_vals[++ptr];
988 size=val&0xff;
989 if(val&0x200)eos=0x200;
990 bytes+=size;
991 }
992
993 if(op){
994 op->e_o_s=eos;
995 op->b_o_s=bos;
996 op->packet=os->body_data+os->body_returned;
997 op->packetno=os->packetno;
998 op->granulepos=os->granule_vals[ptr];
999 op->bytes=bytes;
1000 }
1001
1002 if(adv){
1003 os->body_returned+=bytes;
1004 os->lacing_returned=ptr+1;
1005 os->packetno++;
1006 }
1007 }
1008 return(1);
1009}
1010
1011int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
1012 if(ogg_stream_check(os)) return 0;
1013 return _packetout(os,op,1);
1014}
1015
1016int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
1017 if(ogg_stream_check(os)) return 0;
1018 return _packetout(os,op,0);
1019}
1020
1021void ogg_packet_clear(ogg_packet *op) {
1022 _ogg_free(op->packet);
1023 memset(op, 0, sizeof(*op));
1024}
1025