1 /********************************************************************
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. *
8 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009,2009 *
9 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
11 ********************************************************************
13 function: example encoder application; makes an Ogg Theora
14 file from a sequence of png images
15 last mod: $Id: png2theora.c 16503 2009-08-22 18:14:02Z giles $
16 based on code from Vegard Nossum
18 ********************************************************************/
20 #define _FILE_OFFSET_BITS 64
31 #include <sys/types.h>
40 #include "theora/theoraenc.h"
42 #define PROGRAM_NAME "png2theora"
43 #define PROGRAM_VERSION "1.1"
45 static const char *option_output = NULL;
46 static int video_fps_numerator = 24;
47 static int video_fps_denominator = 1;
48 static int video_aspect_numerator = 0;
49 static int video_aspect_denominator = 0;
50 static int video_rate = -1;
51 static int video_quality = -1;
52 ogg_uint32_t keyframe_frequency=0;
55 static int chroma_format = TH_PF_420;
57 static FILE *twopass_file = NULL;
61 static FILE *ogg_fp = NULL;
62 static ogg_stream_state ogg_os;
66 static th_enc_ctx *td;
69 static char *input_filter;
71 const char *optstring = "o:hv:\4:\2:V:s:S:f:F:ck:d:\1\2\3\4\5\6";
72 struct option options [] = {
73 {"output",required_argument,NULL,'o'},
74 {"help",no_argument,NULL,'h'},
75 {"chroma-444",no_argument,NULL,'\5'},
76 {"chroma-422",no_argument,NULL,'\6'},
77 {"video-rate-target",required_argument,NULL,'V'},
78 {"video-quality",required_argument,NULL,'v'},
79 {"aspect-numerator",required_argument,NULL,'s'},
80 {"aspect-denominator",required_argument,NULL,'S'},
81 {"framerate-numerator",required_argument,NULL,'f'},
82 {"framerate-denominator",required_argument,NULL,'F'},
83 {"vp3-compatible",no_argument,NULL,'c'},
84 {"soft-target",no_argument,NULL,'\1'},
85 {"keyframe-freq",required_argument,NULL,'k'},
86 {"buf-delay",required_argument,NULL,'d'},
87 {"two-pass",no_argument,NULL,'\2'},
88 {"first-pass",required_argument,NULL,'\3'},
89 {"second-pass",required_argument,NULL,'\4'},
93 static void usage(void){
96 "Usage: %s [options] <input>\n\n"
97 "The input argument uses C printf format to represent a list of files,\n"
98 " i.e. file-%%06d.png to look for files file000001.png to file9999999.png \n\n"
100 " -o --output <filename.ogv> file name for encoded output (required);\n"
101 " -v --video-quality <n> Theora quality selector fro 0 to 10\n"
102 " (0 yields smallest files but lowest\n"
103 " video quality. 10 yields highest\n"
104 " fidelity but large files)\n\n"
105 " -V --video-rate-target <n> bitrate target for Theora video\n\n"
106 " --soft-target Use a large reservoir and treat the rate\n"
107 " as a soft target; rate control is less\n"
108 " strict but resulting quality is usually\n"
109 " higher/smoother overall. Soft target also\n"
110 " allows an optional -v setting to specify\n"
111 " a minimum allowed quality.\n\n"
112 " --two-pass Compress input using two-pass rate control\n"
113 " This option performs both passes automatically.\n\n"
114 " --first-pass <filename> Perform first-pass of a two-pass rate\n"
115 " controlled encoding, saving pass data to\n"
116 " <filename> for a later second pass\n\n"
117 " --second-pass <filename> Perform second-pass of a two-pass rate\n"
118 " controlled encoding, reading first-pass\n"
119 " data from <filename>. The first pass\n"
120 " data must come from a first encoding pass\n"
121 " using identical input video to work\n"
123 " -k --keyframe-freq <n> Keyframe frequency\n"
124 " -d --buf-delay <n> Buffer delay (in frames). Longer delays\n"
125 " allow smoother rate adaptation and provide\n"
126 " better overall quality, but require more\n"
127 " client side buffering and add latency. The\n"
128 " default value is the keyframe interval for\n"
129 " one-pass encoding (or somewhat larger if\n"
130 " --soft-target is used) and infinite for\n"
131 " two-pass encoding.\n"
132 " --chroma-444 Use 4:4:4 chroma subsampling\n"
133 " --chroma-422 Use 4:2:2 chroma subsampling\n"
134 " (4:2:0 is default)\n\n"
135 " -s --aspect-numerator <n> Aspect ratio numerator, default is 0\n"
136 " -S --aspect-denominator <n> Aspect ratio denominator, default is 0\n"
137 " -f --framerate-numerator <n> Frame rate numerator\n"
138 " -F --framerate-denominator <n> Frame rate denominator\n"
139 " The frame rate nominator divided by this\n"
140 " determines the frame rate in units per tick\n"
141 ,PROGRAM_NAME, PROGRAM_VERSION, PROGRAM_NAME
148 alphasort (const void *a, const void *b)
150 return strcoll ((*(const struct dirent **) a)->d_name,
151 (*(const struct dirent **) b)->d_name);
155 scandir (const char *dir, struct dirent ***namelist,
156 int (*select)(const struct dirent *), int (*compar)(const void *, const void *))
159 struct dirent *entry;
163 if ((d=opendir(dir)) == NULL)
167 while ((entry=readdir(d)) != NULL)
169 if (select == NULL || (select != NULL && (*select)(entry)))
171 *namelist=(struct dirent **)realloc((void *)(*namelist),
172 (size_t)((i+1)*sizeof(struct dirent *)));
173 if (*namelist == NULL) return(-1);
174 entrysize=sizeof(struct dirent)-sizeof(entry->d_name)+strlen(entry->d_name)+1;
175 (*namelist)[i]=(struct dirent *)malloc(entrysize);
176 if ((*namelist)[i] == NULL) return(-1);
177 memcpy((*namelist)[i], entry, entrysize);
181 if (closedir(d)) return(-1);
182 if (i == 0) return(-1);
184 qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);
191 theora_write_frame(unsigned long w, unsigned long h, unsigned char *yuv, int last)
193 th_ycbcr_buffer ycbcr;
200 unsigned char *yuv_y;
201 unsigned char *yuv_u;
202 unsigned char *yuv_v;
207 /* Must hold: yuv_w >= w */
208 yuv_w = (w + 15) & ~15;
210 /* Must hold: yuv_h >= h */
211 yuv_h = (h + 15) & ~15;
213 ycbcr[0].width = yuv_w;
214 ycbcr[0].height = yuv_h;
215 ycbcr[0].stride = yuv_w;
216 ycbcr[1].width = (chroma_format == TH_PF_444) ? yuv_w : (yuv_w >> 1);
217 ycbcr[1].stride = ycbcr[1].width;
218 ycbcr[1].height = (chroma_format == TH_PF_420) ? (yuv_h >> 1) : yuv_h;
219 ycbcr[2].width = ycbcr[1].width;
220 ycbcr[2].stride = ycbcr[1].stride;
221 ycbcr[2].height = ycbcr[1].height;
223 ycbcr[0].data = yuv_y = malloc(ycbcr[0].stride * ycbcr[0].height);
224 ycbcr[1].data = yuv_u = malloc(ycbcr[1].stride * ycbcr[1].height);
225 ycbcr[2].data = yuv_v = malloc(ycbcr[2].stride * ycbcr[2].height);
227 for(y = 0; y < h; y++) {
228 for(x = 0; x < w; x++) {
229 yuv_y[x + y * yuv_w] = yuv[3 * (x + y * w) + 0];
233 if (chroma_format == TH_PF_420) {
234 for(y = 0; y < h; y += 2) {
235 for(x = 0; x < w; x += 2) {
236 yuv_u[(x >> 1) + (y >> 1) * (yuv_w >> 1)] =
237 yuv[3 * (x + y * w) + 1];
238 yuv_v[(x >> 1) + (y >> 1) * (yuv_w >> 1)] =
239 yuv[3 * (x + y * w) + 2];
242 } else if (chroma_format == TH_PF_444) {
243 for(y = 0; y < h; y++) {
244 for(x = 0; x < w; x++) {
245 yuv_u[x + y * ycbcr[1].stride] = yuv[3 * (x + y * w) + 1];
246 yuv_v[x + y * ycbcr[2].stride] = yuv[3 * (x + y * w) + 2];
249 } else { /* TH_PF_422 */
250 for(y = 0; y < h; y += 1) {
251 for(x = 0; x < w; x += 2) {
252 yuv_u[(x >> 1) + y * ycbcr[1].stride] =
253 yuv[3 * (x + y * w) + 1];
254 yuv_v[(x >> 1) + y * ycbcr[2].stride] =
255 yuv[3 * (x + y * w) + 2];
260 /* Theora is a one-frame-in,one-frame-out system; submit a frame
261 for compression and pull out the packet */
262 /* in two-pass mode's second pass, we need to submit first-pass data */
266 static unsigned char buffer[80];
269 /*Ask the encoder how many bytes it would like.*/
270 bytes=th_encode_ctl(td,TH_ENCCTL_2PASS_IN,NULL,0);
272 fprintf(stderr,"Error submitting pass data in second pass.\n");
275 /*If it's got enough, stop.*/
277 /*Read in some more bytes, if necessary.*/
278 if(bytes>80-buf_pos)bytes=80-buf_pos;
279 if(bytes>0&&fread(buffer+buf_pos,1,bytes,twopass_file)<bytes){
280 fprintf(stderr,"Could not read frame data from two-pass data file!\n");
283 /*And pass them off.*/
284 ret=th_encode_ctl(td,TH_ENCCTL_2PASS_IN,buffer,bytes);
286 fprintf(stderr,"Error submitting pass data in second pass.\n");
289 /*If the encoder consumed the whole buffer, reset it.*/
290 if(ret>=bytes)buf_pos=0;
291 /*Otherwise remember how much it used.*/
296 if(th_encode_ycbcr_in(td, ycbcr)) {
297 fprintf(stderr, "%s: error: could not encode frame\n",
302 /* in two-pass mode's first pass we need to extract and save the pass data */
304 unsigned char *buffer;
305 int bytes = th_encode_ctl(td, TH_ENCCTL_2PASS_OUT, &buffer, sizeof(buffer));
307 fprintf(stderr,"Could not read two-pass data from encoder.\n");
310 if(fwrite(buffer,1,bytes,twopass_file)<bytes){
311 fprintf(stderr,"Unable to write to two-pass data file.\n");
314 fflush(twopass_file);
317 if(!th_encode_packetout(td, last, &op)) {
318 fprintf(stderr, "%s: error: could not read packets\n",
324 ogg_stream_packetin(&ogg_os, &op);
325 while(ogg_stream_pageout(&ogg_os, &og)) {
326 fwrite(og.header, og.header_len, 1, ogg_fp);
327 fwrite(og.body, og.body_len, 1, ogg_fp);
351 rgb_to_yuv(png_bytep *png,
353 unsigned int w, unsigned int h)
358 for(y = 0; y < h; y++) {
359 for(x = 0; x < w; x++) {
364 r = png[y][3 * x + 0];
365 g = png[y][3 * x + 1];
366 b = png[y][3 * x + 2];
369 yuv[3 * (x + w * y) + 0] = clamp(
373 yuv[3 * (x + w * y) + 1] = clamp((0.436 * 255
376 + 0.436 * b) / 0.872);
377 yuv[3 * (x + w * y) + 2] = clamp((0.615 * 255
380 - 0.10001 * b) / 1.230);
386 png_read(const char *pathname, unsigned int *w, unsigned int *h, unsigned char **yuv)
389 unsigned char header[8];
394 png_bytep *row_pointers;
401 int compression_type;
405 fp = fopen(pathname, "rb");
407 fprintf(stderr, "%s: error: %s\n",
408 pathname, strerror(errno));
412 fread(header, 1, 8, fp);
413 if(png_sig_cmp(header, 0, 8)) {
414 fprintf(stderr, "%s: error: %s\n",
415 pathname, "not a PNG");
420 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
423 fprintf(stderr, "%s: error: %s\n",
424 pathname, "couldn't create png read structure");
429 info_ptr = png_create_info_struct(png_ptr);
431 fprintf(stderr, "%s: error: %s\n",
432 pathname, "couldn't create png info structure");
433 png_destroy_read_struct(&png_ptr, NULL, NULL);
438 end_ptr = png_create_info_struct(png_ptr);
440 fprintf(stderr, "%s: error: %s\n",
441 pathname, "couldn't create png info structure");
442 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
447 png_init_io(png_ptr, fp);
448 png_set_sig_bytes(png_ptr, 8);
449 png_read_info(png_ptr, info_ptr);
450 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
451 &interlace_type, &compression_type, &filter_method);
452 png_set_expand(png_ptr);
453 if(bit_depth<8)png_set_packing(png_ptr);
454 if(bit_depth==16)png_set_strip_16(png_ptr);
455 if(!(color_type&PNG_COLOR_MASK_COLOR))png_set_gray_to_rgb(png_ptr);
456 if(png_get_bKGD(png_ptr, info_ptr, &bkgd)){
457 png_set_background(png_ptr, bkgd, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
459 /*Note that color_type 2 and 3 can also have alpha, despite not setting the
460 PNG_COLOR_MASK_ALPHA bit.
461 We always strip it to prevent libpng from overrunning our buffer.*/
462 png_set_strip_alpha(png_ptr);
464 row_data = (png_bytep)png_malloc(png_ptr,
465 3*height*width*png_sizeof(*row_data));
466 row_pointers = (png_bytep *)png_malloc(png_ptr,
467 height*png_sizeof(*row_pointers));
468 for(y = 0; y < height; y++) {
469 row_pointers[y] = row_data + y*(3*width);
471 png_read_image(png_ptr, row_pointers);
472 png_read_end(png_ptr, end_ptr);
476 *yuv = malloc(*w * *h * 3);
477 rgb_to_yuv(row_pointers, *yuv, *w, *h);
479 png_free(png_ptr, row_pointers);
480 png_free(png_ptr, row_data);
481 png_destroy_read_struct(&png_ptr, &info_ptr, &end_ptr);
487 static int include_files (const struct dirent *de)
491 sscanf(de->d_name, input_filter, &number);
492 sprintf(name, input_filter, number);
493 return !strcmp(name, de->d_name);
496 static int ilog(unsigned _v){
498 for(ret=0;_v;ret++)_v>>=1;
503 main(int argc, char *argv[])
505 int c,long_option_index;
508 char *input_directory;
511 struct dirent **png_files;
517 c=getopt_long(argc,argv,optstring,options,&long_option_index);
526 option_output = optarg;
529 video_quality=rint(atof(optarg)*6.3);
530 if(video_quality<0 || video_quality>63){
531 fprintf(stderr,"Illegal video quality (choose 0 through 10)\n");
537 video_rate=rint(atof(optarg)*1000);
539 fprintf(stderr,"Illegal video bitrate (choose > 0 please)\n");
551 keyframe_frequency=rint(atof(optarg));
552 if(keyframe_frequency<1 || keyframe_frequency>2147483647){
553 fprintf(stderr,"Illegal keyframe frequency\n");
559 buf_delay=atoi(optarg);
561 fprintf(stderr,"Illegal buffer delay\n");
566 video_aspect_numerator=rint(atof(optarg));
569 video_aspect_denominator=rint(atof(optarg));
572 video_fps_numerator=rint(atof(optarg));
575 video_fps_denominator=rint(atof(optarg));
578 chroma_format=TH_PF_444;
581 chroma_format=TH_PF_422;
584 twopass=3; /* perform both passes */
585 twopass_file=tmpfile();
587 fprintf(stderr,"Unable to open temporary file for twopass data\n");
592 twopass=1; /* perform first pass */
593 twopass_file=fopen(optarg,"wb");
595 fprintf(stderr,"Unable to open \'%s\' for twopass data\n",optarg);
600 twopass=2; /* perform second pass */
601 twopass_file=fopen(optarg,"rb");
603 fprintf(stderr,"Unable to open twopass data file \'%s\'",optarg);
619 fprintf(stderr,"Soft rate target (--soft-target) requested without a bitrate (-V).\n");
622 if(video_quality==-1)
627 if(video_quality==-1)
631 if(keyframe_frequency<=0){
632 /*Use a default keyframe frequency of 64 for 1-pass (streaming) mode, and
633 256 for two-pass mode.*/
634 keyframe_frequency=twopass?256:64;
637 input_mask = argv[optind];
639 fprintf(stderr, "no input files specified; run with -h for help.\n");
642 /* dirname and basename must operate on scratch strings */
643 scratch = strdup(input_mask);
644 input_directory = strdup(dirname(scratch));
646 scratch = strdup(input_mask);
647 input_filter = strdup(basename(scratch));
651 fprintf(stderr, "scanning %s with filter '%s'\n",
652 input_directory, input_filter);
654 n = scandir (input_directory, &png_files, include_files, alphasort);
657 fprintf(stderr, "no input files found; run with -h for help.\n");
661 ogg_fp = fopen(option_output, "wb");
663 fprintf(stderr, "%s: error: %s\n",
664 option_output, "couldn't open output file");
669 if(ogg_stream_init(&ogg_os, rand())) {
670 fprintf(stderr, "%s: error: %s\n",
671 option_output, "couldn't create ogg stream state");
675 for(passno=(twopass==3?1:twopass);passno<=(twopass==3?2:twopass);passno++){
679 char input_png[1024];
682 snprintf(input_png, 1023,"%s/%s", input_directory, png_files[0]->d_name);
683 if(png_read(input_png, &w, &h, &yuv)) {
684 fprintf(stderr, "could not read %s\n", input_png);
688 if (passno!=2) fprintf(stderr,"%d frames, %dx%d\n",n,w,h);
690 /* setup complete. Raw processing loop */
693 fprintf(stderr,"\rCompressing.... \n");
696 fprintf(stderr,"\rScanning first pass.... \n");
700 fprintf(stderr, "%s\n", input_png);
703 ti.frame_width = ((w + 15) >>4)<<4;
704 ti.frame_height = ((h + 15)>>4)<<4;
709 ti.fps_numerator = video_fps_numerator;
710 ti.fps_denominator = video_fps_denominator;
711 ti.aspect_numerator = video_aspect_numerator;
712 ti.aspect_denominator = video_aspect_denominator;
713 ti.colorspace = TH_CS_UNSPECIFIED;
714 ti.pixel_fmt = chroma_format;
715 ti.target_bitrate = video_rate;
716 ti.quality = video_quality;
717 ti.keyframe_granule_shift=ilog(keyframe_frequency-1);
719 td=th_encode_alloc(&ti);
721 /* setting just the granule shift only allows power-of-two keyframe
722 spacing. Set the actual requested spacing. */
723 ret=th_encode_ctl(td,TH_ENCCTL_SET_KEYFRAME_FREQUENCY_FORCE,
724 &keyframe_frequency,sizeof(keyframe_frequency-1));
726 fprintf(stderr,"Could not set keyframe interval to %d.\n",(int)keyframe_frequency);
729 ret=th_encode_ctl(td,TH_ENCCTL_SET_VP3_COMPATIBLE,&vp3_compatible,
730 sizeof(vp3_compatible));
731 if(ret<0||!vp3_compatible){
732 fprintf(stderr,"Could not enable strict VP3 compatibility.\n");
734 fprintf(stderr,"Ensure your source format is supported by VP3.\n");
736 "(4:2:0 pixel format, width and height multiples of 16).\n");
741 /* reverse the rate control flags to favor a 'long time' strategy */
742 int arg = TH_RATECTL_CAP_UNDERFLOW;
743 ret=th_encode_ctl(td,TH_ENCCTL_SET_RATE_FLAGS,&arg,sizeof(arg));
745 fprintf(stderr,"Could not set encoder flags for --soft-target\n");
746 /* Default buffer control is overridden on two-pass */
747 if(!twopass&&buf_delay<0){
748 if((keyframe_frequency*7>>1) > 5*video_fps_numerator/video_fps_denominator)
749 arg=keyframe_frequency*7>>1;
751 arg=5*video_fps_numerator/video_fps_denominator;
752 ret=th_encode_ctl(td,TH_ENCCTL_SET_RATE_BUFFER,&arg,sizeof(arg));
754 fprintf(stderr,"Could not set rate control buffer for --soft-target\n");
757 /* set up two-pass if needed */
759 unsigned char *buffer;
761 bytes=th_encode_ctl(td,TH_ENCCTL_2PASS_OUT,&buffer,sizeof(buffer));
763 fprintf(stderr,"Could not set up the first pass of two-pass mode.\n");
764 fprintf(stderr,"Did you remember to specify an estimated bitrate?\n");
767 /*Perform a seek test to ensure we can overwrite this placeholder data at
768 the end; this is better than letting the user sit through a whole
769 encode only to find out their pass 1 file is useless at the end.*/
770 if(fseek(twopass_file,0,SEEK_SET)<0){
771 fprintf(stderr,"Unable to seek in two-pass data file.\n");
774 if(fwrite(buffer,1,bytes,twopass_file)<bytes){
775 fprintf(stderr,"Unable to write to two-pass data file.\n");
778 fflush(twopass_file);
781 /*Enable the second pass here.
782 We make this call just to set the encoder into 2-pass mode, because
783 by default enabling two-pass sets the buffer delay to the whole file
784 (because there's no way to explicitly request that behavior).
785 If we waited until we were actually encoding, it would overwite our
787 if(th_encode_ctl(td,TH_ENCCTL_2PASS_IN,NULL,0)<0){
788 fprintf(stderr,"Could not set up the second pass of two-pass mode.\n");
792 if(fseek(twopass_file,0,SEEK_SET)<0){
793 fprintf(stderr,"Unable to seek in two-pass data file.\n");
798 /*Now we can set the buffer delay if the user requested a non-default one
799 (this has to be done after two-pass is enabled).*/
800 if(passno!=1&&buf_delay>=0){
801 ret=th_encode_ctl(td,TH_ENCCTL_SET_RATE_BUFFER,
802 &buf_delay,sizeof(buf_delay));
804 fprintf(stderr,"Warning: could not set desired buffer delay.\n");
807 /* write the bitstream header packets with proper page interleave */
808 th_comment_init(&tc);
809 /* first packet will get its own page automatically */
810 if(th_encode_flushheader(td,&tc,&op)<=0){
811 fprintf(stderr,"Internal Theora library error.\n");
814 th_comment_clear(&tc);
816 ogg_stream_packetin(&ogg_os,&op);
817 if(ogg_stream_pageout(&ogg_os,&og)!=1){
818 fprintf(stderr,"Internal Ogg library error.\n");
821 fwrite(og.header,1,og.header_len,ogg_fp);
822 fwrite(og.body,1,og.body_len,ogg_fp);
824 /* create the remaining theora headers */
826 ret=th_encode_flushheader(td,&tc,&op);
828 fprintf(stderr,"Internal Theora library error.\n");
832 if(passno!=1)ogg_stream_packetin(&ogg_os,&op);
834 /* Flush the rest of our headers. This ensures
835 the actual data in each stream will start
836 on a new page, as per spec. */
839 int result = ogg_stream_flush(&ogg_os,&og);
842 fprintf(stderr,"Internal Ogg library error.\n");
846 fwrite(og.header,1,og.header_len,ogg_fp);
847 fwrite(og.body,1,og.body_len,ogg_fp);
853 if(i >= n-1) last = 1;
854 if(theora_write_frame(w, h, yuv, last)) {
855 fprintf(stderr,"Encoding error.\n");
861 snprintf(input_png, 1023,"%s/%s", input_directory, png_files[i]->d_name);
862 if(png_read(input_png, &w, &h, &yuv)) {
863 fprintf(stderr, "could not read %s\n", input_png);
866 fprintf(stderr, "%s\n", input_png);
871 /* need to read the final (summary) packet */
872 unsigned char *buffer;
873 int bytes = th_encode_ctl(td, TH_ENCCTL_2PASS_OUT, &buffer, sizeof(buffer));
875 fprintf(stderr,"Could not read two-pass summary data from encoder.\n");
878 if(fseek(twopass_file,0,SEEK_SET)<0){
879 fprintf(stderr,"Unable to seek in two-pass data file.\n");
882 if(fwrite(buffer,1,bytes,twopass_file)<bytes){
883 fprintf(stderr,"Unable to write to two-pass data file.\n");
886 fflush(twopass_file);
891 if(ogg_stream_flush(&ogg_os, &og)) {
892 fwrite(og.header, og.header_len, 1, ogg_fp);
893 fwrite(og.body, og.body_len, 1, ogg_fp);
896 free(input_directory);
899 while (n--) free(png_files[n]);
904 if(ogg_fp!=stdout)fclose(ogg_fp);
907 ogg_stream_clear(&ogg_os);
908 if(twopass_file)fclose(twopass_file);
909 fprintf(stderr,"\r \ndone.\n\n");