]> 4ch.mooo.com Git - 16.git/blob - src/lib/dl/ext/vorbtool/encode.c
meh did some cleanings and i will work on mapread to mm thingy sometime soon! oops...
[16.git] / src / lib / dl / ext / vorbtool / encode.c
1 /* OggEnc
2  **
3  ** This program is distributed under the GNU General Public License, version 2.
4  ** A copy of this license is included with this source.
5  **
6  ** Copyright 2000-2002, Michael Smith <msmith@xiph.org>
7  **
8  ** Portions from Vorbize, (c) Kenneth Arnold <kcarnold-xiph@arnoldnet.net>
9  ** and libvorbis examples, (c) Monty <monty@xiph.org>
10  **/
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <math.h>
19 #include <string.h>
20 #include <time.h>
21
22 #include "platform.h"
23 #include <ext/vorbis/vorbisenc.h>
24 #include "encode.h"
25 #include "i18n.h"
26 #include "skeleton.h"
27
28 #ifdef HAVE_KATE
29 #include "lyrics.h"
30 #include <kate/oggkate.h>
31 #endif
32
33 #define READSIZE 1024
34
35
36 int oe_write_page(ogg_page *page, FILE *fp);
37
38 #define SETD(toset) \
39     do {\
40         if(sscanf(opts[i].val, "%lf", &dval) != 1)\
41             fprintf(stderr, "For option %s, couldn't read value %s as double\n",\
42                     opts[i].arg, opts[i].val);\
43         else\
44             toset = dval;\
45     } while(0)
46
47 #define SETL(toset) \
48     do {\
49         if(sscanf(opts[i].val, "%ld", &lval) != 1)\
50             fprintf(stderr, "For option %s, couldn't read value %s as integer\n",\
51                     opts[i].arg, opts[i].val);\
52         else\
53             toset = lval;\
54     } while(0)
55
56 static void set_advanced_encoder_options(adv_opt *opts, int count,
57         vorbis_info *vi)
58 {
59 #ifdef OV_ECTL_RATEMANAGE2_GET
60     int manage = 0;
61     struct ovectl_ratemanage2_arg ai;
62     int i;
63     double dval;
64     long lval;
65
66     vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE2_GET, &ai);
67
68     for(i=0; i < count; i++) {
69       if(opts[i].val)
70         fprintf(stderr, _("Setting advanced encoder option \"%s\" to %s\n"),
71                 opts[i].arg, opts[i].val);
72       else
73         fprintf(stderr, _("Setting advanced encoder option \"%s\"\n"),
74                 opts[i].arg);
75
76         if(!strcmp(opts[i].arg, "bitrate_average_damping")) {
77             SETD(ai.bitrate_average_damping);
78             manage = 1;
79         }
80         else if(!strcmp(opts[i].arg, "bitrate_average")) {
81             SETL(ai.bitrate_average_kbps);
82             manage = 1;
83         }
84         else if(!strcmp(opts[i].arg, "bit_reservoir_bias")) {
85             SETD(ai.bitrate_limit_reservoir_bias);
86             manage = 1;
87         }
88         else if(!strcmp(opts[i].arg, "bit_reservoir_bits")) {
89             SETL(ai.bitrate_limit_reservoir_bits);
90             manage = 1;
91         }
92         else if(!strcmp(opts[i].arg, "bitrate_hard_min")) {
93             SETL(ai.bitrate_limit_min_kbps);
94             manage = 1;
95         }
96         else if(!strcmp(opts[i].arg, "bitrate_hard_max")) {
97             SETL(ai.bitrate_limit_max_kbps);
98             manage = 1;
99         }
100         else if(!strcmp(opts[i].arg, "disable_coupling")) {
101             int val=0;
102             vorbis_encode_ctl(vi, OV_ECTL_COUPLING_SET, &val);
103         }
104         else if(!strcmp(opts[i].arg, "impulse_noisetune")) {
105             double val;
106             SETD(val);
107             vorbis_encode_ctl(vi, OV_ECTL_IBLOCK_SET, &val);
108         }
109         else if(!strcmp(opts[i].arg, "lowpass_frequency")) {
110             double prev, new;
111             SETD(new);
112             vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_GET, &prev);
113             vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &new);
114             fprintf(stderr, _("Changed lowpass frequency from %f kHz to %f kHz\n"), prev, new);
115         }
116         else {
117             fprintf(stderr, _("Unrecognised advanced option \"%s\"\n"),
118                     opts[i].arg);
119         }
120     }
121
122     if(manage) {
123         if(vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE2_SET, &ai)) {
124             fprintf(stderr, _("Failed to set advanced rate management parameters\n"));
125         }
126     }
127 #else
128     fprintf(stderr,_( "This version of libvorbisenc cannot set advanced rate management parameters\n"));
129 #endif
130 }
131
132 static void add_fishead_packet (ogg_stream_state *os) {
133
134    fishead_packet fp;
135
136    memset(&fp, 0, sizeof(fp));
137    fp.ptime_n = 0;
138    fp.ptime_d = 1000;
139    fp.btime_n = 0;
140    fp.btime_d = 1000;
141
142    add_fishead_to_stream(os, &fp);
143 }
144
145 /*
146  * Adds the fishead packets in the skeleton output stream
147  */
148 static void add_vorbis_fisbone_packet (ogg_stream_state *os, oe_enc_opt *opt) {
149
150    fisbone_packet fp;
151
152    memset(&fp, 0, sizeof(fp));
153    fp.serial_no = opt->serialno;
154    fp.nr_header_packet = 3;
155    fp.granule_rate_n = opt->rate;
156    fp.granule_rate_d = 1;
157    fp.start_granule = 0;
158    fp.preroll = 2;
159    fp.granule_shift = 0;
160
161    add_message_header_field(&fp, "Content-Type", "audio/vorbis");
162
163    add_fisbone_to_stream(os, &fp);
164 }
165
166 #ifdef HAVE_KATE
167 static void add_kate_fisbone_packet (ogg_stream_state *os, oe_enc_opt *opt, kate_info *ki) {
168
169    fisbone_packet fp;
170
171    memset(&fp, 0, sizeof(fp));
172    fp.serial_no = opt->kate_serialno;
173    fp.nr_header_packet = ki->num_headers;
174    fp.granule_rate_n = ki->gps_numerator;
175    fp.granule_rate_d = ki->gps_denominator;
176    fp.start_granule = 0;
177    fp.preroll = 0;
178    fp.granule_shift = ki->granule_shift;
179
180    add_message_header_field(&fp, "Content-Type", "application/x-kate");
181
182    add_fisbone_to_stream(os, &fp);
183 }
184 #endif
185
186 #ifdef HAVE_KATE
187 static void add_kate_karaoke_style(kate_info *ki,unsigned char r,unsigned char g,unsigned char b,unsigned char a)
188 {
189     kate_style *ks;
190     int ret;
191
192     if (!ki) return;
193
194     ks=(kate_style*)malloc(sizeof(kate_style));
195     kate_style_init(ks);
196     ks->text_color.r = r;
197     ks->text_color.g = g;
198     ks->text_color.b = b;
199     ks->text_color.a = a;
200     ret=kate_info_add_style(ki,ks);
201     if (ret<0) {
202       fprintf(stderr, _("WARNING: failed to add Kate karaoke style\n"));
203     }
204 }
205 #endif
206
207 int oe_encode(oe_enc_opt *opt)
208 {
209
210     ogg_stream_state os;
211     ogg_stream_state so; /* stream for skeleton bitstream */
212     ogg_stream_state ko; /* stream for kate bitstream */
213     ogg_page         og;
214     ogg_packet       op;
215
216     vorbis_dsp_state vd;
217     vorbis_block     vb;
218     vorbis_info      vi;
219
220 #ifdef HAVE_KATE
221     kate_info        ki;
222     kate_comment     kc;
223     kate_state       k;
224     oe_lyrics        *lyrics=NULL;
225     size_t           lyrics_index=0;
226     double           vorbis_time = 0.0;
227 #endif
228
229     long samplesdone=0;
230     int eos;
231     long bytes_written = 0, packetsdone=0;
232     double time_elapsed;
233     int ret=0;
234     TIMER *timer;
235     int result;
236
237     if(opt->channels > 255) {
238         fprintf(stderr, _("255 channels should be enough for anyone. (Sorry, but Vorbis doesn't support more)\n"));
239         return 1;
240     }
241
242     /* get start time. */
243     timer = timer_start();
244
245     if(!opt->managed && (opt->min_bitrate>=0 || opt->max_bitrate>=0)){
246       fprintf(stderr, _("Requesting a minimum or maximum bitrate requires --managed\n"));
247       return 1;
248     }
249
250     /* if we had no quality or bitrate spec at all from the user, use
251        the default quality with no management --Monty 20020711 */
252     if(opt->bitrate < 0 && opt->min_bitrate < 0 && opt->max_bitrate < 0){
253       opt->quality_set=1;
254     }
255
256     opt->start_encode(opt->infilename, opt->filename, opt->bitrate, opt->quality, 
257               opt->quality_set, opt->managed, opt->min_bitrate, opt->max_bitrate);
258
259     /* Have vorbisenc choose a mode for us */
260     vorbis_info_init(&vi);
261
262     if(opt->quality_set > 0){
263         if(vorbis_encode_setup_vbr(&vi, opt->channels, opt->rate, opt->quality)){
264             fprintf(stderr, _("Mode initialisation failed: invalid parameters for quality\n"));
265             vorbis_info_clear(&vi);
266             return 1;
267         }
268
269         /* do we have optional hard bitrate restrictions? */
270         if(opt->max_bitrate > 0 || opt->min_bitrate > 0){
271 #ifdef OV_ECTL_RATEMANAGE2_GET
272             long bitrate;
273             struct ovectl_ratemanage2_arg ai;
274
275         vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE2_GET, &ai);
276
277             /* libvorbis 1.1 (and current svn) doesn't actually fill this in,
278                which looks like a bug. It'll then reject it when we call the
279                SET version below. So, fill it in with the values that libvorbis
280                would have used to fill in this structure if we were using the
281                bitrate-oriented setup functions. Unfortunately, some of those
282                values are dependent on the bitrate, and libvorbis has no way to
283                get a nominal bitrate from a quality value. Well, except by doing
284                a full setup... So, we do that.
285                Also, note that this won't work correctly unless you have 
286            version 1.1.1 or later of libvorbis.
287              */
288
289             {
290                 vorbis_info vi2;
291                 vorbis_info_init(&vi2);
292                 vorbis_encode_setup_vbr(&vi2, opt->channels, opt->rate, opt->quality);
293                 vorbis_encode_setup_init(&vi2);
294                 bitrate = vi2.bitrate_nominal;
295                 vorbis_info_clear(&vi2);
296             }
297
298             ai.bitrate_average_kbps = bitrate/1000;
299             ai.bitrate_average_damping = 1.5;
300             ai.bitrate_limit_reservoir_bits = bitrate * 2;
301             ai.bitrate_limit_reservoir_bias = .1;
302
303             /* And now the ones we actually wanted to set */
304             ai.bitrate_limit_min_kbps=opt->min_bitrate;
305             ai.bitrate_limit_max_kbps=opt->max_bitrate;
306             ai.management_active=1;
307
308             if(vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE2_SET, &ai) == 0)
309                 fprintf(stderr, _("Set optional hard quality restrictions\n"));
310             else {
311                 fprintf(stderr, _("Failed to set bitrate min/max in quality mode\n"));
312                 vorbis_info_clear(&vi);
313                 return 1;
314             }
315 #else
316             fprintf(stderr, _("This version of libvorbisenc cannot set advanced rate management parameters\n"));
317             return 1;
318 #endif
319         }
320
321
322     }else {
323         if(vorbis_encode_setup_managed(&vi, opt->channels, opt->rate, 
324                      opt->max_bitrate>0?opt->max_bitrate*1000:-1,
325                      opt->bitrate*1000, 
326                      opt->min_bitrate>0?opt->min_bitrate*1000:-1)){
327             fprintf(stderr, _("Mode initialisation failed: invalid parameters for bitrate\n"));
328             vorbis_info_clear(&vi);
329             return 1;
330         }
331     }
332
333 #ifdef OV_ECTL_RATEMANAGE2_SET
334     if(opt->managed && opt->bitrate < 0)
335     {
336       struct ovectl_ratemanage2_arg ai;
337       vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE2_GET, &ai);
338       ai.bitrate_average_kbps=-1;
339       vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE2_SET, &ai);
340     }
341     else if(!opt->managed)
342     {
343         /* Turn off management entirely (if it was turned on). */
344         vorbis_encode_ctl(&vi, OV_ECTL_RATEMANAGE2_SET, NULL);
345     }
346 #endif
347
348     set_advanced_encoder_options(opt->advopt, opt->advopt_count, &vi);
349
350     vorbis_encode_setup_init(&vi);
351
352
353     /* Now, set up the analysis engine, stream encoder, and other
354        preparation before the encoding begins.
355      */
356
357     vorbis_analysis_init(&vd,&vi);
358     vorbis_block_init(&vd,&vb);
359
360 #ifdef HAVE_KATE
361     if (opt->lyrics) {
362         /* load lyrics */
363         lyrics=load_lyrics(opt->lyrics);
364         /* if it fails, don't do anything else for lyrics */
365         if (!lyrics) {
366             opt->lyrics = NULL;
367         } else {
368             /* init kate for encoding */
369             kate_info_init(&ki);
370             kate_info_set_category(&ki, "LRC");
371             if (opt->lyrics_language)
372               kate_info_set_language(&ki, opt->lyrics_language);
373             else
374               fprintf(stderr, _("WARNING: no language specified for %s\n"), opt->lyrics);
375             kate_comment_init(&kc);
376             kate_encode_init(&k,&ki);
377
378             /* if we're in karaoke mode (we have syllable level timing info),
379                add style info in case some graphical player is used */
380             add_kate_karaoke_style(&ki, 255, 255, 255, 255);
381             add_kate_karaoke_style(&ki, 255, 128, 128, 255);
382         }
383     }
384 #endif
385
386     ogg_stream_init(&os, opt->serialno);
387     if (opt->with_skeleton)
388         ogg_stream_init(&so, opt->skeleton_serialno);
389     if (opt->lyrics)
390         ogg_stream_init(&ko, opt->kate_serialno);
391
392     /* create the skeleton fishead packet and output it */ 
393     if (opt->with_skeleton) {
394         add_fishead_packet(&so);
395         if ((ret = flush_ogg_stream_to_file(&so, opt->out))) {
396             opt->error(_("Failed writing fishead packet to output stream\n"));
397             goto cleanup; 
398         }
399     }
400
401     /* Now, build the three header packets and send through to the stream 
402        output stage (but defer actual file output until the main encode loop) */
403
404     {
405         ogg_packet header_main;
406         ogg_packet header_comments;
407         ogg_packet header_codebooks;
408
409         /* Build the packets */
410         vorbis_analysis_headerout(&vd,opt->comments,
411                 &header_main,&header_comments,&header_codebooks);
412
413         /* And stream them out */
414         /* output the vorbis bos first, then the kate bos, then the fisbone packets */
415         ogg_stream_packetin(&os,&header_main);
416         while((result = ogg_stream_flush(&os, &og)))
417         {
418             if(!result) break;
419             ret = oe_write_page(&og, opt->out);
420             if(ret != og.header_len + og.body_len)
421             {
422                 opt->error(_("Failed writing header to output stream\n"));
423                 ret = 1;
424                 goto cleanup; /* Bail and try to clean up stuff */
425             }
426         }
427
428 #ifdef HAVE_KATE
429         if (opt->lyrics) {
430             ogg_packet kate_op;
431             ret = kate_ogg_encode_headers(&k, &kc, &kate_op);
432             if (ret < 0) {
433                 opt->error(_("Failed encoding Kate header\n"));
434                 goto cleanup;
435             }
436             ogg_stream_packetin(&ko,&kate_op);
437             while((result = ogg_stream_flush(&ko, &og)))
438             {
439                 if(!result) break;
440                 ret = oe_write_page(&og, opt->out);
441                 if(ret != og.header_len + og.body_len)
442                 {
443                     opt->error(_("Failed writing header to output stream\n"));
444                     ret = 1;
445                     goto cleanup; /* Bail and try to clean up stuff */
446                 }
447             }
448             ogg_packet_clear(&kate_op);
449         }
450 #endif
451
452         if (opt->with_skeleton) {
453             add_vorbis_fisbone_packet(&so, opt);
454             if ((ret = flush_ogg_stream_to_file(&so, opt->out))) {
455                 opt->error(_("Failed writing fisbone header packet to output stream\n"));
456                 goto cleanup;
457             }
458 #ifdef HAVE_KATE
459             if (opt->lyrics) {
460                 add_kate_fisbone_packet(&so, opt, &ki);
461                 if ((ret = flush_ogg_stream_to_file(&so, opt->out))) {
462                     opt->error(_("Failed writing fisbone header packet to output stream\n"));
463                     goto cleanup;
464                 }
465             }
466 #endif
467         }
468
469         /* write the next Vorbis headers */
470         ogg_stream_packetin(&os,&header_comments);
471         ogg_stream_packetin(&os,&header_codebooks);
472
473         while((result = ogg_stream_flush(&os, &og)))
474         {
475             if(!result) break;
476             ret = oe_write_page(&og, opt->out);
477             if(ret != og.header_len + og.body_len)
478             {
479                 opt->error(_("Failed writing header to output stream\n"));
480                 ret = 1;
481                 goto cleanup; /* Bail and try to clean up stuff */
482             }
483         }
484     }
485
486     /* build kate headers if requested */
487 #ifdef HAVE_KATE
488     if (opt->lyrics) {
489         while (kate_ogg_encode_headers(&k,&kc,&op)==0) {
490           ogg_stream_packetin(&ko,&op);
491           ogg_packet_clear(&op);
492         }
493         while((result = ogg_stream_flush(&ko, &og)))
494         {
495             if(!result) break;
496             ret = oe_write_page(&og, opt->out);
497             if(ret != og.header_len + og.body_len)
498             {
499                 opt->error(_("Failed writing header to output stream\n"));
500                 ret = 1;
501                 goto cleanup; /* Bail and try to clean up stuff */
502             }
503         }
504     }
505 #endif
506
507     if (opt->with_skeleton) {
508         add_eos_packet_to_stream(&so);
509         if ((ret = flush_ogg_stream_to_file(&so, opt->out))) {
510             opt->error(_("Failed writing skeleton eos packet to output stream\n"));
511             goto cleanup;
512         }
513     }
514
515     eos = 0;
516
517     /* Main encode loop - continue until end of file */
518     while(!eos)
519     {
520         float **buffer = vorbis_analysis_buffer(&vd, READSIZE);
521         long samples_read = opt->read_samples(opt->readdata, 
522                 buffer, READSIZE);
523
524         if(samples_read ==0)
525             /* Tell the library that we wrote 0 bytes - signalling the end */
526             vorbis_analysis_wrote(&vd,0);
527         else
528         {
529             samplesdone += samples_read;
530
531             /* Call progress update every 40 pages */
532             if(packetsdone>=40)
533             {
534                 double time;
535
536                 packetsdone = 0;
537                 time = timer_time(timer);
538
539                 opt->progress_update(opt->filename, opt->total_samples_per_channel, 
540                         samplesdone, time);
541             }
542
543             /* Tell the library how many samples (per channel) we wrote 
544                into the supplied buffer */
545             vorbis_analysis_wrote(&vd, samples_read);
546         }
547
548         /* While we can get enough data from the library to analyse, one
549            block at a time... */
550         while(vorbis_analysis_blockout(&vd,&vb)==1)
551         {
552
553             /* Do the main analysis, creating a packet */
554             vorbis_analysis(&vb, NULL);
555             vorbis_bitrate_addblock(&vb);
556
557             while(vorbis_bitrate_flushpacket(&vd, &op)) 
558             {
559                 /* Add packet to bitstream */
560                 ogg_stream_packetin(&os,&op);
561                 packetsdone++;
562
563                 /* If we've gone over a page boundary, we can do actual output,
564                    so do so (for however many pages are available) */
565
566                 while(!eos)
567                 {
568                     int result = ogg_stream_pageout(&os,&og);
569                     if(!result) break;
570
571                     /* now that we have a new Vorbis page, we scan lyrics for any that is due */
572 #ifdef HAVE_KATE
573                     if (opt->lyrics && ogg_page_granulepos(&og)>=0) {
574                         vorbis_time = vorbis_granule_time(&vd, ogg_page_granulepos(&og));
575                         const oe_lyrics_item *item;
576                         while ((item = get_lyrics(lyrics, vorbis_time, &lyrics_index))) {
577                             ogg_packet kate_op;
578                             if (item->km) {
579                                 ret = kate_encode_set_style_index(&k, 0);
580                                 if (ret < 0) {
581                                     opt->error(_("Failed encoding karaoke style - continuing anyway\n"));
582                                 }
583                                 ret = kate_encode_set_secondary_style_index(&k, 1);
584                                 if (ret < 0) {
585                                     opt->error(_("Failed encoding karaoke style - continuing anyway\n"));
586                                 }
587                                 ret = kate_encode_add_motion(&k, item->km, 0);
588                                 if (ret < 0) {
589                                     opt->error(_("Failed encoding karaoke motion - continuing anyway\n"));
590                                 }
591                             }
592                             ret = kate_ogg_encode_text(&k, item->t0, item->t1, item->text, strlen(item->text)+1, &kate_op);
593                             if (ret < 0) {
594                                 opt->error(_("Failed encoding lyrics - continuing anyway\n"));
595                             }
596                             else {
597                                 ogg_stream_packetin(&ko, &kate_op);
598                                 ogg_packet_clear(&kate_op);
599                                 while (1) {
600                                     ogg_page ogk;
601                                     int result=ogg_stream_flush(&ko,&ogk);
602                                     if (!result) break;
603                                     ret = oe_write_page(&ogk, opt->out);
604                                     if(ret != ogk.header_len + ogk.body_len)
605                                     {
606                                         opt->error(_("Failed writing data to output stream\n"));
607                                         ret = 1;
608                                         goto cleanup; /* Bail */
609                                     }
610                                     else
611                                         bytes_written += ret;
612                                 }
613                             }
614                         }
615                     }
616 #endif
617
618                     ret = oe_write_page(&og, opt->out);
619                     if(ret != og.header_len + og.body_len)
620                     {
621                         opt->error(_("Failed writing data to output stream\n"));
622                         ret = 1;
623                         goto cleanup; /* Bail */
624                     }
625                     else
626                         bytes_written += ret; 
627
628                     if(ogg_page_eos(&og))
629                         eos = 1;
630                 }
631             }
632         }
633     }
634
635     /* if encoding lyrics, signal EOS and cleanup the kate state */
636 #ifdef HAVE_KATE
637     if (opt->lyrics) {
638         ogg_packet kate_op;
639         ret = kate_ogg_encode_finish(&k, vorbis_time, &kate_op);
640         if (ret < 0) {
641             opt->error(_("Failed encoding Kate EOS packet\n"));
642         }
643         else {
644             ogg_stream_packetin(&ko,&kate_op);
645             packetsdone++;
646             ogg_packet_clear(&kate_op);
647
648             eos = 0;
649             while(!eos)
650             {
651                 int result = ogg_stream_pageout(&ko,&og);
652                 if(!result) break;
653
654                 ret = oe_write_page(&og, opt->out);
655                 if(ret != og.header_len + og.body_len)
656                 {
657                     opt->error(_("Failed writing data to output stream\n"));
658                     ret = 1;
659                     goto cleanup; /* Bail */
660                 }
661                 else
662                     bytes_written += ret;
663
664                 if(ogg_page_eos(&og))
665                     eos = 1;
666             }
667         }
668     }
669 #endif
670
671     ret = 0; /* Success.  Set return value to 0 since other things reuse it
672               * for nefarious purposes. */
673
674     /* Cleanup time */
675 cleanup:
676
677 #ifdef HAVE_KATE
678     if (opt->lyrics) {
679        ogg_stream_clear(&ko);
680         kate_clear(&k);
681         kate_info_clear(&ki);
682         kate_comment_clear(&kc);
683         free_lyrics(lyrics);
684     }
685 #endif
686
687     if (opt->with_skeleton)
688         ogg_stream_clear(&so);
689
690     ogg_stream_clear(&os);
691
692     vorbis_block_clear(&vb);
693     vorbis_dsp_clear(&vd);
694     vorbis_info_clear(&vi);
695
696     time_elapsed = timer_time(timer);
697     opt->end_encode(opt->filename, time_elapsed, opt->rate, samplesdone, bytes_written);
698
699     timer_clear(timer);
700
701     return ret;
702 }
703
704 void update_statistics_full(char *fn, long total, long done, double time)
705 {
706     static char *spinner="|/-\\";
707     static int spinpoint = 0;
708     double remain_time;
709     int minutes=0,seconds=0;
710
711     remain_time = time/((double)done/(double)total) - time;
712     minutes = ((int)remain_time)/60;
713     seconds = (int)(remain_time - (double)((int)remain_time/60)*60);
714
715     fprintf(stderr, "\r");
716     fprintf(stderr, _("\t[%5.1f%%] [%2dm%.2ds remaining] %c "), 
717             done*100.0/total, minutes, seconds, spinner[spinpoint++%4]);
718 }
719
720 void update_statistics_notime(char *fn, long total, long done, double time)
721 {
722     static char *spinner="|/-\\";
723     static int spinpoint =0;
724  
725     fprintf(stderr, "\r");
726     fprintf(stderr, _("\tEncoding [%2dm%.2ds so far] %c "), 
727             ((int)time)/60, (int)(time - (double)((int)time/60)*60),
728             spinner[spinpoint++%4]);
729 }
730
731 int oe_write_page(ogg_page *page, FILE *fp)
732 {
733     int written;
734     written = fwrite(page->header,1,page->header_len, fp);
735     written += fwrite(page->body,1,page->body_len, fp);
736
737     return written;
738 }
739
740 void final_statistics(char *fn, double time, int rate, long samples, long bytes)
741 {
742     double speed_ratio;
743     if(fn)
744         fprintf(stderr, _("\n\nDone encoding file \"%s\"\n"), fn);
745     else
746         fprintf(stderr, _("\n\nDone encoding.\n"));
747
748     speed_ratio = (double)samples / (double)rate / time;
749  
750     fprintf(stderr, _("\n\tFile length:  %dm %04.1fs\n"),
751             (int)(samples/rate/60),
752             samples/rate - 
753             floor(samples/rate/60)*60);
754     fprintf(stderr, _("\tElapsed time: %dm %04.1fs\n"),
755             (int)(time/60),
756             time - floor(time/60)*60);
757     fprintf(stderr, _("\tRate:         %.4f\n"), speed_ratio);
758     fprintf(stderr, _("\tAverage bitrate: %.1f kb/s\n\n"), 
759         8./1000.*((double)bytes/((double)samples/(double)rate)));
760 }
761
762 void final_statistics_null(char *fn, double time, int rate, long samples, 
763         long bytes)
764 {
765     /* Don't do anything, this is just a placeholder function for quiet mode */
766 }
767
768 void update_statistics_null(char *fn, long total, long done, double time)
769 {
770     /* So is this */
771 }
772
773 void encode_error(char *errmsg)
774 {
775     fprintf(stderr, "\n%s\n", errmsg);
776 }
777
778 static void print_brconstraints(int min, int max)
779 {
780     if(min > 0 && max > 0)
781         fprintf(stderr, _("(min %d kbps, max %d kbps)"), min,max);
782     else if(min > 0)
783         fprintf(stderr, _("(min %d kbps, no max)"), min);
784     else if(max > 0)
785         fprintf(stderr, _("(no min, max %d kbps)"), max);
786     else
787         fprintf(stderr, _("(no min or max)"));
788 }
789
790 void start_encode_full(char *fn, char *outfn, int bitrate, float quality, int qset,
791         int managed, int min, int max)
792 {
793   if(bitrate>0){
794     if(managed>0){
795       fprintf(stderr, _("Encoding %s%s%s to \n         "
796             "%s%s%s \nat average bitrate %d kbps "),
797           fn?"\"":"", fn?fn:_("standard input"), fn?"\"":"",
798           outfn?"\"":"", outfn?outfn:_("standard output"), outfn?"\"":"",
799           bitrate);
800       print_brconstraints(min,max);
801       fprintf(stderr, ", \nusing full bitrate management engine\n");
802     } else {
803       fprintf(stderr, _("Encoding %s%s%s to \n         %s%s%s \nat approximate bitrate %d kbps (VBR encoding enabled)\n"),
804           fn?"\"":"", fn?fn:_("standard input"), fn?"\"":"",
805         outfn?"\"":"", outfn?outfn:_("standard output"), outfn?"\"":"",
806           bitrate);
807     }
808   }else{
809     if(qset>0){
810       if(managed>0){
811     fprintf(stderr, _("Encoding %s%s%s to \n         %s%s%s \nat quality level %2.2f using constrained VBR "),
812         fn?"\"":"", fn?fn:_("standard input"), fn?"\"":"",
813         outfn?"\"":"", outfn?outfn:_("standard output"), outfn?"\"":"",
814         quality * 10);
815     print_brconstraints(min,max);
816     fprintf(stderr, "\n");
817       }else{
818         fprintf(stderr, _("Encoding %s%s%s to \n         %s%s%s \nat quality %2.2f\n"),
819                 fn?"\"":"", fn?fn:_("standard input"), fn?"\"":"",
820                 outfn?"\"":"", outfn?outfn:_("standard output"), outfn?"\"":"",
821                 quality * 10);
822       }
823     }else{
824       fprintf(stderr, _("Encoding %s%s%s to \n         %s%s%s \nusing bitrate management "),
825           fn?"\"":"", fn?fn:_("standard input"), fn?"\"":"",
826           outfn?"\"":"", outfn?outfn:_("standard output"), outfn?"\"":"");
827       print_brconstraints(min,max);
828       fprintf(stderr, "\n");
829     }
830   }
831 }
832
833 void start_encode_null(char *fn, char *outfn, int bitrate, float quality, int qset,
834         int managed, int min, int max)
835 {
836 }