Coin Logo Coin3D is Free Software,
published under the BSD 3-clause license.
https://coin3d.github.io
https://www.kongsberg.com/en/kogt/
simage_oggvorbis_reader.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) Kongsberg Oil & Gas Technologies
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif /* HAVE_CONFIG_H */
20 
21 #ifdef SIMAGE_OGGVORBIS_SUPPORT
22 
23 #include <simage.h>
24 #include <simage_private.h>
25 #include <simage_oggvorbis.h>
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 
30 #include <vorbis/codec.h>
31 #include <vorbis/vorbisfile.h>
32 
33 typedef struct {
34  FILE *file;
35  OggVorbis_File vorbisfile;
36  int current_section;
37 } oggvorbis_reader_context;
38 
39 
40 static void
41 oggvorbis_reader_init_context(oggvorbis_reader_context *context)
42 {
43  context->file = NULL;
44  context->current_section = 0;
45 }
46 
47 static void
48 oggvorbis_reader_cleanup_context(oggvorbis_reader_context *context)
49 {
50 }
51 
52 static size_t
53 oggvorbis_reader_read_cb(void *ptr, size_t size, size_t nmemb,
54  void *datasource)
55 {
56  oggvorbis_reader_context *context = (oggvorbis_reader_context *)datasource;
57  return fread(ptr, size, nmemb, context->file);
58 }
59 
60 static int
61 oggvorbis_reader_seek_cb(void *datasource, ogg_int64_t offset, int whence)
62 {
63  oggvorbis_reader_context *context = (oggvorbis_reader_context *)datasource;
64  return fseek(context->file, (int)offset, whence);
65 }
66 
67 static long
68 oggvorbis_reader_tell_cb(void *datasource)
69 {
70  oggvorbis_reader_context *context = (oggvorbis_reader_context *)datasource;
71  return ftell(context->file);
72 }
73 
74 static int
75 oggvorbis_reader_close_cb(void *datasource)
76 {
77  oggvorbis_reader_context *context = (oggvorbis_reader_context *)datasource;
78  if (context->file != NULL)
79  fclose(context->file);
80  context->file = NULL;
81  return 0;
82 }
83 
84 static int
85 oggvorbis_reader_open(oggvorbis_reader_context **contextp,
86  const char *filename)
87 {
88  ov_callbacks callbacks;
89  oggvorbis_reader_context *context;
90 
91  *contextp = (oggvorbis_reader_context *)
92  malloc(sizeof(oggvorbis_reader_context));
93  oggvorbis_reader_init_context(*contextp);
94  context = *contextp;
95 
96  context->file = fopen(filename, "rb");
97  if (context->file == NULL) {
98  oggvorbis_reader_cleanup_context(context);
99  free(context);
100  return 0;
101  }
102 
103  callbacks.read_func = oggvorbis_reader_read_cb;
104  callbacks.seek_func = oggvorbis_reader_seek_cb;
105  callbacks.close_func = oggvorbis_reader_close_cb;
106  callbacks.tell_func = oggvorbis_reader_tell_cb;
107 
108  if(ov_open_callbacks((void *)context, &context->vorbisfile, NULL, 0,
109  callbacks) < 0) {
110  fclose(context->file);
111  context->file = NULL;
112  oggvorbis_reader_cleanup_context(context);
113  free(context);
114  return 0;
115  }
116 
117  return 1;
118 }
119 
120 static int
121 oggvorbis_reader_read(oggvorbis_reader_context *context,
122  char *buffer, int size)
123 {
124  int readsize;
125  int numread;
126  int bigEndian;
127 
128  union {
129  int testWord;
130  char testByte[4];
131  } endianTest;
132 
133  endianTest.testWord = 1;
134  if (endianTest.testByte[0] == 1) {
135  bigEndian = 0; // little endian
136  } else {
137  bigEndian = 1; // big endian
138  }
139 
140 
141  readsize = 0;
142  numread = 0;
143 
144  while (readsize<size) {
145  /* FIXME: Check how libvorbisfile handles odd sizes. The
146  libvorbisfile documentation doesn't say anything about this, so
147  everything might be OK.
148  2002-01-10 thammer.
149  */
150  numread=ov_read(&context->vorbisfile,
151  buffer+readsize,
152  size-readsize, bigEndian, 2, 1,
153  &context->current_section);
154  /* FIXME: Verify that EOF's (and numread=0) are
155  handled correctly. 2003-01-09 thammer
156  */
157  if (numread<=0)
158  return numread;
159  else
160  readsize += numread;
161  }
162 
163  return readsize;
164 }
165 
166 static void
167 oggvorbis_reader_get_stream_info(oggvorbis_reader_context *context,
168  int *channels, int *samplerate)
169 {
170  if (context->file) {
171  vorbis_info * vi;
172  vi = ov_info(&context->vorbisfile,-1);
173  *channels = vi->channels;
174  *samplerate = vi->rate;
175  }
176 }
177 
178 
179 static void
180 oggvorbis_reader_close(oggvorbis_reader_context *context)
181 {
182  if (context->file != NULL)
183  ov_clear(&context->vorbisfile);
184 
185  oggvorbis_reader_cleanup_context(context);
186  free(context);
187 }
188 
189 
190 int
191 oggvorbis_reader_stream_open(const char * filename, s_stream * stream,
192  s_params * params)
193 {
194  oggvorbis_reader_context *context;
195  int channels, samplerate;
196 
197  if (!oggvorbis_reader_open(&context, filename))
198  return 0;
199 
200  s_stream_context_set(stream, (void *)context);
201 
202  oggvorbis_reader_get_stream_info(context, &channels, &samplerate);
204  "channels", S_INTEGER_PARAM_TYPE, channels,
205  "samplerate", S_INTEGER_PARAM_TYPE, samplerate,
206  NULL);
207  return 1;
208 }
209 
210 void *
211 oggvorbis_reader_stream_get(s_stream * stream, void * buffer, int * size, s_params * params)
212 {
213  int ret;
214  oggvorbis_reader_context *context;
215 
216  context = (oggvorbis_reader_context *)s_stream_context_get(stream);
217 
218  if (context != NULL) {
219  ret = oggvorbis_reader_read(context, (char*) buffer, *size);
220  if (ret>0) {
221  *size = ret;
222  return buffer;
223  }
224  /* fixme 20020904 thammer: check params for conversion requests
225  */
226  }
227  *size=0;
228  return NULL;
229 }
230 
231 void
233 {
234  oggvorbis_reader_context *context;
235 
236  context = (oggvorbis_reader_context *)s_stream_context_get(stream);
237  if (context != NULL) {
238  oggvorbis_reader_close(context);
239  }
240 }
241 
242 int
243 oggvorbis_reader_stream_seek(s_stream * stream, int offset, int whence,
244  s_params * params)
245 {
246  oggvorbis_reader_context *context;
247 
248  context = (oggvorbis_reader_context *)s_stream_context_get(stream);
249 
250  if (context != NULL) {
251  if (whence == SIMAGE_SEEK_SET)
252  return ov_pcm_seek(&context->vorbisfile, offset);
253  else
254  return -1;
255  /* FIXME: Support the whence parameter. 2003-03-10 thammer */
256  }
257  else
258  return -1;
259 }
260 
261 int
263 {
264  oggvorbis_reader_context *context;
265 
266  context = (oggvorbis_reader_context *)s_stream_context_get(stream);
267 
268  if (context != NULL) {
269  return ov_pcm_tell(&context->vorbisfile);
270  }
271  else
272  return -1;
273 }
274 
275 #endif /* SIMAGE_OGGVORBIS_SUPPORT */
void oggvorbis_reader_stream_close(s_stream *stream)
void s_params_set(s_params *params,...)
Definition: params.c:187
void s_stream_context_set(s_stream *stream, void *context)
Definition: stream.c:219
int oggvorbis_reader_stream_open(const char *filename, s_stream *stream, s_params *params)
void * oggvorbis_reader_stream_get(s_stream *stream, void *buffer, int *size, s_params *params)
Windows specific information.
int oggvorbis_reader_stream_seek(s_stream *stream, int offset, int whence, s_params *params)
int oggvorbis_reader_stream_tell(s_stream *stream, s_params *params)
void * s_stream_context_get(s_stream *stream)
Definition: stream.c:213
s_params * s_stream_params(s_stream *stream)
Definition: stream.c:204