yafeilinux 发表于 2013-10-7 09:50:36

第49篇 进阶(九) 多媒体应用简介

多媒体应用简介

版权声明该文章原创于Qter开源社区(www.qter.org),作者yafeilinux,转载请注明出处!



导语
   Qt对于音频视频的播放和控制等多媒体应用提供了强大的支持。要想使计算机发出响声,最简单的方法是调用QApplication::beep()静态函数;而对于简单的声音播放,可以使用 QSound类;对于简单的动画播放,可以使用QMovie类;要想对音频视频实现更多的控制,可以使用Phonon多媒体框架;而对于音频视频底层的控制,可以使用QtMultimedia模块。虽然在Qt 5中已经已经放弃了Phonon,但是使用Qt 4时,Phonon还是一个很好的选择,所以这里我们也对其进行了简单介绍。


环境:Windows Xp + Qt 4.8.5+QtCreator2.8.0



目录
一、使用QSound播放声音二、Phonon 简介三、使用Phonon播放音频四、使用Phonon播放视频




正文
一、使用QSound播放声音


1.新建Qt Gui应用,名称为“mySound”,类名“MainWindow”和基类QMainWindow保持默认即可。
2.完成后在mainwindow.cpp文件中添加头文件#include <QSound>,然后在构造函数中添加如下一行代码:
QSound::play("../mySound/sound.wav");        这时运行程序就可以播放指定的音频文件了,注意这里将音频文件放在了项目目录中。因为现在QSound并不支持资源文件,所以音频文件必须要放在程序外面。除了简单的使用静态函数进行播放外,也可以先构建一个QSound对象,然后再调用play()槽进行播放,可以使用stop()槽来停止声音的播放,还可以使用setLoops()函数设置播放重复的次数,如果设置为-1表示无限循环。


