Exemple #1
0
/***********************************************************************
 * Flush
 ***********************************************************************
 *
 **********************************************************************/
static hb_buffer_t * Flush( hb_work_object_t * w )
{
    hb_work_private_t * pv = w->private_data;
    hb_buffer_t * buf;
    int64_t     blocksize = 0;

    if( vorbis_analysis_blockout( &pv->vd, &pv->vb ) == 1 )
    {
        ogg_packet op;

        vorbis_analysis( &pv->vb, NULL );
        vorbis_bitrate_addblock( &pv->vb );

        if( vorbis_bitrate_flushpacket( &pv->vd, &op ) )
        {
            buf = hb_buffer_init( sizeof( ogg_packet ) + op.bytes );
            memcpy( buf->data, &op, sizeof( ogg_packet ) );
            memcpy( buf->data + sizeof( ogg_packet ), op.packet,
                    op.bytes );
            blocksize = vorbis_packet_blocksize(&pv->vi, &op);
            buf->frametype   = HB_FRAME_AUDIO;
            buf->start = (int64_t)(vorbis_granule_time(&pv->vd, op.granulepos) * 90000);
            buf->stop  = (int64_t)(vorbis_granule_time(&pv->vd, (pv->prev_blocksize + blocksize)/4 + op.granulepos) * 90000);
            /* The stop time isn't accurate for the first ~3 packets, as the actual blocksize depends on the previous _and_ current packets. */
            pv->prev_blocksize = blocksize;
            return buf;
        }
    }

    return NULL;
}
static int tc_frame_audio_add_ogg_packet(VorbisPrivateData *pd, 
                                         TCFrameAudio *f, ogg_packet *op)
{
    int16_t *pkt_num = (int16_t*)f->audio_buf;
    double ts = vorbis_granule_time(&(pd->vd), op->granulepos);
    int needed = sizeof(*op) + op->bytes;
    int avail = f->audio_size - f->audio_len;

    TC_FRAME_SET_TIMESTAMP_DOUBLE(f, ts);
    if (avail < needed) {
        tc_log_error(__FILE__, "(%s) no buffer in frame: (avail=%i|needed=%i)",
                     __func__, avail, needed);
        return TC_ERROR;
    }
    ac_memcpy(f->audio_buf + f->audio_len, op, sizeof(*op));
    f->audio_len += sizeof(*op);
    ac_memcpy(f->audio_buf + f->audio_len, op->packet, op->bytes);
    f->audio_len += op->bytes;
    *pkt_num += 1;

    if (op->e_o_s) {
        f->attributes |= TC_FRAME_IS_END_OF_STREAM; // useless?
    }
    return TC_OK;
}
	float VideoClip_Theora::_decodeAudio()
	{
		if (this->restarted)
		{
			return -1.0f;
		}
		ogg_packet opVorbis;
		float** pcm;
		int length = 0;
		float timeStamp = -1.0f;
		bool readPastTimestamp = false;
		float factor = 1.0f / this->audioFrequency;
		float videoTime = (float)this->lastDecodedFrameNumber / this->fps;
		float min = this->frameQueue->getSize() / this->fps + 1.0f;
		float audioTime = 0.0f;
		while (true)
		{
			length = vorbis_synthesis_pcmout(&this->info.VorbisDSPState, &pcm);
			if (length == 0)
			{
				if (ogg_stream_packetout(&this->info.VorbisStreamState, &opVorbis) > 0)
				{
					if (vorbis_synthesis(&this->info.VorbisBlock, &opVorbis) == 0)
					{
						if (timeStamp < 0 && opVorbis.granulepos >= 0)
						{
							timeStamp = (float)vorbis_granule_time(&this->info.VorbisDSPState, opVorbis.granulepos);
						}
						else if (timeStamp >= 0)
						{
							readPastTimestamp = true;
						}
						vorbis_synthesis_blockin(&this->info.VorbisDSPState, &this->info.VorbisBlock);
					}
					continue;
				}
				audioTime = this->readAudioSamples * factor;
				// always buffer up of audio ahead of the frames
				if (audioTime - videoTime >= min || !this->_readData())
				{
					break;
				}
			}
			if (length > 0)
			{
				this->addAudioPacket(pcm, length, this->audioGain);
				this->readAudioSamples += length;
				if (readPastTimestamp)
				{
					timeStamp += (float)length / this->info.VorbisInfo.rate;
				}
				vorbis_synthesis_read(&this->info.VorbisDSPState, length); // tell vorbis we read a number of samples
			}
		}
		return timeStamp;
	}
