저는 자체 C++ API를 사용하여 마이크 배열 시스템에서 원시 오디오를 읽거나 처리하거나 재생하는 C++ 프로젝트 작업을하고 있습니다. QT를 사용하여 소프트웨어를 프로그래밍하고 있습니다.QT C++ QAudioOutput을 사용한 실시간 스트리밍
Real Time Streaming With QAudioOutput (QT)에 대한이 게시물에서 Raw 오디오 데이터가 처리를 위해 약 1000ms (1 초)가 소요되는 함수 호출에서 오는 경우 어떻게해야하는지에 대한 조언을 구하고 싶습니다. 실시간 오디오 재생을 어떻게 계속 유지할 수 있습니까?
QIODevice :: QAudioFormat-> start();에 쓸 때 읽었 기 때문에 처리하는 데 약 1 초가 걸립니다. 버퍼 언더런/오버런을 방지하려면 바이트 단위의 바이트를 사용하는 것이 좋습니다. http://cell0907.blogspot.sg/2012/10/qt-audio-output.html
QByteArray 및 QDataStream을 설정하여 함수 호출에서 수신 한 데이터를 스트리밍했습니다.
- API는 마이크로폰 어레이는 32 개 비트 정수 32 개 비트 정수
- , 24 비트의 해상도, 8 비트 LSB 패딩 제로의 배열을 반환로부터 데이터를 판독 CcmXXX()
- 이다.
- 블록 크기 (1024 샘플로 설정) x 마이크 40 개
- 각 청크는 기록 된 바이트 수가 기간 크기/여유 공간 크기에 거의 도달 할 때까지 약 1 블록을 기록합니다.
테스트 됨 : 내 슬롯을 약 50ms의 알림에 연결하여 한 기간 가치를 기록합니다. 원형 버퍼 스타일의 QByteArray. 읽기/쓰기 부분에 뮤텍스 잠금/잠금 해제를 추가했습니다.
결과 : 실제 오디오 재생시 매우 짧은 스플릿 ms, 많은 지터 및 녹음되지 않은 사운드.
코드 개선 방법에 대한 의견을 보내주십시오.
void MainWindow::slot_writedata(){
QMutex mutex;
mutex.lock();
read_frames();
mutex.unlock();
}
:
void MainWindow::init_audio_output(){
m_bytearray.resize(65536);
mstream = new QDataStream(&m_bytearray,QIODevice::ReadWrite);
mstream->setByteOrder(QDataStream::LittleEndian);
audio = new QAudioOutput(m_device,m_format,this);
audio->setBufferSize(131072);
audio->setNotifyInterval(50);
m_audiodevice = audio->start();
connect(audio,SIGNAL(notify()),this,SLOT(slot_writedata()));
read_frames();
}
슬롯
QAudioFormat
void MainWindow::init_audio_format(){
m_format.setSampleRate(48000); //(8000, 11025, 16000, 22050, 32000, 44100, 48000, 88200, 96000, 192000
m_format.setByteOrder(QAudioFormat::LittleEndian);
m_format.setChannelCount(1);
m_format.setCodec("audio/pcm");
m_format.setSampleSize(32); //(8, 16, 24, 32, 48, 64)
m_format.setSampleType(QAudioFormat::SignedInt); //(SignedInt, UnSignedInt, Float)
m_device = QAudioDeviceInfo::defaultOutputDevice();
QAudioDeviceInfo info(m_device);
if (!info.isFormatSupported(m_format)) {
qWarning() << "Raw audio format not supported by backend, cannot play audio.";
return;
}
}
초기화하는 오디오 설정 및 QByteArray/데이터 스트림 0
는 프레임을 읽으려면 :
void MainWindow::read_frames(){
qint32* buffer;
int frameSize, byteCount=0;
DWORD tdFrames, fdFrames;
float fvalue = 0;
qint32 q32value;
frameSize = 40 * mBlockSize; //40 mics
buffer = new int[frameSize];
int periodBytes = audio->periodSize();
int freeBytes = audio->bytesFree();
int chunks = qMin(periodBytes/mBlockSize,freeBytes/mBlockSize);
CcmStartInput();
while(chunks){
CcmReadFrames(buffer,NULL,frameSize,0,&tdFrames,&fdFrames,NULL,CCM_WAIT);
if(tdFrames==0){
break;
}
int diffBytes = periodBytes - byteCount;
if(diffBytes>=(int)sizeof(q32value)*mBlockSize){
for(int x=0;x<mBlockSize;x++){
q32value = (quint32)buffer[x]/256;
*mstream << (qint32)fvalue;
byteCount+=sizeof(q32value);
}
}
else{
for(int x=0;x<(diffBytes/(int)sizeof(q32value));x++){
q32value = (quint32)buffer[x]/256;
*mstream << (qint32) fvalue;
byteCount+=sizeof(q32value);
}
}
--chunks;
}
CcmStopInput();
mPosEnd = mPos + byteCount;
write_frames();
mPos += byteCount;
if(mPos >= m_bytearray.length()){
mPos = 0;
mstream->device()->seek(0); //change mstream pointer back to bytearray start
}
}
이 프레임을 작성하려면 : Qt는에
void MainWindow::write_frames()
{
int len = m_bytearray.length() - mPos;
int bytesWritten = mPosEnd - mPos;
if(len>=audio->periodSize()){
m_audiodevice->write(m_bytearray.data()+mPos, bytesWritten);
}
else{
w_data.replace(0,qAbs(len),m_bytearray.data()+mPos);
w_data.replace(qAbs(len),audio->periodSize()-abs(len),m_bytearray.data());
m_audiodevice->write(w_data.data(),audio->periodSize());
}
}
예, 물론입니다. Qt에서 관련된 모든 비디오/오디오는 불행히도 초보적입니다. QMediaPlayer조차도 FFmpeg와 같은 무언가를 사용하는 대신 OS의 재생 기능 (!!!)을 사용하여 모든 종류의 문제를 일으 킵니다. 특수 라이브러리 (GUI 용 Qt와 혼합)를 사용하는 것이 더 나을 것입니다. – TheSHEEEP
의견 및 제안에 감사드립니다. 나는 그 도서관을 시험 할 것이다! 건배! – MrS05
안녕하십니까, TheSHEEEP, 다른 API에 대해 더 궁금해합니다. 나는 rtaudio API를 추가하려고 시도했다. http://www.music.mcgill.ca/~gary/rtaudio/에서 파일을 다운로드했습니다. 그런 다음 CMake make 파일을 생성하여 DLL을 생성 한 다음 mingw64 make를 실행하여 rtaudio DLL 또는 lib 파일을 생성하는 파일을 만들어야합니까? – MrS05