void AudioPluginCache::load(const QDir &dir) { qDebug() << Q_FUNC_INFO << dir.path(); /* Check that we can access the directory */ if (dir.exists() == false || dir.isReadable() == false) return; /* Loop through all files in the directory */ QStringListIterator it(dir.entryList()); while (it.hasNext() == true) { /* Attempt to load a plugin from the path */ QString fileName(it.next()); QString path = dir.absoluteFilePath(fileName); QPluginLoader loader(path, this); AudioDecoder* ptr = qobject_cast<AudioDecoder*> (loader.instance()); if (ptr != NULL) { qDebug() << "Loaded audio decoder plugin from" << fileName; /* Just append the plugin path to be used at runtime * for dynamic creation of instances */ ptr->initialize(""); m_pluginsPathList << path; loader.unload(); } else qDebug() << "Failed to load plugin: " << loader.errorString(); } }
AudioDecoder * AudioDecoder::CreateDecoderForInputSourceRegion(InputSource *inputSource, SInt64 startingFrame, UInt32 frameCount, UInt32 repeatCount, CFErrorRef *error) { if(NULL == inputSource) return NULL; if(!inputSource->SupportsSeeking()) return NULL; AudioDecoder *decoder = CreateDecoderForInputSource(inputSource, error); if(NULL == decoder) return NULL; if(!decoder->SupportsSeeking()) { delete decoder, decoder = NULL; return NULL; } AudioDecoder *regionDecoder = CreateDecoderForDecoderRegion(decoder, startingFrame, frameCount, repeatCount, error); if(NULL == regionDecoder) { delete decoder, decoder = NULL; return NULL; } return regionDecoder; }
AudioDecoder * AudioDecoder::CreateDecoderForInputSourceRegion(InputSource *inputSource, SInt64 startingFrame, CFErrorRef *error) { if(nullptr == inputSource) return nullptr; if(!inputSource->SupportsSeeking()) return nullptr; AudioDecoder *decoder = CreateDecoderForInputSource(inputSource, error); if(nullptr == decoder) return nullptr; if(!decoder->SupportsSeeking()) { delete decoder, decoder = nullptr; return nullptr; } AudioDecoder *regionDecoder = CreateDecoderForDecoderRegion(decoder, startingFrame, error); if(nullptr == regionDecoder) { delete decoder, decoder = nullptr; return nullptr; } return regionDecoder; }
void AudioItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *) { QMenu menu; QFont menuFont = qApp->font(); menuFont.setPixelSize(14); menu.setFont(menuFont); if (m_audio->getAudioDecoder() != NULL) { AudioDecoder *ad = m_audio->getAudioDecoder(); AudioParameters ap = ad->audioParameters(); if (ap.channels() == 1) m_previewLeftAction->setText(tr("Preview Mono")); menu.addAction(m_previewLeftAction); if (ap.channels() == 2) { m_previewLeftAction->setText(tr("Preview Left Channel")); menu.addAction(m_previewRightAction); menu.addAction(m_previewStereoAction); } menu.addSeparator(); } foreach(QAction *action, getDefaultActions()) menu.addAction(action); menu.exec(QCursor::pos()); }
int AudioOpenAL::music_stream (ALuint buffer) { size_t size = music_decoder->read (music_data, setting.buffer); if (size > 0) { alBufferData (buffer, music_decoder->get_format (), music_data, size, music_decoder->get_frequency ()); } return size; }
void AudioEditor::slotSourceFileClicked() { QString fn; /* Create a file open dialog */ QFileDialog dialog(this); dialog.setWindowTitle(tr("Open Audio File")); dialog.setAcceptMode(QFileDialog::AcceptOpen); /* Append file filters to the dialog */ QStringList extList = Audio::getCapabilities(); QStringList filters; qDebug() << Q_FUNC_INFO << "Extensions: " << extList.join(" "); filters << tr("Audio Files (%1)").arg(extList.join(" ")); #if defined(WIN32) || defined(Q_OS_WIN) filters << tr("All Files (*.*)"); #else filters << tr("All Files (*)"); #endif dialog.setNameFilters(filters); /* Append useful URLs to the dialog */ QList <QUrl> sidebar; sidebar.append(QUrl::fromLocalFile(QDir::homePath())); sidebar.append(QUrl::fromLocalFile(QDir::rootPath())); dialog.setSidebarUrls(sidebar); /* Get file name */ if (dialog.exec() != QDialog::Accepted) return; fn = dialog.selectedFiles().first(); if (fn.isEmpty() == true) return; if (m_audio->isRunning()) m_audio->stopAndWait(); m_audio->setSourceFileName(fn); m_filenameLabel->setText(m_audio->getSourceFileName()); AudioDecoder *adec = m_audio->getAudioDecoder(); if (adec != NULL) { AudioParameters ap = adec->audioParameters(); m_durationLabel->setText(Function::speedToString(m_audio->getDuration())); m_srateLabel->setText(QString("%1 Hz").arg(ap.sampleRate())); m_channelsLabel->setText(QString("%1").arg(ap.channels())); m_bitrateLabel->setText(QString("%1 kb/s").arg(adec->bitrate())); } }
QStringList AudioPluginCache::getSupportedFormats() { QStringList caps; foreach(QString path, m_pluginsPathList) { QPluginLoader loader(path, this); AudioDecoder* ptr = qobject_cast<AudioDecoder*> (loader.instance()); if (ptr != NULL) { ptr->initialize(""); caps << ptr->supportedFormats(); loader.unload(); } }
void scheduler_OnTimer() { if (audio_decoder_->isBusy() == false) { void *data = stream_->ReadAudio(); if (data != nullptr) audio_decoder_->Decode(data); } if (audio_renderer_->isBusy() == false) { void *data = audio_decoder_->getDecodeData(); if (data != nullptr) audio_renderer_->AudioOut(data); } int position = audio_decoder_->getPosition(); void *data = stream_->ReadVideo(position); if (data != nullptr) video_decoder_->Deocde(data); }
bool AudioOpenAL::music_open (MusicType type) { int f; size_t count; count = 0; for (size_t mi = 0; mi < music[type].size (); mi++) { count += music[type][mi].played; } if (count == music[type].size ()) { for (size_t mi = 0; mi < music[type].size (); mi++) { music[type][mi].played = false; } count = 0; } while (count < music[type].size ()) { f = random () % music[type].size (); if (!music[type][f].played) { music[type][f].played = true; count++; music_decoder = new MplayerDecoder (); if (music_decoder->open (music[type][f].filename)) { return true; } logger.warnln ("could not play %s", music[type][f].filename.c_str ()); delete music_decoder; music_decoder = NULL; } } return false; }
void Open(std::string filename) { stream_->Open(filename); audio_decoder_->Open(stream_->getHandle()); video_decoder_->Open(); audio_renderer_->Open(); video_renderer_->Open(); }
QVariant AudioEditor::mediaInfo() const { QVariantMap infoMap; if (m_audio == nullptr) return QVariant(); AudioDecoder *adec = m_audio->getAudioDecoder(); if (adec == nullptr) return QVariant(); AudioParameters ap = adec->audioParameters(); infoMap.insert("duration", Function::speedToString(m_audio->totalDuration())); infoMap.insert("sampleRate", QString("%1 Hz").arg(ap.sampleRate())); infoMap.insert("channels", ap.channels()); infoMap.insert("bitrate", QString("%1 kb/s").arg(adec->bitrate())); return QVariant::fromValue(infoMap); }
void Close() { Stop(); stream_->Close(); audio_decoder_->Close(); video_decoder_->Close(); audio_renderer_->Close(); video_renderer_->Close(); }
void AudioItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *) { QMenu menu; QFont menuFont = qApp->font(); menuFont.setPixelSize(14); menu.setFont(menuFont); if (m_audio->getAudioDecoder() != NULL) { AudioDecoder *ad = m_audio->getAudioDecoder(); AudioParameters ap = ad->audioParameters(); if (ap.channels() == 1) m_previewLeftAction->setText(tr("Preview Mono")); menu.addAction(m_previewLeftAction); if (ap.channels() == 2) { m_previewLeftAction->setText(tr("Preview Left Channel")); menu.addAction(m_previewRightAction); menu.addAction(m_previewStereoAction); } menu.addSeparator(); } menu.addAction(m_alignToCursor); if (isLocked()) { m_lockAction->setText(tr("Unlock item")); m_lockAction->setIcon(QIcon(":/unlock.png")); } else { m_lockAction->setText(tr("Lock item")); m_lockAction->setIcon(QIcon(":/lock.png")); } menu.addAction(m_lockAction); menu.exec(QCursor::pos()); }
void Psp2Audio::SE_Play(std::string const& file, int volume, int pitch) { // Opening file FILE* stream = FileFinder::fopenUTF8(file, "rb"); if (!stream) { Output::Warning("Couldn't open sound file %s", file.c_str()); return; } // Pick the next free SE slot. // Does not need synchronisation int idx = -1; for (int i = 0; i < AUDIO_CHANNELS; ++i) { if (sfx_sounds[i].isPlaying && sfx_sounds[i].isFinished) { idx = i; break; } } if (idx == -1) { fclose(stream); Output::Warning("SE: No free channels available (%s)", file.c_str()); return; } DecodedSound& sfx = sfx_sounds[idx]; sfx.decoder = AudioDecoder::Create(stream, file); if (sfx.decoder == nullptr){ fclose(stream); Output::Warning("Unsupported sound format (%s)", file.c_str()); return; } // Initializing internal audio decoder int audiotype; AudioDecoder* decoder = sfx.decoder.get(); if (!decoder->Open(stream)) { Output::Warning("Error occured in audio decoder (%s)", audio_decoder->GetError().c_str()); return; } decoder->SetLooping(false); AudioDecoder::Format int_format; int samplerate; decoder->SetFormat(48000, AudioDecoder::Format::S16, 2); decoder->GetFormat(samplerate, int_format, audiotype); if (samplerate != 48000) Output::Warning("Cannot resample sound file. Sound will be distorted."); // Check for file audiocodec sfx.isStereo = audiotype == 2; // Setting default streaming values sfx.cur_audiobuf = sfx.audiobuf; decoder->SetPitch(pitch); decoder->SetVolume(volume); // Wait and signal is required to prevent reordering sceKernelWaitSema(SFX_Mutex_ID, 1, NULL); sfx.isPlaying = false; sfx.isFinished = false; sceKernelSignalSema(SFX_Mutex_ID, 1); // Start one SE thread sceKernelSignalSema(SFX_Mutex, 1); }
//TODO: if output is null or dummy, the use duration to wait void AudioThread::run() { DPTR_D(AudioThread); //No decoder or output. No audio output is ok, just display picture if (!d.dec || !d.dec->isAvailable()) return; resetState(); Q_ASSERT(d.clock != 0); AudioDecoder *dec = static_cast<AudioDecoder*>(d.dec); AudioOutput *ao = static_cast<AudioOutput*>(d.writer); int sample_rate = dec->codecContext()->sample_rate; int channels = dec->codecContext()->channels; int csf = channels * sample_rate * sizeof(float); static const double max_len = 0.02; d.last_pts = 0; while (!d.stop) { //TODO: why put it at the end of loop then playNextFrame() not work? if (tryPause()) { //DO NOT continue, or playNextFrame() will fail if (d.stop) break; //the queue is empty and may block. should setBlocking(false) wake up cond empty? } QMutexLocker locker(&d.mutex); Q_UNUSED(locker); if (d.packets.isEmpty() && !d.stop) { d.stop = d.demux_end; if (d.stop) { break; } } Packet pkt = d.packets.take(); //wait to dequeue if (!pkt.isValid()) { qDebug("Invalid packet! flush audio codec context!!!!!!!!"); dec->flush(); continue; } d.clock->updateValue(pkt.pts); //DO NOT decode and convert if ao is not available or mute! if (dec->decode(pkt.data)) { QByteArray decoded(dec->data()); int decodedSize = decoded.size(); int decodedPos = 0; qreal delay =0; while (decodedSize > 0) { int chunk = qMin(decodedSize, int(max_len*csf)); d.clock->updateDelay(delay += (qreal)chunk/(qreal)csf); QByteArray decodedChunk(chunk, 0); //volume == 0 || mute if (ao && ao->isAvailable()) { if (!ao->isMute()) { decodedChunk = QByteArray::fromRawData(decoded.constData() + decodedPos, chunk); qreal vol = ao->volume(); if (vol != 1.0) { int len = decodedChunk.size()/sizeof(float); //TODO: why??? float *data = (float*)decodedChunk.data(); for (int i = 0; i < len; ++i) data[i] *= vol; } } ao->writeData(decodedChunk); } else { /* * why need this even if we add delay? and usleep sounds weird * the advantage is if no audio device, the play speed is ok too * So is portaudio blocking the thread when playing? */ static bool sWarn_no_ao = true; //FIXME: no warning when replay. warn only once if (sWarn_no_ao) { qDebug("Audio output not available! msleep(%lu)", (unsigned long)((qreal)chunk/(qreal)csf * 1000)); sWarn_no_ao = false; } //TODO: avoid acummulative error. External clock? msleep((unsigned long)((qreal)chunk/(qreal)csf * 1000.0)); } decodedPos += chunk; decodedSize -= chunk; } } else { //qWarning("Decode audio failed"); qreal dt = pkt.pts - d.last_pts; if (abs(dt) > 0.618 || dt < 0) { dt = 0; } //qDebug("sleep %f", dt); //TODO: avoid acummulative error. External clock? msleep((unsigned long)(dt*1000.0)); } d.last_pts = d.clock->value(); //not pkt.pts! the delay is updated! } qDebug("Audio thread stops running..."); }
void AudioItem::createWaveform(bool left, bool right) { if ((left == true || right == true) && m_audio->getAudioDecoder() != NULL) { AudioDecoder *ad = m_audio->getAudioDecoder(); AudioParameters ap = ad->audioParameters(); // 1- find out how many samples have to be represented on a single pixel on a 1:1 time scale int sampleSize = ap.sampleSize(); int channels = ap.channels(); int oneSecondSamples = ap.sampleRate() * channels; int onePixelSamples = oneSecondSamples / 50; //qint32 maxValue = qPow(0xFF, sampleSize); qint32 maxValue = 0; if (left == true && right == true) maxValue = 0x7F << (8 * (sampleSize - 1)); else maxValue = 0x3F << (8 * (sampleSize - 1)); quint32 defaultDataLen = onePixelSamples * sampleSize; // 2- decode the whole file and fill a QPixmap with a sample block RMS value for each pixel qint64 dataRead = 1; unsigned char audioData[defaultDataLen * 4]; quint32 audioDataOffset = 0; m_preview = new QPixmap((50 * m_audio->totalDuration()) / 1000, 76); m_preview->fill(Qt::transparent); QPainter p(m_preview); int xpos = 0; qDebug() << "Audio duration: " << m_audio->totalDuration() << ", pixmap width: " << ((50 * m_audio->totalDuration()) / 1000) << ", maxValue: " << maxValue; qDebug() << "Samples per second: " << oneSecondSamples << ", for one pixel: " << onePixelSamples; while (dataRead) { quint32 tmpExceedData = 0; if (audioDataOffset < defaultDataLen) { dataRead = ad->read((char *)audioData + audioDataOffset, defaultDataLen * 2); if (dataRead > 0) { if(dataRead + audioDataOffset >= defaultDataLen) { tmpExceedData = dataRead + audioDataOffset - defaultDataLen; dataRead = defaultDataLen; } else { audioDataOffset = dataRead; continue; } } } else { dataRead = defaultDataLen; tmpExceedData = audioDataOffset - defaultDataLen; } if (dataRead > 0) { quint32 i = 0; // calculate the RMS value (peak) for this data block double rmsLeft = 0; double rmsRight = 0; bool done = false; while (!done) { if (left == true) { qint32 sampleVal = getSample(audioData, &i, sampleSize); rmsLeft += (sampleVal * sampleVal); } if (channels == 2) { if (right == true) { qint32 sampleVal = getSample(audioData, &i, sampleSize); rmsRight += (sampleVal * sampleVal); } else getSample(audioData, &i, sampleSize); // got to read it anyway and discard data } if (i >= dataRead / sampleSize) done = true; } quint32 divisor = (dataRead / sampleSize) / channels; if (left == true) rmsLeft = sqrt(rmsLeft / divisor); if (right == true) rmsRight = sqrt(rmsRight / divisor); // 3- Draw the actual waveform unsigned short lineHeightLeft = 0, lineHeightRight = 0; if (left == true) lineHeightLeft = (76 * rmsLeft) / maxValue; if (right == true) lineHeightRight = (76 * rmsRight) / maxValue; if (left == true && right == true) { if (lineHeightLeft > 1) p.drawLine(xpos, 19 - (lineHeightLeft / 2), xpos, 19 + (lineHeightLeft / 2)); else p.drawLine(xpos, 19, xpos + 1, 19); if (lineHeightRight > 1) p.drawLine(xpos, 51 - (lineHeightRight / 2), xpos, 51 + (lineHeightRight / 2)); else p.drawLine(xpos, 51, xpos + 1, 51); } else { unsigned short lineHeight = 0; if (left == true) lineHeight = lineHeightLeft; else lineHeight = lineHeightRight; if (lineHeight > 1) p.drawLine(xpos, 38 - (lineHeight / 2), xpos, 38 + (lineHeight / 2)); else p.drawLine(xpos, 38, xpos + 1, 38); //qDebug() << "Data read: " << dataRead << ", rms: " << rms << ", line height: " << lineHeight << ", xpos = " << xpos; } xpos++; if (tmpExceedData > 0) { //qDebug() << "Exceed data found: " << tmpExceedData; memmove(audioData, audioData + defaultDataLen, tmpExceedData); audioDataOffset = tmpExceedData; } else audioDataOffset = 0; } } //qDebug() << "Iterations done: " << xpos; ad->seek(0); } else // no preview selected. Delete pixmap { delete m_preview; m_preview = NULL; } update(); }
/* *TODO: * if output is null or dummy, the use duration to wait */ void AudioThread::run() { DPTR_D(AudioThread); //No decoder or output. No audio output is ok, just display picture if (!d.dec || !d.dec->isAvailable() || !d.outputSet) return; resetState(); Q_ASSERT(d.clock != 0); AudioDecoder *dec = static_cast<AudioDecoder*>(d.dec); AudioOutput *ao = 0; // first() is not null even if list empty if (!d.outputSet->outputs().isEmpty()) ao = static_cast<AudioOutput*>(d.outputSet->outputs().first()); //TODO: not here d.init(); //TODO: bool need_sync in private class bool is_external_clock = d.clock->clockType() == AVClock::ExternalClock; Packet pkt; while (!d.stop) { processNextTask(); //TODO: why put it at the end of loop then playNextFrame() not work? if (tryPause()) { //DO NOT continue, or playNextFrame() will fail if (d.stop) break; //the queue is empty and may block. should setBlocking(false) wake up cond empty? } else { if (isPaused()) continue; } if (d.packets.isEmpty() && !d.stop) { d.stop = d.demux_end; } if (d.stop) { qDebug("audio thread stop before take packet"); break; } if (!pkt.isValid()) { pkt = d.packets.take(); //wait to dequeue } if (!pkt.isValid()) { qDebug("Invalid packet! flush audio codec context!!!!!!!! audio queue size=%d", d.packets.size()); dec->flush(); continue; } bool skip_render = pkt.pts < d.render_pts0; // audio has no key frame, skip rendering equals to skip decoding if (skip_render) { d.clock->updateValue(pkt.pts); /* * audio may be too fast than video if skip without sleep * a frame is about 20ms. sleep time must be << frame time */ qreal a_v = pkt.pts - d.clock->videoPts(); //qDebug("skip audio decode at %f/%f v=%f a-v=%f", pkt.pts, d.render_pts0, d.clock->videoPts(), a_v); if (a_v > 0) msleep(qMin((ulong)300, ulong(a_v*1000.0))); else msleep(2); pkt = Packet(); //mark invalid to take next continue; } d.render_pts0 = 0; if (is_external_clock) { d.delay = pkt.pts - d.clock->value(); /* *after seeking forward, a packet may be the old, v packet may be *the new packet, then the d.delay is very large, omit it. *TODO: 1. how to choose the value * 2. use last delay when seeking */ if (qAbs(d.delay) < 2.718) { if (d.delay < -kSyncThreshold) { //Speed up. drop frame? //continue; } while (d.delay > kSyncThreshold) { //Slow down //d.delay_cond.wait(&d.mutex, d.delay*1000); //replay may fail. why? //qDebug("~~~~~wating for %f msecs", d.delay*1000); usleep(kSyncThreshold * 1000000UL); if (d.stop) d.delay = 0; else d.delay -= kSyncThreshold; } if (d.delay > 0) usleep(d.delay * 1000000UL); } else { //when to drop off? if (d.delay > 0) { msleep(64); } else { //audio packet not cleaned up? continue; } } } else { d.clock->updateValue(pkt.pts); } //DO NOT decode and convert if ao is not available or mute! bool has_ao = ao && ao->isAvailable(); //if (!has_ao) {//do not decode? // TODO: move resampler to AudioFrame, like VideoFrame does if (has_ao && dec->resampler()) { if (dec->resampler()->speed() != ao->speed() || dec->resampler()->outAudioFormat() != ao->audioFormat()) { //resample later to ensure thread safe. TODO: test if (d.resample) { qDebug("decoder set speed: %.2f", ao->speed()); dec->resampler()->setOutAudioFormat(ao->audioFormat()); dec->resampler()->setSpeed(ao->speed()); dec->resampler()->prepare(); d.resample = false; } else { d.resample = true; } } } else { if (dec->resampler() && dec->resampler()->speed() != d.clock->speed()) { if (d.resample) { qDebug("decoder set speed: %.2f", d.clock->speed()); dec->resampler()->setSpeed(d.clock->speed()); dec->resampler()->prepare(); d.resample = false; } else { d.resample = true; } } } if (d.stop) { qDebug("audio thread stop before decode()"); break; } QMutexLocker locker(&d.mutex); Q_UNUSED(locker); if (!dec->decode(pkt.data)) { qWarning("Decode audio failed"); qreal dt = pkt.pts - d.last_pts; if (dt > 0.618 || dt < 0) { dt = 0; } //qDebug("sleep %f", dt); //TODO: avoid acummulative error. External clock? msleep((unsigned long)(dt*1000.0)); pkt = Packet(); d.last_pts = d.clock->value(); //not pkt.pts! the delay is updated! continue; } QByteArray decoded(dec->data()); int decodedSize = decoded.size(); int decodedPos = 0; qreal delay = 0; //AudioFormat.durationForBytes() calculates int type internally. not accurate AudioFormat &af = dec->resampler()->inAudioFormat(); qreal byte_rate = af.bytesPerSecond(); while (decodedSize > 0) { if (d.stop) { qDebug("audio thread stop after decode()"); break; } // TODO: set to format.bytesPerFrame()*1024? const int chunk = qMin(decodedSize, has_ao ? ao->bufferSize() : 1024*4);//int(max_len*byte_rate)); //AudioFormat.bytesForDuration const qreal chunk_delay = (qreal)chunk/(qreal)byte_rate; pkt.pts += chunk_delay; QByteArray decodedChunk(chunk, 0); //volume == 0 || mute if (has_ao) { //TODO: volume filter and other filters!!! if (!ao->isMute()) { decodedChunk = QByteArray::fromRawData(decoded.constData() + decodedPos, chunk); qreal vol = ao->volume(); if (vol != 1.0) { int len = decodedChunk.size()/ao->audioFormat().bytesPerSample(); switch (ao->audioFormat().sampleFormat()) { case AudioFormat::SampleFormat_Unsigned8: case AudioFormat::SampleFormat_Unsigned8Planar: { quint8 *data = (quint8*)decodedChunk.data(); //TODO: other format? for (int i = 0; i < len; data[i++] *= vol) {} } break; case AudioFormat::SampleFormat_Signed16: case AudioFormat::SampleFormat_Signed16Planar: { qint16 *data = (qint16*)decodedChunk.data(); //TODO: other format? for (int i = 0; i < len; data[i++] *= vol) {} } break; case AudioFormat::SampleFormat_Signed32: case AudioFormat::SampleFormat_Signed32Planar: { qint32 *data = (qint32*)decodedChunk.data(); //TODO: other format? for (int i = 0; i < len; data[i++] *= vol) {} } break; case AudioFormat::SampleFormat_Float: case AudioFormat::SampleFormat_FloatPlanar: { float *data = (float*)decodedChunk.data(); //TODO: other format? for (int i = 0; i < len; data[i++] *= vol) {} } break; case AudioFormat::SampleFormat_Double: case AudioFormat::SampleFormat_DoublePlanar: { double *data = (double*)decodedChunk.data(); //TODO: other format? for (int i = 0; i < len; data[i++] *= vol) {} } break; default: break; } } } ao->waitForNextBuffer(); ao->receiveData(decodedChunk, pkt.pts); ao->play(); d.clock->updateValue(ao->timestamp()); } else { d.clock->updateDelay(delay += chunk_delay); /* * why need this even if we add delay? and usleep sounds weird * the advantage is if no audio device, the play speed is ok too * So is portaudio blocking the thread when playing? */ static bool sWarn_no_ao = true; //FIXME: no warning when replay. warn only once if (sWarn_no_ao) { qDebug("Audio output not available! msleep(%lu)", (unsigned long)((qreal)chunk/(qreal)byte_rate * 1000)); sWarn_no_ao = false; } //TODO: avoid acummulative error. External clock? msleep((unsigned long)(chunk_delay * 1000.0)); } decodedPos += chunk; decodedSize -= chunk; } int undecoded = dec->undecodedSize(); if (undecoded > 0) { pkt.data.remove(0, pkt.data.size() - undecoded); } else { pkt = Packet(); } d.last_pts = d.clock->value(); //not pkt.pts! the delay is updated! } qDebug("Audio thread stops running..."); }
AudioDecoder * AudioDecoder::CreateDecoderForInputSource(InputSource *inputSource, CFStringRef mimeType, CFErrorRef *error) { if(NULL == inputSource) return NULL; AudioDecoder *decoder = NULL; // Open the input source if it isn't already if(AutomaticallyOpenDecoders() && !inputSource->IsOpen() && !inputSource->Open(error)) return NULL; // As a factory this class has knowledge of its subclasses // It would be possible (and perhaps preferable) to switch to a generic // plugin interface at a later date #if 0 // If the input is an instance of HTTPInputSource, use the MIME type from the server // This code is disabled because most HTTP servers don't send the correct MIME types HTTPInputSource *httpInputSource = dynamic_cast<HTTPInputSource *>(inputSource); bool releaseMIMEType = false; if(!mimeType && httpInputSource && httpInputSource->IsOpen()) { mimeType = httpInputSource->CopyContentMIMEType(); if(mimeType) releaseMIMEType = true; } #endif // The MIME type takes precedence over the file extension if(mimeType) { #if BUILD_FOR_MAC_OSX if(FLACDecoder::HandlesMIMEType(mimeType)) { decoder = new FLACDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && WavPackDecoder::HandlesMIMEType(mimeType)) { decoder = new WavPackDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && MPEGDecoder::HandlesMIMEType(mimeType)) { decoder = new MPEGDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && OggVorbisDecoder::HandlesMIMEType(mimeType)) { decoder = new OggVorbisDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && MusepackDecoder::HandlesMIMEType(mimeType)) { decoder = new MusepackDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && MonkeysAudioDecoder::HandlesMIMEType(mimeType)) { decoder = new MonkeysAudioDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && OggSpeexDecoder::HandlesMIMEType(mimeType)) { decoder = new OggSpeexDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && MODDecoder::HandlesMIMEType(mimeType)) { decoder = new MODDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && LibsndfileDecoder::HandlesMIMEType(mimeType)) { decoder = new LibsndfileDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } #endif if(NULL == decoder && CoreAudioDecoder::HandlesMIMEType(mimeType)) { decoder = new CoreAudioDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } #if 0 if(releaseMIMEType) CFRelease(mimeType), mimeType = NULL; #endif if(decoder) return decoder; } // If no MIME type was specified, use the extension-based resolvers CFURLRef inputURL = inputSource->GetURL(); if(!inputURL) return NULL; CFStringRef pathExtension = CFURLCopyPathExtension(inputURL); if(!pathExtension) { if(error) { CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 32, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFStringRef displayName = CFURLCopyLastPathComponent(inputURL); CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFCopyLocalizedString(CFSTR("The type of the file “%@” could not be determined."), ""), displayName); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedDescriptionKey, errorString); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedFailureReasonKey, CFCopyLocalizedString(CFSTR("Unknown file type"), "")); CFDictionarySetValue(errorDictionary, kCFErrorLocalizedRecoverySuggestionKey, CFCopyLocalizedString(CFSTR("The file's extension may be missing or may not match the file's type."), "")); CFRelease(errorString), errorString = NULL; CFRelease(displayName), displayName = NULL; *error = CFErrorCreate(kCFAllocatorDefault, InputSourceErrorDomain, InputSourceFileNotFoundError, errorDictionary); CFRelease(errorDictionary), errorDictionary = NULL; } return NULL; } // TODO: Some extensions (.oga for example) support multiple audio codecs (Vorbis, FLAC, Speex) // and if openDecoder is false the wrong decoder type may be returned, since the file isn't analyzed // until Open() is called #if BUILD_FOR_MAC_OSX if(FLACDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new FLACDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && WavPackDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new WavPackDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && MPEGDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new MPEGDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && OggVorbisDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new OggVorbisDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && MusepackDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new MusepackDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && MonkeysAudioDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new MonkeysAudioDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && OggSpeexDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new OggSpeexDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && MODDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new MODDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } if(NULL == decoder && LibsndfileDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new LibsndfileDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } #endif if(NULL == decoder && CoreAudioDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new CoreAudioDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = NULL; delete decoder, decoder = NULL; } } CFRelease(pathExtension), pathExtension = NULL; return decoder; }
StreamTranscoder::StreamTranscoder( IInputStream& inputStream, IOutputFile& outputFile, const ProfileLoader::Profile& profile, const int subStreamIndex, const double offset ) : _inputStream( &inputStream ) , _outputStream( NULL ) , _sourceBuffer( NULL ) , _frameBuffer( NULL ) , _inputDecoder( NULL ) , _generator( NULL ) , _currentDecoder( NULL ) , _outputEncoder( NULL ) , _transform( NULL ) , _subStreamIndex( subStreamIndex ) , _offset( offset ) , _canSwitchToGenerator( false ) { // create a transcode case switch( _inputStream->getStreamType() ) { case AVMEDIA_TYPE_VIDEO : { // input decoder VideoDecoder* inputVideo = new VideoDecoder( *static_cast<InputStream*>( _inputStream ) ); // set decoder options with empty profile to set some key options to specific values (example: threads to auto) inputVideo->setProfile( ProfileLoader::Profile() ); inputVideo->setup(); _inputDecoder = inputVideo; _currentDecoder = _inputDecoder; // output encoder VideoEncoder* outputVideo = new VideoEncoder( profile.at( constants::avProfileCodec ) ); _outputEncoder = outputVideo; VideoFrameDesc outputFrameDesc = _inputStream->getVideoCodec().getVideoFrameDesc(); outputFrameDesc.setParameters( profile ); outputVideo->setProfile( profile, outputFrameDesc ); // output stream _outputStream = &outputFile.addVideoStream( outputVideo->getVideoCodec() ); // buffers to process _sourceBuffer = new VideoFrame( _inputStream->getVideoCodec().getVideoFrameDesc() ); _frameBuffer = new VideoFrame( outputVideo->getVideoCodec().getVideoFrameDesc() ); // transform _transform = new VideoTransform(); // generator decoder VideoGenerator* generatorVideo = new VideoGenerator(); generatorVideo->setVideoFrameDesc( outputVideo->getVideoCodec().getVideoFrameDesc() ); _generator = generatorVideo; break; } case AVMEDIA_TYPE_AUDIO : { // input decoder AudioDecoder* inputAudio = new AudioDecoder( *static_cast<InputStream*>( _inputStream ) ); // set decoder options with empty profile to set some key options to specific values (example: threads to auto) inputAudio->setProfile( ProfileLoader::Profile() ); inputAudio->setup(); _inputDecoder = inputAudio; _currentDecoder = _inputDecoder; // output encoder AudioEncoder* outputAudio = new AudioEncoder( profile.at( constants::avProfileCodec ) ); _outputEncoder = outputAudio; AudioFrameDesc outputFrameDesc( _inputStream->getAudioCodec().getAudioFrameDesc() ); outputFrameDesc.setParameters( profile ); if( subStreamIndex > -1 ) { // @todo manage downmix ? outputFrameDesc.setChannels( 1 ); } outputAudio->setProfile( profile, outputFrameDesc ); // output stream _outputStream = &outputFile.addAudioStream( outputAudio->getAudioCodec() ); // buffers to process AudioFrameDesc inputFrameDesc( _inputStream->getAudioCodec().getAudioFrameDesc() ); if( subStreamIndex > -1 ) inputFrameDesc.setChannels( 1 ); _sourceBuffer = new AudioFrame( inputFrameDesc ); _frameBuffer = new AudioFrame( outputAudio->getAudioCodec().getAudioFrameDesc() ); // transform _transform = new AudioTransform(); // generator decoder AudioGenerator* generatorAudio = new AudioGenerator(); generatorAudio->setAudioFrameDesc( outputAudio->getAudioCodec().getAudioFrameDesc() ); _generator = generatorAudio; break; } default: { throw std::runtime_error( "unupported stream type" ); break; } } if( offset ) switchToGeneratorDecoder(); }
void AudioPlayer::rotateBufferThread(int offsetFrame) { char* tmpBuffer = nullptr; AudioDecoder* decoder = AudioDecoderManager::createDecoder(_audioCache->_fileFullPath.c_str()); do { BREAK_IF(decoder == nullptr || !decoder->open(_audioCache->_fileFullPath.c_str())); uint32_t framesRead = 0; const uint32_t framesToRead = _audioCache->_queBufferFrames; const uint32_t bufferSize = framesToRead * decoder->getBytesPerFrame(); tmpBuffer = (char*)malloc(bufferSize); memset(tmpBuffer, 0, bufferSize); if (offsetFrame != 0) { decoder->seek(offsetFrame); } ALint sourceState; ALint bufferProcessed = 0; bool needToExitThread = false; while (!_isDestroyed) { alGetSourcei(_alSource, AL_SOURCE_STATE, &sourceState); if (sourceState == AL_PLAYING) { alGetSourcei(_alSource, AL_BUFFERS_PROCESSED, &bufferProcessed); while (bufferProcessed > 0) { bufferProcessed--; if (_timeDirty) { _timeDirty = false; offsetFrame = _currTime * decoder->getSampleRate(); decoder->seek(offsetFrame); } else { _currTime += QUEUEBUFFER_TIME_STEP; if (_currTime > _audioCache->_duration) { if (_loop) { _currTime = 0.0f; } else { _currTime = _audioCache->_duration; } } } framesRead = decoder->readFixedFrames(framesToRead, tmpBuffer); if (framesRead == 0) { if (_loop) { decoder->seek(0); framesRead = decoder->readFixedFrames(framesToRead, tmpBuffer); } else { needToExitThread = true; break; } } ALuint bid; alSourceUnqueueBuffers(_alSource, 1, &bid); alBufferData(bid, _audioCache->_format, tmpBuffer, framesRead * decoder->getBytesPerFrame(), decoder->getSampleRate()); alSourceQueueBuffers(_alSource, 1, &bid); } } std::unique_lock<std::mutex> lk(_sleepMutex); if (_isDestroyed || needToExitThread) { break; } _sleepCondition.wait_for(lk,std::chrono::milliseconds(75)); } } while(false); ALOGV("Exit rotate buffer thread ..."); if (decoder != nullptr) { decoder->close(); } AudioDecoderManager::destroyDecoder(decoder); free(tmpBuffer); _isRotateThreadExited = true; ALOGV("%s exited.\n", __FUNCTION__); }
bool sbsms_convert(const char *filenameIn, const char *filenameOut, bool bAnalyze, bool bSynthesize, progress_cb progressCB, void *data, float rate0, float rate1, float pitch0, float pitch1, float volume) { bool status = true; int srOut = 44100; long blockSize; int channels; SampleCountType samplesIn; int srIn; SampleCountType samplesToOutput; SampleCountType samplesToInput; bool bRead = false; bool bWrite = false; audio *abuf = NULL; float *fbuf = NULL; SBSMSInterface *iface = NULL; SBSMSInterface *ifacePre = NULL; SBSMS *sbsms = NULL; PcmWriter *writer = NULL; AudioDecoder *decoder = NULL; AudioDecoder *decoderPre = NULL; SBSMSQuality quality(&SBSMSQualityStandard); Slide rateSlide(SlideLinearInputRate,rate0,rate1); Slide pitchSlide(SlideLinearOutputRate,pitch0,pitch1); if(bAnalyze) { float preProgress = 0.0f; decoder = import(filenameIn); if(!decoder) { printf("File: %s cannot be opened\n",filenameIn); exit(-1); } srIn = decoder->getSampleRate(); channels = decoder->getChannels(); samplesIn = decoder->getFrames(); samplesToInput = (SampleCountType) (samplesIn*(float)srOut/(float)srIn); float pitch = (srOut == srIn?1.0f:(float)srOut / (float)srIn); iface = new SBSMSInterfaceDecoder(&rateSlide,&pitchSlide,false, channels,samplesToInput,0,&quality,decoder,pitch); sbsms = new SBSMS(channels,&quality,bSynthesize); samplesToOutput = iface->getSamplesToOutput(); if(bSynthesize) { blockSize = quality.getFrameSize(); fbuf = (float*)calloc(blockSize*channels,sizeof(float)); abuf = (audio*)calloc(blockSize,sizeof(audio)); writer = new PcmWriter(filenameOut,samplesToOutput,srOut,channels); if(writer->isError()) { printf("File: %s cannot be opened\n",filenameOut); status = false; goto cleanup; } SampleCountType pos = 0; long ret = -1; while(pos<samplesToOutput && ret) { long lastPercent=0; ret = sbsms->read(iface,abuf,blockSize); if(pos+ret > samplesToOutput) { ret = (long)(samplesToOutput - pos); } audio_convert_from(fbuf,0,abuf,0,ret,channels); for(int k=0;k<ret*channels;k++) { fbuf[k] *= volume; } if(ret) writer->write(fbuf, ret); pos += ret; float progress = (float)pos / (float)samplesToOutput; progressCB(progress,"Progress",data); } writer->close(); } } cleanup: if(decoderPre) delete decoderPre; if(decoder) delete decoder; if(fbuf) free(fbuf); if(abuf) free(abuf); if(sbsms) delete sbsms; if(iface) delete iface; if(ifacePre) delete ifacePre; if(writer) delete writer; return status; }
AudioEditor::AudioEditor(QWidget* parent, Audio *audio, Doc* doc) : QWidget(parent) , m_doc(doc) , m_audio(audio) , m_speedDials(NULL) { Q_ASSERT(doc != NULL); Q_ASSERT(audio != NULL); setupUi(this); m_nameEdit->setText(m_audio->name()); m_nameEdit->setSelection(0, m_nameEdit->text().length()); m_fadeInEdit->setText(Function::speedToString(audio->fadeInSpeed())); m_fadeOutEdit->setText(Function::speedToString(audio->fadeOutSpeed())); connect(m_nameEdit, SIGNAL(textEdited(const QString&)), this, SLOT(slotNameEdited(const QString&))); connect(m_fileButton, SIGNAL(clicked()), this, SLOT(slotSourceFileClicked())); connect(m_speedDialButton, SIGNAL(toggled(bool)), this, SLOT(slotSpeedDialToggle(bool))); connect(m_fadeInEdit, SIGNAL(returnPressed()), this, SLOT(slotFadeInEdited())); connect(m_fadeOutEdit, SIGNAL(returnPressed()), this, SLOT(slotFadeOutEdited())); connect(m_previewButton, SIGNAL(toggled(bool)), this, SLOT(slotPreviewToggled(bool))); AudioDecoder *adec = m_audio->getAudioDecoder(); m_filenameLabel->setText(m_audio->getSourceFileName()); if (adec != NULL) { AudioParameters ap = adec->audioParameters(); m_durationLabel->setText(Function::speedToString(m_audio->getDuration())); m_srateLabel->setText(QString("%1 Hz").arg(ap.sampleRate())); m_channelsLabel->setText(QString("%1").arg(ap.channels())); m_bitrateLabel->setText(QString("%1 kb/s").arg(adec->bitrate())); } QList<AudioDeviceInfo> devList; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #if defined( __APPLE__) || defined(Q_OS_MAC) devList = AudioRendererPortAudio::getDevicesInfo(); #elif defined(WIN32) || defined(Q_OS_WIN) devList = AudioRendererWaveOut::getDevicesInfo(); #else devList = AudioRendererAlsa::getDevicesInfo(); #endif #else devList = AudioRendererQt::getDevicesInfo(); #endif QSettings settings; QString outputName; int i = 0, selIdx = 0; m_audioDevCombo->addItem(tr("Default device"), "__qlcplusdefault__"); if (m_audio->audioDevice().isEmpty()) { QVariant var = settings.value(SETTINGS_AUDIO_OUTPUT_DEVICE); if (var.isValid() == true) outputName = var.toString(); } else outputName = m_audio->audioDevice(); foreach( AudioDeviceInfo info, devList) { if (info.capabilities & AUDIO_CAP_OUTPUT) { m_audioDevCombo->addItem(info.deviceName, info.privateName); if (info.privateName == outputName) selIdx = i; i++; } } m_audioDevCombo->setCurrentIndex(selIdx); connect(m_audioDevCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotAudioDeviceChanged(int))); // Set focus to the editor m_nameEdit->setFocus(); }
AudioDecoder * AudioDecoder::CreateDecoderForInputSource(InputSource *inputSource, CFStringRef mimeType, CFErrorRef *error) { if(nullptr == inputSource) return nullptr; AudioDecoder *decoder = nullptr; // Open the input source if it isn't already if(AutomaticallyOpenDecoders() && !inputSource->IsOpen() && !inputSource->Open(error)) return nullptr; // As a factory this class has knowledge of its subclasses // It would be possible (and perhaps preferable) to switch to a generic // plugin interface at a later date #if 0 // If the input is an instance of HTTPInputSource, use the MIME type from the server // This code is disabled because most HTTP servers don't send the correct MIME types HTTPInputSource *httpInputSource = dynamic_cast<HTTPInputSource *>(inputSource); bool releaseMIMEType = false; if(!mimeType && httpInputSource && httpInputSource->IsOpen()) { mimeType = httpInputSource->CopyContentMIMEType(); if(mimeType) releaseMIMEType = true; } #endif // The MIME type takes precedence over the file extension if(mimeType) { if(FLACDecoder::HandlesMIMEType(mimeType)) { decoder = new FLACDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && WavPackDecoder::HandlesMIMEType(mimeType)) { decoder = new WavPackDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && MPEGDecoder::HandlesMIMEType(mimeType)) { decoder = new MPEGDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && OggVorbisDecoder::HandlesMIMEType(mimeType)) { decoder = new OggVorbisDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && OggSpeexDecoder::HandlesMIMEType(mimeType)) { decoder = new OggSpeexDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } #if !TARGET_OS_IPHONE if(nullptr == decoder && MusepackDecoder::HandlesMIMEType(mimeType)) { decoder = new MusepackDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && MonkeysAudioDecoder::HandlesMIMEType(mimeType)) { decoder = new MonkeysAudioDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && MODDecoder::HandlesMIMEType(mimeType)) { decoder = new MODDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && TrueAudioDecoder::HandlesMIMEType(mimeType)) { decoder = new TrueAudioDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && LibsndfileDecoder::HandlesMIMEType(mimeType)) { decoder = new LibsndfileDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } #endif if(nullptr == decoder && CoreAudioDecoder::HandlesMIMEType(mimeType)) { decoder = new CoreAudioDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } #if 0 if(releaseMIMEType) CFRelease(mimeType), mimeType = nullptr; #endif if(decoder) return decoder; } // If no MIME type was specified, use the extension-based resolvers CFURLRef inputURL = inputSource->GetURL(); if(!inputURL) return nullptr; // Determining the extension isn't as simple as using CFURLCopyPathExtension (wouldn't that be nice?), // because although the behavior on Lion works like one would expect, on Snow Leopard it returns // a number that I believe is part of the inode number, but is definitely NOT the extension CFStringRef pathExtension = nullptr; #if !TARGET_OS_IPHONE CFURLRef filePathURL = CFURLCreateFilePathURL(kCFAllocatorDefault, inputURL, nullptr); if(filePathURL) { pathExtension = CFURLCopyPathExtension(filePathURL); CFRelease(filePathURL), filePathURL = nullptr; } else #endif pathExtension = CFURLCopyPathExtension(inputURL); if(!pathExtension) { if(error) { CFStringRef description = CFCopyLocalizedString(CFSTR("The type of the file “%@” could not be determined."), ""); CFStringRef failureReason = CFCopyLocalizedString(CFSTR("Unknown file type"), ""); CFStringRef recoverySuggestion = CFCopyLocalizedString(CFSTR("The file's extension may be missing or may not match the file's type."), ""); *error = CreateErrorForURL(InputSourceErrorDomain, InputSourceFileNotFoundError, description, inputURL, failureReason, recoverySuggestion); CFRelease(description), description = nullptr; CFRelease(failureReason), failureReason = nullptr; CFRelease(recoverySuggestion), recoverySuggestion = nullptr; } return nullptr; } // TODO: Some extensions (.oga for example) support multiple audio codecs (Vorbis, FLAC, Speex) // and if openDecoder is false the wrong decoder type may be returned, since the file isn't analyzed // until Open() is called if(FLACDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new FLACDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && WavPackDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new WavPackDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && MPEGDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new MPEGDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && OggVorbisDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new OggVorbisDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && OggSpeexDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new OggSpeexDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } #if !TARGET_OS_IPHONE if(nullptr == decoder && MusepackDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new MusepackDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && MonkeysAudioDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new MonkeysAudioDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && MODDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new MODDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && TrueAudioDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new TrueAudioDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } if(nullptr == decoder && LibsndfileDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new LibsndfileDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } #endif if(nullptr == decoder && CoreAudioDecoder::HandlesFilesWithExtension(pathExtension)) { decoder = new CoreAudioDecoder(inputSource); if(AutomaticallyOpenDecoders() && !decoder->Open(error)) { decoder->mInputSource = nullptr; delete decoder, decoder = nullptr; } } CFRelease(pathExtension), pathExtension = nullptr; return decoder; }