/** central buffer management function 
  * @param openmaxStandComp the component handle
  * @param inputbuffer contains the input ogg file content
  * @param outputbuffer is returned along with its output pcm file content that is produced as a result of this function execution
  */
void omx_vorbisdec_component_BufferMgmtCallbackVorbis(OMX_COMPONENTTYPE *openmaxStandComp, OMX_BUFFERHEADERTYPE* inputbuffer, OMX_BUFFERHEADERTYPE* outputbuffer) {

  omx_vorbisdec_component_PrivateType* omx_vorbisdec_component_Private = openmaxStandComp->pComponentPrivate;
  OMX_U8* outputCurrBuffer;
  OMX_U32 outputLength;
  OMX_S32 result;  
  float **pcm;
  OMX_S32 samples;
  OMX_S32 i, j;
  OMX_S32 bout;
  OMX_S32 clipflag=0;
  int val;
  float  *mono;
  int eos=0;
  char *vorbis_buffer;
  ogg_int16_t convbuffer[4096];

 
  DEBUG(DEB_LEV_FULL_SEQ, "input buf %x filled len : %d \n", (int)inputbuffer->pBuffer, (int)inputbuffer->nFilledLen);  
  /** Fill up the current input buffer when a new buffer has arrived */
  if(omx_vorbisdec_component_Private->isNewBuffer) {
    omx_vorbisdec_component_Private->inputCurrBuffer = inputbuffer->pBuffer;
    omx_vorbisdec_component_Private->inputCurrLength = inputbuffer->nFilledLen;
    omx_vorbisdec_component_Private->positionInOutBuf = 0;

    DEBUG(DEB_LEV_SIMPLE_SEQ, "new -- input buf %x filled len : %d \n", (int)inputbuffer->pBuffer, (int)inputbuffer->nFilledLen);  

    /** for each new input buffer --- copy buffer content into into ogg sync state structure data */
    vorbis_buffer = ogg_sync_buffer(&omx_vorbisdec_component_Private->oy, inputbuffer->nAllocLen);
    memcpy(vorbis_buffer, inputbuffer->pBuffer, inputbuffer->nFilledLen);
    ogg_sync_wrote(&omx_vorbisdec_component_Private->oy, inputbuffer->nFilledLen);
    DEBUG(DEB_LEV_FULL_SEQ,"***** bytes read to buffer (of first header): %d \n",(int)inputbuffer->nFilledLen);
  }
  outputCurrBuffer = outputbuffer->pBuffer;
  outputLength = outputbuffer->nAllocLen;
  outputbuffer->nFilledLen = 0;
  outputbuffer->nOffset = 0;
  
  if(omx_vorbisdec_component_Private->packetNumber < 3) {
    omx_vorbisdec_component_Private->isNewBuffer = 0;
    if(omx_vorbisdec_component_Private->packetNumber == 0) {
      DEBUG(DEB_LEV_SIMPLE_SEQ, "in processing the first header buffer\n");      
      if(ogg_sync_pageout(&omx_vorbisdec_component_Private->oy, &omx_vorbisdec_component_Private->og) != 1)  {
        DEBUG(DEB_LEV_ERR, "this input stream is not an Ogg stream\n");
        return;
      }  
      ogg_stream_init(&omx_vorbisdec_component_Private->os, ogg_page_serialno(&omx_vorbisdec_component_Private->og));    
      vorbis_info_init(&omx_vorbisdec_component_Private->vi);
      vorbis_comment_init(&omx_vorbisdec_component_Private->vc);

      if(ogg_stream_pagein(&omx_vorbisdec_component_Private->os, &omx_vorbisdec_component_Private->og) < 0)  {
        DEBUG(DEB_LEV_ERR, "Error reading first page of Ogg bitstream data.\n");
        return;
      }
      if(ogg_stream_packetout(&omx_vorbisdec_component_Private->os, &omx_vorbisdec_component_Private->op) != 1)  {
        DEBUG(DEB_LEV_ERR, "Error reading initial header packet.\n");
        return;
      }
      
      omx_vorbisdec_component_Private->packetNumber++;

      if(vorbis_synthesis_headerin(&omx_vorbisdec_component_Private->vi, &omx_vorbisdec_component_Private->vc, &omx_vorbisdec_component_Private->op) < 0)  {
        DEBUG(DEB_LEV_ERR, "This Ogg bitstream does not contain Vorbis audio data\n");
        return;
      }  
    }

    while(omx_vorbisdec_component_Private->packetNumber < 3)
    {
      int result=ogg_sync_pageout(&omx_vorbisdec_component_Private->oy,&omx_vorbisdec_component_Private->og);
      if(result==0) { //break; /* Need more data */
        omx_vorbisdec_component_Private->isNewBuffer = 1;
        inputbuffer->nFilledLen = 0;
        return;
      }
      /* Don't complain about missing or corrupt data yet.  We'll
      catch it at the packet output phase */
      if(result==1) 
      {
        ogg_stream_pagein(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->og);
        /* we can ignore any errors here as they'll also become apparent at packetout */
        while(omx_vorbisdec_component_Private->packetNumber < 3) {
          result=ogg_stream_packetout(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->op);
          if(result==0)break;
          if(result<0) {
          /* Uh oh; data at some point was corrupted or missing!
            We can't tolerate that in a header.  Die. */
            DEBUG(DEB_LEV_ERR,"Corrupt secondary header.  Exiting.\n");
            break;
          }//end if
          omx_vorbisdec_component_Private->packetNumber++;
          vorbis_synthesis_headerin(&omx_vorbisdec_component_Private->vi,&omx_vorbisdec_component_Private->vc,&omx_vorbisdec_component_Private->op);
        }//end while
      }//end if
    }//end while

    omx_vorbisdec_component_Private->isNewBuffer = 1;
    inputbuffer->nFilledLen = 0;
    return;

  }

  /* A Vorbis logical bitstream begins with 3 headers. Once the last of these has been processed,
   * we can report the metadata and set up the output audio port appropriately. */
  if(omx_vorbisdec_component_Private->packetNumber == 3) {
    /* Throw the comments plus a few lines about the bitstream we're decoding */
    {
      // ptr should be declared earlier//
      char **ptr=omx_vorbisdec_component_Private->vc.user_comments;
      while(*ptr){
        DEBUG(DEB_LEV_ERR,"%s\n",*ptr);
        ++ptr;
      }
      DEBUG(DEB_LEV_ERR,"Bitstream is %d channel, %ldHz\n",omx_vorbisdec_component_Private->vi.channels,omx_vorbisdec_component_Private->vi.rate);
      DEBUG(DEB_LEV_ERR,"Encoded by: %s\n\n",omx_vorbisdec_component_Private->vc.vendor);
    }

    /* Update pAudioVorbis settings */
    omx_vorbisdec_component_Private->pAudioVorbis.nSampleRate = omx_vorbisdec_component_Private->vi.rate;
    omx_vorbisdec_component_Private->pAudioVorbis.nChannels = omx_vorbisdec_component_Private->vi.channels;

    /* Update audio port settings for this Vorbis bitstream */
    if ((omx_vorbisdec_component_Private->pAudioPcmMode.nSamplingRate != omx_vorbisdec_component_Private->pAudioVorbis.nSampleRate) ||
        (omx_vorbisdec_component_Private->pAudioPcmMode.nChannels != omx_vorbisdec_component_Private->pAudioVorbis.nChannels)) {
      omx_vorbisdec_component_Private->pAudioPcmMode.nSamplingRate = omx_vorbisdec_component_Private->pAudioVorbis.nSampleRate;
      omx_vorbisdec_component_Private->pAudioPcmMode.nChannels = omx_vorbisdec_component_Private->pAudioVorbis.nChannels;

      /*Send Port Settings changed call back*/
      (*(omx_vorbisdec_component_Private->callbacks->EventHandler))
        (openmaxStandComp,
        omx_vorbisdec_component_Private->callbackData,
        OMX_EventPortSettingsChanged, /* The command was completed */
        0,
        1, /* This is the output port index */
        NULL);
    }

    omx_vorbisdec_component_Private->convsize=inputbuffer->nFilledLen/omx_vorbisdec_component_Private->vi.channels;
    /* OK, got and parsed all three headers. Initialize the Vorbis
    packet->PCM decoder. */
    vorbis_synthesis_init(&omx_vorbisdec_component_Private->vd,&omx_vorbisdec_component_Private->vi); /* central decode state */
    vorbis_block_init(&omx_vorbisdec_component_Private->vd,&omx_vorbisdec_component_Private->vb);/* local state for most of the decode
                               so multiple block decodes can
                               proceed in parallel.  We could init
                               multiple vorbis_block structures
                               for vd here */
  }
  DEBUG(DEB_LEV_FULL_SEQ,"***** now the decoding will start *****\n");

  if(omx_vorbisdec_component_Private->isNewBuffer)  {
    omx_vorbisdec_component_Private->isNewBuffer=0;
    int result=ogg_sync_pageout(&omx_vorbisdec_component_Private->oy,&omx_vorbisdec_component_Private->og);
    DEBUG(DEB_LEV_FULL_SEQ," --->  page (read in decoding) - header len :  %ld body len : %ld \n",omx_vorbisdec_component_Private->og.header_len,omx_vorbisdec_component_Private->og.body_len);
    if(result == 0)  {
      omx_vorbisdec_component_Private->isNewBuffer = 1;
      inputbuffer->nFilledLen = 0;
      return;
    }
    if(result<0)
    { 
      /* missing or corrupt data at this page position */
      DEBUG(DEB_LEV_ERR,"Corrupt or missing data in bitstream; continuing...\n");
    }
    else {
      ogg_stream_pagein(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->og); /* can safely ignore errors at */
    }
  }
  
  result=ogg_stream_packetout(&omx_vorbisdec_component_Private->os,&omx_vorbisdec_component_Private->op);
  DEBUG(DEB_LEV_FULL_SEQ," packet length (read in decoding a particular page): %ld \n",omx_vorbisdec_component_Private->op.bytes);
  if(result == 0)  {
    omx_vorbisdec_component_Private->isNewBuffer = 1;
    inputbuffer->nFilledLen = 0;
    return;
  }
  if(result<0)
  {
    /* missing or corrupt data at this page position */
    /* no reason to complain; already complained above */
    DEBUG(DEB_LEV_ERR,"Corrupt or missing data in bitstream; continuing...\n");
  } else {
    /* we have a packet.  Decode it */
    omx_vorbisdec_component_Private->packetNumber++;

    if(vorbis_synthesis(&omx_vorbisdec_component_Private->vb,&omx_vorbisdec_component_Private->op)==0) /* test for success! */
    vorbis_synthesis_blockin(&omx_vorbisdec_component_Private->vd,&omx_vorbisdec_component_Private->vb);
    /**pcm is a multichannel float vector.  In stereo, for
      example, pcm[0] is left, and pcm[1] is right.  samples is
      the size of each channel.  Convert the float values
      (-1.<=range<=1.) to whatever PCM format and write it out */

    while((samples=vorbis_synthesis_pcmout(&omx_vorbisdec_component_Private->vd,&pcm))>0)
    {
      bout=(samples<omx_vorbisdec_component_Private->convsize?samples:omx_vorbisdec_component_Private->convsize);

      /* convert floats to 16 bit signed ints (host order) and interleave */
      for(i=0;i<omx_vorbisdec_component_Private->vi.channels;i++)
      {
        ogg_int16_t *ptr=convbuffer+i;
        mono=pcm[i];
        for(j=0;j<bout;j++)
        {
#if 1
          val=mono[j]*32767.f;
#else     /* optional dither */
          val=mono[j]*32767.f+drand48()-0.5f;
#endif
          /* might as well guard against clipping */
          if(val>32767)
          {
            val=32767;
            clipflag=1;
          }
          if(val<-32768)
          {
            val=-32768;
            clipflag=1;
          }
          *ptr=val;
          ptr+=omx_vorbisdec_component_Private->vi.channels;
        }
      }

      outputbuffer->nFilledLen=2*omx_vorbisdec_component_Private->vi.channels*bout;
      memcpy(outputCurrBuffer,(char *)convbuffer,outputbuffer->nFilledLen);

      if(clipflag) {
        DEBUG(DEB_LEV_FULL_SEQ,"Clipping in frame %ld\n",(long)(omx_vorbisdec_component_Private->vd.sequence));
      }
      vorbis_synthesis_read(&omx_vorbisdec_component_Private->vd,bout); /* tell libvorbis how many samples we actually consumed */
    }
  }
  if(ogg_page_eos(&omx_vorbisdec_component_Private->og)) {
    DEBUG(DEB_LEV_FULL_SEQ, "In %s EOS Detected\n",__func__);
    eos=1;
  }
 
  DEBUG(DEB_LEV_FULL_SEQ, "One output buffer %x len=%d is full returning\n", (int)outputbuffer->pBuffer, (int)outputbuffer->nFilledLen);  
}
Example #2
0
void test_pack(const int *pl, const int **headers){
  unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
  long inptr=0;
  long outptr=0;
  long deptr=0;
  long depacket=0;
  long granule_pos=7,pageno=0;
  int i,j,packets,pageout=0;
  int eosflag=0;
  int bosflag=0;

  ogg_stream_reset(&os_en);
  ogg_stream_reset(&os_de);
  ogg_sync_reset(&oy);

  for(packets=0;;packets++)if(pl[packets]==-1)break;

  for(i=0;i<packets;i++){
    /* construct a test packet */
    ogg_packet op;
    int len=pl[i];
    
    op.packet=data+inptr;
    op.bytes=len;
    op.e_o_s=(pl[i+1]<0?1:0);
    op.granulepos=granule_pos;

    granule_pos+=1024;

    for(j=0;j<len;j++)data[inptr++]=i+j;

    /* submit the test packet */
    ogg_stream_packetin(&os_en,&op);

    /* retrieve any finished pages */
    {
      ogg_page og;
      
      while(ogg_stream_pageout(&os_en,&og)){
	/* We have a page.  Check it carefully */

	fprintf(stderr,"%ld, ",pageno);

	if(headers[pageno]==NULL){
	  fprintf(stderr,"coded too many pages!\n");
	  exit(1);
	}

	check_page(data+outptr,headers[pageno],&og);

	outptr+=og.body_len;
	pageno++;

	/* have a complete page; submit it to sync/decode */

	{
	  ogg_page og_de;
	  ogg_packet op_de,op_de2;
	  char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
	  memcpy(buf,og.header,og.header_len);
	  memcpy(buf+og.header_len,og.body,og.body_len);
	  ogg_sync_wrote(&oy,og.header_len+og.body_len);

	  while(ogg_sync_pageout(&oy,&og_de)>0){
	    /* got a page.  Happy happy.  Verify that it's good. */
	    
	    check_page(data+deptr,headers[pageout],&og_de);
	    deptr+=og_de.body_len;
	    pageout++;

	    /* submit it to deconstitution */
	    ogg_stream_pagein(&os_de,&og_de);

	    /* packets out? */
	    while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
	      ogg_stream_packetpeek(&os_de,NULL);
	      ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
	      
	      /* verify peek and out match */
	      if(memcmp(&op_de,&op_de2,sizeof(ogg_packet))){
		fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
			depacket);
		exit(1);
	      }

	      /* verify the packet! */
	      /* check data */
	      if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
		fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
			depacket);
		exit(1);
	      }
	      /* check bos flag */
	      if(bosflag==0 && op_de.b_o_s==0){
		fprintf(stderr,"b_o_s flag not set on packet!\n");
		exit(1);
	      }
	      if(bosflag && op_de.b_o_s){
		fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
		exit(1);
	      }
	      bosflag=1;
	      depacket+=op_de.bytes;
	      
	      /* check eos flag */
	      if(eosflag){
		fprintf(stderr,"Multiple decoded packets with eos flag!\n");
		exit(1);
	      }

	      if(op_de.e_o_s)eosflag=1;

	      /* check granulepos flag */
	      if(op_de.granulepos!=-1){
		fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
	      }
	    }
	  }
	}
      }
    }
  }
  _ogg_free(data);
  if(headers[pageno]!=NULL){
    fprintf(stderr,"did not write last page!\n");
    exit(1);
  }
  if(headers[pageout]!=NULL){
    fprintf(stderr,"did not decode last page!\n");
    exit(1);
  }
  if(inptr!=outptr){
    fprintf(stderr,"encoded page data incomplete!\n");
    exit(1);
  }
  if(inptr!=deptr){
    fprintf(stderr,"decoded page data incomplete!\n");
    exit(1);
  }
  if(inptr!=depacket){
    fprintf(stderr,"decoded packet data incomplete!\n");
    exit(1);
  }
  if(!eosflag){
    fprintf(stderr,"Never got a packet with EOS set!\n");
    exit(1);
  }
  fprintf(stderr,"ok.\n");
}
Example #3
0
FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data)
{
	static const size_t OGG_BYTES_CHUNK = 8192;
	const size_t bytes_requested = *bytes;

	/*
	 * The FLAC decoding API uses pull-based reads, whereas Ogg decoding
	 * is push-based.  In libFLAC, when you ask to decode a frame, the
	 * decoder will eventually call the read callback to supply some data,
	 * but how much it asks for depends on how much free space it has in
	 * its internal buffer.  It does not try to grow its internal buffer
	 * to accomodate a whole frame because then the internal buffer size
	 * could not be limited, which is necessary in embedded applications.
	 *
	 * Ogg however grows its internal buffer until a whole page is present;
	 * only then can you get decoded data out.  So we can't just ask for
	 * the same number of bytes from Ogg, then pass what's decoded down to
	 * libFLAC.  If what libFLAC is asking for will not contain a whole
	 * page, then we will get no data from ogg_sync_pageout(), and at the
	 * same time cannot just read more data from the client for the purpose
	 * of getting a whole decoded page because the decoded size might be
	 * larger than libFLAC's internal buffer.
	 *
	 * Instead, whenever this read callback wrapper is called, we will
	 * continually request data from the client until we have at least one
	 * page, and manage pages internally so that we can send pieces of
	 * pages down to libFLAC in such a way that we obey its size
	 * requirement.  To limit the amount of callbacks, we will always try
	 * to read in enough pages to return the full number of bytes
	 * requested.
	 */
	*bytes = 0;
	while (*bytes < bytes_requested && !aspect->end_of_stream) {
		if (aspect->have_working_page) {
			if (aspect->have_working_packet) {
				size_t n = bytes_requested - *bytes;
				if ((size_t)aspect->working_packet.bytes <= n) {
					/* the rest of the packet will fit in the buffer */
					n = aspect->working_packet.bytes;
					memcpy(buffer, aspect->working_packet.packet, n);
					*bytes += n;
					buffer += n;
					aspect->have_working_packet = false;
				}
				else {
					/* only n bytes of the packet will fit in the buffer */
					memcpy(buffer, aspect->working_packet.packet, n);
					*bytes += n;
					buffer += n;
					aspect->working_packet.packet += n;
					aspect->working_packet.bytes -= n;
				}
			}
			else {
				/* try and get another packet */
				const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet);
				if (ret > 0) {
					aspect->have_working_packet = true;
					/* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */
					if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE) {
						const FLAC__byte *b = aspect->working_packet.packet;
						const unsigned header_length =
							FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
							FLAC__OGG_MAPPING_MAGIC_LENGTH +
							FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
							FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
							FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH;
						if (aspect->working_packet.bytes < (long)header_length)
							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
						b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH;
						if (memcmp(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH))
							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
						b += FLAC__OGG_MAPPING_MAGIC_LENGTH;
						aspect->version_major = (unsigned)(*b);
						b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
						aspect->version_minor = (unsigned)(*b);
						if (aspect->version_major != 1)
							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION;
						aspect->working_packet.packet += header_length;
						aspect->working_packet.bytes -= header_length;
					}
				}
				else if (ret == 0) {
					aspect->have_working_page = false;
				}
				else { /* ret < 0 */
					/* lost sync, we'll leave the working page for the next call */
					return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
				}
			}
		}
		else {
			/* try and get another page */
			const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page);
			if (ret > 0) {
				/* got a page, grab the serial number if necessary */
				if(aspect->need_serial_number) {
					aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page);
					aspect->need_serial_number = false;
				}
				if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) {
					aspect->have_working_page = true;
					aspect->have_working_packet = false;
				}
				/* else do nothing, could be a page from another stream */
			}
			else if (ret == 0) {
				/* need more data */
				const size_t ogg_bytes_to_read = max(bytes_requested - *bytes, OGG_BYTES_CHUNK);
				char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read);

				if(0 == oggbuf) {
					return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
				}
				else {
					size_t ogg_bytes_read = ogg_bytes_to_read;

					switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) {
						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
							break;
						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
							aspect->end_of_stream = true;
							break;
						case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
							return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
						default:
							FLAC__ASSERT(0);
					}

					if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) {
						/* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */
						FLAC__ASSERT(0);
						return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
					}
				}
			}
			else { /* ret < 0 */
				/* lost sync, bail out */
				return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
			}
		}
	}

	if (aspect->end_of_stream && *bytes == 0) {
		return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
	}

	return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
}
Example #4
0
/* Read the speex header. Return 0 on error. */
static int read_speex_header (struct spx_data *data)
{
	int packet_count = 0;
	int stream_init = 0;
	char *buf;
	ssize_t nb_read;
	int header_packets = 2;

	while (packet_count < header_packets) {

		/* Get the ogg buffer for writing */
		buf = ogg_sync_buffer (&data->oy, 200);

		/* Read bitstream from input file */
		nb_read = io_read (data->stream, buf, 200);

		if (nb_read < 0) {
			decoder_error (&data->error, ERROR_FATAL, 0,
					"Can't open speex file: IO error: %s",
					io_strerror(data->stream));
			return 0;
		}

		if (nb_read == 0) {
			decoder_error (&data->error, ERROR_FATAL, 0,
					"Can't open speex header");
			return 0;
		}

		ogg_sync_wrote (&data->oy, nb_read);

		/* Loop for all complete pages we got (most likely only one) */
		while (ogg_sync_pageout(&data->oy, &data->og) == 1) {

			if (stream_init == 0) {
				ogg_stream_init(&data->os,
						ogg_page_serialno(&data->og));
				stream_init = 1;
			}

			/* Add page to the bitstream */
			ogg_stream_pagein (&data->os, &data->og);

			/* Extract all available packets FIXME: EOS! */
			while (ogg_stream_packetout(&data->os, &data->op) == 1) {

				/* If first packet, process as Speex header */
				if (packet_count == 0) {
					data->st = process_header (data);

					if (!data->st) {
						ogg_stream_clear (&data->os);
						return 0;
					}

					data->rate = data->header->rate;
					data->nchannels
						= data->header->nb_channels;
					data->frames_per_packet
						= data->header->frames_per_packet;
					/*data->vbr = data->header->vbr; */

					if (!data->frames_per_packet)
						data->frames_per_packet=1;

					data->output = xmalloc (data->frame_size *
							data->nchannels *
							data->frames_per_packet *
							sizeof(int16_t));
					data->output_start = 0;
					data->output_left = 0;

					header_packets += data->header->extra_headers;
				}
				else if (packet_count == 1) {
					data->comment_packet_len
						= data->op.bytes;
					data->comment_packet = xmalloc (
							sizeof(char) *
							data->comment_packet_len);
					memcpy (data->comment_packet,
							data->op.packet,
							data->comment_packet_len);
				}

				packet_count++;
			}
		}
	}

	return 1;
}
Example #5
0
static int spx_decode (void *prv_data, char *sound_buf, int nbytes,
		struct sound_params *sound_params)
{
	struct spx_data *data = (struct spx_data *)prv_data;
  	int bytes_requested = nbytes;
	int16_t *out = (int16_t *)sound_buf;

