Mercurial > SDL_sound_CoreAudio
annotate decoders/ogg.c @ 474:c66080364dff
Most decoders now report total sample play time, now. Technically, this
breaks binary compatibility with the 1.0 branch, since it extends the
Sound_Sample struct, but most (all?) programs are just passing pointers
allocated by SDL_sound around, and might be okay.
Source-level compatibility is not broken...yet! :)
--ryan.
-------- Original Message --------
Subject: SDL_sound patch: Finding total length of time of sound file.
Date: Sun, 26 Jan 2003 09:31:17 -0800 (PST)
Hi Ryan,
I am working with Eric Wing and helping him modify
SDL_sound. AS part of our efforts in improving and
enhancing SDL_sound, we like to submit this patch. We
modified the codecs to find the total time of a sound
file. Below is the explanation of the patch. The
patch is appended as an attachment to this email.
* MOTIVATION:
We needed the ability to get the total play time of a
sample (And we noticed that we're not the only ones).
Since SDL_sound blocks direct access to the specific
decoders, there is no way for a user to know this
information short of decoding the whole thing.
Because of this, we believe this will be a useful
addition, even though the accuracy may not be perfect
(subject to each decoder) or the information may not
always be available.
* CONTRIBUTORS:
Wesley Leong (modified the majority of the codecs and
verified the results)
Eric Wing (showed everyone how to do modify codec,
modified mikmod)
Wang Lam (modified a handful of codecs, researched
into specs and int overflow)
Ahilan Anantha (modified a few codecs and helped with
integer math)
* GENERAL ISSUES:
We chose the value to be milliseconds as an Sint32.
Milliseconds because that's what Sound_Seek takes as a
parameter and -1 to allow for instances/codecs where
the value could not be determined. We are
not sure if this is the final convention you want, so
we are willing to work with you on this.
We also expect the total_time field to be set on open
and never again modified by SDL_sound. Users may
access it directly much like the sample buffer and
buffer_size. We thought about recomputing the time
on DecodeAll, but since users may seek or decode small
chunks first, not all the data may be there. So this
is better done by the user. This may be good
information to document.
Currently, all the main codecs are implemented except
for QuickTime.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Sat, 08 May 2004 08:19:50 +0000 |
parents | 30f96c853462 |
children | 3e705c9180e5 |
rev | line source |
---|---|
24 | 1 /* |
2 * SDL_sound -- An abstract sound format decoding API. | |
3 * Copyright (C) 2001 Ryan C. Gordon. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2.1 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 /* | |
21 * Ogg Vorbis decoder for SDL_sound. | |
22 * | |
23 * This driver handles .OGG audio files, and depends on libvorbisfile to | |
24 * do the actual decoding work. libvorbisfile is part of libvorbis, which | |
25 * is part of the Ogg Vorbis project. | |
26 * | |
27 * Ogg Vorbis: http://www.xiph.org/ogg/vorbis/ | |
28 * vorbisfile documentation: http://www.xiph.org/ogg/vorbis/doc/vorbisfile/ | |
29 * | |
184
47cc2de2ae36
Changed reference to "LICENSE" file to "COPYING".
Ryan C. Gordon <icculus@icculus.org>
parents:
149
diff
changeset
|
30 * Please see the file COPYING in the source's root directory. |
24 | 31 * |
32 * This file written by Ryan C. Gordon. (icculus@clutteredmind.org) | |
33 */ | |
34 | |
106
40de367eb59e
Changing my include structure to do this right.
Ryan C. Gordon <icculus@icculus.org>
parents:
104
diff
changeset
|
35 #if HAVE_CONFIG_H |
40de367eb59e
Changing my include structure to do this right.
Ryan C. Gordon <icculus@icculus.org>
parents:
104
diff
changeset
|
36 # include <config.h> |
40de367eb59e
Changing my include structure to do this right.
Ryan C. Gordon <icculus@icculus.org>
parents:
104
diff
changeset
|
37 #endif |
100
6d9fdec2f708
added config.h, added --enable-debug flag, various other changes to the build system
fingolfin
parents:
63
diff
changeset
|
38 |
104
103cfcb3c014
Updated to fix build system problem.
Ryan C. Gordon <icculus@icculus.org>
parents:
100
diff
changeset
|
39 #ifdef SOUND_SUPPORTS_OGG |
103cfcb3c014
Updated to fix build system problem.
Ryan C. Gordon <icculus@icculus.org>
parents:
100
diff
changeset
|
40 |
24 | 41 #include <stdio.h> |
42 #include <stdlib.h> | |
43 #include <string.h> | |
44 #include <math.h> | |
106
40de367eb59e
Changing my include structure to do this right.
Ryan C. Gordon <icculus@icculus.org>
parents:
104
diff
changeset
|
45 |
40de367eb59e
Changing my include structure to do this right.
Ryan C. Gordon <icculus@icculus.org>
parents:
104
diff
changeset
|
46 #include "SDL_sound.h" |
40de367eb59e
Changing my include structure to do this right.
Ryan C. Gordon <icculus@icculus.org>
parents:
104
diff
changeset
|
47 |
40de367eb59e
Changing my include structure to do this right.
Ryan C. Gordon <icculus@icculus.org>
parents:
104
diff
changeset
|
48 #define __SDL_SOUND_INTERNAL__ |
40de367eb59e
Changing my include structure to do this right.
Ryan C. Gordon <icculus@icculus.org>
parents:
104
diff
changeset
|
49 #include "SDL_sound_internal.h" |
40de367eb59e
Changing my include structure to do this right.
Ryan C. Gordon <icculus@icculus.org>
parents:
104
diff
changeset
|
50 |
443 | 51 #include <vorbis/codec.h> |
52 #include <vorbis/vorbisfile.h> | |
24 | 53 |
54 | |
47
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
55 static int OGG_init(void); |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
56 static void OGG_quit(void); |
24 | 57 static int OGG_open(Sound_Sample *sample, const char *ext); |
58 static void OGG_close(Sound_Sample *sample); | |
59 static Uint32 OGG_read(Sound_Sample *sample); | |
221
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
60 static int OGG_rewind(Sound_Sample *sample); |
306
c97be6e1bd27
Added framework for Sound_Seek() support.
Ryan C. Gordon <icculus@icculus.org>
parents:
231
diff
changeset
|
61 static int OGG_seek(Sound_Sample *sample, Uint32 ms); |
24 | 62 |
149
1df5c106504e
Decoders can now list multiple file extensions.
Ryan C. Gordon <icculus@icculus.org>
parents:
122
diff
changeset
|
63 static const char *extensions_ogg[] = { "OGG", NULL }; |
24 | 64 const Sound_DecoderFunctions __Sound_DecoderFunctions_OGG = |
65 { | |
66 { | |
149
1df5c106504e
Decoders can now list multiple file extensions.
Ryan C. Gordon <icculus@icculus.org>
parents:
122
diff
changeset
|
67 extensions_ogg, |
24 | 68 "Ogg Vorbis audio through VorbisFile", |
69 "Ryan C. Gordon <icculus@clutteredmind.org>", | |
70 "http://www.icculus.org/SDL_sound/" | |
71 }, | |
72 | |
221
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
73 OGG_init, /* init() method */ |
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
74 OGG_quit, /* quit() method */ |
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
75 OGG_open, /* open() method */ |
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
76 OGG_close, /* close() method */ |
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
77 OGG_read, /* read() method */ |
306
c97be6e1bd27
Added framework for Sound_Seek() support.
Ryan C. Gordon <icculus@icculus.org>
parents:
231
diff
changeset
|
78 OGG_rewind, /* rewind() method */ |
c97be6e1bd27
Added framework for Sound_Seek() support.
Ryan C. Gordon <icculus@icculus.org>
parents:
231
diff
changeset
|
79 OGG_seek /* seek() method */ |
24 | 80 }; |
81 | |
82 | |
47
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
83 static int OGG_init(void) |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
84 { |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
85 return(1); /* always succeeds. */ |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
86 } /* OGG_init */ |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
87 |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
88 |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
89 static void OGG_quit(void) |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
90 { |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
91 /* it's a no-op. */ |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
92 } /* OGG_quit */ |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
93 |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
94 |
ea58bc3b15d7
Added init() and quit() methods.
Ryan C. Gordon <icculus@icculus.org>
parents:
24
diff
changeset
|
95 |
24 | 96 /* |
97 * These are callbacks from vorbisfile that let them read data from | |
98 * a RWops... | |
99 */ | |
100 | |
63
9669aa13d3e0
Changes in preparation for autoconf, and the RWops wrappers changed to
Ryan C. Gordon <icculus@icculus.org>
parents:
59
diff
changeset
|
101 static size_t RWops_ogg_read(void *ptr, size_t size, size_t nmemb, void *datasource) |
24 | 102 { |
103 return((size_t) SDL_RWread((SDL_RWops *) datasource, ptr, size, nmemb)); | |
104 } /* RWops_ogg_read */ | |
105 | |
122 | 106 static int RWops_ogg_seek(void *datasource, ogg_int64_t offset, int whence) |
24 | 107 { |
108 return(SDL_RWseek((SDL_RWops *) datasource, offset, whence)); | |
109 } /* RWops_ogg_seek */ | |
110 | |
63
9669aa13d3e0
Changes in preparation for autoconf, and the RWops wrappers changed to
Ryan C. Gordon <icculus@icculus.org>
parents:
59
diff
changeset
|
111 static int RWops_ogg_close(void *datasource) |
24 | 112 { |
113 /* do nothing; SDL_sound will delete the RWops at a higher level. */ | |
114 return(0); /* this is success in fclose(), so I guess that's okay. */ | |
115 } /* RWops_ogg_close */ | |
116 | |
63
9669aa13d3e0
Changes in preparation for autoconf, and the RWops wrappers changed to
Ryan C. Gordon <icculus@icculus.org>
parents:
59
diff
changeset
|
117 static long RWops_ogg_tell(void *datasource) |
24 | 118 { |
119 return((long) SDL_RWtell((SDL_RWops *) datasource)); | |
120 } /* RWops_ogg_tell */ | |
121 | |
122 static const ov_callbacks RWops_ogg_callbacks = | |
123 { | |
124 RWops_ogg_read, | |
125 RWops_ogg_seek, | |
126 RWops_ogg_close, | |
127 RWops_ogg_tell | |
128 }; | |
129 | |
130 | |
131 /* Return a human readable version of an VorbisFile error code... */ | |
59
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
132 #if (defined DEBUG_CHATTER) |
24 | 133 static const char *ogg_error(int errnum) |
134 { | |
135 switch(errnum) | |
136 { | |
137 case OV_EREAD: | |
138 return("i/o error"); | |
139 case OV_ENOTVORBIS: | |
140 return("not a vorbis file"); | |
141 case OV_EVERSION: | |
142 return("Vorbis version mismatch"); | |
143 case OV_EBADHEADER: | |
144 return("invalid Vorbis bitstream header"); | |
145 case OV_EFAULT: | |
146 return("internal logic fault in Vorbis library"); | |
147 } /* switch */ | |
148 | |
149 return("unknown error"); | |
150 } /* ogg_error */ | |
59
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
151 #endif |
24 | 152 |
153 static __inline__ void output_ogg_comments(OggVorbis_File *vf) | |
154 { | |
155 #if (defined DEBUG_CHATTER) | |
156 int i; | |
157 vorbis_comment *vc = ov_comment(vf, -1); | |
158 | |
159 if (vc == NULL) | |
160 return; | |
161 | |
59
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
162 SNDDBG(("OGG: vendor == [%s].\n", vc->vendor)); |
24 | 163 for (i = 0; i < vc->comments; i++) |
164 { | |
59
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
165 SNDDBG(("OGG: user comment [%s].\n", vc->user_comments[i])); |
24 | 166 } /* for */ |
167 #endif | |
168 } /* output_ogg_comments */ | |
169 | |
170 | |
171 static int OGG_open(Sound_Sample *sample, const char *ext) | |
172 { | |
173 int rc; | |
474
c66080364dff
Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents:
443
diff
changeset
|
174 double total_time; |
24 | 175 OggVorbis_File *vf; |
176 vorbis_info *info; | |
177 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
178 | |
179 vf = (OggVorbis_File *) malloc(sizeof (OggVorbis_File)); | |
180 BAIL_IF_MACRO(vf == NULL, ERR_OUT_OF_MEMORY, 0); | |
181 | |
182 rc = ov_open_callbacks(internal->rw, vf, NULL, 0, RWops_ogg_callbacks); | |
183 if (rc != 0) | |
184 { | |
59
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
185 SNDDBG(("OGG: can't grok data. reason: [%s].\n", ogg_error(rc))); |
24 | 186 free(vf); |
187 BAIL_MACRO("OGG: Not valid Ogg Vorbis data.", 0); | |
188 } /* if */ | |
189 | |
190 info = ov_info(vf, -1); | |
191 if (info == NULL) | |
192 { | |
193 ov_clear(vf); | |
194 free(vf); | |
195 BAIL_MACRO("OGG: failed to retrieve bitstream info", 0); | |
196 } /* if */ | |
197 | |
59
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
198 SNDDBG(("OGG: Accepting data stream.\n")); |
24 | 199 |
200 output_ogg_comments(vf); | |
59
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
201 SNDDBG(("OGG: bitstream version == (%d).\n", info->version)); |
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
202 SNDDBG(("OGG: bitstream channels == (%d).\n", info->channels)); |
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
203 SNDDBG(("OGG: bitstream sampling rate == (%ld).\n", info->rate)); |
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
204 SNDDBG(("OGG: seekable == {%s}.\n", ov_seekable(vf) ? "TRUE" : "FALSE")); |
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
205 SNDDBG(("OGG: number of logical bitstreams == (%ld).\n", ov_streams(vf))); |
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
206 SNDDBG(("OGG: serial number == (%ld).\n", ov_serialnumber(vf, -1))); |
cd91e1857b42
Changed _D macro to SNDDBG, and fixed a warning if compiling without debug
Ryan C. Gordon <icculus@icculus.org>
parents:
47
diff
changeset
|
207 SNDDBG(("OGG: total seconds of sample == (%f).\n", ov_time_total(vf, -1))); |
24 | 208 |
209 internal->decoder_private = vf; | |
327
aa7f6a110971
Added seek implementation.
Ryan C. Gordon <icculus@icculus.org>
parents:
306
diff
changeset
|
210 sample->flags = SOUND_SAMPLEFLAG_CANSEEK; |
24 | 211 sample->actual.rate = (Uint32) info->rate; |
212 sample->actual.channels = (Uint8) info->channels; | |
474
c66080364dff
Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents:
443
diff
changeset
|
213 total_time = ov_time_total(vf, -1); |
c66080364dff
Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents:
443
diff
changeset
|
214 if (OV_EINVAL == total_time) |
c66080364dff
Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents:
443
diff
changeset
|
215 sample->total_time = -1; |
c66080364dff
Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents:
443
diff
changeset
|
216 else |
c66080364dff
Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents:
443
diff
changeset
|
217 sample->total_time = (Sint32)(total_time * 1000.0 + 0.5); |
c66080364dff
Most decoders now report total sample play time, now. Technically, this
Ryan C. Gordon <icculus@icculus.org>
parents:
443
diff
changeset
|
218 |
24 | 219 |
220 /* | |
221 * Since we might have more than one logical bitstream in the OGG file, | |
222 * and these bitstreams may be in different formats, we might be | |
223 * converting two or three times: once in vorbisfile, once again in | |
224 * SDL_sound, and perhaps a third time to get it to the sound device's | |
225 * format. That's wickedly inefficient. | |
226 * | |
227 * To combat this a little, if the user specified a desired format, we | |
228 * claim that to be the "actual" format of the collection of logical | |
229 * bitstreams. This means that VorbisFile will do a conversion as | |
230 * necessary, and SDL_sound will not. If the user didn't specify a | |
231 * desired format, then we pretend the "actual" format is something that | |
232 * OGG files are apparently commonly encoded in. | |
233 */ | |
234 sample->actual.format = (sample->desired.format == 0) ? | |
235 AUDIO_S16LSB : sample->desired.format; | |
236 return(1); | |
237 } /* OGG_open */ | |
238 | |
239 | |
240 static void OGG_close(Sound_Sample *sample) | |
241 { | |
242 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
243 OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private; | |
244 ov_clear(vf); | |
245 free(vf); | |
246 } /* OGG_close */ | |
247 | |
433
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
248 /* Note: According to the Vorbis documentation: |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
249 * "ov_read() will decode at most one vorbis packet per invocation, |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
250 * so the value returned will generally be less than length." |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
251 * Due to this, for buffer sizes like 16384, SDL_Sound was always getting |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
252 * an underfilled buffer and always setting the EAGAIN flag. |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
253 * Since the SDL_Sound API implies that the entire buffer |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
254 * should be filled unless EOF, additional code has been added |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
255 * to this function to call ov_read() until the buffer is filled. |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
256 * However, there may still be some corner cases where the buffer |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
257 * cannot be entirely filled. So be aware. |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
258 */ |
24 | 259 static Uint32 OGG_read(Sound_Sample *sample) |
260 { | |
261 int rc; | |
262 int bitstream; | |
433
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
263 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; |
24 | 264 OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private; |
433
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
265 |
24 | 266 rc = ov_read(vf, internal->buffer, internal->buffer_size, |
267 ((sample->actual.format & 0x1000) ? 1 : 0), /* bigendian? */ | |
268 ((sample->actual.format & 0xFF) / 8), /* bytes per sample point */ | |
269 ((sample->actual.format & 0x8000) ? 1 : 0), /* signed data? */ | |
270 &bitstream); | |
271 | |
272 /* Make sure the read went smoothly... */ | |
273 if (rc == 0) | |
274 sample->flags |= SOUND_SAMPLEFLAG_EOF; | |
433
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
275 |
24 | 276 else if (rc < 0) |
277 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
278 | |
433
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
279 /* If the buffer isn't filled, keep trying to fill it |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
280 * until no more data can be grabbed */ |
24 | 281 else if ((Uint32) rc < internal->buffer_size) |
433
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
282 { |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
283 /* Creating a pointer to the buffer that denotes where to start |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
284 * writing new data. */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
285 Uint8* buffer_start_point = NULL; |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
286 int total_bytes_read = rc; |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
287 int bytes_remaining = internal->buffer_size - rc; |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
288 |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
289 /* Keep grabbing data until something prevents |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
290 * us from getting more. (Could be EOF, |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
291 * packets are too large to fit in remaining |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
292 * space, or an error.) |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
293 */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
294 while( (rc > 0) && (bytes_remaining > 0) ) |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
295 { |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
296 /* Set buffer pointer to end of last write */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
297 /* All the messiness is to get rid of the warning for |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
298 * dereferencing a void* |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
299 */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
300 buffer_start_point = &(((Uint8*)internal->buffer)[total_bytes_read]); |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
301 rc = ov_read(vf, buffer_start_point, bytes_remaining, |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
302 ((sample->actual.format & 0x1000) ? 1 : 0), /* bigendian? */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
303 ((sample->actual.format & 0xFF) / 8), /* bytes per sample point */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
304 ((sample->actual.format & 0x8000) ? 1 : 0), /* signed data? */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
305 &bitstream); |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
306 /* Make sure rc > 0 because we don't accidently want |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
307 * to change the counters if there was an error |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
308 */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
309 if(rc > 0) |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
310 { |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
311 total_bytes_read += rc; |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
312 bytes_remaining = bytes_remaining - rc; |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
313 } |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
314 } |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
315 /* I think the minimum read size is 2, though I'm |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
316 * not sure about this. (I've hit cases where I |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
317 * couldn't read less than 4.) What I don't want to do is |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
318 * accidently claim we hit EOF when the reason rc == 0 |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
319 * is because the requested amount of data was smaller |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
320 * than the minimum packet size. |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
321 * For now, I will be conservative |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
322 * and not set the EOF flag, and let the next call to |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
323 * this function figure it out. |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
324 * I think the ERROR flag is safe to set because |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
325 * it looks like OGG simply returns 0 if the |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
326 * read size is too small. |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
327 * And in most cases for sensible buffer sizes, |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
328 * this fix will fill the buffer, |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
329 * so we can set the EAGAIN flag without worrying |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
330 * that it will always be set. |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
331 */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
332 if(rc < 0) |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
333 { |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
334 sample->flags |= SOUND_SAMPLEFLAG_ERROR; |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
335 } |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
336 else if(rc == 0) |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
337 { |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
338 /* Do nothing for now until there is a better solution */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
339 /* sample->flags |= SOUND_SAMPLEFLAG_EOF; */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
340 } |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
341 |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
342 /* Test for a buffer underrun. It should occur less frequently |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
343 * now, but it still may happen and not necessarily mean |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
344 * anything useful. */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
345 if ((Uint32) total_bytes_read < internal->buffer_size) |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
346 { |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
347 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
348 } |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
349 /* change rc to the total bytes read so function |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
350 * can return the correct value. |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
351 */ |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
352 rc = total_bytes_read; |
f1c16afd9ebe
Read until buffer is full in Sound_Decode() rather than one packet per call.
Ryan C. Gordon <icculus@icculus.org>
parents:
377
diff
changeset
|
353 } |
24 | 354 |
355 return((Uint32) rc); | |
356 } /* OGG_read */ | |
357 | |
221
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
358 |
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
359 static int OGG_rewind(Sound_Sample *sample) |
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
360 { |
231
d3dc34315ac7
Rewind method implemented by Torbj�rn.
Ryan C. Gordon <icculus@icculus.org>
parents:
221
diff
changeset
|
361 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; |
d3dc34315ac7
Rewind method implemented by Torbj�rn.
Ryan C. Gordon <icculus@icculus.org>
parents:
221
diff
changeset
|
362 OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private; |
d3dc34315ac7
Rewind method implemented by Torbj�rn.
Ryan C. Gordon <icculus@icculus.org>
parents:
221
diff
changeset
|
363 |
d3dc34315ac7
Rewind method implemented by Torbj�rn.
Ryan C. Gordon <icculus@icculus.org>
parents:
221
diff
changeset
|
364 BAIL_IF_MACRO(ov_raw_seek(vf, 0) < 0, ERR_IO_ERROR, 0); |
d3dc34315ac7
Rewind method implemented by Torbj�rn.
Ryan C. Gordon <icculus@icculus.org>
parents:
221
diff
changeset
|
365 return(1); |
221
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
366 } /* OGG_rewind */ |
c9772a9f5271
Initial implementation or stubs for rewind method. Other cleanups.
Ryan C. Gordon <icculus@icculus.org>
parents:
184
diff
changeset
|
367 |
306
c97be6e1bd27
Added framework for Sound_Seek() support.
Ryan C. Gordon <icculus@icculus.org>
parents:
231
diff
changeset
|
368 |
c97be6e1bd27
Added framework for Sound_Seek() support.
Ryan C. Gordon <icculus@icculus.org>
parents:
231
diff
changeset
|
369 static int OGG_seek(Sound_Sample *sample, Uint32 ms) |
c97be6e1bd27
Added framework for Sound_Seek() support.
Ryan C. Gordon <icculus@icculus.org>
parents:
231
diff
changeset
|
370 { |
327
aa7f6a110971
Added seek implementation.
Ryan C. Gordon <icculus@icculus.org>
parents:
306
diff
changeset
|
371 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; |
aa7f6a110971
Added seek implementation.
Ryan C. Gordon <icculus@icculus.org>
parents:
306
diff
changeset
|
372 OggVorbis_File *vf = (OggVorbis_File *) internal->decoder_private; |
aa7f6a110971
Added seek implementation.
Ryan C. Gordon <icculus@icculus.org>
parents:
306
diff
changeset
|
373 double timepos = (((double) ms) / 1000.0); |
aa7f6a110971
Added seek implementation.
Ryan C. Gordon <icculus@icculus.org>
parents:
306
diff
changeset
|
374 BAIL_IF_MACRO(ov_time_seek(vf, timepos) < 0, ERR_IO_ERROR, 0); |
aa7f6a110971
Added seek implementation.
Ryan C. Gordon <icculus@icculus.org>
parents:
306
diff
changeset
|
375 return(1); |
306
c97be6e1bd27
Added framework for Sound_Seek() support.
Ryan C. Gordon <icculus@icculus.org>
parents:
231
diff
changeset
|
376 } /* OGG_seek */ |
c97be6e1bd27
Added framework for Sound_Seek() support.
Ryan C. Gordon <icculus@icculus.org>
parents:
231
diff
changeset
|
377 |
63
9669aa13d3e0
Changes in preparation for autoconf, and the RWops wrappers changed to
Ryan C. Gordon <icculus@icculus.org>
parents:
59
diff
changeset
|
378 #endif /* SOUND_SUPPORTS_OGG */ |
9669aa13d3e0
Changes in preparation for autoconf, and the RWops wrappers changed to
Ryan C. Gordon <icculus@icculus.org>
parents:
59
diff
changeset
|
379 |
9669aa13d3e0
Changes in preparation for autoconf, and the RWops wrappers changed to
Ryan C. Gordon <icculus@icculus.org>
parents:
59
diff
changeset
|
380 |
24 | 381 /* end of ogg.c ... */ |
382 |