📄 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 <stdio.h>#include <stdlib.h>#include <string.h>#include "ogg.h"#include "misc.h"#define dprintf(stuff) /* printf stuff *//* 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)); dprintf(("ogg_buffer_create bs %p %d bytes\n", bs, 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; if (!bs->outstanding) { dprintf(("_ogg_buffer_destroy free bs %p\n", bs)); _ogg_free(bs);// return; // commenting this line out lets the function free the rest of the allocated memory } while (bt) { ogg_buffer *b = bt; bt = b->ptr.next; if (b->data) { dprintf(("_ogg_buffer_destroy free b->data %p\n", b->data)); _ogg_free(b->data); } dprintf(("_ogg_buffer_destroy free b %p\n", b)); _ogg_free(b); } bs->unused_buffers = 0; while (rt) { ogg_reference *r = rt; rt = r->next; dprintf(("_ogg_buffer_destroy free r %p\n", r)); _ogg_free(r); } bs->unused_references = 0; }}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) { dprintf(("_fetch_buffer AAA free ob->data %p\n", ob->data)); ob->data = _ogg_realloc(ob->data, bytes); dprintf(("_fetch_buffer AAA ob->data %p %d bytes\n", ob->data, bytes)); ob->size = bytes; } } else { /* allocate a new buffer */ ob = _ogg_malloc(sizeof(*ob)); dprintf(("_fetch_buffer CCC ob %p %d bytes\n", ob, bytes)); ob->data = _ogg_malloc(bytes < 16 ? 16 : bytes); dprintf(("_fetch_buffer CCC ob->data %p %d bytes\n", ob->data, bytes)); ob->size = bytes; } 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)); dprintf(("_fetch_ref or %p %d bytes\n", or, 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(ob->data, bytes); dprintf(("ogg_buffer_realloc ob->data %p %d bytes\n", 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) { 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -