コード例 #1
0
static refbuf_t *get_buffer_finished (ogg_state_t *ogg_info, ogg_codec_t *codec)
{
    vorbis_codec_t *source_vorbis = codec->specific;
    ogg_page page;
    refbuf_t *refbuf;

    if (ogg_stream_flush (&source_vorbis->new_os, &page) > 0)
    {
        source_vorbis->samples_in_page -= (ogg_page_granulepos (&page) - source_vorbis->prev_page_samples);
        source_vorbis->prev_page_samples = ogg_page_granulepos (&page);

        refbuf = make_refbuf_with_page (&page);
        DEBUG0 ("flushing page");
        return refbuf;
    }
    ogg_stream_clear (&source_vorbis->new_os);
    ogg_stream_init (&source_vorbis->new_os, rand());

    format_ogg_free_headers (ogg_info);
    source_vorbis->get_buffer_page = NULL;
    if (source_vorbis->prev_packet)
        source_vorbis->process_packet = process_vorbis_headers;
    else
        source_vorbis->process_packet = NULL;

    if (source_vorbis->initial_audio_packet == 0)
        source_vorbis->prev_window = 0;

    return NULL;
}
コード例 #2
0
ファイル: encode.c プロジェクト: miksago/icecast
/* Returns:
 *   0     No output at this time
 *   >0    Page produced
 *
 * Caller should loop over this to ensure that we don't end up with
 * excessive buffering in libvorbis.
 */
int encode_dataout(encoder_state *s, ogg_page *og)
{
    ogg_packet op;
    int result;

    if(s->in_header)
    {
        result = ogg_stream_flush(&s->os, og);
        if(result==0) 
        {
            s->in_header = 0;
            return encode_dataout(s,og);
        }
        else
            return 1;
    }
    else
    {
        while(vorbis_analysis_blockout(&s->vd, &s->vb)==1)
        {
            vorbis_analysis(&s->vb, NULL);
            vorbis_bitrate_addblock(&s->vb);

            while(vorbis_bitrate_flushpacket(&s->vd, &op)) 
                ogg_stream_packetin(&s->os, &op);
        }

        /* FIXME: Make this threshold configurable.
         * We don't want to buffer too many samples in one page when doing
         * live encoding - that's fine for non-live encoding, but breaks
         * badly when doing things live. 
         * So, we flush the stream if we have too many samples buffered
         */
        if(s->samples_in_current_page > s->samplerate * 2)
        {
            /*LOG_DEBUG1("Forcing flush: Too many samples in current page (%d)",
                    s->samples_in_current_page); */
            result = ogg_stream_flush(&s->os, og);
        }
        else
            result = ogg_stream_pageout(&s->os, og);

        if(result==0)
            return 0;
        else /* Page found! */
        {
            s->samples_in_current_page -= ogg_page_granulepos(og) - 
                    s->prevgranulepos;
            s->prevgranulepos = ogg_page_granulepos(og);
            return 1;
        }
    }
}
コード例 #3
0
ファイル: encode.c プロジェクト: eggpi/xmms2-guilherme
/* Returns TRUE if an ogg page was output, FALSE if there is nothing
 * left to do.
 */
gboolean xmms_ices_encoder_output (encoder_state *s, ogg_page *og)
{
	ogg_packet op;

	/* As long as we're still in the header, we still have the header
	 * packets to output. Loop over those before going to the actual
	 * vorbis data. */
	if (s->in_header) {
		if (ogg_stream_flush (&s->os, og))
			return TRUE;
		else
			s->in_header = FALSE;
	}

	/* If we're flushing the end of the stream, just output. */
	if (s->flushing) {
		if (ogg_stream_flush (&s->os, og))
			return TRUE;
		else
			return FALSE;
	}

	/* Flush the vorbis analysis stream into ogg packets, and add
	 * those to the ogg packet stream. */
	while (vorbis_analysis_blockout (&s->vd, &s->vb) == 1) {
		vorbis_analysis (&s->vb, NULL);
		vorbis_bitrate_addblock (&s->vb);

		while (vorbis_bitrate_flushpacket (&s->vd, &op))
			ogg_stream_packetin (&s->os, &op);
	}

	/* For live encoding, we want to stream pages regularly, rather
	 * than burst huge pages. Therefore, we periodically manually
	 * flush the stream. */
	if (s->samples_in_current_page > s->rate * 2) {
		if (!ogg_stream_flush (&s->os, og))
			return FALSE;
	} else {
		if (!ogg_stream_pageout (&s->os, og))
			return FALSE;
	}

	/* At this point, we have an ogg page in og. Keep bookkeeping
	 * accurate regarding the number of samples still in the page
	 * buffer, and return. */
	s->samples_in_current_page -= (ogg_page_granulepos (og)
	                               - s->previous_granulepos);
	s->previous_granulepos = ogg_page_granulepos (og);

	return TRUE;
}
コード例 #4
0
ファイル: vorbisfile.c プロジェクト: OS2World/LIB-SDL
/* 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;
      }
    }
  }
}
コード例 #5
0
ファイル: ogg_vorbis.c プロジェクト: stohrendorf/libsndfile
static sf_count_t
vorbis_length_aux (SF_PRIVATE * psf)
{	ogg_sync_state osync ;
	ogg_page page ;
	sf_count_t len = 0 ;
	stream_set *processors ;

	processors = create_stream_set () ;
	if (processors == NULL)
		return 0 ;	// out of memory?

	ogg_sync_init (&osync) ;

	while (vorbis_length_get_next_page (psf, &osync, &page))
	{	stream_processor *p = find_stream_processor (processors, &page) ;

		if (!p)
		{	len = 0 ;
			break ;
		} ;

		if (p->isillegal && !p->shownillegal)
		{	p->shownillegal = 1 ;
			/* If it's a new stream, we want to continue processing this page
			** anyway to suppress additional spurious errors
			*/
			if (!p->isnew) continue ;
		} ;

		if (!p->isillegal)
		{	ogg_packet packet ;
			int header = 0 ;

			ogg_stream_pagein (&p->ostream, &page) ;
			if (p->doneheaders < 3)
				header = 1 ;

			while (ogg_stream_packetout (&p->ostream, &packet) > 0)
			{	if (p->doneheaders < 3)
				{	if (vorbis_synthesis_headerin (&p->vinfo, &p->vcomment, &packet) < 0)
						continue ;
					p->doneheaders ++ ;
				} ;
			} ;
			if (!header)
			{	sf_count_t gp = ogg_page_granulepos (&page) ;
				if (gp > 0) p->lastgranulepos = gp ;
			} ;
			if (p->end)
			{	vorbis_end (p, &len) ;
				p->isillegal = 1 ;
			} ;
		} ;
	} ;

	ogg_sync_clear (&osync) ;
	free_stream_set (processors, &len) ;

	return len ;
} /* vorbis_length_aux */
コード例 #6
0
ファイル: oggeyman.cpp プロジェクト: ivanamihalek/oggeyman
bool Oggeyman::is_header_page(ogg_page * ogg_page_ptr) {
	// From Ogg spec: "Granule Position must always increase forward or remain equal
	// from page to page, be unset, or be zero for a header page. "
	bool is_header = false;
	if (ogg_page_granulepos(ogg_page_ptr) == 0)
		is_header = true;
	return is_header;
}
コード例 #7
0
ファイル: utils.c プロジェクト: JanX2/XiphQT
void find_last_page_GP(const unsigned char *data, UInt32 data_size,
                       ogg_int64_t *gp, long *serialno)
{
    unsigned char *ptr = (unsigned char *) data;
    const unsigned char *end = data + data_size;
    ogg_page op;

    *gp = -1;
    *serialno = 0;

    while (FindPage(&ptr, end, &op)) {
        if (ogg_page_granulepos(&op) > 0) {
            *gp = ogg_page_granulepos(&op);
            *serialno = ogg_page_serialno(&op);
        }
    }
}
コード例 #8
0
ファイル: pyEx_ogg.c プロジェクト: vigith/ogg-theora-vorbis
static PyObject * py_ogg_ogg_page_granulepos(PyObject *self, PyObject *args) {
  int size;
  ogg_int64_t c_out;
  ogg_page * og;
  PyArg_ParseTuple(args, "s#", &og, &size);
  c_out = ogg_page_granulepos(og);
  return Py_BuildValue("l", c_out);
};
コード例 #9
0
ファイル: ucil_theora.c プロジェクト: hotlens/spherO
static double encode_vorbis( FILE *f, vorbis_dsp_state *vd, ogg_stream_state *vo, vorbis_block *vb, 
			     unsigned int audio_rate, double audiopos, signed char *buf, int n_samples )
{
   float **vorbis_buffer;
   const int audio_ch = 2;
   int i,j;
   int count = 0;
   ogg_page og;
   int got_page = 0;

   vorbis_buffer = vorbis_analysis_buffer( vd, n_samples );
   
   for( i = 0; i < n_samples; i++ )
   {
      for( j = 0; j < audio_ch; j++ )
      {
	 vorbis_buffer[j][i] = ( ( buf[count+1] << 8 ) | ( buf[count] & 0xff ) ) / 32768.0f;
	 count += 2;
      }
   }
   
   vorbis_analysis_wrote( vd, n_samples );

   while( vorbis_analysis_blockout( vd, vb ) == 1 )
   {
      ogg_packet op;
      
      vorbis_analysis( vb, NULL );
      vorbis_bitrate_addblock( vb );
      
      while( vorbis_bitrate_flushpacket( vd, &op ) )
      {
	 ogg_stream_packetin( vo, &op );
      }
   }
   
   while( ogg_stream_pageout( vo, &og ) )
   {
      got_page = 1;
      audiopos = vorbis_granule_time( vd, ogg_page_granulepos( &og ) );
/*       printf( "VORBIS: %f\n", audiopos ); */
      fwrite( og.header, og.header_len, 1, f );
      fwrite( og.body, og.body_len, 1, f );
   }

   if( !got_page )
   {
      double t;
      
      t = ( ( 1.0 * n_samples ) / audio_rate );
      
      audiopos += t;
   }

   return audiopos;
}
コード例 #10
0
ファイル: oggmux.c プロジェクト: ChinnaSuhas/ossbuild
static ChainState *
validate_ogg_page (ogg_page * page)
{
  gulong serialno;
  gint64 granule;
  ChainState *state;

  serialno = ogg_page_serialno (page);
  granule = ogg_page_granulepos (page);
  state = g_hash_table_lookup (eos_chain_states, GINT_TO_POINTER (serialno));

  fail_if (ogg_page_packets (page) == 0 && granule != -1,
      "Must have granulepos -1 when page has no packets, has %" G_GINT64_FORMAT,
      granule);

  if (ogg_page_bos (page)) {
    fail_unless (state == NULL, "Extraneous BOS flag on chain %u", serialno);

    state = g_new0 (ChainState, 1);
    g_hash_table_insert (eos_chain_states, GINT_TO_POINTER (serialno), state);
    state->serialno = serialno;
    state->last_granule = granule;
    state->codec = get_page_codec (page);

    /* check for things like BOS ordering, etc */
    switch (state->codec) {
      case CODEC_THEORA:
        /* check we have no vorbis/speex chains yet */
        g_hash_table_foreach (eos_chain_states, (GHFunc) fail_if_audio, NULL);
        break;
      case CODEC_VORBIS:
      case CODEC_SPEEX:
        /* no checks (yet) */
        break;
      case CODEC_UNKNOWN:
      default:
        break;
    }
  } else if (ogg_page_eos (page)) {
    fail_unless (state != NULL, "Missing BOS flag on chain %u", serialno);
    state->eos = TRUE;
  } else {
    fail_unless (state != NULL, "Missing BOS flag on chain %u", serialno);
    fail_unless (!state->eos, "Data after EOS flag on chain %u", serialno);
  }

  if (granule != -1) {
    fail_unless (granule >= state->last_granule,
        "Granulepos out-of-order for chain %u: old=%" G_GINT64_FORMAT ", new="
        G_GINT64_FORMAT, serialno, state->last_granule, granule);
    state->last_granule = granule;
  }

  return state;
}
コード例 #11
0
static refbuf_t *get_buffer_audio (ogg_state_t *ogg_info, ogg_codec_t *codec)
{
    refbuf_t *refbuf = NULL;
    ogg_page page;
    vorbis_codec_t *source_vorbis = codec->specific;
    int (*get_ogg_page)(ogg_stream_state*, ogg_page *) = ogg_stream_pageout;

    if (source_vorbis->samples_in_page > source_vorbis->page_samples_trigger)
        get_ogg_page = ogg_stream_flush;

    if (get_ogg_page (&source_vorbis->new_os, &page) > 0)
    {
        /* squeeze a page copy into a buffer */
        source_vorbis->samples_in_page -= (ogg_page_granulepos (&page) - source_vorbis->prev_page_samples);
        source_vorbis->prev_page_samples = ogg_page_granulepos (&page);

        refbuf = make_refbuf_with_page (&page);
    }
    return refbuf;
}
コード例 #12
0
ファイル: file.c プロジェクト: Garalv/miumiu
int read_page_cb(OGGZ *oggz, const ogg_page *og, long serialno, void *data)
{
	if ( serialno == audio_stream->serialno )
	{
		audio_stream->page_ts = ogg_page_granulepos(og) * 1000 / SPEEX_SAMPLING_RATE;
		audio_stream->page_count = 0;
	} else if ( serialno == video_stream->serialno )
	{
		//mylog("Got theora page serialno=%d, header_len=%d, body_len=%d, granulepos=%lld\n",
		//		serialno, og->header_len, og->body_len, ogg_page_granulepos(og));
	}
	return 0;
}
コード例 #13
0
ファイル: stream_video.c プロジェクト: mecke/xiph-qt
static void _ready_page(StreamInfoPtr si)
{
    UInt32 len = si->og.header_len + si->og.body_len;
    Float64 pos;

    if (si->og_buffer_size < len) {
        si->og_buffer = realloc(si->og_buffer, len);
        si->og_buffer_size = len;
    }
    BlockMoveData(si->og.header, si->og_buffer, si->og.header_len);
    BlockMoveData(si->og.body, si->og_buffer + si->og.header_len,
                  si->og.body_len);
    si->og.header = si->og_buffer;
    si->og.body = si->og_buffer + si->og.header_len;
    si->og_ready = true;
    si->acc_packets -= ogg_page_packets(&si->og);
    if (ogg_page_granulepos(&si->og) != -1) {
        si->og_grpos = ogg_page_granulepos(&si->og);
        if (si->si_v.grpos_shift > 0) {
            /* with theora, si->og_grpos represents total number of frames */
            ogg_int64_t frames = si->og_grpos >> si->si_v.grpos_shift;
            si->og_grpos = frames + si->og_grpos -
                (frames << si->si_v.grpos_shift);
        }
コード例 #14
0
	bool VideoClip_Theora::_readData()
	{
		int audioEos = 0;
		int serno = 0;
		float audioTime = 0;
		float time = this->timer->getTime();
		if (this->restarted)
		{
			time = 0.0f;
		}
		char* buffer = NULL;
		int bytesRead = 0;
		ogg_int64_t granule = 0;
		do
		{
			buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE);
			bytesRead = this->stream->read(buffer, BUFFER_SIZE);
			ogg_sync_wrote(&this->info.OggSyncState, bytesRead);
			if (bytesRead == 0)
			{
				if (!this->autoRestart)
				{
					this->endOfFile = true;
					log(this->name + " finished playing");
				}
				return false;
			}
			// when we fill the stream with enough pages, it'll start spitting out packets
			// which contain key frames, delta frames or audio data
			while (ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage) > 0)
			{
				serno = ogg_page_serialno(&this->info.OggPage);
				if (serno == this->info.TheoraStreamState.serialno)
				{
					ogg_stream_pagein(&this->info.TheoraStreamState, &this->info.OggPage);
				}
				if (this->audioInterface != NULL && serno == this->info.VorbisStreamState.serialno)
				{
					granule = ogg_page_granulepos(&this->info.OggPage);
					audioTime = (float)vorbis_granule_time(&this->info.VorbisDSPState, granule);
					audioEos = ogg_page_eos(&this->info.OggPage);
					ogg_stream_pagein(&this->info.VorbisStreamState, &this->info.OggPage);
				}
			}
		} while (this->audioInterface != NULL && audioEos == 0 && audioTime < time + 1.0f);
		return true;
	}
コード例 #15
0
static page_type
gst_ogg_parse_is_header (GstOggParse * ogg, GstOggStream * stream,
    ogg_page * page)
{
  ogg_int64_t gpos = ogg_page_granulepos (page);

  if (gpos < 0)
    return PAGE_PENDING;

  /* This is good enough for now, but technically requires codec-specific
   * behaviour to be perfect. This is where we need the mooted library for 
   * this stuff, which nobody has written.
   */
  if (gpos > 0)
    return PAGE_DATA;
  else
    return PAGE_HEADER;
}
コード例 #16
0
ファイル: speex.c プロジェクト: gitkaste/moc
static int count_time (struct spx_data *data)
{
	unsigned long last_granulepos = 0;

	/* Seek to somewhere neer the last page */
	if (io_file_size(data->stream) > 10000) {
		debug ("Seeking near the end");
		if (io_seek(data->stream, -10000, SEEK_END) == -1)
			logit ("Seeking failed, scaning whole file");
		ogg_sync_reset (&data->oy);
	}
	
	/* Read granulepos from the last packet */
	while (!io_eof(data->stream)) {

		/* Sync to page and read it */
		while (!io_eof(data->stream)) {
			char *buf;
			int nb_read;

			if (ogg_sync_pageout(&data->oy, &data->og) == 1) {
				debug ("Sync");
				break;
			}
			else if (!io_eof(data->stream)) {
				debug ("Need more data");
				buf = ogg_sync_buffer (&data->oy, 200);
				nb_read = io_read (data->stream, buf, 200);
				ogg_sync_wrote (&data->oy, nb_read);
			}
		}

		/* We have last packet */
		if (io_eof(data->stream))
			break;

		last_granulepos = ogg_page_granulepos (&data->og);
	}

	return last_granulepos / data->rate;
}
コード例 #17
0
ファイル: r_ogm.cpp プロジェクト: Azpidatziak/mkvtoolnix
/*
   Process the contents of a page. First find the demuxer associated with
   the page's serial number. If there is no such demuxer then either the
   OGG file is damaged (very rare) or the page simply belongs to a stream
   that the user didn't want extracted.
   If the demuxer is found then hand over all packets in this page to the
   associated packetizer.
*/
void
ogm_reader_c::process_page(ogg_page *og) {
  ogm_demuxer_cptr dmx;
  int64_t granulepos;

  dmx = find_demuxer(ogg_page_serialno(og));
  if (!dmx || !dmx->in_use)
    return;

  granulepos = ogg_page_granulepos(og);

  if ((-1 != granulepos) && (granulepos < dmx->last_granulepos)) {
    mxwarn_tid(m_ti.m_fname, dmx->track_id,
               Y("The timecodes for this stream have been reset in the middle of the file. This is not supported. The current packet will be discarded.\n"));
    return;
  }

  ogg_stream_pagein(&dmx->os, og);

  dmx->process_page(granulepos);

  dmx->last_granulepos = granulepos;
}
コード例 #18
0
ファイル: speex.c プロジェクト: jonsafari/mocp
static int count_time (struct spx_data *data)
{
	ogg_int64_t last_granulepos = 0;

	/* Seek to somewhere near the last page */
	if (io_file_size(data->stream) > 10000) {
		debug ("Seeking near the end");
		if (io_seek(data->stream, -10000, SEEK_END) == -1)
			logit ("Seeking failed, scanning whole file");
		ogg_sync_reset (&data->oy);
	}

	/* Read granulepos from the last packet */
	while (!io_eof(data->stream)) {

		/* Sync to page and read it */
		while (!io_eof(data->stream)) {
			if (ogg_sync_pageout(&data->oy, &data->og) == 1) {
				debug ("Sync");
				break;
			}

			if (!io_eof(data->stream)) {
				debug ("Need more data");
				get_more_data (data);
			}
		}

		/* We have last packet */
		if (io_eof(data->stream))
			break;

		last_granulepos = ogg_page_granulepos (&data->og);
	}

	return last_granulepos / data->rate;
}
コード例 #19
0
ファイル: ogg_speex.c プロジェクト: CarlosXViera/SoundShake
static int
spx_read_header (SF_PRIVATE * psf)
{	static SpeexStereoState STEREO_INIT = SPEEX_STEREO_STATE_INIT ;

	OGG_PRIVATE* odata = psf->container_data ;
	SPX_PRIVATE* spx = psf->codec_data ;

	ogg_int64_t page_granule = 0 ;
	int stream_init = 0 ;
	int	page_nb_packets = 0 ;
	int packet_count = 0 ;
	int enh_enabled = 1 ;
	int force_mode = -1 ;
	char * data ;
	int nb_read ;
	int lookahead ;

printf ("%s %d\n", __func__, __LINE__) ;

	psf_log_printf (psf, "Speex header\n") ;
	odata->eos = 0 ;

	/* Reset ogg stuff which has already been used in src/ogg.c. */
	ogg_stream_reset (&odata->ostream) ;
	ogg_sync_reset (&odata->osync) ;

	/* Seek to start of stream. */
	psf_fseek (psf, 0, SEEK_SET) ;

	/* Initialize. */
	ogg_sync_init (&odata->osync) ;
	speex_bits_init (&spx->bits) ;

	/* Set defaults. */
	psf->sf.channels = -1 ;
	psf->sf.samplerate = 0 ;
	spx->stereo = STEREO_INIT ;

	/* Get a pointer to the ogg buffer and read data into it. */
	data = ogg_sync_buffer (&odata->osync, OGG_SPX_READ_SIZE) ;
	nb_read = psf_fread (data, 1, OGG_SPX_READ_SIZE, psf) ;
	ogg_sync_wrote (&odata->osync, nb_read) ;

	/* Now we chew on Ogg packets. */
	while (ogg_sync_pageout (&odata->osync, &odata->opage) == 1)
	{	if (stream_init == 0)
		{	ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ;
			stream_init = 1 ;
			} ;

		if (ogg_page_serialno (&odata->opage) != odata->ostream.serialno)
		{	/* so all streams are read. */
			ogg_stream_reset_serialno (&odata->ostream, ogg_page_serialno (&odata->opage)) ;
			} ;

		/*Add page to the bitstream*/
		ogg_stream_pagein (&odata->ostream, &odata->opage) ;
		page_granule = ogg_page_granulepos (&odata->opage) ;
		page_nb_packets = ogg_page_packets (&odata->opage) ;

		/*Extract all available packets*/
		while (odata->eos == 0 && ogg_stream_packetout (&odata->ostream, &odata->opacket) == 1)
		{	if (odata->opacket.bytes >= 8 && memcmp (odata->opacket.packet, "Speex   ", 8) == 0)
			{	spx->serialno = odata->ostream.serialno ;
				} ;

			if (spx->serialno == -1 || odata->ostream.serialno != spx->serialno)
				break ;

			if (packet_count == 0)
			{	spx->state = spx_header_read (psf, &odata->opacket, enh_enabled, force_mode) ;
				if (! spx->state)
					break ;

				speex_decoder_ctl (spx->state, SPEEX_GET_LOOKAHEAD, &lookahead) ;
				if (spx->nframes == 0)
					spx->nframes = 1 ;
				}
			else if (packet_count == 1)
			{	spx_print_comments ((const char*) odata->opacket.packet, odata->opacket.bytes) ;
				}
			else if (packet_count < 2 + spx->header.extra_headers)
			{	/* Ignore extra headers */
				}
			packet_count ++ ;
			} ;
		} ;

	psf_log_printf (psf, "End\n") ;

	psf_log_printf (psf, "packet_count %d\n", packet_count) ;
	psf_log_printf (psf, "page_nb_packets %d\n", page_nb_packets) ;
	psf_log_printf (psf, "page_granule %lld\n", page_granule) ;

	return 0 ;
} /* spx_read_header */
コード例 #20
0
ファイル: input.c プロジェクト: xiph/Icecast-IceS
int input_calculate_ogg_sleep(ogg_page *page)
{
    static ogg_stream_state os;
    ogg_packet op;
    static vorbis_info vi;
    static vorbis_comment vc;
    static input_type codec = ICES_INPUT_UNKNOWN;
    static int need_start_pos, need_headers, state_in_use = 0;
    static int serialno = 0;
    static uint64_t offset;
    static uint64_t first_granulepos;

    if (ogg_page_granulepos(page) == -1)
    {
        LOG_ERROR0("Timing control: corrupt timing information in vorbis file, cannot stream.");
        return -1;
    }
    if (ogg_page_bos (page))
    {
        control.oldsamples = 0;

        if (state_in_use)
            ogg_stream_clear (&os);
        ogg_stream_init (&os, ogg_page_serialno (page));
        serialno = ogg_page_serialno (page);
        state_in_use = 1;
        vorbis_info_init (&vi);
        vorbis_comment_init (&vc);
        need_start_pos = 1;
        need_headers = 3;
        codec = ICES_INPUT_UNKNOWN;
        offset = (uint64_t)0;
    }
    if (need_start_pos)
    {
        int found_first_granulepos = 0;

        ogg_stream_pagein (&os, page);
        while (ogg_stream_packetout (&os, &op) == 1)
        {
            if (need_headers)
            {
                /* check for Vorbis. For Vorbis the Magic is {0x01|0x03|0x05}"vorbis" */
                if (op.bytes > 7 && memcmp(op.packet+1, "vorbis", 6) == 0)
                {
                    if (vorbis_synthesis_headerin (&vi, &vc, &op) < 0)
                    {
                        LOG_ERROR0("Timing control: can't determine sample rate for input, not vorbis.");
                        control.samplerate = 0;
                        vorbis_info_clear (&vi);
                        ogg_stream_clear (&os);
                        return -1;
                    }
                    control.samplerate = vi.rate;
                    codec = ICES_INPUT_VORBIS;
                }
                /* check for Opus. For Opus the magic is "OpusHead" */
                else if (op.bytes == 19 && memcmp(op.packet, "OpusHead", 8) == 0)
                {
                    if (op.packet[8] != 1)
                    {
                        LOG_ERROR0("Timing control: can't determine sample rate for input, unsupported Opus version.");
                        control.samplerate = 0;
                        vorbis_info_clear (&vi);
                        ogg_stream_clear (&os);
                        return -1;
                    }
                    /* Sample rate is fixed for Opus: 48kHz */
                    control.samplerate = 48000;
                    codec = ICES_INPUT_OGG;
                    /* No more headers after this one needed */
                    need_headers = 1;
                }
                else if (op.bytes >= 80 && memcmp(op.packet, "Speex   ", 8) == 0)
                {
                    if (__read_int32_le(op.packet+28) != 1 || __read_int32_le(op.packet+32) != op.bytes)
                    {
                        LOG_ERROR0("Timing control: can't determine sample rate for input, bad or unsupported Speex header.");
                        control.samplerate = 0;
                        vorbis_info_clear (&vi);
                        ogg_stream_clear (&os);
                        return -1;
                    }

                    control.samplerate = __read_int32_le(op.packet+36);
                    codec = ICES_INPUT_OGG;
                    /* No more headers after this one needed */
                    need_headers = 1;
                }
                else if (op.bytes >= 51 && memcmp(op.packet, "\177FLAC\1\0", 7) == 0 && memcmp(op.packet+9, "fLaC\0", 5) == 0)
                {
                    control.samplerate = __read_int20_be(op.packet+27);
                    codec = ICES_INPUT_OGG;
                    /* No more headers after this one needed */
                    need_headers = 1;
                }
                else if (codec == ICES_INPUT_UNKNOWN)
                {
                    LOG_ERROR0("Timing control: can't determine sample rate for input, unsupported input format.");
                    control.samplerate = 0;
                    vorbis_info_clear (&vi);
                    ogg_stream_clear (&os);
                    return -1;
                }
                need_headers--;

                if (need_headers == 0)
                {
                    vorbis_comment_clear (&vc);
                    first_granulepos = (uint64_t)0;
                    return 0;
                }
                continue;
            }
            /* headers have been read */
            if (first_granulepos == 0 && op.granulepos > 0)
            {
                first_granulepos = op.granulepos;
                found_first_granulepos = 1;
            }
            if (codec == ICES_INPUT_VORBIS)
            {
                offset += vorbis_packet_blocksize (&vi, &op) / 4;
            }
        }
        if (!found_first_granulepos)
            return 0;

        need_start_pos = 0;
        control.oldsamples = first_granulepos - offset;
        vorbis_info_clear (&vi);
        ogg_stream_clear (&os);
        state_in_use = 0;
    }
    if (serialno != ogg_page_serialno (page))
    {
        LOG_ERROR0 ("Found page which does not belong to current logical stream");
        return -1;
    }
    control.samples = ogg_page_granulepos (page) - control.oldsamples;
    control.oldsamples = ogg_page_granulepos (page);

    control.senttime += ((uint64_t)control.samples * 1000000 /
            (uint64_t)control.samplerate);

    return 0;
}
コード例 #21
0
/* Reads in buffers, parses them, reframes into one-buffer-per-ogg-page, submits
 * pages to output pad.
 */
static GstFlowReturn
gst_ogg_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
  GstOggParse *ogg;
  GstFlowReturn result = GST_FLOW_OK;
  gint ret = -1;
  guint32 serialno;
  GstBuffer *pagebuffer;
  GstClockTime buffertimestamp = GST_BUFFER_TIMESTAMP (buffer);

  ogg = GST_OGG_PARSE (parent);

  GST_LOG_OBJECT (ogg,
      "Chain function received buffer of size %" G_GSIZE_FORMAT,
      gst_buffer_get_size (buffer));

  gst_ogg_parse_submit_buffer (ogg, buffer);

  while (ret != 0 && result == GST_FLOW_OK) {
    ogg_page page;

    /* We use ogg_sync_pageseek() rather than ogg_sync_pageout() so that we can
     * track how many bytes the ogg layer discarded (in the case of sync errors,
     * etc.); this allows us to accurately track the current stream offset
     */
    ret = ogg_sync_pageseek (&ogg->sync, &page);
    if (ret == 0) {
      /* need more data, that's fine... */
      break;
    } else if (ret < 0) {
      /* discontinuity; track how many bytes we skipped (-ret) */
      ogg->offset -= ret;
    } else {
      gint64 granule = ogg_page_granulepos (&page);
#ifndef GST_DISABLE_GST_DEBUG
      int bos = ogg_page_bos (&page);
#endif
      guint64 startoffset = ogg->offset;
      GstOggStream *stream;
      gboolean keyframe;

      serialno = ogg_page_serialno (&page);
      stream = gst_ogg_parse_find_stream (ogg, serialno);

      GST_LOG_OBJECT (ogg, "Timestamping outgoing buffer as %" GST_TIME_FORMAT,
          GST_TIME_ARGS (buffertimestamp));

      if (stream) {
        buffertimestamp = gst_ogg_stream_get_end_time_for_granulepos (stream,
            granule);
        if (ogg->video_stream) {
          if (stream == ogg->video_stream) {
            keyframe = gst_ogg_stream_granulepos_is_key_frame (stream, granule);
          } else {
            keyframe = FALSE;
          }
        } else {
          keyframe = TRUE;
        }
      } else {
        buffertimestamp = GST_CLOCK_TIME_NONE;
        keyframe = TRUE;
      }
      pagebuffer = gst_ogg_parse_buffer_from_page (&page, startoffset,
          buffertimestamp);

      /* We read out 'ret' bytes, so we set the next offset appropriately */
      ogg->offset += ret;

      GST_LOG_OBJECT (ogg,
          "processing ogg page (serial %08x, pageno %ld, "
          "granule pos %" G_GUINT64_FORMAT ", bos %d, offset %"
          G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT ") keyframe=%d",
          serialno, ogg_page_pageno (&page),
          granule, bos, startoffset, ogg->offset, keyframe);

      if (ogg_page_bos (&page)) {
        /* If we've seen this serialno before, this is technically an error,
         * we log this case but accept it - this one replaces the previous
         * stream with this serialno. We can do this since we're streaming, and
         * not supporting seeking...
         */
        GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno);

        if (stream != NULL) {
          GST_LOG_OBJECT (ogg, "Incorrect stream; repeats serial number %08x "
              "at offset %" G_GINT64_FORMAT, serialno, ogg->offset);
        }

        if (ogg->last_page_not_bos) {
          GST_LOG_OBJECT (ogg, "Deleting all referenced streams, found a new "
              "chain starting with serial %u", serialno);
          gst_ogg_parse_delete_all_streams (ogg);
        }

        stream = gst_ogg_parse_new_stream (ogg, &page);

        ogg->last_page_not_bos = FALSE;

        gst_buffer_ref (pagebuffer);
        stream->headers = g_list_append (stream->headers, pagebuffer);

        if (!ogg->in_headers) {
          GST_LOG_OBJECT (ogg,
              "Found start of new chain at offset %" G_GUINT64_FORMAT,
              startoffset);
          ogg->in_headers = 1;
        }

        /* For now, we just keep the header buffer in the stream->headers list;
         * it actually gets output once we've collected the entire set
         */
      } else {
        /* Non-BOS page. Either: we're outside headers, and this isn't a 
         * header (normal data), outside headers and this is (error!), inside
         * headers, this is (append header), or inside headers and this isn't 
         * (we've found the end of headers; flush the lot!)
         *
         * Before that, we flag that the last page seen (this one) was not a 
         * BOS page; that way we know that when we next see a BOS page it's a
         * new chain, and we can flush all existing streams.
         */
        page_type type;
        GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno);

        if (!stream) {
          GST_LOG_OBJECT (ogg,
              "Non-BOS page unexpectedly found at %" G_GINT64_FORMAT,
              ogg->offset);
          goto failure;
        }

        ogg->last_page_not_bos = TRUE;

        type = gst_ogg_parse_is_header (ogg, stream, &page);

        if (type == PAGE_PENDING && ogg->in_headers) {
          gst_buffer_ref (pagebuffer);

          stream->unknown_pages = g_list_append (stream->unknown_pages,
              pagebuffer);
        } else if (type == PAGE_HEADER) {
          if (!ogg->in_headers) {
            GST_LOG_OBJECT (ogg, "Header page unexpectedly found outside "
                "headers at offset %" G_GINT64_FORMAT, ogg->offset);
            goto failure;
          } else {
            /* Append the header to the buffer list, after any unknown previous
             * pages
             */
            stream->headers = g_list_concat (stream->headers,
                stream->unknown_pages);
            g_list_free (stream->unknown_pages);
            gst_buffer_ref (pagebuffer);
            stream->headers = g_list_append (stream->headers, pagebuffer);
          }
        } else {                /* PAGE_DATA, or PAGE_PENDING but outside headers */
          if (ogg->in_headers) {
            /* First non-header page... set caps, flush headers.
             *
             * First up, we build a single GValue list of all the pagebuffers
             * we're using for the headers, in order.
             * Then we set this on the caps structure. Then we can start pushing
             * buffers for the headers, and finally we send this non-header
             * page.
             */
            GstCaps *caps;
            GstStructure *structure;
            GValue array = { 0 };
            gint count = 0;
            gboolean found_pending_headers = FALSE;
            GSList *l;

            g_value_init (&array, GST_TYPE_ARRAY);

            for (l = ogg->oggstreams; l != NULL; l = l->next) {
              GstOggStream *stream = (GstOggStream *) l->data;

              if (g_list_length (stream->headers) == 0) {
                GST_LOG_OBJECT (ogg, "No primary header found for stream %08x",
                    stream->serialno);
                goto failure;
              }

              gst_ogg_parse_append_header (&array,
                  GST_BUFFER (stream->headers->data));
              count++;
            }

            for (l = ogg->oggstreams; l != NULL; l = l->next) {
              GstOggStream *stream = (GstOggStream *) l->data;
              GList *j;

              /* already appended the first header, now do headers 2-N */
              for (j = stream->headers->next; j != NULL; j = j->next) {
                gst_ogg_parse_append_header (&array, GST_BUFFER (j->data));
                count++;
              }
            }

            caps = gst_pad_query_caps (ogg->srcpad, NULL);
            caps = gst_caps_make_writable (caps);

            structure = gst_caps_get_structure (caps, 0);
            gst_structure_take_value (structure, "streamheader", &array);

            gst_pad_set_caps (ogg->srcpad, caps);

            if (ogg->caps)
              gst_caps_unref (ogg->caps);
            ogg->caps = caps;

            GST_LOG_OBJECT (ogg, "Set \"streamheader\" caps with %d buffers "
                "(one per page)", count);

            /* Now, we do the same thing, but push buffers... */
            for (l = ogg->oggstreams; l != NULL; l = l->next) {
              GstOggStream *stream = (GstOggStream *) l->data;
              GstBuffer *buf = GST_BUFFER (stream->headers->data);

              result = gst_pad_push (ogg->srcpad, buf);
              if (result != GST_FLOW_OK)
                return result;
            }
            for (l = ogg->oggstreams; l != NULL; l = l->next) {
              GstOggStream *stream = (GstOggStream *) l->data;
              GList *j;

              /* pushed the first one for each stream already, now do 2-N */
              for (j = stream->headers->next; j != NULL; j = j->next) {
                GstBuffer *buf = GST_BUFFER (j->data);

                result = gst_pad_push (ogg->srcpad, buf);
                if (result != GST_FLOW_OK)
                  return result;
              }
            }

            ogg->in_headers = 0;

            /* And finally the pending data pages */
            for (l = ogg->oggstreams; l != NULL; l = l->next) {
              GstOggStream *stream = (GstOggStream *) l->data;
              GList *k;

              if (stream->unknown_pages == NULL)
                continue;

              if (found_pending_headers) {
                GST_WARNING_OBJECT (ogg, "Incorrectly muxed headers found at "
                    "approximate offset %" G_GINT64_FORMAT, ogg->offset);
              }
              found_pending_headers = TRUE;

              GST_LOG_OBJECT (ogg, "Pushing %d pending pages after headers",
                  g_list_length (stream->unknown_pages) + 1);

              for (k = stream->unknown_pages; k != NULL; k = k->next) {
                GstBuffer *buf = GST_BUFFER (k->data);

                result = gst_pad_push (ogg->srcpad, buf);
                if (result != GST_FLOW_OK)
                  return result;
              }
              g_list_foreach (stream->unknown_pages,
                  (GFunc) gst_mini_object_unref, NULL);
              g_list_free (stream->unknown_pages);
              stream->unknown_pages = NULL;
            }
          }

          if (granule == -1) {
            stream->stored_buffers = g_list_append (stream->stored_buffers,
                pagebuffer);
          } else {
            while (stream->stored_buffers) {
              GstBuffer *buf = stream->stored_buffers->data;

              buf = gst_buffer_make_writable (buf);

              GST_BUFFER_TIMESTAMP (buf) = buffertimestamp;
              if (!keyframe) {
                GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
              } else {
                keyframe = FALSE;
              }

              result = gst_pad_push (ogg->srcpad, buf);
              if (result != GST_FLOW_OK)
                return result;

              stream->stored_buffers =
                  g_list_delete_link (stream->stored_buffers,
                  stream->stored_buffers);
            }

            pagebuffer = gst_buffer_make_writable (pagebuffer);
            if (!keyframe) {
              GST_BUFFER_FLAG_SET (pagebuffer, GST_BUFFER_FLAG_DELTA_UNIT);
            } else {
              keyframe = FALSE;
            }

            result = gst_pad_push (ogg->srcpad, pagebuffer);
            if (result != GST_FLOW_OK)
              return result;
          }
        }
      }
    }
  }

  return result;