3.先到mainwindow.h文件中添加前置声明classQSound;然后声明一个私有对象:QSound *sound;再到mainwindow.cpp文件中,将构造函数里添加的调用play()函数的代码更改为:sound = new QSound("../mySound/sound.wav", this);       然后我们双击mainwindow.ui文件进入设计模式,向界面上添加两个Push Button和一个Spin Box,并将两个按钮的文本分别改为“播放”和“停止”。然后更改Spin Box的属性,将最小值minimum设置为-1,将当前值value设置为1。最后分别转到两个按钮的clicked()槽和Spin Box的valueChanged(int )槽,更改它们的内容如下:
void MainWindow::on_pushButton_clicked(){ // 播放按钮   sound->play();}void MainWindow::on_pushButton_2_clicked(){ // 停止按钮   sound->stop();}void MainWindow::on_spinBox_valueChanged(int value){    sound->setLoops(value);}


4.现在运行程序,可以设置播放的次数,然后使用开始按钮进行播放,使用停止按钮来停止播放了。要说明一下,在Windows平台上,如果设置了循环次数,那么stop()函数无法立即停止播放,需要完成当前的循环才可以停止播放。


       使用QSound可以实现一些简短的声音的播放,使用它来实现单击按钮或者其他事件的音效是很好的选择。根据平台的音频设备的不同,如果使用QSound同时播放多个音频文件,那么后面播放的声音或者会与前面播放的声音进行混合,或者会停止前面播放的声音,在Windows平台上,新播放的声音会停止前面播放的声音。如果要播放其他格式的音频文件,或者需要对播放进行更多的控制,那么就需要使用Phonon多媒体框架来实现了。


二、Phonon 简介
Phonon包含三个基本的概念:媒体对象(Media Objects)、汇点(Sinks)和路径(Paths)。媒体对象是MediaObject类的一个实例,用来管理媒体源,例如一个音乐文件,它提供开始、停止和暂停等简单的播放控制功能;汇点用来从Phonon中输出媒体,例如在部件上渲染视频或者将音频传送到声卡,汇点通常是一个渲染设备,如VideoWidget;路径用来连接Phonon对象,例如连接一个媒体对象和一个汇点,这样形成的关系图在Phonon中被称为媒体图(mediagraph)。下图是一个音频流的媒体图:






下图是一个播放带有声音的视频文件的媒体图:



多媒体功能并不是由Phonon本身实现的,而是由后端(也常被称为引擎)实现的,这包含了连接、管理和驱动底层的硬件或中间技术。对于编程人员来说,这意味着媒体的节点,例如媒体对象、处理器和汇点,它们都由后端提供。而且,后端还负责构建媒体图,例如连接各个节点。       Qt使用的后端,在Windows上是DirectShow,在Mac上是QuickTime,在Linux上是Gstreamer。依赖于底层的系统,在不同的平台上所提供的功能会有所不同。后端可以显示顶层系统的信息,可以获取它支持的媒体格式,例如AVI、mp3或者OGG等。


三、使用Phonon播放音频
当播放音频时,需要创建一个媒体对象,然后将它连接到一个音频输出节点,该节点由AudioOutput类提供,它用来将音频输出到声卡。
1.新建Qt Gui应用,名称为“myPhonon1”,类名“MainWindow”和基类QMainWindow保持默认即可。完成后,在项目文件myPhonon1.pro中添加如下一行代码:
QT       += phonon 然后保存该文件。


2.再到mainwindow.cpp文件中添加头文件包含: #include <phonon>#include <QDebug>#include <QUrl> 并在构造函数中添加如下代码:
Phonon::MediaObject *mediaObject = new Phonon::MediaObject(this);mediaObject->setCurrentSource(Phonon::MediaSource("../myPhonon1/mysong.mp3"));Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);Phonon::Path path = Phonon::createPath(mediaObject, audioOutput);mediaObject->play();
       AudioOutput类用来向音频输出设备发送数据,音频输出需要使用createPath()函数连接到媒体对象上。AudioOutput提供了函数来控制音量的大小,还可以设置静音,而且Phonon还使用AudioOutput提供了一个音量控制部件VolumeSlider类,它是QWidget的子类。另外,Phonon中也提供了播放进度滑块SeekSlider,该类也是QWidget的子类,它需要连接到媒体对象上。


3.往源码目录中添加一个mysong.mp3文件,运行程序就可以自动播放了。不过,现在还无法进行任何的控制。大家可以查看《Qt及Qt Quick开发实战精解》的音乐播放器实例,那是一个比较完整的播放器例子。


四、使用Phonon播放视频


1.新建Qt Gui应用,项目名称为“myPhonon2”,基类选择QWidget,类名为“Widget”。完成后先到项目文件myPhonon2.pro中添加代码:
QT       += phonon 然后保存该文件。


2.播放视频,可以使用VideoWidget类,该部件可以自动选择可用的设备来播放视频。VideoWidget并不会播放媒体流中的音频,如果要播放视频中的音频,那么就要创建一个AudioOutput节点。在mainwindow.cpp文件中添加头文件包含:#include <phonon>#include <QAction>#include <QVBoxLayout>#include <QToolBar>
再在构造函数中添加如下代码:// 创建媒体图
Phonon::MediaObject *mediaObject = new Phonon::MediaObject(this);
Phonon::VideoWidget *videoWidget = new Phonon::VideoWidget(this);
Phonon::createPath(mediaObject, videoWidget);
Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput(
                                    Phonon::VideoCategory, this);
Phonon::createPath(mediaObject, audioOutput);
mediaObject->setCurrentSource(Phonon::MediaSource(
"../myPhonon2/myVideo.WMV"));

// 创建播放进度滑块
Phonon::SeekSlider *seekSlider = new Phonon::SeekSlider(
mediaObject, this);

