Visual c++ 使用QIODevice(带VC的Qt4.6+;+;)播放音频数据

Visual c++ 使用QIODevice(带VC的Qt4.6+;+;)播放音频数据,visual-c++,qt,audio,stream,Visual C++,Qt,Audio,Stream,我正在使用VC++和QT多媒体库从音频流播放音频。由于我对Qt的库不太熟悉,我从读取.wav文件并将其写入缓冲区开始: ifstream wavFile; char* file = "error_ex.wav"; wavFile.open( file, ios::binary ); 之后,我使用ifstream的.read()函数将所有数据写入缓冲区。写入缓冲区后,它被发送到音频编写器,音频编写器为Qt做准备: QByteArray fData; for( int i = 0; i <

我正在使用VC++和QT多媒体库从音频流播放音频。由于我对Qt的库不太熟悉,我从读取.wav文件并将其写入缓冲区开始:

ifstream wavFile;
char* file = "error_ex.wav";
wavFile.open( file, ios::binary );
之后,我使用ifstream的.read()函数将所有数据写入缓冲区。写入缓冲区后,它被发送到音频编写器,音频编写器为Qt做准备:

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_pAudioOut为QAudioOutput型)

这会导致扬声器发出一声小的爆裂声,然后停止播放。你知道为什么吗


使用Qt library 4.6.3在Windows XP SP2上运行Visual Studio 2008。

您确定使用了正确的(高级)API吗?如果您必须手动处理数据流和缓冲,这会很奇怪。此外,QIODevice::write()不一定要写入整个缓冲区,但可能会在n个字节后停止,就像POSIX write()一样(这就是为什么总是要检查返回值的原因)

我还没有研究QT多媒体,但在过去,使用更成熟的声子、视频和音频输出对我来说效果很好。它的工作原理如下:

  • 创建声子::AudioOutput对象
  • 创建一个声子::MediaObject对象
  • Phonon::createPath(mediaObject、audioObject)
  • mediaObject->setCurrentSource(声子::MediaSource(路径))
  • mediaObject->play()
    Qt中也有一些例子。

    正如Frank指出的那样,如果您的需求只是播放文件中的音频数据,那么更高级别的API可以完成这项工作,并简化您的应用程序代码。这将是一种选择;或者,QtMobility项目为高级用例提供API

    然而,考虑到问题是关于使用的,并且您提到从WAV文件读取只是您最初的方法,我假设您实际上需要一个流API,即允许客户端控制缓冲的API,而不是将此控制权交给更高级别的抽象,如Phonon

    可以在两种不同的模式下使用,具体取决于调用的是
    start()
    的哪个重载:

    • “拉动模式”:

      在此模式下,QAudioOutput将从提供的QIODevice中提取数据,而无需客户端进一步干预。如果使用的QIODevice是由Qt提供的(例如,etc),则这是一个很好的选择

    • “推送模式”:

      在此模式下,QAudioOutput客户端必须通过调用
      QIODevice::write()
      将模式推送到音频设备。这需要在循环中完成,类似于:

      qint64 dataRemaining = ... // assign correct value here
      while (dataRemaining) {
          qint64 bytesWritten = audioOutput->write(buffer, dataRemaining);
          dataRemaining -= bytesWritten;
          buffer += bytesWritten;
          // Then wait for a short time
      }
      
      等待的实现方式将取决于应用程序的上下文——如果音频是从专用线程写入的,那么它可能只是简单的。或者,如果音频是从主线程写入的,那么您可能希望写入由一个线程触发

      因为你没有提到在你的应用程序中使用write()调用的循环,看起来发生的事情是你写了一小段数据(作为流行音乐播放),然后就不再写了


    您可以在Qt附带的示例/多媒体/音频输出应用程序中看到使用这两种模式的代码。

    Ah!谢谢,这是一个比Qt文档更好的信息来源。我正在“克隆”与我的需求相关的示例代码。不过,我遇到了两个问题。当我尝试使用pull模式时,我得到了与之前相同的结果,同时还得到了一些QObject警告,告诉我如何在线程中启动qtimer。然后,当我使用push模式时,read调用返回-1(错误)。这让我相信我的缓冲器有问题。我会继续努力。谢谢你的帮助。所以我正在研究pull方法。我的“play”方法只是打开QBuffer,然后QAudioOutput启动它(下面是示例和Qt文档)。它听起来像是先放第一个音符,然后停下来。这个方法不需要我手动确保它播放所有的数据包。想法?我的直觉是对的。在命令行应用程序中运行它会导致程序终止并几乎立即停止音频输出。我将我的代码添加到GUI应用程序中,它成功了!谢谢你的帮助@托尼:正如你发现的,你需要一个事件循环来播放整个片段。但是,您不一定需要GUI应用程序-
    QCoreApplication::exec()
    QApplication::exec()。但是,每当我将源设置为流url时,即rtp://@123.123.12.1:8080,它都不会播放流。Phonon还依赖于您使用的系统,因为它没有实现自己的后端(根据Qt文档)。例如,在Windows Phonon上使用DirectShow的后端支持,在Linux上使用GStreamer。@Tony:Phonon和QtMultimedia都需要后端,它使用适当的本机API来实现公共Qt API。目前,
    QAudio*
    后端被静态编译到qtmedia.dll中,而声子后端被构建为单独的dll,并通过Qt插件机制加载。但从设计角度来看,Phonon和QtMultimedia都由一个通用实现、一个后端接口和多个特定于平台的后端实现组成。
    qint64 dataRemaining = ... // assign correct value here
    while (dataRemaining) {
        qint64 bytesWritten = audioOutput->write(buffer, dataRemaining);
        dataRemaining -= bytesWritten;
        buffer += bytesWritten;
        // Then wait for a short time
    }