2010-08-06 2 views
11

QtMultimedia 라이브러리와 함께 VC++를 사용하여 오디오 스트림에서 오디오를 재생하려고합니다. 내가 너무 Qt의 라이브러리와 경험이 아니에요 때문에 내가 .wav 파일에 읽고 버퍼에 쓰기 시작 : 그 후QIODevice를 사용하여 오디오 데이터 재생 (VC++의 Qt4.6)

ifstream wavFile; 
char* file = "error_ex.wav"; 
wavFile.open(file, ios::binary); 

, 나는 ifstream의 .read() 함수를 사용에 모든 데이터를 기록 버퍼. QBuffer가 준비되면 내가 버퍼를 재생하려고

QByteArray fData; 

for(int i = 0; i < (int)data.size(); ++i) 
{ 
    fData.push_back(data.at(i)); 
} 

m_pBuffer->open(QIODevice::ReadWrite); 
m_pBuffer->write(fData); 

m_pBuffer->close(); 

(m_pBuffer 유형 QBuffer이다)

: 버퍼가 기록 된 후에는 Qt를 위해 준비 오디오 라이터에 퇴장 것

QIODevice* ioDevice = m_pAudioOut->start(); 
ioDevice->write(m_pBuffer->buffer()); 

이 스피커에서 작은 팝업 결과 후 재생이 중지 (m_pAudioOut 유형 QAudioOutput이다). 어떤 아이디어?

Windows XP SP2에서 Visual Studio 2008을 Qt 라이브러리를 사용하여 실행 4.6.3.

답변

12

프랭크 (Frank)는 파일에서 오디오 데이터를 재생하기 만하면 높은 수준의 API가 작업을 수행하고 응용 프로그램 코드를 단순화 할 것이라고 지적했습니다. Phonon은 하나의 옵션입니다. 또는 QtMobility 프로젝트는 고급 사용 사례에 대해 QMediaPlayer API를 제공합니다.

그러나이 질문은 구체적으로 QIODevice을 사용하는 것에 관한 것이고 WAV 파일을 읽는 것은 사용자의 접근 방법이라고 언급 했으므로 실제로 스트리밍 API가 필요하다고 가정합니다. 즉, 클라이언트가 Phonon과 같은 상위 수준의 추상화에이 컨트롤을 넘겨주는 대신 버퍼링을 제어합니다.

QAudioOutput 호출된다 start() 어느 과부하에 따라 두 가지 상이한 모드로 사용될 수있다

  • "풀 모드"void QAudioOutput::start(QIODevice *)이 모드

    , QAudioOutput 제공된 데이터를 끌어 클라이언트의 개입없이 QIODevice. 사용중인 QIODevice가 Qt에서 제공하는 QIODevice (예 : QFile, QAbstractSocket 등) 일 경우 좋은 선택입니다.

  • "푸시 모드":이 모드에서는 QIODevice* QAudioOutput::start()

    는 QAudioOutput 클라이언트는 QIODevice::write()를 호출하여 오디오 장치 모드를 밀어해야합니다. 오디오 전용 스레드에서 작성되는 경우, 그 수 단순히 sleep() -

    대기가 응용 프로그램의 상황에 따라 달라집니다 구현하는 방법
    qint64 dataRemaining = ... // assign correct value here 
    while (dataRemaining) { 
        qint64 bytesWritten = audioOutput->write(buffer, dataRemaining); 
        dataRemaining -= bytesWritten; 
        buffer += bytesWritten; 
        // Then wait for a short time 
    } 
    

    :이 뭔가처럼, 루프에서 수행해야합니다. 또는 오디오가 주 스레드에서 쓰여지고있는 경우에는 QTimer에 의해 기록이 시작되기를 원할 것입니다.

    앱에서 write() 호출을 둘러싼 루프를 사용하는 방법에 대해서는 언급하지 않았기 때문에 어떤 일이 일어나고 있는지 (즉, 팝으로 재생되는) 짧은 데이터 세그먼트를 작성한 다음 더 이상 쓰지 마라.