	sound_params->channels = data->nchannels;
	sound_params->rate = data->rate;
	sound_params->fmt = SFMT_S16 | SFMT_NE;

	while (nbytes) {
		int j;

		/* First see if there is anything left in the output buffer and
		 * empty it out */
		if (data->output_left > 0) {
			int to_copy = nbytes / sizeof(int16_t);

			to_copy = MIN(data->output_left, to_copy);

			memcpy (out, data->output + data->output_start,
					to_copy * sizeof(int16_t));

			out += to_copy;
			data->output_start += to_copy;
			data->output_left -= to_copy;

			nbytes -= to_copy * sizeof(int16_t);
		}
		else if (ogg_stream_packetout (&data->os, &data->op) == 1) {
			int16_t *temp_output = data->output;

			/* Decode some more samples */

			/* Copy Ogg packet to Speex bitstream */
			speex_bits_read_from (&data->bits,
					(char*)data->op.packet, data->op.bytes);

			for (j = 0; j < data->frames_per_packet; j++) {

				/* Decode frame */
				speex_decode_int (data->st, &data->bits,
						temp_output);
				if (data->nchannels == 2)
					speex_decode_stereo_int (temp_output,
							data->frame_size,
							&data->stereo);

				speex_decoder_ctl (data->st, SPEEX_GET_BITRATE,
						&data->bitrate);
				/*data->samples_decoded += data->frame_size;*/

				temp_output += data->frame_size *
					data->nchannels;
			}

			/*logit ("Read %d bytes from page", data->frame_size *
					data->nchannels *
					data->frames_per_packet);*/

			data->output_start = 0;
			data->output_left = data->frame_size *
				data->nchannels * data->frames_per_packet;
		}
		else if (ogg_sync_pageout(&data->oy, &data->og) == 1) {

			/* Read in another ogg page */
			ogg_stream_pagein (&data->os, &data->og);
			debug ("Granulepos: %"PRId64, ogg_page_granulepos(&data->og));

		}
		else if (!io_eof(data->stream)) {
			/* Finally, pull in some more data and try again on the next pass */
			get_more_data (data);
		}
		else
			break;
	}

	return bytes_requested - nbytes;
}
UInt32 SFB::Audio::OggSpeexDecoder::_ReadAudio(AudioBufferList *bufferList, UInt32 frameCount)
{
	if(bufferList->mNumberBuffers != mFormat.mChannelsPerFrame) {
		LOGGER_WARNING("org.sbooth.AudioEngine.Decoder.OggSpeex", "_ReadAudio() called with invalid parameters");
		return 0;
	}

	UInt32 framesRead = 0;

	// Reset output buffer data size
	for(UInt32 i = 0; i < bufferList->mNumberBuffers; ++i)
		bufferList->mBuffers[i].mDataByteSize = 0;

	for(;;) {

		UInt32	framesRemaining	= frameCount - framesRead;
		UInt32	framesToSkip	= (UInt32)(bufferList->mBuffers[0].mDataByteSize / sizeof(float));
		UInt32	framesInBuffer	= (UInt32)(mBufferList->mBuffers[0].mDataByteSize / sizeof(float));
		UInt32	framesToCopy	= std::min(framesInBuffer, framesRemaining);

		// Copy data from the buffer to output
		for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i) {
			float *floatBuffer = (float *)bufferList->mBuffers[i].mData;
			memcpy(floatBuffer + framesToSkip, mBufferList->mBuffers[i].mData, framesToCopy * sizeof(float));
			bufferList->mBuffers[i].mDataByteSize += framesToCopy * sizeof(float);

			// Move remaining data in buffer to beginning
			if(framesToCopy != framesInBuffer) {
				floatBuffer = (float *)mBufferList->mBuffers[i].mData;
				memmove(floatBuffer, floatBuffer + framesToCopy, (framesInBuffer - framesToCopy) * sizeof(float));
			}

			mBufferList->mBuffers[i].mDataByteSize -= framesToCopy * sizeof(float);
		}

		framesRead += framesToCopy;

		// All requested frames were read
		if(framesRead == frameCount)
			break;

		// EOS reached
		if(mSpeexEOSReached)
			break;

		// Attempt to process the desired number of packets
		unsigned packetsDesired = 1;
		while(0 < packetsDesired && !mSpeexEOSReached) {

			// Process any packets in the current page
			while(0 < packetsDesired && !mSpeexEOSReached) {

				// Grab a packet from the streaming layer
				ogg_packet oggPacket;
				int result = ogg_stream_packetout(&mOggStreamState, &oggPacket);
				if(-1 == result) {
					LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Ogg Speex decoding error: Ogg loss of streaming");
					break;
				}

				// If result is 0, there is insufficient data to assemble a packet
				if(0 == result)
					break;

				// Otherwise, we got a valid packet for processing
				if(1 == result) {
					if(5 <= oggPacket.bytes && !memcmp(oggPacket.packet, "Speex", 5))
						mSpeexSerialNumber = mOggStreamState.serialno;

					if(-1 == mSpeexSerialNumber || mOggStreamState.serialno != mSpeexSerialNumber)
						break;

					// Ignore the following:
					//  - Speex comments in packet #2
					//  - Extra headers (optionally) in packets 3+
					if(1 != mOggPacketCount && 1 + mExtraSpeexHeaderCount <= mOggPacketCount) {
						// Detect Speex EOS
						if(oggPacket.e_o_s && mOggStreamState.serialno == mSpeexSerialNumber)
							mSpeexEOSReached = true;

						// SPEEX_GET_FRAME_SIZE is in samples
						spx_int32_t speexFrameSize;
						speex_decoder_ctl(mSpeexDecoder, SPEEX_GET_FRAME_SIZE, &speexFrameSize);
						float buffer [(2 == mFormat.mChannelsPerFrame) ? 2 * speexFrameSize : speexFrameSize];

						// Copy the Ogg packet to the Speex bitstream
						speex_bits_read_from(&mSpeexBits, (char *)oggPacket.packet, (int)oggPacket.bytes);

						// Decode each frame in the Speex packet
						for(spx_int32_t i = 0; i < mSpeexFramesPerOggPacket; ++i) {

							result = speex_decode(mSpeexDecoder, &mSpeexBits, buffer);

							// -1 indicates EOS
							if(-1 == result)
								break;
							else if(-2 == result) {
								LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Ogg Speex decoding error: possible corrupted stream");
								break;
							}

							if(0 > speex_bits_remaining(&mSpeexBits)) {
								LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Ogg Speex decoding overflow: possible corrupted stream");
								break;
							}

							// Normalize the values
							float maxSampleValue = 1u << 15;
							vDSP_vsdiv(buffer, 1, &maxSampleValue, buffer, 1, (vDSP_Length)speexFrameSize);

							// Copy the frames from the decoding buffer to the output buffer, skipping over any frames already decoded
							framesInBuffer = mBufferList->mBuffers[0].mDataByteSize / sizeof(float);
							memcpy((float *)mBufferList->mBuffers[0].mData + framesInBuffer, buffer, (size_t)speexFrameSize * sizeof(float));
							mBufferList->mBuffers[0].mDataByteSize += (size_t)speexFrameSize * sizeof(float);

							// Process stereo channel, if present
							if(2 == mFormat.mChannelsPerFrame) {
								speex_decode_stereo(buffer, speexFrameSize, mSpeexStereoState);
								vDSP_vsdiv(buffer + speexFrameSize, 1, &maxSampleValue, buffer + speexFrameSize, 1, (vDSP_Length)speexFrameSize);

								memcpy((float *)mBufferList->mBuffers[1].mData + framesInBuffer, buffer + speexFrameSize, (size_t)speexFrameSize * sizeof(float));
								mBufferList->mBuffers[1].mDataByteSize += (size_t)speexFrameSize * sizeof(float);
							}

							// Packet processing finished
							--packetsDesired;
						}
					}

					++mOggPacketCount;
				}
			}

			// Grab a new Ogg page for processing, if necessary
			if(!mSpeexEOSReached && 0 < packetsDesired) {
				while(1 != ogg_sync_pageout(&mOggSyncState, &mOggPage)) {
					// Get the ogg buffer for writing
					char *data = ogg_sync_buffer(&mOggSyncState, READ_SIZE_BYTES);

					// Read bitstream from input file
					ssize_t bytesRead = (ssize_t)GetInputSource().Read(data, READ_SIZE_BYTES);
					if(-1 == bytesRead) {
						LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Unable to read from the input file");
						break;
					}

					ogg_sync_wrote(&mOggSyncState, bytesRead);

					// No more data available from input file
					if(0 == bytesRead)
						break;
				}

				// Ensure all Ogg streams are read
				if(ogg_page_serialno(&mOggPage) != mOggStreamState.serialno)
					ogg_stream_reset_serialno(&mOggStreamState, ogg_page_serialno(&mOggPage));

				// Get the resultant Ogg page
				int result = ogg_stream_pagein(&mOggStreamState, &mOggPage);
				if(0 != result) {
					LOGGER_ERR("org.sbooth.AudioEngine.Decoder.OggSpeex", "Error reading Ogg page");
					break;
				}
			}
		}
	}

	mCurrentFrame += framesRead;

	if(0 == framesRead && mSpeexEOSReached)
		mTotalFrames = mCurrentFrame;

	return framesRead;
}
Example #7
0
BOOL getogg_open(GETSND snd, UINT8 *ptr, UINT size) {

	__OV	*ov;
	char	*buffer;
	int		bytes;
	int 	i;
	int		result;

	snd->datptr = ptr;
	snd->datsize = size;

	ov = (__OV *)_MALLOC(sizeof(__OV), "__OV");
	if (ov == NULL) {
		goto ovopn_err0;
	}
	ZeroMemory(ov, sizeof(__OV));

	buffer = ogg_sync_buffer(&ov->oy, 4096);
	bytes = snd_read(snd, buffer, 4096);
	ogg_sync_wrote(&ov->oy, bytes);

	if (ogg_sync_pageout(&ov->oy, &ov->og) != 1) {
		TRACEOUT(("Input does not appear to be an Ogg bitstream."));
		goto ovopn_err1;
	}
	ogg_stream_init(&ov->os, ogg_page_serialno(&ov->og));

	vorbis_info_init(&ov->vi);
	vorbis_comment_init(&ov->vc);
	if (ogg_stream_pagein(&ov->os, &ov->og) < 0) {
		TRACEOUT(("Error reading first page of Ogg bitstream data."));
		goto ovopn_err1;
	}

	if (ogg_stream_packetout(&ov->os, &ov->op) != 1) {
		TRACEOUT(("Error reading initial header packet."));
		goto ovopn_err1;
	}

	if (vorbis_synthesis_headerin(&ov->vi, &ov->vc, &ov->op) < 0) {
		TRACEOUT(("This Ogg bitstream does not contain Vorbis audio data."));
		goto ovopn_err1;
	}

	i = 0;
	while(i < 2) {
		while(i < 2) {
			result = ogg_sync_pageout(&ov->oy, &ov->og);
			if (result == 0) {
				break;
			}
			if (result == 1) {
				ogg_stream_pagein(&ov->os, &ov->og);
				while(i < 2) {
					result = ogg_stream_packetout(&ov->os, &ov->op);
					if (result == 0) {
						break;
					}
					if (result < 0) {
						TRACEOUT(("Corrupt secondary header. Exiting."));
						goto ovopn_err1;
					}
					vorbis_synthesis_headerin(&ov->vi, &ov->vc, &ov->op);
					i++;
				}
			}
		}
		buffer = ogg_sync_buffer(&ov->oy, 4096);
		bytes = snd_read(snd, buffer, 4096);
		if ((bytes == 0) && (i < 2)) {
			TRACEOUT(("End of file before finding all Vorbis headers!"));
			return(-1);
		}
		ogg_sync_wrote(&ov->oy, bytes);
	}

	snd->snd = ov;
	snd->dec = (GSDEC)ogg_dec;
	snd->decend = ogg_decend;
	snd->samplingrate = ov->vi.rate;
	snd->channels = ov->vi.channels;
	snd->blocksize = 4096 * 2;
	snd->blocksamples = 4096 / ov->vi.channels;
	snd->bit = 16;

	vorbis_synthesis_init(&ov->vd, &ov->vi);
	vorbis_block_init(&ov->vd, &ov->vb);
	return(SUCCESS);

ovopn_err1:
	ogg_sync_clear(&ov->oy);
	_MFREE(ov);

ovopn_err0:
	return(FAILURE);
}
Example #8
0
int main(int argc, char *argv[]) {
  daala_packet dp;
  ogg_packet op;

  int long_option_index;
  int c;
  ogg_sync_state oy;
  ogg_page og;
  ogg_stream_state to;
  daala_info di;
  daala_comment dc;
  daala_setup_info *ds;
  daala_dec_ctx *dd;
  daala_image img;
  const char *optstring = "o:r";
  struct option options [] = {
   { "output", required_argument, NULL, 'o' },
   { "raw", no_argument, NULL, 'r' }, /*Disable YUV4MPEG2 headers:*/
   { "version", no_argument, NULL, 0},
   { NULL, 0, NULL, 0 }
  };
  int frames = 0;
  int pix_fmt = 1;
  int daala_p = 0;
  int daala_processing_headers = 0;
  int stateflag = 0;
  /* single frame video buffering */
  int videobuf_ready = 0;
  int raw = 0;
  FILE *outfile = NULL;
  ogg_int32_t pic_width = 0;
  ogg_int32_t pic_height = 0;
  ogg_int32_t fps_num = 0;
  ogg_int32_t fps_denom = 0;
  FILE *infile = stdin;
  outfile = stdout;
  dd = NULL;
  ds = NULL;
  daala_log_init();
#ifdef _WIN32 /* We need to set stdin/stdout to binary mode on windows. */
  /* Beware the evil ifdef. We avoid these where we can, but this one we
     cannot. Don't add any more, you'll probably go to hell if you do. */
  _setmode(_fileno(stdin), _O_BINARY);
  _setmode(_fileno(stdout), _O_BINARY);
#endif
  /* Process option arguments. */
  while ((c = getopt_long(argc, argv, optstring, options, &long_option_index))
   != EOF) {
    switch (c) {
      case 'o': {
        if (strcmp(optarg, "-") != 0) {
          outfile = fopen(optarg, "wb");
          if (outfile == NULL) {
            fprintf(stderr, "Unable to open output file '%s'\n", optarg);
            exit(1);
          }
        }
        else {
          outfile = stdout;
        }
        break;
      }
      case 'r': {
        raw = 1;
        break;
      }
      case 0: {
        if (strcmp(options[long_option_index].name, "version") == 0) {
          version();
        }
        break;
      }
      default: usage(); break;
    }
  }
  if (optind < argc) {
    infile = fopen(argv[optind], "rb");
    if (infile == NULL) {
      fprintf(stderr, "Unable to open '%s' for extraction.\n", argv[optind]);
      exit(1);
    }
    if (++optind < argc) {
      usage();
      exit(1);
    }
  }
  /*Ok, Ogg parsing.
    The idea here is we have a bitstream that is made up of Ogg pages.
    The libogg sync layer will find them for us.
    There may be pages from several logical streams interleaved; we find the
     first daala stream and ignore any others.
    Then we pass the pages for our stream to the libogg stream layer which
     assembles our original set of packets out of them.
   start up Ogg stream synchronization layer */
  ogg_sync_init(&oy);

  /* init supporting Theora structures needed in header parsing */
  daala_comment_init(&dc);
  daala_info_init(&di);
  /*Ogg file open; parse the headers.
    Theora (like Vorbis) depends on some initial header packets for decoder
     setup and initialization.
    We retrieve these first before entering the main decode loop.*/
  /* Only interested in Daala streams */
  while (!stateflag) {
    int ret = buffer_data(infile, &oy);
    if (ret == 0) break;
    while (ogg_sync_pageout(&oy, &og) > 0) {
      int got_packet;
      ogg_stream_state test;
      /* is this a mandated initial header? If not, stop parsing */
      if (!ogg_page_bos(&og)) {
        /* don't leak the page; get it into the appropriate stream */
        queue_page(&og, &to, daala_p);
        stateflag = 1;
        break;
      }
      ogg_stream_init(&test, ogg_page_serialno(&og));
      ogg_stream_pagein(&test, &og);
      got_packet = ogg_stream_packetpeek(&test, &op);

      ogg_to_daala_packet(&dp, &op);
      /* identify the codec: try daala */
      if ((got_packet == 1) && !daala_p && (daala_processing_headers =
       daala_decode_header_in(&di, &dc, &ds, &dp)) >= 0) {
        /* it is daala -- save this stream state */
        memcpy(&to, &test, sizeof(test));
        daala_p = 1;
        /*Advance past the successfully processed header.*/
        if (daala_processing_headers) ogg_stream_packetout(&to, NULL);
      }
      else {
        /* whatever it is, we don't care about it */
        ogg_stream_clear(&test);
      }
    }
    /* fall through to non-bos page parsing */
  }
  /* we're expecting more header packets. */
  while (daala_p && daala_processing_headers) {
    int ret;
    /* look for further daala headers */
    while (daala_processing_headers &&
     (ret = ogg_stream_packetpeek(&to, &op))) {
      if (ret < 0) continue;
      ogg_to_daala_packet(&dp, &op);
      daala_processing_headers = daala_decode_header_in(&di, &dc, &ds, &dp);
      if (daala_processing_headers < 0) {
        fprintf(stderr, "Error parsing Daala stream headers; "
         "corrupt stream?\n");
        exit(1);
      }
      else if (daala_processing_headers >= 0) {
        /*Advance past the successfully processed header.*/
        ogg_stream_packetout(&to, NULL);
      }
      daala_p++;
    }
    /*Stop now so we don't fail if there aren't enough pages in a short
       stream.*/
    if (!(daala_p && daala_processing_headers)) break;
    /* The header pages/packets will arrive before anything else we
       care about, or the stream is not obeying spec */
    if (ogg_sync_pageout(&oy, &og) > 0) {
      queue_page(&og, &to, daala_p); /* demux into the appropriate stream */
    }
    else {
      if (buffer_data(infile, &oy) == 0) { /* someone needs more data */
        fprintf(stderr, "End of file while searching for codec headers.\n");
        exit(1);
      }
    }
  }
  /* and now we have it all.  initialize decoders */
  if (daala_p) {
    dump_comments(&dc);
    dd = daala_decode_create(&di, ds);
    fprintf(stderr, "Ogg logical stream %lx is Daala %dx%d %.02f fps video\n",
     to.serialno, di.pic_width, di.pic_height,
     di.timebase_numerator/(double)di.timebase_denominator*di.frame_duration);
  }
  else {
    /* tear down the partial daala setup */
    daala_info_clear(&di);
    daala_comment_clear(&dc);
  }
  /*Either way, we're done with the codec setup data.*/
  daala_setup_free(ds);
  if (!raw && outfile) {
    static const char *CHROMA_TYPES[5] = {
      "420jpeg", NULL, "422jpeg", "444", "mono"
    };
    pic_width = di.pic_width;
    pic_height = di.pic_height;
    fps_num = di.timebase_numerator;
    fps_denom = di.timebase_denominator*di.frame_duration;
    if (di.nplanes > 1) {
      /*calculate pixel_fmt based on the xdec & ydec values from one of the
        chroma planes.*/
      if (di.plane_info[1].xdec == 1 && di.plane_info[1].ydec == 1) {
        pix_fmt = 0;
      }
      else if (di.plane_info[1].xdec == 1 && di.plane_info[1].ydec == 0) {
        pix_fmt = 2;
      }
      else if (di.plane_info[1].xdec == 0 && di.plane_info[1].ydec == 0) {
        pix_fmt = 3;
      }
    }
    else {
      pix_fmt = 4;
    }
    if (pix_fmt >= 5 || pix_fmt == 1) {
      fprintf(stderr, "Unknown pixel format: %i\n", pix_fmt);
      exit(1);
    }
    /*Store header information*/
    fprintf(outfile, "YUV4MPEG2 W%d H%d F%d:%d Ip A%d:%d C%s\n",
     pic_width, pic_height, fps_num, fps_denom,
     di.pixel_aspect_numerator, di.pixel_aspect_denominator,
     CHROMA_TYPES[pix_fmt]);
  }
  /* install signal handler */
  signal(SIGINT, sigint_handler);

  /*Finally the main decode loop.

    It's one Daala packet per frame, so this is pretty straightforward if
     we're not trying to maintain sync with other multiplexed streams.

    The videobuf_ready flag is used to maintain the input buffer in the libogg
     stream state.
    If there's no output frame available at the end of the decode step, we must
     need more input data.
    We could simplify this by just using the return code on
     ogg_page_packetout(), but the flag system extends easily to the case where
     you care about more than one multiplexed stream (like with audio
     playback).
    In that case, just maintain a flag for each decoder you care about, and
     pull data when any one of them stalls.*/

  stateflag = 0; /* playback has not begun */
  /* queue any remaining pages from data we buffered but that did not
      contain headers */
  while (ogg_sync_pageout(&oy, &og) > 0) {
    queue_page(&og, &to, daala_p);
  }
  while (!got_sigint) {
    while (daala_p && !videobuf_ready) {
      if (ogg_stream_packetout(&to, &op) > 0) {
        ogg_to_daala_packet(&dp, &op);
        if (daala_decode_packet_in(dd, &dp) >= 0) {
          videobuf_ready = 1;
          frames++;
        }
      }
      else break;
    }
    if (!videobuf_ready && feof(infile)) break;
    if (!videobuf_ready) {
      /* no data yet for somebody.  Grab another page */
      buffer_data(infile, &oy);
      while (ogg_sync_pageout(&oy, &og) > 0) {
        queue_page(&og, &to, daala_p);
      }
    }
    /* dumpvideo frame, and get new one */
    else if (outfile && daala_decode_img_out(dd, &img)) {
      video_write(outfile, &img, raw);
    }
    videobuf_ready = 0;
  }
  /*Flush the output frame buffer of decoder.*/
  while (!got_sigint && daala_decode_img_out(dd, &img)) {
    video_write(outfile, &img, raw);
  }
  /* end of decoder loop -- close everything */
  if (daala_p) {
    ogg_stream_clear(&to);
    daala_decode_free(dd);
    daala_comment_clear(&dc);
    daala_info_clear(&di);
  }
  ogg_sync_clear(&oy);
  if (infile && infile != stdin) fclose(infile);
  if (outfile && outfile != stdout) fclose(outfile);
  fprintf(stderr, "\n\n%d frames\n", frames);
  fprintf(stderr, "\nDone.\n");

  return 0;
}
Example #9
0
static int play_vorbis(lua_State *lstate) {
	char buf[BLOCKSIZE];
	char *pt, *oggbuf, **comm, *mark;
	int n, sock, sr_err, port;
	const char *host, *mount;
	VORBIS_FEED *feed;
	lua_pushstring(lstate, "host");
	lua_gettable(lstate, -2);
	lua_pushstring(lstate, "port");
	lua_gettable(lstate, -3);
	lua_pushstring(lstate, "mount");
	lua_gettable(lstate, -4);
	mount = lua_tostring(lstate, -1);
	port = lua_tointeger(lstate, -2);
	host = lua_tostring(lstate, -3);
	sock = stream_connect(host, port, mount, buf, &mark);
	lua_pop(lstate, 3);
	if (sock == 0) {
		lua_pop(lstate, 1);
		return 0;
		}
	lua_pushstring(lstate, "intern");
	lua_gettable(lstate, -2);
	feed = (VORBIS_FEED *)lua_touserdata(lstate, -1);
	lua_pop(lstate, 1);
	feed->base.sock = sock;
	pthread_mutex_init(&(feed->base.thread_lock), NULL);
	pthread_cond_init(&(feed->base.data_ready), NULL);
	ogg_sync_init(&(feed->oy));
	oggbuf = ogg_sync_buffer(&(feed->oy), BLOCKSIZE);
	n = BLOCKSIZE - (mark - buf);
	memcpy(oggbuf, mark, n);
	read_sock(feed->base.sock, oggbuf + n, BLOCKSIZE - n);
	ogg_sync_wrote(&(feed->oy), BLOCKSIZE);
	if ((n = ogg_sync_pageout(&(feed->oy), &(feed->og))) != 1) {
		logmsg("out of data: %d\n", n);
		free_vorbis((FEED *)feed);
		lua_pop(lstate, 1);
		return 0;
		}
	ogg_stream_init(&(feed->os), ogg_page_serialno(&(feed->og)));
	vorbis_info_init(&(feed->vi));
	vorbis_comment_init(&(feed->vc));
	if (ogg_stream_pagein(&(feed->os), &(feed->og)) < 1) {
		logmsg("error reading first ogg page\n");
		//free_feed(feed);
		//return 0;
		}
	if (ogg_stream_packetout(&(feed->os), &(feed->op)) != 1) {
		logmsg("error reading first header packet\n");
		free_vorbis((FEED *)feed);
		lua_pop(lstate, 1);
		return 0;
		}
	if (vorbis_synthesis_headerin(&(feed->vi),
			&(feed->vc), &(feed->op)) < 0) {
		logmsg("stream is not vorbis\n");
		free_vorbis((FEED *)feed);
		lua_pop(lstate, 1);
		return 0;
		}
	vorbis_headers(feed);
	add_table(lstate, "info");
	add_table(lstate, "comments");
	comm = feed->vc.user_comments;
	while (*comm) {
		if ((pt = index(*comm, '=')) != NULL) {
			*pt++ = '\0';
			set_string(lstate, *comm, pt);
			}
		++comm;
		}
	lua_pop(lstate, 1); // comments
	feed->base.channels = feed->vi.channels;
	set_integer(lstate, "channels", feed->base.channels);
	set_integer(lstate, "srate", feed->vi.rate);
	lua_pop(lstate, 1); // info
	feed->base.cbuf = new_ringbuf(feed->vi.rate, feed->base.channels,
			BUFSECS, 0.333, 0.667);
	if (jack_sr != feed->vi.rate) {
		feed->base.converter = src_new(SRC_SINC_MEDIUM_QUALITY,
				feed->base.channels, &sr_err);
		feed->base.src_data_in = (float *)malloc(SRC_DATA_FRAMES *
				feed->base.channels * sizeof(float));
		feed->base.src_data.data_in = feed->base.src_data_in;
		feed->base.src_data_remain = 0;
		feed->base.src_data.src_ratio = jack_sr
					/ (double)feed->vi.rate;
		feed->base.src_data_out = (float *)malloc(
				(int)ceil(SRC_DATA_FRAMES *
				feed->base.channels * sizeof(float) *
				feed->base.src_data.src_ratio));
		}
	feed->base.init = 1;
	lua_pop(lstate, 1);
	pthread_create(&(feed->base.thread_id), NULL, vorbis_thread, feed);
	return 0;
	}
