32 VorbisAudioCursor(VorbisAudio *src, istream *stream) :
37 nassertv(stream !=
nullptr);
38 nassertv(stream->good());
41 ov_callbacks callbacks;
42 callbacks.read_func = &cb_read_func;
43 callbacks.close_func = &cb_close_func;
44 callbacks.tell_func = &cb_tell_func;
46 if (vorbis_enable_seek) {
47 callbacks.seek_func = &cb_seek_func;
49 callbacks.seek_func =
nullptr;
52 if (ov_open_callbacks((
void*) stream, &_ov,
nullptr, 0, callbacks) != 0) {
54 <<
"Failed to read Ogg Vorbis file.\n";
58 double time_total = ov_time_total(&_ov, -1);
59 if (time_total != OV_EINVAL) {
63 vorbis_info *vi = ov_info(&_ov, -1);
64 _audio_channels = vi->channels;
65 _audio_rate = vi->rate;
67 _can_seek = vorbis_enable_seek && (ov_seekable(&_ov) != 0);
68 _can_seek_fast = _can_seek;
77 ~VorbisAudioCursor() {
85 void VorbisAudioCursor::
87 if (!vorbis_enable_seek) {
95 if (vorbis_seek_lap) {
96 result = ov_time_seek_lap(&_ov, t);
98 result = ov_time_seek(&_ov, t);
104 if (result == OV_ENOSEEK && t == 0.0) {
105 std::istream *stream = (std::istream *)_ov.datasource;
107 if (stream->rdbuf()->pubseekpos(0, std::ios::in) == (std::streampos)0) {
110 ov_callbacks callbacks = _ov.callbacks;
111 _ov.datasource =
nullptr;
114 if (ov_open_callbacks((
void *)stream, &_ov,
nullptr, 0, callbacks) != 0) {
116 <<
"Failed to reopen Ogg Vorbis file to seek to beginning.\n";
121 vorbis_info *vi = ov_info(&_ov, -1);
122 _audio_channels = vi->channels;
123 _audio_rate = vi->rate;
132 <<
"Seek failed. Ogg Vorbis stream may not be seekable.\n";
135 _last_seek = ov_time_tell(&_ov);
144 void VorbisAudioCursor::
145 read_samples(
int n, int16_t *data) {
146 int desired = n * _audio_channels;
148 char *buffer = (
char*) data;
149 int length = desired * 2;
156 long read_bytes = ov_read(&_ov, buffer, length, 0, 2, 1, &bitstream);
157 if (read_bytes > 0) {
158 buffer += read_bytes;
159 length -= read_bytes;
164 if (_bitstream != bitstream) {
167 vorbis_info *vi = ov_info(&_ov, -1);
168 if (vi->channels != _audio_channels || vi->rate != _audio_rate) {
170 <<
"Ogg Vorbis file has non-matching bitstreams!\n";
173 _audio_channels = vi->channels;
174 _audio_rate = vi->rate;
178 _bitstream = bitstream;
184 memset(buffer, 0, length);
185 n -= length / 2 / _audio_channels;
195 size_t VorbisAudioCursor::
196 cb_read_func(
void *ptr,
size_t size,
size_t nmemb,
void *datasource) {
197 istream *stream = (istream*) datasource;
198 nassertr(stream !=
nullptr, -1);
200 stream->read((
char *)ptr, size * nmemb);
207 return stream->gcount();
214 int VorbisAudioCursor::
215 cb_seek_func(
void *datasource, ogg_int64_t offset,
int whence) {
216 if (!vorbis_enable_seek) {
220 istream *stream = (istream*) datasource;
221 nassertr(stream !=
nullptr, -1);
225 stream->seekg(offset, std::ios::beg);
232 std::streambuf *buf = stream->rdbuf();
233 std::streampos pos = buf->pubseekoff(0, std::ios::cur, std::ios::in);
237 if (buf->pubseekoff(0, std::ios::end, std::ios::in) >= 0) {
239 buf->pubseekpos(pos, std::ios::in);
245 stream->seekg(offset, std::ios::cur);
249 stream->seekg(offset, std::ios::end);
254 <<
"Illegal parameter to seek in VorbisAudioCursor::cb_seek_func\n";
258 if (stream->fail()) {
261 <<
"Failure to seek to byte " << offset;
265 movies_cat.error(
false)
266 <<
" from current location!\n";
270 movies_cat.error(
false)
271 <<
" from end of file!\n";
275 movies_cat.error(
false) <<
"!\n";
288 int VorbisAudioCursor::
289 cb_close_func(
void *datasource) {
290 istream *stream = (istream*) datasource;
291 nassertr(stream !=
nullptr, -1);
304 long VorbisAudioCursor::
305 cb_tell_func(
void *datasource) {
306 istream *stream = (istream*) datasource;
307 nassertr(stream !=
nullptr, -1);
309 return stream->tellg();
312 #endif // HAVE_VORBIS