Result SoundSourceOpus::open() { int error = 0; QByteArray qBAFilename = m_qFilename.toLocal8Bit(); m_ptrOpusFile = op_open_file(qBAFilename.constData(), &error); if ( m_ptrOpusFile == NULL ) { qDebug() << "opus: Input does not appear to be an Opus bitstream."; m_lFilelength = 0; return ERR; } // opusfile lib all ways gives you 48000 samplerate and stereo 16 bit sample m_iChannels = 2; this->setBitrate((int)op_bitrate_instant(m_ptrOpusFile)); this->setSampleRate(48000); this->setChannels(m_iChannels); if (m_iChannels > 2) { qDebug() << "opus: No support for more than 2 m_iChannels!"; op_free(m_ptrOpusFile); m_lFilelength = 0; return ERR; } // op_pcm_total returns the total number of frames in the ogg file. The // frame is the channel-independent measure of samples. The total samples in // the file is m_iChannels * ov_pcm_total. rryan 7/2009 I verified this by // hand. a 30 second long 48khz mono ogg and a 48khz stereo ogg both report // 1440000 for op_pcm_total. qint64 ret = op_pcm_total(m_ptrOpusFile, -1) * 2; // qDebug() << m_qFilename << "chan:" << m_iChannels << "sample:" << m_iSampleRate << "LEN:" << ret; if (ret >= 0) { // We pretend that the file is stereo to the rest of the world. m_lFilelength = ret; } else { //error if (ret == OP_EINVAL) { //The file is not seekable. Not sure if any action is needed. qDebug() << "opus: file is not seekable " << m_qFilename; } } return OK; }
static int opusdec_read (DB_fileinfo_t *_info, char *bytes, int size) { opusdec_info_t *info = (opusdec_info_t *)_info; // Work round some streamer limitations and infobar issue #22 if (info->new_track && is_playing_track(info->new_track)) { info->new_track = NULL; send_event(info->it, DB_EV_TRACKINFOCHANGED); info->next_update = -2; } // Don't read past the end of a sub-track int samples_to_read = size / sizeof(float) / _info->fmt.channels; int64_t endsample = deadbeef->pl_item_get_endsample (info->it); if (endsample > 0) { opus_int64 samples_left = endsample - op_pcm_tell (info->opusfile); if (samples_left < samples_to_read) { samples_to_read = (int)samples_left; size = samples_to_read * sizeof(float) * _info->fmt.channels; } } // Read until we have enough bytes to satisfy streamer, or there are none left int bytes_read = 0; int ret = OP_HOLE; int samples_read = 0; while (samples_read < samples_to_read && (ret > 0 || ret == OP_HOLE)) { int nframes = samples_to_read-samples_read; float pcm[nframes * _info->fmt.channels]; int new_link = -1; ret = op_read_float(info->opusfile, pcm, nframes * _info->fmt.channels, &new_link); if (ret < 0) { } else if (new_link != info->cur_bit_stream && !op_seekable (info->opusfile) && new_streaming_link(info, new_link)) { samples_read = samples_to_read; break; } else if (ret > 0) { for (int channel = 0; channel < _info->fmt.channels; channel++) { const float *pcm_channel = &pcm[info->channelmap ? info->channelmap[channel] : channel]; float *ptr = ((float *)bytes + samples_read*_info->fmt.channels) + channel; for (int sample = 0; sample < ret; sample ++, pcm_channel += _info->fmt.channels) { *ptr = *pcm_channel; ptr += _info->fmt.channels; } } samples_read += ret; } } bytes_read = samples_read * sizeof(float) * _info->fmt.channels; info->currentsample += bytes_read / (sizeof (float) * _info->fmt.channels); int64_t startsample = deadbeef->pl_item_get_startsample (info->it); _info->readpos = (float)(op_pcm_tell(info->opusfile) - startsample) / _info->fmt.samplerate; if (info->set_bitrate && _info->readpos > info->next_update) { const int rate = (int)op_bitrate_instant(info->opusfile) / 1000; if (rate > 0) { deadbeef->streamer_set_bitrate(rate); info->next_update = info->next_update <= 0 ? info->next_update + 1 : _info->readpos + 5; } } return bytes_read; }