1 /* OggDec
2  *
3  * This program is distributed under the GNU General Public License, version 2.
4  * A copy of this license is included with this source.
5  *
6  * Copyright 2002, Michael Smith <msmith@xiph.org>
7  *
8  */
9 
10 /*
11  *
12  * This code was hacked off of the carcass of oggdec.c, from
13  * the vorbistools-1.2.0 package, and is copyrighted as above,
14  * with the modifications made by me,
15  * (c) Copyright Stephen M. Cameron, 2008,
16  * (and of course also released under the GNU General Public License, version 2.)
17  *
18  */
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <stdint.h>
25 #include <errno.h>
26 
27 #include <vorbis/vorbisfile.h>
28 
29 #define DEFINE_OGG_TO_PCM_GLOBALS
30 #include "ogg_to_pcm.h"
31 
32 static const int bits = 16;
33 
34 /* Reads an ogg vorbis file, infile, and dumps the data into
35    a big buffer, *pcmbuffer (which it allocates via malloc)
36    and returns the number of samples in *nsamples.
37 */
ogg_to_pcm(char * infile,int16_t ** pcmbuffer,int * sample_rate,int * nchannels,uint64_t * nsamples)38 int ogg_to_pcm(char *infile, int16_t **pcmbuffer,
39 	int *sample_rate, int *nchannels,
40 	uint64_t *nsamples)
41 {
42 	OggVorbis_File vf;
43 	char buf[8192];
44 	unsigned char *bufferptr;
45 	int link, ret, chainsallowed = 0, bs = 0;
46 
47 	/* how to do this portably at compile time? */
48 	const uint32_t dummy = 0x01020304;
49 	const unsigned char *endian = (unsigned char *) &dummy;
50 
51 	/* use ov_fopen to avoid runtime conflicts on win32 */
52 	if (ov_fopen(infile, &vf) < 0) {
53 		fprintf(stderr, "%s:%d: ERROR: Failed to open '%s' as vorbis\n",
54 			__FILE__, __LINE__, infile);
55 		ov_clear(&vf);
56 		return -1;
57 	}
58 	if (!ov_seekable(&vf)) {
59 		fprintf(stderr, "%s:%d: %s is not seekable.\n",
60 			__FILE__, __LINE__, infile);
61 		ov_clear(&vf);
62 		return -1;
63 	}
64 
65 	*nchannels = ov_info(&vf,0)->channels;
66 	*sample_rate = ov_info(&vf,0)->rate;
67 
68 	for (link = 0; link < ov_streams(&vf); link++) {
69 		if (ov_info(&vf, link)->channels == *nchannels &&
70 		    ov_info(&vf, link)->rate == *sample_rate) {
71 			chainsallowed = 1;
72 		}
73 	}
74 
75 	if (chainsallowed)
76 		*nsamples = ov_pcm_total(&vf, -1);
77 	else
78 		*nsamples = ov_pcm_total(&vf, 0);
79 
80 	*pcmbuffer = (void *) malloc(sizeof(int16_t) * *nsamples * *nchannels);
81 	memset(*pcmbuffer, 0, sizeof(int16_t) * *nsamples * *nchannels);
82 	if (*pcmbuffer == NULL) {
83 		fprintf(stderr, "%s:%d: Failed to allocate memory for '%s'\n",
84 			__FILE__, __LINE__, infile);
85 		ov_clear(&vf);
86 		return -1;
87 	}
88 	bufferptr = (unsigned char *) *pcmbuffer;
89 
90 	while ((ret = ov_read(&vf, buf, sizeof(buf), endian[0] == 0x01, bits/8, 1, &bs)) != 0) {
91 		if (bs != 0) {
92 			vorbis_info *vi = ov_info(&vf, -1);
93 			if (*nchannels != vi->channels || *sample_rate != vi->rate) {
94 				fprintf(stderr, "%s:%d: Logical bitstreams with changing "
95 					"parameters are not supported\n",
96 					__FILE__, __LINE__);
97 				break;
98 			}
99 		}
100 
101 		if(ret < 0 ) {
102 			fprintf(stderr, "%s:%d: Warning: hole in data (%d)\n",
103 				__FILE__, __LINE__, ret);
104 			continue;
105 		}
106 
107 		/* copy the data to the pcmbuffer. */
108 		memcpy(bufferptr, buf, ret);
109 		bufferptr += ret;
110 	}
111 
112 	/* ov_clear closes the file, so don't fclose here, even though we fopen()ed.
113 	 * libvorbis is weird that way.
114  	 */
115 	ov_clear(&vf);
116 
117 	return 0;
118 }
119