Qt와 함께 제공되는 examples/multimedia/audiooutput 앱에서 두 모드를 모두 사용하는 코드를 볼 수 있습니다.

+0

아! Qt 설명서보다 훨씬 좋은 정보원입니다. 필자의 필요에 맞는 예제 코드를 "복제"하고 있습니다. 나는 두 가지 문제를 겪었다. 풀 모드를 사용하려고 할 때 QTimers를 스레드에서 시작해야하는 방법에 대한 일부 QObject 경고와 함께 이전과 동일한 결과를 얻습니다. 그런 다음 푸시 모드를 사용하면 읽기 호출이 -1 (오류)을 반환합니다. 내 완충제로 무언가를 믿게 만드는 것은 잘못된 것입니다. 나는 이것을 계속 연구 할 것이다. 도와 주셔서 감사합니다. – Tony

+0

그래서 나는 pull 메소드를 더보고 있습니다. 내 "재생"방법은 단순히 QBuffer를 연 다음 QAudioOutput이이를 시작합니다 (Qt 문서와 함께 예제를 따라). 그것은 첫 번째 음을 연주하고 멈춘 것처럼 들립니다. 이 방법을 사용하면 수동으로 모든 패킷을 재생할 필요가 없습니다. 아이디어? – Tony

+0

내 직감이 옳았습니다. 명령 줄 응용 프로그램에서 실행하면 프로그램이 거의 즉시 오디오 출력을 종료하고 종료시킵니다. 내 코드를 GUI 응용 프로그램에 추가했는데 성공했습니다! 도와 주셔서 감사합니다! – Tony

2

올바른 (상위 수준의) API를 사용하고 있습니까? 데이터 스트림을 처리하고 수동으로 버퍼링해야한다면 이상 할 것입니다. 또한, QIODevice :: write()는 반드시 전체 버퍼를 쓰지는 않지만 POSIX write()처럼 n 바이트 후에 멈출 수 있습니다. (항상 리턴 값을 확인해야하는 이유입니다).

나는 QtMultimedia를 아직 보지 못했지만 좀더 성숙한 Phonon을 사용하면 비디오 및 오디오 출력물이 저에게 잘 돌아갔습니다. 그것은 다음과 같이 작동

  1. 포논 :: AudioOutput 객체
  2. 만들기 포논 :: 미디어 오브젝트 객체
  3. 포논 :: createPath (미디어 오브젝트, audioObject) 만들기
  4. mediaObject-> setCurrentSource (포논 : : MediaSource (경로));
  5. mediaObject-> play();

Qt에도 예제가 있습니다.

+1

프랭크, 나는 스트림 재생을 지원한다고 주장한 이후로 Phonon을 먼저 조사했습니다. 그러나 소스를 스트림 URL (예 : rtp : //@123.123.12.1 : 8080)로 설정할 때마다 스트림이 재생되지 않습니다. Phonon은 또한 자체 백엔드를 구현하지 않으므로 (Qt 문서에 따라) 어떤 시스템을 사용하고 있는지에 의존합니다. 예를 들어, Windows에서 Phonon은 DirectShow와 Linux, GStreamer의 백엔드 지원을 사용합니다. – Tony

+1

@ 토니 : Phonon과 QtMultimedia 모두 백엔드가 필요합니다. 백엔드는 적절한 네이티브 API를 사용하여 공개 Qt API를 구현합니다. 현재'QAudio *'백엔드는 QtMultimedia.dll에 정적으로 컴파일되어있는 반면, Phonon 백엔드는 별도의 DLL로 빌드되고 Qt 플러그인 메커니즘을 통해로드됩니다. 그러나 디자인 측면에서 Phonon과 QtMultimedia는 일반 구현, 백엔드 인터페이스 및 플랫폼 별 백엔드 구현으로 구성됩니다. –