Qt Multimedia 在 Qt6.2中的新变化

英文原文

---

Qt 6.2 的第一个测试版刚刚发布,在多个其他新附加组件中加入了全新的 Qt 多媒体模块。

Qt Multimedia 是一个在 Qt 6 中发生了较大变化的模块。在很多方面,它是一个新的 API 和实现,尽管我们重新使用了 Qt 5.15 中的一些代码。

虽然我们试图为我们的大多数模块保持 Qt 5 和 Qt 6 之间尽可能多的源代码兼容性,但我们不得不在此处进行大量更改以使 API 和实现适合未来,最终决定以最好的为目标 API 而不是最大的兼容性。 如果您一直在 Qt 5 中使用 Qt Multimedia,您将需要对您的实现进行更改。

这篇博文将尝试引导您完成最大的变化,同时查看 API 和内部结构。

## 目标

Qt 5 中的 Qt 多媒体有一个相当松散定义的范围。不同后端对 API 不同部分的支持不一致,并且 API 本身的部分内容不容易跨平台使用。

对于 Qt 6,我们试图在一定程度上缩小范围,并致力于开发一套一致的功能,适用于所有支持的平台。我们还没有达到这个目标,但希望通过 Qt 6.2.0 的发布填补大部分实施空白。

我们希望在 Qt 6.2 中支持的主要用例是:

- 音视频播放

- 音频和视频录制(来自相机和麦克风)

- 低级(基于 PCM)音频和音频解码

- 与 Qt Quick 和小部件集成

- 尽量使用硬件加速

据我们所知,这些功能涵盖了我们用户过去使用 Qt 多媒体的大部分用例。我们的目标是首先关注那些核心用例,并确保它们在我们所有平台上一致工作,然后再使用新功能扩展模块。

## 内部架构变化

Qt 5 中的 Qt Multimedia 有一个复杂的基于插件的架构,使用多个插件来实现不同的前端功能。一个完整的多媒体后端实现将包含不少于 4 个插件。用于实现这些插件的后端 API 是公开的,很难调整和改进这些后端的功能。

构建的架构非常难以维护和开发模块。在 Qt6 中,我们选择显着简化这一点并移除插件基础设施。现在在编译时选择后端并编译到 Qt Multimedia 的共享库中。现在只有一个后端 API 涵盖了所有的多媒体,消除了我们在 Qt 5 中人为拆分成多个后端的问题。最后,我们选择将后端 API 设为私有,以便我们将来可以轻松地对其进行调整和扩展。

完成后,我们可以仔细查看平台相关后端代码所需的 API 和接口。我们设法将实现多媒体后端所需的类集从 40 个减少到 15 个,并减少了纯虚拟方法的数量,为许多非必要功能提供了后备实现。

新的后端 API 在某种程度上模仿了我们在 Qt Gui 中用于窗口系统集成的 QPA 架构,并且新的 QPlatformMediaIntegration 类现在确实作为通用入口点和工厂类来实例化平台相关的后端对象。在大多数情况下,我们现在的目标是在公共 API 中的类和实现该功能的类之间建立一对一的关系。所以,公共 QMediaPlayer API 有一个 QPlatformMediaPlayer 类实现平台相关的功能。

通过这些更改,我们还可以删除大量在前端和后端之间重复的代码,并避免它们之间的大量呼叫转移。有了这个,我们还可以将许多跨平台功能和验证移到代码的共享、平台独立部分中。

总而言之,这极大地简化了我们的代码库,并在不丢失大量功能的情况下大大减少了代码大小。 5.15 中的 Qt Multimedia 大约有 140.000 行代码,而我们目前在 Qt 6 中减少到大约 74.000 行代码。

## 支持的后端

在 Qt 6 中,我们还重新审视了支持的后端,并将其缩减为我们认为将来可以支持的一组。 例如,在 Qt 5 中,我们在 Windows 上有三个完全不同的后端实现,使用 DirectShow、WMF 和一个单独的基于 WMF 的 WinRT 实现。

在 Qt 6 中,当前支持的集合是:

Linux,使用 GStreamer

使用 AVFoundation 的 macOS 和 iOS

使用 WMF 的 Windows

使用 MediaPlayer 和 Camera Java API 的 Android

Qt 6.3 计划支持 QNX。 我们可能还会在 6.2 中及时在 WebAssembly 上使用低级音频。 此外,我们仍有使用 PulseAudio 或 ALSA 在 Linux 上支持低级音频的代码,但目前尚未测试或支持这些代码。 根据需求,我们可能会在以后的版本中将它们带回来。

