65d93116cba135c35cd377dfbf5c342cb99f1c88
[opus.git] / tools / celtenc.c
1 /* Copyright (c) 2002-2010 Jean-Marc Valin
2    Copyright (c) 2007-2010 Xiph.Org Foundation
3    Copyright (c) 2008-2010 Gregory Maxwell
4    File: celtenc.c
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9    
10    - Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12    
13    - Redistributions in binary form must reproduce the above copyright
14    notice, this list of conditions and the following disclaimer in the
15    documentation and/or other materials provided with the distribution.
16    
17    - Neither the name of the Xiph.org Foundation nor the names of its
18    contributors may be used to endorse or promote products derived from
19    this software without specific prior written permission.
20    
21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
25    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <stdio.h>
39 #if !defined WIN32 && !defined _WIN32
40 #include <unistd.h>
41 #endif
42
43 #ifdef HAVE_GETOPT_H
44 #include <getopt.h>
45 #endif
46
47 #ifndef HAVE_GETOPT_LONG
48 #include "getopt_win.h"
49 #endif
50
51 #include <stdlib.h>
52 #include <string.h>
53 #include <time.h>
54
55 #ifdef _MSC_VER
56 #define snprintf _snprintf
57 #endif
58
59 #include "celt.h"
60 #include "celt_header.h"
61 #include <ogg/ogg.h>
62 #include "wav_io.h"
63
64 #if defined WIN32 || defined _WIN32
65 /* We need the following two to set stdout to binary */
66 #include <io.h>
67 #include <fcntl.h>
68 #endif
69
70 #include "skeleton.h"
71
72
73 void comment_init(char **comments, int* length, char *vendor_string);
74 void comment_add(char **comments, int* length, char *tag, char *val);
75
76
77 /*Write an Ogg page to a file pointer*/
78 int oe_write_page(ogg_page *page, FILE *fp)
79 {
80    int written;
81    written = fwrite(page->header,1,page->header_len, fp);
82    written += fwrite(page->body,1,page->body_len, fp);
83    
84    return written;
85 }
86
87 #define MAX_FRAME_SIZE 2048
88 #define MAX_FRAME_BYTES 1275
89 #define IMIN(a,b) ((a) < (b) ? (a) : (b))   /**< Minimum int value.   */
90 #define IMAX(a,b) ((a) > (b) ? (a) : (b))   /**< Maximum int value.   */
91
92 /* Convert input audio bits, endians and channels */
93 static int read_samples(FILE *fin,int frame_size, int bits, int channels, int lsb, short * input, char *buff, celt_int32 *size)
94 {   
95    unsigned char in[MAX_FRAME_SIZE*2];
96    int i;
97    short *s;
98    int nb_read;
99
100    if (size && *size<=0)
101    {
102       return 0;
103    }
104    /*Read input audio*/
105    if (size)
106       *size -= bits/8*channels*frame_size;
107    if (buff)
108    {
109       for (i=0;i<12;i++)
110          in[i]=buff[i];
111       nb_read = fread(in+12,1,bits/8*channels*frame_size-12, fin) + 12;
112       if (size)
113          *size += 12;
114    } else {
115       nb_read = fread(in,1,bits/8*channels* frame_size, fin);
116    }
117    nb_read /= bits/8*channels;
118
119    /*fprintf (stderr, "%d\n", nb_read);*/
120    if (nb_read==0)
121       return 0;
122
123    s=(short*)in;
124    if(bits==8)
125    {
126       /* Convert 8->16 bits */
127       for(i=frame_size*channels-1;i>=0;i--)
128       {
129          s[i]=(in[i]<<8)^0x8000;
130       }
131    } else
132    {
133       /* convert to our endian format */
134       for(i=0;i<frame_size*channels;i++)
135       {
136          if(lsb) 
137             s[i]=le_short(s[i]); 
138          else
139             s[i]=be_short(s[i]);
140       }
141    }
142
143    /* FIXME: This is probably redundent now */
144    /* copy to float input buffer */
145    for (i=0;i<frame_size*channels;i++)
146    {
147       input[i]=(short)s[i];
148    }
149
150    for (i=nb_read*channels;i<frame_size*channels;i++)
151    {
152       input[i]=0;
153    }
154
155
156    return nb_read;
157 }
158
159 void add_fishead_packet (ogg_stream_state *os) {
160
161    fishead_packet fp;
162
163    memset(&fp, 0, sizeof(fp));
164    fp.ptime_n = 0;
165    fp.ptime_d = 1000;
166    fp.btime_n = 0;
167    fp.btime_d = 1000;
168
169    add_fishead_to_stream(os, &fp);
170 }
171
172 /*
173  * Adds the fishead packets in the skeleton output stream along with the e_o_s packet
174  */
175 void add_fisbone_packet (ogg_stream_state *os, celt_int32 serialno, CELTHeader *header) {
176
177    fisbone_packet fp;
178
179    memset(&fp, 0, sizeof(fp));
180    fp.serial_no = serialno;
181    fp.nr_header_packet = 2 + header->extra_headers;
182    fp.granule_rate_n = header->sample_rate;
183    fp.granule_rate_d = 1;
184    fp.start_granule = 0;
185    fp.preroll = 3;
186    fp.granule_shift = 0;
187
188    add_message_header_field(&fp, "Content-Type", "audio/x-celt");
189
190    add_fisbone_to_stream(os, &fp);
191 }
192
193 void version(void)
194 {
195    printf ("celtenc (CELT %s encoder)\n",CELT_VERSION);
196    printf ("Copyright (C) 2008-2010 Xiph.Org Foundation (written by Jean-Marc Valin)\n");
197 }
198
199 void version_short(void)
200 {
201    printf ("celtenc (CELT %s encoder)\n",CELT_VERSION);
202    printf ("Copyright (C) 2008-2010 Xiph.Org Foundation (written by Jean-Marc Valin)\n");
203 }
204
205 void usage(void)
206 {
207    printf ("Usage: celtenc [options] input_file output_file.oga\n");
208    printf ("\n");
209    printf ("Encodes input_file using CELT. It can read the WAV or raw files.\n");
210    printf ("\n");
211    printf ("input_file can be:\n");
212    printf ("  filename.wav      wav file\n");
213    printf ("  filename.*        Raw PCM file (any extension other than .wav)\n");
214    printf ("  -                 stdin\n");
215    printf ("\n");  
216    printf ("output_file can be:\n");
217    printf ("  filename.oga      compressed file\n");
218    printf ("  -                 stdout\n");
219    printf ("\n");  
220    printf ("Options:\n");
221    printf (" --bitrate n        Encoding bit-rate in kbit/sec\n"); 
222    printf (" --cbr              Use constant bitrate encoding\n");
223    printf (" --comp n           Encoding complexity (0-10)\n");
224    printf (" --framesize n      Frame size (Default: 960)\n");
225    printf (" --noltp            Do not use long-term prediction\n");
226    printf (" --independent      Encode frames independently (implies noltp)\n");
227    printf (" --skeleton         Outputs ogg skeleton metadata (may cause incompatibilities)\n");
228    printf (" --comment          Add the given string as an extra comment. This may be\n");
229    printf ("                     used multiple times\n");
230    printf (" --author           Author of this track\n");
231    printf (" --title            Title for this track\n");
232    printf (" -h, --help         This help\n"); 
233    printf (" -v, --version      Version information\n"); 
234    printf (" -V                 Verbose mode (show bit-rate)\n"); 
235    printf ("Raw input options:\n");
236    printf (" --rate n           Sampling rate for raw input\n"); 
237    printf (" --mono             Consider raw input as mono\n"); 
238    printf (" --stereo           Consider raw input as stereo\n"); 
239    printf (" --le               Raw input is little-endian\n"); 
240    printf (" --be               Raw input is big-endian\n"); 
241    printf (" --8bit             Raw input is 8-bit unsigned\n"); 
242    printf (" --16bit            Raw input is 16-bit signed\n"); 
243    printf ("Default raw PCM input is 48kHz, 16-bit, little-endian, stereo\n");
244 }
245
246
247 int main(int argc, char **argv)
248 {
249    int nb_samples, total_samples=0, nb_encoded;
250    int c;
251    int option_index = 0;
252    char *inFile, *outFile;
253    FILE *fin, *fout;
254    short input[MAX_FRAME_SIZE];
255    celt_int32 frame_size = 960;
256    int quiet=0;
257    int nbBytes;
258    CELTMode *mode;
259    void *st;
260    unsigned char bits[MAX_FRAME_BYTES];
261    int with_cbr = 0;
262    int with_cvbr = 0;
263    int with_skeleton = 0;
264    int total_bytes = 0;
265    int peak_bytes = 0;
266    struct option long_options[] =
267    {
268       {"bitrate", required_argument, NULL, 0},
269       {"cbr",no_argument,NULL, 0},
270       {"cvbr",no_argument,NULL, 0},
271       {"comp", required_argument, NULL, 0},
272       {"noltp", no_argument, NULL, 0},
273       {"independent", no_argument, NULL, 0},
274       {"framesize", required_argument, NULL, 0},
275       {"skeleton",no_argument,NULL, 0},
276       {"help", no_argument, NULL, 0},
277       {"quiet", no_argument, NULL, 0},
278       {"le", no_argument, NULL, 0},
279       {"be", no_argument, NULL, 0},
280       {"8bit", no_argument, NULL, 0},
281       {"16bit", no_argument, NULL, 0},
282       {"mono", no_argument, NULL, 0},
283       {"stereo", no_argument, NULL, 0},
284       {"rate", required_argument, NULL, 0},
285       {"version", no_argument, NULL, 0},
286       {"version-short", no_argument, NULL, 0},
287       {"comment", required_argument, NULL, 0},
288       {"author", required_argument, NULL, 0},
289       {"title", required_argument, NULL, 0},
290       {0, 0, 0, 0}
291    };
292    int print_bitrate=0;
293    celt_int32 rate=48000;
294    celt_int32 size;
295    int chan=1;
296    int fmt=16;
297    int lsb=1;
298    ogg_stream_state os;
299    ogg_stream_state so; /* ogg stream for skeleton bitstream */
300    ogg_page              og;
301    ogg_packet            op;
302    int bytes_written=0, ret, result;
303    int id=-1;
304    CELTHeader header;
305    char vendor_string[64];
306    char *comments;
307    int comments_length;
308    int close_in=0, close_out=0;
309    int eos=0;
310    float bitrate=-1;
311    char first_bytes[12];
312    int wave_input=0;
313    celt_int32 lookahead = 0;
314    int bytes_per_packet=-1;
315    int complexity=-127;
316    int prediction=2; 
317    int bitstream;
318
319
320    /*Process command-line options*/
321    while(1)
322    {
323       c = getopt_long (argc, argv, "hvV",
324                        long_options, &option_index);
325       if (c==-1)
326          break;
327       
328       switch(c)
329       {
330       case 0:
331          if (strcmp(long_options[option_index].name,"bitrate")==0)
332          {
333             bitrate = atof (optarg);
334          } else if (strcmp(long_options[option_index].name,"cbr")==0)
335          {
336             with_cbr=1;
337          } else if (strcmp(long_options[option_index].name,"cvbr")==0)
338          {
339             with_cvbr=1;
340          } else if (strcmp(long_options[option_index].name,"skeleton")==0)
341          {
342             with_skeleton=1;
343          } else if (strcmp(long_options[option_index].name,"help")==0)
344          {
345             usage();
346             exit(0);
347          } else if (strcmp(long_options[option_index].name,"quiet")==0)
348          {
349             quiet = 1;
350          } else if (strcmp(long_options[option_index].name,"version")==0)
351          {
352             version();
353             exit(0);
354          } else if (strcmp(long_options[option_index].name,"version-short")==0)
355          {
356             version_short();
357             exit(0);
358          } else if (strcmp(long_options[option_index].name,"le")==0)
359          {
360             lsb=1;
361          } else if (strcmp(long_options[option_index].name,"be")==0)
362          {
363             lsb=0;
364          } else if (strcmp(long_options[option_index].name,"8bit")==0)
365          {
366             fmt=8;
367          } else if (strcmp(long_options[option_index].name,"16bit")==0)
368          {
369             fmt=16;
370          } else if (strcmp(long_options[option_index].name,"stereo")==0)
371          {
372             chan=2;
373          } else if (strcmp(long_options[option_index].name,"mono")==0)
374          {
375             chan=1;
376          } else if (strcmp(long_options[option_index].name,"rate")==0)
377          {
378             rate=atoi (optarg);
379          } else if (strcmp(long_options[option_index].name,"comp")==0)
380          {
381             complexity=atoi (optarg);
382          } else if (strcmp(long_options[option_index].name,"framesize")==0)
383          {
384             frame_size=atoi (optarg);
385          } else if (strcmp(long_options[option_index].name,"noltp")==0)
386          {
387             if (prediction>1)
388               prediction=1;
389          } else if (strcmp(long_options[option_index].name,"independent")==0)
390          {
391               prediction=0;
392          } else if (strcmp(long_options[option_index].name,"comment")==0)
393          {
394            if (!strchr(optarg, '='))
395            {
396              fprintf (stderr, "Invalid comment: %s\n", optarg);
397              fprintf (stderr, "Comments must be of the form name=value\n");
398              exit(1);
399            }
400            comment_add(&comments, &comments_length, NULL, optarg); 
401          } else if (strcmp(long_options[option_index].name,"author")==0)
402          {
403            comment_add(&comments, &comments_length, "author=", optarg); 
404          } else if (strcmp(long_options[option_index].name,"title")==0)
405          {
406            comment_add(&comments, &comments_length, "title=", optarg); 
407          }
408
409          break;
410       case 'h':
411          usage();
412          exit(0);
413          break;
414       case 'v':
415          version();
416          exit(0);
417          break;
418       case 'V':
419          print_bitrate=1;
420          break;
421       case '?':
422          usage();
423          exit(1);
424          break;
425       }
426    }
427    if (argc-optind!=2)
428    {
429       usage();
430       exit(1);
431    }
432    inFile=argv[optind];
433    outFile=argv[optind+1];
434
435    /*Initialize Ogg stream struct*/
436    srand(time(NULL));
437    if (ogg_stream_init(&os, rand())==-1)
438    {
439       fprintf(stderr,"Error: stream init failed\n");
440       exit(1);
441    }
442    if (with_skeleton && ogg_stream_init(&so, rand())==-1)
443    {
444       fprintf(stderr,"Error: stream init failed\n");
445       exit(1);
446    }
447
448    if (strcmp(inFile, "-")==0)
449    {
450 #if defined WIN32 || defined _WIN32
451          _setmode(_fileno(stdin), _O_BINARY);
452 #elif defined OS2
453          _fsetmode(stdin,"b");
454 #endif
455       fin=stdin;
456    }
457    else 
458    {
459       fin = fopen(inFile, "rb");
460       if (!fin)
461       {
462          perror(inFile);
463          exit(1);
464       }
465       close_in=1;
466    }
467
468    {
469       fread(first_bytes, 1, 12, fin);
470       if (strncmp(first_bytes,"RIFF",4)==0 && strncmp(first_bytes,"RIFF",4)==0)
471       {
472          if (read_wav_header(fin, &rate, &chan, &fmt, &size)==-1)
473             exit(1);
474          wave_input=1;
475          lsb=1; /* CHECK: exists big-endian .wav ?? */
476       }
477    }
478
479    if (bitrate<=0.005)
480      if (chan==1)
481        bitrate=64.0;
482      else
483        bitrate=128.0;
484      
485    bytes_per_packet = (bitrate*1000*frame_size/rate+4)/8;
486    
487    if (bytes_per_packet > MAX_FRAME_BYTES) {
488       bytes_per_packet=MAX_FRAME_BYTES;
489       fprintf (stderr, "Warning: Requested bitrate (%0.3fkbit/sec) is too high. Setting CELT to %d bytes/frame.\n",bitrate,MAX_FRAME_BYTES);      
490    }
491
492    if (with_cbr)
493    {
494      bitrate = ((rate/(float)frame_size)*8*bytes_per_packet)/1000.0;
495    } else {
496      /*In VBR mode the bytes_per_packet argument becomes a hard maximum. 3x the average rate is just a random choice.*/
497      bytes_per_packet=IMIN(bytes_per_packet*3,MAX_FRAME_BYTES);
498    }
499    
500    mode = celt_mode_create(rate, frame_size, NULL);
501    if (!mode)
502       return 1;
503
504   celt_mode_info(mode,CELT_GET_BITSTREAM_VERSION,&bitstream);      
505
506    snprintf(vendor_string, sizeof(vendor_string), "Encoded with CELT %s (bitstream: %d)\n",CELT_VERSION,bitstream);
507    comment_init(&comments, &comments_length, vendor_string);
508
509    /*celt_mode_info(mode, CELT_GET_FRAME_SIZE, &frame_size);*/
510    
511    celt_header_init(&header, mode, chan);
512    header.nb_channels = chan;
513
514    {
515       char *st_string="mono";
516       if (chan==2)
517          st_string="stereo";
518       if (!quiet)
519          if (with_cbr)
520            fprintf (stderr, "Encoding %.0f kHz %s audio in %.0fms packets at %0.3fkbit/sec (%d bytes per packet, CBR) with bitstream version %d\n",
521                header.sample_rate/1000., st_string, frame_size/(float)header.sample_rate*1000., bitrate, bytes_per_packet,bitstream);
522          else      
523            fprintf (stderr, "Encoding %.0f kHz %s audio in %.0fms packets at %0.3fkbit/sec (%d bytes per packet maximum) with bitstream version %d\n",
524                header.sample_rate/1000., st_string, frame_size/(float)header.sample_rate*1000., bitrate, bytes_per_packet,bitstream);
525    }
526
527    /*Initialize CELT encoder*/
528    st = celt_encoder_create(mode, chan, NULL);
529
530    if (!with_cbr)
531    {
532      int tmp = (bitrate*1000);
533      if (celt_encoder_ctl(st, CELT_SET_VBR_RATE(tmp)) != CELT_OK)
534      {
535         fprintf (stderr, "VBR request failed\n");
536         return 1;
537      }
538      if (!with_cvbr)
539      {
540         if (celt_encoder_ctl(st, CELT_SET_VBR_CONSTRAINT(0)) != CELT_OK)
541         {
542            fprintf (stderr, "VBR constraint failed\n");
543            return 1;
544         }
545      }
546    }
547
548    if (celt_encoder_ctl(st, CELT_SET_PREDICTION(prediction)) != CELT_OK)
549    {
550       fprintf (stderr, "Prediction request failed\n");
551       return 1;
552    }
553
554    if (complexity!=-127) {
555      if (celt_encoder_ctl(st, CELT_SET_COMPLEXITY(complexity)) != CELT_OK)
556      {
557         fprintf (stderr, "Only complexity 0 through 10 is supported\n");
558         return 1;
559      }
560    }
561
562    if (strcmp(outFile,"-")==0)
563    {
564 #if defined WIN32 || defined _WIN32
565       _setmode(_fileno(stdout), _O_BINARY);
566 #endif
567       fout=stdout;
568    }
569    else 
570    {
571       fout = fopen(outFile, "wb");
572       if (!fout)
573       {
574          perror(outFile);
575          exit(1);
576       }
577       close_out=1;
578    }
579
580    if (with_skeleton) {
581       fprintf (stderr, "Warning: Enabling skeleton output may cause some decoders to fail.\n");
582    }
583
584    /* first packet should be the skeleton header. */
585    if (with_skeleton) {
586       add_fishead_packet(&so);
587       if ((ret = flush_ogg_stream_to_file(&so, fout))) {
588          fprintf (stderr,"Error: failed skeleton (fishead) header to output stream\n");
589          exit(1);
590       } else
591          bytes_written += ret;
592    }
593
594    /*Write header*/
595    {
596       unsigned char header_data[100];
597       int packet_size = celt_header_to_packet(&header, header_data, 100);
598       op.packet = header_data;
599       op.bytes = packet_size;
600       op.b_o_s = 1;
601       op.e_o_s = 0;
602       op.granulepos = 0;
603       op.packetno = 0;
604       ogg_stream_packetin(&os, &op);
605
606       while((result = ogg_stream_flush(&os, &og)))
607       {
608          if(!result) break;
609          ret = oe_write_page(&og, fout);
610          if(ret != og.header_len + og.body_len)
611          {
612             fprintf (stderr,"Error: failed writing header to output stream\n");
613             exit(1);
614          }
615          else
616             bytes_written += ret;
617       }
618
619       op.packet = (unsigned char *)comments;
620       op.bytes = comments_length;
621       op.b_o_s = 0;
622       op.e_o_s = 0;
623       op.granulepos = 0;
624       op.packetno = 1;
625       ogg_stream_packetin(&os, &op);
626    }
627
628    /* fisbone packet should be write after all bos pages */
629    if (with_skeleton) {
630       add_fisbone_packet(&so, os.serialno, &header);
631       if ((ret = flush_ogg_stream_to_file(&so, fout))) {
632          fprintf (stderr,"Error: failed writing skeleton (fisbone )header to output stream\n");
633          exit(1);
634       } else
635          bytes_written += ret;
636    }
637
638    /* writing the rest of the celt header packets */
639    while((result = ogg_stream_flush(&os, &og)))
640    {
641       if(!result) break;
642       ret = oe_write_page(&og, fout);
643       if(ret != og.header_len + og.body_len)
644       {
645          fprintf (stderr,"Error: failed writing header to output stream\n");
646          exit(1);
647       }
648       else
649          bytes_written += ret;
650    }
651
652    free(comments);
653
654    /* write the skeleton eos packet */
655    if (with_skeleton) {
656       add_eos_packet_to_stream(&so);
657       if ((ret = flush_ogg_stream_to_file(&so, fout))) {
658          fprintf (stderr,"Error: failed writing skeleton header to output stream\n");
659          exit(1);
660       } else
661          bytes_written += ret;
662    }
663
664
665    if (!wave_input)
666    {
667       nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, first_bytes, NULL);
668    } else {
669       nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size);
670    }
671    if (nb_samples==0)
672       eos=1;
673    total_samples += nb_samples;
674    nb_encoded = -lookahead;
675    /*Main encoding loop (one frame per iteration)*/
676    while (!eos || total_samples>nb_encoded)
677    {
678       id++;
679       /*Encode current frame*/
680
681       nbBytes = celt_encode(st, input, frame_size, bits, bytes_per_packet);
682       if (nbBytes<0)
683       {
684          fprintf(stderr, "Got error %d while encoding. Aborting.\n", nbBytes);
685          break;
686       }
687       nb_encoded += frame_size;
688       total_bytes += nbBytes;
689       peak_bytes=IMAX(nbBytes,peak_bytes);
690
691       if (wave_input)
692       {
693          nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, &size);
694       } else {
695          nb_samples = read_samples(fin,frame_size,fmt,chan,lsb,input, NULL, NULL);
696       }
697       if (nb_samples==0)
698       {
699          eos=1;
700       }
701       if (eos && total_samples<=nb_encoded)
702          op.e_o_s = 1;
703       else
704          op.e_o_s = 0;
705       total_samples += nb_samples;
706
707       op.packet = (unsigned char *)bits;
708       op.bytes = nbBytes;
709       op.b_o_s = 0;
710       /*Is this redundent?*/
711       if (eos && total_samples<=nb_encoded)
712          op.e_o_s = 1;
713       else
714          op.e_o_s = 0;
715       op.granulepos = (id+1)*frame_size-lookahead;
716       if (op.granulepos>total_samples)
717          op.granulepos = total_samples;
718       /*printf ("granulepos: %d %d %d %d %d %d\n", (int)op.granulepos, id, nframes, lookahead, 5, 6);*/
719       op.packetno = 2+id;
720       ogg_stream_packetin(&os, &op);
721
722       /*Write all new pages (most likely 0 or 1)*/
723       while (ogg_stream_pageout(&os,&og))
724       {
725          ret = oe_write_page(&og, fout);
726          if(ret != og.header_len + og.body_len)
727          {
728             fprintf (stderr,"Error: failed writing header to output stream\n");
729             exit(1);
730          }
731          else
732             bytes_written += ret;
733       }
734    }
735    /*Flush all pages left to be written*/
736    while (ogg_stream_flush(&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 (!with_cbr && !quiet)
749      fprintf (stderr, "Average rate %0.3fkbit/sec, %d peak bytes per packet\n", (total_bytes*8.0/((float)nb_encoded/header.sample_rate))/1000.0, peak_bytes);
750
751    celt_encoder_destroy(st);
752    celt_mode_destroy(mode);
753    ogg_stream_clear(&os);
754
755    if (close_in)
756       fclose(fin);
757    if (close_out)
758       fclose(fout);
759    return 0;
760 }
761
762 /*                 
763  Comments will be stored in the Vorbis style.            
764  It is describled in the "Structure" section of
765     http://www.xiph.org/ogg/vorbis/doc/v-comment.html
766
767 The comment header is decoded as follows:
768   1) [vendor_length] = read an unsigned integer of 32 bits
769   2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
770   3) [user_comment_list_length] = read an unsigned integer of 32 bits
771   4) iterate [user_comment_list_length] times {
772      5) [length] = read an unsigned integer of 32 bits
773      6) this iteration's user comment = read a UTF-8 vector as [length] octets
774      }
775   7) [framing_bit] = read a single bit as boolean
776   8) if ( [framing_bit]  unset or end of packet ) then ERROR
777   9) done.
778
779   If you have troubles, please write to ymnk@jcraft.com.
780  */
781
782 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
783                            ((buf[base+2]<<16)&0xff0000)| \
784                            ((buf[base+1]<<8)&0xff00)| \
785                             (buf[base]&0xff))
786 #define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \
787                                      buf[base+2]=((val)>>16)&0xff; \
788                                      buf[base+1]=((val)>>8)&0xff; \
789                                      buf[base]=(val)&0xff; \
790                                  }while(0)
791
792 void comment_init(char **comments, int* length, char *vendor_string)
793 {
794   int vendor_length=strlen(vendor_string);
795   int user_comment_list_length=0;
796   int len=4+vendor_length+4;
797   char *p=(char*)malloc(len);
798   if(p==NULL){
799      fprintf (stderr, "malloc failed in comment_init()\n");
800      exit(1);
801   }
802   writeint(p, 0, vendor_length);
803   memcpy(p+4, vendor_string, vendor_length);
804   writeint(p, 4+vendor_length, user_comment_list_length);
805   *length=len;
806   *comments=p;
807 }
808 void comment_add(char **comments, int* length, char *tag, char *val)
809 {
810   char* p=*comments;
811   int vendor_length=readint(p, 0);
812   int user_comment_list_length=readint(p, 4+vendor_length);
813   int tag_len=(tag?strlen(tag):0);
814   int val_len=strlen(val);
815   int len=(*length)+4+tag_len+val_len;
816
817   p=(char*)realloc(p, len);
818   if(p==NULL){
819      fprintf (stderr, "realloc failed in comment_add()\n");
820      exit(1);
821   }
822
823   writeint(p, *length, tag_len+val_len);      /* length of comment */
824   if(tag) memcpy(p+*length+4, tag, tag_len);  /* comment */
825   memcpy(p+*length+4+tag_len, val, val_len);  /* comment */
826   writeint(p, 4+vendor_length, user_comment_list_length+1);
827
828   *comments=p;
829   *length=len;
830 }
831 #undef readint
832 #undef writeint