Qtを使ってオーディオを再生します
記事の目次.使用類Qudio Format、Qudio Output .オーディオを再生する 前の2つの記事では、FFMpegを使ってオーディオ情報を取得する方法と、FFMpegを使ってMP 3ファイルの情報と画像を取得する方法を紹介しました.FFMpegを使ってオーディオファイルを復号します.
この記事では、Qtを使って復号後のPCMデータを再生する方法を紹介します.
1.使用類Qudio Format、Qudio Output
Qudio Formatを使用して、サンプルレート、サンプルビット数、チャネル数などのオーディオのフォーマット関連情報を設定することができます.コードは以下の通りです
Qudio Outputを使ってオーディオを再生する方法は以下の通りです. Qudio Output*m_OutPut=new Qudio Output(nFormat)Qudio Outputオブジェクトを作成します. QIODevice*m_AudioIo=m_OutPut->start();QIODeviceのポインタオブジェクトを取得します. m_AudioIo->write関数はオーディオデバイスにデータを書き込みます. 2.オーディオを再生する
ここでは、スレッドを使ってオーディオを再生し、スレッドの中で絶えずにオーディオデータを書き込み、オーディオが連続して非同期で再生されます.コードは以下の通りです
以下の時の完全なコード:AudioPlayThread.h
この記事では、Qtを使って復号後のPCMデータを再生する方法を紹介します.
1.使用類Qudio Format、Qudio Output
Qudio Formatを使用して、サンプルレート、サンプルビット数、チャネル数などのオーディオのフォーマット関連情報を設定することができます.コードは以下の通りです
QAudioFormat nFormat;
nFormat.setSampleRate(sampleRate);
nFormat.setSampleSize(sampleSize);
nFormat.setChannelCount(channelCount);
nFormat.setCodec("audio/pcm");
nFormat.setByteOrder(QAudioFormat::LittleEndian);
nFormat.setSampleType(QAudioFormat::UnSignedInt);
Qudio Outputクラスの構成にはFormatを設定する必要があります.Qudio Outputはオーディオの再生、一時停止、設定、音量の取得などの制御ができます.Qudio Outputを使ってオーディオを再生する方法は以下の通りです.
ここでは、スレッドを使ってオーディオを再生し、スレッドの中で絶えずにオーディオデータを書き込み、オーディオが連続して非同期で再生されます.コードは以下の通りです
void AudioPlayThread::run(void)
{
while (!this->isInterruptionRequested())
{
if (!m_IsPlaying)
{
continue;
QThread::msleep(10);
}
QMutexLocker locker(&m_Mutex);
if (m_PCMDataBuffer.count() <= 0 || m_CurrentPlayIndex >= m_PCMDataBuffer.count())
{
QThread::msleep(10);
continue;
}
if (m_OutPut->bytesFree() >= m_OutPut->periodSize())
{
char *writeData = new char[m_OutPut->periodSize()];
//
int size = m_OutPut->periodSize();
size = qMin(size, m_PCMDataBuffer.size() - m_CurrentPlayIndex);
memcpy(writeData, &m_PCMDataBuffer.data()[m_CurrentPlayIndex], size);
//
m_AudioIo->write(writeData, size);
m_CurrentPlayIndex += size;
emit updatePlayStatus();
delete []writeData;
QThread::msleep(10);
}
}
}
オーディオの再生データをQByteAray m_に入れました.PCMDA Bufferにあります.periodSize個のデータを書き込むたびに、デバイスのオーディオバッファに一旦解放されたら>=periodSizeのメモリを一度書き込みます.これにより、バッファではずっと再生されているデータがあり、元のデータも上書きされません.一時停止または再生終了まで.以下の時の完全なコード:AudioPlayThread.h
#ifndef AUDIO_PLAY_THREAD_H
#define AUDIO_PLAY_THREAD_H
#include
#include
#include
#include
#include
#include
#define g_AudioPlayThread AudioPlayThread::getInstance()
class AudioPlayThread : public QThread
{
Q_OBJECT
public:
static AudioPlayThread *getInstance(void);
public:
AudioPlayThread(QObject *parent = nullptr);
~AudioPlayThread();
// ----------- ----------------------------------------
// PCM Buffer
void setCurrentBuffer(QByteArray buffer);
//
void addAudioBuffer(char* pData, int len);
//
void cleanAllAudioBuffer(void);
// ------------- End ----------------------------------------------
// 、 、
void setCurrentSampleInfo(int sampleRate, int sampleSize, int channelCount);
virtual void run(void) override;
//
int getCurrentBuffIndex(void);
//
int getCurrentTime(void);
//
void playMusic(bool status);
//
bool getPlayMusicStatus(void);
//
void setCurrentVolumn(qreal volumn);
//
qreal getCurrentVolumn(void);
private:
QAudioOutput *m_OutPut = nullptr;
QIODevice *m_AudioIo = nullptr;
QByteArray m_PCMDataBuffer;
int m_CurrentPlayIndex = 0;
QMutex m_Mutex;
//
bool m_IsPlaying = true;
signals:
void updatePlayStatus(void);
};
#endif
AudioPlayThread.cpp#include "AudioPlayThread.h"
#include
#include
AudioPlayThread::AudioPlayThread(QObject *parent)
:QThread(parent)
{
m_PCMDataBuffer.clear();
}
AudioPlayThread::~AudioPlayThread()
{
}
AudioPlayThread *AudioPlayThread::getInstance(void)
{
static AudioPlayThread instance;
return &instance;
}
void AudioPlayThread::setCurrentBuffer(QByteArray buffer)
{
QMutexLocker locker(&m_Mutex);
m_PCMDataBuffer.clear();
m_PCMDataBuffer = buffer;
m_IsPlaying = true;
}
void AudioPlayThread::setCurrentSampleInfo(int sampleRate, int sampleSize, int channelCount)
{
QMutexLocker locker(&m_Mutex);
//this->requestInterruption();
// Format
QAudioFormat nFormat;
nFormat.setSampleRate(sampleRate);
nFormat.setSampleSize(sampleSize);
nFormat.setChannelCount(channelCount);
nFormat.setCodec("audio/pcm");
nFormat.setByteOrder(QAudioFormat::LittleEndian);
nFormat.setSampleType(QAudioFormat::UnSignedInt);
if (m_OutPut != nullptr)
delete m_OutPut;
m_OutPut = new QAudioOutput(nFormat);
m_AudioIo = m_OutPut->start();
//this->start();
}
void AudioPlayThread::run(void)
{
while (!this->isInterruptionRequested())
{
if (!m_IsPlaying)
{
continue;
QThread::msleep(10);
}
QMutexLocker locker(&m_Mutex);
if (m_PCMDataBuffer.count() <= 0 || m_CurrentPlayIndex >= m_PCMDataBuffer.count())
{
QThread::msleep(10);
continue;
}
if (m_OutPut->bytesFree() >= m_OutPut->periodSize())
{
char *writeData = new char[m_OutPut->periodSize()];
//
int size = m_OutPut->periodSize();
size = qMin(size, m_PCMDataBuffer.size() - m_CurrentPlayIndex);
memcpy(writeData, &m_PCMDataBuffer.data()[m_CurrentPlayIndex], size);
//
m_AudioIo->write(writeData, size);
m_CurrentPlayIndex += size;
emit updatePlayStatus();
delete []writeData;
QThread::msleep(10);
}
}
}
//
void AudioPlayThread::addAudioBuffer(char* pData, int len)
{
QMutexLocker locker(&m_Mutex);
m_PCMDataBuffer.append(pData, len);
m_IsPlaying = true;
}
void AudioPlayThread::cleanAllAudioBuffer(void)
{
QMutexLocker locker(&m_Mutex);
m_CurrentPlayIndex = 0;
m_PCMDataBuffer.clear();
m_IsPlaying = false;
}
void AudioPlayThread::playMusic(bool status)
{
m_IsPlaying = status;
}
bool AudioPlayThread::getPlayMusicStatus(void)
{
return m_IsPlaying;
}
void AudioPlayThread::setCurrentVolumn(qreal volumn)
{
if (m_OutPut)
m_OutPut->setVolume(volumn);
}
qreal AudioPlayThread::getCurrentVolumn(void)
{
if (!m_OutPut)
return 0;
return m_OutPut->volume();
}
//
int AudioPlayThread::getCurrentBuffIndex(void)
{
return m_CurrentPlayIndex;
}
int AudioPlayThread::getCurrentTime(void)
{
QMutexLocker locker(&m_Mutex);
qreal sec = m_CurrentPlayIndex * 1.0 / 4 * (1 * 1.0 / m_OutPut->format().sampleRate());
return sec * 1000;
}