Example #10
0
static int ReadHeader(OGG_context *ctx, SYS_FILEHANDLE file)
{
	const size_t size = 4096;
	int theError;
	void *buffer;
	int i, serialNo;
	size_t bytes = 0;

	ogg_sync_init(&ctx->oy); /* Now we can read pages */
	/* submit a 4k block to libvorbis' Ogg layer */
	if (!ctx->eos)
	{
		buffer = ogg_sync_buffer(&ctx->oy, (int32_t)size);
		bytes = FIO_cur->fread(buffer, 1 , size, file);
		ogg_sync_wrote(&ctx->oy, (int32_t)size);
	}

	/* Get the first page. */
	theError = ogg_sync_pageout(&ctx->oy, &ctx->og);
	SYS_ASSERT(theError == 1);
	if (theError!=1)
	{
		/* error case.	Must not be Vorbis data */
		SYS_ASSERT(bytes<size);
		return 0;
	}

	/* Get the serial number and set up the rest of decode. */
	/* serialno first; use it to set up a logical stream */
	serialNo = ogg_page_serialno(&ctx->og);
	theError = ogg_stream_init(&ctx->os, serialNo);
	SYS_ASSERT(theError==0);

	/* extract the initial header from the first page and verify that the
	   Ogg bitstream is in fact Vorbis data */

	/* I handle the initial header first instead of just having the code
	   read all three Vorbis headers at once because reading the initial
	   header is an easy way to identify a Vorbis bitstream and it's
	   useful to see that functionality seperated out. */

	theError = ogg_stream_pagein(&ctx->os, &ctx->og);
	SYS_ASSERT(theError>=0);
	if (theError < 0)
	{
		/* error; stream version mismatch perhaps */
		return 0;
	}
	theError = ogg_stream_packetout(&ctx->os, &ctx->op);
	SYS_ASSERT(theError == 1);
	if (theError!=1)
	{
		/* no page? must not be vorbis */
		return 0;
	}
	theError = vorbis_synthesis_headerin(&ctx->vi, &ctx->vc, &ctx->op);
	SYS_ASSERT(theError >=0);
	if (theError < 0)
	{
		return 0;
	}
	/* At this point, we're sure we're Vorbis.	We've set up the logical
	   (Ogg) bitstream decoder.  Get the comment and codebook headers and
	   set up the Vorbis decoder */

	/* The next two packets in order are the comment and codebook headers.
	   They're likely large and may span multiple pages.  Thus we reead
	   and submit data until we get our two pacakets, watching that no
	   pages are missing.  If a page is missing, error out; losing a
	   header page is the only place where missing data is fatal. */

	i=0;
	while(i<2)
	{
		while(i<2)
		{
			int result = ogg_sync_pageout(&ctx->oy, &ctx->og);
			if (result==0)
				break; /* Need more data */
			/* Don't complain about missing or corrupt data yet.  We'll
			catch it at the packet output phase */
			if(result==1)
			{
				ogg_stream_pagein(&ctx->os, &ctx->og); /* we can ignore any errors here
				as they'll also become apparent
				at packetout */
				while(i<2)
				{
					result = ogg_stream_packetout(&ctx->os, &ctx->op);
					if (result==0)
						break;
					if (result<0)
					{
						/* Uh oh; data at some point was corrupted or missing!
						We can't tolerate that in a header.  Die. */
						SYS_ASSERT(0);
						return 0;
					}
					vorbis_synthesis_headerin(&ctx->vi, &ctx->vc, &ctx->op);
					i++;
				}
			}
		}
		buffer = ogg_sync_buffer(&ctx->oy, (int32_t)size);
		bytes  = FIO_cur->fread(buffer, 1 , size, file);
		SYS_ASSERT(!(bytes==0 && i<2));
		ogg_sync_wrote(&ctx->oy,(int32_t) size);
	}
	/* OK, got and parsed all three headers. Initialize the Vorbis
	 packet->PCM decoder. */
	vorbis_synthesis_init(&ctx->vd, &ctx->vi); /*	central decode state */
	vorbis_block_init(&ctx->vd, &ctx->vb);		/*	local state for most of the decode
													so multiple block decodes can
													proceed in parallel.  We could init
													multiple vorbis_block structures
													for vd here */

	ctx->input_size = size;
	ctx->state = 0;
	return 1;
}
Example #11
0
/* this is called for each file to process */
enum codec_status codec_run(void)
{
    int error = CODEC_ERROR;
    long action;
    intptr_t param;
    ogg_sync_state oy;
    ogg_page og;
    ogg_packet op;
    ogg_stream_state os;
    int64_t page_granule = 0;
    int stream_init = -1;
    int sample_rate = 48000;
    OpusDecoder *st = NULL;
    OpusHeader header;
    int ret;
    unsigned long strtoffset;
    int skip = 0;
    int64_t seek_target;
    uint64_t granule_pos;

    ogg_malloc_init();

    action = CODEC_ACTION_NULL;
    param = ci->id3->elapsed;
    strtoffset = ci->id3->offset;

#if defined(CPU_COLDFIRE)
    /* EMAC rounding is disabled because of MULT16_32_Q15, which will be
       inaccurate with rounding in its current incarnation */
    coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE);
