⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 framing.c

📁 这是一个和OGGPLAY的播放程序的附代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/********************************************************************
 *                                                                  *
 * 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->data)_ogg_free(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(ob->data,bytes);
      ob->size=bytes;
    }
  }else{
    /* allocate a new buffer */
    ob=_ogg_malloc(sizeof(*ob));
    ob->data=_ogg_malloc(bytes<16?16: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));
  }

  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);
    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;
    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;
    b->end=b->ref->length;
    b->ptr=b->ref->buffer->data+b->ref->begin;  
    return 0;
  }else
    return -1;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -