23 #include <opus/opusfile.h>
31 int cb_read(
void *stream,
unsigned char *ptr,
int nbytes) {
32 istream *in = (istream *)stream;
33 nassertr(in !=
nullptr, -1);
35 in->read((
char *)ptr, nbytes);
45 int cb_seek(
void *stream, opus_int64 offset,
int whence) {
46 if (!opus_enable_seek) {
50 istream *in = (istream *)stream;
51 nassertr(in !=
nullptr, -1);
55 in->seekg(offset, std::ios::beg);
62 std::streambuf *buf = in->rdbuf();
63 std::streampos pos = buf->pubseekoff(0, std::ios::cur, std::ios::in);
67 if (buf->pubseekoff(0, std::ios::end, std::ios::in) >= 0) {
69 buf->pubseekpos(pos, std::ios::in);
75 in->seekg(offset, std::ios::cur);
79 in->seekg(offset, std::ios::end);
84 <<
"Illegal parameter to seek in cb_seek\n";
90 <<
"Failure to seek to byte " << offset;
94 movies_cat.error(
false)
95 <<
" from current location!\n";
99 movies_cat.error(
false)
100 <<
" from end of file!\n";
104 movies_cat.error(
false) <<
"!\n";
113 opus_int64 cb_tell(
void *stream) {
114 istream *in = (istream *)stream;
115 nassertr(in !=
nullptr, -1);
120 int cb_close(
void *stream) {
121 istream *in = (istream *)stream;
122 nassertr(in !=
nullptr, EOF);
129 static const OpusFileCallbacks callbacks = {cb_read, cb_seek, cb_tell, cb_close};
138 OpusAudioCursor(OpusAudio *src, istream *stream) :
143 nassertv(stream !=
nullptr);
144 nassertv(stream->good());
147 _op = op_open_callbacks((
void *)stream, &callbacks,
nullptr, 0, &error);
148 if (_op ==
nullptr) {
150 <<
"Failed to read Opus file (error code " << error <<
").\n";
154 ogg_int64_t samples = op_pcm_total(_op, -1);
155 if (samples != OP_EINVAL) {
157 _length = (double)samples / 48000.0;
160 _audio_channels = op_channel_count(_op, -1);
163 _can_seek = opus_enable_seek && op_seekable(_op);
164 _can_seek_fast = _can_seek;
174 if (_op !=
nullptr) {
184 void OpusAudioCursor::
186 if (!opus_enable_seek) {
190 t = std::max(t, 0.0);
193 int error = op_pcm_seek(_op, (ogg_int64_t)(t * 48000.0));
196 <<
"Seek failed (error " << error <<
"). Opus stream may not be seekable.\n";
200 _last_seek = op_pcm_tell(_op) / 48000.0;
209 void OpusAudioCursor::
210 read_samples(
int n, int16_t *data) {
211 int16_t *end = data + (n * _audio_channels);
216 int read_samples = op_read(_op, data, end - data, &link);
217 if (read_samples > 0) {
218 data += read_samples * _audio_channels;
219 _samples_read += read_samples;
227 int channels = op_channel_count(_op, link);
228 if (channels != _audio_channels) {
230 <<
"Opus file has inconsistent channel count!\n";
233 _audio_channels = channels;
242 memset(data, 0, (
unsigned char *)end - (
unsigned char *)data);