// 创建工具栏,包含了播放、暂停和停止动作,以及控制音量滑块
QToolBar *toolBar = new QToolBar(this);
QAction *playAction = new QAction(style()->standardIcon(QStyle::SP_MediaPlay), tr("播放"), this);
connect(playAction, SIGNAL(triggered()), mediaObject, SLOT(play()));
QAction *pauseAction = new QAction(style()->standardIcon(QStyle::SP_MediaPause), tr("暂停"), this);
connect(pauseAction, SIGNAL(triggered()), mediaObject, SLOT(pause()));
QAction *stopAction = new QAction(style()->standardIcon(QStyle::SP_MediaStop), tr("停止"), this);
connect(stopAction, SIGNAL(triggered()), mediaObject, SLOT(stop()));
Phonon::VolumeSlider *volumeSlider = new Phonon::VolumeSlider(audioOutput, this);
volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
toolBar->addAction(playAction);
toolBar->addAction(pauseAction);
toolBar->addAction(stopAction);
toolBar->addWidget(volumeSlider);

// 创建布局管理器,将各个部件都添加到布局管理器中
QVBoxLayout *mainLayout = new QVBoxLayout;
videoWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
mainLayout->addWidget(videoWidget);
mainLayout->addWidget(seekSlider);
mainLayout->addWidget(toolBar);
setLayout(mainLayout);
       这里创建了两个路径,分别用于视频流和音频流。创建VideoWidget时不需要指定类别,它会自动指定为VideoCategory类别,我们需要做的只是确保AudioOutput也在同一个类别中。Phonon中的SeekSlider类提供了一个滑块来定位媒体流,只要与媒体对象MediaObject连接后,该部件就可以自动和媒体流的播放进度同步起来,不需要我们手动进行信号和槽的关联。Phonon中的VolumeSlider部件提供了一个用来控制音频输出设备音量的滑块,该滑块还会默认显示一个可以设置静音的图标,这个图标可以使用setMuteVisible()来移除。


3.需要将一个myVideo.WMV的视频文件复制到源码目录,然后运行程序,效果如下图所示。




结语
Movie类是一个使用QImageReader来播放动画的便捷类。该类用来显示没有声音的简单动画,主要支持GIF和MNG格式的文件;在Qt 4.6中新加入了QtMultimedia模块来提供一些底层的多媒体功能,比如音频的采集和回放、频谱分析、操作视频帧等。关于这两个类的使用,可以参考《Qt Creator 快速入门》的第13章,进一步学习Phonon的内容,可以参考第14章。


涉及到的源码:


上一篇:   

下一篇:   

返回:系列教程目录    



kang清峻 发表于 2013-10-12 15:06:28

老师 在QT5.1版本中,好像不存在#include <phonon> ,这个怎么处理呢?

yafeilinux 发表于 2013-10-13 23:08:17

kang清峻 发表于 2013-10-12 15:06 static/image/common/back.gif
老师 在QT5.1版本中,好像不存在#include,这个怎么处理呢?

Qt 5中已经没有phonon了。使用QtMultimedia吧

liuqiam 发表于 2013-12-26 17:42:21

老师,在Qt5.1版本中,我包含的头文件是<QtMultimedia/QSound>,然后我使用QSound 但总是说 无法解析的外部符号 该怎么办呀?

yafeilinux 发表于 2013-12-27 11:59:09

liuqiam 发表于 2013-12-26 17:42 static/image/common/back.gif
老师,在Qt5.1版本中,我包含的头文件是,然后我使用QSound 但总是说 无法解析的外部符号 该怎么办呀? ...

在pro文件中添加       
QT += multimedia

然后使用的时候添加

#include <QSound>

这样调用就可以了:QSound::play("mysounds/bells.wav");

你是怎么使用的?

liuqiam 发表于 2013-12-27 13:43:20

yafeilinux 发表于 2013-12-27 11:59 static/image/common/back.gif
在pro文件中添加       
QT += multimedia



原来我就是没加 QT += multimedia
问题解决了,谢谢。又学习了。

wangxiangjun88 发表于 2014-3-5 22:26:12

