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