couple fixes to Ogg encoder/decoder
[opus.git] / tools / celtdec.c
1 /* Copyright (C) 2008 Jean-Marc Valin, CSIRO
2    File: celtdec.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 #endif
40 #ifdef HAVE_GETOPT_H
41 #include <getopt.h>
42 #endif
43 #ifndef HAVE_GETOPT_LONG
44 #include "getopt_win.h"
45 #endif
46 #include <stdlib.h>
47 #include <string.h>
48
49 #include <celt.h>
50 #include <ogg/ogg.h>
51
52 #if defined WIN32 || defined _WIN32
53 #include "wave_out.h"
54 /* We need the following two to set stdout to binary */
55 #include <io.h>
56 #include <fcntl.h>
57 #endif
58 #include <math.h>
59
60 #ifdef __MINGW32__
61 #include "wave_out.c"
62 #endif
63
64 #ifdef HAVE_SYS_SOUNDCARD_H
65 #include <sys/soundcard.h>
66 #include <sys/types.h>
67 #include <sys/stat.h>
68 #include <fcntl.h>
69 #include <sys/ioctl.h>
70
71 #elif defined HAVE_SYS_AUDIOIO_H
72 #include <sys/types.h>
73 #include <fcntl.h>
74 #include <sys/ioctl.h>
75 #include <sys/audioio.h>
76 #ifndef AUDIO_ENCODING_SLINEAR
77 #define AUDIO_ENCODING_SLINEAR AUDIO_ENCODING_LINEAR /* Solaris */
78 #endif
79
80 #endif
81
82 #include <string.h>
83 #include "wav_io.h"
84 #include <celt_header.h>
85
86 #define MAX_FRAME_SIZE 2000
87
88 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
89                            ((buf[base+2]<<16)&0xff0000)| \
90                            ((buf[base+1]<<8)&0xff00)| \
91                             (buf[base]&0xff))
92
93 static void print_comments(char *comments, int length)
94 {
95    char *c=comments;
96    int len, i, nb_fields;
97    char *end;
98    
99    if (length<8)
100    {
101       fprintf (stderr, "Invalid/corrupted comments\n");
102       return;
103    }
104    end = c+length;
105    len=readint(c, 0);
106    c+=4;
107    if (c+len>end)
108    {
109       fprintf (stderr, "Invalid/corrupted comments\n");
110       return;
111    }
112    fwrite(c, 1, len, stderr);
113    c+=len;
114    fprintf (stderr, "\n");
115    if (c+4>end)
116    {
117       fprintf (stderr, "Invalid/corrupted comments\n");
118       return;
119    }
120    nb_fields=readint(c, 0);
121    c+=4;
122    for (i=0;i<nb_fields;i++)
123    {
124       if (c+4>end)
125       {
126          fprintf (stderr, "Invalid/corrupted comments\n");
127          return;
128       }
129       len=readint(c, 0);
130       c+=4;
131       if (c+len>end)
132       {
133          fprintf (stderr, "Invalid/corrupted comments\n");
134          return;
135       }
136       fwrite(c, 1, len, stderr);
137       c+=len;
138       fprintf (stderr, "\n");
139    }
140 }
141
142 FILE *out_file_open(char *outFile, int rate, int *channels)
143 {
144    FILE *fout=NULL;
145    /*Open output file*/
146    if (strlen(outFile)==0)
147    {
148 #if defined HAVE_SYS_SOUNDCARD_H
149       int audio_fd, format, stereo;
150       audio_fd=open("/dev/dsp", O_WRONLY);
151       if (audio_fd<0)
152       {
153          perror("Cannot open /dev/dsp");
154          exit(1);         
155       }
156
157       format=AFMT_S16_NE;
158       if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format)==-1)
159       {
160          perror("SNDCTL_DSP_SETFMT");
161          close(audio_fd);
162          exit(1);
163       }
164
165       stereo=0;
166       if (*channels==2)
167          stereo=1;
168       if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo)==-1)
169       {
170          perror("SNDCTL_DSP_STEREO");
171          close(audio_fd);
172          exit(1);
173       }
174       if (stereo!=0)
175       {
176          if (*channels==1)
177             fprintf (stderr, "Cannot set mono mode, will decode in stereo\n");
178          *channels=2;
179       }
180
181       if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate)==-1)
182       {
183          perror("SNDCTL_DSP_SPEED");
184          close(audio_fd);
185          exit(1);
186       }
187       fout = fdopen(audio_fd, "w");
188 #elif defined HAVE_SYS_AUDIOIO_H
189       audio_info_t info;
190       int audio_fd;
191       
192       audio_fd = open("/dev/audio", O_WRONLY);
193       if (audio_fd<0)
194       {
195          perror("Cannot open /dev/audio");
196          exit(1);
197       }
198
199       AUDIO_INITINFO(&info);
200 #ifdef AUMODE_PLAY    /* NetBSD/OpenBSD */
201       info.mode = AUMODE_PLAY;
202 #endif
203       info.play.encoding = AUDIO_ENCODING_SLINEAR;
204       info.play.precision = 16;
205       info.play.sample_rate = rate;
206       info.play.channels = *channels;
207       
208       if (ioctl(audio_fd, AUDIO_SETINFO, &info) < 0)
209       {
210          perror ("AUDIO_SETINFO");
211          exit(1);
212       }
213       fout = fdopen(audio_fd, "w");
214 #elif defined WIN32 || defined _WIN32
215       {
216          unsigned int celt_channels = *channels;
217          if (Set_WIN_Params (INVALID_FILEDESC, rate, SAMPLE_SIZE, celt_channels))
218          {
219             fprintf (stderr, "Can't access %s\n", "WAVE OUT");
220             exit(1);
221          }
222       }
223 #else
224       fprintf (stderr, "No soundcard support\n");
225       exit(1);
226 #endif
227    } else {
228       if (strcmp(outFile,"-")==0)
229       {
230 #if defined WIN32 || defined _WIN32
231          _setmode(_fileno(stdout), _O_BINARY);
232 #endif
233          fout=stdout;
234       }
235       else 
236       {
237          fout = fopen(outFile, "wb");
238          if (!fout)
239          {
240             perror(outFile);
241             exit(1);
242          }
243          if (strcmp(outFile+strlen(outFile)-4,".wav")==0 || strcmp(outFile+strlen(outFile)-4,".WAV")==0)
244             write_wav_header(fout, rate, *channels, 0, 0);
245       }
246    }
247    return fout;
248 }
249
250 void usage()
251 {
252    printf ("Usage: celtdec [options] input_file.spx [output_file]\n");
253    printf ("\n");
254    printf ("Decodes a CELT file and produce a WAV file or raw file\n");
255    printf ("\n");
256    printf ("input_file can be:\n");
257    printf ("  filename.oga         regular CELT file\n");
258    printf ("  -                    stdin\n");
259    printf ("\n");  
260    printf ("output_file can be:\n");
261    printf ("  filename.wav         Wav file\n");
262    printf ("  filename.*           Raw PCM file (any extension other that .wav)\n");
263    printf ("  -                    stdout\n");
264    printf ("  (nothing)            Will be played to soundcard\n");
265    printf ("\n");  
266    printf ("Options:\n");
267    printf (" --mono                Force decoding in mono\n");
268    printf (" --stereo              Force decoding in stereo\n");
269    printf (" --rate n              Force decoding at sampling rate n Hz\n");
270    printf (" --packet-loss n       Simulate n %% random packet loss\n");
271    printf (" -V                    Verbose mode (show bit-rate)\n"); 
272    printf (" -h, --help            This help\n");
273    printf (" -v, --version         Version information\n");
274    printf ("\n");
275 }
276
277 void version()
278 {
279    printf ("celtenc (CELT encoder)\n");
280    printf ("Copyright (C) 2008 Jean-Marc Valin\n");
281 }
282
283 void version_short()
284 {
285    printf ("celtenc (CELT encoder)\n");
286    printf ("Copyright (C) 2008 Jean-Marc Valin\n");
287 }
288
289 static CELTDecoder *process_header(ogg_packet *op, celt_int32_t enh_enabled, celt_int32_t *frame_size, int *granule_frame_size, celt_int32_t *rate, int *nframes, int forceMode, int *channels, int *extra_headers, int quiet)
290 {
291    CELTDecoder *st;
292    const CELTMode *mode;
293    CELTHeader header;
294    int modeID;
295       
296    celt_header_from_packet((char*)op->packet, op->bytes, &header);
297       
298    if (header.mode==0)
299       mode = celt_mono;
300    else if (header.mode==1)
301       mode = celt_stereo;
302    else
303    {
304       fprintf (stderr, "Invalid mode: %d\n", header.mode);
305       return NULL;
306    }
307
308    st = celt_decoder_new(mode);
309    if (!st)
310    {
311       fprintf (stderr, "Decoder initialization failed.\n");
312       return NULL;
313    }
314    
315    celt_mode_info(mode, CELT_GET_FRAME_SIZE, frame_size);
316    *granule_frame_size = *frame_size;
317
318    if (!*rate)
319       *rate = header.sample_rate;
320    /* Adjust rate if --force-* options are used */
321
322    *nframes = 1;
323
324    if (*channels==-1)
325       *channels = header.nb_channels;
326    
327    if (!quiet)
328    {
329       fprintf (stderr, "Decoding %d Hz audio in", *rate);
330
331       if (*channels==1)
332          fprintf (stderr, " (mono");
333       else
334          fprintf (stderr, " (stereo");
335       fprintf(stderr, ")\n");
336    }
337
338    *extra_headers = header.extra_headers;
339
340    return st;
341 }
342
343 int main(int argc, char **argv)
344 {
345    int c;
346    int option_index = 0;
347    char *inFile, *outFile;
348    FILE *fin, *fout=NULL;
349    short out[MAX_FRAME_SIZE];
350    short output[MAX_FRAME_SIZE];
351    int frame_size=0, granule_frame_size=0;
352    void *st=NULL;
353    unsigned char bits[1000];
354    int packet_count=0;
355    int stream_init = 0;
356    int quiet = 0;
357    ogg_int64_t page_granule=0, last_granule=0;
358    int skip_samples=0, page_nb_packets;
359    struct option long_options[] =
360    {
361       {"help", no_argument, NULL, 0},
362       {"quiet", no_argument, NULL, 0},
363       {"version", no_argument, NULL, 0},
364       {"version-short", no_argument, NULL, 0},
365       {"rate", required_argument, NULL, 0},
366       {"mono", no_argument, NULL, 0},
367       {"stereo", no_argument, NULL, 0},
368       {"packet-loss", required_argument, NULL, 0},
369       {0, 0, 0, 0}
370    };
371    ogg_sync_state oy;
372    ogg_page       og;
373    ogg_packet     op;
374    ogg_stream_state os;
375    int enh_enabled;
376    int nframes=2;
377    int print_bitrate=0;
378    int close_in=0;
379    int eos=0;
380    int forceMode=-1;
381    int audio_size=0;
382    float loss_percent=-1;
383    int channels=-1;
384    int rate=0;
385    int extra_headers=0;
386    int wav_format=0;
387    int lookahead;
388    int celt_serialno = -1;
389
390    enh_enabled = 1;
391
392    /*Process options*/
393    while(1)
394    {
395       c = getopt_long (argc, argv, "hvV",
396                        long_options, &option_index);
397       if (c==-1)
398          break;
399       
400       switch(c)
401       {
402       case 0:
403          if (strcmp(long_options[option_index].name,"help")==0)
404          {
405             usage();
406             exit(0);
407          } else if (strcmp(long_options[option_index].name,"quiet")==0)
408          {
409             quiet = 1;
410          } else if (strcmp(long_options[option_index].name,"version")==0)
411          {
412             version();
413             exit(0);
414          } else if (strcmp(long_options[option_index].name,"version-short")==0)
415          {
416             version_short();
417             exit(0);
418          } else if (strcmp(long_options[option_index].name,"mono")==0)
419          {
420             channels=1;
421          } else if (strcmp(long_options[option_index].name,"stereo")==0)
422          {
423             channels=2;
424          } else if (strcmp(long_options[option_index].name,"rate")==0)
425          {
426             rate=atoi (optarg);
427          } else if (strcmp(long_options[option_index].name,"packet-loss")==0)
428          {
429             loss_percent = atof(optarg);
430          }
431          break;
432       case 'h':
433          usage();
434          exit(0);
435          break;
436       case 'v':
437          version();
438          exit(0);
439          break;
440       case 'V':
441          print_bitrate=1;
442          break;
443       case '?':
444          usage();
445          exit(1);
446          break;
447       }
448    }
449    if (argc-optind!=2 && argc-optind!=1)
450    {
451       usage();
452       exit(1);
453    }
454    inFile=argv[optind];
455
456    if (argc-optind==2)
457       outFile=argv[optind+1];
458    else
459       outFile = "";
460    wav_format = strlen(outFile)>=4 && (
461                                        strcmp(outFile+strlen(outFile)-4,".wav")==0
462                                        || strcmp(outFile+strlen(outFile)-4,".WAV")==0);
463    /*Open input file*/
464    if (strcmp(inFile, "-")==0)
465    {
466 #if defined WIN32 || defined _WIN32
467       _setmode(_fileno(stdin), _O_BINARY);
468 #endif
469       fin=stdin;
470    }
471    else 
472    {
473       fin = fopen(inFile, "rb");
474       if (!fin)
475       {
476          perror(inFile);
477          exit(1);
478       }
479       close_in=1;
480    }
481
482
483    /*Init Ogg data struct*/
484    ogg_sync_init(&oy);
485    
486    /*Main decoding loop*/
487    
488    while (1)
489    {
490       char *data;
491       int i, j, nb_read;
492       /*Get the ogg buffer for writing*/
493       data = ogg_sync_buffer(&oy, 200);
494       /*Read bitstream from input file*/
495       nb_read = fread(data, sizeof(char), 200, fin);      
496       ogg_sync_wrote(&oy, nb_read);
497
498       /*Loop for all complete pages we got (most likely only one)*/
499       while (ogg_sync_pageout(&oy, &og)==1)
500       {
501          int packet_no;
502          if (stream_init == 0) {
503             ogg_stream_init(&os, ogg_page_serialno(&og));
504             stream_init = 1;
505          }
506          if (ogg_page_serialno(&og) != os.serialno) {
507             /* so all streams are read. */
508             ogg_stream_reset_serialno(&os, ogg_page_serialno(&og));
509          }
510          /*Add page to the bitstream*/
511          ogg_stream_pagein(&os, &og);
512          page_granule = ogg_page_granulepos(&og);
513          page_nb_packets = ogg_page_packets(&og);
514          if (page_granule>0 && frame_size)
515          {
516             /* FIXME: shift the granule values if --force-* is specified */
517             skip_samples = frame_size*(page_nb_packets*granule_frame_size*nframes - (page_granule-last_granule))/granule_frame_size;
518             if (ogg_page_eos(&og))
519                skip_samples = -skip_samples;
520             /*else if (!ogg_page_bos(&og))
521                skip_samples = 0;*/
522          } else
523          {
524             skip_samples = 0;
525          }
526          /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/
527          last_granule = page_granule;
528          /*Extract all available packets*/
529          packet_no=0;
530          while (!eos && ogg_stream_packetout(&os, &op) == 1)
531          {
532             if (!memcmp(op.packet, "CELT    ", 8)) {
533                celt_serialno = os.serialno;
534             }
535             if (celt_serialno == -1 || os.serialno != celt_serialno)
536                break;
537             /*If first packet, process as CELT header*/
538             if (packet_count==0)
539             {
540                st = process_header(&op, enh_enabled, &frame_size, &granule_frame_size, &rate, &nframes, forceMode, &channels, &extra_headers, quiet);
541                if (!st)
542                   exit(1);
543                //FIXME: Do that properly
544                //celt_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
545                lookahead = 0;
546                if (!nframes)
547                   nframes=1;
548                fout = out_file_open(outFile, rate, &channels);
549
550             } else if (packet_count==1)
551             {
552                if (!quiet)
553                   print_comments((char*)op.packet, op.bytes);
554             } else if (packet_count<=1+extra_headers)
555             {
556                /* Ignore extra headers */
557             } else {
558                int lost=0;
559                packet_no++;
560                if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
561                   lost=1;
562
563                /*End of stream condition*/
564                if (op.e_o_s && os.serialno == celt_serialno) /* don't care for anything except celt eos */
565                   eos=1;
566                
567                {
568                   int ret;
569                   /*Decode frame*/
570                   if (!lost)
571                      ret = celt_decode(st, (unsigned char*)op.packet, op.bytes, output);
572                   else
573                      ret = celt_decode(st, NULL, 0, output);
574
575                   /*for (i=0;i<frame_size*channels;i++)
576                     printf ("%d\n", (int)output[i]);*/
577
578                   if (ret!=0)
579                   {
580                      fprintf (stderr, "Decoding error: corrupted stream?\n");
581                      break;
582                   }
583
584                   if (print_bitrate) {
585                      celt_int32_t tmp=40;
586                      char ch=13;
587                      fputc (ch, stderr);
588                      fprintf (stderr, "Bitrate is use: %d bytes/packet     ", tmp);
589                   }
590                   /*Convert to short and save to output file*/
591                   if (strlen(outFile)!=0)
592                   {
593                      for (i=0;i<frame_size*channels;i++)
594                         out[i]=le_short(output[i]);
595                   } else {
596                      for (i=0;i<frame_size*channels;i++)
597                         out[i]=output[i];
598                   }
599                   {
600                      int frame_offset = 0;
601                      int new_frame_size = frame_size;
602                      /*printf ("packet %d %d\n", packet_no, skip_samples);*/
603                      /*fprintf (stderr, "packet %d %d %d\n", packet_no, skip_samples, lookahead);*/
604                      if (packet_no == 1 && j==0 && skip_samples > 0)
605                      {
606                         /*printf ("chopping first packet\n");*/
607                         new_frame_size -= skip_samples+lookahead;
608                         frame_offset = skip_samples+lookahead;
609                      }
610                      if (packet_no == page_nb_packets && skip_samples < 0)
611                      {
612                         int packet_length = nframes*frame_size+skip_samples+lookahead;
613                         new_frame_size = packet_length - j*frame_size;
614                         if (new_frame_size<0)
615                            new_frame_size = 0;
616                         if (new_frame_size>frame_size)
617                            new_frame_size = frame_size;
618                         /*printf ("chopping end: %d %d %d\n", new_frame_size, packet_length, packet_no);*/
619                      }
620                      if (new_frame_size>0)
621                      {  
622 #if defined WIN32 || defined _WIN32
623                         if (strlen(outFile)==0)
624                            WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels);
625                         else
626 #endif
627                            fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);
628                   
629                         audio_size+=sizeof(short)*new_frame_size*channels;
630                      }
631                   }
632                }
633             }
634             packet_count++;
635          }
636       }
637       if (feof(fin))
638          break;
639
640    }
641
642    if (fout && wav_format)
643    {
644       if (fseek(fout,4,SEEK_SET)==0)
645       {
646          int tmp;
647          tmp = le_int(audio_size+36);
648          fwrite(&tmp,4,1,fout);
649          if (fseek(fout,32,SEEK_CUR)==0)
650          {
651             tmp = le_int(audio_size);
652             fwrite(&tmp,4,1,fout);
653          } else
654          {
655             fprintf (stderr, "First seek worked, second didn't\n");
656          }
657       } else {
658          fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n");
659       }
660    }
661
662    if (st)
663       celt_decoder_destroy(st);
664    else 
665    {
666       fprintf (stderr, "This doesn't look like a CELT file\n");
667    }
668    if (stream_init)
669       ogg_stream_clear(&os);
670    ogg_sync_clear(&oy);
671
672 #if defined WIN32 || defined _WIN32
673    if (strlen(outFile)==0)
674       WIN_Audio_close ();
675 #endif
676
677    if (close_in)
678       fclose(fin);
679    if (fout != NULL)
680       fclose(fout);   
681
682    return 0;
683 }