int ogg_page_packets(const ogg_page *og){ int i,n=og->header[26],count=0; for(i=0;i<n;i++) if(og->header[27+i]<255)count++; return(count);
}
#if0 /* helper to initialize lookup for direct-table CRC (illustrative; we
use the static init in crctable.h) */
staticvoid _ogg_crc_init(){ int i, j;
ogg_uint32_t polynomial, crc;
polynomial = 0x04c11db7; /* The same as the ethernet generator polynomial,althoughweusean unreflectedalgandaninit/final
of 0, not 0xffffffff */ for (i = 0; i <= 0xFF; i++){
crc = i << 24;
/* async/delayed error detection for the ogg_stream_state */ int ogg_stream_check(ogg_stream_state *os){ if(!os || !os->body_data) return -1; return0;
}
/* _clear does not free os, only the non-flat storage within */ int ogg_stream_clear(ogg_stream_state *os){ if(os){ if(os->body_data)_ogg_free(os->body_data); if(os->lacing_vals)_ogg_free(os->lacing_vals); if(os->granule_vals)_ogg_free(os->granule_vals);
memset(os,0,sizeof(*os));
} return(0);
}
int ogg_stream_destroy(ogg_stream_state *os){ if(os){
ogg_stream_clear(os);
_ogg_free(os);
} return(0);
}
/* Helpers for ogg_stream_encode; this keeps the structure and
what's happening fairly clear */
/* checksum the page */ /* Direct table CRC; note that this will be faster in the future if we
perform the checksum simultaneously with other copies */
static ogg_uint32_t _os_update_crc(ogg_uint32_t crc, unsignedchar *buffer, int size){ while (size>=8){
crc^=((ogg_uint32_t)buffer[0]<<24)|((ogg_uint32_t)buffer[1]<<16)|((ogg_uint32_t)buffer[2]<<8)|((ogg_uint32_t)buffer[3]);
/* submit data to the internal buffer of the framing engine */ int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count, long e_o_s, ogg_int64_t granulepos){
/* make sure we have the buffer storage */ if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals)) return -1;
/* Copy in the submitted packet. Yes, the copy is a waste; this is theliabilityofoverlycleanabstractionforthetimebeing.It willactuallybefairlyeasytoeliminatetheextracopyinthe
future */
for (i = 0; i < count; ++i) {
memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
os->body_fill += (int)iov[i].iov_len;
}
/* Store lacing vals for this packet */ for(i=0;i<lacing_vals-1;i++){
os->lacing_vals[os->lacing_fill+i]=255;
os->granule_vals[os->lacing_fill+i]=os->granulepos;
}
os->lacing_vals[os->lacing_fill+i]=bytes%255;
os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
/* flag the first segment as the beginning of the packet */
os->lacing_vals[os->lacing_fill]|= 0x100;
os->lacing_fill+=lacing_vals;
/* for the sake of completeness */
os->packetno++;
/* Conditionally flush a page; force==0 will only flush nominal-size pages,force==1forcesustoflushapageregardlessofpagesize
so long as there's any data available at all. */ staticint ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){ int i; int vals=0; int maxvals; int bytes=0; long acc=0;
ogg_int64_t granule_pos=-1;
/* construct a page */ /* decide how many segments to include */
/* If this is the initial header case, the first page must only include
the initial header packet */ if(os->b_o_s==0){ /* 'initial header page' case */
granule_pos=0; for(vals=0;vals<maxvals;vals++){ if((os->lacing_vals[vals]&0x0ff)<255){
vals++; break;
}
}
}else{
/* The extra packets_done, packet_just_done logic here attempts to do two things: 1)Don'tunnecessarilyspanpages. 2)Unlessnecessary,don'tflushpagesiftherearelessthanfourpacketson them;thisexpandspagesizetoreduceunnecessaryoverheadifincomingpackets arelarge. Thesearenotnecessarybehaviors,just'alwaysbetterthannaiveflushing' withoutrequiringanapplicationtoexplicitlyrequestaspecificoptimized
behavior. We'll want an explicit behavior setup pathway eventually as well. */
int packets_done=0; int packet_just_done=0; for(vals=0;vals<maxvals;vals++){ if(acc>nfill && packet_just_done>=4){
force=1; break;
}
acc+=os->lacing_vals[vals]&0x0ff; if((os->lacing_vals[vals]&0xff)<255){
granule_pos=os->granule_vals[vals];
packet_just_done=++packets_done;
}else
packet_just_done=0;
} if(vals==255)force=1;
}
if(!force) return(0);
/* construct the header in temp storage */
memcpy(os->header,"OggS",4);
/* stream structure version */
os->header[4]=0x00;
/* continued packet flag? */
os->header[5]=0x00; if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; /* first page flag? */ if(os->b_o_s==0)os->header[5]|=0x02; /* last page flag? */ if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
os->b_o_s=1;
/* 64 bits of PCM position */ for(i=6;i<14;i++){
os->header[i]=(unsignedchar)(granule_pos&0xff);
granule_pos>>=8;
}
/* 32 bits of stream serial number */
{ long serialno=os->serialno; for(i=14;i<18;i++){
os->header[i]=(unsignedchar)(serialno&0xff);
serialno>>=8;
}
}
/* 32 bits of page counter (we have both counter and page header
because this val can roll over) */ if(os->pageno==-1)os->pageno=0; /* because someone called stream_reset;thiswouldbea strangethingtodoinan encodestream,butithas
plausible uses */
{ long pageno=os->pageno++; for(i=18;i<22;i++){
os->header[i]=(unsignedchar)(pageno&0xff);
pageno>>=8;
}
}
/* zero for computation; filled in later */
os->header[22]=0;
os->header[23]=0;
os->header[24]=0;
os->header[25]=0;
/* set pointers in the ogg_page struct */
og->header=os->header;
og->header_len=os->header_fill=vals+27;
og->body=os->body_data+os->body_returned;
og->body_len=bytes;
/* advance the lacing data and set the body_returned pointer */
/* This will flush remaining packets into a page (returning nonzero), evenifthereisnotenoughdatatotriggeraflushnormally (undersizedpage).Iftherearenopacketsorpartialpacketsto flush,ogg_stream_flushreturns0.Notethatogg_stream_flushwill trytoflushanormalsizedpagelikeogg_stream_pageout;acallto ogg_stream_flushdoesnotguaranteethatallpacketshaveflushed. Onlyareturnvalueof0fromogg_stream_flushindicatesallpacket dataisflushedintopages.
sinceogg_stream_flushwillflushthelastpageinastreamevenif it'sundersized,youalmostcertainlywanttouseogg_stream_pageout (and*not*ogg_stream_flush)unlessyouspecificallyneedtoflush
a page regardless of size in the middle of a stream. */
int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ return ogg_stream_flush_i(os,og,1,4096);
}
/* Like the above, but an argument is provided to adjust the nominal pagesizeforapplicationswhicharesmartenoughtoprovidetheir
own delay based flushing */
int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){ return ogg_stream_flush_i(os,og,1,nfill);
}
/* This constructs pages from buffered packet segments. The pointers returnedaretostaticbuffers;donotfree.Thereturnedbuffersare
good only until the next call (using the same ogg_stream_state) */
int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ int force=0; if(ogg_stream_check(os)) return0;
if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
(os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
force=1;
return(ogg_stream_flush_i(os,og,force,4096));
}
/* Like the above, but an argument is provided to adjust the nominal pagesizeforapplicationswhicharesmartenoughtoprovidetheir
own delay based flushing */
int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){ int force=0; if(ogg_stream_check(os)) return0;
if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
(os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
force=1;
return(ogg_stream_flush_i(os,og,force,nfill));
}
int ogg_stream_eos(ogg_stream_state *os){ if(ogg_stream_check(os)) return1; return os->e_o_s;
}
/* This has two layers to place more of the multi-serialno and paging controlintheapplication'shands.First,weexposeadatabuffer usingogg_sync_buffer().Theappeithercopiesintothe buffer,orpassesitdirectlytoread(),etc.Wethencall ogg_sync_wrote()totellhowmanybyteswejustadded.
/* initialize the struct to a known state */ int ogg_sync_init(ogg_sync_state *oy){ if(oy){
oy->storage = -1; /* used as a readiness flag */
memset(oy,0,sizeof(*oy));
} return(0);
}
/* clear non-flat storage within */ int ogg_sync_clear(ogg_sync_state *oy){ if(oy){ if(oy->data)_ogg_free(oy->data);
memset(oy,0,sizeof(*oy));
} return(0);
}
int ogg_sync_destroy(ogg_sync_state *oy){ if(oy){
ogg_sync_clear(oy);
_ogg_free(oy);
} return(0);
}
int ogg_sync_check(ogg_sync_state *oy){ if(oy->storage<0) return -1; return0;
}
char *ogg_sync_buffer(ogg_sync_state *oy, long size){ if(ogg_sync_check(oy)) return NULL;
/* first, clear out any space that has been previously returned */ if(oy->returned){
oy->fill-=oy->returned; if(oy->fill>0)
memmove(oy->data,oy->data+oy->returned,oy->fill);
oy->returned=0;
}
if(size>oy->storage-oy->fill){ /* We need to extend the internal buffer */ long newsize; void *ret;
if(size>INT_MAX-4096-oy->fill){
ogg_sync_clear(oy); return NULL;
}
newsize=size+oy->fill+4096; /* an extra page to be nice */ if(oy->data)
ret=_ogg_realloc(oy->data,newsize); else
ret=_ogg_malloc(newsize); if(!ret){
ogg_sync_clear(oy); return NULL;
}
oy->data=ret;
oy->storage=newsize;
}
/* expose a segment at least as large as requested at the fill mark */ return((char *)oy->data+oy->fill);
}
int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ if(ogg_sync_check(oy))return -1; if(oy->fill+bytes>oy->storage)return -1;
oy->fill+=bytes; return(0);
}
/* sync the stream. This is meant to be useful for finding page boundaries.
/* The whole test page is buffered. Verify the checksum */
{ /* Grab the checksum bytes, set the header field to zero */ char chksum[4];
ogg_page log;
memcpy(chksum,page+22,4);
memset(page+22,0,4);
/* set up a temp page struct and recompute the checksum */
log.header=page;
log.header_len=oy->headerbytes;
log.body=page+oy->headerbytes;
log.body_len=oy->bodybytes;
ogg_page_checksum_set(&log);
/* Compare */ if(memcmp(chksum,page+22,4)){ /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
at all) */ /* replace the computed checksum with the one actually read in */
memcpy(page+22,chksum,4);
/* yes, have a whole page all ready to go */
{ if(og){
og->header=page;
og->header_len=oy->headerbytes;
og->body=page+oy->headerbytes;
og->body_len=oy->bodybytes;
}
Returnspointersintobuffereddata;invalidatedbynextcallto
_stream, _clear, _init, or _buffer */
int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
if(ogg_sync_check(oy))return0;
/* all we need to do is verify a page at the head of the stream buffer.Ifitdoesn'tverify,welookforthenextpotential
frame */
for(;;){ long ret=ogg_sync_pageseek(oy,og); if(ret>0){ /* have a page */ return(1);
} if(ret==0){ /* need more data */ return(0);
}
/* head did not start a synced page... skipped some bytes */ if(!oy->unsynced){
oy->unsynced=1; return(-1);
}
/* loop. keep looking */
}
}
/* add the incoming page to the stream state; we decompose the page
into packet segments here as well. */
int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ unsignedchar *header=og->header; unsignedchar *body=og->body; long bodysize=og->body_len; int segptr=0;
int version=ogg_page_version(og); int continued=ogg_page_continued(og); int bos=ogg_page_bos(og); int eos=ogg_page_eos(og);
ogg_int64_t granulepos=ogg_page_granulepos(og); int serialno=ogg_page_serialno(og); long pageno=ogg_page_pageno(og); int segments=header[26];
if(ogg_stream_check(os)) return -1;
/* clean up 'returned data' */
{ long lr=os->lacing_returned; long br=os->body_returned;
/* body data */ if(br){
os->body_fill-=br; if(os->body_fill)
memmove(os->body_data,os->body_data+br,os->body_fill);
os->body_returned=0;
}
/* make a note of dropped data in segment table */ if(os->pageno!=-1){
os->lacing_vals[os->lacing_fill++]=0x400;
os->lacing_packet++;
}
}
/* are we a 'continued packet' page? If so, we may need to skip
some segments */ if(continued){ if(os->lacing_fill<1 ||
(os->lacing_vals[os->lacing_fill-1]&0xff)<255 ||
os->lacing_vals[os->lacing_fill-1]==0x400){
bos=0; for(;segptr<segments;segptr++){ int val=header[27+segptr];
body+=val;
bodysize-=val; if(val<255){
segptr++; break;
}
}
}
}
/* The last part of decode. We have the stream broken into packet segments.Nowweneedtogroupthemintopackets(orreturnthe
out of sync markers) */
int ptr=os->lacing_returned;
if(os->lacing_packet<=ptr)return(0);
if(os->lacing_vals[ptr]&0x400){ /* we need to tell the codec there's a gap; it might need to
handle previous packet dependencies. */
os->lacing_returned++;
os->packetno++; return(-1);
}
if(!op && !adv)return(1); /* just using peek as an inexpensive way toaskifthere'sawholepacket
waiting */
/* Gather the whole packet. We'll have no holes or a partial packet */
{ int size=os->lacing_vals[ptr]&0xff; long bytes=size; int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
while(size==255){ int val=os->lacing_vals[++ptr];
size=val&0xff; if(val&0x200)eos=0x200;
bytes+=size;
}
/* packet number just follows sequence/gap; adjust the input number
for that */ if(no==0){
sequence=0;
}else{
sequence++; if(no>lastno+1)
sequence++;
}
lastno=no; if(op->packetno!=sequence){
fprintf(stderr,"incorrect packet sequence %ld != %d\n",
(long)(op->packetno),sequence); exit(1);
}
/* Test data */ for(j=0;j<op->bytes;j++) if(op->packet[j]!=((j+no)&0xff)){
fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
j,op->packet[j],(j+no)&0xff); exit(1);
}
}
void check_page(unsignedchar *data,constint *header,ogg_page *og){ long j; /* Test data */ for(j=0;j<og->body_len;j++) if(og->body[j]!=data[j]){
fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
j,data[j],og->body[j]); exit(1);
}
void test_pack(constint *pl, constint **headers, int byteskip, int pageskip, int packetskip){ unsignedchar *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ long inptr=0; long outptr=0; long deptr=0; long depacket=0; long granule_pos=7,pageno=0; int i,j,packets,pageout=pageskip; int eosflag=0; int bosflag=0;
int byteskipcount=0;
if (!data) {
fprintf(stderr,"unable to allocate requried data buffer!\n"); exit(1);
}
/* submit it to deconstitution */
ogg_stream_pagein(&os_de,&og_de);
/* packets out? */ while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
ogg_stream_packetpeek(&os_de,NULL);
ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
/* verify peek and out match */ if(compare_packet(&op_de,&op_de2)){
fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
depacket); exit(1);
}
/* verify the packet! */ /* check data */ if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
depacket); exit(1);
} /* check bos flag */ if(bosflag==0 && op_de.b_o_s==0){
fprintf(stderr,"b_o_s flag not set on packet!\n"); exit(1);
} if(bosflag && op_de.b_o_s){
fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); exit(1);
}
bosflag=1;
depacket+=op_de.bytes;
/* check eos flag */ if(eosflag){
fprintf(stderr,"Multiple decoded packets with eos flag!\n"); exit(1);
}
if(op_de.e_o_s)eosflag=1;
/* check granulepos flag */ if(op_de.granulepos!=-1){
fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
}
}
}
}
}
}
}
_ogg_free(data); if(headers[pageno]!=NULL){
fprintf(stderr,"did not write last page!\n"); exit(1);
} if(headers[pageout]!=NULL){
fprintf(stderr,"did not decode last page!\n"); exit(1);
} if(inptr!=outptr){
fprintf(stderr,"encoded page data incomplete!\n"); exit(1);
} if(inptr!=deptr){
fprintf(stderr,"decoded page data incomplete!\n"); exit(1);
} if(inptr!=depacket){
fprintf(stderr,"decoded packet data incomplete!\n"); exit(1);
} if(!eosflag){
fprintf(stderr,"Never got a packet with EOS set!\n"); exit(1);
}
fprintf(stderr,"ok.\n");
}
{ /* continuing packet test; with page spill expansion, we have to
overflow the lacing table. */ constint packets[]={0,65500,259,255,-1}; constint *headret[]={head1_4,head2_4,head3_4,NULL};
fprintf(stderr,"testing single packet page span... ");
test_pack(packets,headret,0,0,0);
}
fprintf(stderr,"testing max packet segments... ");
test_pack(packets,headret,0,0,0);
}
{ /* packet that overspans over an entire page */ constint packets[]={0,100,130049,259,255,-1}; constint *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
fprintf(stderr,"testing very large packets... ");
test_pack(packets,headret,0,0,0);
}
#ifndef DISABLE_CRC
{ /* test for the libogg 1.1.1 resync in large continuation bug
found by Josh Coalson) */ constint packets[]={0,100,130049,259,255,-1}; constint *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
fprintf(stderr,"testing continuation resync in very large packets... ");
test_pack(packets,headret,100,2,3);
} #else
fprintf(stderr,"Skipping continuation resync test due to --disable-crc\n"); #endif
{ /* term only page. why not? */ constint packets[]={0,100,64770,-1}; constint *headret[]={head1_7,head2_7,head3_7,NULL};
fprintf(stderr,"testing zero data page (1 nil packet)... ");
test_pack(packets,headret,0,0,0);
}
{ /* build a bunch of pages for testing */ unsignedchar *data=_ogg_malloc(1024*1024); int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1}; int inptr=0,i,j;
ogg_page og[5];
if (!data) {
fprintf(stderr,"unable to allocate requried packet data buffer!\n"); exit(1);
}
ogg_stream_reset(&os_en);
for(i=0;pl[i]!=-1;i++){
ogg_packet op; int len=pl[i];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.