Exemple #4
0
static double encode_vorbis( FILE *f, vorbis_dsp_state *vd, ogg_stream_state *vo, vorbis_block *vb, 
			     unsigned int audio_rate, double audiopos, signed char *buf, int n_samples )
{
   float **vorbis_buffer;
   const int audio_ch = 2;
   int i,j;
   int count = 0;
   ogg_page og;
   int got_page = 0;

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

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

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

   return audiopos;
}
	bool VideoClip_Theora::_readData()
	{
		int audioEos = 0;
		int serno = 0;
		float audioTime = 0;
		float time = this->timer->getTime();
		if (this->restarted)
		{
			time = 0.0f;
		}
		char* buffer = NULL;
		int bytesRead = 0;
		ogg_int64_t granule = 0;
		do
		{
			buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE);
			bytesRead = this->stream->read(buffer, BUFFER_SIZE);
			ogg_sync_wrote(&this->info.OggSyncState, bytesRead);
			if (bytesRead == 0)
			{
				if (!this->autoRestart)
				{
					this->endOfFile = true;
					log(this->name + " finished playing");
				}
				return false;
			}
			// when we fill the stream with enough pages, it'll start spitting out packets
			// which contain key frames, delta frames or audio data
			while (ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage) > 0)
			{
				serno = ogg_page_serialno(&this->info.OggPage);
				if (serno == this->info.TheoraStreamState.serialno)
				{
					ogg_stream_pagein(&this->info.TheoraStreamState, &this->info.OggPage);
				}
				if (this->audioInterface != NULL && serno == this->info.VorbisStreamState.serialno)
				{
					granule = ogg_page_granulepos(&this->info.OggPage);
					audioTime = (float)vorbis_granule_time(&this->info.VorbisDSPState, granule);
					audioEos = ogg_page_eos(&this->info.OggPage);
					ogg_stream_pagein(&this->info.VorbisStreamState, &this->info.OggPage);
				}
			}
		} while (this->audioInterface != NULL && audioEos == 0 && audioTime < time + 1.0f);
		return true;
	}
Exemple #6
0
int main(int argc,char *argv[]){
  int c,long_option_index,ret;

  ogg_stream_state to; /* take physical pages, weld into a logical
                           stream of packets */
  ogg_stream_state vo; /* 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 */

  theora_state     td;
  theora_info      ti;
  theora_comment   tc;

  vorbis_info      vi; /* struct that stores all the static vorbis bitstream
                          settings */
  vorbis_comment   vc; /* struct that stores all the user comments */

  vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
  vorbis_block     vb; /* local working space for packet->PCM decode */

  int audioflag=0;
  int videoflag=0;
  int akbps=0;
  int vkbps=0;

  ogg_int64_t audio_bytesout=0;
  ogg_int64_t video_bytesout=0;
  double timebase;


  FILE* outfile = stdout;

#ifdef _WIN32 
# ifdef THEORA_PERF_DATA
    LARGE_INTEGER start_time;
    LARGE_INTEGER final_time;

    LONGLONG elapsed_ticks;
    LARGE_INTEGER ticks_per_second;
    
    LONGLONG elapsed_secs;
    LONGLONG elapsed_sec_mod;
    double elapsed_secs_dbl ;
# endif
  /* We need to set stdin/stdout to binary mode. Damn windows. */
  /* if we were reading/writing a file, it would also need to in
     binary mode, eg, fopen("file.wav","wb"); */
  /* 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

  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;;

    case 'a':
      audio_q=atof(optarg)*.099;
      if(audio_q<-.1 || audio_q>1){
        fprintf(stderr,"Illegal audio quality (choose -1 through 10)\n");
        exit(1);
      }
      audio_r=-1;
      break;

    case 'v':
      video_q=rint(atof(optarg)*6.3);
      if(video_q<0 || video_q>63){
        fprintf(stderr,"Illegal video quality (choose 0 through 10)\n");
        exit(1);
      }
      video_r=0;
      break;

    case 'A':
      audio_r=atof(optarg)*1000;
      if(audio_q<0){
        fprintf(stderr,"Illegal audio quality (choose > 0 please)\n");
        exit(1);
      }
      audio_q=-99;
      break;

    case 'V':
      video_r=rint(atof(optarg)*1000);
      if(video_r<45000 || video_r>2000000){
        fprintf(stderr,"Illegal video bitrate (choose 45kbps through 2000kbps)\n");
        exit(1);
      }
      video_q=0;
     break;

    case 's':
      video_an=rint(atof(optarg));
      break;

    case 'S':
      video_ad=rint(atof(optarg));
      break;

    case 'f':
      video_hzn=rint(atof(optarg));
      break;

    case 'F':
      video_hzd=rint(atof(optarg));
      break;

    default:
      usage();
    }
  }

  while(optind<argc){
    /* assume that anything following the options must be a filename */
    id_file(argv[optind]);
    optind++;
  }



