[xiph-commits] r13989 - trunk/theora-tools/vp32theora

j at svn.xiph.org j at svn.xiph.org
Mon Oct 15 10:10:12 PDT 2007


Author: j
Date: 2007-10-15 10:10:12 -0700 (Mon, 15 Oct 2007)
New Revision: 13989

Added:
   trunk/theora-tools/vp32theora/vp32theora.c
Removed:
   trunk/theora-tools/vp32theora/theora_transcoder.c
Log:
move to v32theora.c, remove local copy of theora_granule_time



Deleted: trunk/theora-tools/vp32theora/theora_transcoder.c
===================================================================
--- trunk/theora-tools/vp32theora/theora_transcoder.c	2007-10-15 17:01:38 UTC (rev 13988)
+++ trunk/theora-tools/vp32theora/theora_transcoder.c	2007-10-15 17:10:12 UTC (rev 13989)
@@ -1,926 +0,0 @@
-/********************************************************************
- *                                                                  *
- * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   *
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
- * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
- * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
- *                                                                  *
- * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2004                *
- * by the Xiph.Org Foundation http://www.xiph.org/                  *
- *                                                                  *
- ********************************************************************
-
-  function: example encoder application; makes an Ogg Theora/Vorbis
-            file from YUV4MPEG2 and WAV input
-  last mod: $Id: transcoder_example.c,v 1.4 2004/03/20 00:14:04 tterribe Exp $
-
- ********************************************************************/
-
-#define _GNU_SOURCE
-#define _REENTRANT
-#define _LARGEFILE_SOURCE
-#define _LARGEFILE64_SOURCE
-#define _FILE_OFFSET_BITS 64
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <time.h>
-#include <math.h>
-#include "theora/theora.h"
-#include "vorbis/codec.h"
-#include "vorbis/vorbisenc.h"
-
-#ifdef _WIN32
-/*supply missing headers and functions to Win32. going to hell, I know*/
-#include <io.h>
-#include <fcntl.h>
-
-static double rint(double x)
-{
-  if (x < 0.0)
-    return (double)(int)(x - 0.5);
-  else
-    return (double)(int)(x + 0.5);
-}
-#endif
-
-/*Copied from vorbis/sharedbook.c*/
-static int _ilog(unsigned int v){
-  int ret=0;
-  while(v){
-    ret++;
-    v>>=1;
-  }
-  return(ret);
-}
-
-
-const char *optstring = "o:a:A:v:V:";
-struct option options [] = {
-  {"output",required_argument,NULL,'o'},
-  {"audio-rate-target",required_argument,NULL,'A'},
-  {"video-rate-target",required_argument,NULL,'V'},
-  {"audio-quality",required_argument,NULL,'a'},
-  {"video-quality",required_argument,NULL,'v'},
-  {NULL,0,NULL,0}
-};
-
-typedef struct TC_INSTANCE {
-  ogg_uint32_t     LastKeyFrame ;
-  ogg_int64_t      KeyFrameCount;
-  int              ThisIsFirstFrame;
-  int              ThisIsKeyFrame;
-  ogg_uint32_t     CurrentFrame;
-  ogg_int64_t      granulepos;
-  int              keyframe_granule_shift;
-  char *           in_bytes;
-  long             in_bytecount;
-  ogg_uint32_t     fps_denominator;
-  ogg_uint32_t     fps_numerator;
-  oggpack_buffer   opb_in;
-  oggpack_buffer   opb_out;
-} TC_INSTANCE;
-
-/* You'll go to Hell for using globals. */
-
-FILE *audio=NULL;
-FILE *video=NULL;
-
-int audio_ch=0;
-int audio_hz=0;
-
-float audio_q=.1;
-int audio_r=-1;
-
-int video_x=0;
-int video_y=0;
-int frame_x=0;
-int frame_y=0;
-int frame_x_offset=0;
-int frame_y_offset=0;
-int video_hzn=0;
-int video_hzd=0;
-int video_an=0;
-int video_ad=0;
-
-int video_r=-1;
-int video_q=16;
-
-  char *vp3frame[2];
-  int framebytecount[2];
-  int frameiskey[2];
-
-    ogg_page audiopage;
-    ogg_page videopage;
-
-static void usage(void){
-  fprintf(stderr,
-          "Usage: encoder_example [options] [audio_file] video_file\n\n"
-          "Options: \n\n"
-          "  -o --output <filename.ogg>  file name for encoded output;\n"
-          "                              If this option is not given, the\n"
-          "                              compressed data is sent to stdout.\n\n"
-          "  -A --audio-rate-target <n>  bitrate target for Vorbis audio;\n"
-          "                              use -a and not -A if at all possible,\n"
-          "                              as -a gives higher quality for a given\n"
-          "                              bitrate.\n\n"
-          "  -V --video-rate-target <n>  bitrate target for Theora video\n\n"
-          "  -a --audio-quality <n>      Vorbis quality selector from -1 to 10\n"
-          "                              (-1 yields smallest files but lowest\n"
-          "                              fidelity; 10 yields highest fidelity\n"
-          "                              but large files. '2' is a reasonable\n"
-          "                              default).\n\n"
-          "   -v --video-quality <n>     Theora quality selector fro 0 to 10\n"
-          "                              (0 yields smallest files but lowest\n"
-          "                              video quality. 10 yields highest\n"
-          "                              fidelity but large files).\n\n"
-          "encoder_example accepts only uncompressed RIFF WAV format audio and\n"
-          "YUV4MPEG2 uncompressed video.\n\n");
-  exit(1);
-}
-
-static void id_file(char *f){
-  FILE *test;
-  unsigned char buffer[80];
-  int ret;
-
-  /* open it, look for magic */
-
-  if(!strcmp(f,"-")){
-    /* stdin */
-    test=stdin;
-  }else{
-    test=fopen(f,"rb");
-    if(!test){
-      fprintf(stderr,"Unable to open file %s.\n",f);
-      exit(1);
-    }
-  }
-
-  ret=fread(buffer,1,4,test);
-  if(ret<4){
-    fprintf(stderr,"EOF determining file type of file %s.\n",f);
-    exit(1);
-  }
-
-  if(!memcmp(buffer,"RIFF",4)){
-    /* possible WAV file */
-
-    if(audio){
-      /* umm, we already have one */
-      fprintf(stderr,"Multiple RIFF WAVE files specified on command line.\n");
-      exit(1);
-    }
-
-    /* Parse the rest of the header */
-
-    ret=fread(buffer,1,4,test);
-    ret=fread(buffer,1,4,test);
-    if(ret<4)goto riff_err;
-    if(!memcmp(buffer,"WAVE",4)){
-
-      while(!feof(test)){
-        ret=fread(buffer,1,4,test);
-        if(ret<4)goto riff_err;
-        if(!memcmp("fmt",buffer,3)){
-
-          /* OK, this is our audio specs chunk.  Slurp it up. */
-
-          ret=fread(buffer,1,20,test);
-          if(ret<20)goto riff_err;
-
-          if(memcmp(buffer+4,"\001\000",2)){
-            fprintf(stderr,"The WAV file %s is in a compressed format; "
-                    "can't read it.\n",f);
-            exit(1);
-          }
-
-          audio=test;
-          audio_ch=buffer[6]+(buffer[7]<<8);
-          audio_hz=buffer[8]+(buffer[9]<<8)+
-            (buffer[10]<<16)+(buffer[11]<<24);
-
-          if(buffer[18]+(buffer[19]<<8)!=16){
-            fprintf(stderr,"Can only read 16 bit WAV files for now.\n");
-            exit(1);
-          }
-
-          /* Now, align things to the beginning of the data */
-          /* Look for 'dataxxxx' */
-          while(!feof(test)){
-            ret=fread(buffer,1,4,test);
-            if(ret<4)goto riff_err;
-            if(!memcmp("data",buffer,4)){
-              /* We're there.  Ignore the declared size for now. */
-              ret=fread(buffer,1,4,test);
-              if(ret<4)goto riff_err;
-
-              fprintf(stderr,"File %s is 16 bit %d channel %d Hz RIFF WAV audio.\n",
-                      f,audio_ch,audio_hz);
-
-              return;
-            }
-          }
-        }
-      }
-    }
-
-    fprintf(stderr,"Couldn't find WAVE data in RIFF file %s.\n",f);
-    exit(1);
-
-  }
-  if(!memcmp(buffer,"AVI2",4)){
-    /* possible AVI2VP31 format file */
-    /* read until newline, or 80 cols, whichever happens first */
-    int i;
-    for(i=0;i<79;i++){
-      ret=fread(buffer+i,1,1,test);
-      if(ret<1)goto yuv_err;
-      if(buffer[i]=='\n')break;
-    }
-    if(i==79){
-      fprintf(stderr,"Error parsing %s header; not a VP31 raw frames file?\n",f);
-    }
-    buffer[i]='\0';
-
-    if(!memcmp(buffer,"VP31",4)){
-      char interlace;
-
-      if(video){
-        /* umm, we already have one */
-        fprintf(stderr,"Multiple video files specified on command line.\n");
-        exit(1);
-      }
-
-      if(buffer[4]!='R'){
-        fprintf(stderr,"Incorrect file ; VP31 raw frames required.\n");
-      }
-
-      ret=sscanf(buffer,"VP31R W%d H%d F%d:%d I%c A%d:%d",
-                 &frame_x,&frame_y,&video_hzn,&video_hzd,&interlace,
-                 &video_an,&video_ad);
-      if(ret<7){
-        fprintf(stderr,"Error parsing AVI2VP31R header in file %s.\n",f);
-        exit(1);
-      }
-
-      if(interlace!='p'){
-        fprintf(stderr,"Input video is interlaced; Theora handles only progressive scan\n");
-        exit(1);
-      }
-
-      video=test;
-
-      fprintf(stderr,"File %s is %dx%d %.02f fps VP31 video.\n",
-              f,frame_x,frame_y,(double)video_hzn/video_hzd);
-
-      return;
-    }
-  }
-  fprintf(stderr,"Input file %s is neither a WAV nor VP31 file.\n",f);
-  exit(1);
-
- riff_err:
-  fprintf(stderr,"EOF parsing RIFF file %s.\n",f);
-  exit(1);
- yuv_err:
-  fprintf(stderr,"EOF parsing VP31 file %s.\n",f);
-  exit(1);
-
-}
-
-int spinner=0;
-char *spinascii="|/-\\";
-void spinnit(void){
-  spinner++;
-  if(spinner==4)spinner=0;
-  fprintf(stderr,"\r%c",spinascii[spinner]);
-}
-
-int fetch_and_process_audio(FILE *audio,ogg_page *audiopage,
-                            ogg_stream_state *vo,
-                            vorbis_dsp_state *vd,
-                            vorbis_block *vb,
-                            int audioflag){
-  ogg_packet op;
-  int i,j;
-
-  while(audio && !audioflag){
-    /* process any audio already buffered */
-    spinnit();
-    if(ogg_stream_pageout(vo,audiopage)>0) return 1;
-    if(ogg_stream_eos(vo))return 0;
-
-    {
-      /* read and process more audio */
-      signed char readbuffer[4096];
-      int toread=4096/2/audio_ch;
-      int bytesread=fread(readbuffer,1,toread*2*audio_ch,audio);
-      int sampread=bytesread/2/audio_ch;
-      float **vorbis_buffer;
-      int count=0;
-
-      if(bytesread<=0){
-        /* end of file.  this can be done implicitly, but it's
-           easier to see here in non-clever fashion.  Tell the
-           library we're at end of stream so that it can handle the
-           last frame and mark end of stream in the output properly */
-        vorbis_analysis_wrote(vd,0);
-      }else{
-        vorbis_buffer=vorbis_analysis_buffer(vd,sampread);
-        /* uninterleave samples */
-        for(i=0;i<sampread;i++){
-          for(j=0;j<audio_ch;j++){
-            vorbis_buffer[j][i]=((readbuffer[count+1]<<8)|
-                                 (0x00ff&(int)readbuffer[count]))/32768.f;
-            count+=2;
-          }
-        }
-        
-        vorbis_analysis_wrote(vd,sampread);
-        
-      }
-
-      while(vorbis_analysis_blockout(vd,vb)==1){
-        
-        /* analysis, assume we want to use bitrate management */
-        vorbis_analysis(vb,NULL);
-        vorbis_bitrate_addblock(vb);
-        
-        /* weld packets into the bitstream */
-        while(vorbis_bitrate_flushpacket(vd,&op))
-          ogg_stream_packetin(vo,&op);
-        
-      }
-    }
-  }
-
-  return audioflag;
-}
-
-int theora_transcode_packetout( TC_INSTANCE *ttc, int last_p, ogg_packet *op){
-
-  long bytes=ttc->in_bytecount;
-
-  if(!bytes)return(0);
-
-  op->packet=ttc->in_bytes;
-  op->bytes=bytes;
-  op->b_o_s=0;
-  op->e_o_s=last_p;
-
-  op->packetno=ttc->CurrentFrame;
-  op->granulepos=ttc->granulepos;
-
-  return 1;
-}
-
-void TranscodeKeyFrame(TC_INSTANCE *ttc){
-    /* Keep track of the total number of Key Frames Coded */
-    ttc->KeyFrameCount += 1;
-    ttc->LastKeyFrame = 1;
-}
-
-void TranscodeFrame(TC_INSTANCE *ttc){
-    ttc->LastKeyFrame++;
-}
-
-void TranscodeFirstFrame(TC_INSTANCE *ttc){
-  /* Keep track of the total number of Key Frames Coded. */
-  ttc->KeyFrameCount = 1;
-  ttc->LastKeyFrame = 1;
-}
-
-int theora_transcode_bufferin( TC_INSTANCE *ttc, int isKeyFrame, char * bytes, int bytecount){
-
-  /*transcode: record keyframe flag*/
-  ttc->ThisIsKeyFrame = isKeyFrame;
-
-  /* Special case for first frame */
-  if ( ttc->ThisIsFirstFrame ){
-    ttc->ThisIsFirstFrame = 0;
-    ttc->ThisIsKeyFrame = 0;
-  } else if ( ttc->ThisIsKeyFrame ) {
-    TranscodeKeyFrame(ttc);
-    ttc->ThisIsKeyFrame = 0;
-  } else  {
-    /* Compress the frame. */
-    TranscodeFrame( ttc );
-  }
-  /*need to pack info here*/
-  {
-
-    int            frame_type;
-    long           total_bits;
-    long           total_words;
-    int            frac_bits;
-
-    oggpackB_readinit(&ttc->opb_in,bytes,bytecount);
-    oggpackB_reset(&ttc->opb_out);
-
-    /*Mark as video frame.*/
-    oggpackB_write(&ttc->opb_out,0,1);
-    /*Copy frame type.*/
-    frame_type=oggpackB_read1(&ttc->opb_in);
-    oggpackB_write(&ttc->opb_out,frame_type,1);
-    /*Skip an unused bit in the VP32 header.*/
-    oggpackB_adv1(&ttc->opb_in);
-    /*Copy Q multiplier.*/
-    oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,6),6);
-    /*VP3 has no per-block Q multipliers*/
-    oggpackB_write(&ttc->opb_out,0,1);
-    /*If the frame is a base/key/golden frame, copy a few extra bits.*/
-    if(frame_type==0){
-      /*These 13 bits are not included in a Theora frame header.
-        They were 0's and VP3 version info in VP32.*/
-      oggpackB_adv(&ttc->opb_in,13);
-      /*Copy the key frame type and the spare configuration bits.*/
-      oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,3),3);
-    }
-
-    /*Copy the rest of the bits over.*/
-    total_bits=bytecount*8-oggpack_bits(&ttc->opb_in);
-    frac_bits=(int)(total_bits&31);
-    if(frac_bits){
-      oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,frac_bits),
-       frac_bits);
-    }
-    total_words=total_bits>>5;
-    while(total_words-->0){
-      oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,32),32);
-    }
-
-    ttc->in_bytecount = oggpackB_bytes(&ttc->opb_out);
-    ttc->in_bytes = oggpackB_get_buffer(&ttc->opb_out);
-  }
-
-  /* Update stats variables. */
-  ttc->CurrentFrame++;
-
-  ttc->granulepos=
-    ((ttc->CurrentFrame-ttc->LastKeyFrame-1)<<ttc->keyframe_granule_shift)+
-    ttc->LastKeyFrame-1;
-
-  return 0;
-}
-
-//static void _tp_writebuffer(oggpack_buffer *opb, const char *buf, const long len)
-
-int theora_transcoder_init(theora_info * ti, TC_INSTANCE * ttc){
-  memset(ttc, 0, sizeof(*ttc));
-  ttc->granulepos = -1;
-  ttc->keyframe_granule_shift=_ilog(ti->keyframe_frequency_force-1);
-  ttc->LastKeyFrame  = 0;
-  ttc->KeyFrameCount = 0;
-  ttc->ThisIsFirstFrame = 1;
-  ttc->ThisIsKeyFrame = 0;
-  ttc->CurrentFrame = 1; 
-  ttc->in_bytes = 0;
-  ttc->in_bytecount  = 0;
-  ttc->fps_denominator = ti->fps_denominator;
-  ttc->fps_numerator = ti->fps_numerator;
-  oggpackB_writeinit(&ttc->opb_out);
-  return 0;
-}
-
-int fetch_and_process_video(FILE *video,ogg_page *videopage,
-                            ogg_stream_state *to,
-                            TC_INSTANCE *ttc,
-                            int videoflag){
-  /* You'll go to Hell for using static variables */
-  static int          state=-1;
-  ogg_packet          op;
-  int i;
-  int keyframeflag, framelength;
-
-
-  if(state==-1){
-        /* initialize the double frame buffer */
-    state=0;
-  }
-
-  /* is there a video page flushed?  If not, work until there is. */
-  while(!videoflag){
-    spinnit();
-
-    if(ogg_stream_pageout(to,videopage)>0) return 1;
-    if(ogg_stream_eos(to)) return 0;
-
-    {
-      /* read and process more video */
-      /* video strategy reads one frame ahead so we know when we're
-         at end of stream and can mark last video frame as such
-         (vorbis audio has to flush one frame past last video frame
-         due to overlap and thus doesn't need this extra work */
-
-      /* have two frame buffers full (if possible) before
-         proceeding.  after first pass and until eos, one will
-         always be full when we get here */
-
-      for(i=state;i<2;i++){
-        char c,frame[6];
-        int ret=fread(frame,1,6,video);
-        
-	/* match and skip the frame header */
-        if(ret<6)break;
-        if(memcmp(frame,"FRAME",5)){
-          fprintf(stderr,"Loss of framing in VP31 input data\n");
-          exit(1);
-        }
-        if(frame[5]!='\n'){
-          int j;
-          for(j=0;j<79;j++)
-            if(fread(&c,1,1,video)&&c=='\n')break;
-          if(j==79){
-            fprintf(stderr,"Error parsing VP31 frame header\n");
-            exit(1);
-          }
-        }
-
-        /*read the length*/
-        ret=fread(&framelength, sizeof(int), 1, video);
-
-        /*read the keyframeflag*/
-        ret=fread(&keyframeflag, sizeof(int), 1, video);
-
-        vp3frame[i] = malloc(framelength);
-        framebytecount[i] = framelength;
-        frameiskey[i] = keyframeflag;
-
-        /* read the frame */
-        ret=fread((char *) vp3frame[i], sizeof(char), framelength, video);
-            if(ret!=framelength) break;
-        
-        state++;
-      }
-
-      if(state<1){
-        /* can't get here unless VP31 stream has no video */
-        fprintf(stderr,"Video input contains no frames.\n");
-        exit(1);
-      }
-
-      /* Theora is a one-frame-in,one-frame-out system; submit a frame
-         for compression and pull out the packet */
-
-      //theora_encode_YUVin(td,&yuv);
-      theora_transcode_bufferin( ttc, frameiskey[0], vp3frame[0], framebytecount[0]);
-
-      /* if there's only one frame, it's the last in the stream */
-      if(state<2)
-        theora_transcode_packetout(ttc,1,&op);
-      else
-        theora_transcode_packetout(ttc,0,&op);
-
-      ogg_stream_packetin(to,&op);
-
-      {
-        signed char *temp=vp3frame[0];
-        vp3frame[0]=vp3frame[1];
-        vp3frame[1] = temp;
-        free(temp);
-        
-        framebytecount[0]= framebytecount[1];
-        frameiskey[0] = frameiskey[1];
-        state--;
-      }
-    }
-  }
-  return videoflag;
-}
-
-/* returns, in seconds, absolute time of current packet in given
-   logical stream */
-double transcode_granule_time(TC_INSTANCE *ttc,ogg_int64_t granulepos){
-  if(granulepos>=0){
-    ogg_int64_t iframe=granulepos>>ttc->keyframe_granule_shift;
-    ogg_int64_t pframe=granulepos-(iframe<<ttc->keyframe_granule_shift);
-
-    return (iframe+pframe)*
-      ((double)ttc->fps_denominator/ttc->fps_numerator);
-
-  }
-  return(-1);
-}
-
-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;
-
-  TC_INSTANCE ttc;
-
-#ifdef _WIN32 /* 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;
-    default:
-      usage();
-    }
-  }
-
-  while(optind<argc){
-    /* assume that anything following the options must be a filename */
-    id_file(argv[optind]);
-    optind++;
-  }
-
-  /* yayness.  Set up Ogg output stream */
-  srand(time(NULL));
-  ogg_stream_init(&vo,rand());
-  ogg_stream_init(&to,rand()); /* oops, add one ot the above */
-
-  /* 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;
-  frame_x_offset=(video_x-frame_x)/2;
-  frame_y_offset=(video_y-frame_y)/2;
-
-  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.target_bitrate=video_r;
-  ti.quality=video_q;
-
-  ti.dropframes_p=0;
-  ti.quick_p=1;
-  ti.keyframe_auto_p=1;
-  ti.keyframe_frequency=32768;
-  ti.keyframe_frequency_force=32768;
-  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_transcoder_init(&ti, &ttc);
-  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_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){
-
-
-    /* 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,&ttc,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?transcode_granule_time(&ttc,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,
-                "\n      %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");
-
-  return(0);
-
-}

Copied: trunk/theora-tools/vp32theora/vp32theora.c (from rev 13987, trunk/theora-tools/vp32theora/theora_transcoder.c)
===================================================================
--- trunk/theora-tools/vp32theora/vp32theora.c	                        (rev 0)
+++ trunk/theora-tools/vp32theora/vp32theora.c	2007-10-15 17:10:12 UTC (rev 13989)
@@ -0,0 +1,912 @@
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
+ *                                                                  *
+ * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2004                *
+ * by the Xiph.Org Foundation http://www.xiph.org/                  *
+ *                                                                  *
+ ********************************************************************
+
+  function: example encoder application; makes an Ogg Theora/Vorbis
+            file from YUV4MPEG2 and WAV input
+  last mod: $Id: transcoder_example.c,v 1.4 2004/03/20 00:14:04 tterribe Exp $
+
+ ********************************************************************/
+
+#define _GNU_SOURCE
+#define _REENTRANT
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <time.h>
+#include <math.h>
+#include "theora/theora.h"
+#include "vorbis/codec.h"
+#include "vorbis/vorbisenc.h"
+
+#ifdef _WIN32
+/*supply missing headers and functions to Win32. going to hell, I know*/
+#include <io.h>
+#include <fcntl.h>
+
+static double rint(double x)
+{
+  if (x < 0.0)
+    return (double)(int)(x - 0.5);
+  else
+    return (double)(int)(x + 0.5);
+}
+#endif
+
+/*Copied from vorbis/sharedbook.c*/
+static int _ilog(unsigned int v){
+  int ret=0;
+  while(v){
+    ret++;
+    v>>=1;
+  }
+  return(ret);
+}
+
+
+const char *optstring = "o:a:A:v:V:";
+struct option options [] = {
+  {"output",required_argument,NULL,'o'},
+  {"audio-rate-target",required_argument,NULL,'A'},
+  {"video-rate-target",required_argument,NULL,'V'},
+  {"audio-quality",required_argument,NULL,'a'},
+  {"video-quality",required_argument,NULL,'v'},
+  {NULL,0,NULL,0}
+};
+
+typedef struct TC_INSTANCE {
+  ogg_uint32_t     LastKeyFrame ;
+  ogg_int64_t      KeyFrameCount;
+  int              ThisIsFirstFrame;
+  int              ThisIsKeyFrame;
+  ogg_uint32_t     CurrentFrame;
+  ogg_int64_t      granulepos;
+  int              keyframe_granule_shift;
+  char *           in_bytes;
+  long             in_bytecount;
+  ogg_uint32_t     fps_denominator;
+  ogg_uint32_t     fps_numerator;
+  oggpack_buffer   opb_in;
+  oggpack_buffer   opb_out;
+} TC_INSTANCE;
+
+/* You'll go to Hell for using globals. */
+
+FILE *audio=NULL;
+FILE *video=NULL;
+
+int audio_ch=0;
+int audio_hz=0;
+
+float audio_q=.1;
+int audio_r=-1;
+
+int video_x=0;
+int video_y=0;
+int frame_x=0;
+int frame_y=0;
+int frame_x_offset=0;
+int frame_y_offset=0;
+int video_hzn=0;
+int video_hzd=0;
+int video_an=0;
+int video_ad=0;
+
+int video_r=-1;
+int video_q=16;
+
+  char *vp3frame[2];
+  int framebytecount[2];
+  int frameiskey[2];
+
+    ogg_page audiopage;
+    ogg_page videopage;
+
+static void usage(void){
+  fprintf(stderr,
+          "Usage: encoder_example [options] [audio_file] video_file\n\n"
+          "Options: \n\n"
+          "  -o --output <filename.ogg>  file name for encoded output;\n"
+          "                              If this option is not given, the\n"
+          "                              compressed data is sent to stdout.\n\n"
+          "  -A --audio-rate-target <n>  bitrate target for Vorbis audio;\n"
+          "                              use -a and not -A if at all possible,\n"
+          "                              as -a gives higher quality for a given\n"
+          "                              bitrate.\n\n"
+          "  -V --video-rate-target <n>  bitrate target for Theora video\n\n"
+          "  -a --audio-quality <n>      Vorbis quality selector from -1 to 10\n"
+          "                              (-1 yields smallest files but lowest\n"
+          "                              fidelity; 10 yields highest fidelity\n"
+          "                              but large files. '2' is a reasonable\n"
+          "                              default).\n\n"
+          "   -v --video-quality <n>     Theora quality selector fro 0 to 10\n"
+          "                              (0 yields smallest files but lowest\n"
+          "                              video quality. 10 yields highest\n"
+          "                              fidelity but large files).\n\n"
+          "encoder_example accepts only uncompressed RIFF WAV format audio and\n"
+          "YUV4MPEG2 uncompressed video.\n\n");
+  exit(1);
+}
+
+static void id_file(char *f){
+  FILE *test;
+  unsigned char buffer[80];
+  int ret;
+
+  /* open it, look for magic */
+
+  if(!strcmp(f,"-")){
+    /* stdin */
+    test=stdin;
+  }else{
+    test=fopen(f,"rb");
+    if(!test){
+      fprintf(stderr,"Unable to open file %s.\n",f);
+      exit(1);
+    }
+  }
+
+  ret=fread(buffer,1,4,test);
+  if(ret<4){
+    fprintf(stderr,"EOF determining file type of file %s.\n",f);
+    exit(1);
+  }
+
+  if(!memcmp(buffer,"RIFF",4)){
+    /* possible WAV file */
+
+    if(audio){
+      /* umm, we already have one */
+      fprintf(stderr,"Multiple RIFF WAVE files specified on command line.\n");
+      exit(1);
+    }
+
+    /* Parse the rest of the header */
+
+    ret=fread(buffer,1,4,test);
+    ret=fread(buffer,1,4,test);
+    if(ret<4)goto riff_err;
+    if(!memcmp(buffer,"WAVE",4)){
+
+      while(!feof(test)){
+        ret=fread(buffer,1,4,test);
+        if(ret<4)goto riff_err;
+        if(!memcmp("fmt",buffer,3)){
+
+          /* OK, this is our audio specs chunk.  Slurp it up. */
+
+          ret=fread(buffer,1,20,test);
+          if(ret<20)goto riff_err;
+
+          if(memcmp(buffer+4,"\001\000",2)){
+            fprintf(stderr,"The WAV file %s is in a compressed format; "
+                    "can't read it.\n",f);
+            exit(1);
+          }
+
+          audio=test;
+          audio_ch=buffer[6]+(buffer[7]<<8);
+          audio_hz=buffer[8]+(buffer[9]<<8)+
+            (buffer[10]<<16)+(buffer[11]<<24);
+
+          if(buffer[18]+(buffer[19]<<8)!=16){
+            fprintf(stderr,"Can only read 16 bit WAV files for now.\n");
+            exit(1);
+          }
+
+          /* Now, align things to the beginning of the data */
+          /* Look for 'dataxxxx' */
+          while(!feof(test)){
+            ret=fread(buffer,1,4,test);
+            if(ret<4)goto riff_err;
+            if(!memcmp("data",buffer,4)){
+              /* We're there.  Ignore the declared size for now. */
+              ret=fread(buffer,1,4,test);
+              if(ret<4)goto riff_err;
+
+              fprintf(stderr,"File %s is 16 bit %d channel %d Hz RIFF WAV audio.\n",
+                      f,audio_ch,audio_hz);
+
+              return;
+            }
+          }
+        }
+      }
+    }
+
+    fprintf(stderr,"Couldn't find WAVE data in RIFF file %s.\n",f);
+    exit(1);
+
+  }
+  if(!memcmp(buffer,"AVI2",4)){
+    /* possible AVI2VP31 format file */
+    /* read until newline, or 80 cols, whichever happens first */
+    int i;
+    for(i=0;i<79;i++){
+      ret=fread(buffer+i,1,1,test);
+      if(ret<1)goto yuv_err;
+      if(buffer[i]=='\n')break;
+    }
+    if(i==79){
+      fprintf(stderr,"Error parsing %s header; not a VP31 raw frames file?\n",f);
+    }
+    buffer[i]='\0';
+
+    if(!memcmp(buffer,"VP31",4)){
+      char interlace;
+
+      if(video){
+        /* umm, we already have one */
+        fprintf(stderr,"Multiple video files specified on command line.\n");
+        exit(1);
+      }
+
+      if(buffer[4]!='R'){
+        fprintf(stderr,"Incorrect file ; VP31 raw frames required.\n");
+      }
+
+      ret=sscanf(buffer,"VP31R W%d H%d F%d:%d I%c A%d:%d",
+                 &frame_x,&frame_y,&video_hzn,&video_hzd,&interlace,
+                 &video_an,&video_ad);
+      if(ret<7){
+        fprintf(stderr,"Error parsing AVI2VP31R header in file %s.\n",f);
+        exit(1);
+      }
+
+      if(interlace!='p'){
+        fprintf(stderr,"Input video is interlaced; Theora handles only progressive scan\n");
+        exit(1);
+      }
+
+      video=test;
+
+      fprintf(stderr,"File %s is %dx%d %.02f fps VP31 video.\n",
+              f,frame_x,frame_y,(double)video_hzn/video_hzd);
+
+      return;
+    }
+  }
+  fprintf(stderr,"Input file %s is neither a WAV nor VP31 file.\n",f);
+  exit(1);
+
+ riff_err:
+  fprintf(stderr,"EOF parsing RIFF file %s.\n",f);
+  exit(1);
+ yuv_err:
+  fprintf(stderr,"EOF parsing VP31 file %s.\n",f);
+  exit(1);
+
+}
+
+int spinner=0;
+char *spinascii="|/-\\";
+void spinnit(void){
+  spinner++;
+  if(spinner==4)spinner=0;
+  fprintf(stderr,"\r%c",spinascii[spinner]);
+}
+
+int fetch_and_process_audio(FILE *audio,ogg_page *audiopage,
+                            ogg_stream_state *vo,
+                            vorbis_dsp_state *vd,
+                            vorbis_block *vb,
+                            int audioflag){
+  ogg_packet op;
+  int i,j;
+
+  while(audio && !audioflag){
+    /* process any audio already buffered */
+    spinnit();
+    if(ogg_stream_pageout(vo,audiopage)>0) return 1;
+    if(ogg_stream_eos(vo))return 0;
+
+    {
+      /* read and process more audio */
+      signed char readbuffer[4096];
+      int toread=4096/2/audio_ch;
+      int bytesread=fread(readbuffer,1,toread*2*audio_ch,audio);
+      int sampread=bytesread/2/audio_ch;
+      float **vorbis_buffer;
+      int count=0;
+
+      if(bytesread<=0){
+        /* end of file.  this can be done implicitly, but it's
+           easier to see here in non-clever fashion.  Tell the
+           library we're at end of stream so that it can handle the
+           last frame and mark end of stream in the output properly */
+        vorbis_analysis_wrote(vd,0);
+      }else{
+        vorbis_buffer=vorbis_analysis_buffer(vd,sampread);
+        /* uninterleave samples */
+        for(i=0;i<sampread;i++){
+          for(j=0;j<audio_ch;j++){
+            vorbis_buffer[j][i]=((readbuffer[count+1]<<8)|
+                                 (0x00ff&(int)readbuffer[count]))/32768.f;
+            count+=2;
+          }
+        }
+        
+        vorbis_analysis_wrote(vd,sampread);
+        
+      }
+
+      while(vorbis_analysis_blockout(vd,vb)==1){
+        
+        /* analysis, assume we want to use bitrate management */
+        vorbis_analysis(vb,NULL);
+        vorbis_bitrate_addblock(vb);
+        
+        /* weld packets into the bitstream */
+        while(vorbis_bitrate_flushpacket(vd,&op))
+          ogg_stream_packetin(vo,&op);
+        
+      }
+    }
+  }
+
+  return audioflag;
+}
+
+int vp32theora_packetout( TC_INSTANCE *ttc, int last_p, ogg_packet *op){
+
+  long bytes=ttc->in_bytecount;
+
+  if(!bytes)return(0);
+
+  op->packet=ttc->in_bytes;
+  op->bytes=bytes;
+  op->b_o_s=0;
+  op->e_o_s=last_p;
+
+  op->packetno=ttc->CurrentFrame;
+  op->granulepos=ttc->granulepos;
+
+  return 1;
+}
+
+void TranscodeKeyFrame(TC_INSTANCE *ttc){
+    /* Keep track of the total number of Key Frames Coded */
+    ttc->KeyFrameCount += 1;
+    ttc->LastKeyFrame = 1;
+}
+
+void TranscodeFrame(TC_INSTANCE *ttc){
+    ttc->LastKeyFrame++;
+}
+
+void TranscodeFirstFrame(TC_INSTANCE *ttc){
+  /* Keep track of the total number of Key Frames Coded. */
+  ttc->KeyFrameCount = 1;
+  ttc->LastKeyFrame = 1;
+}
+
+int vp32theora_bufferin( TC_INSTANCE *ttc, int isKeyFrame, char * bytes, int bytecount){
+
+  /*transcode: record keyframe flag*/
+  ttc->ThisIsKeyFrame = isKeyFrame;
+
+  /* Special case for first frame */
+  if ( ttc->ThisIsFirstFrame ){
+    ttc->ThisIsFirstFrame = 0;
+    ttc->ThisIsKeyFrame = 0;
+  } else if ( ttc->ThisIsKeyFrame ) {
+    TranscodeKeyFrame(ttc);
+    ttc->ThisIsKeyFrame = 0;
+  } else  {
+    /* Compress the frame. */
+    TranscodeFrame( ttc );
+  }
+  /*need to pack info here*/
+  {
+
+    int            frame_type;
+    long           total_bits;
+    long           total_words;
+    int            frac_bits;
+
+    oggpackB_readinit(&ttc->opb_in,bytes,bytecount);
+    oggpackB_reset(&ttc->opb_out);
+
+    /*Mark as video frame.*/
+    oggpackB_write(&ttc->opb_out,0,1);
+    /*Copy frame type.*/
+    frame_type=oggpackB_read1(&ttc->opb_in);
+    oggpackB_write(&ttc->opb_out,frame_type,1);
+    /*Skip an unused bit in the VP32 header.*/
+    oggpackB_adv1(&ttc->opb_in);
+    /*Copy Q multiplier.*/
+    oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,6),6);
+    /*VP3 has no per-block Q multipliers*/
+    oggpackB_write(&ttc->opb_out,0,1);
+    /*If the frame is a base/key/golden frame, copy a few extra bits.*/
+    if(frame_type==0){
+      /*These 13 bits are not included in a Theora frame header.
+        They were 0's and VP3 version info in VP32.*/
+      oggpackB_adv(&ttc->opb_in,13);
+      /*Copy the key frame type and the spare configuration bits.*/
+      oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,3),3);
+    }
+
+    /*Copy the rest of the bits over.*/
+    total_bits=bytecount*8-oggpack_bits(&ttc->opb_in);
+    frac_bits=(int)(total_bits&31);
+    if(frac_bits){
+      oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,frac_bits),
+       frac_bits);
+    }
+    total_words=total_bits>>5;
+    while(total_words-->0){
+      oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,32),32);
+    }
+
+    ttc->in_bytecount = oggpackB_bytes(&ttc->opb_out);
+    ttc->in_bytes = oggpackB_get_buffer(&ttc->opb_out);
+  }
+
+  /* Update stats variables. */
+  ttc->CurrentFrame++;
+
+  ttc->granulepos=
+    ((ttc->CurrentFrame-ttc->LastKeyFrame-1)<<ttc->keyframe_granule_shift)+
+    ttc->LastKeyFrame-1;
+
+  return 0;
+}
+
+//static void _tp_writebuffer(oggpack_buffer *opb, const char *buf, const long len)
+
+int theora_transcoder_init(theora_info * ti, TC_INSTANCE * ttc){
+  memset(ttc, 0, sizeof(*ttc));
+  ttc->granulepos = -1;
+  ttc->keyframe_granule_shift=_ilog(ti->keyframe_frequency_force-1);
+  ttc->LastKeyFrame  = 0;
+  ttc->KeyFrameCount = 0;
+  ttc->ThisIsFirstFrame = 1;
+  ttc->ThisIsKeyFrame = 0;
+  ttc->CurrentFrame = 1; 
+  ttc->in_bytes = 0;
+  ttc->in_bytecount  = 0;
+  ttc->fps_denominator = ti->fps_denominator;
+  ttc->fps_numerator = ti->fps_numerator;
+  oggpackB_writeinit(&ttc->opb_out);
+  return 0;
+}
+
+int fetch_and_process_video(FILE *video,ogg_page *videopage,
+                            ogg_stream_state *to,
+                            TC_INSTANCE *ttc,
+                            int videoflag){
+  /* You'll go to Hell for using static variables */
+  static int          state=-1;
+  ogg_packet          op;
+  int i;
+  int keyframeflag, framelength;
+
+
+  if(state==-1){
+        /* initialize the double frame buffer */
+    state=0;
+  }
+
+  /* is there a video page flushed?  If not, work until there is. */
+  while(!videoflag){
+    spinnit();
+
+    if(ogg_stream_pageout(to,videopage)>0) return 1;
+    if(ogg_stream_eos(to)) return 0;
+
+    {
+      /* read and process more video */
+      /* video strategy reads one frame ahead so we know when we're
+         at end of stream and can mark last video frame as such
+         (vorbis audio has to flush one frame past last video frame
+         due to overlap and thus doesn't need this extra work */
+
+      /* have two frame buffers full (if possible) before
+         proceeding.  after first pass and until eos, one will
+         always be full when we get here */
+
+      for(i=state;i<2;i++){
+        char c,frame[6];
+        int ret=fread(frame,1,6,video);
+        
+	/* match and skip the frame header */
+        if(ret<6)break;
+        if(memcmp(frame,"FRAME",5)){
+          fprintf(stderr,"Loss of framing in VP31 input data\n");
+          exit(1);
+        }
+        if(frame[5]!='\n'){
+          int j;
+          for(j=0;j<79;j++)
+            if(fread(&c,1,1,video)&&c=='\n')break;
+          if(j==79){
+            fprintf(stderr,"Error parsing VP31 frame header\n");
+            exit(1);
+          }
+        }
+
+        /*read the length*/
+        ret=fread(&framelength, sizeof(int), 1, video);
+
+        /*read the keyframeflag*/
+        ret=fread(&keyframeflag, sizeof(int), 1, video);
+
+        vp3frame[i] = malloc(framelength);
+        framebytecount[i] = framelength;
+        frameiskey[i] = keyframeflag;
+
+        /* read the frame */
+        ret=fread((char *) vp3frame[i], sizeof(char), framelength, video);
+            if(ret!=framelength) break;
+        
+        state++;
+      }
+
+      if(state<1){
+        /* can't get here unless VP31 stream has no video */
+        fprintf(stderr,"Video input contains no frames.\n");
+        exit(1);
+      }
+
+      /* Theora is a one-frame-in,one-frame-out system; submit a frame
+         for compression and pull out the packet */
+
+      //theora_encode_YUVin(td,&yuv);
+      vp32theora_bufferin( ttc, frameiskey[0], vp3frame[0], framebytecount[0]);
+
+      /* if there's only one frame, it's the last in the stream */
+      if(state<2)
+        vp32theora_packetout(ttc,1,&op);
+      else
+        vp32theora_packetout(ttc,0,&op);
+
+      ogg_stream_packetin(to,&op);
+
+      {
+        signed char *temp=vp3frame[0];
+        vp3frame[0]=vp3frame[1];
+        vp3frame[1] = temp;
+        free(temp);
+        
+        framebytecount[0]= framebytecount[1];
+        frameiskey[0] = frameiskey[1];
+        state--;
+      }
+    }
+  }
+  return videoflag;
+}
+
+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;
+
+  TC_INSTANCE ttc;
+
+#ifdef _WIN32 /* 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;
+    default:
+      usage();
+    }
+  }
+
+  while(optind<argc){
+    /* assume that anything following the options must be a filename */
+    id_file(argv[optind]);
+    optind++;
+  }
+
+  /* yayness.  Set up Ogg output stream */
+  srand(time(NULL));
+  ogg_stream_init(&vo,rand());
+  ogg_stream_init(&to,rand()); /* oops, add one ot the above */
+
+  /* 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;
+  frame_x_offset=(video_x-frame_x)/2;
+  frame_y_offset=(video_y-frame_y)/2;
+
+  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.target_bitrate=video_r;
+  ti.quality=video_q;
+
+  ti.dropframes_p=0;
+  ti.quick_p=1;
+  ti.keyframe_auto_p=1;
+  ti.keyframe_frequency=32768;
+  ti.keyframe_frequency_force=32768;
+  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_transcoder_init(&ti, &ttc);
+  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_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){
+
+
+    /* 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,&ttc,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(&ttc,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,
+                "\n      %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");
+
+  return(0);
+
+}



More information about the commits mailing list