#endif

    /* pre-init the ogg_sync_state buffer, so it won't need many reallocs */
    ogg_sync_init(&oy);
    oy.storage = 64*1024;
    oy.data = _ogg_malloc(oy.storage);

    /* allocate output buffer */
    uint16_t *output = (uint16_t*) _ogg_malloc(MAX_FRAME_SIZE*sizeof(uint16_t));

    ci->seek_buffer(0);
    ci->set_elapsed(0);

    goto next_page; /* need to decode header before we do anything else */

    while (1) {
        action = ci->get_command(&param);

    process_action:
        if (action == CODEC_ACTION_SEEK_TIME) {
            if (st != NULL) {
                /* calculate granule to seek to (including seek rewind) */
                seek_target = (48LL * param) + header.preskip;
                skip = MIN(seek_target, SEEK_REWIND);
                seek_target -= skip;

                LOGF("Opus seek page:%lld,%lld,%ld\n",
                    seek_target, page_granule, (long)param);
                opus_seek_page_granule(seek_target, page_granule, &oy, &os);
            }

            ci->set_elapsed(param);
            ci->seek_complete();
            param = 0;
        } else  if (action == CODEC_ACTION_HALT)
            break;

    next_page:
        /*Get the ogg buffer for writing*/
        if (get_more_data(&oy) < 1) {
            goto done;
        }

        /* Loop for all complete pages we got (most likely only one) */
        while (ogg_sync_pageout(&oy, &og) == 1) {
            if (stream_init != 0) {
                stream_init = ogg_stream_init(&os, ogg_page_serialno(&og));
                if (stream_init != 0) {
                    LOGF("Stream init failed");
                    goto done;
                }
            }

            /* Add page to the bitstream */
            ogg_stream_pagein(&os, &og);

            page_granule = ogg_page_granulepos(&og);
            granule_pos = page_granule;

            while ((ogg_stream_packetout(&os, &op) == 1) && !op.e_o_s) {
                if (op.packetno == 0){
                    /* identification header */
                
                    if (opus_header_parse(op.packet, op.bytes, &header) == 0) {
                        LOGF("Could not parse header");
                        goto done;
                    }
                    skip = header.preskip;

                    st = opus_decoder_create(sample_rate, header.channels, &ret);
                    if (ret != OPUS_OK) {
                        LOGF("opus_decoder_create failed %d", ret);
                        goto done;
                    }
                    LOGF("Decoder inited");

                    codec_set_replaygain(ci->id3);

                    opus_decoder_ctl(st, OPUS_SET_GAIN(header.gain));

                    ci->configure(DSP_SET_FREQUENCY, sample_rate);
                    ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
                    ci->configure(DSP_SET_STEREO_MODE, (header.channels == 2) ?
                        STEREO_INTERLEAVED : STEREO_MONO);

                    if (strtoffset)
                        seek_ogg_page(strtoffset);
                    else if (param) {
                        action = CODEC_ACTION_SEEK_TIME;
                        goto process_action;
                    } else {
                    /* seek buffer directly to the first audio packet to avoid 
                       allocating space for huge comment packets
                       (embedded Album Art) */
                        if (seek_opus_tags())
                            seek_ogg_page(ci->curpos);
                        else {
                            LOGF("Could not find comment header");
                            goto done;
                        }
                    }
                    LOGF("sync reset");
                    ogg_sync_reset(&oy); /* next page */
                    break;
                } else {
                    /* report progress */
                    ci->set_offset((size_t) ci->curpos);
                    ci->set_elapsed((granule_pos - header.preskip) / 48);

                    /* Decode audio packets */
                    ret = opus_decode(st, op.packet, op.bytes, output, MAX_FRAME_SIZE, 0);

                    if (ret > skip) {
                        /* part of or entire output buffer is played */
                        ret -= skip;
                        ci->pcmbuf_insert(&output[skip * header.channels], NULL, ret);
                        skip = 0;
                    } else {
                        if (ret < 0) {
                            LOGF("opus_decode failed %d", ret);
                            goto done;
                        } else if (ret == 0)
                            break;
                        else {
                            /* entire output buffer is skipped */
                            skip -= ret;
                            ret = 0;
                        }
                    }
                }
            }
        }
    }
    LOGF("Returned OK");
    error = CODEC_OK;
done:
    ogg_malloc_destroy();
    return error;
}
Example #12
0
// Decode
static int Decode(void *context, const void *dataRAW,
					size_t sizeRAW, void **ppdataPCM, size_t *sizePCM)
{
	OGG_context *ctx = (OGG_context*)context;

	*sizePCM = 0;
	*ppdataPCM = 0;

	if (!dataRAW)
		return 0;

	switch(ctx->state)
	{
		// Sync buffer
		case 0xff:
		{
			sysMemCpy(ogg_sync_buffer(&ctx->oy, (int32_t)sizeRAW), dataRAW, sizeRAW);
			ctx->input_size = sizeRAW;
			ogg_sync_wrote(&ctx->oy, (int32_t)ctx->input_size);
			ctx->state = 0;
		}
		break;
		// Sync page out
		case 0:
		{
			int result = ogg_sync_pageout(&ctx->oy, &ctx->og);
			if (result == 0)
			{
				ctx->state = 0xff;
			}
			else
			if (result < 0)
			{
				ctx->state = -1;
			}
			else
			{
				ogg_stream_pagein(&ctx->os, &ctx->og); /* can safely ignore errors at this point */
				ctx->state = 1;
			}
		}
		break;

		// Stream packet out
		case 1:
		{
			int result = ogg_stream_packetout(&ctx->os, &ctx->op);
			if (result == 0)
			{
				ctx->state = 0;
			}
			else
			if (result < 0)
			{
				ctx->state = -2;
			}
			else
			{
				/* we have a packet.	Decode it */
				if (vorbis_synthesis(&ctx->vb, &ctx->op)==0) /* test for success! */
					vorbis_synthesis_blockin(&ctx->vd, &ctx->vb);
				ctx->state = 3;
			}
		}
		break;

		// synthetis pcm out
		case 3:
		{
			size_t samples;
			float **pcm;
			samples = vorbis_synthesis_pcmout(&ctx->vd, &pcm);
			if (samples<=0)
			{
				ctx->state = 1;
			}
			else
			{
				size_t convsize = ctx->input_size / ctx->vi.channels;
				size_t bytesCount = samples < convsize ? samples : convsize;
				SYS_ASSERT(bytesCount < OGG_BUFFER_SIZE);
#ifdef SUPPORT_IEEE_AUDIO
				DeinterleaveAudio(ctx->uncompressed, pcm, ctx->vi.channels, bytesCount);
				*sizePCM = 4 * ctx->vi.channels * bytesCount;
#else
				ConvertFloatToInteger(ctx->uncompressed, pcm, ctx->vi.channels, bytesCount);
				*sizePCM = 2 * ctx->vi.channels * bytesCount;
#endif
				/* tell libvorbis how many samples we actually consumed */
				vorbis_synthesis_read(&ctx->vd, (int32_t)bytesCount);
				*ppdataPCM = ctx->uncompressed;
			}
		}
		break;

		// Invalid state
		default:
			SYS_ASSERT(0);
			return -1;
		break;

	}
	return ctx->state != 0xff ? 1 : 0;
}
Example #13
0
static gboolean
xmms_speex_init (xmms_xform_t *xform)
{
	gint pe;

	xmms_config_property_t *val;
	xmms_speex_data_t *data;
	xmms_error_t error;

	g_return_val_if_fail (xform, FALSE);

	data = g_new0 (xmms_speex_data_t, 1);
	g_return_val_if_fail (data, FALSE);

	xmms_xform_private_data_set (xform, data);

	ogg_sync_init (&data->sync_state);
	speex_bits_init (&data->speex_bits);

	/* Find the speex header */

	while (42) {
		gint ret;

		data->ogg_data = ogg_sync_buffer (&data->sync_state, 1024);
		ret = xmms_xform_read (xform, data->ogg_data, 1024, &error);
		ogg_sync_wrote (&data->sync_state, ret);

		if (ret <= 0) {
			return FALSE;
		}

		if (ogg_sync_pageout (&data->sync_state, &data->ogg_page) == 1) {
			break;
		}
	}

	ogg_stream_init (&data->stream_state, ogg_page_serialno (&data->ogg_page));

	if (ogg_stream_pagein (&data->stream_state, &data->ogg_page) < 0) {
		return FALSE;
	}

	if (ogg_stream_packetout (&data->stream_state, &data->ogg_packet) != 1) {
		return FALSE;
	}

	data->speexheader = speex_packet_to_header ((char *)data->ogg_packet.packet,
	                                            data->ogg_packet.bytes);
	data->speex_state = speex_decoder_init (speex_mode_list[data->speexheader->mode]);

	val = xmms_xform_config_lookup (xform, "perceptual_enhancer");
	pe = xmms_config_property_get_int (val);
	speex_decoder_ctl (data->speex_state, SPEEX_SET_ENH, &pe);

	ogg_sync_pageout (&data->sync_state, &data->ogg_page);
	ogg_stream_pagein (&data->stream_state, &data->ogg_page);
	ogg_stream_packetout (&data->stream_state, &data->ogg_packet);

	data->samples_buf = g_new (gint16,
	                           data->speexheader->frames_per_packet *
	                           data->speexheader->frame_size *
	                           data->speexheader->nb_channels);
	data->samples_start = data->samples_buf;
	data->samples_count = 0;

	xmms_speex_read_metadata (xform, data);

	xmms_xform_outdata_type_add (xform,
	                             XMMS_STREAM_TYPE_MIMETYPE,
	                             "audio/pcm",
	                             XMMS_STREAM_TYPE_FMT_FORMAT,
	                             XMMS_SAMPLE_FORMAT_S16,
	                             XMMS_STREAM_TYPE_FMT_CHANNELS,
	                             data->speexheader->nb_channels,
	                             XMMS_STREAM_TYPE_FMT_SAMPLERATE,
	                             data->speexheader->rate,
	                             XMMS_STREAM_TYPE_END);

	return TRUE;
}
Example #14
0
static gint
xmms_speex_read (xmms_xform_t *xform, gpointer buf, gint len,
                 xmms_error_t *err)
{
	gint ret = 0, n;
	gfloat outfloat [2000];
	gint16 *outbuf = (gint16 *) buf;
	xmms_speex_data_t *data;
	xmms_error_t error;
	SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;

	g_return_val_if_fail (xform, -1);

	data = xmms_xform_private_data_get (xform);
	g_return_val_if_fail (data, -1);

	/* convert from bytes to samples */
	len /= 2;

	/* first, copy already decoded samples over if we have any. */
	if (data->samples_count) {
		n = MIN (data->samples_count, len);

		memcpy (outbuf, data->samples_start, n * 2);
		data->samples_count -= n;

		if (!data->samples_count) {
			data->samples_start = data->samples_buf;
		} else {
			data->samples_start += n;
		}

		/* convert from samples to bytes */
		return n * 2;
	}

	while (42) {
		gint samples_per_frame;

		samples_per_frame = data->speexheader->frame_size *
		                    data->speexheader->nb_channels;

		while (ogg_stream_packetout (&data->stream_state, &data->ogg_packet) == 1) {
			gint frame;

			speex_bits_read_from (&data->speex_bits,
			                      (char *)data->ogg_packet.packet,
			                      data->ogg_packet.bytes);

			for (frame = 0; frame < data->speexheader->frames_per_packet; frame++) {
				gint cnt;

				speex_decode (data->speex_state, &data->speex_bits, outfloat);

				if (data->speexheader->nb_channels == 2) {
					speex_decode_stereo (outfloat, data->speexheader->frame_size,&stereo);
				}

				n = MIN (samples_per_frame, len);

				/* copy as many samples to the output buffer as
				 * possible.
				 */
				for (cnt = 0; cnt < n; cnt++) {
					*outbuf++ = outfloat[cnt];
					len--;
					ret += 2;
				}

				/* store the remaining samples for later use */
				for (; cnt < samples_per_frame; cnt++) {
					data->samples_buf[data->samples_count++] =
						outfloat[cnt];
				}
			}

			return ret;
		}

		/* Need more data */

		do {
			gint ret;

			data->ogg_data = ogg_sync_buffer (&data->sync_state, 200);
			ret = xmms_xform_read (xform, data->ogg_data, 200, &error);
			ogg_sync_wrote (&data->sync_state, ret);

			if (ret <= 0) {
				return ret;
			}
		} while (ogg_sync_pageout (&data->sync_state, &data->ogg_page) != 1);

		ogg_stream_pagein (&data->stream_state, &data->ogg_page);
	}
}
Example #15
0
/* main plugin handler for getting a buffer for the queue. In here we
 * just add an incoming page to the codecs and process it until either
 * more data is needed or we prodice a buffer for the queue.
 */
