Qt的多媒体api分为四个主要组件。
一、音频概览
1、QAudio:包含音频类使用的枚举
QAudio::Error:错误信息枚举
QAudio::Mode:输入或者输出模式
QAudio::Role:描述音频流的角色。
QAudio::State:音频设备当前的状态
QAudio::VolumeScale:定义了不同的音频音量刻度
qreal convertVolume(qreal volume, VolumeScale from, VolumeScale to)//调整音频音量
2、QAudioBuffer:表示具有特定格式和采样率的音频样本集合。
3、QAudioBuffer::StereoFrame:为立体声音频帧提供了一个简单的包装器。
4、QAudioDecoder:是一个用于解码本地音频媒体文件的高级类。
调用start()和stop()函数开始或者停止解码。
setSourceDevice()/setSourceFilename()设置要解码的资源,可以是文件,也可以是某个输入输出设备
stateChanged()信号可以捕捉解码过程中的所处的状态
bufferReady()和bufferAvailable()捕捉这两个信号之后再调用read()函数 便可获取解码的数据
finished()解码成功的信号 error()出错的信号
5、QAudioDeviceInfo类提供了一个接口来查询音频设备及其功能。QAudioDeviceInfo被Qt用来构造与设备通信的类——例如QAudioInput和QAudioOutput。
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//获取本机支持的输出设备
foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) {
qDebug() << "输出设备:" << deviceInfo.deviceName();
//支持的音频编码格式
qDebug() << deviceInfo.supportedCodecs();//"audio/pcm"
}
//获取本机支持的输入设备
foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioInput)) {
qDebug() << "输入设备:" << deviceInfo.deviceName();
//支持的音频编码格式
qDebug() << deviceInfo.supportedCodecs();//"audio/pcm"
}
return a.exec();
}
6、QAudioFormat类存储音频流参数信息。音频格式指定音频流中的数据是如何排列的。该类通常与QAudioInput或QAudioOutput一起使用,以允许您指定正在读取或写入的音频流的参数,或者在处理内存中的示例时使用QAudioBuffer。
这里介绍的比较详细:
https://blog.csdn.net/tianyuan521521/article/details/41824809
7、QAudioInput类提供了一个接口,用于从音频输入设备接收音频数据。
union Endian{
int i;
char c;
};
QAudioFormat::Endian getEndian()
{
Endian endian;
endian.i = 1;
if(endian.c == 1){
qDebug() << "小端";
return QAudioFormat::LittleEndian;
}
else{
qDebug() << "大端";
return QAudioFormat::BigEndian;
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QFile destinationFile;
QAudioInput *audio;
{
destinationFile.setFileName("F:/aaa.raw");
destinationFile.open(QIODevice::WriteOnly|QIODevice::Truncate);
//设置所需的格式
QAudioFormat format;
//设置大小端
format.setByteOrder(getEndian());
//设定声道数目 1是平声道 2是立体声
format.setChannelCount(1);
//设置编码器
format.setCodec("audio/pcm");//所有平台都支持
//设置采样率 单位HZ 44100HZ(标准CD级) 8000HZ(对于人说话的声音已足够)
format.setSampleRate(8000);
//设置采样大小 通常是8或16
format.setSampleSize(8);
//设置采样类型 分为有符号 无符号 浮点 一般采用无符号
format.setSampleType(QAudioFormat::UnSignedInt);
//获得默认的音频设备
QAudioDeviceInfo deviceInfo = QAudioDeviceInfo::defaultInputDevice();
//检测是否支持我们设置的音频格式
if(!deviceInfo.isFormatSupported(format)){
//设置一个最接近的格式
format = deviceInfo.nearestFormat(format);
}
//创建一个音频输入设备
audio = new QAudioInput(format);
//观察设备的状态
QObject::connect(audio,&QAudioInput::stateChanged,[=](QAudio::State state){
switch (state) {
case QAudio::StoppedState:
qDebug() << "音频设备处于关闭状态,没有处理任何音频数据";
break;
case QAudio::SuspendedState:
qDebug() << "音频设备处于挂起状态,此状态仅在调用suspend()后输入。";
break;
case QAudio::ActiveState:
qDebug() << "正在处理音频数据,此状态是在调用start()之后设置的,而音频数据可用于处理";
break;
case QAudio::IdleState:
qDebug() << "传入的QIODevice没有数据,音频系统缓冲区为空,调用start()后设置此状态,此时没有音频数据可处理。";
break;
default:
break;
}
});
//开启一个10s的音频输入
QEventLoop loop;
QTimer::singleShot(10000, &loop, SLOT(quit()));
audio->start(&destinationFile);
loop.exec();
qDebug() << "11111";
//保存音频
audio->stop();
destinationFile.close();
delete audio;
}
return a.exec();
}
8、QAudioOutput类提供了一个接口,用于将音频数据发送到音频输出设备
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QFile *sourceFile = new QFile("F:/aaa.raw");
QAudioOutput *audio;
sourceFile->open(QIODevice::ReadOnly);
QAudioFormat format;
format.setByteOrder(QAudioFormat::LittleEndian);
format.setChannelCount(1);
format.setCodec("audio/pcm");
format.setSampleRate(8000);
format.setSampleSize(8);
format.setSampleType(QAudioFormat::UnSignedInt);
QAudioDeviceInfo info = QAudioDeviceInfo::defaultOutputDevice();
if(!info.isFormatSupported(format))
format = info.nearestFormat(format);
audio = new QAudioOutput(format);
QObject::connect(audio,&QAudioOutput::stateChanged,[=](QAudio::State state){
switch (state) {
case QAudio::StoppedState:
qDebug() << "音频设备处于关闭状态,没有处理任何音频数据";
if(audio->error() == QAudio::NoError)
qDebug() << "没有错误";
else
qDebug() << audio->error();
break;
case QAudio::SuspendedState:
qDebug() << "音频设备处于挂起状态,此状态仅在调用suspend()后输入。";
break;
case QAudio::ActiveState:
qDebug() << "正在处理音频数据,此状态是在调用start()之后设置的,而音频数据可用于处理";
break;
case QAudio::IdleState:
qDebug() << "播放完毕(无数据)";
audio->stop();
sourceFile->close();
delete audio;
break;
default:
break;
}
});
audio->start(sourceFile);
return a.exec();
}
9、QAudioProbe类允许您监视正在播放或录制的音频。
10、QAbstractAudioDeviceInfo类是音频后端的基类。
11、QAudioSystemPlugin类为音频插件提供了一个抽象基础。
12、QSound类提供了播放.wav声音文件的方法。比较简单
QSound::play("mysounds/bells.wav");
或者
QSound bells("mysounds/bells.wav");
bells.play();
相关信号:
isFinished()
loopsRemaining()
13、QSoundEffect类提供了一种播放低延迟音效的方法。
二、视频概览
Qt多媒体提供了用于播放和操作视频数据的高级和低级c++类,以及用于回放和控制的QML类型。其中一些类还与摄像机类和音频类重叠,这很有用。
1、QAbstractPlanarVideoBuffer类是平面视频数据的抽象
2、QAbstractVideoBuffer类是视频数据的抽象。
3、QAbstractVideoFilter类表示应用于VideoOutput类型接收的视频帧的筛选器。
4、QVideoFilterRunnable类表示拥有所有图形和计算资源的筛选器的实现,并执行实际的筛选或计算。
5、QAbstractVideoSurface类是视频表示表面的基类。
6、QVideoFrame类表示一帧视频数据。
7、QVideoProbe类允许您监视正在播放或录制的视频帧。
8、QVideoSurfaceFormat类指定视频表示表面的流格式。
以上类都是与视频相关的辅助类,单单使用无法进行视频功能的编码,需要结合 QMediaPlayer类 QCamera类等。
三、相机概览
Qt多媒体API提供了许多相机相关的类,因此您可以从移动设备相机或web相机访问图像和视频。
以下概述相机的工作方式:相机组件的一端是镜头组件(一个或多个镜头,用于将光线聚焦到传感器上)。镜头本身有时可以移动来调整焦距和变焦等东西,也可以固定在一个固定的位置上,以便在焦距和成本之间取得良好的平衡。
一些镜头组件可以自动调整,这样距离相机不同距离的物体就可以保持对焦。这通常是通过测量镜头特定区域的锐度来完成的,并通过调整镜头组件直到其锐度达到最大。在某些情况下,相机将始终使用的中心框架,这一点。其他相机也可能允许指定区域对焦(用于“触摸变焦”或“脸部变焦”功能)。
一旦光线到达传感器,它就被转换成数字像素。这个过程可以依赖于很多东西,但最终归结为两件事——允许转换的时间和光线的亮度。转换时间越长,质量越好。使用闪光灯可以让更多的光线照射到传感器上,让它更快地转换像素,在相同的时间内提供更好的质量。相反,允许较长的转换时间可以让你在较暗的环境下拍照,只要相机是稳定的。
当传感器捕获图像后,相机固件对其执行各种图像处理任务,以补偿各种传感器特性、当前光照和所需的图像属性。更快的传感器像素转换时间往往会引入数字噪声,因此可以根据相机传感器的设置进行一些图像处理来消除这种噪声。
还可以调整图片的颜色在这个阶段补偿不同的光源——荧光灯和阳光给同一个对象非常不同的表象,所以图像可以根据图片的白平衡调整(由于不同颜色的光源的温度)。
一些形式的“特效”也可以在这个阶段进行。黑色和白色,黑色,或“消极”风格的图像可以产生。
最后,一旦一个完美的聚焦,曝光和处理的图像已经创建,它可以很好地使用。相机图像可以通过应用程序代码进一步处理(例如,检测条形码,或将全景图像拼接在一起),或保存为JPEG之类的通用格式,或用于创建电影。许多这些任务都有类来帮助它们。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
//检测和选择相机
if(QCameraInfo::availableCameras().count() > 0){
//遍历
QList cameras = QCameraInfo::availableCameras();
foreach (const QCameraInfo info, cameras) {
qDebug() << info.deviceName();
}
//获取默认的相机
QCamera *camera = new QCamera(QCameraInfo::defaultCamera(),this);
//在手机上可以设置前置还是后置
// QCamera *camera = new QCamera(QCamera::FrontFace,this);//前置
// QCamera *camera = new QCamera(QCamera::BackFace,this);//后置
//设置一个取景器部件
QCameraViewfinder *viewFinder = new QCameraViewfinder;
// viewFinder->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
setCentralWidget(viewFinder);
camera->setViewfinder(viewFinder);
viewFinder->show();//显示部件
if(camera->isCaptureModeSupported(QCamera::CaptureStillImage)){
//截图
//构造一个图片捕捉对象
QCameraImageCapture *imageCapture = new QCameraImageCapture(camera);
QAction *capture = menuBar()->addAction("截图");
connect(capture,&QAction::triggered,[=]{
camera->setCaptureMode(QCamera::CaptureStillImage);//设置捕捉的模式为图片捕捉
//锁住 然后 截图
camera->searchAndLock();
imageCapture->capture();//保存到默认位置
// imageCapture->capture("F:/aaa.jpg");//保存指定位置
camera->unlock();
});
}else{
qDebug() << "不支持截图";
}
if(camera->isCaptureModeSupported(QCamera::CaptureVideo)){
//录制
//构造一个录制对象
QMediaRecorder *mediaRecorder = new QMediaRecorder(camera);
QAction *recordMoviesStart = menuBar()->addAction("开始录制");
connect(recordMoviesStart,&QAction::triggered,[=]{
camera->setCaptureMode(QCamera::CaptureVideo);//设置捕捉的模式为媒体录制
qDebug() << "开始录制";
mediaRecorder->record();
});
QAction *recordMoviesStop = menuBar()->addAction("停止录制");
connect(recordMoviesStop,&QAction::triggered,[=]{
qDebug() << "停止录制";
mediaRecorder->stop();
});
//查看 默认的录制保存的位置
connect(mediaRecorder,&QMediaRecorder::actualLocationChanged,
[=](const QUrl &location){
qDebug() << location.url();
});
connect(mediaRecorder,QOverload::of(&QMediaRecorder::error),
[=](QMediaRecorder::Error error){
qDebug() << mediaRecorder->errorString();
});
connect(mediaRecorder,&QMediaRecorder::statusChanged,[=](QMediaRecorder::Status status){
switch(status){
case QMediaRecorder::UnavailableStatus:
qDebug() << "所连接的媒体对象不可用或不支持记录器。";
break;
case QMediaRecorder::UnloadedStatus:
qDebug() << "这台录音机可以使用,但没有装载。";
break;
case QMediaRecorder::LoadingStatus:
qDebug() << "记录器正在初始化。";
break;
case QMediaRecorder::LoadedStatus:
qDebug() << "记录器初始化并准备记录媒体";
break;
case QMediaRecorder::StartingStatus:
qDebug() << "请求记录,但尚未激活。";
break;
case QMediaRecorder::RecordingStatus:
qDebug() << "记录是活跃的。";
break;
case QMediaRecorder::PausedStatus:
qDebug() << "记录是停了下来。";
break;
case QMediaRecorder::FinalizingStatus:
qDebug() << "随着媒体的最终确定,录音停止。";
break;
}
});
}else{
qDebug() << "不支持录制";
}
//开启相机
camera->start();
}else{
qDebug() << "无可用的相机";
}
}
四、收音机概览
五、局限性:Qt多媒体api构建在底层平台的多媒体框架之上。这可能意味着对各种编解码器或容器的支持在不同的机器之间可能有所不同,这取决于最终用户安装了什么。
六、高级用法:对于希望访问某些平台特定设置或将Qt多媒体api移植到新的平台或技术的开发人员,请参见多媒体后端开发。
七、下面是这个模块提供的重要c++类的列表
类 | 描述 |
QAudioOutput |
将音频数据发送到音频输出设备 |
QAudioRecorder | 从音频源记录媒体内容。 |
QCamera | 截图/录像 |
QCameraImageCapture | 截图辅助类 |
QMediaRecorder | 录像辅助类 |
QMediaPlayer | 从源文件播放媒体。 |
QMediaPlaylist | 播放QMediaPlayer的媒体列表。 |
QRadioTuner | 无线电设备的访问。 |
QAbstractVideoSurface | 用于视频演示的基类。 |
1、QAudioRecorder类用于录制音频。
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//获得可用音频输入的列表
QAudioRecorder *recorder = new QAudioRecorder;
QStringList inputs = recorder->audioInputs();
qDebug() << inputs;
//获得默认音频输入设备
qDebug() << recorder->defaultAudioInput();
//音频编码器设置
QAudioEncoderSettings settings = recorder->audioSettings();
qDebug() << settings.codec();//windows下默认的是audio/pcm
#if defined(Q_OS_UNIX) || defined(Q_OS_ANDROID)
settings.setCodec("audio/amr");
settings.setQuality(QMultimedia::HighQuality);
recorder->setOutputLocation(QUrl::fromLocalFile("F:/aaa.amr"));
#else
settings.setCodec("audio/pcm");
settings.setQuality(QMultimedia::HighQuality);
recorder->setOutputLocation(QUrl::fromLocalFile("F:/aaa.wav"));
#endif
QObject::connect(recorder,&QAudioRecorder::actualLocationChanged,[=](const QUrl &location){
qDebug() << location.url();//windows下默认的文件后缀是wav
});
//录音10s
recorder->record();
QEventLoop loop;
QTimer::singleShot(10000,&loop,SLOT(quit()));
loop.exec();
recorder->stop();
qDebug() << "录制完成";
return a.exec();
}
2、QMediaPlayer类允许播放媒体源。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QWidget *widget = new QWidget;
QVBoxLayout *layout = new QVBoxLayout;
widget->setLayout(layout);
QProgressBar *bar = new QProgressBar;
layout->addWidget(bar);
QVideoWidget *video = new QVideoWidget;
layout->addWidget(video);
setCentralWidget(widget);
resize(300,200);
QAction *mp3 = menuBar()->addAction("播放mp3");
QAction *mp4 = menuBar()->addAction("播放mp4");
connect(mp3,&QAction::triggered,[=]{
QEventLoop loop;
QMediaPlayer media;
media.setMedia(QUrl::fromLocalFile("F:/aaa.wav"));//windows平台支持
media.setVolume(50);
connect(&media,&QMediaPlayer::durationChanged,[=](qint64 duration){
bar->setMaximum(duration);
});
connect(&media,&QMediaPlayer::positionChanged,[=,&loop](qint64 duration){
bar->setValue(duration);
if(duration == bar->maximum())
loop.quit();
});
media.play();
qDebug() << "playing...";
loop.exec();
qDebug() << "play end...";
});
connect(mp4,&QAction::triggered,[=]{
QEventLoop loop;
QMediaPlaylist list;
list.addMedia(QUrl::fromLocalFile("F:/WIN_20190109_14_09_42_Pro.avi"));//windows平台支持
list.setCurrentIndex(0);
QMediaPlayer player;
player.setPlaylist(&list);
player.setVideoOutput(video);
video->show();
connect(&player,&QMediaPlayer::durationChanged,[=](qint64 duration){
bar->setMaximum(duration);
});
connect(&player,&QMediaPlayer::positionChanged,[=,&loop](qint64 position){
bar->setValue(position);
if(position == bar->maximum())
loop.quit();
});
player.play();
qDebug() << "playing...";
loop.exec();
qDebug() << "play end...";
});
}