📄 framing.c
字号:
/******************************************************************** * * * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** function: decode Ogg streams back into raw packets note: The CRC code is directly derived from public domain code by Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html for details. ********************************************************************/#include <stdlib.h>#include <string.h>#include "ogg.h"#include "misc.h"/* A complete description of Ogg framing exists in docs/framing.html *//* basic, centralized Ogg memory management based on linked lists of references to refcounted memory buffers. References and buffers are both recycled. Buffers are passed around and consumed in reference form. */static ogg_buffer_state *ogg_buffer_create(void){ ogg_buffer_state *bs=_ogg_calloc(1,sizeof(*bs)); return bs;}/* destruction is 'lazy'; there may be memory references outstanding, and yanking the buffer state out from underneath would be antisocial. Dealloc what is currently unused and have _release_one watch for the stragglers to come in. When they do, finish destruction. *//* call the helper while holding lock */static void _ogg_buffer_destroy(ogg_buffer_state *bs){ ogg_buffer *bt; ogg_reference *rt; if(bs->shutdown){ bt=bs->unused_buffers; rt=bs->unused_references; while(bt){ ogg_buffer *b=bt; bt=b->ptr.next;
if(b->ext)oggext_release(b->ext,b->extdata);
else if(b->data)_ogg_free((void*)b->data); _ogg_free(b); } bs->unused_buffers=0; while(rt){ ogg_reference *r=rt; rt=r->next; _ogg_free(r); } bs->unused_references=0;
if(!bs->outstanding){
_ogg_free(bs);
return;
}
}}static void ogg_buffer_destroy(ogg_buffer_state *bs){ bs->shutdown=1; _ogg_buffer_destroy(bs);}static ogg_buffer *_fetch_buffer(ogg_buffer_state *bs,long bytes){ ogg_buffer *ob; bs->outstanding++; /* do we have an unused buffer sitting in the pool? */ if(bs->unused_buffers){ ob=bs->unused_buffers; bs->unused_buffers=ob->ptr.next; /* if the unused buffer is too small, grow it */ if(ob->size<bytes){ ob->data=_ogg_realloc((void*)ob->data,bytes); ob->size=bytes; }
if (bytes<0){
if (ob->data) _ogg_free((void*)ob->data);
ob->data=NULL;
ob->size=0;
}
}else{ /* allocate a new buffer */ ob=_ogg_malloc(sizeof(*ob));
ob->ext = NULL;
ob->extdata = NULL;
if (bytes>=0){ ob->data=_ogg_malloc(bytes<16?16:bytes); ob->size=bytes;
} else{
ob->data=NULL;
ob->size=0;
} } ob->refcount=1; ob->ptr.owner=bs; return ob;}static ogg_reference *_fetch_ref(ogg_buffer_state *bs){ ogg_reference *or; bs->outstanding++; /* do we have an unused reference sitting in the pool? */ if(bs->unused_references){ or=bs->unused_references; bs->unused_references=or->next; }else{ /* allocate a new reference */ or=_ogg_malloc(sizeof(*or)); } or->begin=0; or->length=0; or->next=0; return or;}/* fetch a reference pointing to a fresh, initially continguous buffer of at least [bytes] length */static ogg_reference *ogg_buffer_alloc(ogg_buffer_state *bs,long bytes){ ogg_buffer *ob=_fetch_buffer(bs,bytes); ogg_reference *or=_fetch_ref(bs); or->buffer=ob; return or;}/* enlarge the data buffer in the current link */static void ogg_buffer_realloc(ogg_reference *or,long bytes){ ogg_buffer *ob=or->buffer; /* if the unused buffer is too small, grow it */ if(ob->size<bytes){ ob->data=_ogg_realloc((void*)ob->data,bytes); ob->size=bytes; }}static void _ogg_buffer_mark_one(ogg_reference *or){ or->buffer->refcount++;}/* increase the refcount of the buffers to which the reference points */static void ogg_buffer_mark(ogg_reference *or){ while(or){ _ogg_buffer_mark_one(or); or=or->next; }}/* duplicate a reference (pointing to the same actual buffer memory) and increment buffer refcount. If the desired segment begins out of range, NULL is returned; if the desired segment is simply zero length, a zero length ref is returned. Partial range overlap returns the overlap of the ranges */static ogg_reference *ogg_buffer_sub(ogg_reference *or,long begin,long length){ ogg_reference *ret=0,*head=0; /* walk past any preceeding fragments we don't want */ while(or && begin>=or->length){ begin-=or->length; or=or->next; } /* duplicate the reference chain; increment refcounts */ while(or && length){ ogg_reference *temp=_fetch_ref(or->buffer->ptr.owner); if(head) head->next=temp; else ret=temp; head=temp; head->buffer=or->buffer; head->begin=or->begin+begin; head->length=length; if(head->length>or->length-begin) head->length=or->length-begin; begin=0; length-=head->length; or=or->next; } ogg_buffer_mark(ret); return ret;}ogg_reference *ogg_buffer_dup(ogg_reference *or){ ogg_reference *ret=0,*head=0; /* duplicate the reference chain; increment refcounts */ while(or){ ogg_reference *temp=_fetch_ref(or->buffer->ptr.owner); if(head) head->next=temp; else ret=temp; head=temp; head->buffer=or->buffer; head->begin=or->begin; head->length=or->length; or=or->next; } ogg_buffer_mark(ret); return ret;}/* split a reference into two references; 'return' is a reference to the buffer preceeding pos and 'head'/'tail' are the buffer past the split. If pos is at or past the end of the passed in segment, 'head/tail' are NULL */static ogg_reference *ogg_buffer_split(ogg_reference **tail, ogg_reference **head,long pos){ /* walk past any preceeding fragments to one of: a) the exact boundary that seps two fragments b) the fragment that needs split somewhere in the middle */ ogg_reference *ret=*tail; ogg_reference *or=*tail; while(or && pos>or->length){ pos-=or->length; or=or->next; } if(!or || pos==0){ return 0; }else{ if(pos>=or->length){ /* exact split, or off the end? */ if(or->next){ /* a split */ *tail=or->next; or->next=0; }else{ /* off or at the end */ *tail=*head=0; } }else{ /* split within a fragment */ long lengthA=pos; long beginB=or->begin+pos; long lengthB=or->length-pos; /* make a new reference to tail the second piece */ *tail=_fetch_ref(or->buffer->ptr.owner); (*tail)->buffer=or->buffer; (*tail)->begin=beginB; (*tail)->length=lengthB; (*tail)->next=or->next; _ogg_buffer_mark_one(*tail); if(head && or==*head)*head=*tail; /* update the first piece */ or->next=0; or->length=lengthA; } } return ret;}static void ogg_buffer_release_one(ogg_reference *or){ ogg_buffer *ob=or->buffer; ogg_buffer_state *bs=ob->ptr.owner; ob->refcount--; if(ob->refcount==0){
if (ob->ext) {
oggext_release(ob->ext,ob->extdata);
ob->ext = NULL;
ob->extdata = NULL;
ob->data = NULL;
ob->size = 0;
}
bs->outstanding--; /* for the returned buffer */ ob->ptr.next=bs->unused_buffers; bs->unused_buffers=ob; } bs->outstanding--; /* for the returned reference */ or->next=bs->unused_references; bs->unused_references=or; _ogg_buffer_destroy(bs); /* lazy cleanup (if needed) */}/* release the references, decrease the refcounts of buffers to which they point, release any buffers with a refcount that drops to zero */static void ogg_buffer_release(ogg_reference *or){ while(or){ ogg_reference *next=or->next; ogg_buffer_release_one(or); or=next; }}static ogg_reference *ogg_buffer_pretruncate(ogg_reference *or,long pos){ /* release preceeding fragments we don't want */ while(or && pos>=or->length){ ogg_reference *next=or->next; pos-=or->length; ogg_buffer_release_one(or); or=next; } if (or) { or->begin+=pos; or->length-=pos; } return or;}static ogg_reference *ogg_buffer_walk(ogg_reference *or){ if(!or)return NULL; while(or->next){ or=or->next; } return(or);}/* *head is appended to the front end (head) of *tail; both continue to be valid pointers, with *tail at the tail and *head at the head */static ogg_reference *ogg_buffer_cat(ogg_reference *tail, ogg_reference *head){ if(!tail)return head; while(tail->next){ tail=tail->next; } tail->next=head; return ogg_buffer_walk(head);}static void _positionB(oggbyte_buffer *b,int pos){ if(pos<b->pos){ /* start at beginning, scan forward */ b->ref=b->baseref; b->pos=0; b->end=b->pos+b->ref->length; b->ptr=b->ref->buffer->data+b->ref->begin; }}static void _positionF(oggbyte_buffer *b,int pos){ /* scan forward for position */ while(pos>=b->end){ /* just seek forward */ b->pos+=b->ref->length; b->ref=b->ref->next; b->end=b->ref->length+b->pos; b->ptr=b->ref->buffer->data+b->ref->begin; }}static int oggbyte_init(oggbyte_buffer *b,ogg_reference *or){ memset(b,0,sizeof(*b)); if(or){ b->ref=b->baseref=or; b->pos=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -