Qt开发总结(22)——多媒体

多t体支持是Qt不可或缺的一部分。但是Qt除了提供直观的GUI界面之外,它还提供访问摄像头和收音机功能所需的API。这使得我们可以完全用Qt自身,不用第三方库就可以写一个视频播放器或者音乐播放器。这对于一些入门者来说似乎很有魅力,我本人在接触到Qt之后就用多媒体技术编写了一个音乐播放器,那时候的我还编写了一个简易版的QQ,装在了女友和自己电脑上。

概述

在Qt多媒体(MultiMedia)中存在两个大的模块——Qt Multimedia,提供了针对音视频的底层API;Qt Multimedia Widgets,提供了简易直观的多媒体窗体。在使用时,需要包含这两个模块对应的头文件,当然还是建议用到什么包含什么。

#include <QtMultimedia>

#include <QtMultimediaWidgets>

对于Qt pro工程的话,需要将支持添加在Qt的pro文件中:

QT += multimedia multimediawidgets

对于windows VS用户,你需要在Qt VS tool中勾选上这两个模块支持。

Qt多媒体涉及的类有:

描述

QAudioOutput

将音频数据发送到音频输出设备

QAudioRecorder

记录来自音频源的媒体内容。

QCamera

访问相机取景器。

QCameraImageCapture

用相机拍摄静止图像。

QMediaRecorder

记录来自摄像机或收音机调谐器源的媒体内容。

QMediaPlayer

从源播放媒体。

QMediaPlaylist

要播放的媒体列表。

QRadioTuner

接入无线电设备。

QAbstractVideoSurface

视频演示的基类。

音频 Audio

