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>
16
#if defined(_WIN32) || defined(__EMX__) || defined(__WATCOMC__)
21
#include <vorbis/vorbisfile.h>
23
struct option long_options[] = {
26
{"version", 0, 0, 'v'},
28
{"endianness", 1, 0, 'e'},
31
{"output", 1, 0, 'o'},
35
#define VERSIONSTRING "OggDec 1.0.1\n"
39
static int endian = 0;
42
unsigned char headbuf[44]; /* The whole buffer */
43
char *outfilename = NULL;
45
static void usage(void) {
46
fprintf(stderr, "Usage: oggdec [flags] file1.ogg [file2.ogg ... fileN.ogg]\n"
49
" --quiet, -Q Quiet mode. No console output.\n"
50
" --help, -h Produce this help message.\n"
51
" --version, -v Print out version number.\n"
52
" --bits, -b Bit depth for output (8 and 16 supported)\n"
53
" --endianness, -e Output endianness for 16 bit output. 0 for\n"
54
" little endian (default), 1 for big endian\n"
55
" --sign, -s Sign for output PCM, 0 for unsigned, 1 for\n"
56
" signed (default 1)\n"
57
" --raw, -R Raw (headerless) output.\n"
58
" --output, -o Output to given filename. May only be used\n"
59
" if there is only one input file\n"
66
static void parse_options(int argc, char **argv)
71
while((ret = getopt_long(argc, argv, "Qhvb:e:Rs:o:",
72
long_options, &option_index)) != -1)
84
fprintf(stderr, VERSIONSTRING);
98
endian = atoi(optarg);
101
outfilename = strdup(optarg);
107
fprintf(stderr, "Internal error: Unrecognised argument\n");
113
#define WRITE_U32(buf, x) *(buf) = (unsigned char)((x)&0xff);\
114
*((buf)+1) = (unsigned char)(((x)>>8)&0xff);\
115
*((buf)+2) = (unsigned char)(((x)>>16)&0xff);\
116
*((buf)+3) = (unsigned char)(((x)>>24)&0xff);
118
#define WRITE_U16(buf, x) *(buf) = (unsigned char)((x)&0xff);\
119
*((buf)+1) = (unsigned char)(((x)>>8)&0xff);
121
/* Some of this based on ao/src/ao_wav.c */
122
int write_prelim_header(OggVorbis_File *vf, FILE *out, ogg_int64_t knownlength) {
123
unsigned int size = 0x7fffffff;
124
int channels = ov_info(vf,0)->channels;
125
int samplerate = ov_info(vf,0)->rate;
126
int bytespersec = channels*samplerate*bits/8;
127
int align = channels*bits/8;
128
int samplesize = bits;
130
if(knownlength && knownlength*bits/8*channels < size)
131
size = (unsigned int)(knownlength*bits/8*channels+44) ;
133
memcpy(headbuf, "RIFF", 4);
134
WRITE_U32(headbuf+4, size-8);
135
memcpy(headbuf+8, "WAVE", 4);
136
memcpy(headbuf+12, "fmt ", 4);
137
WRITE_U32(headbuf+16, 16);
138
WRITE_U16(headbuf+20, 1); /* format */
139
WRITE_U16(headbuf+22, channels);
140
WRITE_U32(headbuf+24, samplerate);
141
WRITE_U32(headbuf+28, bytespersec);
142
WRITE_U16(headbuf+32, align);
143
WRITE_U16(headbuf+34, samplesize);
144
memcpy(headbuf+36, "data", 4);
145
WRITE_U32(headbuf+40, size - 44);
147
if(fwrite(headbuf, 1, 44, out) != 44) {
148
fprintf(stderr, "ERROR: Failed to write wav header: %s\n", strerror(errno));
155
int rewrite_header(FILE *out, unsigned int written)
157
unsigned int length = written;
161
WRITE_U32(headbuf+4, length-8);
162
WRITE_U32(headbuf+40, length-44);
163
if(fseek(out, 0, SEEK_SET) != 0)
166
if(fwrite(headbuf, 1, 44, out) != 44) {
167
fprintf(stderr, "ERROR: Failed to write wav header: %s\n", strerror(errno));
173
static int decode_file(char *infile, char *outfile)
180
unsigned int written = 0;
182
ogg_int64_t length = 0;
183
ogg_int64_t done = 0;
190
setmode(fileno(stdin), O_BINARY);
192
_setmode(_fileno(stdin), _O_BINARY);
197
in = fopen(infile, "rb");
199
fprintf(stderr, "ERROR: Failed to open input file: %s\n", strerror(errno));
206
setmode(fileno(stdout), O_BINARY);
208
_setmode(_fileno(stdout), _O_BINARY);
213
out = fopen(outfile, "wb");
215
fprintf(stderr, "ERROR: Failed to open output file: %s\n", strerror(errno));
220
if(ov_open(in, &vf, NULL, 0) < 0) {
221
fprintf(stderr, "ERROR: Failed to open input as vorbis\n");
227
if(ov_seekable(&vf)) {
229
length = ov_pcm_total(&vf, 0);
230
size = bits/8 * ov_info(&vf, 0)->channels;
232
fprintf(stderr, "Decoding \"%s\" to \"%s\"\n",
233
infile?infile:"standard input",
234
outfile?outfile:"standard output");
238
if(write_prelim_header(&vf, out, length)) {
245
while((ret = ov_read(&vf, buf, buflen, endian, bits/8, sign, &bs)) != 0) {
247
fprintf(stderr, "Only one logical bitstream currently supported\n");
251
if(ret < 0 && !quiet) {
252
fprintf(stderr, "Warning: hole in data\n");
256
if(fwrite(buf, 1, ret, out) != ret) {
257
fprintf(stderr, "Error writing to file: %s\n", strerror(errno));
264
if(!quiet && seekable) {
266
if((double)done/(double)length * 200. > (double)percent) {
267
percent = (double)done/(double)length *200;
268
fprintf(stderr, "\r\t[%5.1f%%]", (double)percent/2.);
273
if(seekable && !quiet)
274
fprintf(stderr, "\n");
277
rewrite_header(out, written); /* We don't care if it fails, too late */
285
int main(int argc, char **argv)
290
fprintf(stderr, VERSIONSTRING);
295
parse_options(argc,argv);
298
fprintf(stderr, VERSIONSTRING);
301
fprintf(stderr, "ERROR: No input files specified. Use -h for help\n");
305
if(argc - optind > 1 && outfilename) {
306
fprintf(stderr, "ERROR: Can only specify one input file if output filename is specified\n");
310
for(i=optind; i < argc; i++) {
312
if(!strcmp(argv[i], "-"))
318
if(!strcmp(outfilename, "-"))
324
char *end = strrchr(argv[i], '.');
325
end = end?end:(argv[i] + strlen(argv[i]) + 1);
327
out = malloc(strlen(argv[i]) + 10);
328
strncpy(out, argv[i], end-argv[i]);
329
out[end-argv[i]] = 0;
336
if(decode_file(in,out))