Add Russian translation provided by Валерий Крувялис <valkru@mail.ru>
[xiph-mirror.git] / theora-old / examples / encoder_example.c
blob72737b964bd2d90447c921804cd12a515cedd267
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2003 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
10 * *
11 ********************************************************************
13 function: example encoder application; makes an Ogg Theora/Vorbis
14 file from YUV4MPEG2 and WAV input
15 last mod: $Id$
17 ********************************************************************/
19 #define _GNU_SOURCE
20 #define _LARGEFILE_SOURCE
21 #define _LARGEFILE64_SOURCE
22 #define _FILE_OFFSET_BITS 64
24 /* Define to give performance data win32 only*/
25 //#define THEORA_PERF_DATA
26 #ifdef THEORA_PERF_DATA
27 #include <windows.h>
28 #endif
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
33 #endif
35 #ifndef _REENTRANT
36 # define _REENTRANT
37 #endif
39 #include <stdio.h>
40 #ifndef WIN32
41 #include <unistd.h>
42 #endif
43 #include <stdlib.h>
44 #include <string.h>
45 #ifndef WIN32
46 #include <getopt.h>
47 #else
48 #include "getopt.h"
49 #endif
50 #include <time.h>
51 #include <math.h>
52 #include "theora/theora.h"
53 #include "vorbis/codec.h"
54 #include "vorbis/vorbisenc.h"
56 #ifdef _WIN32
57 /* supply missing headers and functions to Win32 */
59 #include <fcntl.h>
61 static double rint(double x)
63 if (x < 0.0)
64 return (double)(int)(x - 0.5);
65 else
66 return (double)(int)(x + 0.5);
68 #endif
70 const char *optstring = "o:a:A:v:V:s:S:f:F:";
71 struct option options [] = {
72 {"output",required_argument,NULL,'o'},
73 {"audio-rate-target",required_argument,NULL,'A'},
74 {"video-rate-target",required_argument,NULL,'V'},
75 {"audio-quality",required_argument,NULL,'a'},
76 {"video-quality",required_argument,NULL,'v'},
77 {"aspect-numerator",optional_argument,NULL,'s'},
78 {"aspect-denominator",optional_argument,NULL,'S'},
79 {"framerate-numerator",optional_argument,NULL,'f'},
80 {"framerate-denominator",optional_argument,NULL,'F'},
81 {NULL,0,NULL,0}
84 /* You'll go to Hell for using globals. */
86 FILE *audio=NULL;
87 FILE *video=NULL;
89 int audio_ch=0;
90 int audio_hz=0;
92 float audio_q=.1;
93 int audio_r=-1;
95 int video_x=0;
96 int video_y=0;
97 int frame_x=0;
98 int frame_y=0;
99 int frame_x_offset=0;
100 int frame_y_offset=0;
101 int video_hzn=-1;
102 int video_hzd=-1;
103 int video_an=-1;
104 int video_ad=-1;
106 int video_r=-1;
107 int video_q=16;
109 static void usage(void){
110 fprintf(stderr,
111 "Usage: encoder_example [options] [audio_file] video_file\n\n"
112 "Options: \n\n"
113 " -o --output <filename.ogg> file name for encoded output;\n"
114 " If this option is not given, the\n"
115 " compressed data is sent to stdout.\n\n"
116 " -A --audio-rate-target <n> bitrate target for Vorbis audio;\n"
117 " use -a and not -A if at all possible,\n"
118 " as -a gives higher quality for a given\n"
119 " bitrate.\n\n"
120 " -V --video-rate-target <n> bitrate target for Theora video\n\n"
121 " -a --audio-quality <n> Vorbis quality selector from -1 to 10\n"
122 " (-1 yields smallest files but lowest\n"
123 " fidelity; 10 yields highest fidelity\n"
124 " but large files. '2' is a reasonable\n"
125 " default).\n\n"
126 " -v --video-quality <n> Theora quality selector fro 0 to 10\n"
127 " (0 yields smallest files but lowest\n"
128 " video quality. 10 yields highest\n"
129 " fidelity but large files).\n\n"
130 " -s --aspect-numerator <n> Aspect ratio numerator, default is 0\n"
131 " or extracted from YUV input file\n"
132 " -S --aspect-denominator <n> Aspect ratio denominator, default is 0\n"
133 " or extracted from YUV input file\n"
134 " -f --framerate-numerator <n> Frame rate numerator, can be extracted\n"
135 " from YUV input file. ex: 30000000\n"
136 " -F --framerate-denominator <n>Frame rate denominator, can be extracted\n"
137 " from YUV input file. ex: 1000000\n"
138 " The frame rate nominator divided by this\n"
139 " determinates the frame rate in units per tick\n"
140 "encoder_example accepts only uncompressed RIFF WAV format audio and\n"
141 "YUV4MPEG2 uncompressed video.\n\n");
142 exit(1);
145 static void id_file(char *f){
146 FILE *test;
147 unsigned char buffer[80];
148 int ret;
149 int tmp_video_hzn = -1,
150 tmp_video_hzd = -1,
151 tmp_video_an = -1,
152 tmp_video_ad = -1;
153 int extra_hdr_bytes;
155 /* open it, look for magic */
157 if(!strcmp(f,"-")){
158 /* stdin */
159 test=stdin;
160 }else{
161 test=fopen(f,"rb");
162 if(!test){
163 fprintf(stderr,"Unable to open file %s.\n",f);
164 exit(1);
168 ret=fread(buffer,1,4,test);
169 if(ret<4){
170 fprintf(stderr,"EOF determining file type of file %s.\n",f);
171 exit(1);
174 if(!memcmp(buffer,"RIFF",4)){
175 /* possible WAV file */
177 if(audio){
178 /* umm, we already have one */
179 fprintf(stderr,"Multiple RIFF WAVE files specified on command line.\n");
180 exit(1);
183 /* Parse the rest of the header */
185 ret=fread(buffer,1,4,test);
186 ret=fread(buffer,1,4,test);
187 if(ret<4)goto riff_err;
188 if(!memcmp(buffer,"WAVE",4)){
190 while(!feof(test)){
191 ret=fread(buffer,1,4,test);
192 if(ret<4)goto riff_err;
193 if(!memcmp("fmt",buffer,3)){
195 /* OK, this is our audio specs chunk. Slurp it up. */
197 ret=fread(buffer,1,20,test);
198 if(ret<20)goto riff_err;
200 extra_hdr_bytes = (buffer[0] + (buffer[1] << 8) +
201 (buffer[2] << 16) + (buffer[3] << 24)) - 16;
203 if(memcmp(buffer+4,"\001\000",2)){
204 fprintf(stderr,"The WAV file %s is in a compressed format; "
205 "can't read it.\n",f);
206 exit(1);
209 audio=test;
210 audio_ch=buffer[6]+(buffer[7]<<8);
211 audio_hz=buffer[8]+(buffer[9]<<8)+
212 (buffer[10]<<16)+(buffer[11]<<24);
214 if(buffer[18]+(buffer[19]<<8)!=16){
215 fprintf(stderr,"Can only read 16 bit WAV files for now.\n");
216 exit(1);
219 /* read past extra header bytes */
220 while(extra_hdr_bytes){
221 int read_size = (extra_hdr_bytes > sizeof(buffer)) ?
222 sizeof(buffer) : extra_hdr_bytes;
223 ret = fread(buffer, 1, read_size, test);
225 if (ret < read_size)
226 goto riff_err;
227 else
228 extra_hdr_bytes -= read_size;
231 /* Now, align things to the beginning of the data */
232 /* Look for 'dataxxxx' */
233 while(!feof(test)){
234 ret=fread(buffer,1,4,test);
235 if(ret<4)goto riff_err;
236 if(!memcmp("data",buffer,4)){
237 /* We're there. Ignore the declared size for now. */
238 ret=fread(buffer,1,4,test);
239 if(ret<4)goto riff_err;
241 fprintf(stderr,"File %s is 16 bit %d channel %d Hz RIFF WAV audio.\n",
242 f,audio_ch,audio_hz);
244 return;
251 fprintf(stderr,"Couldn't find WAVE data in RIFF file %s.\n",f);
252 exit(1);
255 if(!memcmp(buffer,"YUV4",4)){
256 /* possible YUV2MPEG2 format file */
257 /* read until newline, or 80 cols, whichever happens first */
258 /* NB the mjpegtools spec doesn't define a length limit */
259 int i,j;
260 for(i=0;i<79;i++){
261 ret=fread(buffer+i,1,1,test);
262 if(ret<1)goto yuv_err;
263 if(buffer[i]=='\n')break;
265 if(i==79){
266 fprintf(stderr,"Error parsing %s header; not a YUV2MPEG2 file?\n",f);
268 buffer[i]='\0';
270 if(!memcmp(buffer,"MPEG",4)){
271 char interlace = '?';
273 if(video){
274 /* umm, we already have one */
275 fprintf(stderr,"Multiple video files specified on command line.\n");
276 exit(1);
279 if(buffer[4]!='2'){
280 fprintf(stderr,"Incorrect YUV input file version; YUV4MPEG2 required.\n");
283 /* parse the frame header */
284 j = 5;
285 while (j < i) {
286 if ((buffer[j] != ' ') && (buffer[j-1] == ' '))
287 switch (buffer[j]) {
288 case 'W': frame_x = atoi((char*)&buffer[j+1]); break;
289 case 'H': frame_y = atoi((char*)&buffer[j+1]); break;
290 case 'C': /* chroma subsampling */ break;
291 case 'I': interlace = buffer[j+1]; break;
292 case 'F': /* frame rate ratio */
293 tmp_video_hzn = atoi((char*)&buffer[j+1]);
294 while ((buffer[j] != ':') && (j < i)) j++;
295 tmp_video_hzd = atoi((char*)&buffer[j+1]);
296 break;
297 case 'A': /* sample aspect ratio */
298 tmp_video_an = atoi((char*)&buffer[j+1]);
299 while ((buffer[j] != ':') && (j < i)) j++;
300 tmp_video_ad = atoi((char*)&buffer[j+1]);
301 break;
302 case 'X': /* metadata */ break;
303 default:
304 fprintf(stderr, "unrecognized stream header tag '%c'\n", buffer[j]);
305 break;
307 j++;
309 /* verify data from the stream header */
310 if (frame_x <= 0) {
311 fprintf(stderr,"Error parsing YUV4MPEG2 header:"
312 " missing width tag in file %s.\n", f);
313 exit(1);
315 if (frame_y <= 0) {
316 fprintf(stderr,"Error parsing YUV4MPEG2 header:"
317 " missing height tag in file %s.\n", f);
318 exit(1);
320 if (tmp_video_hzn < 0 || tmp_video_hzd < 0) {
321 /* default to 30 fps */
322 tmp_video_hzn = 30; tmp_video_hzd = 1;
323 fprintf(stderr,"Warning: no framerate defined in file %s.\n", f);
325 if (tmp_video_an < 0 || tmp_video_ad < 0) {
326 /* default to unknown */
327 tmp_video_an = 0; tmp_video_ad = 0;
330 /* update fps and aspect ratio globals if not specified in the command line */
331 if (video_hzn==-1) video_hzn = tmp_video_hzn;
332 if (video_hzd==-1) video_hzd = tmp_video_hzd;
333 if (video_an==-1) video_an = tmp_video_an;
334 if (video_ad==-1) video_ad = tmp_video_ad;
336 if(interlace=='?'){
337 fprintf(stderr,"Warning: input video isn't marked for interlacing;"
338 " treating this\nas progressive scan video."
339 " Deinterlace first if you get poor results.\n");
340 }else if(interlace!='p'){
341 fprintf(stderr,"Input video is interlaced; Theora handles only progressive scan\n");
342 exit(1);
345 video=test;
347 fprintf(stderr,"File %s is %dx%d %.02f fps YUV12 video.\n",
348 f,frame_x,frame_y,(double)video_hzn/video_hzd);
350 return;
353 fprintf(stderr,"Input file %s is neither a WAV nor YUV4MPEG2 file.\n",f);
354 exit(1);
356 riff_err:
357 fprintf(stderr,"EOF parsing RIFF file %s.\n",f);
358 exit(1);
359 yuv_err:
360 fprintf(stderr,"EOF parsing YUV4MPEG2 file %s.\n",f);
361 exit(1);
365 int spinner=0;
366 char *spinascii="|/-\\";
367 void spinnit(void){
368 spinner++;
369 if(spinner==4)spinner=0;
370 fprintf(stderr,"\r%c",spinascii[spinner]);
373 int fetch_and_process_audio(FILE *audio,ogg_page *audiopage,
374 ogg_stream_state *vo,
375 vorbis_dsp_state *vd,
376 vorbis_block *vb,
377 int audioflag){
378 ogg_packet op;
379 int i,j;
381 while(audio && !audioflag){
382 /* process any audio already buffered */
383 spinnit();
384 if(ogg_stream_pageout(vo,audiopage)>0) return 1;
385 if(ogg_stream_eos(vo))return 0;
388 /* read and process more audio */
389 signed char readbuffer[4096];
390 int toread=4096/2/audio_ch;
391 int bytesread=fread(readbuffer,1,toread*2*audio_ch,audio);
392 int sampread=bytesread/2/audio_ch;
393 float **vorbis_buffer;
394 int count=0;
396 if(bytesread<=0){
397 /* end of file. this can be done implicitly, but it's
398 easier to see here in non-clever fashion. Tell the
399 library we're at end of stream so that it can handle the
400 last frame and mark end of stream in the output properly */
401 vorbis_analysis_wrote(vd,0);
402 }else{
403 vorbis_buffer=vorbis_analysis_buffer(vd,sampread);
404 /* uninterleave samples */
405 for(i=0;i<sampread;i++){
406 for(j=0;j<audio_ch;j++){
407 vorbis_buffer[j][i]=((readbuffer[count+1]<<8)|
408 (0x00ff&(int)readbuffer[count]))/32768.f;
409 count+=2;
413 vorbis_analysis_wrote(vd,sampread);
417 while(vorbis_analysis_blockout(vd,vb)==1){
419 /* analysis, assume we want to use bitrate management */
420 vorbis_analysis(vb,NULL);
421 vorbis_bitrate_addblock(vb);
423 /* weld packets into the bitstream */
424 while(vorbis_bitrate_flushpacket(vd,&op))
425 ogg_stream_packetin(vo,&op);
431 return audioflag;
434 int fetch_and_process_video(FILE *video,ogg_page *videopage,
435 ogg_stream_state *to,
436 theora_state *td,
437 int videoflag){
438 /* You'll go to Hell for using static variables */
439 static int state=-1;
440 static unsigned char *yuvframe[2];
441 unsigned char *line;
442 yuv_buffer yuv;
443 ogg_packet op;
444 int i, e;
446 if(state==-1){
447 /* initialize the double frame buffer */
448 yuvframe[0]=malloc(video_x*video_y*3/2);
449 yuvframe[1]=malloc(video_x*video_y*3/2);
451 /* clear initial frame as it may be larger than actual video data */
452 /* fill Y plane with 0x10 and UV planes with 0X80, for black data */
453 memset(yuvframe[0],0x10,video_x*video_y);
454 memset(yuvframe[0]+video_x*video_y,0x80,video_x*video_y/2);
455 memset(yuvframe[1],0x10,video_x*video_y);
456 memset(yuvframe[1]+video_x*video_y,0x80,video_x*video_y/2);
458 state=0;
461 /* is there a video page flushed? If not, work until there is. */
462 while(!videoflag){
463 spinnit();
465 if(ogg_stream_pageout(to,videopage)>0) return 1;
466 if(ogg_stream_eos(to)) return 0;
469 /* read and process more video */
470 /* video strategy reads one frame ahead so we know when we're
471 at end of stream and can mark last video frame as such
472 (vorbis audio has to flush one frame past last video frame
473 due to overlap and thus doesn't need this extra work */
475 /* have two frame buffers full (if possible) before
476 proceeding. after first pass and until eos, one will
477 always be full when we get here */
479 for(i=state;i<2;i++){
480 char c,frame[6];
481 int ret=fread(frame,1,6,video);
483 /* match and skip the frame header */
484 if(ret<6)break;
485 if(memcmp(frame,"FRAME",5)){
486 fprintf(stderr,"Loss of framing in YUV input data\n");
487 exit(1);
489 if(frame[5]!='\n'){
490 int j;
491 for(j=0;j<79;j++)
492 if(fread(&c,1,1,video)&&c=='\n')break;
493 if(j==79){
494 fprintf(stderr,"Error parsing YUV frame header\n");
495 exit(1);
499 /* read the Y plane into our frame buffer with centering */
500 line=yuvframe[i]+video_x*frame_y_offset+frame_x_offset;
501 for(e=0;e<frame_y;e++){
502 ret=fread(line,1,frame_x,video);
503 if(ret!=frame_x) break;
504 line+=video_x;
506 /* now get U plane*/
507 line=yuvframe[i]+(video_x*video_y)
508 +(video_x/2)*(frame_y_offset/2)+frame_x_offset/2;
509 for(e=0;e<frame_y/2;e++){
510 ret=fread(line,1,frame_x/2,video);
511 if(ret!=frame_x/2) break;
512 line+=video_x/2;
514 /* and the V plane*/
515 line=yuvframe[i]+(video_x*video_y*5/4)
516 +(video_x/2)*(frame_y_offset/2)+frame_x_offset/2;
517 for(e=0;e<frame_y/2;e++){
518 ret=fread(line,1,frame_x/2,video);
519 if(ret!=frame_x/2) break;
520 line+=video_x/2;
522 state++;
525 if(state<1){
526 /* can't get here unless YUV4MPEG stream has no video */
527 fprintf(stderr,"Video input contains no frames.\n");
528 exit(1);
531 /* Theora is a one-frame-in,one-frame-out system; submit a frame
532 for compression and pull out the packet */
535 yuv.y_width=video_x;
536 yuv.y_height=video_y;
537 yuv.y_stride=video_x;
539 yuv.uv_width=video_x/2;
540 yuv.uv_height=video_y/2;
541 yuv.uv_stride=video_x/2;
543 yuv.y= yuvframe[0];
544 yuv.u= yuvframe[0]+ video_x*video_y;
545 yuv.v= yuvframe[0]+ video_x*video_y*5/4 ;
548 theora_encode_YUVin(td,&yuv);
550 /* if there's only one frame, it's the last in the stream */
551 if(state<2)
552 theora_encode_packetout(td,1,&op);
553 else
554 theora_encode_packetout(td,0,&op);
556 ogg_stream_packetin(to,&op);
559 unsigned char *temp=yuvframe[0];
560 yuvframe[0]=yuvframe[1];
561 yuvframe[1]=temp;
562 state--;
567 return videoflag;
570 int main(int argc,char *argv[]){
571 int c,long_option_index,ret;
573 ogg_stream_state to; /* take physical pages, weld into a logical
574 stream of packets */
575 ogg_stream_state vo; /* take physical pages, weld into a logical
576 stream of packets */
577 ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
578 ogg_packet op; /* one raw packet of data for decode */
580 theora_state td;
581 theora_info ti;
582 theora_comment tc;
584 vorbis_info vi; /* struct that stores all the static vorbis bitstream
585 settings */
586 vorbis_comment vc; /* struct that stores all the user comments */
588 vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
589 vorbis_block vb; /* local working space for packet->PCM decode */
591 int audioflag=0;
592 int videoflag=0;
593 int akbps=0;
594 int vkbps=0;
596 ogg_int64_t audio_bytesout=0;
597 ogg_int64_t video_bytesout=0;
598 double timebase;
601 FILE* outfile = stdout;
603 #ifdef _WIN32
604 # ifdef THEORA_PERF_DATA
605 LARGE_INTEGER start_time;
606 LARGE_INTEGER final_time;
608 LONGLONG elapsed_ticks;
609 LARGE_INTEGER ticks_per_second;
611 LONGLONG elapsed_secs;
612 LONGLONG elapsed_sec_mod;
613 double elapsed_secs_dbl ;
614 # endif
615 /* We need to set stdin/stdout to binary mode. Damn windows. */
616 /* if we were reading/writing a file, it would also need to in
617 binary mode, eg, fopen("file.wav","wb"); */
618 /* Beware the evil ifdef. We avoid these where we can, but this one we
619 cannot. Don't add any more, you'll probably go to hell if you do. */
620 _setmode( _fileno( stdin ), _O_BINARY );
621 _setmode( _fileno( stdout ), _O_BINARY );
624 #endif
626 while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
627 switch(c){
628 case 'o':
629 outfile=fopen(optarg,"wb");
630 if(outfile==NULL){
631 fprintf(stderr,"Unable to open output file '%s'\n", optarg);
632 exit(1);
634 break;;
636 case 'a':
637 audio_q=atof(optarg)*.099;
638 if(audio_q<-.1 || audio_q>1){
639 fprintf(stderr,"Illegal audio quality (choose -1 through 10)\n");
640 exit(1);
642 audio_r=-1;
643 break;
645 case 'v':
646 video_q=rint(atof(optarg)*6.3);
647 if(video_q<0 || video_q>63){
648 fprintf(stderr,"Illegal video quality (choose 0 through 10)\n");
649 exit(1);
651 video_r=0;
652 break;
654 case 'A':
655 audio_r=atof(optarg)*1000;
656 if(audio_q<0){
657 fprintf(stderr,"Illegal audio quality (choose > 0 please)\n");
658 exit(1);
660 audio_q=-99;
661 break;
663 case 'V':
664 video_r=rint(atof(optarg)*1000);
665 if(video_r<45000 || video_r>2000000){
666 fprintf(stderr,"Illegal video bitrate (choose 45kbps through 2000kbps)\n");
667 exit(1);
669 video_q=0;
670 break;
672 case 's':
673 video_an=rint(atof(optarg));
674 break;
676 case 'S':
677 video_ad=rint(atof(optarg));
678 break;
680 case 'f':
681 video_hzn=rint(atof(optarg));
682 break;
684 case 'F':
685 video_hzd=rint(atof(optarg));
686 break;
688 default:
689 usage();
693 while(optind<argc){
694 /* assume that anything following the options must be a filename */
695 id_file(argv[optind]);
696 optind++;
701 #ifdef THEORA_PERF_DATA
702 # ifdef WIN32
703 QueryPerformanceCounter(&start_time);
704 # endif
705 #endif
708 /* yayness. Set up Ogg output stream */
709 srand(time(NULL));
711 /* need two inequal serial numbers */
712 int serial1, serial2;
713 serial1 = rand();
714 serial2 = rand();
715 if (serial1 == serial2) serial2++;
716 ogg_stream_init(&to,serial1);
717 ogg_stream_init(&vo,serial2);
720 /* Set up Theora encoder */
721 if(!video){
722 fprintf(stderr,"No video files submitted for compression?\n");
723 exit(1);
725 /* Theora has a divisible-by-sixteen restriction for the encoded video size */
726 /* scale the frame size up to the nearest /16 and calculate offsets */
727 video_x=((frame_x + 15) >>4)<<4;
728 video_y=((frame_y + 15) >>4)<<4;
729 /* We force the offset to be even.
730 This ensures that the chroma samples align properly with the luma
731 samples. */
732 frame_x_offset=((video_x-frame_x)/2)&~1;
733 frame_y_offset=((video_y-frame_y)/2)&~1;
735 theora_info_init(&ti);
736 ti.width=video_x;
737 ti.height=video_y;
738 ti.frame_width=frame_x;
739 ti.frame_height=frame_y;
740 ti.offset_x=frame_x_offset;
741 ti.offset_y=frame_y_offset;
742 ti.fps_numerator=video_hzn;
743 ti.fps_denominator=video_hzd;
744 ti.aspect_numerator=video_an;
745 ti.aspect_denominator=video_ad;
746 ti.colorspace=OC_CS_UNSPECIFIED;
747 ti.pixelformat=OC_PF_420;
748 ti.target_bitrate=video_r;
749 ti.quality=video_q;
751 ti.dropframes_p=0;
752 ti.quick_p=1;
753 ti.keyframe_auto_p=1;
754 ti.keyframe_frequency=64;
755 ti.keyframe_frequency_force=64;
756 ti.keyframe_data_target_bitrate=video_r*1.5;
757 ti.keyframe_auto_threshold=80;
758 ti.keyframe_mindistance=8;
759 ti.noise_sensitivity=1;
761 theora_encode_init(&td,&ti);
762 theora_info_clear(&ti);
764 /* initialize Vorbis too, assuming we have audio to compress. */
765 if(audio){
766 vorbis_info_init(&vi);
767 if(audio_q>-99)
768 ret = vorbis_encode_init_vbr(&vi,audio_ch,audio_hz,audio_q);
769 else
770 ret = vorbis_encode_init(&vi,audio_ch,audio_hz,-1,audio_r,-1);
771 if(ret){
772 fprintf(stderr,"The Vorbis encoder could not set up a mode according to\n"
773 "the requested quality or bitrate.\n\n");
774 exit(1);
777 vorbis_comment_init(&vc);
778 vorbis_analysis_init(&vd,&vi);
779 vorbis_block_init(&vd,&vb);
782 /* write the bitstream header packets with proper page interleave */
784 /* first packet will get its own page automatically */
785 theora_encode_header(&td,&op);
786 ogg_stream_packetin(&to,&op);
787 if(ogg_stream_pageout(&to,&og)!=1){
788 fprintf(stderr,"Internal Ogg library error.\n");
789 exit(1);
791 fwrite(og.header,1,og.header_len,outfile);
792 fwrite(og.body,1,og.body_len,outfile);
794 /* create the remaining theora headers */
795 theora_comment_init(&tc);
796 theora_encode_comment(&tc,&op);
797 ogg_stream_packetin(&to,&op);
798 /*theora_encode_comment() doesn't take a theora_state parameter, so it has to
799 allocate its own buffer to pass back the packet data.
800 If we don't free it here, we'll leak.
801 libogg2 makes this much cleaner: the stream owns the buffer after you call
802 packetin in libogg2, but this is not true in libogg1.*/
803 free(op.packet);
804 theora_encode_tables(&td,&op);
805 ogg_stream_packetin(&to,&op);
807 if(audio){
808 ogg_packet header;
809 ogg_packet header_comm;
810 ogg_packet header_code;
812 vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
813 ogg_stream_packetin(&vo,&header); /* automatically placed in its own
814 page */
815 if(ogg_stream_pageout(&vo,&og)!=1){
816 fprintf(stderr,"Internal Ogg library error.\n");
817 exit(1);
819 fwrite(og.header,1,og.header_len,outfile);
820 fwrite(og.body,1,og.body_len,outfile);
822 /* remaining vorbis header packets */
823 ogg_stream_packetin(&vo,&header_comm);
824 ogg_stream_packetin(&vo,&header_code);
827 /* Flush the rest of our headers. This ensures
828 the actual data in each stream will start
829 on a new page, as per spec. */
830 while(1){
831 int result = ogg_stream_flush(&to,&og);
832 if(result<0){
833 /* can't get here */
834 fprintf(stderr,"Internal Ogg library error.\n");
835 exit(1);
837 if(result==0)break;
838 fwrite(og.header,1,og.header_len,outfile);
839 fwrite(og.body,1,og.body_len,outfile);
841 if(audio){
842 while(1){
843 int result=ogg_stream_flush(&vo,&og);
844 if(result<0){
845 /* can't get here */
846 fprintf(stderr,"Internal Ogg library error.\n");
847 exit(1);
849 if(result==0)break;
850 fwrite(og.header,1,og.header_len,outfile);
851 fwrite(og.body,1,og.body_len,outfile);
855 /* setup complete. Raw processing loop */
856 fprintf(stderr,"Compressing....\n");
857 while(1){
858 ogg_page audiopage;
859 ogg_page videopage;
861 /* is there an audio page flushed? If not, fetch one if possible */
862 audioflag=fetch_and_process_audio(audio,&audiopage,&vo,&vd,&vb,audioflag);
864 /* is there a video page flushed? If not, fetch one if possible */
865 videoflag=fetch_and_process_video(video,&videopage,&to,&td,videoflag);
867 /* no pages of either? Must be end of stream. */
868 if(!audioflag && !videoflag)break;
870 /* which is earlier; the end of the audio page or the end of the
871 video page? Flush the earlier to stream */
873 int audio_or_video=-1;
874 double audiotime=
875 audioflag?vorbis_granule_time(&vd,ogg_page_granulepos(&audiopage)):-1;
876 double videotime=
877 videoflag?theora_granule_time(&td,ogg_page_granulepos(&videopage)):-1;
879 if(!audioflag){
880 audio_or_video=1;
881 } else if(!videoflag) {
882 audio_or_video=0;
883 } else {
884 if(audiotime<videotime)
885 audio_or_video=0;
886 else
887 audio_or_video=1;
890 if(audio_or_video==1){
891 /* flush a video page */
892 video_bytesout+=fwrite(videopage.header,1,videopage.header_len,outfile);
893 video_bytesout+=fwrite(videopage.body,1,videopage.body_len,outfile);
894 videoflag=0;
895 timebase=videotime;
897 }else{
898 /* flush an audio page */
899 audio_bytesout+=fwrite(audiopage.header,1,audiopage.header_len,outfile);
900 audio_bytesout+=fwrite(audiopage.body,1,audiopage.body_len,outfile);
901 audioflag=0;
902 timebase=audiotime;
905 int hundredths=timebase*100-(long)timebase*100;
906 int seconds=(long)timebase%60;
907 int minutes=((long)timebase/60)%60;
908 int hours=(long)timebase/3600;
910 if(audio_or_video)
911 vkbps=rint(video_bytesout*8./timebase*.001);
912 else
913 akbps=rint(audio_bytesout*8./timebase*.001);
915 fprintf(stderr,
916 "\r %d:%02d:%02d.%02d audio: %dkbps video: %dkbps ",
917 hours,minutes,seconds,hundredths,akbps,vkbps);
923 /* clear out state */
925 if(audio){
926 ogg_stream_clear(&vo);
927 vorbis_block_clear(&vb);
928 vorbis_dsp_clear(&vd);
929 vorbis_comment_clear(&vc);
930 vorbis_info_clear(&vi);
932 if(video){
933 ogg_stream_clear(&to);
934 theora_clear(&td);
937 if(outfile && outfile!=stdout)fclose(outfile);
939 fprintf(stderr,"\r \ndone.\n\n");
941 #ifdef THEORA_PERF_DATA
942 # ifdef WIN32
943 QueryPerformanceCounter(&final_time);
944 elapsed_ticks = final_time.QuadPart - start_time.QuadPart;
945 ticks_per_second;
946 QueryPerformanceFrequency(&ticks_per_second);
947 elapsed_secs = elapsed_ticks / ticks_per_second.QuadPart;
948 elapsed_sec_mod = elapsed_ticks % ticks_per_second.QuadPart;
949 elapsed_secs_dbl = elapsed_secs;
950 elapsed_secs_dbl += ((double)elapsed_sec_mod / (double)ticks_per_second.QuadPart);
951 printf("Encode time = %lld ticks\n", elapsed_ticks);
952 printf("~%lld and %lld / %lld seconds\n", elapsed_secs, elapsed_sec_mod, ticks_per_second.QuadPart);
953 printf("~%Lf seconds\n", elapsed_secs_dbl);
954 # endif
956 #endif
958 return(0);