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 <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 (stderr
, _("oggdec from %s %s\n"), PACKAGE
, VERSION
);
53 static void usage(void)
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"
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"
78 static void parse_options(int argc
, char **argv
)
83 while((ret
= getopt_long(argc
, argv
, "Qhvb:e:Rs:o:",
84 long_options
, &option_index
)) != -1)
110 endian
= atoi(optarg
);
113 outfilename
= strdup(optarg
);
119 fprintf(stderr
, "Internal error: Unrecognised argument\n");
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
));
167 int rewrite_header(FILE *out
, unsigned int written
)
169 unsigned int length
= written
;
173 WRITE_U32(headbuf
+4, length
-8);
174 WRITE_U32(headbuf
+40, length
-44);
175 if(fseek(out
, 0, SEEK_SET
) != 0)
178 if(fwrite(headbuf
, 1, 44, out
) != 44) {
179 fprintf(stderr
, "ERROR: Failed to write wav header: %s\n", strerror(errno
));
185 static FILE *open_input(char *infile
)
191 setmode(fileno(stdin
), O_BINARY
);
193 _setmode(_fileno(stdin
), _O_BINARY
);
198 in
= fopen(infile
, "rb");
200 fprintf(stderr
, "ERROR: Failed to open input file: %s\n", strerror(errno
));
208 static FILE *open_output(char *outfile
)
213 setmode(fileno(stdout
), O_BINARY
);
215 _setmode(_fileno(stdout
), _O_BINARY
);
220 out
= fopen(outfile
, "wb");
222 fprintf(stderr
, "ERROR: Failed to open output file: %s\n", strerror(errno
));
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},
236 int samples
= len
/channels
/bytespersample
;
238 /* Can't handle, don't try */
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
)
257 char buf
[8192], outbuf
[8192];
260 unsigned int written
= 0;
262 ogg_int64_t length
= 0;
263 ogg_int64_t done
= 0;
270 if(ov_open(in
, &vf
, NULL
, 0) < 0) {
271 fprintf(stderr
, "ERROR: Failed to open input as vorbis\n");
276 channels
= ov_info(&vf
,0)->channels
;
277 samplerate
= ov_info(&vf
,0)->rate
;
279 if(ov_seekable(&vf
)) {
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
)
292 length
= ov_pcm_total(&vf
, -1);
294 length
= ov_pcm_total(&vf
, 0);
295 size
= bits
/8 * channels
;
297 fprintf(stderr
, "Decoding \"%s\" to \"%s\"\n",
298 infile
?infile
:"standard input",
299 outfile
?outfile
:"standard output");
303 if(write_prelim_header(&vf
, out
, length
)) {
309 while((ret
= ov_read(&vf
, buf
, buflen
, endian
, bits
/8, sign
, &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");
320 fprintf(stderr
, "Warning: hole in data (%d)\n", ret
);
325 if(channels
> 2 && !raw
) {
327 permute_channels(buf
, outbuf
, ret
, channels
, bits
/8);
334 if(fwrite(p_outbuf
, 1, ret
, out
) != ret
) {
335 fprintf(stderr
, "Error writing to file: %s\n", strerror(errno
));
341 if(!quiet
&& seekable
) {
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");
354 rewrite_header(out
, written
); /* We don't care if it fails, too late */
361 int main(int argc
, char **argv
)
370 parse_options(argc
,argv
);
376 fprintf(stderr
, "ERROR: No input files specified. Use -h for help\n");
380 if(argc
- optind
> 1 && outfilename
&& !raw
) {
381 fprintf(stderr
, "ERROR: Can only specify one input file if output filename is specified\n");
385 if(outfilename
&& raw
) {
386 FILE *infile
, *outfile
;
389 if(!strcmp(outfilename
, "-")) {
391 outfile
= open_output(NULL
);
394 outfile
= open_output(outfilename
);
399 for(i
=optind
; i
< argc
; i
++) {
400 if(!strcmp(argv
[i
], "-")) {
402 infile
= open_input(NULL
);
405 infilename
= argv
[i
];
406 infile
= open_input(argv
[i
]);
413 if(decode_file(infile
, outfile
, infilename
, outfilename
)) {
423 for(i
=optind
; i
< argc
; i
++) {
425 FILE *infile
, *outfile
;
427 if(!strcmp(argv
[i
], "-"))
433 if(!strcmp(outfilename
, "-"))
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;
451 infile
= open_input(in
);
454 outfile
= open_output(out
);
460 if(decode_file(infile
, outfile
, in
, out
)) {