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