static refbuf_t *ogg_get_buffer (source_t *source)
{
    ogg_state_t *ogg_info = source->format->_state;
    format_plugin_t *format = source->format;
    char *data = NULL;
    int bytes = 0, total = 0;

    while (total < 15000)
    {
        while (1)
        {
            ogg_page page;
            refbuf_t *refbuf = NULL;
            ogg_codec_t *codec = ogg_info->current;

            /* if a codec has just been given a page then process it */
            if (codec && codec->process)
            {
                refbuf = codec->process (ogg_info, codec);
                if (refbuf)
                    return complete_buffer (source, refbuf);

                ogg_info->current = NULL;
            }

            if (ogg_sync_pageout (&ogg_info->oy, &page) > 0)
            {
                if (ogg_page_bos (&page))
                {
                    process_initial_page (source->format, &page);
                }
                else
                {
                    ogg_info->bos_completed = 1;
                    refbuf = process_ogg_page (ogg_info, &page);
                }
                if (ogg_info->error)
                {
                    ERROR0 ("Problem processing stream");
                    source->flags &= ~SOURCE_RUNNING;
                    return NULL;
                }
                if (refbuf)
                    return complete_buffer (source, refbuf);
                continue;
            }
            /* need more stream data */
            break;
        }
        /* we need more data to continue getting pages */
        data = ogg_sync_buffer (&ogg_info->oy, 4096);

        bytes = client_read_bytes (source->client, data, 4096);
        if (bytes <= 0)
        {
            ogg_sync_wrote (&ogg_info->oy, 0);
            source->client->schedule_ms += 50;
            break;
        }
        total += bytes;
        format->read_bytes += bytes;
        rate_add (source->in_bitrate, bytes, source->client->worker->current_time.tv_sec);
        ogg_sync_wrote (&ogg_info->oy, bytes);
    }
    return NULL;
}
Example #16
0
void VideoStreamPlaybackTheora::set_file(const String& p_file) {

	ERR_FAIL_COND(playing);
	ogg_packet op;
	th_setup_info    *ts = NULL;

	file_name = p_file;
	if (file) {
		memdelete(file);
	}
	file = FileAccess::open(p_file, FileAccess::READ);
	ERR_FAIL_COND(!file);

#ifdef THEORA_USE_THREAD_STREAMING
	thread_exit=false;
	thread_eof=false;
	//pre-fill buffer
	int to_read = ring_buffer.space_left();
	int read = file->get_buffer(read_buffer.ptr(),to_read);
	ring_buffer.write(read_buffer.ptr(),read);

	thread=Thread::create(_streaming_thread,this);

#endif

	ogg_sync_init(&oy);

	/* init supporting Vorbis structures needed in header parsing */
	vorbis_info_init(&vi);
	vorbis_comment_init(&vc);

	/* init supporting Theora structures needed in header parsing */
	th_comment_init(&tc);
	th_info_init(&ti);

	theora_eos=false;
	vorbis_eos=false;

	/* Ogg file open; parse the headers */
	/* Only interested in Vorbis/Theora streams */
	int stateflag = 0;

	int audio_track_skip=audio_track;


	while(!stateflag){
		int ret=buffer_data();
		if(ret==0)break;
		while(ogg_sync_pageout(&oy,&og)>0){
			ogg_stream_state test;

			/* is this a mandated initial header? If not, stop parsing */
			if(!ogg_page_bos(&og)){
				/* don't leak the page; get it into the appropriate stream */
				queue_page(&og);
				stateflag=1;
				break;
			}

			ogg_stream_init(&test,ogg_page_serialno(&og));
			ogg_stream_pagein(&test,&og);
			ogg_stream_packetout(&test,&op);


			/* identify the codec: try theora */
			if(!theora_p && th_decode_headerin(&ti,&tc,&ts,&op)>=0){
				/* it is theora */
				copymem(&to,&test,sizeof(test));
				theora_p=1;
			}else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){


				/* it is vorbis */
				if (audio_track_skip) {
					vorbis_info_clear(&vi);
					vorbis_comment_clear(&vc);
					ogg_stream_clear(&test);
					vorbis_info_init(&vi);
					vorbis_comment_init(&vc);

					audio_track_skip--;
				} else {
                                        copymem(&vo,&test,sizeof(test));
					vorbis_p=1;
				}
			}else{
				/* whatever it is, we don't care about it */
				ogg_stream_clear(&test);
			}
		}
		/* fall through to non-bos page parsing */
	}

	/* we're expecting more header packets. */
	while((theora_p && theora_p<3) || (vorbis_p && vorbis_p<3)){
		int ret;

		/* look for further theora headers */
		while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&to,&op))){
			if(ret<0){
				fprintf(stderr,"Error parsing Theora stream headers; "
						"corrupt stream?\n");
				clear();
				return;
			}
			if(!th_decode_headerin(&ti,&tc,&ts,&op)){
				fprintf(stderr,"Error parsing Theora stream headers; "
						"corrupt stream?\n");
				clear();
				return;
			}
			theora_p++;
		}

		/* look for more vorbis header packets */
		while(vorbis_p && (vorbis_p<3) && (ret=ogg_stream_packetout(&vo,&op))){
			if(ret<0){
				fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n");
				clear();
				return;
			}
			ret = vorbis_synthesis_headerin(&vi,&vc,&op);
			if(ret){
				fprintf(stderr,"Error parsing Vorbis stream headers; corrupt stream?\n");
				clear();
				return;
			}
			vorbis_p++;
			if(vorbis_p==3)break;
		}

		/* The header pages/packets will arrive before anything else we
		care about, or the stream is not obeying spec */

		if(ogg_sync_pageout(&oy,&og)>0){
			queue_page(&og); /* demux into the appropriate stream */
		}else{
			int ret=buffer_data(); /* someone needs more data */
			if(ret==0){
				fprintf(stderr,"End of file while searching for codec headers.\n");
				clear();
				return;
			}
		}
	}

	/* and now we have it all.  initialize decoders */
	if(theora_p){
		td=th_decode_alloc(&ti,ts);
		printf("Ogg logical stream %lx is Theora %dx%d %.02f fps",
			   to.serialno,ti.pic_width,ti.pic_height,
			   (double)ti.fps_numerator/ti.fps_denominator);
		px_fmt=ti.pixel_fmt;
		switch(ti.pixel_fmt){
		case TH_PF_420: printf(" 4:2:0 video\n"); break;
		case TH_PF_422: printf(" 4:2:2 video\n"); break;
		case TH_PF_444: printf(" 4:4:4 video\n"); break;
		case TH_PF_RSVD:
		default:
			printf(" video\n  (UNKNOWN Chroma sampling!)\n");
			break;
		}
		if(ti.pic_width!=ti.frame_width || ti.pic_height!=ti.frame_height)
			printf("  Frame content is %dx%d with offset (%d,%d).\n",
				   ti.frame_width, ti.frame_height, ti.pic_x, ti.pic_y);
		th_decode_ctl(td,TH_DECCTL_GET_PPLEVEL_MAX,&pp_level_max,
					  sizeof(pp_level_max));
		pp_level=pp_level_max;
		pp_level=0;
		th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,sizeof(pp_level));
		pp_inc=0;

		/*{
		int arg = 0xffff;
		th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MBMODE,&arg,sizeof(arg));
		th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_MV,&arg,sizeof(arg));
		th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_QI,&arg,sizeof(arg));
		arg=10;
		th_decode_ctl(td,TH_DECCTL_SET_TELEMETRY_BITS,&arg,sizeof(arg));
		}*/

		int w;
		int h;
		w=(ti.pic_x+ti.frame_width+1&~1)-(ti.pic_x&~1);
		h=(ti.pic_y+ti.frame_height+1&~1)-(ti.pic_y&~1);
		size.x = w;
		size.y = h;

		texture->create(w,h,Image::FORMAT_RGBA,Texture::FLAG_FILTER|Texture::FLAG_VIDEO_SURFACE);

	}else{
		/* tear down the partial theora setup */
		th_info_clear(&ti);
		th_comment_clear(&tc);
	}

	th_setup_free(ts);

	if(vorbis_p){
		vorbis_synthesis_init(&vd,&vi);
		vorbis_block_init(&vd,&vb);
		fprintf(stderr,"Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n",
				vo.serialno,vi.channels,vi.rate);
		//_setup(vi.channels, vi.rate);

	}else{
		/* tear down the partial vorbis setup */
		vorbis_info_clear(&vi);
		vorbis_comment_clear(&vc);
	}

	playing = false;
	buffering=true;
	time=0;
	audio_frames_wrote=0;


};
int main(int argc,char *argv[]){

  ogg_packet op;

  int long_option_index;
  int c;

  FILE *infile = stdin;
  outfile = stdout;


#ifdef _WIN32 /* We need to set stdin/stdout to binary mode on windows. */
  /* Beware the evil ifdef. We avoid these where we can, but this one we
     cannot. Don't add any more, you'll probably go to hell if you do. */
  _setmode( _fileno( stdin ), _O_BINARY );
  _setmode( _fileno( stdout ), _O_BINARY );
#endif

  /* Process option arguments. */
  while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
    switch(c){
      case 'o':
      outfile=fopen(optarg,"wb");
      if(outfile==NULL){
        fprintf(stderr,"Unable to open output file '%s'\n", optarg);
        exit(1);
      }
      break;

      default:
        usage();
    }
  }
  if(optind<argc){
    infile=fopen(argv[optind],"rb");
    if(infile==NULL){
      fprintf(stderr,"Unable to open '%s' for extraction.\n", argv[optind]);
      exit(1);
    }
    if(++optind<argc){
      usage();
      exit(1);
    }
  }


  /*
     Ok, Ogg parsing. The idea here is we have a bitstream
     that is made up of Ogg pages. The libogg sync layer will
     find them for us. There may be pages from several logical
     streams interleaved; we find the first theora stream and
     ignore any others.

     Then we pass the pages for our stream to the libogg stream
     layer which assembles our original set of packets out of
     them. It's the packets that libtheora actually knows how
     to handle.
  */

  /* start up Ogg stream synchronization layer */
  ogg_sync_init(&oy);

  /* init supporting Theora structures needed in header parsing */
  theora_comment_init(&tc);
  theora_info_init(&ti);

  /* Ogg file open; parse the headers */

  /* Vorbis and Theora both depend on some initial header packets
     for decoder setup and initialization. We retrieve these first
     before entering the main decode loop. */

  /* Only interested in Theora streams */
  while(!stateflag){
    int ret=buffer_data(infile,&oy);
    if(ret==0)break;
    while(ogg_sync_pageout(&oy,&og)>0){
      ogg_stream_state test;

      /* is this a mandated initial header? If not, stop parsing */
      if(!ogg_page_bos(&og)){
        /* don't leak the page; get it into the appropriate stream */
        queue_page(&og);
        stateflag=1;
        break;
      }

      ogg_stream_init(&test,ogg_page_serialno(&og));
      ogg_stream_pagein(&test,&og);
      ogg_stream_packetout(&test,&op);

      /* identify the codec: try theora */
      if(!theora_p && theora_decode_header(&ti,&tc,&op)>=0){
        /* it is theora -- save this stream state */
        memcpy(&to,&test,sizeof(test));
        theora_p=1;
      }else{
        /* whatever it is, we don't care about it */
        ogg_stream_clear(&test);
      }
    }
    /* fall through to non-initial page parsing */
  }

  /* we're expecting more header packets. */
  while(theora_p && theora_p<3){
    int ret;

    /* look for further theora headers */
    while(theora_p && (theora_p<3) && (ret=ogg_stream_packetout(&to,&op))){
      if(ret<0){
        fprintf(stderr,"Error parsing Theora stream headers; corrupt stream?\n");
        exit(1);
      }
      if(theora_decode_header(&ti,&tc,&op)){
        printf("Error parsing Theora stream headers; corrupt stream?\n");
        exit(1);
      }
      theora_p++;
      if(theora_p==3)break;
    }


    /* The header pages/packets will arrive before anything else we
       care about, or the stream is not obeying spec */

    if(ogg_sync_pageout(&oy,&og)>0){
      queue_page(&og); /* demux into the stream state */
    }else{
      int ret=buffer_data(infile,&oy); /* need more data */
      if(ret==0){
        fprintf(stderr,"End of file while searching for codec headers.\n");
        exit(1);
      }
    }
  }

  /* Now we have all the required headers. initialize the decoder. */
  if(theora_p){
    theora_decode_init(&td,&ti);
    fprintf(stderr,"Ogg logical stream %x is Theora %dx%d %.02f fps video\nEncoded frame content is %dx%d with %dx%d offset\n",
            to.serialno,ti.width,ti.height, (double)ti.fps_numerator/ti.fps_denominator,
            ti.frame_width, ti.frame_height, ti.offset_x, ti.offset_y);
  }else{
    /* tear down the partial theora setup */
    theora_info_clear(&ti);
    theora_comment_clear(&tc);
  }

  /* open video */
  if(theora_p)open_video();

  /* install signal handler */
  signal (SIGINT, sigint_handler);

  /* Finally the main decode loop. 

     It's one Theora packet per frame, so this is pretty 
     straightforward if we're not trying to maintain sync
     with other multiplexed streams.

     the videobuf_ready flag is used to maintain the input
     buffer in the libogg stream state. If there's no output
     frame available at the end of the decode step, we must
     need more input data. We could simplify this by just 
     using the return code on ogg_page_packetout(), but the
     flag system extends easily to the case were you care
     about more than one multiplexed stream (like with audio
     playback). In that case, just maintain a flag for each
     decoder you care about, and pull data when any one of
     them stalls.

     videobuf_time holds the presentation time of the currently
     buffered video frame. We ignore this value.
  */

  stateflag=0; /* playback has not begun */
  /* queue any remaining pages from data we buffered but that did not
      contain headers */
  while(ogg_sync_pageout(&oy,&og)>0){
    queue_page(&og);
  }
  while(!got_sigint){

    while(theora_p && !videobuf_ready){
      /* theora is one in, one out... */
      if(ogg_stream_packetout(&to,&op)>0){

        theora_decode_packetin(&td,&op);
        videobuf_granulepos=td.granulepos;
        videobuf_time=theora_granule_time(&td,videobuf_granulepos);
        videobuf_ready=1;

      }else
        break;
    }

    if(!videobuf_ready && feof(infile))break;

    if(!videobuf_ready){
      /* no data yet for somebody.  Grab another page */
      int ret=buffer_data(infile,&oy);
      while(ogg_sync_pageout(&oy,&og)>0){
        queue_page(&og);
      }
    }
    /* dumpvideo frame, and get new one */
    else video_write();

    videobuf_ready=0;
  }

  /* end of decoder loop -- close everything */

  if(theora_p){
    ogg_stream_clear(&to);
    theora_clear(&td);
    theora_comment_clear(&tc);
    theora_info_clear(&ti);
  }
  ogg_sync_clear(&oy);

  if(infile && infile!=stdin)fclose(infile);

  fprintf(stderr,
          "\r                                                              "
          "\nDone.\n");
  return(0);

}
Example #18
0
void VideoStreamPlaybackTheora::update(float p_delta) {

	if (!file)
		return;

	if (!playing || paused) {
		//printf("not playing\n");
		return;
	};



#ifdef THEORA_USE_THREAD_STREAMING
	thread_sem->post();
#endif

	//double ctime =AudioServer::get_singleton()->get_mix_time();

	//print_line("play "+rtos(p_delta));
	time+=p_delta;

	if (videobuf_time>get_time()) {
		return; //no new frames need to be produced
	}

	bool frame_done=false;
	bool audio_done=false;

	bool theora_done=false;

	while (!frame_done || (!audio_done && !vorbis_eos)) {
		//a frame needs to be produced

		ogg_packet op;
		bool audio_pending = false;


		bool no_vorbis=false;
		bool no_theora=false;


		while (vorbis_p) {
			int ret;
			float **pcm;

			bool buffer_full=false;

			/* if there's pending, decoded audio, grab it */
			if ((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0) {



				const int AUXBUF_LEN=4096;
				int to_read = ret;
				int16_t aux_buffer[AUXBUF_LEN];

				while(to_read) {

					int m = MIN(AUXBUF_LEN/vi.channels,to_read);

					int count = 0;

					for(int j=0;j<m;j++){
						for(int i=0;i<vi.channels;i++){

							int val=Math::fast_ftoi(pcm[i][j]*32767.f);
							if(val>32767)val=32767;
							if(val<-32768)val=-32768;
							aux_buffer[count++] = val;
						}
					}

					if (mix_callback) {
						int mixed = mix_callback(mix_udata,aux_buffer,m);
						to_read-=mixed;
						if (mixed!=m) { //could mix no more
							buffer_full=true;
							break;
						}
					} else {
						to_read-=m; //just pretend we sent the audio
					}


				}


				int tr = vorbis_synthesis_read(&vd, ret-to_read);

				audio_pending=true;


				if (vd.granulepos>=0) {
				//	print_line("wrote: "+itos(audio_frames_wrote)+" gpos: "+itos(vd.granulepos));
				}

				//print_line("mix audio!");

				audio_frames_wrote+=ret-to_read;

				//print_line("AGP: "+itos(vd.granulepos)+" added "+itos(ret-to_read));


			} else {

				/* no pending audio; is there a pending packet to decode? */
				if (ogg_stream_packetout(&vo,&op)>0){
					if(vorbis_synthesis(&vb,&op)==0) { /* test for success! */
						vorbis_synthesis_blockin(&vd,&vb);
					}
				} else {  /* we need more data; break out to suck in another page */
					//printf("need moar data\n");
					no_vorbis=true;
					break;
				};
			}


			audio_done = videobuf_time < (audio_frames_wrote/float(vi.rate));

			if (buffer_full)
				break;
		}

		while(theora_p && !frame_done){
			/* theora is one in, one out... */
			if(ogg_stream_packetout(&to,&op)>0){


				if(false && pp_inc){
					pp_level+=pp_inc;
					th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,
								  sizeof(pp_level));
					pp_inc=0;
				}
				/*HACK: This should be set after a seek or a gap, but we might not have
				a granulepos for the first packet (we only have them for the last
				packet on a page), so we just set it as often as we get it.
				To do this right, we should back-track from the last packet on the
				page and compute the correct granulepos for the first packet after
				a seek or a gap.*/
				if(op.granulepos>=0){
					th_decode_ctl(td,TH_DECCTL_SET_GRANPOS,&op.granulepos,
								  sizeof(op.granulepos));
				}
				ogg_int64_t videobuf_granulepos;
				if(th_decode_packetin(td,&op,&videobuf_granulepos)==0){
					videobuf_time=th_granule_time(td,videobuf_granulepos);

					//printf("frame time %f, play time %f, ready %i\n", (float)videobuf_time, get_time(), videobuf_ready);

					/* is it already too old to be useful?  This is only actually
					 useful cosmetically after a SIGSTOP.  Note that we have to
					 decode the frame even if we don't show it (for now) due to
					 keyframing.  Soon enough libtheora will be able to deal
					 with non-keyframe seeks.  */

					if(videobuf_time>=get_time()) {
						frame_done=true;
					} else{
						/*If we are too slow, reduce the pp level.*/
						pp_inc=pp_level>0?-1:0;
					}
				} else {

				}

			} else {
				no_theora=true;
				break;
			}
		}


		//print_line("no theora: "+itos(no_theora)+" theora eos: "+itos(theora_eos)+" frame done "+itos(frame_done));

#ifdef THEORA_USE_THREAD_STREAMING
		if (file && thread_eof && no_theora && theora_eos && ring_buffer.data_left()==0) {
#else
		if (file && /*!videobuf_ready && */ no_theora && theora_eos) {
#endif
			printf("video done, stopping\n");
			stop();
			return;
		};
	#if 0
		if (!videobuf_ready || audio_todo > 0){
			/* no data yet for somebody.  Grab another page */

			buffer_data();
			while(ogg_sync_pageout(&oy,&og)>0){
				queue_page(&og);
			}
		}
	#else


		if (!frame_done || !audio_done){
			//what's the point of waiting for audio to grab a page?

			buffer_data();
			while(ogg_sync_pageout(&oy,&og)>0){
				queue_page(&og);
			}
		}
	#endif
		/* If playback has begun, top audio buffer off immediately. */
		//if(stateflag) audio_write_nonblocking();

		/* are we at or past time for this video frame? */
		if(videobuf_ready && videobuf_time<=get_time()){

			//video_write();
			//videobuf_ready=0;
		} else {
			//printf("frame at %f not ready (time %f), ready %i\n", (float)videobuf_time, get_time(), videobuf_ready);
		}

		float tdiff=videobuf_time-get_time();
		/*If we have lots of extra time, increase the post-processing level.*/
		if(tdiff>ti.fps_denominator*0.25/ti.fps_numerator){
			pp_inc=pp_level<pp_level_max?1:0;
		}
		else if(tdiff<ti.fps_denominator*0.05/ti.fps_numerator){
			pp_inc=pp_level>0?-1:0;
		}

	}

	video_write();

};


void VideoStreamPlaybackTheora::play() {

	if (!playing)
		time=0;
	else {
		stop();
	}

	playing = true;
	delay_compensation=Globals::get_singleton()->get("audio/video_delay_compensation_ms");
	delay_compensation/=1000.0;


};

void VideoStreamPlaybackTheora::stop() {

	if (playing) {

		clear();
		set_file(file_name); //reset
	}
	playing = false;
	time=0;
};

bool VideoStreamPlaybackTheora::is_playing() const {

	return playing;
};

void VideoStreamPlaybackTheora::set_paused(bool p_paused) {

	paused=p_paused;
	//pau = !p_paused;
};

bool VideoStreamPlaybackTheora::is_paused(bool p_paused) const {

	return paused;
};

void VideoStreamPlaybackTheora::set_loop(bool p_enable) {

};

bool VideoStreamPlaybackTheora::has_loop() const {

	return false;
};

float VideoStreamPlaybackTheora::get_length() const {

	return 0;
};

String VideoStreamPlaybackTheora::get_stream_name() const {

	return "";
};

int VideoStreamPlaybackTheora::get_loop_count() const {

	return 0;
};

float VideoStreamPlaybackTheora::get_pos() const {

	return get_time();
};

void VideoStreamPlaybackTheora::seek_pos(float p_time) {

	// no
};

void VideoStreamPlaybackTheora::set_mix_callback(AudioMixCallback p_callback,void *p_userdata) {

	mix_callback=p_callback;
	mix_udata=p_userdata;
}
bool SFB::Audio::OggSpeexDecoder::_Open(CFErrorRef *error)
{
	// Initialize Ogg data struct
	ogg_sync_init(&mOggSyncState);

	// Get the ogg buffer for writing
	char *data = ogg_sync_buffer(&mOggSyncState, READ_SIZE_BYTES);

	// Read bitstream from input file
	ssize_t bytesRead = (ssize_t)GetInputSource().Read(data, READ_SIZE_BYTES);
	if(-1 == bytesRead) {
		if(error) {
			SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” could not be read."), ""));
			SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Read error"), ""));
			SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("Unable to read from the input file."), ""));

			*error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion);
		}

		ogg_sync_destroy(&mOggSyncState);
		return false;
	}

	// Tell the sync layer how many bytes were written to its internal buffer
	int result = ogg_sync_wrote(&mOggSyncState, bytesRead);
	if(-1 == result) {
		if(error) {
			SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), ""));
			SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), ""));
			SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			*error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion);
		}

		ogg_sync_destroy(&mOggSyncState);
		return false;
	}

	// Turn the data we wrote into an ogg page
	result = ogg_sync_pageout(&mOggSyncState, &mOggPage);
	if(1 != result) {
		if(error) {
			SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), ""));
			SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), ""));
			SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			*error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion);
		}

		ogg_sync_destroy(&mOggSyncState);
		return false;
	}

	// Initialize the stream and grab the serial number
	ogg_stream_init(&mOggStreamState, ogg_page_serialno(&mOggPage));

	// Get the first Ogg page
	result = ogg_stream_pagein(&mOggStreamState, &mOggPage);
	if(0 != result) {
		if(error) {
			SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), ""));
			SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), ""));
			SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			*error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion);
		}

		ogg_sync_destroy(&mOggSyncState);
		return false;
	}

	// Get the first packet (should be the header) from the page
	ogg_packet op;
	result = ogg_stream_packetout(&mOggStreamState, &op);
	if(1 != result) {
		if(error) {
			SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg file."), ""));
			SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg file"), ""));
			SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			*error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion);
		}

		ogg_sync_destroy(&mOggSyncState);
		return false;
	}

	if(op.bytes >= 5 && !memcmp(op.packet, "Speex", 5))
		mSpeexSerialNumber = mOggStreamState.serialno;

	++mOggPacketCount;

	// Convert the packet to the Speex header
	SpeexHeader *header = speex_packet_to_header((char *)op.packet, (int)op.bytes);
	if(nullptr == header) {
		if(error) {
			SFB::CFString description(CFCopyLocalizedString(CFSTR("The file “%@” is not a valid Ogg Speex file."), ""));
			SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Not an Ogg Speex file"), ""));
			SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			*error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotRecognizedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion);
		}

		ogg_sync_destroy(&mOggSyncState);
		return false;
	}
	else if(SPEEX_NB_MODES <= header->mode) {
		if(error) {
			SFB::CFString description(CFCopyLocalizedString(CFSTR("The Speex mode in the file “%@” is not supported."), ""));
			SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file mode"), ""));
			SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("This file may have been encoded with a newer version of Speex."), ""));

			*error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotSupportedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion);
		}

		speex_header_free(header);
		header = nullptr;
		ogg_sync_destroy(&mOggSyncState);
		return false;
	}

	const SpeexMode *mode = speex_lib_get_mode(header->mode);
	if(mode->bitstream_version != header->mode_bitstream_version) {
		if(error) {
			SFB::CFString description(CFCopyLocalizedString(CFSTR("The Speex version in the file “%@” is not supported."), ""));
			SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Unsupported Ogg Speex file version"), ""));
			SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("This file was encoded with a different version of Speex."), ""));

			*error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::FileFormatNotSupportedError, description, mInputSource->GetURL(), failureReason, recoverySuggestion);
		}

		speex_header_free(header);
		header = nullptr;
		ogg_sync_destroy(&mOggSyncState);
		return false;
	}

	// Initialize the decoder
	mSpeexDecoder = speex_decoder_init(mode);
	if(nullptr== mSpeexDecoder) {
		if(error) {
			SFB::CFString description(CFCopyLocalizedString(CFSTR("Unable to initialize the Speex decoder."), ""));
			SFB::CFString failureReason(CFCopyLocalizedString(CFSTR("Error initializing Speex decoder"), ""));
			SFB::CFString recoverySuggestion(CFCopyLocalizedString(CFSTR("An unknown error occurred."), ""));

			*error = CreateErrorForURL(Decoder::ErrorDomain, Decoder::InputOutputError, description, mInputSource->GetURL(), failureReason, recoverySuggestion);
		}

		speex_header_free(header);
		header = nullptr;
		ogg_sync_destroy(&mOggSyncState);
		return false;
	}

	speex_decoder_ctl(mSpeexDecoder, SPEEX_SET_SAMPLING_RATE, &header->rate);

	mSpeexFramesPerOggPacket = (0 == header->frames_per_packet ? 1 : header->frames_per_packet);
	mExtraSpeexHeaderCount = (UInt32)header->extra_headers;

	// Initialize the speex bit-packing data structure
	speex_bits_init(&mSpeexBits);

	// Initialize the stereo mode
	mSpeexStereoState = speex_stereo_state_init();

	if(2 == header->nb_channels) {
		SpeexCallback callback;
		callback.callback_id = SPEEX_INBAND_STEREO;
		callback.func = speex_std_stereo_request_handler;
		callback.data = mSpeexStereoState;
		speex_decoder_ctl(mSpeexDecoder, SPEEX_SET_HANDLER, &callback);
	}

	// Canonical Core Audio format
	mFormat.mFormatID			= kAudioFormatLinearPCM;
	mFormat.mFormatFlags		= kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved;

	mFormat.mBitsPerChannel		= 8 * sizeof(float);
	mFormat.mSampleRate			= header->rate;
	mFormat.mChannelsPerFrame	= (UInt32)header->nb_channels;

	mFormat.mBytesPerPacket		= (mFormat.mBitsPerChannel / 8);
	mFormat.mFramesPerPacket	= 1;
	mFormat.mBytesPerFrame		= mFormat.mBytesPerPacket * mFormat.mFramesPerPacket;

	mFormat.mReserved			= 0;

	// Set up the source format
	mSourceFormat.mFormatID				= 'SPEE';

	mSourceFormat.mSampleRate			= header->rate;
	mSourceFormat.mChannelsPerFrame		= (UInt32)header->nb_channels;

	switch(header->nb_channels) {
		case 1:		mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Mono);		break;
		case 2:		mChannelLayout = ChannelLayout::ChannelLayoutWithTag(kAudioChannelLayoutTag_Stereo);	break;
	}

	speex_header_free(header);
	header = nullptr;

	// Allocate the buffer list
	spx_int32_t speexFrameSize = 0;
	speex_decoder_ctl(mSpeexDecoder, SPEEX_GET_FRAME_SIZE, &speexFrameSize);

	if(!mBufferList.Allocate(mFormat, (UInt32)speexFrameSize)) {
		if(error)
			*error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainPOSIX, ENOMEM, nullptr);

		speex_stereo_state_destroy(mSpeexStereoState);
		mSpeexStereoState = nullptr;
		speex_decoder_destroy(mSpeexDecoder);
		mSpeexDecoder = nullptr;
		speex_bits_destroy(&mSpeexBits);

		ogg_sync_destroy(&mOggSyncState);
		return false;
	}

	for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i)
		mBufferList->mBuffers[i].mDataByteSize = 0;

	return true;
}
bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) {
	close();

	_fileStream = stream;

	// start up Ogg stream synchronization layer
	ogg_sync_init(&_oggSync);

	// init supporting Vorbis structures needed in header parsing
	vorbis_info_init(&_vorbisInfo);
	vorbis_comment vorbisComment;
	vorbis_comment_init(&vorbisComment);

	// init supporting Theora structures needed in header parsing
	th_info theoraInfo;
	th_info_init(&theoraInfo);
	th_comment theoraComment;
	th_comment_init(&theoraComment);
	th_setup_info *theoraSetup = 0;

	uint theoraPackets = 0, vorbisPackets = 0;

	// Ogg file open; parse the headers
	// Only interested in Vorbis/Theora streams
	bool foundHeader = false;
	while (!foundHeader) {
		int ret = bufferData();

		if (ret == 0)
			break; // FIXME: Shouldn't this error out?

		while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
			ogg_stream_state test;

			// is this a mandated initial header? If not, stop parsing
			if (!ogg_page_bos(&_oggPage)) {
				// don't leak the page; get it into the appropriate stream
				queuePage(&_oggPage);
				foundHeader = true;
				break;
			}

			ogg_stream_init(&test, ogg_page_serialno(&_oggPage));
			ogg_stream_pagein(&test, &_oggPage);
			ogg_stream_packetout(&test, &_oggPacket);

			// identify the codec: try theora
			if (theoraPackets == 0 && th_decode_headerin(&theoraInfo, &theoraComment, &theoraSetup, &_oggPacket) >= 0) {
				// it is theora
				memcpy(&_theoraOut, &test, sizeof(test));
				theoraPackets = 1;
				_hasVideo = true;
			} else if (vorbisPackets == 0 && vorbis_synthesis_headerin(&_vorbisInfo, &vorbisComment, &_oggPacket) >= 0) {
				// it is vorbis
				memcpy(&_vorbisOut, &test, sizeof(test));
				vorbisPackets = 1;
				_hasAudio = true;
			} else {
				// whatever it is, we don't care about it
				ogg_stream_clear(&test);
			}
		}
		// fall through to non-bos page parsing
	}

	// we're expecting more header packets.
	while ((theoraPackets && theoraPackets < 3) || (vorbisPackets && vorbisPackets < 3)) {
		int ret;

		// look for further theora headers
		while (theoraPackets && (theoraPackets < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) {
			if (ret < 0)
				error("Error parsing Theora stream headers; corrupt stream?");

			if (!th_decode_headerin(&theoraInfo, &theoraComment, &theoraSetup, &_oggPacket))
				error("Error parsing Theora stream headers; corrupt stream?");

			theoraPackets++;
		}

		// look for more vorbis header packets
		while (vorbisPackets && (vorbisPackets < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) {
			if (ret < 0)
				error("Error parsing Vorbis stream headers; corrupt stream?");

			if (vorbis_synthesis_headerin(&_vorbisInfo, &vorbisComment, &_oggPacket))
				error("Error parsing Vorbis stream headers; corrupt stream?");

			vorbisPackets++;

			if (vorbisPackets == 3)
				break;
		}

		// The header pages/packets will arrive before anything else we
		// care about, or the stream is not obeying spec

		if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) {
			queuePage(&_oggPage); // demux into the appropriate stream
		} else {
			ret = bufferData(); // someone needs more data

			if (ret == 0)
				error("End of file while searching for codec headers.");
		}
	}

	// And now we have it all. Initialize decoders next
	if (_hasVideo) {
		_videoTrack = new TheoraVideoTrack(getDefaultHighColorFormat(), theoraInfo, theoraSetup);
		addTrack(_videoTrack);
	}

	th_info_clear(&theoraInfo);
	th_comment_clear(&theoraComment);
	th_setup_free(theoraSetup);

	if (_hasAudio) {
		_audioTrack = new VorbisAudioTrack(_soundType, _vorbisInfo);

		// Get enough audio data to start us off
		while (!_audioTrack->hasAudio()) {
			// Queue more data
			bufferData();
			while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0)
				queuePage(&_oggPage);

			queueAudio();
		}

		addTrack(_audioTrack);
	}

	vorbis_comment_clear(&vorbisComment);

	return true;
}
Example #21
0
static UINT ogg_dec(GETSND snd, short *dst) {

	__OV	*ov;
	int		result;
	char	*buffer;
	int		bytes;
	float	**pcm;
	int		samples;
	int		i;
	int		j;
	float	*mono;
	short	*ptr;
	long	val;

	ov = (__OV *)snd->snd;

	do {
		switch(ov->phase) {
			case OVPHASE_HEAD:
				result = ogg_sync_pageout(&ov->oy, &ov->og);
				if (result > 0) {
					ogg_stream_pagein(&ov->os, &ov->og);
					ov->phase = OVPHASE_STREAMIN;
				}
				else if (result == 0) {
					ov->phase = OVPHASE_NEXT;
				}
				else {
					TRACEOUT(("Corrupt or missing data in bitstream"));
				}
				break;

			case OVPHASE_STREAMIN:
				result = ogg_stream_packetout(&ov->os, &ov->op);
				if (result > 0) {
					if (vorbis_synthesis(&ov->vb, &ov->op) == 0) {
						vorbis_synthesis_blockin(&ov->vd, &ov->vb);
					}
					ov->phase = OVPHASE_GETPCM;
				}
				else if (result == 0) {
					if (!ogg_page_eos(&ov->og)) {
						ov->phase = OVPHASE_NEXT;
					}
					else {
						ov->phase = OVPHASE_CLOSE;
					}
				}
				break;

			case OVPHASE_GETPCM:
				samples = vorbis_synthesis_pcmout(&ov->vd, &pcm);
				if (samples > 0) {
					if (samples > (int)snd->blocksamples) {
						samples = (int)snd->blocksamples;
					}
					for (i=0; i<ov->vi.channels; i++) {
						ptr = dst + i;
						mono = pcm[i];
						for (j=0; j<samples; j++) {
							val = (long)(mono[j] * 32767.f);
							if (val > 32767) {
								val = 32767;
							}
							if (val < -32768) {
								val = -32768;
							}
							*ptr = (short)val;
							ptr += ov->vi.channels;
						}
					}
					vorbis_synthesis_read(&ov->vd, samples);
					return((UINT)samples);
				}
				ov->phase = OVPHASE_STREAMIN;
				break;

			case OVPHASE_NEXT:
				buffer = ogg_sync_buffer(&ov->oy, 4096);
				bytes = snd_read(snd, buffer, 4096);
				ogg_sync_wrote(&ov->oy, bytes);
#if 1
				ov->phase = OVPHASE_HEAD;
#else
				if (bytes) {
					ov->phase = OVPHASE_HEAD;
				}
				else {
					ov->phase = OVPHASE_CLOSE;
				}
#endif
				break;

			case OVPHASE_CLOSE:
				return(0);
		}
	} while(1);
}
Example #22
0
int sndogg_open(SMIXTRACK trk) {

	__OV	*ov;
	char	*buffer;
	UINT	r;
	int		bytes;
	int 	i;
	int		result;

	ov = (__OV *)_MALLOC(sizeof(__OV), "__OV");
	if (ov == NULL) {
		goto ovopn_next;
	}
	ZeroMemory(ov, sizeof(__OV));

	r = sndmix_dataload(trk, trk->maxdatas);
	if ((r == (UINT)-1) || (r == 0)) {
		goto ovopn_next2;
	}
	buffer = ogg_sync_buffer(&ov->oy, trk->maxdatas);
	CopyMemory(buffer, trk->data, r);
	ogg_sync_wrote(&ov->oy, (int)r);

	if (ogg_sync_pageout(&ov->oy, &ov->og) != 1) {
		TRACEOUT(("Input does not appear to be an Ogg bitstream."));
		goto ovopn_next2;
	}
	ogg_stream_init(&ov->os, ogg_page_serialno(&ov->og));
	sndmix_datatrash(trk, (UINT)-1);

	vorbis_info_init(&ov->vi);
	vorbis_comment_init(&ov->vc);
	if (ogg_stream_pagein(&ov->os, &ov->og) < 0) {
		TRACEOUT(("Error reading first page of Ogg bitstream data."));
		goto ovopn_err1;
	}

	if (ogg_stream_packetout(&ov->os, &ov->op) != 1) {
		TRACEOUT(("Error reading initial header packet."));
		goto ovopn_err1;
	}

	if (vorbis_synthesis_headerin(&ov->vi, &ov->vc, &ov->op) < 0) {
		TRACEOUT(("This Ogg bitstream does not contain Vorbis audio data."));
		goto ovopn_err1;
	}

	i = 0;
	while(i < 2) {
		while(i < 2) {
			result = ogg_sync_pageout(&ov->oy, &ov->og);
			if (result == 0) {
				break;
			}
			if (result == 1) {
				ogg_stream_pagein(&ov->os, &ov->og);
				while(i < 2) {
					result = ogg_stream_packetout(&ov->os, &ov->op);
					if (result == 0) {
						break;
					}
					if (result < 0) {
						TRACEOUT(("Corrupt secondary header. Exiting."));
						goto ovopn_err1;
					}
					vorbis_synthesis_headerin(&ov->vi, &ov->vc, &ov->op);
					i++;
				}
			}
		}
		buffer = ogg_sync_buffer(&ov->oy, 4096);
		bytes = sndmix_dataread(trk, buffer, 4096);
		if ((bytes == 0) && (i < 2)) {
			TRACEOUT(("End of file before finding all Vorbis headers!"));
			return(SNDMIX_FAILURE);
		}
		ogg_sync_wrote(&ov->oy, bytes);
	}

	trk->snd = ov;
	trk->dec = (DECFN)ogg_dec;
	trk->decend = ogg_decend;
	trk->samprate = ov->vi.rate;
	trk->channels = ov->vi.channels;
	trk->block = 4096;
	trk->blksamp = 4096 / ov->vi.channels;
	trk->bit = 16;
#if defined(SOUND_MOREINFO)
	trk->bps = 0;
	trk->fmt = WAVEFMT_OGG;
	CopyMemory(trk->info, "Ogg vorbis", 11);
#endif

	vorbis_synthesis_init(&ov->vd, &ov->vi);
	vorbis_block_init(&ov->vd, &ov->vb);
	return(SNDMIX_SUCCESS);

ovopn_err1:
	ogg_sync_clear(&ov->oy);
	_MFREE(ov);
	return(SNDMIX_FAILURE);

ovopn_next2:
	_MFREE(ov);

ovopn_next:
	return(SNDMIX_NOTSUPPORT);
}
Example #23
0
static int spx_seek (void *prv_data, int sec)
{
	struct spx_data *data = (struct spx_data *)prv_data;
	off_t begin = 0, end, old_pos;

	assert (sec >= 0);

	end = io_file_size (data->stream);
	if (end == -1)
		return -1;
	old_pos = io_tell (data->stream);

	debug ("Seek request to %ds", sec);

	while (1) {
		off_t middle = (end + begin) / 2;
		ogg_int64_t granule_pos;
		int position_seconds;

		debug ("Seek to %"PRId64, middle);

		if (io_seek(data->stream, middle, SEEK_SET) == -1) {
			io_seek (data->stream, old_pos, SEEK_SET);
			ogg_stream_reset (&data->os);
			ogg_sync_reset (&data->oy);
			return -1;
		}

		debug ("Syncing...");

		/* Sync to page and read it */
		ogg_sync_reset (&data->oy);
		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);
			}
		}

		if (io_eof(data->stream)) {
			debug ("EOF when syncing");
			return -1;
		}

		granule_pos = ogg_page_granulepos(&data->og);
		position_seconds = granule_pos / data->rate;

		debug ("We are at %ds", position_seconds);

		if (position_seconds == sec) {
			ogg_stream_pagein (&data->os, &data->og);
			debug ("We have it at granulepos %"PRId64, granule_pos);
			break;
		}
		else if (sec < position_seconds) {
			end = middle;
			debug ("going back");
		}
		else {
			begin = middle;
			debug ("going forward");
		}

		debug ("begin - end %"PRId64" - %"PRId64, begin, end);

		if (end - begin <= 200) {

			/* Can't find the exact position. */
			sec = position_seconds;
			break;
		}
	}

	ogg_sync_reset (&data->oy);
	ogg_stream_reset (&data->os);

	return sec;
}
Example #24
0
static UINT ogg_dec(SMIXTRACK trk, SINT16 *dst) {

	__OV	*ov;
	int		result;
	char	*buffer;
	UINT	r;
	float	**pcm;
	int		samples;
	int		i;
	int		j;
	float	*mono;
	SINT16	*ptr;
	SINT32	val;

	ov = (__OV *)trk->snd;

	do {
		switch(ov->phase) {
			case OVPHASE_HEAD:
				result = ogg_sync_pageout(&ov->oy, &ov->og);
				if (result > 0) {
					ogg_stream_pagein(&ov->os, &ov->og);
					ov->phase = OVPHASE_STREAMIN;
				}
				else if (result == 0) {
					ov->phase = OVPHASE_NEXT;
				}
				else {
					TRACEOUT(("Corrupt or missing data in bitstream"));
				}
				break;

			case OVPHASE_STREAMIN:
				result = ogg_stream_packetout(&ov->os, &ov->op);
				if (result > 0) {
					if (vorbis_synthesis(&ov->vb, &ov->op) == 0) {
						vorbis_synthesis_blockin(&ov->vd, &ov->vb);
					}
					ov->phase = OVPHASE_GETPCM;
				}
				else if (result == 0) {
					if (!ogg_page_eos(&ov->og)) {
						ov->phase = OVPHASE_NEXT;
					}
					else {
						ov->phase = OVPHASE_CLOSE;
					}
				}
				break;

			case OVPHASE_GETPCM:
				samples = vorbis_synthesis_pcmout(&ov->vd, &pcm);
				if (samples > 0) {
					if (samples > (int)trk->blksamp) {
						samples = (int)trk->blksamp;
					}
					for (i=0; i<ov->vi.channels; i++) {
						ptr = dst + i;
						mono = pcm[i];
						for (j=0; j<samples; j++) {
							val = (long)(mono[j] * 32767.f);
							if (val > 32767) {
								val = 32767;
							}
							if (val < -32768) {
								val = -32768;
							}
							*ptr = (SINT16)val;
							ptr += ov->vi.channels;
						}
					}
					vorbis_synthesis_read(&ov->vd, samples);
					return((UINT)samples);
				}
				ov->phase = OVPHASE_STREAMIN;
				break;

			case OVPHASE_NEXT:
				buffer = ogg_sync_buffer(&ov->oy, trk->block);
				r = sndmix_dataread(trk, buffer, trk->block);
				ogg_sync_wrote(&ov->oy, (int)r);
				if (r) {
					ov->phase = OVPHASE_HEAD;
				}
				else {
					ov->phase = OVPHASE_CLOSE;
				}
				break;

			case OVPHASE_CLOSE:
				ov->phase = OVPHASE_HEAD;			// ��[��
				return(0);
		}
	} while(1);
}
Example #25
0
int main(){
  ogg_sync_state   oy; /* sync and verify incoming physical bitstream */
  ogg_stream_state os; /* take physical pages, weld into a logical
			  stream of packets */
  ogg_page         og; /* one Ogg bitstream page.  Vorbis packets are inside */
  ogg_packet       op; /* one raw packet of data for decode */
  
  vorbis_info      vi; /* struct that stores all the static vorbis bitstream
			  settings */
  vorbis_comment   vc; /* struct that stores all the bitstream user comments */
  vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
  vorbis_block     vb; /* local working space for packet->PCM decode */
  
  char *buffer;
  int  bytes;

#ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
  /* Beware the evil ifdef. We avoid these where we can, but this one we 
     cannot. Don't add any more, you'll probably go to hell if you do. */
  _setmode( _fileno( stdin ), _O_BINARY );
  _setmode( _fileno( stdout ), _O_BINARY );
#endif

#if defined(macintosh) && defined(__MWERKS__)
  {
    int argc;
    char **argv;
    argc=ccommand(&argv); /* get a "command line" from the Mac user */
                     /* this also lets the user set stdin and stdout */
  }
#endif

  /********** Decode setup ************/

  ogg_sync_init(&oy); /* Now we can read pages */
  
  while(1){ /* we repeat if the bitstream is chained */
    int eos=0;
    int i;

    /* grab some data at the head of the stream.  We want the first page
       (which is guaranteed to be small and only contain the Vorbis
       stream initial header) We need the first page to get the stream
       serialno. */

    /* submit a 4k block to libvorbis' Ogg layer */
    buffer=ogg_sync_buffer(&oy,4096);
    bytes=fread(buffer,1,4096,stdin);
    ogg_sync_wrote(&oy,bytes);
    
    /* Get the first page. */
    if(ogg_sync_pageout(&oy,&og)!=1){
      /* have we simply run out of data?  If so, we're done. */
      if(bytes<4096)break;
      
      /* error case.  Must not be Vorbis data */
      fprintf(stderr,"Input does not appear to be an Ogg bitstream.\n");
      exit(1);
    }
  
    /* Get the serial number and set up the rest of decode. */
    /* serialno first; use it to set up a logical stream */
    ogg_stream_init(&os,ogg_page_serialno(&og));
    
    /* extract the initial header from the first page and verify that the
       Ogg bitstream is in fact Vorbis data */
    
    /* I handle the initial header first instead of just having the code
       read all three Vorbis headers at once because reading the initial
       header is an easy way to identify a Vorbis bitstream and it's
       useful to see that functionality seperated out. */
    
    vorbis_info_init(&vi);
    vorbis_comment_init(&vc);
    if(ogg_stream_pagein(&os,&og)<0){ 
      /* error; stream version mismatch perhaps */
      fprintf(stderr,"Error reading first page of Ogg bitstream data.\n");
      exit(1);
    }
    
    if(ogg_stream_packetout(&os,&op)!=1){ 
      /* no page? must not be vorbis */
      fprintf(stderr,"Error reading initial header packet.\n");
      exit(1);
    }
    
    if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ 
      /* error case; not a vorbis header */
      fprintf(stderr,"This Ogg bitstream does not contain Vorbis "
	      "audio data.\n");
      exit(1);
    }
    
    /* At this point, we're sure we're Vorbis.  We've set up the logical
       (Ogg) bitstream decoder.  Get the comment and codebook headers and
       set up the Vorbis decoder */
    
    /* The next two packets in order are the comment and codebook headers.
       They're likely large and may span multiple pages.  Thus we reead
       and submit data until we get our two pacakets, watching that no
       pages are missing.  If a page is missing, error out; losing a
       header page is the only place where missing data is fatal. */
    
    i=0;
    while(i<2){
      while(i<2){
	int result=ogg_sync_pageout(&oy,&og);
	if(result==0)break; /* Need more data */
	/* Don't complain about missing or corrupt data yet.  We'll
	   catch it at the packet output phase */
	if(result==1){
	  ogg_stream_pagein(&os,&og); /* we can ignore any errors here
					 as they'll also become apparent
					 at packetout */
	  while(i<2){
	    result=ogg_stream_packetout(&os,&op);
	    if(result==0)break;
	    if(result<0){
	      /* Uh oh; data at some point was corrupted or missing!
		 We can't tolerate that in a header.  Die. */
	      fprintf(stderr,"Corrupt secondary header.  Exiting.\n");
	      exit(1);
	    }
	    vorbis_synthesis_headerin(&vi,&vc,&op);
	    i++;
	  }
	}
      }
      /* no harm in not checking before adding more */
      buffer=ogg_sync_buffer(&oy,4096);
      bytes=fread(buffer,1,4096,stdin);
      if(bytes==0 && i<2){
	fprintf(stderr,"End of file before finding all Vorbis headers!\n");
	exit(1);
      }
      ogg_sync_wrote(&oy,bytes);
    }
    
    /* Throw the comments plus a few lines about the bitstream we're
       decoding */
    {
      char **ptr=vc.user_comments;
      while(*ptr){
	fprintf(stderr,"%s\n",*ptr);
	++ptr;
      }
      fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi.channels,vi.rate);
      fprintf(stderr,"Encoded by: %s\n\n",vc.vendor);
    }
    
    convsize=4096/vi.channels;

    /* OK, got and parsed all three headers. Initialize the Vorbis
       packet->PCM decoder. */
    vorbis_synthesis_init(&vd,&vi); /* central decode state */
    vorbis_block_init(&vd,&vb);     /* local state for most of the decode
				       so multiple block decodes can
				       proceed in parallel.  We could init
				       multiple vorbis_block structures
				       for vd here */
    
    /* The rest is just a straight decode loop until end of stream */
    while(!eos){
      while(!eos){
	int result=ogg_sync_pageout(&oy,&og);
	if(result==0)break; /* need more data */
	if(result<0){ /* missing or corrupt data at this page position */
	  fprintf(stderr,"Corrupt or missing data in bitstream; "
		  "continuing...\n");
	}else{
	  ogg_stream_pagein(&os,&og); /* can safely ignore errors at
					 this point */
	  while(1){
	    result=ogg_stream_packetout(&os,&op);

	    if(result==0)break; /* need more data */
	    if(result<0){ /* missing or corrupt data at this page position */
	      /* no reason to complain; already complained above */
	    }else{
	      /* we have a packet.  Decode it */
	      float **pcm;
	      int samples;
	      
	      if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
		vorbis_synthesis_blockin(&vd,&vb);
	      /* 
		 
	      **pcm is a multichannel float vector.  In stereo, for
	      example, pcm[0] is left, and pcm[1] is right.  samples is
	      the size of each channel.  Convert the float values
	      (-1.<=range<=1.) to whatever PCM format and write it out */
	      
	      while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){
		int j;
		int clipflag=0;
		int bout=(samples<convsize?samples:convsize);
		
		/* convert floats to 16 bit signed ints (host order) and
		   interleave */
		for(i=0;i<vi.channels;i++){
		  ogg_int16_t *ptr=convbuffer+i;
		  float  *mono=pcm[i];
		  for(j=0;j<bout;j++){
#if 1
		    int val=mono[j]*32767.f;
#else /* optional dither */
		    int val=mono[j]*32767.f+drand48()-0.5f;
#endif
		    /* might as well guard against clipping */
		    if(val>32767){
		      val=32767;
		      clipflag=1;
		    }
		    if(val<-32768){
		      val=-32768;
		      clipflag=1;
		    }
		    *ptr=val;
		    ptr+=vi.channels;
		  }
		}
		
		if(clipflag)
		  fprintf(stderr,"Clipping in frame %ld\n",(long)(vd.sequence));
		
		
		fwrite(convbuffer,2*vi.channels,bout,stdout);
		
		vorbis_synthesis_read(&vd,bout); /* tell libvorbis how
						   many samples we
						   actually consumed */
	      }	    
	    }
	  }
	  if(ogg_page_eos(&og))eos=1;
	}
      }
      if(!eos){
	buffer=ogg_sync_buffer(&oy,4096);
	bytes=fread(buffer,1,4096,stdin);
	ogg_sync_wrote(&oy,bytes);
	if(bytes==0)eos=1;
      }
    }
    
    /* clean up this logical bitstream; before exit we see if we're
       followed by another [chained] */

    ogg_stream_clear(&os);
  
    /* ogg_page and ogg_packet structs always point to storage in
       libvorbis.  They're never freed or manipulated directly */
    
    vorbis_block_clear(&vb);
    vorbis_dsp_clear(&vd);
	vorbis_comment_clear(&vc);
    vorbis_info_clear(&vi);  /* must be called last */
  }

  /* OK, clean up the framer */
  ogg_sync_clear(&oy);
  
  fprintf(stderr,"Done.\n");
  return(0);
}
Example #26
0
void JVideoServer::Init()
{return;
    memset( &m_StreamState, 0, sizeof( m_StreamState    ) );
    memset( &m_SyncState,   0, sizeof( m_SyncState      ) );
    memset( &m_Page,        0, sizeof( m_Page           ) );
    memset( &m_Packet,      0, sizeof( m_Packet         ) );
    memset( &m_Comment,     0, sizeof( m_Comment        ) );
    memset( &m_Info,        0, sizeof( m_Info           ) );
    memset( &m_State,       0, sizeof( m_State          ) );
    memset( &m_YUVBuffer,   0, sizeof( m_YUVBuffer      ) );

    ogg_stream_clear( &m_StreamState );
    ogg_sync_init( &m_SyncState );
  
    theora_comment_init( &m_Comment );
    theora_info_init( &m_Info );

    // теперь ищем начало логического потока theora
    bool bStartHeader = true;
    int nHeaderPackets = 0;  // число обработанных пакетов заголовков theora

    do
    {
      if (LoadChunk( m_File, &m_SyncState ) ==0)
      {
        // кончился файл, на данном этапе это ошибка
        assert( "!eof searched, terminate...");
      }

      // ogg_sync_pageout - формирует страницу
      while (ogg_sync_pageout( &m_SyncState, &m_Page ) > 0)
        // 1-больше данных не требуется
        // 0-требуется больше данных для создания страницы
      {

        // что страница сформирована успешно

        // это страница заголовков? если нет, кончаем искать заголовки
        if (ogg_page_bos( &m_Page ) == false)
        {
          // нет, это не страница заголовков
          // значит, страницы заголовков всех логических потоков кончились
          // и начались данные этих потоков
          // таким образом надо переходить к чтению страниц данных

          // закидываем эту страничку в логический видеопоток
          PushPage( &m_Page );
          // PushPage - закидывает страничку
          // в логический поток theora, если
          // совпадает идентификатор логического потока
          // в противном случае страница игнорируется

          // выходим из циклов
          bStartHeader = false;
          break;
        }
        else
        {
          // да, это страница заголовков

          // тестовый логический поток
          ogg_stream_state m_StreamStateTest;
          memset(&m_StreamStateTest, 0x00, sizeof(ogg_stream_state));

          // инициализируем тестовый поток на тот же поток с таким же
          // идентификатором потока, как и у текущей странички
          if(0!= ogg_stream_init(&m_StreamStateTest,ogg_page_serialno(&m_Page)) )
            assert( "!error during ogg_stream_init");
          
          // добавляем страницу в тестовый поток
          if(0!= ogg_stream_pagein(&m_StreamStateTest,&m_Page) )
            assert( "!error during ogg_stream_pagein");

          // декодируем данные из этого тестового потока в пакет
          if( ogg_stream_packetout(&m_StreamStateTest,&m_Packet) ==-1)
            assert( "!error during ogg_stream_packetout");

          // nHeaderPackets - число прочитанных
          // заголовочных ПАКЕТОВ theora (не страниц)
          // по спецификации theora таких пакетов должно быть три
          if(nHeaderPackets==0)
          {
            int dhr = theora_decode_header (&m_Info, &m_Comment, &m_Packet);
            // декодируем заголовок theora

            if(dhr<0)
            {
              // это не заголовок theora
                
              // очищаем структуру тестового потока
              ogg_stream_clear(&m_StreamStateTest);
              //и продолжаем цикл в поисках заголовков theora
            }
            else
            {
              // это заголовок theora!

              // вот таким образом "инициализируем" логический поток theora:
              memcpy(&m_StreamState, &m_StreamStateTest,
                              sizeof(m_StreamStateTest));
              // теперь из этого потока будут всегда сыпаться пакеты theora

              nHeaderPackets++;

              // после того, как мы нашли заголовочную страницу логического потока theora,
              // нам необходимо прочитать все остальные заголовочные страницы
              // других потоков и отбросить их (если таковые, конечно, имеются)
            }
          }
        }
      }

    }
    while (bStartHeader);
 
    // сейчас надо получить еще два пакета заголовков theora (см. её документацию)
    // и можно переходить к потоковому воспроизведению

    while(nHeaderPackets<3)
    {
        int result=ogg_stream_packetout(&m_StreamState,&m_Packet);
        // если функция возвращает нуль, значит не хватает данных для декодирования
        // почему то этого НЕТ в спецификации libogg, или я плохо искал

        if (result < 0)
        {
          // ошибка декодирования, поврежденный поток
          assert( "!error during ogg_stream_packetout");
        }

        if (result > 0)
        {
          // удалось успешно извлечь пакет информации theora

          int result2 = theora_decode_header( &m_Info, &m_Comment, &m_Packet );

          if(result2<0)
          {
            // ошибка декодирования, поврежденный поток
            rlog.err("VIDEO: error during theora_decode_header (corrupt stream)");
          }

          ++nHeaderPackets;
        }

      // эту страничку обработали, надо извлечь новую
      // для этого проверяем буфер чтения, вдруг там осталось что-нить похожее
      // на страничку. Если не осталось, тогда просто читаем эти данные из файла:

      if (ogg_sync_pageout( &m_SyncState, &m_Page ) > 0)
        // ogg_sync_pageout - функция, берет данные из буфера приема ogg
        // и записывает их в ogg_page
      {
        //мы нашли страничку в буфере и...
        PushPage( &m_Page );
        // ...пихаем эти данные в подходящий поток
      }
      else
      {
        // ничего мы в буфере не нашли
        int ret = LoadChunk( m_File, &m_SyncState );
        // надо больше данных! читаем их из файла
        
        if (ret == 0)
        {
          // опять файл кончился!
          rlog.err("VIDEO: eof searched. terminate...");
        }
      }
    }

    // init videostream
    theora_decode_init( &m_State, &m_Info );

    switch(m_Info.colorspace)
    {
      case OC_CS_UNSPECIFIED:
        // nothing to report
        break;
      case OC_CS_ITU_REC_470M:
        rlog.msg("Encoder specified ITU Rec 470M (NTSC) color.");
        // выводим в лог информацию о цветовом пространстве
        break;
      case OC_CS_ITU_REC_470BG:
        rlog.msg("Encoder specified ITU Rec 470BG (PAL) color.");
        break;
      default:
        rlog.msg("Warning: encoder specified unknown colorspace.");
        break;
    }

  // theora processing...
  while (ogg_stream_packetout( &m_StreamState, &m_Packet ) <= 0)
  {
    // не хватает данных в логическом потоке theora
    // надо надергать данных из физического потока и затолкать их в логический поток

    // читаем данные из файла
    int ret = LoadChunk( m_File, &m_SyncState );
    if (ret == 0)
    {
      // файл кончился, необходимо выполнить закрывающие действия
      // и выйти из приложения
      TheoraClose();
      return;
    }

    while (ogg_sync_pageout( &m_SyncState, &m_Page ) > 0)
      // декодируем данные из буфера в страницы (ogg_page)
      // пока они не кончатся в буфере
    {
      // пихаем эти страницы в соотв. логические потоки
      PushPage( &m_Page );
    }
  }


   
  // удачно декодировали. в пакете содержится декодированная ogg-информация
  // (то бишь закодированная theora-информация)

  // загружаем пакет в декодер theora
  if (theora_decode_packetin(&m_State,&m_Packet) == OC_BADPACKET)
  {
    // ошибка декодирования
      rlog.err( "error during theora_decode_packetin..." );
  }

  // все данные получены, готовим кадр

  // декодируем страничку в YUV-виде в спец. структуру yuv_buffer
  if (theora_decode_YUVout( &m_State, &m_YUVBuffer ) != 0)
  {
    // ошибка декодирования
    rlog.err( "error during theora_decode_YUVout...");
  }
    
    // если это первый кадр, то создаем буфер кадра
    BYTE* frame = new BYTE[m_YUVBuffer.y_height*m_YUVBuffer.y_width*4];

  // yuv to rgb
  for (int cy = 0; cy < m_YUVBuffer.y_height; cy++)
  {
    int nYShift  = m_YUVBuffer.y_stride*cy;
    int nUVShift = m_YUVBuffer.uv_stride*(cy >> 1);
    
    for (int cx = 0; cx < m_YUVBuffer.y_width; cx++)
    {
      int nHX = (cx >> 1);

      BYTE nY = *(BYTE*)(m_YUVBuffer.y + nYShift  + cx  );
      BYTE nU = *(BYTE*)(m_YUVBuffer.u + nUVShift + nHX );
      BYTE nV = *(BYTE*)(m_YUVBuffer.v + nUVShift + nHX );

      int index = (cy*m_YUVBuffer.y_width + cx)*4;

      float r = nY + 1.371f*(nV - 128);
      float g = nY - 0.698f*(nV - 128) - 0.336f*(nU - 128);
      float b = nY + 1.732f*(nU - 128);

      frame[index + 0] = (BYTE)clamp( r, 0.0f, 255.0f );
      frame[index + 1] = (BYTE)clamp( g, 0.0f, 255.0f );
      frame[index + 2] = (BYTE)clamp( b, 0.0f, 255.0f );
      frame[index + 3] = 255;
    }
  }
} // JVideoServer::Init
Example #27
0
int main(void){

  ogg_stream_init(&os_en,0x04030201);
  ogg_stream_init(&os_de,0x04030201);
  ogg_sync_init(&oy);

  /* Exercise each code path in the framing code.  Also verify that
     the checksums are working.  */

  {
    /* 17 only */
    const int packets[]={17, -1};
    const int *headret[]={head1_0,NULL};
    
    fprintf(stderr,"testing single page encoding... ");
    test_pack(packets,headret);
  }

  {
    /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
    const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
    const int *headret[]={head1_1,head2_1,NULL};
    
    fprintf(stderr,"testing basic page encoding... ");
    test_pack(packets,headret);
  }

  {
    /* nil packets; beginning,middle,end */
    const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
    const int *headret[]={head1_2,head2_2,NULL};
    
    fprintf(stderr,"testing basic nil packets... ");
    test_pack(packets,headret);
  }

  {
    /* large initial packet */
    const int packets[]={4345,259,255,-1};
    const int *headret[]={head1_3,head2_3,NULL};
    
    fprintf(stderr,"testing initial-packet lacing > 4k... ");
    test_pack(packets,headret);
  }

  {
    /* continuing packet test */
    const int packets[]={0,4345,259,255,-1};
    const int *headret[]={head1_4,head2_4,head3_4,NULL};
    
    fprintf(stderr,"testing single packet page span... ");
    test_pack(packets,headret);
  }

  /* page with the 255 segment limit */
  {

    const int packets[]={0,10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,10,
		   10,10,10,10,10,10,10,50,-1};
    const int *headret[]={head1_5,head2_5,head3_5,NULL};
    
    fprintf(stderr,"testing max packet segments... ");
    test_pack(packets,headret);
  }

  {
    /* packet that overspans over an entire page */
    const int packets[]={0,100,9000,259,255,-1};
    const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
    
    fprintf(stderr,"testing very large packets... ");
    test_pack(packets,headret);
  }

  {
    /* term only page.  why not? */
    const int packets[]={0,100,4080,-1};
    const int *headret[]={head1_7,head2_7,head3_7,NULL};
    
    fprintf(stderr,"testing zero data page (1 nil packet)... ");
    test_pack(packets,headret);
  }



  {
    /* build a bunch of pages for testing */
    unsigned char *data=_ogg_malloc(1024*1024);
    int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
    int inptr=0,i,j;
    ogg_page og[5];
    
    ogg_stream_reset(&os_en);

    for(i=0;pl[i]!=-1;i++){
      ogg_packet op;
      int len=pl[i];
      
      op.packet=data+inptr;
      op.bytes=len;
      op.e_o_s=(pl[i+1]<0?1:0);
      op.granulepos=(i+1)*1000;

      for(j=0;j<len;j++)data[inptr++]=i+j;
      ogg_stream_packetin(&os_en,&op);
    }

    _ogg_free(data);

    /* retrieve finished pages */
    for(i=0;i<5;i++){
      if(ogg_stream_pageout(&os_en,&og[i])==0){
	fprintf(stderr,"Too few pages output building sync tests!\n");
	exit(1);
      }
      copy_page(&og[i]);
    }

    /* Test lost pages on pagein/packetout: no rollback */
    {
      ogg_page temp;
      ogg_packet test;

      fprintf(stderr,"Testing loss of pages... ");

      ogg_sync_reset(&oy);
      ogg_stream_reset(&os_de);
      for(i=0;i<5;i++){
	memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
	       og[i].header_len);
	ogg_sync_wrote(&oy,og[i].header_len);
	memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
	ogg_sync_wrote(&oy,og[i].body_len);
      }

      ogg_sync_pageout(&oy,&temp);
      ogg_stream_pagein(&os_de,&temp);
      ogg_sync_pageout(&oy,&temp);
      ogg_stream_pagein(&os_de,&temp);
      ogg_sync_pageout(&oy,&temp);
      /* skip */
      ogg_sync_pageout(&oy,&temp);
      ogg_stream_pagein(&os_de,&temp);

      /* do we get the expected results/packets? */
      
      if(ogg_stream_packetout(&os_de,&test)!=1)error();
      checkpacket(&test,0,0,0);
      if(ogg_stream_packetout(&os_de,&test)!=1)error();
      checkpacket(&test,100,1,-1);
      if(ogg_stream_packetout(&os_de,&test)!=1)error();
      checkpacket(&test,4079,2,3000);
      if(ogg_stream_packetout(&os_de,&test)!=-1){
	fprintf(stderr,"Error: loss of page did not return error\n");
	exit(1);
      }
      if(ogg_stream_packetout(&os_de,&test)!=1)error();
      checkpacket(&test,76,5,-1);
      if(ogg_stream_packetout(&os_de,&test)!=1)error();
      checkpacket(&test,34,6,-1);
      fprintf(stderr,"ok.\n");
    }

    /* Test lost pages on pagein/packetout: rollback with continuation */
    {
      ogg_page temp;
      ogg_packet test;

      fprintf(stderr,"Testing loss of pages (rollback required)... ");

      ogg_sync_reset(&oy);
      ogg_stream_reset(&os_de);
      for(i=0;i<5;i++){
	memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
	       og[i].header_len);
	ogg_sync_wrote(&oy,og[i].header_len);
	memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
	ogg_sync_wrote(&oy,og[i].body_len);
      }

      ogg_sync_pageout(&oy,&temp);
      ogg_stream_pagein(&os_de,&temp);
      ogg_sync_pageout(&oy,&temp);
      ogg_stream_pagein(&os_de,&temp);
      ogg_sync_pageout(&oy,&temp);
      ogg_stream_pagein(&os_de,&temp);
      ogg_sync_pageout(&oy,&temp);
      /* skip */
      ogg_sync_pageout(&oy,&temp);
      ogg_stream_pagein(&os_de,&temp);

      /* do we get the expected results/packets? */
      
      if(ogg_stream_packetout(&os_de,&test)!=1)error();
      checkpacket(&test,0,0,0);
      if(ogg_stream_packetout(&os_de,&test)!=1)error();
      checkpacket(&test,100,1,-1);
      if(ogg_stream_packetout(&os_de,&test)!=1)error();
      checkpacket(&test,4079,2,3000);
      if(ogg_stream_packetout(&os_de,&test)!=1)error();
      checkpacket(&test,2956,3,4000);
      if(ogg_stream_packetout(&os_de,&test)!=-1){
	fprintf(stderr,"Error: loss of page did not return error\n");
	exit(1);
      }
      if(ogg_stream_packetout(&os_de,&test)!=1)error();
      checkpacket(&test,300,13,14000);
      fprintf(stderr,"ok.\n");
    }
    
    /* the rest only test sync */
    {
      ogg_page og_de;
      /* Test fractional page inputs: incomplete capture */
      fprintf(stderr,"Testing sync on partial inputs... ");
      ogg_sync_reset(&oy);
      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
	     3);
      ogg_sync_wrote(&oy,3);
      if(ogg_sync_pageout(&oy,&og_de)>0)error();
      
      /* Test fractional page inputs: incomplete fixed header */
      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
	     20);
      ogg_sync_wrote(&oy,20);
      if(ogg_sync_pageout(&oy,&og_de)>0)error();
      
      /* Test fractional page inputs: incomplete header */
      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
	     5);
      ogg_sync_wrote(&oy,5);
      if(ogg_sync_pageout(&oy,&og_de)>0)error();
      
      /* Test fractional page inputs: incomplete body */
      
      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
	     og[1].header_len-28);
      ogg_sync_wrote(&oy,og[1].header_len-28);
      if(ogg_sync_pageout(&oy,&og_de)>0)error();
      
      memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
      ogg_sync_wrote(&oy,1000);
      if(ogg_sync_pageout(&oy,&og_de)>0)error();
      
      memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
	     og[1].body_len-1000);
      ogg_sync_wrote(&oy,og[1].body_len-1000);
      if(ogg_sync_pageout(&oy,&og_de)<=0)error();
      
      fprintf(stderr,"ok.\n");
    }

    /* Test fractional page inputs: page + incomplete capture */
    {
      ogg_page og_de;
      fprintf(stderr,"Testing sync on 1+partial inputs... ");
      ogg_sync_reset(&oy); 

      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
	     og[1].header_len);
      ogg_sync_wrote(&oy,og[1].header_len);

      memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
	     og[1].body_len);
      ogg_sync_wrote(&oy,og[1].body_len);

      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
	     20);
      ogg_sync_wrote(&oy,20);
      if(ogg_sync_pageout(&oy,&og_de)<=0)error();
      if(ogg_sync_pageout(&oy,&og_de)>0)error();

      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
	     og[1].header_len-20);
      ogg_sync_wrote(&oy,og[1].header_len-20);
      memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
	     og[1].body_len);
      ogg_sync_wrote(&oy,og[1].body_len);
      if(ogg_sync_pageout(&oy,&og_de)<=0)error();

      fprintf(stderr,"ok.\n");
    }
    
    /* Test recapture: garbage + page */
    {
      ogg_page og_de;
      fprintf(stderr,"Testing search for capture... ");
      ogg_sync_reset(&oy); 
      
      /* 'garbage' */
      memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
	     og[1].body_len);
      ogg_sync_wrote(&oy,og[1].body_len);

      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
	     og[1].header_len);
      ogg_sync_wrote(&oy,og[1].header_len);

      memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
	     og[1].body_len);
      ogg_sync_wrote(&oy,og[1].body_len);

      memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
	     20);
      ogg_sync_wrote(&oy,20);
      if(ogg_sync_pageout(&oy,&og_de)>0)error();
      if(ogg_sync_pageout(&oy,&og_de)<=0)error();
      if(ogg_sync_pageout(&oy,&og_de)>0)error();

      memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
	     og[2].header_len-20);
      ogg_sync_wrote(&oy,og[2].header_len-20);
      memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
	     og[2].body_len);
      ogg_sync_wrote(&oy,og[2].body_len);
      if(ogg_sync_pageout(&oy,&og_de)<=0)error();

      fprintf(stderr,"ok.\n");
    }

    /* Test recapture: page + garbage + page */
    {
      ogg_page og_de;
      fprintf(stderr,"Testing recapture... ");
      ogg_sync_reset(&oy); 

      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
	     og[1].header_len);
      ogg_sync_wrote(&oy,og[1].header_len);

      memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
	     og[1].body_len);
      ogg_sync_wrote(&oy,og[1].body_len);

      memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
	     og[2].header_len);
      ogg_sync_wrote(&oy,og[2].header_len);

      memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
	     og[2].header_len);
      ogg_sync_wrote(&oy,og[2].header_len);

      if(ogg_sync_pageout(&oy,&og_de)<=0)error();

      memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
	     og[2].body_len-5);
      ogg_sync_wrote(&oy,og[2].body_len-5);

      memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
	     og[3].header_len);
      ogg_sync_wrote(&oy,og[3].header_len);

      memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
	     og[3].body_len);
      ogg_sync_wrote(&oy,og[3].body_len);

      if(ogg_sync_pageout(&oy,&og_de)>0)error();
      if(ogg_sync_pageout(&oy,&og_de)<=0)error();

      fprintf(stderr,"ok.\n");
    }
  }    

  return(0);
}
Example #28
0
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)
         {
	    if (op.bytes>=8 && !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, frame_size);
                  else
                     ret = celt_decode(st, NULL, 0, output, frame_size);

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

                  if (ret<0)
                  {
                     fprintf (stderr, "Decoding error: %s\n", celt_strerror(ret));
                     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;
}
Example #29
0
static int decode(quicktime_t *file, 
					int16_t *output_i, 
					float *output_f, 
					long samples, 
					int track, 
					int channel)
{
	int result = 0;
	int bytes;
	int i, j;
	quicktime_audio_map_t *track_map = &(file->atracks[track]);
	quicktime_trak_t *trak = track_map->track;
	quicktime_vorbis_codec_t *codec = ((quicktime_codec_t*)track_map->codec)->priv;
	long current_position = track_map->current_position;
	long end_position = current_position + samples;
  	unsigned char *buffer;
// End of data in ogg buffer
	int eos = 0;
// End of file
	int eof = 0;
	float *pcm;
	int have_chunk = 0;


	if(samples > OUTPUT_ALLOCATION)
		printf("vorbis.c decode: can't read more than %p samples at a time.\n", OUTPUT_ALLOCATION);



	if(output_i) bzero(output_i, sizeof(int16_t) * samples);
	if(output_f) bzero(output_f, sizeof(float) * samples);







// Seeked outside output buffer's range or not initialized: restart
	if(current_position < codec->output_position - codec->output_size ||
		current_position > codec->output_position ||
		!codec->decode_initialized)
	{

		quicktime_chunk_of_sample(&codec->output_position, 
			&codec->chunk, 
			trak, 
			current_position);
// We know the first ogg packet in the chunk has a pcm_offset from the encoding.

		codec->output_size = 0;
		codec->output_end = 0;
		codec->chunk_samples = 0;



	
// Initialize and load initial buffer for decoding
		if(!codec->decode_initialized)
		{
			int init_chunk = 1;
			codec->decode_initialized = 1;

			codec->output = malloc(sizeof(float*) * track_map->channels);
			for(i = 0; i < track_map->channels; i++)
			{
				codec->output[i] = malloc(sizeof(float) * OUTPUT_ALLOCATION);
			}

			codec->output_allocated = OUTPUT_ALLOCATION;

        	ogg_sync_init(&codec->dec_oy); /* Now we can read pages */




			READ_CHUNK(init_chunk);
			init_chunk++;

   	 		if(ogg_sync_pageout(&codec->dec_oy, &codec->dec_og)!=1)
			{
				fprintf(stderr, "decode: ogg_sync_pageout: Must not be Vorbis data\n");
				return 1;
			}


    		ogg_stream_init(&codec->dec_os, ogg_page_serialno(&codec->dec_og));
    		vorbis_info_init(&codec->dec_vi);
    		vorbis_comment_init(&codec->dec_vc);

    		if(ogg_stream_pagein(&codec->dec_os, &codec->dec_og) < 0)
			{
    	  		fprintf(stderr,"decode: ogg_stream_pagein: stream version mismatch perhaps.\n");
    	  		return 1;
    		}

			if(ogg_stream_packetout(&codec->dec_os, &codec->dec_op) != 1)
			{
				fprintf(stderr, "decode: ogg_stream_packetout: Must not be Vorbis data\n");
    	  		return 1;
			}

			if(vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op) < 0)
			{
				fprintf(stderr, "decode: vorbis_synthesis_headerin: not a vorbis header\n");
				return 1;
			}


			i = 0;
			while(i < 2)
			{
				while(i < 2)
				{
					result = ogg_sync_pageout(&codec->dec_oy, &codec->dec_og);
					if(result == 0) break;

					if(result == 1)
					{
						ogg_stream_pagein(&codec->dec_os, &codec->dec_og);

						while(i < 2)
						{
							result = ogg_stream_packetout(&codec->dec_os, &codec->dec_op);

							if(result == 0) break;

							if(result < 0)
							{
								fprintf(stderr, "decode: ogg_stream_packetout: corrupt secondary header\n");
								return 1;
							}

							vorbis_synthesis_headerin(&codec->dec_vi, &codec->dec_vc, &codec->dec_op);
							i++;




						}
					}
				}

				if(i < 2)
				{
					READ_CHUNK(init_chunk);
					init_chunk++;
				}

// Header should never span more than one chunk so assume it's done here
			}

			vorbis_synthesis_init(&codec->dec_vd, &codec->dec_vi);
			vorbis_block_init(&codec->dec_vd, &codec->dec_vb);

// Also the first chunk needed in decoding so don't reread after this.
			if(codec->chunk == init_chunk - 1) 
			{
				have_chunk = 1;
				codec->chunk++;
			}
		}




// Don't already have initial chunk from header
		if(!have_chunk)
		{
// Get initial chunk for decoding at new location
// From vorbisfile.c
/* clear out decoding machine state */
			ogg_stream_clear(&codec->dec_os);
			vorbis_dsp_clear(&codec->dec_vd);
			vorbis_block_clear(&codec->dec_vb);
    		ogg_sync_reset(&codec->dec_oy);

    		ogg_stream_init(&codec->dec_os, ogg_page_serialno(&codec->dec_og));
        	ogg_sync_init(&codec->dec_oy);
			vorbis_synthesis_init(&codec->dec_vd, &codec->dec_vi);
			vorbis_block_init(&codec->dec_vd, &codec->dec_vb);


			READ_CHUNK(codec->chunk);
			codec->chunk++;
			have_chunk = 1;
		}
	}

// Assume the chunk exists by now and rely on libogg to say if it's out of
// data.
	have_chunk = 1;











// Read chunks until output buffer is on or after end_position
	result = 0;
	while(codec->output_position < end_position)
	{


// Read chunk to decode if it hasn't been read yet.
		if(!have_chunk)
		{
			codec->chunk_samples = 0;

			READ_CHUNK(codec->chunk);
			if(result) break;
			codec->chunk++;
		}

		eos = 0;
		while(!eos)
		{
			result = ogg_sync_pageout(&codec->dec_oy, &codec->dec_og);







// Need more data from chunk
			if(result == 0)
			{
// End of chunk
				eos = 1;
			}
			else
// This stage checks for OggS and a checksum error.
// It doesn't tell if it's the end of a chunk.  Need to manually parse OggS
// pages to figure out how big the chunk is.
			if(result < 0)
			{
//printf("ogg_sync_pageout=-1\n");
				;
			}
			else
			{
				ogg_stream_pagein(&codec->dec_os, &codec->dec_og);



				while(!eos)
				{
//printf("decode 7\n");
					result = ogg_stream_packetout(&codec->dec_os, &codec->dec_op);

//printf("decode 8 %d\n", result);
					if(result == 0)
					{
//printf("ogg_stream_packetout=0\n");
// End of page
						eos = 1;
					}
					else
// This stage doesn't check for OggS.
					if(result < 0)
					{
//printf("ogg_stream_packetout=-1\n");
					}
					else
					{
						float **pcm;







						if(vorbis_synthesis(&codec->dec_vb, &codec->dec_op) == 0)
						{
							vorbis_synthesis_blockin(&codec->dec_vd, 
								&codec->dec_vb);
						}


						while((result = vorbis_synthesis_pcmout(&codec->dec_vd, &pcm)) > 0)
						{
//printf("vorbis_synthesis_pcmout=%x\n", result);
							for(i = 0; i < track_map->channels; i++)
							{
								float *output_channel = codec->output[i];
								float *input_channel = pcm[i];
								int k = codec->output_end;

								for(j = 0; j < result; j++)
								{
									output_channel[k++] = input_channel[j];
									if(k >= codec->output_allocated)
										k = 0;
								}
								
								if(i == track_map->channels - 1) 
									codec->output_end = k;
							}
//printf("codec->output_end = %d\n", codec->output_end);

							codec->output_position += result;
							codec->output_size += result;
							codec->chunk_samples += result;
							if(codec->output_size > codec->output_allocated)
								codec->output_size = codec->output_allocated;
							vorbis_synthesis_read(&codec->dec_vd, result);
						}
					}
//printf("decode 11\n");
				}

// Reset end of page so it isn't interpreted as an end of chunk
				eos = 0;
			}
		}


// Next chunk
		if(eos)
		{
//printf("decode 12 got=%x\n", codec->chunk_samples);
			have_chunk = 0;
		}
	}


// Fill silence
	while(codec->output_position < end_position)
	{
		for(i = 0; i < track_map->channels; i++)
			codec->output[i][codec->output_end] = 0;
		
		codec->output_end++;
		if(codec->output_end >= codec->output_allocated)
			codec->output_end = 0;
		codec->output_position++;
	}
//printf("decode 15\n");


//printf("decode 2 codec->output_position=%lld codec->output_end=%d codec->output_size=%d\n", 
//	codec->output_position, codec->output_end, codec->output_size);

	current_position = track_map->current_position;
	i = codec->output_end - (codec->output_position - current_position);
	j = 0;
	while(i < 0) i += codec->output_allocated;
	pcm = codec->output[channel];

	if(output_i)
	{
		for( ; j < samples; j++)
		{
			int sample = pcm[i] * 32767;
			CLAMP(sample, -32768, 32767);
			output_i[j] = sample;

			i++;
			if(i >= codec->output_allocated) i = 0;
		}
	}
	else
	if(output_f)
	{
		for( ; j < samples; j++)
		{
			output_f[j] = pcm[i];
			i++;
			if(i >= codec->output_allocated) i = 0;
		}
	}
//printf("decode 16\n");

	return 0;
}
Example #30
0
int
main (int argc, char **argv)
{
  int indexing, ch;
  FILE *in;
  ogg_sync_state    oy;
  ogg_page          og;
  ogg_stream_state  os;
  
  indexing = 0;
  
  while ((ch = getopt(argc, argv, "io:")) != -1) 
  {
    switch (ch) 
    {
      case 'i':
        indexing = 1;
        break;

      case 'o':
        break;

      case '?':
      default:
        usage();
    }
  }

  argc -= optind;
  argv += optind;
  
  if (argc == 0)
  {
    usage ();
    return 1;
  }
  
  in = fopen (argv[0], "rb");
  if (in == NULL)
  {
    perror ("error opening input");
    return -1;
  }

  /* initialise ogg_sync_state */
  ogg_sync_init (&oy);
  
  /* process all the headers of the Ogg container */
  while (1)
  {
    int ret = buffer_data (in, &oy);
    if (ret == 0) break;
    while (ogg_sync_pageout (&oy, &og) > 0)
    {
      ogg_packet        op;
      int               got_packet;

      ogg_stream_init (&os, ogg_page_serialno (&og));
      ogg_stream_pagein (&os, &og);
      if ((got_packet = ogg_stream_packetout (&os, &op)))
      {
      }
    }
  }

  fclose (in);
  
  return 0;
}