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

📄 vorbisfile.c

📁 一个播放器 使用了evc 大家可以参考下 哦
💻 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-2002    * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  * *                                                                  * ******************************************************************** function: stdio-based convenience library for opening/seeking/decoding ********************************************************************/#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_buffer(&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,long 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 */static long _get_next_page(OggVorbis_File *vf,ogg_page *og,int 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 */	long 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 */static long _get_prev_page(OggVorbis_File *vf,ogg_page *og){  long begin=vf->offset;  long ret;  int offset=-1;  while(offset==-1){    begin-=CHUNKSIZE;    if(begin<0)      begin=0;    _seek_helper(vf,begin);    while(vf->offset<begin+CHUNKSIZE){      ret=_get_next_page(vf,og,begin+CHUNKSIZE-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,				    long begin,				    long searched,				    long end,				    long currentno,				    long m){  long endsearched=end;  long next=end;  ogg_page og;  long ret;    /* the below guards against garbage seperating the last and     first pages of two links. */  while(searched<endsearched){    long 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;    }  }  _seek_helper(vf,next);  ret=_get_next_page(vf,&og,-1);  if(ret==OV_EREAD)return(OV_EREAD);    if(searched>=end || ret<0){    vf->links=m+1;    vf->offsets=(ogg_int64_t *)_ogg_malloc((m+2)*sizeof(*vf->offsets));    vf->offsets[m+1]=searched;  }else{    ret=_bisect_forward_serialno(vf,next,vf->offset,				 end,ogg_page_serialno(&og),m+1);    if(ret==OV_EREAD)return(OV_EREAD);  }    vf->offsets[m]=begin;  return(0);}/* uses the local ogg_stream storage in vf; this is important for   non-streaming input sources */static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,			  long *serialno,ogg_page *og_ptr){  ogg_page og;  ogg_packet op;  int i,ret=0;    if(!og_ptr){    ret=_get_next_page(vf,&og,CHUNKSIZE);    if(ret==OV_EREAD)return(OV_EREAD);    if(ret<0)return OV_ENOTVORBIS;    og_ptr=&og;  }  if(serialno)*serialno=ogg_page_serialno(og_ptr);  ogg_stream_init(&vf->os,ogg_page_serialno(og_ptr));  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;      }  }  return 0;  bail_header:  vorbis_info_clear(vi);  vorbis_comment_clear(vc);  ogg_stream_clear(&vf->os);  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, long dataoffset){  ogg_page og;  int i,ret;    vf->vi=(vorbis_info *)_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));  vf->vc=(vorbis_comment *)_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));  vf->dataoffsets=(ogg_int64_t *)_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));  vf->pcmlengths=(ogg_int64_t *)_ogg_malloc(vf->links*sizeof(*vf->pcmlengths));  vf->serialnos=(long *)_ogg_malloc(vf->links*sizeof(*vf->serialnos));    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;    }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;        ogg_stream_clear(&vf->os);      }    }    /* get the serial number and PCM length of this link. To do this,       get the last page of the stream */    {      long 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->serialnos[i]=ogg_page_serialno(&og);	  vf->pcmlengths[i]=ogg_page_granulepos(&og);	  break;	}	vf->offset=ret;      }    }  }}static void _make_decode_ready(OggVorbis_File *vf){  if(vf->ready_state!=STREAMSET)return;  if(vf->seekable){    vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link);  }else{    vorbis_synthesis_init(&vf->vd,vf->vi);  }      vorbis_block_init(&vf->vd,&vf->vb);  vf->ready_state=INITSET;  return;}static int _open_seekable2(OggVorbis_File *vf){  long serialno=vf->current_serialno,end;  long dataoffset=vf->offset;  ogg_page og;  /* we're partially open and have a first link header state in     storage in vf */  /* we can seek, so set out learning all about this file */  (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);  vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);    /* We get the offset for the last page of the physical bitstream.     Most OggVorbis files will contain a single logical bitstream */  end=_get_prev_page(vf,&og);  if(end<0){    ov_clear(vf);    return(end);  }  /* more than one logical bitstream? */  if(ogg_page_serialno(&og)!=serialno){    /* Chained bitstream. Bisect-search each logical bitstream       section.  Do so based on serial number only */    if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0){      ov_clear(vf);      return(OV_EREAD);    }  }else{    /* Only one logical bitstream */    if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0)){      ov_clear(vf);      return(OV_EREAD);    }  }  /* the initial header memory is referenced by vf after; don't free it */  _prefetch_all_headers(vf,dataoffset);  return(ov_raw_seek(vf,0));}/* clear out the current logical bitstream decoder */ static void _decode_clear(OggVorbis_File *vf){  ogg_stream_clear(&vf->os);  vorbis_dsp_clear(&vf->vd);  vorbis_block_clear(&vf->vb);  vf->ready_state=OPENED;  vf->bittrack=0;  vf->samptrack=0;}/* fetch and process a packet.  Handles the case where we're at a   bitstream boundary and dumps the decoding machine.  If the decoding   machine is unloaded, it loads it.  It also keeps pcm_offset up to   date (seek and read both use this.  seek uses a special hack with   readp).    return: <0) error, OV_HOLE (lost packet) or OV_EOF            0) need more data (only if readp==0)	    1) got a packet */static int _process_packet(OggVorbis_File *vf,int readp){  ogg_page og;  /* handle one packet.  Try to fetch it from current stream state */  /* extract packets from page */  while(1){        /* process a packet if we can.  If the machine isn't loaded,       neither is a page */    if(vf->ready_state==INITSET){      while(1) {      	ogg_packet op;	int result=ogg_stream_packetout(&vf->os,&op);	ogg_int64_t granulepos;	if(result==-1)return(OV_HOLE); /* hole in the data. */	if(result>0){	  /* got a packet.  process it */	  granulepos=op.granulepos;	  if(!vorbis_synthesis(&vf->vb,&op)){ /* lazy check for lazy                                                 header handling.  The                                                 header packets aren't                                                 audio, so if/when we                                                 submit them,                                                 vorbis_synthesis will                                                 reject them */	    /* suck in the synthesis data and track bitrate */	    {	      int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);	      vorbis_synthesis_blockin(&vf->vd,&vf->vb);	      vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;	      vf->bittrack+=op.bytes*8;	    }	  	    /* update the pcm offset. */	    if(granulepos!=-1 && !op.e_o_s){	      int link=(vf->seekable?vf->current_link:0);	      int i,samples;	    	      /* this packet has a pcm_offset on it (the last packet	         completed on a page carries the offset) After processing	         (above), we know the pcm position of the *last* sample	         ready to be returned. Find the offset of the *first*	         As an aside, this trick is inaccurate if we begin	         reading anew right at the last page; the end-of-stream	         granulepos declares the last frame in the stream, and the	         last packet of the last page may be a partial frame.	         So, we need a previous granulepos from an in-sequence page	         to have a reference point.  Thus the !op.e_o_s clause	         above */	    	      samples=vorbis_synthesis_pcmout(&vf->vd,NULL);	    	      granulepos-=samples;	      for(i=0;i<link;i++)	        granulepos+=vf->pcmlengths[i];

⌨️ 快捷键说明

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