Tracing for tdb operations.
[ccan] / ccan / ogg_to_pcm / ogg_to_pcm.c
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 #if !defined(__APPLE__)
27 /* Apple gets what it needs for malloc from stdlib.h */
28 #include <malloc.h>
29 #endif
30
31 #include <vorbis/vorbisfile.h>
32
33 #define DEFINE_OGG_TO_PCM_GLOBALS
34 #include "ogg_to_pcm.h"
35
36 static const int bits = 16;
37
38 /* Reads an ogg vorbis file, infile, and dumps the data into
39    a big buffer, *pcmbuffer (which it allocates via malloc)
40    and returns the number of samples in *nsamples, and the
41    samplesize in *samplesize. and etc.
42 */
43 int ogg_to_pcm(char *infile, int16_t **pcmbuffer,
44         int *samplesize, int *sample_rate, int *nchannels,
45         uint64_t *nsamples)
46 {
47         FILE *in;
48         OggVorbis_File vf;
49         char buf[8192];
50         unsigned char *bufferptr;
51         int link, ret, chainsallowed = 0, bs = 0;
52
53         /* how to do this portably at compile time? */
54         const uint32_t dummy = 0x01020304;
55         const unsigned char *endian = (unsigned char *) &dummy;
56
57         in = fopen(infile, "r");
58         if (in == NULL) {
59                 fprintf(stderr, "%s:%d ERROR: Failed to open '%s' for read: '%s'\n",
60                         __FILE__, __LINE__, infile, strerror(errno));
61                 return -1;
62         }
63         if (ov_open(in, &vf, NULL, 0) < 0) {
64                 fprintf(stderr, "%s:%d: ERROR: Failed to open '%s' as vorbis\n",
65                         __FILE__, __LINE__, infile);
66                 fclose(in);
67                 return -1;
68         }
69         if (!ov_seekable(&vf)) {
70                 fprintf(stderr, "%s:%d: %s is not seekable.\n",
71                         __FILE__, __LINE__, infile);
72                 fclose(in);
73                 return -1;
74         }
75
76         *nchannels = ov_info(&vf,0)->channels;
77         *sample_rate = ov_info(&vf,0)->rate;
78
79         for (link = 0; link < ov_streams(&vf); link++) {
80                 if (ov_info(&vf, link)->channels == *nchannels &&
81                     ov_info(&vf, link)->rate == *sample_rate) {
82                         chainsallowed = 1;
83                 }
84         }
85
86         if (chainsallowed)
87                 *nsamples = ov_pcm_total(&vf, -1);
88         else
89                 *nsamples = ov_pcm_total(&vf, 0);
90
91         *pcmbuffer = (void *) malloc(sizeof(int16_t) * *nsamples * *nchannels);
92         memset(*pcmbuffer, 0, sizeof(int16_t) * *nsamples * *nchannels);
93         if (*pcmbuffer == NULL) {
94                 fprintf(stderr, "%s:%d: Failed to allocate memory for '%s'\n",
95                         __FILE__, __LINE__, infile);
96                 fclose(in);
97                 return -1;
98         }
99         bufferptr = (unsigned char *) *pcmbuffer;
100
101         while ((ret = ov_read(&vf, buf, sizeof(buf), endian[0] == 0x01, bits/8, 1, &bs)) != 0) {
102                 if (bs != 0) {
103                         vorbis_info *vi = ov_info(&vf, -1);
104                         if (*nchannels != vi->channels || *sample_rate != vi->rate) {
105                                 fprintf(stderr, "%s:%d: Logical bitstreams with changing "
106                                         "parameters are not supported\n",
107                                         __FILE__, __LINE__);
108                                 break;
109                         }
110                 }
111
112                 if(ret < 0 ) {
113                         fprintf(stderr, "%s:%d: Warning: hole in data (%d)\n",
114                                 __FILE__, __LINE__, ret);
115                         continue;
116                 }
117
118                 /* copy the data to the pcmbuffer. */
119                 memcpy(bufferptr, buf, ret);
120                 bufferptr += ret;
121         }
122
123         /* ov_clear closes the file, so don't fclose here, even though we fopen()ed.
124          * libvorbis is weird that way.
125          */
126         ov_clear(&vf);
127
128         return 0;
129 }