Put the channel count outside of the energy calculation. Increased the allowed
[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 (len < 0 || 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 (len < 0 || 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 *overlap, int *extra_headers, int quiet, CELTMode **mode)
290 {
291    CELTDecoder *st;
292    CELTHeader header;
293       
294    celt_header_from_packet((char*)op->packet, op->bytes, &header);
295
296    if (header.nb_channels>2 || header.nb_channels<1)
297    {
298       fprintf (stderr, "Unsupported number of channels: %d\n", header.nb_channels);
299       return NULL;
300    }
301    *mode = celt_mode_create(header.sample_rate, header.nb_channels, header.frame_size, header.overlap, NULL);
302    if (*mode == NULL)
303    {
304       fprintf (stderr, "Mode initialization failed.\n");
305       return NULL;
306    }
307    *channels = header.nb_channels;
308    *overlap=header.overlap;
309    st = celt_decoder_create(*mode);
310    if (!st)
311    {
312       fprintf (stderr, "Decoder initialization failed.\n");
313       return NULL;
314    }
315    
316    celt_mode_info(*mode, CELT_GET_FRAME_SIZE, frame_size);
317    *granule_frame_size = *frame_size;
318
319    if (!*rate)
320       *rate = header.sample_rate;
321
322    *nframes = 1;
323
324    if (!quiet)
325    {
326       fprintf (stderr, "Decoding %d Hz audio in", *rate);
327
328       if (*channels==1)
329          fprintf (stderr, " (mono");
330       else
331          fprintf (stderr, " (stereo");
332       fprintf(stderr, ")\n");
333    }
334
335    *extra_headers = header.extra_headers;
336
337    return st;
338 }
339
340 int main(int argc, char **argv)
341 {
342    int c;
343    int option_index = 0;
344    char *inFile, *outFile;
345    FILE *fin, *fout=NULL;
346    short out[MAX_FRAME_SIZE];
347    short output[MAX_FRAME_SIZE];
348    int frame_size=0, granule_frame_size=0;
349    void *st=NULL;
350    CELTMode *mode=NULL;
351    unsigned char bits[1000];
352    int packet_count=0;
353    int stream_init = 0;
354    int quiet = 0;
355    ogg_int64_t page_granule=0, last_granule=0;
356    int skip_samples=0, page_nb_packets;
357    struct option long_options[] =
358    {
359       {"help", no_argument, NULL, 0},
360       {"quiet", no_argument, NULL, 0},
361       {"version", no_argument, NULL, 0},
362       {"version-short", no_argument, NULL, 0},
363       {"rate", required_argument, NULL, 0},
364       {"mono", no_argument, NULL, 0},
365       {"stereo", no_argument, NULL, 0},
366       {"packet-loss", required_argument, NULL, 0},
367       {0, 0, 0, 0}
368    };
369    ogg_sync_state oy;
370    ogg_page       og;
371    ogg_packet     op;
372    ogg_stream_state os;
373    int enh_enabled;
374    int nframes=2;
375    int print_bitrate=0;
376    int close_in=0;
377    int eos=0;
378    int forceMode=-1;
379    int audio_size=0;
380    float loss_percent=-1;
381    int channels=-1;
382    int rate=0;
383    int extra_headers=0;
384    int wav_format=0;
385    int lookahead;
386    int celt_serialno = -1;
387    int firstpacket = 1;
388
389    enh_enabled = 1;
390
391    /*Process options*/
392    while(1)
393    {
394       c = getopt_long (argc, argv, "hvV",
395                        long_options, &option_index);
396       if (c==-1)
397          break;
398       
399       switch(c)
400       {
401       case 0:
402          if (strcmp(long_options[option_index].name,"help")==0)
403          {
404             usage();
405             exit(0);
406          } else if (strcmp(long_options[option_index].name,"quiet")==0)
407          {
408             quiet = 1;
409          } else if (strcmp(long_options[option_index].name,"version")==0)
410          {
411             version();
412             exit(0);
413          } else if (strcmp(long_options[option_index].name,"version-short")==0)
414          {
415             version_short();
416             exit(0);
417          } else if (strcmp(long_options[option_index].name,"mono")==0)
418          {
419             channels=1;
420          } else if (strcmp(long_options[option_index].name,"stereo")==0)
421          {
422             channels=2;
423          } else if (strcmp(long_options[option_index].name,"rate")==0)
424          {
425             rate=atoi (optarg);
426          } else if (strcmp(long_options[option_index].name,"packet-loss")==0)
427          {
428             loss_percent = atof(optarg);
429          }
430          break;
431       case 'h':
432          usage();
433          exit(0);
434          break;
435       case 'v':
436          version();
437          exit(0);
438          break;
439       case 'V':
440          print_bitrate=1;
441          break;
442       case '?':
443          usage();
444          exit(1);
445          break;
446       }
447    }
448    if (argc-optind!=2 && argc-optind!=1)
449    {
450       usage();
451       exit(1);
452    }
453    inFile=argv[optind];
454
455    if (argc-optind==2)
456       outFile=argv[optind+1];
457    else
458       outFile = "";
459    wav_format = strlen(outFile)>=4 && (
460                                        strcmp(outFile+strlen(outFile)-4,".wav")==0
461                                        || strcmp(outFile+strlen(outFile)-4,".WAV")==0);
462    /*Open input file*/
463    if (strcmp(inFile, "-")==0)
464    {
465 #if defined WIN32 || defined _WIN32
466       _setmode(_fileno(stdin), _O_BINARY);
467 #endif
468       fin=stdin;
469    }
470    else 
471    {
472       fin = fopen(inFile, "rb");
473       if (!fin)
474       {
475          perror(inFile);
476          exit(1);
477       }
478       close_in=1;
479    }
480
481
482    /*Init Ogg data struct*/
483    ogg_sync_init(&oy);
484    
485    /*Main decoding loop*/
486    
487    while (1)
488    {
489       char *data;
490       int i, j, nb_read;
491       /*Get the ogg buffer for writing*/
492       data = ogg_sync_buffer(&oy, 200);
493       /*Read bitstream from input file*/
494       nb_read = fread(data, sizeof(char), 200, fin);      
495       ogg_sync_wrote(&oy, nb_read);
496
497       /*Loop for all complete pages we got (most likely only one)*/
498       while (ogg_sync_pageout(&oy, &og)==1)
499       {
500          if (stream_init == 0) {
501             ogg_stream_init(&os, ogg_page_serialno(&og));
502             stream_init = 1;
503          }
504          if (ogg_page_serialno(&og) != os.serialno) {
505             /* so all streams are read. */
506             ogg_stream_reset_serialno(&os, ogg_page_serialno(&og));
507          }
508          /*Add page to the bitstream*/
509          ogg_stream_pagein(&os, &og);
510          page_granule = ogg_page_granulepos(&og);
511          page_nb_packets = ogg_page_packets(&og);
512          if (page_granule>0 && frame_size)
513          {
514             /* FIXME: shift the granule values if --force-* is specified */
515             skip_samples = frame_size*(page_nb_packets*granule_frame_size*nframes - (page_granule-last_granule))/granule_frame_size;
516             if (ogg_page_eos(&og))
517                skip_samples = -skip_samples;
518             /*else if (!ogg_page_bos(&og))
519                skip_samples = 0;*/
520          } else
521          {
522             skip_samples = 0;
523          }
524          /*printf ("page granulepos: %d %d %d\n", skip_samples, page_nb_packets, (int)page_granule);*/
525          last_granule = page_granule;
526          /*Extract all available packets*/
527          while (!eos && ogg_stream_packetout(&os, &op) == 1 && op.bytes>=8)
528          {
529             if (!memcmp(op.packet, "CELT    ", 8)) {
530                celt_serialno = os.serialno;
531             }
532             if (celt_serialno == -1 || os.serialno != celt_serialno)
533                break;
534             /*If first packet, process as CELT header*/
535             if (packet_count==0)
536             {
537                st = process_header(&op, enh_enabled, &frame_size, &granule_frame_size, &rate, &nframes, forceMode, &channels, &lookahead, &extra_headers, quiet, &mode);
538                if (!st)
539                   exit(1);
540                if (!nframes)
541                   nframes=1;
542                fout = out_file_open(outFile, rate, &channels);
543
544             } else if (packet_count==1)
545             {
546                if (!quiet)
547                   print_comments((char*)op.packet, op.bytes);
548             } else if (packet_count<=1+extra_headers)
549             {
550                /* Ignore extra headers */
551             } else {
552                int lost=0;
553                if (loss_percent>0 && 100*((float)rand())/RAND_MAX<loss_percent)
554                   lost=1;
555
556                /*End of stream condition*/
557                if (op.e_o_s && os.serialno == celt_serialno) /* don't care for anything except celt eos */
558                   eos=1;
559                
560                {
561                   int ret;
562                   /*Decode frame*/
563                   if (!lost)
564                      ret = celt_decode(st, (unsigned char*)op.packet, op.bytes, output);
565                   else
566                      ret = celt_decode(st, NULL, 0, output);
567
568                   /*for (i=0;i<frame_size*channels;i++)
569                     printf ("%d\n", (int)output[i]);*/
570
571                   if (ret!=0)
572                   {
573                      fprintf (stderr, "Decoding error: corrupted stream?\n");
574                      break;
575                   }
576
577                   if (print_bitrate) {
578                      celt_int32_t tmp=op.bytes;
579                      char ch=13;
580                      fputc (ch, stderr);
581                      fprintf (stderr, "Bitrate in use: %d bytes/packet     ", tmp);
582                   }
583                   /*Convert to short and save to output file*/
584                   if (strlen(outFile)!=0)
585                   {
586                      for (i=0;i<frame_size*channels;i++)
587                         out[i]=le_short(output[i]);
588                   } else {
589                      for (i=0;i<frame_size*channels;i++)
590                         out[i]=output[i];
591                   }
592                   {
593                      int frame_offset = 0;
594                      int new_frame_size = frame_size;
595                      /*printf ("packet %d %d\n", packet_no, skip_samples);*/
596                      /*fprintf (stderr, "packet %d %d %d\n", packet_no, skip_samples, lookahead);*/
597                      if (firstpacket == 1)
598                      {
599                         /*printf ("chopping first packet\n");*/
600                         new_frame_size -= lookahead;
601                         frame_offset = lookahead;
602                         firstpacket = 0;
603                      }
604                      if (new_frame_size>0)
605                      {  
606 #if defined WIN32 || defined _WIN32
607                         if (strlen(outFile)==0)
608                            WIN_Play_Samples (out+frame_offset*channels, sizeof(short) * new_frame_size*channels);
609                         else
610 #endif
611                            fwrite(out+frame_offset*channels, sizeof(short), new_frame_size*channels, fout);
612                   
613                         audio_size+=sizeof(short)*new_frame_size*channels;
614                      }
615                   }
616                }
617             }
618             packet_count++;
619          }
620       }
621       if (feof(fin))
622          break;
623
624    }
625
626    if (fout && wav_format)
627    {
628       if (fseek(fout,4,SEEK_SET)==0)
629       {
630          int tmp;
631          tmp = le_int(audio_size+36);
632          fwrite(&tmp,4,1,fout);
633          if (fseek(fout,32,SEEK_CUR)==0)
634          {
635             tmp = le_int(audio_size);
636             fwrite(&tmp,4,1,fout);
637          } else
638          {
639             fprintf (stderr, "First seek worked, second didn't\n");
640          }
641       } else {
642          fprintf (stderr, "Cannot seek on wave file, size will be incorrect\n");
643       }
644    }
645
646    if (st)
647    {
648       celt_decoder_destroy(st);
649       celt_mode_destroy(mode);
650    } else {
651       fprintf (stderr, "This doesn't look like a CELT file\n");
652    }
653    if (stream_init)
654       ogg_stream_clear(&os);
655    ogg_sync_clear(&oy);
656
657 #if defined WIN32 || defined _WIN32
658    if (strlen(outFile)==0)
659       WIN_Audio_close ();
660 #endif
661
662    if (close_in)
663       fclose(fin);
664    if (fout != NULL)
665       fclose(fout);   
666
667    return 0;
668 }