failure:
  gst_pad_push_event (GST_PAD (ogg->srcpad), gst_event_new_eos ());
  return GST_FLOW_ERROR;
}
コード例 #22
0
ファイル: im_playlist.c プロジェクト: EQ4/Icecast-IceS
/* Core streaming function for this module
 * This is what actually produces the data which gets streamed.
 *
 * returns:  >0  Number of bytes read
 *            0  Non-fatal error.
 *           <0  Fatal error.
 */
static int playlist_read(void *self, ref_buffer *rb)
{
    playlist_state_t *pl = (playlist_state_t *)self;
    int bytes;
    unsigned char *buf;
    char *newfn;
    int result;
    ogg_page og;

    if (pl->errors > 5) 
    {
        LOG_WARN0("Too many consecutive errors - exiting");
        return -1;
    }

    if (!pl->current_file || pl->nexttrack) 
    {
        pl->nexttrack = 0;

        if (pl->current_file && strcmp (pl->filename, "-"))
        {
            fclose(pl->current_file);
            pl->current_file = NULL;
        }
	if (pl->file_ended)
	{
	    pl->file_ended(pl->data, pl->filename);
	}

        newfn = pl->get_filename(pl->data);
        if (!newfn)
        {
            LOG_INFO0("No more filenames available, end of playlist");
            return -1; /* No more files available */
        }

        if (strcmp (newfn, "-"))
        {
            if (!pl->allow_repeat && pl->filename && !strcmp(pl->filename, newfn))
            {
                LOG_ERROR0("Cannot play same file twice in a row, skipping");
                pl->errors++;
                pl->free_filename (pl->data, newfn);
                return 0;
            }
            pl->free_filename(pl->data, pl->filename);
            pl->filename = newfn;

            pl->current_file = fopen(pl->filename, "rb");
            if (!pl->current_file) 
            {
                LOG_WARN2("Error opening file \"%s\": %s",pl->filename, strerror(errno));
                pl->errors++;
                return 0;
            }
            LOG_INFO1("Currently playing \"%s\"", pl->filename);
        }
        else
        {
            LOG_INFO0("Currently playing from stdin");
            pl->current_file = stdin;
            pl->free_filename(pl->data, pl->filename);
            pl->filename = newfn;
        }

        /* Reinit sync, so that dead data from previous file is discarded */
        ogg_sync_clear(&pl->oy);
        ogg_sync_init(&pl->oy);
    }
    input_sleep ();

    while(1)
    {
        result = ogg_sync_pageout(&pl->oy, &og);
        if(result < 0)
            LOG_WARN1("Corrupt or missing data in file (%s)", pl->filename);
        else if(result > 0)
        {
            if (ogg_page_bos (&og))
            {
               if (ogg_page_serialno (&og) == pl->current_serial)
                   LOG_WARN1 ("detected duplicate serial number reading \"%s\"", pl->filename);

               pl->current_serial = ogg_page_serialno (&og);
            }
            if (input_calculate_ogg_sleep (&og) < 0)
            {
                pl->nexttrack = 1;
                return 0;
            }
            rb->len = og.header_len + og.body_len;
            rb->buf = malloc(rb->len);
            rb->aux_data = og.header_len;

            memcpy(rb->buf, og.header, og.header_len);
            memcpy(rb->buf+og.header_len, og.body, og.body_len);
            if(ogg_page_granulepos(&og)==0)
                rb->critical = 1;
            break;
        }

        /* If we got to here, we didn't have enough data. */
        buf = ogg_sync_buffer(&pl->oy, BUFSIZE);
        bytes = fread(buf,1, BUFSIZE, pl->current_file);
        if (bytes <= 0) 
        {
            if (feof(pl->current_file)) 
            {
                pl->nexttrack = 1;
                return playlist_read(pl,rb);
            } 
            else 
            {
                LOG_ERROR2("Read error from \"%s\": %s", pl->filename, strerror(errno));
                fclose(pl->current_file);
                pl->current_file=NULL;
                pl->errors++;
                return 0; 
            }
        }
        else
            ogg_sync_wrote(&pl->oy, bytes);
    }

    pl->errors=0;

    return rb->len;
}
コード例 #23
0
ファイル: framing.c プロジェクト: andreipaga/audacity
int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
  unsigned char *header=og->header;
  unsigned char *body=og->body;
  long           bodysize=og->body_len;
  int            segptr=0;

  int version=ogg_page_version(og);
  int continued=ogg_page_continued(og);
  int bos=ogg_page_bos(og);
  int eos=ogg_page_eos(og);
  ogg_int64_t granulepos=ogg_page_granulepos(og);
  int serialno=ogg_page_serialno(og);
  long pageno=ogg_page_pageno(og);
  int segments=header[26];
  
  /* clean up 'returned data' */
  {
    long lr=os->lacing_returned;
    long br=os->body_returned;

    /* body data */
    if(br){
      os->body_fill-=br;
      if(os->body_fill)
	memmove(os->body_data,os->body_data+br,os->body_fill);
      os->body_returned=0;
    }

    if(lr){
      /* segment table */
      if(os->lacing_fill-lr){
	memmove(os->lacing_vals,os->lacing_vals+lr,
		(os->lacing_fill-lr)*sizeof(*os->lacing_vals));
	memmove(os->granule_vals,os->granule_vals+lr,
		(os->lacing_fill-lr)*sizeof(*os->granule_vals));
      }
      os->lacing_fill-=lr;
      os->lacing_packet-=lr;
      os->lacing_returned=0;
    }
  }

  /* check the serial number */
  if(serialno!=os->serialno)return(-1);
  if(version>0)return(-1);

  _os_lacing_expand(os,segments+1);

  /* are we in sequence? */
  if(pageno!=os->pageno){
    int i;

    /* unroll previous partial packet (if any) */
    for(i=os->lacing_packet;i<os->lacing_fill;i++)
      os->body_fill-=os->lacing_vals[i]&0xff;
    os->lacing_fill=os->lacing_packet;

    /* make a note of dropped data in segment table */
    if(os->pageno!=-1){
      os->lacing_vals[os->lacing_fill++]=0x400;
      os->lacing_packet++;
    }

    /* are we a 'continued packet' page?  If so, we'll need to skip
       some segments */
    if(continued){
      bos=0;
      for(;segptr<segments;segptr++){
	int val=header[27+segptr];
	body+=val;
	bodysize-=val;
	if(val<255){
	  segptr++;
	  break;
	}
      }
    }
  }
  
  if(bodysize){
    _os_body_expand(os,bodysize);
    memcpy(os->body_data+os->body_fill,body,bodysize);
    os->body_fill+=bodysize;
  }

  {
    int saved=-1;
    while(segptr<segments){
      int val=header[27+segptr];
      os->lacing_vals[os->lacing_fill]=val;
      os->granule_vals[os->lacing_fill]=-1;
      
      if(bos){
	os->lacing_vals[os->lacing_fill]|=0x100;
	bos=0;
      }
      
      if(val<255)saved=os->lacing_fill;
      
      os->lacing_fill++;
      segptr++;
      
      if(val<255)os->lacing_packet=os->lacing_fill;
    }
  
    /* set the granulepos on the last granuleval of the last full packet */
    if(saved!=-1){
      os->granule_vals[saved]=granulepos;
    }

  }

  if(eos){
    os->e_o_s=1;
    if(os->lacing_fill>0)
      os->lacing_vals[os->lacing_fill-1]|=0x200;
  }

  os->pageno=pageno+1;

  return(0);
}
コード例 #24
0
ファイル: input.c プロジェクト: miksago/icecast
int input_calculate_ogg_sleep(ogg_page *page)
{
    static ogg_stream_state os;
    ogg_packet op;
    static vorbis_info vi;
    static vorbis_comment vc;
    static int need_start_pos, need_headers, state_in_use = 0;
    static int serialno = 0;
    static uint64_t offset;
    static uint64_t first_granulepos;

    if (ogg_page_granulepos(page) == -1)
    {
        LOG_ERROR0("Timing control: corrupt timing information in vorbis file, cannot stream.");
        return -1;
    }
    if (ogg_page_bos (page))
    {
        control.oldsamples = 0;

        if (state_in_use)
            ogg_stream_clear (&os);
        ogg_stream_init (&os, ogg_page_serialno (page));
        serialno = ogg_page_serialno (page);
        state_in_use = 1;
        vorbis_info_init (&vi);
        vorbis_comment_init (&vc);
        need_start_pos = 1;
        need_headers = 3;
        offset = (uint64_t)0;
    }
    if (need_start_pos)
    {
        int found_first_granulepos = 0;

        ogg_stream_pagein (&os, page);
        while (ogg_stream_packetout (&os, &op) == 1)
        {
            if (need_headers)
            {
                if (vorbis_synthesis_headerin (&vi, &vc, &op) < 0)
                {
                    LOG_ERROR0("Timing control: can't determine sample rate for input, not vorbis.");
                    control.samplerate = 0;
                    return -1;
                }
                need_headers--;
                control.samplerate = vi.rate;

                if (need_headers == 0)
                {
                    vorbis_comment_clear (&vc);
                    first_granulepos = (uint64_t)0;
                    return 0;
                }
                continue;
            }
            /* headers have been read */
            if (first_granulepos == 0 && op.granulepos > 0)
            {
                first_granulepos = op.granulepos;
                found_first_granulepos = 1;
            }
            offset += vorbis_packet_blocksize (&vi, &op) / 4;
        }
        if (!found_first_granulepos)
            return 0;

        need_start_pos = 0;
        control.oldsamples = first_granulepos - offset;
        vorbis_info_clear (&vi);
        ogg_stream_clear (&os);
        state_in_use = 0;
    }
    if (serialno != ogg_page_serialno (page))
    {
        LOG_ERROR0 ("Found page which does not belong to current logical stream");
        return -1;
    }
    control.samples = ogg_page_granulepos (page) - control.oldsamples;
    control.oldsamples = ogg_page_granulepos (page);

    control.senttime += ((uint64_t)control.samples * 1000000 /
            (uint64_t)control.samplerate);

    return 0;
}
コード例 #25
0
ファイル: vorbisfile.c プロジェクト: h16o2u9u/rtoss
/* 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;
    }
コード例 #26
0
ファイル: format_vorbis.c プロジェクト: miksago/icecast
int format_vorbis_get_buffer(format_plugin_t *self, char *data, unsigned long len, refbuf_t **buffer)
{
    char *buf;
    int i, result;
    ogg_packet op;
    char *tag;
    refbuf_t *refbuf;
    vstate_t *state = (vstate_t *)self->_state;
#ifdef USE_YP
    source_t *source;
    time_t current_time;
#endif

    if (data) {
        /* write the data to the buffer */
        buf = ogg_sync_buffer(&state->oy, len);
        memcpy(buf, data, len);
        ogg_sync_wrote(&state->oy, len);
    }

    refbuf = NULL;
    if (ogg_sync_pageout(&state->oy, &state->og) == 1) {
        refbuf = refbuf_new(state->og.header_len + state->og.body_len);
        memcpy(refbuf->data, state->og.header, state->og.header_len);
        memcpy(&refbuf->data[state->og.header_len], state->og.body, state->og.body_len);

        if (state->serialno != ogg_page_serialno(&state->og)) {
            /* this is a new logical bitstream */
            state->header = 0;
            state->packets = 0;

            /* release old headers, stream state, vorbis data */
            for (i = 0; i < MAX_HEADER_PAGES; i++) {
                if (state->headbuf[i]) {
                    refbuf_release(state->headbuf[i]);
                    state->headbuf[i] = NULL;
                }
            }
            /* Clear old stuff. Rarely but occasionally needed. */
            ogg_stream_clear(&state->os);
            vorbis_comment_clear(&state->vc);
            vorbis_info_clear(&state->vi);

            state->serialno = ogg_page_serialno(&state->og);
            ogg_stream_init(&state->os, state->serialno);
            vorbis_info_init(&state->vi);
            vorbis_comment_init(&state->vc);
        }

        if (state->header >= 0) {
            /* FIXME: In some streams (non-vorbis ogg streams), this could get
             * extras pages beyond the header. We need to collect the pages
             * here anyway, but they may have to be discarded later.
             */
            if (ogg_page_granulepos(&state->og) <= 0) {
                state->header++;
            } else {
                /* we're done caching headers */
                state->header = -1;

                /* put known comments in the stats */
                tag = vorbis_comment_query(&state->vc, "TITLE", 0);
                if (tag) stats_event(self->mount, "title", tag);
                else stats_event(self->mount, "title", "unknown");
                tag = vorbis_comment_query(&state->vc, "ARTIST", 0);
                if (tag) stats_event(self->mount, "artist", tag);
                else stats_event(self->mount, "artist", "unknown");

                /* don't need these now */
                ogg_stream_clear(&state->os);
                vorbis_comment_clear(&state->vc);
                vorbis_info_clear(&state->vi);
#ifdef USE_YP
                /* If we get an update on the mountpoint, force a
                   yp touch */
                avl_tree_rlock(global.source_tree);
                source = source_find_mount(self->mount);
                avl_tree_unlock(global.source_tree);

                if (source) {
                    /* If we get an update on the mountpoint, force a
                       yp touch */
                    current_time = time(NULL);
                    for (i=0; i<source->num_yp_directories; i++) {
                        source->ypdata[i]->yp_last_touch = current_time -
                            source->ypdata[i]->yp_touch_interval + 2;
                    }
                }
#endif

            }
        }

        /* cache header pages */
        if (state->header > 0 && state->packets < 3) {
            if(state->header > MAX_HEADER_PAGES) {
                refbuf_release(refbuf);
                ERROR1("Bad vorbis input: header is more than %d pages long", MAX_HEADER_PAGES);

                return -1;
            }
            refbuf_addref(refbuf);
            state->headbuf[state->header - 1] = refbuf;

            if (state->packets >= 0 && state->packets < 3) {
                ogg_stream_pagein(&state->os, &state->og);
                while (state->packets < 3) {
                    result = ogg_stream_packetout(&state->os, &op);
                    if (result == 0) break; /* need more data */
                    if (result < 0) {
                        state->packets = -1;
                        break;
                    }

                    state->packets++;

                    if (vorbis_synthesis_headerin(&state->vi, &state->vc, &op) < 0) {
                        state->packets = -1;
                        break;
                    }
                }
            }
        }
    }

    *buffer = refbuf;
    return 0;
}
コード例 #27
0
ファイル: oggseek.c プロジェクト: brendonjustin/vlc
static int64_t find_first_page( demux_t *p_demux, int64_t i_pos1, int64_t i_pos2,
                                logical_stream_t *p_stream,
                                int64_t *pi_kframe, int64_t *pi_frame )
{
    int64_t i_result;
    int64_t i_granulepos;
    int64_t i_bytes_to_read = i_pos2 - i_pos1 + 1;
    int64_t i_bytes_read;
    int64_t i_pages_checked = 0;
    int64_t i_packets_checked;

    demux_sys_t *p_sys  = p_demux->p_sys;

    ogg_packet op;

    seek_byte( p_demux, i_pos1 );

    if ( i_pos1 == p_stream->i_data_start )
    {
        /* set a dummy granulepos at data_start */
        *pi_kframe = p_stream->i_keyframe_offset;
        *pi_frame = p_stream->i_keyframe_offset;

        p_sys->b_page_waiting = true;
        return p_sys->i_input_position;
    }

    if ( i_bytes_to_read > OGGSEEK_BYTES_TO_READ ) i_bytes_to_read = OGGSEEK_BYTES_TO_READ;

    while ( 1 )
    {

        if ( p_sys->i_input_position >= i_pos2 )
        {
            /* we reached the end and found no pages */
            *pi_frame=-1;
            return -1;
        }

        /* read next chunk */
        if ( ! ( i_bytes_read = get_data( p_demux, i_bytes_to_read ) ) )
        {
            /* EOF */
            *pi_frame = -1;
            return -1;
        }

        i_bytes_to_read = OGGSEEK_BYTES_TO_READ;

        i_result = ogg_sync_pageseek( &p_sys->oy, &p_sys->current_page );

        if ( i_result < 0 )
        {
            /* found a page, sync to page start */
            p_sys->i_input_position -= i_result;
            i_pos1 = p_sys->i_input_position;
            continue;
        }

        if ( i_result > 0 || ( i_result == 0 && p_sys->oy.fill > 3 &&
                               ! strncmp( (char *)p_sys->oy.data, "OggS" , 4 ) ) )
        {
            i_pos1 = p_sys->i_input_position;
            break;
        }

        p_sys->i_input_position += i_bytes_read;

    };

    seek_byte( p_demux, p_sys->i_input_position );
    ogg_stream_reset( &p_stream->os );

    while( 1 )
    {

        if ( p_sys->i_input_position >= i_pos2 )
        {
            /* reached the end of the search region and nothing was found */
            *pi_frame = -1;
            return p_sys->i_input_position;
        }

        p_sys->b_page_waiting = false;

        if ( ! ( i_result = oggseek_read_page( p_demux ) ) )
        {
            /* EOF */
            *pi_frame = -1;
            return p_sys->i_input_position;
        }

        // found a page
        if ( p_stream->os.serialno != ogg_page_serialno( &p_sys->current_page ) )
        {
            /* page is not for this stream */
            p_sys->i_input_position += i_result;
            if ( ! i_pages_checked ) i_pos1 = p_sys->i_input_position;
            continue;
        }


        ogg_stream_pagein( &p_stream->os, &p_sys->current_page );

        i_pages_checked++;
        i_packets_checked = 0;

        if ( ogg_stream_packetout( &p_stream->os, &op ) > 0 )
        {
            i_packets_checked++;
        }

        if ( i_packets_checked )
        {
            i_granulepos = ogg_page_granulepos( &p_sys->current_page );

            oggseek_theora_index_entry_add( p_stream, i_granulepos, i_pos1 );

            *pi_kframe =
                i_granulepos >> p_stream->i_granule_shift;

            *pi_frame = *pi_kframe +
                i_granulepos - ( *pi_kframe << p_stream->i_granule_shift );

            p_sys->b_page_waiting = true;
            return i_pos1;

        }

        /*  -> start of next page */
        p_sys->i_input_position += i_result;
    }
}
コード例 #28
0
ファイル: ogg.c プロジェクト: Erikhht/TCPMP
static int FillQueue(ogg* p,format_reader* Reader)
{
	for (;;)
	{
		int Bytes = ogg_sync_pageseek(p->OggSync,&p->OggPage);

		if (Bytes == 0) // need more data
		{
			int Result;
			format_buffer* Buffer;

			if (!Reader->BufferAvailable && (!p->Format.SyncMode || p->Format.SyncRead<=0))
				return ERR_NEED_MORE_DATA;

			Buffer = Format_BufferRemove(Reader);
			if (!Buffer && p->Format.SyncMode && p->Format.SyncRead>0 && Format_ReadBuffer(Reader,0))
				Buffer = Format_BufferRemove(Reader);

			Result = AddBuffer(p,Buffer);
			if (Result != ERR_NONE)
				return Result;
		}
		else		
		if (Bytes < 0)
			Reader->FilePos -= Bytes;
		else
		if (Bytes > 0)
		{
			int StreamNo;
			oggstream* s;
			int Id;
			
			Reader->FilePos += Bytes;

			Id = ogg_page_serialno(&p->OggPage);
		
			DEBUG_MSG4(DEBUG_FORMAT,T("OGG Page id:%d size:%d gran:%d filepos:%d"),Id,p->OggPage.body_len,(int)ogg_page_granulepos(&p->OggPage),Reader->FilePos - Bytes);

			for (StreamNo=0;StreamNo<p->Format.StreamCount;++StreamNo)
				if (p->Format.Streams[StreamNo]->Id == Id)
					break;

			if (StreamNo==p->Format.StreamCount)
			{
				// check for restarted audio http streaming (comments changed)
				if (p->Format.StreamCount==1 && 
					p->Format.Streams[0]->Format.Type == PACKET_AUDIO &&
					p->Format.Streams[0]->LastTime>0)
				{
					StreamNo = 0;
					s = (oggstream*) p->Format.Streams[0];
					if (s->Vorbis)
					{
						// vorbis decoder have to release s->Info
						s->Stream.Format.Extra = NULL;
						s->Stream.Format.ExtraLength = 0;
						ConnectionUpdate((node*)&p->Format,FORMAT_STREAM+0,s->Stream.Pin.Node,s->Stream.Pin.No);
					}
					FreeStream(p,s);
				}
				else
				{
					s = (oggstream*) Format_AddStream(&p->Format,sizeof(oggstream));
					if (!s)	continue;
				}

				// init stream
				s->Stream.Id = Id;
				s->OggStream = ogg_stream_create(Id);
				s->NeedMorePage = 1;
				s->MediaTime = 0;
				s->Invalid = 0;
				s->Vorbis = 0;
				s->Native = 0;
				s->PacketNo = 0;

				vorbis_info_init(&s->Info);
				vorbis_comment_init(&s->Comment);
			}

			s = (oggstream*) p->Format.Streams[StreamNo];

			if (s->Invalid) // drop invalid streams
				continue;

			if (s->PacketNo>=3)
			{
				if (!s->Stream.Pin.Node) // drop unused streams
					continue;

				if (p->Format.InSeek)
				{
					// reftime needed for SeekByPacket
					if ((s->MediaTime = ogg_page_granulepos(&p->OggPage)) != -1)
					{
						// no need for GlobalOffset here
						s->Stream.LastTime = (tick_t)(s->MediaTime * s->MediaRateDen / s->MediaRateNum);
						if (s->Stream.Format.Type == PACKET_AUDIO)
						{
							s->Stream.LastTime += p->Format.AVOffset;
							if (s->Stream.LastTime < 0)
								s->Stream.LastTime = 0;
						}
					}
				}
			}

			// add page to stream
			if (ogg_stream_pagein(s->OggStream,&p->OggPage) >= 0)
			{
				if (s->PacketNo<3) // header packet needed?
				{
					int i = ogg_stream_packetout(s->OggStream,&s->OggPacket);
					if (i == 0) // stream needs more pages
						continue;
					
					if (++s->PacketNo==1) // first packet?
					{
						ogg_reference* Ref;
						const void* Data;
						int Length;

						if (i < 0)
						{
							// first header packet is a must have
							s->Invalid = 1;
							continue;
						}

						if (p->Format.UseBufferBlock)
						{
							for (Length=0,Ref=s->OggPacket.packet;Ref;Ref=Ref->next)
								Length += Ref->length;

							if (s->Stream.BufferBlockLength<Length && !Format_AllocBufferBlock(&p->Format,&s->Stream,Length))
							{
								Length = 0;
								Data = NULL;
							}
							else
							{
								for (Length=0,Ref=s->OggPacket.packet;Ref;Ref=Ref->next)
								{
									WriteBlock(&s->Stream.BufferBlock,Length,Ref->buffer->data + Ref->begin,Ref->length);
									Length += Ref->length;
								}
								Data = s->Stream.BufferBlock.Ptr;
							}
						}
						else
						{
							BufferDrop(&s->Stream.BufferMem);
							for (Ref=s->OggPacket.packet;Ref;Ref=Ref->next)
								BufferWrite(&s->Stream.BufferMem,Ref->buffer->data + Ref->begin, Ref->length, 16384);
							Data = s->Stream.BufferMem.Data;
							Length = s->Stream.BufferMem.WritePos;
						}

						if (OGMHeader(p,s,(char*)Data,Length) || SpeexHeader(p,s,(char*)Data,Length))
						{
							PacketFormatDefault(&s->Stream.Format);
							s->PacketNo = 3; // no more headers
						}
						else
						if (!VorbisHeader(p,s))
						{
							s->Invalid = 1;
							continue;
						}

						while (s->MediaRateNum > (1<<30))
						{
							s->MediaRateDen >>= 1;
							s->MediaRateNum >>= 1;
						}

						Format_PrepairStream(&p->Format,&s->Stream);
						continue;
					}
					else
					{
						assert(s->Vorbis);

						// error in second or third header packet will not cause fatal error
						vorbis_synthesis_headerin(&s->Info,&s->Comment,&s->OggPacket); 

						if (s->PacketNo == 3)
						{
							// got the three header packets: reinit codec with vorbis_info
							s->Stream.Format.Extra = &s->Info;
							s->Stream.Format.ExtraLength = -1;
							ConnectionUpdate((node*)&p->Format,FORMAT_STREAM+StreamNo,s->Stream.Pin.Node,s->Stream.Pin.No);
							SendComments(s);
						}
						continue;
					}
				}
コード例 #29
0
ファイル: ogg.cpp プロジェクト: OneSleepyDev/boswars_osd
/**
**  Load vorbis.
**
**  @param name   File name.
**  @param flags  Load flags.
**
**  @return       Returns the loaded sample.
*/
CSample *LoadVorbis(const std::string &name, int flags)
{
	CSample *sample;
	OggData *data;
	CFile *f;
	vorbis_info *info;

	f = new CFile;
	if (f->open(name.c_str(), CL_OPEN_READ) == -1) {
		fprintf(stderr, "Can't open file `%s'\n", name.c_str());
		delete f;
		return NULL;
	}

	if (flags & PlayAudioStream) {
		sample = new CSampleVorbisStream;
		data = &((CSampleVorbisStream *)sample)->Data;
	} else {
		sample = new CSampleVorbis;
		data = &((CSampleVorbis *)sample)->Data;
	}
	memset(data, 0, sizeof(*data));

	if (OggInit(f, data) || !data->audio) {
		delete sample;
		f->close();
		delete f;
		return NULL;
	}

	info = &data->vinfo;

	sample->Channels = info->channels;
	sample->SampleSize = 16;
	sample->Frequency = info->rate;

	sample->Len = 0;
	sample->Pos = 0;
	data->File = f;

	if (flags & PlayAudioStream) {
		sample->Buffer = new unsigned char[SOUND_BUFFER_SIZE];
	} else {
		unsigned char *buf;
		int pos;
		int ret;
		int total;
		ogg_page pg;
		ogg_sync_state sync;
		int i;

		// find total size
		pos = f->tell();
		ogg_sync_init(&sync);
		for (i = 0; ; ++i) {
			f->seek(-1 * i * 4096, SEEK_END);
			buf = (unsigned char *)ogg_sync_buffer(&sync, 4096);
			f->read(buf, 8192);
			ogg_sync_wrote(&sync, 8192);
			if (ogg_sync_pageout(&sync, &pg) == 1 && ogg_page_eos(&pg)) {
				total = (int)(ogg_page_granulepos(&pg) * 2 * sample->Channels);
				break;
			}
		}
		f->seek(pos, SEEK_SET);

		sample->Buffer = new unsigned char[total];
		pos = 0;

		while ((ret = VorbisStreamRead(sample, &((CSampleVorbis *)sample)->Data,
				sample->Buffer + pos, 8192))) {
			pos += ret;
		}

		sample->Len = total;
		sample->Pos = 0;

		f->close();
		delete f;
		OggFree(data);
	}

	return sample;
}
コード例 #30
0
ファイル: celtdec.c プロジェクト: EvolveLabs/electron-celt
int main(int argc, char **argv)
{
   int c;
   int option_index = 0;
   char *inFile, *outFile;
   FILE *fin, *fout=NULL;
   short out[MAX_FRAME_SIZE];
   short output[MAX_FRAME_SIZE];
   int frame_size=0, granule_frame_size=0;
   void *st=NULL;
   CELTMode *mode=NULL;
   int packet_count=0;
   int stream_init = 0;
   int quiet = 0;
   ogg_int64_t page_granule=0, last_granule=0;
   int skip_samples=0, page_nb_packets;
   struct option long_options[] =
   {
      {"help", no_argument, NULL, 0},
      {"quiet", no_argument, NULL, 0},
      {"version", no_argument, NULL, 0},
      {"version-short", no_argument, NULL, 0},
      {"rate", required_argument, NULL, 0},
      {"mono", no_argument, NULL, 0},
      {"stereo", no_argument, NULL, 0},
      {"packet-loss", required_argument, NULL, 0},
      {0, 0, 0, 0}
   };
   ogg_sync_state oy;
   ogg_page       og;
   ogg_packet     op;
   ogg_stream_state os;
   int enh_enabled;
   int nframes=2;
   int print_bitrate=0;
   int close_in=0;
   int eos=0;
   int forceMode=-1;
   int audio_size=0;
   float loss_percent=-1;
   int channels=-1;
   int rate=0;
   int extra_headers=0;
   int wav_format=0;
   int lookahead=0;
   int celt_serialno = -1;
   int firstpacket = 1;

   enh_enabled = 1;

   /*Process options*/
   while(1)
   {
      c = getopt_long (argc, argv, "hvV",
                       long_options, &option_index);
      if (c==-1)
         break;
      
      switch(c)
      {
      case 0:
         if (strcmp(long_options[option_index].name,"help")==0)
         {
            usage();
            exit(0);
         } else if (strcmp(long_options[option_index].name,"quiet")==0)
         {
            quiet = 1;
         } else if (strcmp(long_options[option_index].name,"version")==0)
         {
            version();
            exit(0);
         } else if (strcmp(long_options[option_index].name,"version-short")==0)
         {
            version_short();
            exit(0);
         } else if (strcmp(long_options[option_index].name,"mono")==0)
         {
            channels=1;
         } else if (strcmp(long_options[option_index].name,"stereo")==0)
         {
            channels=2;
         } else if (strcmp(long_options[option_index].name,"rate")==0)
         {
            rate=atoi (optarg);
         } else if (strcmp(long_options[option_index].name,"packet-loss")==0)
         {
            loss_percent = atof(optarg);
         }
         break;
      case 'h':
         usage();
         exit(0);
         break;
      case 'v':
         version();
         exit(0);
         break;
      case 'V':
         print_bitrate=1;
         break;
      case '?':
         usage();
         exit(1);
         break;
      }
   }
   if (argc-optind!=2 && argc-optind!=1)
   {
      usage();
      exit(1);
   }
   inFile=argv[optind];

   if (argc-optind==2)
      outFile=argv[optind+1];
   else
      outFile = "";
   wav_format = strlen(outFile)>=4 && (
                                       strcmp(outFile+strlen(outFile)-4,".wav")==0
                                       || strcmp(outFile+strlen(outFile)-4,".WAV")==0);
   /*Open input file*/
   if (strcmp(inFile, "-")==0)
   {
#if defined WIN32 || defined _WIN32
      _setmode(_fileno(stdin), _O_BINARY);
#endif
      fin=stdin;
   }
   else 
   {
      fin = fopen(inFile, "rb");
      if (!fin)
      {
         perror(inFile);
         exit(1);
      }
      close_in=1;
   }


   /*Init Ogg data struct*/
   ogg_sync_init(&oy);
   
   /*Main decoding loop*/
   
   while (1)
   {
      char *data;
      int i, nb_read;
      /*Get the ogg buffer for writing*/
      data = ogg_sync_buffer(&oy, 200);
      /*Read bitstream from input file*/
      nb_read = fread(data, sizeof(char), 200, fin);      
      ogg_sync_wrote(&oy, nb_read);

      /*Loop for all complete pages we got (most likely only one)*/
      while (ogg_sync_pageout(&oy, &og)==1)
      {
         if (stream_init == 0) {
            ogg_stream_init(&os, ogg_page_serialno(&og));
            stream_init = 1;
         }
	 if (ogg_page_serialno(&og) != os.serialno) {
	    /* so all streams are read. */
	    ogg_stream_reset_serialno(&os, ogg_page_serialno(&og));
	 }
         /*Add page to the bitstream*/
         ogg_stream_pagein(&os, &og);
         page_granule = ogg_page_granulepos(&og);
         page_nb_packets = ogg_page_packets(&og);
         if (page_granule>0 && frame_size)
         {
            /* FIXME: shift the granule values if --force-* is specified */
            skip_samples = frame_size*(page_nb_packets*granule_frame_size*nframes - (page_granule-last_granule))/granule_frame_size;
            if (ogg_page_eos(&og))
               skip_samples = -skip_samples;
            /*else if (!ogg_page_bos(&og))
               skip_samples = 0;*/
         } else
         {
            skip_samples = 0;
         }
         /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/
         last_granule = page_granule;
         /*Extract all available packets*/
         while (!eos && ogg_stream_packetout(&os, &op) == 1 && op.bytes>=8)
         {
	    if (!memcmp(op.packet, "CELT    ", 8)) {
	       celt_serialno = os.serialno;
	    }
	    if (celt_serialno == -1 || os.serialno != celt_serialno)
	       break;
            /*If first packet, process as CELT header*/
            if (packet_count==0)
            {
               st = process_header(&op, enh_enabled, &frame_size, &granule_frame_size, &rate, &nframes, forceMode, &channels, &lookahead, &extra_headers, quiet, &mode);
               if (!st)
                  exit(1);
               if (!nframes)
                  nframes=1;
               fout = out_file_open(outFile, rate, &channels);

            } else if (packet_count==1)
            {
               if (!quiet)
                  print_comments((char*)op.packet, op.bytes);
            } else if (packet_count<=1+extra_headers)
            {
               /* Ignore extra headers */
            } else {
               int lost=0;
               if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
                  lost=1;

               /*End of stream condition*/
               if (op.e_o_s && os.serialno == celt_serialno) /* don't care for anything except celt eos */
                  eos=1;
	       
               {
                  int ret;
                  /*Decode frame*/
                  if (!lost)
                     ret = celt_decode(st, (unsigned char*)op.packet, op.bytes, output);
                  else
                     ret = celt_decode(st, NULL, 0, output);

                  /*for (i=0;i<frame_size*channels;i++)
                    printf ("%d\n", (int)output[i]);*/

                  if (ret!=0)
                  {
                     fprintf (stderr, "Decoding error: corrupted stream?\n");
                     break;
                  }

                  if (print_bitrate) {
                     celt_int32 tmp=op.bytes;
                     char ch=13;
                     fputc (ch, stderr);
                     fprintf (stderr, "Bitrate in use: %d bytes/packet     ", tmp);
                  }
                  /*Convert to short and save to output file*/
                  if (strlen(outFile)!=0)
                  {
                     for (i=0;i<frame_size*channels;i++)
                        out[i]=le_short(output[i]);
                  } else {
                     for (i=0;i<frame_size*channels;i++)
                        out[i]=output[i];
                  }
                  {
                     int frame_offset = 0;
                     int new_frame_size = frame_size;
                     /*printf ("packet %d %d\n", packet_no, skip_samples);*/
                     /*fprintf (stderr, "packet %d %d %d\n", packet_no, skip_samples, lookahead);*/
                     if (firstpacket == 1)
                     {
                        /*printf ("chopping first packet\n");*/
                        new_frame_size -= lookahead;
                        frame_offset = lookahead;
                        firstpacket = 0;
                     }
                     if (new_frame_size>0)
                     {  
#if defined WIN32 || defined _WIN32
                        if (strlen(outFile)==0)
                           WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels);
                        else
#endif
                           fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);
                  
                        audio_size+=sizeof(short)*new_frame_size*channels;
                     }
                  }
               }
            }
            packet_count++;
         }
      }
      if (feof(fin))
         break;

   }

   if (fout && wav_format)
   {
      if (fseek(fout,4,SEEK_SET)==0)
      {
         int tmp;
         tmp = le_int(audio_size+36);
         fwrite(&tmp,4,1,fout);
         if (fseek(fout,32,SEEK_CUR)==0)
         {
            tmp = le_int(audio_size);
            fwrite(&tmp,4,1,fout);
         } else
         {
            fprintf (stderr, "First seek worked, second didn't\n");
         }
      } else {
         fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n");
      }
   }

   if (st)
   {
      celt_decoder_destroy(st);
      celt_mode_destroy(mode);
   } else {
      fprintf (stderr, "This doesn't look like a CELT file\n");
   }
   if (stream_init)
      ogg_stream_clear(&os);
   ogg_sync_clear(&oy);

#if defined WIN32 || defined _WIN32
   if (strlen(outFile)==0)
      WIN_Audio_close ();
#endif

   if (close_in)
      fclose(fin);
   if (fout != NULL)
      fclose(fout);   

   return 0;
}