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>
20 #if defined(_WIN32) || defined(__EMX__) || defined(__WATCOMC__)
25 #include <ext/vorbis/vorbisfile.h>
29 struct option long_options[] = {
32 {"version", 0, 0, 'V'},
34 {"endianness", 1, 0, 'e'},
37 {"output", 1, 0, 'o'},
43 static int endian = 0;
46 unsigned char headbuf[44]; /* The whole buffer */
47 char *outfilename = NULL;
49 static void version (void) {
50 fprintf(stdout, _("oggdec from %s %s\n"), PACKAGE, VERSION);
53 static void usage(void)
56 fprintf(stdout, _(" by the Xiph.Org Foundation (http://www.xiph.org/)\n\n"));
57 fprintf(stdout, _("Usage: oggdec [options] file1.ogg [file2.ogg ... fileN.ogg]\n\n"));
58 fprintf(stdout, _("Supported options:\n"));
59 fprintf(stdout, _(" --quiet, -Q Quiet mode. No console output.\n"));
60 fprintf(stdout, _(" --help, -h Produce this help message.\n"));
61 fprintf(stdout, _(" --version, -V Print out version number.\n"));
62 fprintf(stdout, _(" --bits, -b Bit depth for output (8 and 16 supported)\n"));
63 fprintf(stdout, _(" --endianness, -e Output endianness for 16-bit output; 0 for\n"
64 " little endian (default), 1 for big endian.\n"));
65 fprintf(stdout, _(" --sign, -s Sign for output PCM; 0 for unsigned, 1 for\n"
66 " signed (default 1).\n"));
67 fprintf(stdout, _(" --raw, -R Raw (headerless) output.\n"));
68 fprintf(stdout, _(" --output, -o Output to given filename. May only be used\n"
69 " if there is only one input file, except in\n"
73 static void parse_options(int argc, char **argv)
78 while((ret = getopt_long(argc, argv, "QhVb:e:Rs:o:",
79 long_options, &option_index)) != -1)
105 endian = atoi(optarg);
108 outfilename = strdup(optarg);
114 fprintf(stderr, _("Internal error: Unrecognised argument\n"));
120 #define WRITE_U32(buf, x) *(buf) = (unsigned char)((x)&0xff);\
121 *((buf)+1) = (unsigned char)(((x)>>8)&0xff);\
122 *((buf)+2) = (unsigned char)(((x)>>16)&0xff);\
123 *((buf)+3) = (unsigned char)(((x)>>24)&0xff);
125 #define WRITE_U16(buf, x) *(buf) = (unsigned char)((x)&0xff);\
126 *((buf)+1) = (unsigned char)(((x)>>8)&0xff);
128 /* Some of this based on ao/src/ao_wav.c */
129 int write_prelim_header(OggVorbis_File *vf, FILE *out, ogg_int64_t knownlength) {
130 unsigned int size = 0x7fffffff;
131 int channels = ov_info(vf,0)->channels;
132 int samplerate = ov_info(vf,0)->rate;
133 int bytespersec = channels*samplerate*bits/8;
134 int align = channels*bits/8;
135 int samplesize = bits;
137 if(knownlength && knownlength*bits/8*channels < size)
138 size = (unsigned int)(knownlength*bits/8*channels+44) ;
140 memcpy(headbuf, "RIFF", 4);
141 WRITE_U32(headbuf+4, size-8);
142 memcpy(headbuf+8, "WAVE", 4);
143 memcpy(headbuf+12, "fmt ", 4);
144 WRITE_U32(headbuf+16, 16);
145 WRITE_U16(headbuf+20, 1); /* format */
146 WRITE_U16(headbuf+22, channels);
147 WRITE_U32(headbuf+24, samplerate);
148 WRITE_U32(headbuf+28, bytespersec);
149 WRITE_U16(headbuf+32, align);
150 WRITE_U16(headbuf+34, samplesize);
151 memcpy(headbuf+36, "data", 4);
152 WRITE_U32(headbuf+40, size - 44);
154 if(fwrite(headbuf, 1, 44, out) != 44) {
155 fprintf(stderr, _("ERROR: Failed to write Wave header: %s\n"), strerror(errno));
162 int rewrite_header(FILE *out, unsigned int written)
164 unsigned int length = written;
168 WRITE_U32(headbuf+4, length-8);
169 WRITE_U32(headbuf+40, length-44);
170 if(fseek(out, 0, SEEK_SET) != 0)
173 if(fwrite(headbuf, 1, 44, out) != 44) {
174 fprintf(stderr, _("ERROR: Failed to write Wave header: %s\n"), strerror(errno));
180 static FILE *open_input(char *infile)
186 setmode(fileno(stdin), O_BINARY);
188 _setmode(_fileno(stdin), _O_BINARY);
193 in = fopen(infile, "rb");
195 fprintf(stderr, _("ERROR: Failed to open input file: %s\n"), strerror(errno));
203 static FILE *open_output(char *outfile)
208 setmode(fileno(stdout), O_BINARY);
210 _setmode(_fileno(stdout), _O_BINARY);
215 out = fopen(outfile, "wb");
217 fprintf(stderr, _("ERROR: Failed to open output file: %s\n"), strerror(errno));
226 permute_channels(char *in, char *out, int len, int channels, int bytespersample)
228 int permute[6][6] = {{0}, {0,1}, {0,2,1}, {0,1,2,3}, {0,1,2,3,4},
231 int samples = len/channels/bytespersample;
233 /* Can't handle, don't try */
237 for (i=0; i < samples; i++) {
238 for (j=0; j < channels; j++) {
239 for (k=0; k < bytespersample; k++) {
240 out[i*bytespersample*channels +
241 bytespersample*permute[channels-1][j] + k] =
242 in[i*bytespersample*channels + bytespersample*j + k];
248 static int decode_file(FILE *in, FILE *out, char *infile, char *outfile)
252 char buf[8192], outbuf[8192];
255 unsigned int written = 0;
257 ogg_int64_t length = 0;
258 ogg_int64_t done = 0;
265 if (ov_open_callbacks(in, &vf, NULL, 0, OV_CALLBACKS_DEFAULT) < 0) {
266 fprintf(stderr, _("ERROR: Failed to open input as Vorbis\n"));
271 channels = ov_info(&vf,0)->channels;
272 samplerate = ov_info(&vf,0)->rate;
274 if(ov_seekable(&vf)) {
276 int chainsallowed = 0;
277 for(link = 0; link < ov_streams(&vf); link++) {
278 if(ov_info(&vf, link)->channels == channels &&
279 ov_info(&vf, link)->rate == samplerate)
287 length = ov_pcm_total(&vf, -1);
289 length = ov_pcm_total(&vf, 0);
290 size = bits/8 * channels;
292 fprintf(stderr, _("Decoding \"%s\" to \"%s\"\n"),
293 infile?infile:_("standard input"),
294 outfile?outfile:_("standard output"));
298 if(write_prelim_header(&vf, out, length)) {
304 while((ret = ov_read(&vf, buf, buflen, endian, bits/8, sign, &bs)) != 0) {
306 vorbis_info *vi = ov_info(&vf, -1);
307 if(channels != vi->channels || samplerate != vi->rate) {
308 fprintf(stderr, _("Logical bitstreams with changing parameters are not supported\n"));
315 fprintf(stderr, _("WARNING: hole in data (%d)\n"), ret);
320 if(channels > 2 && !raw) {
322 permute_channels(buf, outbuf, ret, channels, bits/8);
329 if(fwrite(p_outbuf, 1, ret, out) != ret) {
330 fprintf(stderr, _("Error writing to file: %s\n"), strerror(errno));
336 if(!quiet && seekable) {
338 if((double)done/(double)length * 200. > (double)percent) {
339 percent = (int)((double)done/(double)length *200);
340 fprintf(stderr, "\r\t[%5.1f%%]", (double)percent/2.);
345 if(seekable && !quiet)
346 fprintf(stderr, "\n");
349 rewrite_header(out, written); /* We don't care if it fails, too late */
356 int main(int argc, char **argv)
365 parse_options(argc,argv);
371 fprintf(stderr, _("ERROR: No input files specified. Use -h for help\n"));
375 if(argc - optind > 1 && outfilename && !raw) {
376 fprintf(stderr, _("ERROR: Can only specify one input file if output filename is specified\n"));
380 if(outfilename && raw) {
381 FILE *infile, *outfile;
384 if(!strcmp(outfilename, "-")) {
386 outfile = open_output(NULL);
389 outfile = open_output(outfilename);
394 for(i=optind; i < argc; i++) {
395 if(!strcmp(argv[i], "-")) {
397 infile = open_input(NULL);
400 infilename = argv[i];
401 infile = open_input(argv[i]);
408 if(decode_file(infile, outfile, infilename, outfilename)) {
418 for(i=optind; i < argc; i++) {
420 FILE *infile, *outfile;
422 if(!strcmp(argv[i], "-"))
428 if(!strcmp(outfilename, "-"))
434 char *end = strrchr(argv[i], '.');
435 end = end?end:(argv[i] + strlen(argv[i]) + 1);
437 out = malloc(strlen(argv[i]) + 10);
438 strncpy(out, argv[i], end-argv[i]);
439 out[end-argv[i]] = 0;
446 infile = open_input(in);
449 outfile = open_output(out);
455 if(decode_file(infile, outfile, in, out)) {