Qt Multimedia提供了一系列音频类,涵盖了音频输入,输出和处理的低级和高级方法。要播放非简单的媒体或音频文件,未压缩的音频,可以使用QMediaPlayer类。该QMediaPlayer类也能够播放视频。压缩音频格式确实取决于操作系统环境,以及用户可能安装了哪些媒体插件。下面的例子显示了简单的播放mp3的方法:

  player = new QMediaPlayer;
  // ...
  player->setMedia(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3"));
  player->setVolume(50);
  player->play();

 

或者通过播放列表播放,甚至是远程(网络)上的歌曲:

  player = new QMediaPlayer;

  playlist = new QMediaPlaylist(player);
  playlist->addMedia(QUrl("http://example.com/myfile1.mp3"));
  playlist->addMedia(QUrl("http://example.com/myfile2.mp3"));
  // ...
  playlist->setCurrentIndex(1);
  player->play();

 

为了将音频记录到文件,可以使用QAudioRecorder类压缩来自输入设备的音频数据并进行记录。

 

  audioRecorder = new QAudioRecorder;

  QAudioEncoderSettings audioSettings;
  audioSettings.setCodec("audio/amr");
  audioSettings.setQuality(QMultimedia::HighQuality);

  audioRecorder->setEncodingSettings(audioSettings);

  audioRecorder->setOutputLocation(QUrl::fromLocalFile("test.amr"));
  audioRecorder->record();

 

除了上述对声音设备的原始访问之外,QSoundEffect类还提供了一种更高级别的声音播放方式。这些类允许您指定WAV格式文件,然后可以在必要时以低延迟播放。您可以调整播放声音效果的循环次数,以及效果的音量(或静音)。

QAudioProbe类允许您监视正在由更高级的类,如QMediaPlayer,QCamera和QAudioRecorder播放或录制的音频数据。您可以用setSource简单地指向这些类的对象,并在音频缓冲区接收它们。这对于一些音频处理任务很有用,尤其是对于可视化或调整增益。注意,您无法修改缓冲区,缓冲区的到达时间可能与媒体管道处理缓冲区的时间略有不同。

  audioRecorder = new QAudioRecorder;

  QAudioEncoderSettings audioSettings;
  audioSettings.setCodec("audio/amr");
  audioSettings.setQuality(QMultimedia::HighQuality);

  audioRecorder->setEncodingSettings(audioSettings);

  audioRecorder->setOutputLocation(QUrl::fromLocalFile("test.amr"));

  audioProbe = new QAudioProbe(this);
  if (audioProbe->setSource(audioRecorder)) {
      // Probing succeeded, audioProbe->isValid() should be true.
      connect(audioProbe, SIGNAL(audioBufferProbed(QAudioBuffer)),
              this, SLOT(calculateLevel(QAudioBuffer)));
  }

  audioRecorder->record();
  // Now audio buffers being recorded should be signaled
  // by the probe, so we can do things like calculating the
  // audio power level, or performing a frequency transform

 

Qt Multimedia提供了用于对音频输入和输出设备进行原始访问的类,允许应用程序从麦克风等设备接收原始数据,并将原始数据写入扬声器或其他输出设备。通常,这些类不执行任何音频解码或其他处理,但是它们可以支持不同类型的原始音频数据。

QAudioOutput类提供了原始音频数据输出,而QAudioInput提供原始音频数据输入。这两类都有可调节的缓冲区和延迟,因此它们既适用于低延迟的用例(如游戏或VOIP)又适用于高延迟的用例(如音乐播放)。可用的硬件确定哪些音频输出和输入可用。

在某些情况下,您可能希望解码压缩的音频文件并自己做进一步处理(例如,混合多个样本或使用自定义数字信号处理算法)。QAudioDecoder支持解码来自QIODevice实例的本地文件或数据流。

 

  QAudioFormat desiredFormat;
  desiredFormat.setChannelCount(2);
  desiredFormat.setCodec("audio/x-raw");
  desiredFormat.setSampleType(QAudioFormat::UnSignedInt);
  desiredFormat.setSampleRate(48000);
  desiredFormat.setSampleSize(16);

  QAudioDecoder *decoder = new QAudioDecoder(this);
  decoder->setAudioFormat(desiredFormat);
  decoder->setSourceFilename("level1.mp3");

  connect(decoder, SIGNAL(bufferReady()), this, SLOT(readBuffer()));
  decoder->start();

  // Now wait for bufferReady() signal and call decoder->read()

 

视频Video

Qt多媒体提供用于播放和处理视频数据的高级C ++类和低级C ++类。这些类中的某些类也与相机和音频类别重叠,这可能很有用。

与音频类似,您可以使用QMediaPlayer类简单的解码视频文件,并使用QVideoWidget,QGraphicsVideoItem或自定义类显示它。

  player = new QMediaPlayer;

  playlist = new QMediaPlaylist(player);
  playlist->addMedia(QUrl("http://example.com/myclip1.mp4"));
  playlist->addMedia(QUrl("http://example.com/myclip2.mp4"));

  videoWidget = new QVideoWidget;
  player->setVideoOutput(videoWidget);

  videoWidget->show();
  playlist->setCurrentIndex(1);
  player->play();

 

或者,用QGraphicsVideoItem显示它: 

  player = new QMediaPlayer(this);

  QGraphicsVideoItem *item = new QGraphicsVideoItem;
  player->setVideoOutput(item);
  graphicsView->scene()->addItem(item);
  graphicsView->show();

  player->setMedia(QUrl("http://example.com/myclip4.ogv"));
  player->play();

Qt Multimedia提供了许多底层类,使处理视频帧变得更加容易。这些类主要用于编写处理视频或摄像机视频帧的代码,QVideoFrame类封装了视频帧允许内容被映射到系统内存,用于进一步处理,而类QAbstractVideoSurface允许您接收从这些QMediaPlayer和QCamera发送来的视频帧。可以通过下面的框架实现一个自定义接受类MyVideoSurface。然后在player时调用player->setVideoOutput(myVideoSurface)。

 

 class MyVideoSurface : public QAbstractVideoSurface
  {
      QList<QVideoFrame::PixelFormat> supportedPixelFormats(
              QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const
      {
          Q_UNUSED(handleType);

          // Return the formats you will support
          return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_RGB565;
      }

      bool present(const QVideoFrame &frame)
      {
          Q_UNUSED(frame);
          // Handle the frame and do your processing

          return true;
      }
  };

 

您可以将QMediaRecorder类与其他类结合使用,以将视频录制到磁盘。主要是与相机一起使用,因此有关更多信息,参见下面的相机描述。

当使用诸如QMediaPlayer,QMediaRecorder或QCamera之类的其他类时,可以使用QVideoProbe类访问这些类的视频帧。创建高级媒体类后,可以通过setSource指向该实例。这对于在正常渲染视频时执行一些视频处理任务(例如条形码识别或对象检测)很有用。同样的,您不能使用此类影响视频帧,另外,它们的到达时间可能与渲染时间略有不同。

 

  camera = new QCamera;
  viewfinder = new QCameraViewfinder();
  camera->setViewfinder(viewfinder);

  camera->setCaptureMode(QCamera::CaptureVideo);

  videoProbe = new QVideoProbe(this);

  if (videoProbe->setSource(camera)) {
      // Probing succeeded, videoProbe->isValid() should be true.
      connect(videoProbe, SIGNAL(videoFrameProbed(QVideoFrame)),
              this, SLOT(detectBarcodes(QVideoFrame)));
  }

  camera->start();
  // Viewfinder frames should now also be emitted by
  // the video probe, even in still image capture mode.
  // Another alternative is to install the probe on a
  // QMediaRecorder connected to the camera to get the
  // recorded frames, if they are different from the
  // viewfinder frames.

 

相机Camera

Qt MultiMedia API提供了许多与摄像头相关的类,因此您可以从移动设备摄像头或网络摄像头访问图像和视频。在使用相机API之前,您应该检查相机在运行时是否可用。如果没有,则可以例如在应用程序中禁用与相机相关的功能。要在代码中执行此检查,请使用QCameraInfo :: availableCameras()函数,如以下示例所示:

  bool checkCameraAvailability()
  {
      if (QCameraInfo::availableCameras().count() > 0)
          return true;
      else
          return false;
  }

 

确定摄像机是否可用后,使用QCamera类访问它。当有多个摄像机可用时,您可以指定要使用的摄像机。

 

  QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
  foreach (const QCameraInfo &cameraInfo, cameras) {
      if (cameraInfo.deviceName() == "mycamera")
          camera = new QCamera(cameraInfo);
  }

 

您还可以通过摄像机在系统上的物理位置而不是设备ID选择摄像机。这在经常具有前置和后置摄像头的移动设备上很有用。

camera = new QCamera(QCamera::FrontFace);

如果未指定设备ID和位置,则将使用默认摄像机。在台式机平台上,默认相机由用户在系统设置中设置。在移动设备上,后置摄像头通常是默认摄像头。你可以在枚举QCameraInfo :: defaultCamera得到有关使用默认的摄像头信息。

尽管并非绝对必要,但能够看到相机所指向的位置通常很有用。大多数数码相机允许以较低的分辨率(通常最大为相机显示屏的尺寸)从相机传感器馈送图像,因此您可以以较低分辨率拍摄视频,然后切换到较慢但较高分辨率的模式以拍摄照片。您的选择取决于您使用的是Widgets还是QGraphicsView。当是Widgets时,使用QCameraViewfinder类,当是 QGraphicsView显示控件时,使用QGraphicsVideoItem。

  camera = new QCamera;
  viewfinder = new QCameraViewfinder;
  camera->setViewfinder(viewfinder);
  viewfinder->show();

  camera->start(); // to start the viewfinder

 

对于高级用法(例如图像检测),还可以从QAbstractVideoSurface派生并将其设置为QCamera对象的取景器。在这种情况下,您将需要自己渲染取景器图像。

 

  camera = new QCamera;
  mySurface = new MyVideoSurface;
  camera->setViewfinder(mySurface);

  camera->start();
  // MyVideoSurface::present(..) will be called with viewfinder frames

 

在移动设备上,取景器图像可能并不总是沿您期望的方向。这些设备上的摄像头传感器通常是横向安装的,而屏幕的自然方向是纵向的。这会导致图像根据设备方向而出现横向或倒置。为了在屏幕上反映用户实际看到的内容,应确保将取景器框架始终旋转到正确的方向,同时考虑到摄像头传感器的方向和当前的显示方向。

 

  // Assuming a QImage has been created from the QVideoFrame that needs to be presented
  QImage videoFrame;
  QCameraInfo cameraInfo(camera); // needed to get the camera sensor position and orientation

  // Get the current display orientation
  const QScreen *screen = QGuiApplication::primaryScreen();
  const int screenAngle = screen->angleBetween(screen->nativeOrientation(), screen->orientation());

  int rotation;
  if (cameraInfo.position() == QCamera::BackFace) {
      rotation = (cameraInfo.orientation() - screenAngle) % 360;
  } else {
      // Front position, compensate the mirror
      rotation = (360 - cameraInfo.orientation() + screenAngle) % 360;
  }

  // Rotate the frame so it always shows in the correct orientation
  videoFrame = videoFrame.transformed(QTransform().rotate(rotation));

 

设置取景器并找到可拍照的东西后,要捕获图像,我们需要初始化一个新的QCameraImageCapture对象。然后所需要做的就是启动相机,锁定相机,以使物体对准焦点,并且在发生图像捕捉时设置与取景器相同的条件,捕捉图像,最后解锁相机以准备下一张照片。

 

  imageCapture = new QCameraImageCapture(camera);

  camera->setCaptureMode(QCamera::CaptureStillImage);
  camera->start(); // Viewfinder frames start flowing

  //半按快门按钮
  camera->searchAndLock();

  //在快门按钮按下
  imageCapture->capture();

  //在快门按钮上释放
  camera->unlock();

 

如果要录制视频,需要使用QMediaRecorder对象。我们需要像以前一样创建一个相机对象,但是这次同时还创建一个取景器,我们还将初始化一个QMediaRecorder对象。

  camera = new QCamera;
  recorder = new QMediaRecorder(camera);

  camera->setCaptureMode(QCamera::CaptureVideo);
  camera->start();

  //按下快门按钮
  recorder->record();

  // 稍后,或再次按下快门
  recorder->stop();

 

可以将来自mediaRecorder的信号连接到插槽,以对录制状态的更改或错误事件做出反应。录制本身从调用mediaRecorder 的record()函数开始,这将导致发出stateChanged()信号。录制过程可以通过record(),stop()和setMuted()接口改变其过程。

聚焦(和缩放)主要由QCameraFocus类管理。QCameraFocus允许开发人员通过FocusMode和FocusPointMode的枚举设置常规策略。FocusMode处理诸如AutoFocus,ContinuousFocus和InfinityFocus之类的设置,而FocusPointMode处理视图内用于自动聚焦模式的各个聚焦区域。FocusPointMode支持面部识别(相机在其中支持),中心对焦和可以指定对焦点的自定义对焦。

有许多设置会影响撞击相机传感器的光量,从而影响最终图像的质量。QCameraExposure类允许您调整这些设置。您可以使用此类来实现一些技术,例如通过锁定曝光参数(使用QCamera :: searchAndLock())来实现高动态范围(HDR)照片,或者通过设置具有小光圈的慢快门速度来实现运动模糊。

在图像处理方面,QCameraImageProcessing类可以对图像进行常见的图像处理。这包括白平衡(或色温),对比度,饱和度,锐化和去噪。大多数相机都支持所有这些设置的自动设置,因此除非用户需要特定设置,否则无需调整它们。

诸如图像捕获和自动聚焦之类的各种操作是异步发生的。只要相机支持,通常可以通过开始新操作来取消这些操作。对于图像捕获,可以通过调用cancelCapture()取消操作。对于自动对焦,可以通过调用QCamera :: unlock(QCamera :: LockFocus)来完成自动曝光或白平衡消除。

收音机 Radio

Qt多媒体API提供了许多与收音机相关的类,用于控制系统的无线电调谐器,并为无线电台提供对无线电数据系统(RDS)信息的访问。Radio API包含两个单独的组件。收音机调谐器QRadioTuner,用于处理收音机硬件的控制以及调谐。另一个是收音机数据组件,QRadioData,可访问RDS信息。

需要注意,radio实际的支持取决于基础系统,并且仅当系统收音机调谐器支持RDS时才适用。

  

  radio = new QRadioTuner;
  connect(radio, SIGNAL(frequencyChanged(int)), this, SLOT(freqChanged(int)));
  if (radio->isBandSupported(QRadioTuner::FM)) {
      radio->setBand(QRadioTuner::FM);
      radio->setFrequency(yourRadioStationFrequency);
      radio->setVolume(100);
      radio->start();
  }

 

Radio对象在bandChanged(), frequencyChanged(), stereoStatusChanged(), searchingChanged(), signalStrengthChanged(), volumeChanged(), mutedChanged().时都会触发信号,可以用来实现相应的功能。

多媒体控件

上述描述和例子中或多多少涉及了Qt Multimedia Widgets的相关类,这里把他们列出来:

QCameraViewfinder

相机取景器控件

QGraphicsVideoItem

显示由QMediaObject产生的视频的图形项

QVideoWidget

展示媒体对象产生的视频的控件

QVideoWidgetControl

实施视频控件的媒体控件

典型应用:

 

  // QCameraViewfinder
  camera = new QCamera;
  viewfinder = new QCameraViewfinder();
  viewfinder->show();
  camera->setViewfinder(viewfinder);
  imageCapture = new QCameraImageCapture(camera);
  camera->setCaptureMode(QCamera::CaptureStillImage);
  camera->start();
  
  // QGraphicsVideoItem
  player = new QMediaPlayer(this);
  QGraphicsVideoItem *item = new QGraphicsVideoItem;
  player->setVideoOutput(item);
  graphicsView->scene()->addItem(item);
  graphicsView->show();
  player->setMedia(QUrl("http://example.com/myclip4.ogv"));
  player->play();

  // QVideoWidget
  player = new QMediaPlayer;
  playlist = new QMediaPlaylist(player);
  playlist->addMedia(QUrl("http://example.com/myclip1.mp4"));
  playlist->addMedia(QUrl("http://example.com/myclip2.mp4"));
  videoWidget = new QVideoWidget;
  player->setVideoOutput(videoWidget);
  videoWidget->show();
  playlist->setCurrentIndex(1);
  player->play();

  // QVideoWidgetControl
  QVideoWidgetControl *widgetControl = mediaService->requestControl<QVideoWidgetControl *>();
  layout->addWidget(widgetControl->videoWidget());

 

例子

这里给出一个比较综合的例子:https://download.csdn.net/download/bjtuwayne/12044747

 

发布了76 篇原创文章 · 获赞 63 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/bjtuwayne/article/details/103795350