#ifdef THEORA_PERF_DATA
# ifdef WIN32
    QueryPerformanceCounter(&start_time);
# endif
#endif


  /* yayness.  Set up Ogg output stream */
  srand(time(NULL));
  {
    /* need two inequal serial numbers */
    int serial1, serial2;
    serial1 = rand();
    serial2 = rand();
    if (serial1 == serial2) serial2++;
    ogg_stream_init(&to,serial1);
    ogg_stream_init(&vo,serial2);
  }

  /* Set up Theora encoder */
  if(!video){
    fprintf(stderr,"No video files submitted for compression?\n");
    exit(1);
  }
  /* Theora has a divisible-by-sixteen restriction for the encoded video size */
  /* scale the frame size up to the nearest /16 and calculate offsets */
  video_x=((frame_x + 15) >>4)<<4;
  video_y=((frame_y + 15) >>4)<<4;
  /* We force the offset to be even.
     This ensures that the chroma samples align properly with the luma
      samples. */
  frame_x_offset=((video_x-frame_x)/2)&~1;
  frame_y_offset=((video_y-frame_y)/2)&~1;

  theora_info_init(&ti);
  ti.width=video_x;
  ti.height=video_y;
  ti.frame_width=frame_x;
  ti.frame_height=frame_y;
  ti.offset_x=frame_x_offset;
  ti.offset_y=frame_y_offset;
  ti.fps_numerator=video_hzn;
  ti.fps_denominator=video_hzd;
  ti.aspect_numerator=video_an;
  ti.aspect_denominator=video_ad;
  ti.colorspace=OC_CS_UNSPECIFIED;
  ti.pixelformat=OC_PF_420;
  ti.target_bitrate=video_r;
  ti.quality=video_q;

  ti.dropframes_p=0;
  ti.quick_p=1;
  ti.keyframe_auto_p=1;
  ti.keyframe_frequency=64;
  ti.keyframe_frequency_force=64;
  ti.keyframe_data_target_bitrate=video_r*1.5;
  ti.keyframe_auto_threshold=80;
  ti.keyframe_mindistance=8;
  ti.noise_sensitivity=1;

  theora_encode_init(&td,&ti);
  theora_info_clear(&ti);

  /* initialize Vorbis too, assuming we have audio to compress. */
  if(audio){
    vorbis_info_init(&vi);
    if(audio_q>-99)
      ret = vorbis_encode_init_vbr(&vi,audio_ch,audio_hz,audio_q);
    else
      ret = vorbis_encode_init(&vi,audio_ch,audio_hz,-1,audio_r,-1);
    if(ret){
      fprintf(stderr,"The Vorbis encoder could not set up a mode according to\n"
              "the requested quality or bitrate.\n\n");
      exit(1);
    }

    vorbis_comment_init(&vc);
    vorbis_analysis_init(&vd,&vi);
    vorbis_block_init(&vd,&vb);
  }

  /* write the bitstream header packets with proper page interleave */

  /* first packet will get its own page automatically */
  theora_encode_header(&td,&op);
  ogg_stream_packetin(&to,&op);
  if(ogg_stream_pageout(&to,&og)!=1){
    fprintf(stderr,"Internal Ogg library error.\n");
    exit(1);
  }
  fwrite(og.header,1,og.header_len,outfile);
  fwrite(og.body,1,og.body_len,outfile);

  /* create the remaining theora headers */
  theora_comment_init(&tc);
  theora_encode_comment(&tc,&op);
  ogg_stream_packetin(&to,&op);
  /*theora_encode_comment() doesn't take a theora_state parameter, so it has to
     allocate its own buffer to pass back the packet data.
    If we don't free it here, we'll leak.
    libogg2 makes this much cleaner: the stream owns the buffer after you call
     packetin in libogg2, but this is not true in libogg1.*/
  free(op.packet);
  theora_encode_tables(&td,&op);
  ogg_stream_packetin(&to,&op);

  if(audio){
    ogg_packet header;
    ogg_packet header_comm;
    ogg_packet header_code;

    vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
    ogg_stream_packetin(&vo,&header); /* automatically placed in its own
                                         page */
    if(ogg_stream_pageout(&vo,&og)!=1){
      fprintf(stderr,"Internal Ogg library error.\n");
      exit(1);
    }
    fwrite(og.header,1,og.header_len,outfile);
    fwrite(og.body,1,og.body_len,outfile);

    /* remaining vorbis header packets */
    ogg_stream_packetin(&vo,&header_comm);
    ogg_stream_packetin(&vo,&header_code);
  }

  /* Flush the rest of our headers. This ensures
     the actual data in each stream will start
     on a new page, as per spec. */
  while(1){
    int result = ogg_stream_flush(&to,&og);
      if(result<0){
        /* can't get here */
        fprintf(stderr,"Internal Ogg library error.\n");
        exit(1);
      }
    if(result==0)break;
    fwrite(og.header,1,og.header_len,outfile);
    fwrite(og.body,1,og.body_len,outfile);
  }
  if(audio){
    while(1){
      int result=ogg_stream_flush(&vo,&og);
      if(result<0){
        /* can't get here */
        fprintf(stderr,"Internal Ogg library error.\n");
        exit(1);
      }
      if(result==0)break;
      fwrite(og.header,1,og.header_len,outfile);
      fwrite(og.body,1,og.body_len,outfile);
    }
  }

  /* setup complete.  Raw processing loop */
  fprintf(stderr,"Compressing....\n");
  while(1){
    ogg_page audiopage;
    ogg_page videopage;

    /* is there an audio page flushed?  If not, fetch one if possible */
    audioflag=fetch_and_process_audio(audio,&audiopage,&vo,&vd,&vb,audioflag);

    /* is there a video page flushed?  If not, fetch one if possible */
    videoflag=fetch_and_process_video(video,&videopage,&to,&td,videoflag);

    /* no pages of either?  Must be end of stream. */
    if(!audioflag && !videoflag)break;

    /* which is earlier; the end of the audio page or the end of the
       video page? Flush the earlier to stream */
    {
      int audio_or_video=-1;
      double audiotime=
        audioflag?vorbis_granule_time(&vd,ogg_page_granulepos(&audiopage)):-1;
      double videotime=
        videoflag?theora_granule_time(&td,ogg_page_granulepos(&videopage)):-1;

      if(!audioflag){
        audio_or_video=1;
      } else if(!videoflag) {
        audio_or_video=0;
      } else {
        if(audiotime<videotime)
          audio_or_video=0;
        else
          audio_or_video=1;
      }

      if(audio_or_video==1){
        /* flush a video page */
        video_bytesout+=fwrite(videopage.header,1,videopage.header_len,outfile);
        video_bytesout+=fwrite(videopage.body,1,videopage.body_len,outfile);
        videoflag=0;
        timebase=videotime;
        
      }else{
        /* flush an audio page */
        audio_bytesout+=fwrite(audiopage.header,1,audiopage.header_len,outfile);
        audio_bytesout+=fwrite(audiopage.body,1,audiopage.body_len,outfile);
        audioflag=0;
        timebase=audiotime;
      }
      {
        int hundredths=timebase*100-(long)timebase*100;
        int seconds=(long)timebase%60;
        int minutes=((long)timebase/60)%60;
        int hours=(long)timebase/3600;
        
        if(audio_or_video)
          vkbps=rint(video_bytesout*8./timebase*.001);
        else
          akbps=rint(audio_bytesout*8./timebase*.001);
        
        fprintf(stderr,
                "\r      %d:%02d:%02d.%02d audio: %dkbps video: %dkbps                 ",
                hours,minutes,seconds,hundredths,akbps,vkbps);
      }
    }

  }

  /* clear out state */

  if(audio){
    ogg_stream_clear(&vo);
    vorbis_block_clear(&vb);
    vorbis_dsp_clear(&vd);
    vorbis_comment_clear(&vc);
    vorbis_info_clear(&vi);
  }
  if(video){
    ogg_stream_clear(&to);
    theora_clear(&td);
  }

  if(outfile && outfile!=stdout)fclose(outfile);

  fprintf(stderr,"\r   \ndone.\n\n");

#ifdef THEORA_PERF_DATA
# ifdef WIN32
    QueryPerformanceCounter(&final_time);
    elapsed_ticks = final_time.QuadPart - start_time.QuadPart;
    ticks_per_second;
    QueryPerformanceFrequency(&ticks_per_second);
    elapsed_secs = elapsed_ticks / ticks_per_second.QuadPart;
    elapsed_sec_mod = elapsed_ticks % ticks_per_second.QuadPart;
    elapsed_secs_dbl = elapsed_secs;
    elapsed_secs_dbl += ((double)elapsed_sec_mod / (double)ticks_per_second.QuadPart);
    printf("Encode time = %lld ticks\n", elapsed_ticks);
    printf("~%lld and %lld / %lld seconds\n", elapsed_secs, elapsed_sec_mod, ticks_per_second.QuadPart);
    printf("~%Lf seconds\n", elapsed_secs_dbl);
# endif

#endif 

  return(0);

}