Added vorbis-tools.
[vorbis-lancer-gcc.git] / vorbis-tools-1.2.0 / oggdec / oggdec.c
blob5511a60dde9864c685c09b7a00720b0d4d28720e
1 /* OggDec
3 * This program is distributed under the GNU General Public License, version 2.
4 * A copy of this license is included with this source.
6 * Copyright 2002, Michael Smith <msmith@xiph.org>
8 */
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <getopt.h>
17 #include <errno.h>
18 #include <string.h>
20 #if defined(_WIN32) || defined(__EMX__) || defined(__WATCOMC__)
21 #include <fcntl.h>
22 #include <io.h>
23 #endif
25 #include <vorbis/vorbisfile.h>
27 #include "i18n.h"
29 struct option long_options[] = {
30 {"quiet", 0,0,'Q'},
31 {"help",0,0,'h'},
32 {"version", 0, 0, 'v'},
33 {"bits", 1, 0, 'b'},
34 {"endianness", 1, 0, 'e'},
35 {"raw", 0, 0, 'R'},
36 {"sign", 1, 0, 's'},
37 {"output", 1, 0, 'o'},
38 {NULL,0,0,0}
41 static int quiet = 0;
42 static int bits = 16;
43 static int endian = 0;
44 static int raw = 0;
45 static int sign = 1;
46 unsigned char headbuf[44]; /* The whole buffer */
47 char *outfilename = NULL;
49 static void version (void) {
50 fprintf (stderr, _("oggdec from %s %s\n"), PACKAGE, VERSION);
53 static void usage(void)
55 version ();
56 fprintf (stderr, _(" by the Xiph.Org Foundation (http://www.xiph.org/)\n\n"));
57 fprintf(stderr, "Usage: oggdec [flags] file1.ogg [file2.ogg ... fileN.ogg]\n"
58 "\n"
59 "Supported flags:\n"
60 " --quiet, -Q Quiet mode. No console output.\n"
61 " --help, -h Produce this help message.\n"
62 " --version, -v Print out version number.\n"
63 " --bits, -b Bit depth for output (8 and 16 supported)\n"
64 " --endianness, -e Output endianness for 16 bit output. 0 for\n"
65 " little endian (default), 1 for big endian\n"
66 " --sign, -s Sign for output PCM, 0 for unsigned, 1 for\n"
67 " signed (default 1)\n"
68 " --raw, -R Raw (headerless) output.\n"
69 " --output, -o Output to given filename. May only be used\n"
70 " if there is only one input file, except in\n"
71 " raw mode.\n"
78 static void parse_options(int argc, char **argv)
80 int option_index = 1;
81 int ret;
83 while((ret = getopt_long(argc, argv, "Qhvb:e:Rs:o:",
84 long_options, &option_index)) != -1)
86 switch(ret)
88 case 'Q':
89 quiet = 1;
90 break;
91 case 'h':
92 usage();
93 exit(0);
94 break;
95 case 'v':
96 version();
97 exit(0);
98 break;
99 case 's':
100 sign = atoi(optarg);
101 break;
102 case 'b':
103 bits = atoi(optarg);
104 if(bits <= 8)
105 bits = 8;
106 else
107 bits = 16;
108 break;
109 case 'e':
110 endian = atoi(optarg);
111 break;
112 case 'o':
113 outfilename = strdup(optarg);
114 break;
115 case 'R':
116 raw = 1;
117 break;
118 default:
119 fprintf(stderr, "Internal error: Unrecognised argument\n");
120 break;
125 #define WRITE_U32(buf, x) *(buf) = (unsigned char)((x)&0xff);\
126 *((buf)+1) = (unsigned char)(((x)>>8)&0xff);\
127 *((buf)+2) = (unsigned char)(((x)>>16)&0xff);\
128 *((buf)+3) = (unsigned char)(((x)>>24)&0xff);
130 #define WRITE_U16(buf, x) *(buf) = (unsigned char)((x)&0xff);\
131 *((buf)+1) = (unsigned char)(((x)>>8)&0xff);
133 /* Some of this based on ao/src/ao_wav.c */
134 int write_prelim_header(OggVorbis_File *vf, FILE *out, ogg_int64_t knownlength) {
135 unsigned int size = 0x7fffffff;
136 int channels = ov_info(vf,0)->channels;
137 int samplerate = ov_info(vf,0)->rate;
138 int bytespersec = channels*samplerate*bits/8;
139 int align = channels*bits/8;
140 int samplesize = bits;
142 if(knownlength && knownlength*bits/8*channels < size)
143 size = (unsigned int)(knownlength*bits/8*channels+44) ;
145 memcpy(headbuf, "RIFF", 4);
146 WRITE_U32(headbuf+4, size-8);
147 memcpy(headbuf+8, "WAVE", 4);
148 memcpy(headbuf+12, "fmt ", 4);
149 WRITE_U32(headbuf+16, 16);
150 WRITE_U16(headbuf+20, 1); /* format */
151 WRITE_U16(headbuf+22, channels);
152 WRITE_U32(headbuf+24, samplerate);
153 WRITE_U32(headbuf+28, bytespersec);
154 WRITE_U16(headbuf+32, align);
155 WRITE_U16(headbuf+34, samplesize);
156 memcpy(headbuf+36, "data", 4);
157 WRITE_U32(headbuf+40, size - 44);
159 if(fwrite(headbuf, 1, 44, out) != 44) {
160 fprintf(stderr, "ERROR: Failed to write wav header: %s\n", strerror(errno));
161 return 1;
164 return 0;
167 int rewrite_header(FILE *out, unsigned int written)
169 unsigned int length = written;
171 length += 44;
173 WRITE_U32(headbuf+4, length-8);
174 WRITE_U32(headbuf+40, length-44);
175 if(fseek(out, 0, SEEK_SET) != 0)
176 return 1;
178 if(fwrite(headbuf, 1, 44, out) != 44) {
179 fprintf(stderr, "ERROR: Failed to write wav header: %s\n", strerror(errno));
180 return 1;
182 return 0;
185 static FILE *open_input(char *infile)
187 FILE *in;
189 if(!infile) {
190 #ifdef __BORLANDC__
191 setmode(fileno(stdin), O_BINARY);
192 #elif _WIN32
193 _setmode(_fileno(stdin), _O_BINARY);
194 #endif
195 in = stdin;
197 else {
198 in = fopen(infile, "rb");
199 if(!in) {
200 fprintf(stderr, "ERROR: Failed to open input file: %s\n", strerror(errno));
201 return NULL;
205 return in;
208 static FILE *open_output(char *outfile)
210 FILE *out;
211 if(!outfile) {
212 #ifdef __BORLANDC__
213 setmode(fileno(stdout), O_BINARY);
214 #elif _WIN32
215 _setmode(_fileno(stdout), _O_BINARY);
216 #endif
217 out = stdout;
219 else {
220 out = fopen(outfile, "wb");
221 if(!out) {
222 fprintf(stderr, "ERROR: Failed to open output file: %s\n", strerror(errno));
223 return NULL;
227 return out;
230 static void
231 permute_channels(char *in, char *out, int len, int channels, int bytespersample)
233 int permute[6][6] = {{0}, {0,1}, {0,2,1}, {0,1,2,3}, {0,1,2,3,4},
234 {0,2,1,5,3,4}};
235 int i,j,k;
236 int samples = len/channels/bytespersample;
238 /* Can't handle, don't try */
239 if (channels > 6)
240 return;
242 for (i=0; i < samples; i++) {
243 for (j=0; j < channels; j++) {
244 for (k=0; k < bytespersample; k++) {
245 out[i*bytespersample*channels +
246 bytespersample*permute[channels-1][j] + k] =
247 in[i*bytespersample*channels + bytespersample*j + k];
253 static int decode_file(FILE *in, FILE *out, char *infile, char *outfile)
255 OggVorbis_File vf;
256 int bs = 0;
257 char buf[8192], outbuf[8192];
258 char *p_outbuf;
259 int buflen = 8192;
260 unsigned int written = 0;
261 int ret;
262 ogg_int64_t length = 0;
263 ogg_int64_t done = 0;
264 int size = 0;
265 int seekable = 0;
266 int percent = 0;
267 int channels;
268 int samplerate;
270 if(ov_open(in, &vf, NULL, 0) < 0) {
271 fprintf(stderr, "ERROR: Failed to open input as vorbis\n");
272 fclose(in);
273 return 1;
276 channels = ov_info(&vf,0)->channels;
277 samplerate = ov_info(&vf,0)->rate;
279 if(ov_seekable(&vf)) {
280 int link;
281 int chainsallowed = 0;
282 for(link = 0; link < ov_streams(&vf); link++) {
283 if(ov_info(&vf, link)->channels == channels &&
284 ov_info(&vf, link)->rate == samplerate)
286 chainsallowed = 1;
290 seekable = 1;
291 if(chainsallowed)
292 length = ov_pcm_total(&vf, -1);
293 else
294 length = ov_pcm_total(&vf, 0);
295 size = bits/8 * channels;
296 if(!quiet)
297 fprintf(stderr, "Decoding \"%s\" to \"%s\"\n",
298 infile?infile:"standard input",
299 outfile?outfile:"standard output");
302 if(!raw) {
303 if(write_prelim_header(&vf, out, length)) {
304 ov_clear(&vf);
305 return 1;
309 while((ret = ov_read(&vf, buf, buflen, endian, bits/8, sign, &bs)) != 0) {
310 if(bs != 0) {
311 vorbis_info *vi = ov_info(&vf, -1);
312 if(channels != vi->channels || samplerate != vi->rate) {
313 fprintf(stderr, "Logical bitstreams with changing parameters are not supported\n");
314 break;
318 if(ret < 0 ) {
319 if( !quiet ) {
320 fprintf(stderr, "Warning: hole in data (%d)\n", ret);
322 continue;
325 if(channels > 2 && !raw) {
326 /* Then permute! */
327 permute_channels(buf, outbuf, ret, channels, bits/8);
328 p_outbuf = outbuf;
330 else {
331 p_outbuf = buf;
334 if(fwrite(p_outbuf, 1, ret, out) != ret) {
335 fprintf(stderr, "Error writing to file: %s\n", strerror(errno));
336 ov_clear(&vf);
337 return 1;
340 written += ret;
341 if(!quiet && seekable) {
342 done += ret/size;
343 if((double)done/(double)length * 200. > (double)percent) {
344 percent = (double)done/(double)length *200;
345 fprintf(stderr, "\r\t[%5.1f%%]", (double)percent/2.);
350 if(seekable && !quiet)
351 fprintf(stderr, "\n");
353 if(!raw)
354 rewrite_header(out, written); /* We don't care if it fails, too late */
356 ov_clear(&vf);
358 return 0;
361 int main(int argc, char **argv)
363 int i;
365 if(argc == 1) {
366 usage();
367 return 1;
370 parse_options(argc,argv);
372 if(!quiet)
373 version();
375 if(optind >= argc) {
376 fprintf(stderr, "ERROR: No input files specified. Use -h for help\n");
377 return 1;
380 if(argc - optind > 1 && outfilename && !raw) {
381 fprintf(stderr, "ERROR: Can only specify one input file if output filename is specified\n");
382 return 1;
385 if(outfilename && raw) {
386 FILE *infile, *outfile;
387 char *infilename;
389 if(!strcmp(outfilename, "-")) {
390 outfilename = NULL;
391 outfile = open_output(NULL);
393 else
394 outfile = open_output(outfilename);
396 if(!outfile)
397 return 1;
399 for(i=optind; i < argc; i++) {
400 if(!strcmp(argv[i], "-")) {
401 infilename = NULL;
402 infile = open_input(NULL);
404 else {
405 infilename = argv[i];
406 infile = open_input(argv[i]);
409 if(!infile) {
410 fclose(outfile);
411 return 1;
413 if(decode_file(infile, outfile, infilename, outfilename)) {
414 fclose(outfile);
415 return 1;
420 fclose(outfile);
422 else {
423 for(i=optind; i < argc; i++) {
424 char *in, *out;
425 FILE *infile, *outfile;
427 if(!strcmp(argv[i], "-"))
428 in = NULL;
429 else
430 in = argv[i];
432 if(outfilename) {
433 if(!strcmp(outfilename, "-"))
434 out = NULL;
435 else
436 out = outfilename;
438 else {
439 char *end = strrchr(argv[i], '.');
440 end = end?end:(argv[i] + strlen(argv[i]) + 1);
442 out = malloc(strlen(argv[i]) + 10);
443 strncpy(out, argv[i], end-argv[i]);
444 out[end-argv[i]] = 0;
445 if(raw)
446 strcat(out, ".raw");
447 else
448 strcat(out, ".wav");
451 infile = open_input(in);
452 if(!infile)
453 return 1;
454 outfile = open_output(out);
455 if(!outfile) {
456 fclose(infile);
457 return 1;
460 if(decode_file(infile, outfile, in, out)) {
461 fclose(outfile);
462 return 1;
465 if(!outfilename)
466 free(out);
468 fclose(outfile);
472 if(outfilename)
473 free(outfilename);
475 return 0;