a7463bfaa6c3ad77631d0b8be0a37cd31f1a3c9e
[speexdsp.git] / src / speexenc.c
1 /* Copyright (C) 2002-2003 Jean-Marc Valin 
2    File: speexenc.c
3
4    Redistribution and use in source and binary forms, with or without
5    modification, are permitted provided that the following conditions
6    are met:
7    
8    - Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10    
11    - Redistributions in binary form must reproduce the above copyright
12    notice, this list of conditions and the following disclaimer in the
13    documentation and/or other materials provided with the distribution.
14    
15    - Neither the name of the Xiph.org Foundation nor the names of its
16    contributors may be used to endorse or promote products derived from
17    this software without specific prior written permission.
18    
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <stdio.h>
37 #if !defined WIN32 && !defined _WIN32
38 #include <unistd.h>
39 #include <getopt.h>
40 #endif
41 #ifndef HAVE_GETOPT_LONG
42 #include "getopt_win.h"
43 #endif
44 #include <stdlib.h>
45 #include <string.h>
46 #include <time.h>
47
48 #include <speex/speex.h>
49 #include <ogg/ogg.h>
50 #include "wav_io.h"
51 #include <speex/speex_header.h>
52 #include <speex/speex_stereo.h>
53 #include "misc.h"
54 #include <speex/speex_preprocess.h>
55
56 #if defined WIN32 || defined _WIN32
57 #include "getopt_win.h"
58 /* We need the following two to set stdout to binary */
59 #include <io.h>
60 #include <fcntl.h>
61 #endif
62
63
64 void comment_init(char **comments, int* length, char *vendor_string);
65 void comment_add(char **comments, int* length, char *tag, char *val);
66
67
68 /*Write an Ogg page to a file pointer*/
69 int oe_write_page(ogg_page *page, FILE *fp)
70 {
71    int written;
72    written = fwrite(page->header,1,page->header_len, fp);
73    written += fwrite(page->body,1,page->body_len, fp);
74    
75    return written;
76 }
77
78 #define MAX_FRAME_SIZE 2000
79 #define MAX_FRAME_BYTES 2000
80
81 /* Convert input audio bits, endians and channels */
82 static int read_samples(FILE *fin,int frame_size, int bits, int channels, int lsb, short * input, char *buff, int *size)
83 {   
84    unsigned char in[MAX_FRAME_BYTES*2];
85    int i;
86    short *s;
87    int nb_read;
88
89    if (size && *size<=0)
90    {
91       return 0;
92    }
93    /*Read input audio*/
94    if (size)
95       *size -= bits/8*channels*frame_size;
96    if (buff)
97    {
98       for (i=0;i<12;i++)
99          in[i]=buff[i];
100       nb_read = fread(in+12,1,bits/8*channels*frame_size-12, fin) + 12;
101       if (size)
102          *size += 12;
103    } else {
104       nb_read = fread(in,1,bits/8*channels* frame_size, fin);
105    }
106    nb_read /= bits/8*channels;
107
108    /*fprintf (stderr, "%d\n", nb_read);*/
109    if (nb_read==0)
110       return 0;
111
112    s=(short*)in;
113    if(bits==8)
114    {
115       /* Convert 8->16 bits */
116       for(i=frame_size*channels-1;i>=0;i--)
117       {
118          s[i]=(in[i]<<8)^0x8000;
119       }
120    } else
121    {
122       /* convert to our endian format */
123       for(i=0;i<frame_size*channels;i++)
124       {
125          if(lsb) 
126             s[i]=le_short(s[i]); 
127          else
128             s[i]=be_short(s[i]);
129       }
130    }
131
132    /* FIXME: This is probably redundent now */
133    /* copy to float input buffer */
134    for (i=0;i<frame_size*channels;i++)
135    {
136       input[i]=(short)s[i];
137    }
138
139    for (i=nb_read*channels;i<frame_size*channels;i++)
140    {
141       input[i]=0;
142    }
143
144
145    return nb_read;
146 }
147
148 void version()
149 {
150    printf ("speexenc (Speex encoder) version " SPEEX_VERSION " (compiled " __DATE__ ")\n");
151    printf ("Copyright (C) 2002-2003 Jean-Marc Valin\n");
152 }
153
154 void version_short()
155 {
156    printf ("speexenc version " SPEEX_VERSION "\n");
157    printf ("Copyright (C) 2002-2003 Jean-Marc Valin\n");
158 }
159
160 void usage()
161 {
162    printf ("Usage: speexenc [options] input_file output_file\n");
163    printf ("\n");
164    printf ("Encodes input_file using Speex. It can read the WAV or raw files.\n");
165    printf ("\n");
166    printf ("input_file can be:\n");
167    printf ("  filename.wav      wav file\n");
168    printf ("  filename.*        Raw PCM file (any extension other than .wav)\n");
169    printf ("  -                 stdin\n");
170    printf ("\n");  
171    printf ("output_file can be:\n");
172    printf ("  filename.spx      Speex file\n");
173    printf ("  -                 stdout\n");
174    printf ("\n");  
175    printf ("Options:\n");
176    printf (" -n, --narrowband   Narrowband (8 kHz) input file\n"); 
177    printf (" -w, --wideband     Wideband (16 kHz) input file\n"); 
178    printf (" -u, --ultra-wideband \"Ultra-wideband\" (32 kHz) input file\n"); 
179    printf (" --quality n        Encoding quality (0-10), default 8\n"); 
180    printf (" --bitrate n        Encoding bit-rate (use bit-rate n or lower)\n"); 
181    printf (" --vbr              Enable variable bit-rate (VBR)\n"); 
182    printf (" --abr rate         Enable average bit-rate (ABR) at rate bps\n"); 
183    printf (" --vad              Enable voice activity detection (VAD)\n"); 
184    printf (" --dtx              Enable file-based discontinuous transmission (DTX)\n"); 
185    printf (" --comp n           Set encoding complexity (0-10), default 3\n"); 
186    printf (" --nframes n        Number of frames per Ogg packet (1-10), default 1\n"); 
187    printf (" --denoise          Denoise the input before encoding\n"); 
188    printf (" --agc              Apply adaptive gain control (AGC) before encoding\n"); 
189    printf (" --comment          Add the given string as an extra comment. This may be\n");
190    printf ("                     used multiple times\n");
191    printf (" --author           Author of this track\n");
192    printf (" --title            Title for this track\n");
193    printf (" -h, --help         This help\n"); 
194    printf (" -v, --version      Version information\n"); 
195    printf (" -V                 Verbose mode (show bit-rate)\n"); 
196    printf ("Raw input options:\n");
197    printf (" --rate n           Sampling rate for raw input\n"); 
198    printf (" --stereo           Consider raw input as stereo\n"); 
199    printf (" --le               Raw input is little-endian\n"); 
200    printf (" --be               Raw input is big-endian\n"); 
201    printf (" --8bit             Raw input is 8-bit unsigned\n"); 
202    printf (" --16bit            Raw input is 16-bit signed\n"); 
203    printf ("Default raw PCM input is 16-bit, little-endian, mono\n"); 
204    printf ("\n");
205    printf ("More information is available from the Speex site: http://www.speex.org\n");
206    printf ("\n");
207    printf ("Please report bugs to the mailing list `speex-dev@xiph.org'.\n");
208 }
209
210
211 int main(int argc, char **argv)
212 {
213    int nb_samples, total_samples=0, nb_encoded;
214    int c;
215    int option_index = 0;
216    char *inFile, *outFile;
217    FILE *fin, *fout;
218    short input[MAX_FRAME_SIZE];
219    int frame_size;
220    int quiet=0;
221    int vbr_enabled=0;
222    int abr_enabled=0;
223    int vad_enabled=0;
224    int dtx_enabled=0;
225    int nbBytes;
226    const SpeexMode *mode=NULL;
227    void *st;
228    SpeexBits bits;
229    char cbits[MAX_FRAME_BYTES];
230    struct option long_options[] =
231    {
232       {"wideband", no_argument, NULL, 0},
233       {"ultra-wideband", no_argument, NULL, 0},
234       {"narrowband", no_argument, NULL, 0},
235       {"vbr", no_argument, NULL, 0},
236       {"abr", required_argument, NULL, 0},
237       {"vad", no_argument, NULL, 0},
238       {"dtx", no_argument, NULL, 0},
239       {"quality", required_argument, NULL, 0},
240       {"bitrate", required_argument, NULL, 0},
241       {"nframes", required_argument, NULL, 0},
242       {"comp", required_argument, NULL, 0},
243       {"denoise", no_argument, NULL, 0},
244       {"agc", no_argument, NULL, 0},
245       {"help", no_argument, NULL, 0},
246       {"quiet", no_argument, NULL, 0},
247       {"le", no_argument, NULL, 0},
248       {"be", no_argument, NULL, 0},
249       {"8bit", no_argument, NULL, 0},
250       {"16bit", no_argument, NULL, 0},
251       {"stereo", no_argument, NULL, 0},
252       {"rate", required_argument, NULL, 0},
253       {"version", no_argument, NULL, 0},
254       {"version-short", no_argument, NULL, 0},
255       {"comment", required_argument, NULL, 0},
256       {"author", required_argument, NULL, 0},
257       {"title", required_argument, NULL, 0},
258       {0, 0, 0, 0}
259    };
260    int print_bitrate=0;
261    int rate=0, size;
262    int chan=1;
263    int fmt=16;
264    int quality=-1;
265    float vbr_quality=-1;
266    int lsb=1;
267    ogg_stream_state os;
268    ogg_page              og;
269    ogg_packet            op;
270    int bytes_written=0, ret, result;
271    int id=-1;
272    SpeexHeader header;
273    int nframes=1;
274    int complexity=3;
275    char *vendor_string = "Encoded with Speex " SPEEX_VERSION;
276    char *comments;
277    int comments_length;
278    int close_in=0, close_out=0;
279    int eos=0;
280    int bitrate=0;
281    double cumul_bits=0, enc_frames=0;
282    char first_bytes[12];
283    int wave_input=0;
284    int tmp;
285    SpeexPreprocessState *preprocess = NULL;
286    int denoise_enabled=0, agc_enabled=0;
287    int lookahead = 0;
288    
289    comment_init(&comments, &comments_length, vendor_string);
290
291    /*Process command-line options*/
292    while(1)
293    {
294       c = getopt_long (argc, argv, "nwuhvV",
295                        long_options, &option_index);
296       if (c==-1)
297          break;
298       
299       switch(c)
300       {
301       case 0:
302          if (strcmp(long_options[option_index].name,"narrowband")==0)
303          {
304             mode=&speex_nb_mode;
305          } else if (strcmp(long_options[option_index].name,"wideband")==0)
306          {
307             mode=&speex_wb_mode;
308          } else if (strcmp(long_options[option_index].name,"ultra-wideband")==0)
309          {
310             mode=&speex_uwb_mode;
311          } else if (strcmp(long_options[option_index].name,"vbr")==0)
312          {
313             vbr_enabled=1;
314          } else if (strcmp(long_options[option_index].name,"abr")==0)
315          {
316             abr_enabled=atoi(optarg);
317             if (!abr_enabled)
318             {
319                fprintf (stderr, "Invalid ABR value: %d\n", abr_enabled);
320                exit(1);
321             }
322          } else if (strcmp(long_options[option_index].name,"vad")==0)
323          {
324             vad_enabled=1;
325          } else if (strcmp(long_options[option_index].name,"dtx")==0)
326          {
327             dtx_enabled=1;
328          } else if (strcmp(long_options[option_index].name,"quality")==0)
329          {
330             quality = atoi (optarg);
331             vbr_quality=atof(optarg);
332          } else if (strcmp(long_options[option_index].name,"bitrate")==0)
333          {
334             bitrate = atoi (optarg);
335          } else if (strcmp(long_options[option_index].name,"nframes")==0)
336          {
337             nframes = atoi (optarg);
338             if (nframes<1)
339                nframes=1;
340             if (nframes>10)
341                nframes=10;
342          } else if (strcmp(long_options[option_index].name,"comp")==0)
343          {
344             complexity = atoi (optarg);
345          } else if (strcmp(long_options[option_index].name,"denoise")==0)
346          {
347             denoise_enabled=1;
348          } else if (strcmp(long_options[option_index].name,"agc")==0)
349          {
350             agc_enabled=1;
351          } else if (strcmp(long_options[option_index].name,"help")==0)
352          {
353             usage();
354             exit(0);
355          } else if (strcmp(long_options[option_index].name,"quiet")==0)
356          {
357             quiet = 1;
358          } else if (strcmp(long_options[option_index].name,"version")==0)
359          {
360             version();
361             exit(0);
362          } else if (strcmp(long_options[option_index].name,"version-short")==0)
363          {
364             version_short();
365             exit(0);
366          } else if (strcmp(long_options[option_index].name,"le")==0)
367          {
368             lsb=1;
369          } else if (strcmp(long_options[option_index].name,"be")==0)
370          {
371             lsb=0;
372          } else if (strcmp(long_options[option_index].name,"8bit")==0)
373          {
374             fmt=8;
375          } else if (strcmp(long_options[option_index].name,"16bit")==0)
376          {
377             fmt=16;
378          } else if (strcmp(long_options[option_index].name,"stereo")==0)
379          {
380             chan=2;
381          } else if (strcmp(long_options[option_index].name,"rate")==0)
382          {
383             rate=atoi (optarg);
384          } else if (strcmp(long_options[option_index].name,"comment")==0)
385          {
386            comment_add(&comments, &comments_length, NULL, optarg); 
387          } else if (strcmp(long_options[option_index].name,"author")==0)
388          {
389            comment_add(&comments, &comments_length, "author=", optarg); 
390          } else if (strcmp(long_options[option_index].name,"title")==0)
391          {
392            comment_add(&comments, &comments_length, "title=", optarg); 
393          }
394
395          break;
396       case 'n':
397          mode=&speex_nb_mode;
398          break;
399       case 'h':
400          usage();
401          exit(0);
402          break;
403       case 'v':
404          version();
405          exit(0);
406          break;
407       case 'V':
408          print_bitrate=1;
409          break;
410       case 'w':
411          mode=&speex_wb_mode;
412          break;
413       case 'u':
414          mode=&speex_uwb_mode;
415          break;
416       case '?':
417          usage();
418          exit(1);
419          break;
420       }
421    }
422    if (argc-optind!=2)
423    {
424       usage();
425       exit(1);
426    }
427    inFile=argv[optind];
428    outFile=argv[optind+1];
429
430    /*Initialize Ogg stream struct*/
431    srand(time(NULL));
432    if (ogg_stream_init(&os, rand())==-1)
433    {
434       fprintf(stderr,"Error: stream init failed\n");
435       exit(1);
436    }
437
438    if (strcmp(inFile, "-")==0)
439    {
440 #if defined WIN32 || defined _WIN32
441          _setmode(_fileno(stdin), _O_BINARY);
442 #endif
443       fin=stdin;
444    }
445    else 
446    {
447       fin = fopen(inFile, "rb");
448       if (!fin)
449       {
450          perror(inFile);
451          exit(1);
452       }
453       close_in=1;
454    }
455
456    {
457       fread(first_bytes, 1, 12, fin);
458       if (strncmp(first_bytes,"RIFF",4)==0 && strncmp(first_bytes,"RIFF",4)==0)
459       {
460          if (read_wav_header(fin, &rate, &chan, &fmt, &size)==-1)
461             exit(1);
462          wave_input=1;
463          lsb=1; /* CHECK: exists big-endian .wav ?? */
464       }
465    }
466
467    if (!mode && !rate)
468    {
469       /* By default, use narrowband/8 kHz */
470       mode=&speex_nb_mode;
471       rate=8000;
472    } else if (mode && rate)
473    {
474       if (rate>48000)
475       {
476          fprintf (stderr, "Error: sampling rate too high: %d Hz, try down-sampling\n", rate);
477          exit(1);
478       } else if (rate>25000)
479       {
480          if (mode!=&speex_uwb_mode)
481          {
482             fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try ultra-wideband instead\n", mode->modeName , rate);
483          }
484       } else if (rate>12500)
485       {
486          if (mode!=&speex_wb_mode)
487          {
488             fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try wideband instead\n", mode->modeName , rate);
489          }
490       } else if (rate>=6000)
491       {
492          if (mode!=&speex_nb_mode)
493          {
494             fprintf (stderr, "Warning: Trying to encode in %s at %d Hz. I'll do it but I suggest you try narrowband instead\n", mode->modeName , rate);
495          }
496       } else {
497          fprintf (stderr, "Error: sampling rate too low: %d Hz\n", rate);
498          exit(1);
499       }
500    } else if (!mode)
501    {
502       if (rate>48000)
503       {
504          fprintf (stderr, "Error: sampling rate too high: %d Hz, try down-sampling\n", rate);
505          exit(1);
506       } else if (rate>25000)
507       {
508          mode=&speex_uwb_mode;
509       } else if (rate>12500)
510       {
511          mode=&speex_wb_mode;
512       } else if (rate>=6000)
513       {
514          mode=&speex_nb_mode;
515       } else {
516          fprintf (stderr, "Error: Sampling rate too low: %d Hz\n", rate);
517          exit(1);
518       }
519    } else if (!rate)
520    {
521       if (mode==&speex_nb_mode)
522          rate=8000;
523       else if (mode==&speex_wb_mode)
524          rate=16000;
525       else if (mode==&speex_uwb_mode)
526          rate=32000;
527    }
528
529    if (!quiet)
530       if (rate!=8000 && rate!=16000 && rate!=32000)
531          fprintf (stderr, "Warning: Speex is only optimized for 8, 16 and 32 kHz. It will still work at %d Hz but your mileage may vary\n", rate); 
532
533    speex_init_header(&header, rate, 1, mode);
534    header.frames_per_packet=nframes;
535    header.vbr=vbr_enabled;
536    header.nb_channels = chan;
537
538    {
539       char *st_string="mono";
540       if (chan==2)
541          st_string="stereo";
542       if (!quiet)
543          fprintf (stderr, "Encoding %d Hz audio using %s mode (%s)\n", 
544                header.rate, mode->modeName, st_string);
545    }
546    /*fprintf (stderr, "Encoding %d Hz audio at %d bps using %s mode\n", 
547      header.rate, mode->bitrate, mode->modeName);*/
548
549    /*Initialize Speex encoder*/
550    st = speex_encoder_init(mode);
551
552    if (strcmp(outFile,"-")==0)
553    {
554 #if defined WIN32 || defined _WIN32
555       _setmode(_fileno(stdout), _O_BINARY);
556 #endif
557       fout=stdout;
558    }
559    else 
560    {
561       fout = fopen(outFile, "wb");
562       if (!fout)
563       {
564          perror(outFile);
565          exit(1);
566       }
567       close_out=1;
568    }
569
570    speex_encoder_ctl(st, SPEEX_GET_FRAME_SIZE, &frame_size);
571    speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &complexity);
572    speex_encoder_ctl(st, SPEEX_SET_SAMPLING_RATE, &rate);
573
574    if (quality >= 0)
575    {
576       if (vbr_enabled)
577          speex_encoder_ctl(st, SPEEX_SET_VBR_QUALITY, &vbr_quality);
578       else
579          speex_encoder_ctl(st, SPEEX_SET_QUALITY, &quality);
580    }
581    if (bitrate)
582    {
583       if (quality >= 0 && vbr_enabled)
584          fprintf (stderr, "Warning: --bitrate option is overriding --quality\n");
585       speex_encoder_ctl(st, SPEEX_SET_BITRATE, &bitrate);
586    }
587    if (vbr_enabled)
588    {
589       tmp=1;
590       speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
591    } else if (vad_enabled)
592    {
593       tmp=1;
594       speex_encoder_ctl(st, SPEEX_SET_VAD, &tmp);
595    }
596    if (dtx_enabled)
597       speex_encoder_ctl(st, SPEEX_SET_DTX, &tmp);
598    if (dtx_enabled && !(vbr_enabled || abr_enabled || vad_enabled))
599    {
600       fprintf (stderr, "Warning: --dtx is useless without --vad, --vbr or --abr\n");
601    } else if ((vbr_enabled || abr_enabled) && (vad_enabled))
602    {
603       fprintf (stderr, "Warning: --vad is already implied by --vbr or --abr\n");
604    }
605
606    if (abr_enabled)
607    {
608       speex_encoder_ctl(st, SPEEX_SET_ABR, &abr_enabled);
609    }
610
611    speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
612    
613    if (denoise_enabled || agc_enabled)
614    {
615       preprocess = speex_preprocess_state_init(frame_size, rate);
616       speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DENOISE, &denoise_enabled);
617       speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC, &agc_enabled);
618       lookahead += frame_size;
619    }
620
621    /*Write header*/
622    {
623
624       op.packet = (unsigned char *)speex_header_to_packet(&header, (int*)&(op.bytes));
625       op.b_o_s = 1;
626       op.e_o_s = 0;
627       op.granulepos = 0;
628       op.packetno = 0;
629       ogg_stream_packetin(&os, &op);
630       free(op.packet);
631
632       op.packet = (unsigned char *)comments;
633       op.bytes = comments_length;
634       op.b_o_s = 0;
635       op.e_o_s = 0;
636       op.granulepos = 0;
637       op.packetno = 1;
638       ogg_stream_packetin(&os, &op);
639       
640       while((result = ogg_stream_flush(&os, &og)))
641       {
642          if(!result) break;
643          ret = oe_write_page(&og, fout);
644          if(ret != og.header_len + og.body_len)
645          {
646             fprintf (stderr,"Error: failed writing header to output stream\n");
647             exit(1);
648          }
649          else
650             bytes_written += ret;
651       }
652    }
653
654    free(comments);
655
656    speex_bits_init(&bits);
657
658    if (!wave_input)
659    {
660       nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL);
661    } else {
662       nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size);
663    }
664    if (nb_samples==0)
665       eos=1;
666    total_samples += nb_samples;
667    nb_encoded = -lookahead;
668    /*Main encoding loop (one frame per iteration)*/
669    while (!eos || total_samples>nb_encoded)
670    {
671       id++;
672       /*Encode current frame*/
673       if (chan==2)
674          speex_encode_stereo_int(input, frame_size, &bits);
675
676       if (preprocess)
677          speex_preprocess(preprocess, input, NULL);
678
679       speex_encode_int(st, input, &bits);
680       
681       nb_encoded += frame_size;
682       if (print_bitrate) {
683          int tmp;
684          char ch=13;
685          speex_encoder_ctl(st, SPEEX_GET_BITRATE, &tmp);
686          fputc (ch, stderr);
687          cumul_bits += tmp;
688          enc_frames += 1;
689          if (!quiet)
690          {
691             if (vad_enabled || vbr_enabled || abr_enabled)
692                fprintf (stderr, "Bitrate is use: %d bps  (average %d bps)   ", tmp, (int)(cumul_bits/enc_frames));
693             else
694                fprintf (stderr, "Bitrate is use: %d bps     ", tmp);
695          }
696          
697       }
698
699       if (wave_input)
700       {
701          nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size);
702       } else {
703          nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL);
704       }
705       if (nb_samples==0)
706       {
707          eos=1;
708       }
709       if (eos && total_samples<=nb_encoded)
710          op.e_o_s = 1;
711       else
712          op.e_o_s = 0;
713       total_samples += nb_samples;
714
715       if ((id+1)%nframes!=0)
716          continue;
717       speex_bits_insert_terminator(&bits);
718       nbBytes = speex_bits_write(&bits, cbits, MAX_FRAME_BYTES);
719       speex_bits_reset(&bits);
720       op.packet = (unsigned char *)cbits;
721       op.bytes = nbBytes;
722       op.b_o_s = 0;
723       /*Is this redundent?*/
724       if (eos && total_samples<=nb_encoded)
725          op.e_o_s = 1;
726       else
727          op.e_o_s = 0;
728       op.granulepos = (id+1)*frame_size-lookahead;
729       if (op.granulepos>total_samples)
730          op.granulepos = total_samples;
731       /*printf ("granulepos: %d %d %d %d %d %d\n", (int)op.granulepos, id, nframes, lookahead, 5, 6);*/
732       op.packetno = 2+id/nframes;
733       ogg_stream_packetin(&os, &op);
734
735       /*Write all new pages (most likely 0 or 1)*/
736       while (ogg_stream_pageout(&os,&og))
737       {
738          ret = oe_write_page(&og, fout);
739          if(ret != og.header_len + og.body_len)
740          {
741             fprintf (stderr,"Error: failed writing header to output stream\n");
742             exit(1);
743          }
744          else
745             bytes_written += ret;
746       }
747    }
748    if ((id+1)%nframes!=0)
749    {
750       while ((id+1)%nframes!=0)
751       {
752          id++;
753          speex_bits_pack(&bits, 15, 5);
754       }
755       nbBytes = speex_bits_write(&bits, cbits, MAX_FRAME_BYTES);
756       op.packet = (unsigned char *)cbits;
757       op.bytes = nbBytes;
758       op.b_o_s = 0;
759       op.e_o_s = 1;
760       op.granulepos = (id+1)*frame_size-lookahead;
761       if (op.granulepos>total_samples)
762          op.granulepos = total_samples;
763
764       op.packetno = 2+id/nframes;
765       ogg_stream_packetin(&os, &op);
766    }
767    /*Flush all pages left to be written*/
768    while (ogg_stream_flush(&os, &og))
769    {
770       ret = oe_write_page(&og, fout);
771       if(ret != og.header_len + og.body_len)
772       {
773          fprintf (stderr,"Error: failed writing header to output stream\n");
774          exit(1);
775       }
776       else
777          bytes_written += ret;
778    }
779    
780
781    speex_encoder_destroy(st);
782    speex_bits_destroy(&bits);
783    ogg_stream_clear(&os);
784
785    if (close_in)
786       fclose(fin);
787    if (close_out)
788       fclose(fout);
789    return 0;
790 }
791
792 /*                 
793  Comments will be stored in the Vorbis style.            
794  It is describled in the "Structure" section of
795     http://www.xiph.org/ogg/vorbis/doc/v-comment.html
796
797 The comment header is decoded as follows:
798   1) [vendor_length] = read an unsigned integer of 32 bits
799   2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
800   3) [user_comment_list_length] = read an unsigned integer of 32 bits
801   4) iterate [user_comment_list_length] times {
802      5) [length] = read an unsigned integer of 32 bits
803      6) this iteration's user comment = read a UTF-8 vector as [length] octets
804      }
805   7) [framing_bit] = read a single bit as boolean
806   8) if ( [framing_bit]  unset or end of packet ) then ERROR
807   9) done.
808
809   If you have troubles, please write to ymnk@jcraft.com.
810  */
811
812 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
813                            ((buf[base+2]<<16)&0xff0000)| \
814                            ((buf[base+1]<<8)&0xff00)| \
815                             (buf[base]&0xff))
816 #define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \
817                                      buf[base+2]=((val)>>16)&0xff; \
818                                      buf[base+1]=((val)>>8)&0xff; \
819                                      buf[base]=(val)&0xff; \
820                                  }while(0)
821
822 void comment_init(char **comments, int* length, char *vendor_string)
823 {
824   int vendor_length=strlen(vendor_string);
825   int user_comment_list_length=0;
826   int len=4+vendor_length+4;
827   char *p=(char*)malloc(len);
828   if(p==NULL){
829   }
830   writeint(p, 0, vendor_length);
831   memcpy(p+4, vendor_string, vendor_length);
832   writeint(p, 4+vendor_length, user_comment_list_length);
833   *length=len;
834   *comments=p;
835 }
836 void comment_add(char **comments, int* length, char *tag, char *val)
837 {
838   char* p=*comments;
839   int vendor_length=readint(p, 0);
840   int user_comment_list_length=readint(p, 4+vendor_length);
841   int tag_len=(tag?strlen(tag):0);
842   int val_len=strlen(val);
843   int len=(*length)+4+tag_len+val_len;
844
845   p=(char*)realloc(p, len);
846   if(p==NULL){
847   }
848
849   writeint(p, *length, tag_len+val_len);      /* length of comment */
850   if(tag) memcpy(p+*length+4, tag, tag_len);  /* comment */
851   memcpy(p+*length+4+tag_len, val, val_len);  /* comment */
852   writeint(p, 4+vendor_length, user_comment_list_length+1);
853
854   *comments=p;
855   *length=len;
856 }
857 #undef readint
858 #undef writeint