## 公共 API

Qt Multimedia 的公共 API 由 5 个大型功能块组成。 其中三个块已经存在于 Qt 5 中,但是这些块中的 API 发生了重大变化。 功能块是:

- Device discovery

- Low level audio

- Playback and decoding

- Capture and recording

- Video output pipeline

    设备发现

    低电平音频

    播放和解码

    捕获和记录

    视频输出管道

在做新的 API 时,我们也力求在 C++ 和 QML 之间有一个统一的 API。 这使我们可以删除大量代码,这些代码只是简单地包装 C++ API 并以稍微不同的方式将其暴露给 QML。 对于大多数公共 C++ 类,现在有一个对应的同名 QML 项。 例如,QMediaPlayer 确实有一个对应的 QML MediaPlayer 项,其 API 与 C++ 类相同。

让我们深入了解不同功能块的更多细节:

### Device discovery 设备发现

让我们从设备发现开始。新的 QMediaDevices 类旨在为您提供有关可用音频和视频设备的信息。它将允许您列出可用的音频输入(通常是麦克风)、音频输出(扬声器和耳机)和摄像头。您可以检索默认设备,并且该类还会通知您有关配置的任何更改,例如,当用户连接外部耳机时。

 

    QMediaDevices devices;

    connect(&devices, &QMediaDevices::audioInputsChanged,

            []() { qDebug() << “available audio inputs have changed”; }

### Low level audio低电平音频

此功能块有助于使用原始 PCM 数据处理低电平音频,并直接从音频设备读取或写入该数据。

这个块在架构上仍然与我们在 Qt 5 中的非常相似,但很多细节都发生了变化。最值得注意的是,读取或写入音频设备的低级类已更改名称。它们现在称为 QAudioSource 和 QAudioSink。命名反映了它们的低级性质,并释放了我们在 Qt 5 中的旧名称(QAudioInput 和 QAudioOutput)以用于播放和捕获 API。

QAudioFormat API 已经过清理和简化,现在支持 4 种最常用的 PCM 数据格式(8 位无符号整数、16 和 32 位有符号整数和浮点数据)。 QAudioFormat 还获得了新的 API 来处理音频通道的定位信息,但目前后端尚未完全支持。

我们还删除了已弃用的 QSound 类。 QSoundEffect 是它以低延迟播放短声音的替代品。 QSoundEffect 目前仍要求您使用 WAV 作为效果格式,但我们计划扩展此格式,并允许在 6.2 之后通过类播放压缩的音频数据。

### Playback  回放

处理媒体文件播放的主要类是 QMediaPlayer。 QMediaPlayer API 已经从我们在 Qt 5 中的内容进行了简化。我们现在已经从模块中删除了所有播放列表功能,Qt 5 媒体播放器中内置了一些功能,但使其 API 和实现变得复杂。我们计划在 6.2 之后将播放列表功能作为一个单独的独立类带回来,然后您可以在需要时连接到 QMediaPlayer。现在,如果需要,您可以在“播放器”示例中找到一些代码来处理播放列表。

另一方面,QMediaPlayer 获得了渲染字幕的能力,您现在可以使用 setActiveAudioTrack()、setActiveVideoTrack() 和 setActiveSubtitleTrack() 方法检查和选择所需的音频、视频或字幕轨道。

Qt 6 中的 QMediaPlayer 要求您使用 setAudioOutput() 和 setVideoOutput() 方法将其主动连接到音频和视频输出。不设置音频输出将意味着媒体播放器不播放音频。这是对 Qt 5 的更改,在 Qt 5 中始终选择默认音频输出。进行了更改以允许音频和视频之间的对称 API 并简化与 QML 的集成

用 C++ 实现的最小媒体播放器如下所示:


 

   QMediaPlayer player;

    QAudioOutput audioOutput; // chooses the default audio routing

    player.setAudioOutput(&audioOutput);

    QVideoWidget *videoOutput = new QVideoWidget;

    player.setVideoOutput(videoOutput);

    player.setSource(“mymediafile.mp4”);

    player.play();

 

基于 C++/Widgets 的播放器示例具有更完整的实现,它还支持字幕和音频语言选择以及显示与媒体文件关联的元数据:

or using QML:


    Window {

        MediaPlayer {

            id: mediaPlayer

            audioOutput: AudioOutput {} // use default audio routing

            videoOutput: videoOutput

            source: “mymediafile.mp4”

        }



        VideoOutput {

            id: videoOutput

            anchors.fill: parent

        }



        Component.onCompleted: mediaPlayer.play()

    }

    还有一个全新的基于 QML 的媒体播放器示例,使用 Qt Quick Controls 可用,您可以使用它:


 

    除了 QMediaPlayer,Qt 6 还具有跨平台支持,可以使用 QAudioDecoder 类将音频文件解码为原始 PCM 数据。 该功能在 Qt 5 的某些平台上存在,但并未在所有地方实现。

### Capturing and recording 捕获和记录

捕获和记录功能在 Qt 6 中经历了最大的 API 变化。在 Qt 5 中,您必须神奇地将相机连接到记录器,而 Qt 6 现在带有更明确的 API 来设置捕获管道。

Qt 6 中的中心类是 QMediaCaptureSession。录制音频/视频或捕获图像时始终需要此类。要设置录音会话,您可以使用 setAudioInput() 将音频输入连接到会话,如果您想从相机录制,请使用 setCamera() 将相机连接到它。

这里要注意的一件事是 QAudioInput 和 QCamera 充当两个输入通道。使用 QAudioInput::setDevice() 或 QCamera::setCameraDevice() 选择要使用的物理设备。选择设备后,QAudioInput 和 QCamera 允许您更改该设备的属性,例如设置音量或相机的分辨率和帧速率。

QMediaCaptureSession 允许将音频和视频输出连接到它以进行预览和监视。要拍摄静止图像,请使用 setImageCapture() 将 QImageCapture 对象连接到它

    QMediaCaptureSession session;

    QCamera camera;

    session.addCamera(&camera);

    QImageCapture imageCapture;

    session.addImageCapture(&imageCapture);

    camera.start();

    imageCapture.captureToFile(“myimage.jpg”);

要录制音频和视频,请将 QMediaRecorder 连接到会话。 QMediaRecorder 允许通过指定 QMediaFormat 来请求特定的文件格式和编解码器进行录制。 在 Qt 6 中,我们没有在此处提供跨平台 API,使用不同格式和编解码器的枚举。 由于编解码器支持取决于平台,您还可以查询 QMediaFormat 以获取支持的文件格式和编解码器集。 后端也将始终尝试将请求的格式解析为支持的格式。 因此,例如,如果您请求带有 H265 视频编解码器的 MPEG4 文件,但不支持 H265,则它可能会回退到 H264 或其他受支持的编解码器。


    session.setRecorder(&recorder);



    QMediaFormat format(QMediaFormat::MPEG4);

    format.setAudioCodec(QMediaFormat::AudioCodec::AAC);

    format.setVideoCodec(QMediaFormat::VideoCodec::H265);

    recorder.setMediaFormat(format);



    recorder.setOutputLocation(“mycapture.mp4”);

    recorder.record();

除了设置格式之外,您还可以在编码器上设置其他属性,例如质量、分辨率和帧率。

### Video pipeline 视频管道

视频管道已使用 Qt 6 完全重写,试图使其更易于用于自定义用例,并允许解码和渲染的完整硬件加速以及在软件中接收原始视频数据。

这个 API 的大部分只能从 C++ 访问,在 QML 端,有一个 VideoOutput QML 元素,但是可以很容易地连接到诸如着色器效果之类的东西,或者可以用作 Qt Quick 3D 中材质的 sourceItem:

对于更底层的访问,C++ 端的中心类是 QVideoSink。 QVideoSink 可用于从媒体播放器或捕获会话接收单个视频帧。然后可以将单个 QVideoFrame 对象映射到内存中,用户必须准备好处理各种 YUV 和 RGB 格式,可以使用 QPainter 渲染或可以转换为 QImage。

## 未来的工作

在 6.2 之后,我们将研究待办事项中的几个项目。这些想法的优先级尚未完成,关于您的需求的反馈将在这里帮助我们。我们的想法包括:

- 支持多视频输出

- 支持多摄像头

- 支持多个音频输入

- 流媒体音频/视频

- 截屏

- 音频混合

然而,目前,我们的大部分工作都集中在错误修复和为 Qt 6.2 做好一切准备上。由于改动较大,在实现过程中仍然存在许多粗糙的边缘,并且某些功能可能存在错误或缺少功能。我们的目标是在 6.2.0 中修复这些问题,但需要您的反馈才能这样做。

最近发布的 Qt 6.2 测试版确实有用于 Qt 多媒体的二进制文件,您可以轻松地尝试和使用它们。我们将不胜感激任何反馈,无论是在博客上还是在 bugreports.qt.io。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值