第一个播放音乐程序,出现 QSoundEffect(qaudio): Error decoding source 是什么意思?
用的QT5.1 音乐不响,音乐用压缩的MP3格式行吗?

yafeilinux 发表于 2014-3-6 21:58:21

wangxiangjun88 发表于 2014-3-5 22:26 static/image/common/back.gif
第一个播放音乐程序,出现 QSoundEffect(qaudio): Error decoding source 是什么意思?
用的QT5.1 音乐不响 ...

Qt 5中在这部分做了很大改动,有些代码已经不能用了。

侠隐 发表于 2015-2-16 02:31:20

老师,你好。
我在书上《控制视频播放》那里做了最后一个例子,在改变视频(使用诸如videoWidget::setBritteness函数)的亮度、饱和度等那里设置了之后发现没有差别,这是为什么?是不是因为范围的问题,它们的范围都是-1到1.

yafeilinux 发表于 2015-2-16 23:41:31

侠隐 发表于 2015-2-16 02:31 static/image/common/back.gif
老师,你好。
我在书上《控制视频播放》那里做了最后一个例子,在改变视频(使用诸如videoWidget::setBritt ...

这个后来我没有测过过,不过当时视频处理这一块Qt自身的bug挺多的,如果理论学的差不多了,可以用Qt 5的多媒体类试试

gzz0204 发表于 2015-3-4 16:15:33

wangxiangjun88 发表于 2014-3-5 22:26 static/image/common/back.gif
第一个播放音乐程序,出现 QSoundEffect(qaudio): Error decoding source 是什么意思?
用的QT5.1 音乐不响 ...

音乐得是WAV格式的,并且可以先用其他播放器试试是否损坏。

wangxx 发表于 2015-7-8 09:15:01

我使用的时候出现了问题好像是不能链接到phonon库,pro文件中 已经添加了 QT+=phonon

yafeilinux 发表于 2015-7-16 16:29:50

wangxx 发表于 2015-7-8 09:15 static/image/common/back.gif
我使用的时候出现了问题好像是不能链接到phonon库,pro文件中 已经添加了 QT+=phonon ...

你用什么版本的Qt

落寞的巴尔扎克 发表于 2016-9-9 15:14:38

老师,qtcreator2.8.0支持flv格式的视频文件吗

yafeilinux 发表于 2016-9-13 16:03:31

落寞的巴尔扎克 发表于 2016-9-9 15:14 static/image/common/back.gif
老师,qtcreator2.8.0支持flv格式的视频文件吗

如果使用Qt 4,那么默认使用phonon,它需要使用后端来完成播放,建议移植mplayer后端。

tz_zch 发表于 2017-1-6 23:09:51

老师,我在做qt实战精解音乐播放器3.1部分的时候,为什么mediaObject对象在播放按钮关联的槽里面执行不了play函数?执行play后我查看状态立马变成了stop状态,这是怎么回事。
void Widget::setPaused()
{
    if(mediaObject->state() == Phonon::PlayingState)
    {
      qDebug() << "111" << endl;
      mediaObject->pause();
    }
    else
    {
      mediaObject->play();
      qDebug() << mediaObject->state() << "xxx"<< endl;
    }
}

yafeilinux 发表于 2017-1-8 11:08:00

tz_zch 发表于 2017-1-6 23:09 static/image/common/back.gif
老师,我在做qt实战精解音乐播放器3.1部分的时候,为什么mediaObject对象在播放按钮关联的槽里面执行不了pl ...

直接运行代码试试!

yafeilinux 发表于 2017-1-8 11:08:00

tz_zch 发表于 2017-1-6 23:09 static/image/common/back.gif
老师,我在做qt实战精解音乐播放器3.1部分的时候,为什么mediaObject对象在播放按钮关联的槽里面执行不了pl ...

直接运行代码试试!
页: [1]
查看完整版本: 第49篇 进阶(九) 多媒体应用简介