Skip to content

Commit

Permalink
ao: simplify API
Browse files Browse the repository at this point in the history
AudioOutput.setAudioFormat() now use a prefered format if not supported,
and return the actual format used
  • Loading branch information
wang-bin committed Jul 25, 2016
1 parent 8680e72 commit 09e6e40
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 125 deletions.
10 changes: 3 additions & 7 deletions examples/audiopipeline/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,12 @@ int main(int argc, char *argv[])
if (ao->isOpen()) {
af = ao->audioFormat();
} else {
dec->resampler()->setOutAudioFormat(af);
ao->setAudioFormat(af);
dec->resampler()->setOutAudioFormat(ao->audioFormat());
// if decoded format is not supported by audio renderer, change decoder output format
if (!ao->isSupported(af)) {
af.setSampleFormat(ao->preferredSampleFormat());
af.setChannelLayout(ao->preferredChannelLayout());
dec->resampler()->setOutAudioFormat(af);
if (af != ao->audioFormat())
dec->resampler()->prepare();
}
// now af is supported by audio renderer. it's safe to open
ao->setAudioFormat(af);
if (!ao->open())
qFatal("Open audio output error");
#if 0 // always resample ONCE due to QtAV bug
Expand Down
4 changes: 3 additions & 1 deletion examples/player/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,9 @@ void MainWindow::changeChannel(QAction *action)
qWarning("close audio failed");
return;
}
ao->audioFormat().setChannelLayout(cl);
AudioFormat af(ao->audioFormat());
af.setChannelLayout(cl);
ao->setAudioFormat(af);
if (!ao->open()) {
qWarning("open audio failed");
return;
Expand Down
21 changes: 2 additions & 19 deletions src/AVPlayerPrivate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,34 +372,17 @@ bool AVPlayer::Private::setupAudioThread(AVPlayer *player)
af.setSampleRate(avctx->sample_rate);
af.setSampleFormatFFmpeg(avctx->sample_fmt);
af.setChannelLayoutFFmpeg(avctx->channel_layout);
qDebug() << "audio format from codec: " << af;
if (!af.isValid()) {
qWarning("invalid audio format. audio stream will be disabled");
return false;
}
// 5, 6, 7 channels may not play
if (avctx->channels > 2)
af.setChannelLayout(ao->preferredChannelLayout());
//af.setChannels(avctx->channels);
// FIXME: workaround. planar convertion crash now!
if (af.isPlanar()) {
af.setSampleFormat(AudioFormat::packedSampleFormat(af.sampleFormat()));
}
if (!ao->isSupported(af)) {
if (!ao->isSupported(af.sampleFormat())) {
af.setSampleFormat(ao->preferredSampleFormat());
}
if (!ao->isSupported(af.channelLayout())) {
af.setChannelLayout(ao->preferredChannelLayout());
}
}
// always reopen to ensure internal buffer queue inside audio backend(openal) is clear. also make it possible to change backend when replay.
//if (ao->audioFormat() != af) {
//qDebug("ao audio format is changed. reopen ao");
ao->close();
if (ao->audioFormat() != af)
ao->setAudioFormat(af);
qDebug() << "AudioOutput format: " <<ao->audioFormat();
ao->setAudioFormat(af);
qDebug() << "AudioOutput format: " << ao->audioFormat() << "; requested: " << ao->requestedFormat();
if (!ao->open()) {
return false;
}
Expand Down
39 changes: 15 additions & 24 deletions src/QtAV/AudioOutput.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ class Q_AV_EXPORT AudioOutput : public QObject, public AVOutput
*/
enum DeviceFeature {
NoFeature = 0,
SetVolume = 1, /// NOT IMPLEMENTED. Use backend volume control api rather than software scale. Ignore if backend does not support.
SetMute = 1 << 1, /// NOT IMPLEMENTED
SetVolume = 1, /// Use backend volume control api rather than software scale. Ignore if backend does not support.
SetMute = 1 << 1,
SetSampleRate = 1 << 2, /// NOT IMPLEMENTED
};
Q_DECLARE_FLAGS(DeviceFeatures, DeviceFeature)
Expand All @@ -75,7 +75,7 @@ class Q_AV_EXPORT AudioOutput : public QObject, public AVOutput
* Audio format set to preferred sample format and channel layout
*/
AudioOutput(QObject *parent = 0);
virtual ~AudioOutput();
~AudioOutput();
/*!
* \brief setBackends
* set the given backends. Old backend instance and backend() is updated soon if backendsChanged.
Expand Down Expand Up @@ -111,15 +111,19 @@ class Q_AV_EXPORT AudioOutput : public QObject, public AVOutput
* \return true if play successfully
*/
bool play(const QByteArray& data, qreal pts = 0.0);
/// TODO: requestAudioFormat(): check support after open, use the nearest format if not supported. Or use suitableFormat(AudioFormat requestedFmt) if requestedFmt is not supported.
void setAudioFormat(const AudioFormat& format);
AudioFormat& audioFormat();
/*!
* \brief setAudioFormat
* Set/Request to use the given \l format. If it's not supported, an prefered format (TODO: best and nearest) will be used
* \param format requested format
* \return actual format to use
*/
AudioFormat setAudioFormat(const AudioFormat& format);
const AudioFormat& requestedFormat() const;
/*!
* \brief audioFormat
* \return actual format for requested format
*/
const AudioFormat& audioFormat() const;

void setSampleRate(int rate); //deprecated
int sampleRate() const; //deprecated
void setChannels(int channels); //deprecated
int channels() const; //deprecated
/*!
* \brief setVolume
* Set volume level.
Expand Down Expand Up @@ -154,19 +158,6 @@ class Q_AV_EXPORT AudioOutput : public QObject, public AVOutput
* \return true if \a format is supported. default is true
*/
bool isSupported(const AudioFormat& format) const;
bool isSupported(AudioFormat::SampleFormat sampleFormat) const;
bool isSupported(AudioFormat::ChannelLayout channelLayout) const;
/*!
* \brief preferredSampleFormat
* \return the preferred sample format. default is signed16 packed
* If the specified format is not supported, resample to preffered format
*/
AudioFormat::SampleFormat preferredSampleFormat() const;
/*!
* \brief preferredChannelLayout
* \return the preferred channel layout. default is stereo
*/
AudioFormat::ChannelLayout preferredChannelLayout() const;
/*!
* \brief bufferSamples
* Number of samples that audio output accept in 1 buffer. Feed the audio output this size of data every time.
Expand Down
6 changes: 4 additions & 2 deletions src/QtAV/private/AudioOutputBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ class Q_AV_PRIVATE_EXPORT AudioOutputBackend : public QObject
virtual bool flush() { return false;}
virtual bool clear() { return false;}
virtual bool isSupported(const AudioFormat& format) const { return isSupported(format.sampleFormat()) && isSupported(format.channelLayout());}
virtual bool isSupported(AudioFormat::SampleFormat) const { return true;}
virtual bool isSupported(AudioFormat::ChannelLayout) const { return true;}
// FIXME: workaround. planar convertion crash now!
virtual bool isSupported(AudioFormat::SampleFormat f) const { return !AudioFormat::isPlanar(f);}
// 5, 6, 7 channels may not play
virtual bool isSupported(AudioFormat::ChannelLayout cl) const { return int(cl) < int(AudioFormat::ChannelLayout_Unsupported);}
/*!
* \brief preferredSampleFormat
* \return the preferred sample format. default is signed16 packed
Expand Down
88 changes: 23 additions & 65 deletions src/output/audio/AudioOutput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ class AudioOutputPrivate : public AVOutputPrivate
qreal vol;
qreal speed;
AudioFormat format;
AudioFormat requested;
QByteArray data;
//AudioFrame audio_frame;
quint32 nb_buffers;
Expand Down Expand Up @@ -257,8 +258,6 @@ AudioOutput::AudioOutput(QObject* parent)
, AVOutput(*new AudioOutputPrivate())
{
qDebug() << "Registered audio backends: " << AudioOutput::backendsAvailable(); // call this to register
d_func().format.setSampleFormat(AudioFormat::SampleFormat_Signed16);
d_func().format.setChannelLayout(AudioFormat::ChannelLayout_Stereo);
setBackends(AudioOutputBackend::defaultPriority()); //ensure a backend is available
}

Expand Down Expand Up @@ -317,7 +316,7 @@ void AudioOutput::setBackends(const QStringList &backendNames)
connect(d.backend, SIGNAL(muteReported(bool)), SLOT(reportMute(bool)));
}

emit backendsChanged();
Q_EMIT backendsChanged();
}

QStringList AudioOutput::backends() const
Expand Down Expand Up @@ -436,48 +435,39 @@ bool AudioOutput::receiveData(const QByteArray &data, qreal pts)
return d.backend->write(d.data);
}

void AudioOutput::setAudioFormat(const AudioFormat& format)
AudioFormat AudioOutput::setAudioFormat(const AudioFormat& format)
{
DPTR_D(AudioOutput);
// no support check because that may require an open device(AL) while this function is called before ao.open()
if (d.format == format)
return;
return format;
d.requested = format;
AudioFormat af(format);
if (d.backend) {
if (!d.backend->isSupported(format)) {
if (!d.backend->isSupported(format.sampleFormat())) {
af.setSampleFormat(d.backend->preferredSampleFormat());
}
if (!d.backend->isSupported(format.channelLayout())) {
af.setChannelLayout(d.backend->preferredChannelLayout());
}
}
}
d.format = af;
d.updateSampleScaleFunc();
d.format = format;
return af;
}

AudioFormat& AudioOutput::audioFormat()
const AudioFormat& AudioOutput::requestedFormat() const
{
return d_func().format;
return d_func().requested;
}

const AudioFormat& AudioOutput::audioFormat() const
{
return d_func().format;
}

void AudioOutput::setSampleRate(int rate)
{
d_func().format.setSampleRate(rate);
}

int AudioOutput::sampleRate() const
{
return d_func().format.sampleRate();
}

// TODO: check isSupported
void AudioOutput::setChannels(int channels)
{
DPTR_D(AudioOutput);
d.format.setChannels(channels);
}

int AudioOutput::channels() const
{
return d_func().format.channels();
}

void AudioOutput::setVolume(qreal value)
{
DPTR_D(AudioOutput);
Expand Down Expand Up @@ -529,38 +519,6 @@ bool AudioOutput::isSupported(const AudioFormat &format) const
return d.backend->isSupported(format);
}

bool AudioOutput::isSupported(AudioFormat::SampleFormat sampleFormat) const
{
DPTR_D(const AudioOutput);
if (!d.backend)
return false;
return d.backend->isSupported(sampleFormat);
}

bool AudioOutput::isSupported(AudioFormat::ChannelLayout channelLayout) const
{
DPTR_D(const AudioOutput);
if (!d.backend)
return false;
return d.backend->isSupported(channelLayout);
}

AudioFormat::SampleFormat AudioOutput::preferredSampleFormat() const
{
DPTR_D(const AudioOutput);
if (!d.backend)
return AudioFormat::SampleFormat_Signed16;
return d.backend->preferredSampleFormat();
}

AudioFormat::ChannelLayout AudioOutput::preferredChannelLayout() const
{
DPTR_D(const AudioOutput);
if (!d.backend)
return AudioFormat::ChannelLayout_Stereo;
return d.backend->preferredChannelLayout();
}

int AudioOutput::bufferSize() const
{
return bufferSamples() * d_func().format.bytesPerSample();
Expand Down Expand Up @@ -641,16 +599,16 @@ bool AudioOutput::waitForNextBuffer()
qint64 last_wait = 0LL;
while (d.processed_remain - processed < next || d.processed_remain < d.data.size()) { //implies next > 0
const qint64 us = d.format.durationForBytes(next - (d.processed_remain - processed));
QMutexLocker lock(&d.mutex);
Q_UNUSED(lock);
d.cond.wait(&d.mutex, us/1000LL);
d.uwait(us);
d.processed_remain = d.backend->getWritableBytes();
if (d.processed_remain < 0)
return false;
#if AO_USE_TIMER
if (!d.timer.isValid()) {
qWarning("invalid timer. closed in another thread");
return false;
}
#endif
if (us >= last_wait
#if AO_USE_TIMER
&& d.timer.elapsed() > 1000
Expand Down
7 changes: 0 additions & 7 deletions src/output/audio/AudioOutputPulse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class AudioOutputPulse Q_DECL_FINAL: public AudioOutputBackend

QString name() const Q_DECL_FINAL { return QString::fromLatin1(kName);}
bool isSupported(AudioFormat::SampleFormat sampleFormat) const Q_DECL_FINAL;
bool isSupported(AudioFormat::ChannelLayout channelLayout) const Q_DECL_FINAL;
bool open() Q_DECL_FINAL;
bool close() Q_DECL_FINAL;

Expand Down Expand Up @@ -369,12 +368,6 @@ bool AudioOutputPulse::isSupported(AudioFormat::SampleFormat spformat) const
return false;
}

bool AudioOutputPulse::isSupported(AudioFormat::ChannelLayout channelLayout) const
{
Q_UNUSED(channelLayout);
return true;
}

bool AudioOutputPulse::open()
{
if (!init(format)) {
Expand Down

0 comments on commit 09e6e40

Please sign in to comment.