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

📄 vorbisfile.c

📁 betaplayer_0.096源码 tcpmp老版本
💻 C
📖 第 1 页 / 共 4 页
字号:
/******************************************************************** *                                                                  * * 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: stdio-based convenience library for opening/seeking/decoding last mod: $Id: vorbisfile.c,v 1.6 2003/03/30 23:40:56 xiphmont Exp $ ********************************************************************/#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include <math.h>#include "ivorbiscodec.h"#include "ivorbisfile.h"#include "os.h"#include "misc.h"/* A 'chained bitstream' is a Vorbis bitstream that contains more than   one logical bitstream arranged end to end (the only form of Ogg   multiplexing allowed in a Vorbis bitstream; grouping [parallel   multiplexing] is not allowed in Vorbis) *//* A Vorbis file can be played beginning to end (streamed) without   worrying ahead of time about chaining (see decoder_example.c).  If   we have the whole file, however, and want random access   (seeking/scrubbing) or desire to know the total length/time of a   file, we need to account for the possibility of chaining. *//* We can handle things a number of ways; we can determine the entire   bitstream structure right off the bat, or find pieces on demand.   This example determines and caches structure for the entire   bitstream, but builds a virtual decoder on the fly when moving   between links in the chain. *//* There are also different ways to implement seeking.  Enough   information exists in an Ogg bitstream to seek to   sample-granularity positions in the output.  Or, one can seek by   picking some portion of the stream roughly in the desired area if   we only want coarse navigation through the stream. *//************************************************************************* * Many, many internal helpers.  The intention is not to be confusing;  * rampant duplication and monolithic function implementation would be  * harder to understand anyway.  The high level functions are last.  Begin * grokking near the end of the file *//* read a little more data from the file/pipe into the ogg_sync framer */static long _get_data(OggVorbis_File *vf){  errno=0;  if(vf->datasource){    char *buffer=ogg_sync_bufferin(vf->oy,CHUNKSIZE);    long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);    if(bytes>0)ogg_sync_wrote(vf->oy,bytes);    if(bytes==0 && errno)return(-1);    return(bytes);  }else    return(0);}/* save a tiny smidge of verbosity to make the code more readable */static void _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){  if(vf->datasource){     (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);    vf->offset=offset;    ogg_sync_reset(vf->oy);  }else{    /* shouldn't happen unless someone writes a broken callback */    return;  }}/* The read/seek functions track absolute position within the stream *//* from the head of the stream, get the next page.  boundary specifies   if the function is allowed to fetch more data from the stream (and   how much) or only use internally buffered data.   boundary: -1) unbounded search              0) read no additional data; use cached only	      n) search for a new page beginning for n bytes   return:   <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)              n) found a page at absolute offset n               produces a refcounted page */static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,				  ogg_int64_t boundary){  if(boundary>0)boundary+=vf->offset;  while(1){    long more;    if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);    more=ogg_sync_pageseek(vf->oy,og);        if(more<0){      /* skipped n bytes */      vf->offset-=more;    }else{      if(more==0){	/* send more paramedics */	if(!boundary)return(OV_FALSE);	{	  long ret=_get_data(vf);	  if(ret==0)return(OV_EOF);	  if(ret<0)return(OV_EREAD);	}      }else{	/* got a page.  Return the offset at the page beginning,           advance the internal offset past the page end */	ogg_int64_t ret=vf->offset;	vf->offset+=more;	return(ret);	      }    }  }}/* find the latest page beginning before the current stream cursor   position. Much dirtier than the above as Ogg doesn't have any   backward search linkage.  no 'readp' as it will certainly have to   read. *//* returns offset or OV_EREAD, OV_FAULT and produces a refcounted page */static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){  ogg_int64_t begin=vf->offset;  ogg_int64_t end=begin;  ogg_int64_t ret;  ogg_int64_t offset=-1;  while(offset==-1){    begin-=CHUNKSIZE;    if(begin<0)      begin=0;    _seek_helper(vf,begin);    while(vf->offset<end){      ret=_get_next_page(vf,og,end-vf->offset);      if(ret==OV_EREAD)return(OV_EREAD);      if(ret<0){	break;      }else{	offset=ret;      }    }  }  /* we have the offset.  Actually snork and hold the page now */  _seek_helper(vf,offset);  ret=_get_next_page(vf,og,CHUNKSIZE);  if(ret<0)    /* this shouldn't be possible */    return(OV_EFAULT);  return(offset);}/* finds each bitstream link one at a time using a bisection search   (has to begin by knowing the offset of the lb's initial page).   Recurses for each link so it can alloc the link storage after   finding them all, then unroll and fill the cache at the same time */static int _bisect_forward_serialno(OggVorbis_File *vf,				    ogg_int64_t begin,				    ogg_int64_t searched,				    ogg_int64_t end,				    ogg_uint32_t currentno,				    long m){  ogg_int64_t endsearched=end;  ogg_int64_t next=end;  ogg_page og={0,0,0,0};  ogg_int64_t ret;    /* the below guards against garbage seperating the last and     first pages of two links. */  while(searched<endsearched){    ogg_int64_t bisect;        if(endsearched-searched<CHUNKSIZE){      bisect=searched;    }else{      bisect=(searched+endsearched)/2;    }        _seek_helper(vf,bisect);    ret=_get_next_page(vf,&og,-1);    if(ret==OV_EREAD)return(OV_EREAD);    if(ret<0 || ogg_page_serialno(&og)!=currentno){      endsearched=bisect;      if(ret>=0)next=ret;    }else{      searched=ret+og.header_len+og.body_len;    }    ogg_page_release(&og);  }  _seek_helper(vf,next);  ret=_get_next_page(vf,&og,-1);  if(ret==OV_EREAD)return(OV_EREAD);    if(searched>=end || ret<0){    ogg_page_release(&og);    vf->links=m+1;    vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));    vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));    vf->offsets[m+1]=searched;  }else{    ret=_bisect_forward_serialno(vf,next,vf->offset,				 end,ogg_page_serialno(&og),m+1);    ogg_page_release(&og);    if(ret==OV_EREAD)return(OV_EREAD);  }    vf->offsets[m]=begin;  vf->serialnos[m]=currentno;  return(0);}/* uses the local ogg_stream storage in vf; this is important for   non-streaming input sources *//* consumes the page that's passed in (if any) */static int _fetch_headers(OggVorbis_File *vf,			  vorbis_info *vi,			  vorbis_comment *vc,			  ogg_uint32_t *serialno,			  ogg_page *og_ptr){  ogg_page og={0,0,0,0};  ogg_packet op={0,0,0,0,0,0};  int i,ret;    if(!og_ptr){    ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);    if(llret==OV_EREAD)return(OV_EREAD);    if(llret<0)return OV_ENOTVORBIS;    og_ptr=&og;  }  ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr));  if(serialno)*serialno=vf->os->serialno;  vf->ready_state=STREAMSET;    /* extract the initial header from the first page and verify that the     Ogg bitstream is in fact Vorbis data */    vorbis_info_init(vi);  vorbis_comment_init(vc);    i=0;  while(i<3){    ogg_stream_pagein(vf->os,og_ptr);    while(i<3){      int result=ogg_stream_packetout(vf->os,&op);      if(result==0)break;      if(result==-1){	ret=OV_EBADHEADER;	goto bail_header;      }      if((ret=vorbis_synthesis_headerin(vi,vc,&op))){	goto bail_header;      }      i++;    }    if(i<3)      if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){	ret=OV_EBADHEADER;	goto bail_header;      }  }  ogg_packet_release(&op);  ogg_page_release(&og);  return 0;  bail_header:  ogg_packet_release(&op);  ogg_page_release(&og);  vorbis_info_clear(vi);  vorbis_comment_clear(vc);  vf->ready_state=OPENED;  return ret;}/* last step of the OggVorbis_File initialization; get all the   vorbis_info structs and PCM positions.  Only called by the seekable   initialization (local stream storage is hacked slightly; pay   attention to how that's done) *//* this is void and does not propogate errors up because we want to be   able to open and use damaged bitstreams as well as we can.  Just   watch out for missing information for links in the OggVorbis_File   struct */static void _prefetch_all_headers(OggVorbis_File *vf, ogg_int64_t dataoffset){  ogg_page og={0,0,0,0};  int i;  ogg_int64_t ret;    vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));  vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));  vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));  vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));    for(i=0;i<vf->links;i++){    if(i==0){      /* we already grabbed the initial header earlier.  Just set the offset */      vf->dataoffsets[i]=dataoffset;      _seek_helper(vf,dataoffset);    }else{      /* seek to the location of the initial header */      _seek_helper(vf,vf->offsets[i]);      if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)<0){    	vf->dataoffsets[i]=-1;      }else{	vf->dataoffsets[i]=vf->offset;      }    }    /* fetch beginning PCM offset */    if(vf->dataoffsets[i]!=-1){      ogg_int64_t accumulated=0,pos;      long        lastblock=-1;      int         result;      ogg_stream_reset_serialno(vf->os,vf->serialnos[i]);      while(1){	ogg_packet op={0,0,0,0,0,0};	ret=_get_next_page(vf,&og,-1);	if(ret<0)	  /* this should not be possible unless the file is             truncated/mangled */	  break;       	if(ogg_page_serialno(&og)!=vf->serialnos[i])	  break;		pos=ogg_page_granulepos(&og);	/* count blocksizes of all frames in the page */	ogg_stream_pagein(vf->os,&og);	while((result=ogg_stream_packetout(vf->os,&op))){	  if(result>0){ /* ignore holes */	    long thisblock=vorbis_packet_blocksize(vf->vi+i,&op);	    if(lastblock!=-1)	      accumulated+=(lastblock+thisblock)>>2;	    lastblock=thisblock;	  }	}	ogg_packet_release(&op);	if(pos!=-1){	  /* pcm offset of last packet on the first audio page */	  accumulated= pos-accumulated;	  break;	}      }      /* less than zero?  This is a stream with samples trimmed off         the beginning, a normal occurrence; set the offset to zero */      if(accumulated<0)accumulated=0;      vf->pcmlengths[i*2]=accumulated;    }    /* get the PCM length of this link. To do this,       get the last page of the stream */    {      ogg_int64_t end=vf->offsets[i+1];      _seek_helper(vf,end);      while(1){	ret=_get_prev_page(vf,&og);	if(ret<0){	  /* this should not be possible */	  vorbis_info_clear(vf->vi+i);	  vorbis_comment_clear(vf->vc+i);	  break;	}	if(ogg_page_granulepos(&og)!=-1){	  vf->pcmlengths[i*2+1]=ogg_page_granulepos(&og)-vf->pcmlengths[i*2];

⌨️ 快捷键说明

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