Qt6中重大改變的QtMultimedia多媒體模組
一、前言
- 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 多媒體的大部分用例。我們的目標是首先關注那些核心用例,並確保它們在我們的所有平臺上一致工作,然後再使用新功能擴充套件模組。
我們希望在 Qt 6.2 中支援的主要用例是:
- 音訊和視訊播放
- 音訊和視訊錄製(來自相機和麥克風)
- 低階(基於 PCM)音訊和音訊解碼
- 與 Qt Quick 和小部件整合
- 儘量使用硬體加速
三、內部架構變化
- Qt 5 中的 Qt 多媒體具有複雜的基於外掛的架構,使用多個外掛來實現不同的前端功能。一個完整的多媒體後端實現將包含不少於 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.3 計劃支援 QNX。我們可能還會在 6.2 中及時在 WebAssembly 上使用低階音訊。此外,我們仍有使用 PulseAudio 或 ALSA 在 Linux 上支援低階音訊的程式碼,但目前尚未測試或支援這些程式碼。根據需求,我們可能會在以後的版本中將它們帶回來。
在 Qt 6 中,當前支援的集合是:
- Linux,使用 GStreamer
- 使用 AVFoundation 的 macOS 和 iOS
- 使用 WMF 的 Windows
- 使用 MediaPlayer 和 Camera Java API 的 Android
五、公共API介面
Qt Multimedia的公共 API由 5 個大型功能塊組成。其中三個塊已經存在於 Qt 5 中,但是這些塊中的 API 發生了重大變化。功能塊是:
- 裝置發現
- 低電平音訊
- 播放和解碼
- 捕獲和記錄
- 視訊輸出管道
在做新的 API 的時候,我們也希望在 C++ 和 QML 之間有一個統一的 API。這使我們可以刪除大量程式碼,這些程式碼只是簡單地包裝了 C++ API 並以稍微不同的方式將其暴露給 QML。對於大多數公共 C++ 類,現在有一個相應的同名 QML 項。所以QMediaPlayer並例如具有相應QML MediaPlayer的具有相同的API作為C ++類的專案。
(一)裝置發現
讓我們從裝置發現開始。新的QMediaDevices 類旨在為您提供有關可用音訊和視訊裝置的資訊。它將允許您列出可用的音訊輸入(通常是麥克風)、音訊輸出(揚聲器和耳機)和攝像頭。您可以檢索預設裝置,類還會通知您有關配置的任何更改,例如,當用戶連線外部耳機時。
QMediaDevices devices;
connect(&devices, &QMediaDevices::audioInputsChanged,
[]() { qDebug() << “available audio inputs have changed”; }
(二)低電平音訊
- 此功能塊有助於使用原始 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 之後通過類播放壓縮的音訊資料。
(三)回放
- 處理媒體檔案播放的主要類是QMediaPlayer。該QMediaPlayer API已經從我們在Qt5簡化了我們必須從現在模組去掉了所有的播放列表功能,這在過去是內建了Qt 5媒體播放器,但其複雜的API和實現。我們計劃在 6.2 之後將播放列表功能作為一個單獨的獨立類帶回來,然後您可以在需要時連線到QMediaPlayer。現在,如果需要,您可以在“播放器”示例中找到一些處理播放列表的程式碼。
- 另一方面,QMediaPlayer獲得了渲染字幕的能力,您現在可以使用setActiveAudioTrack()、setActiveVideoTrack()和setActiveSubtitleTrack()方法檢查和選擇所需的音訊、視訊或字幕軌道。
- Qt 6 中的 QMediaPlayer 要求您使用setAudioOutput()和setVideoOutput()方法將其主動連線到音訊和視訊輸出。不設定音訊輸出將意味著媒體播放器不播放音訊。這是對 Qt 5 的更改,在 Qt 5 中始終選擇預設音訊輸出。進行了更改以允許音訊和視訊之間的對稱 API 並簡化與 QML 的整合
- 除了QMediaPlayer 之外,Qt 6 還具有跨平臺支援,可以使用QAudioDecoder類將音訊檔案解碼為原始 PCM 資料。該功能存在於 Qt 5 的某些平臺上,但並未在所有平臺上實現。
用 C++ 實現的最小媒體播放器如下所示:
//widget示例
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();
//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()
}
(四)捕獲和記錄
- 捕獲和記錄功能在 Qt 6 中經歷了最大的 API 更改。在 Qt 5 中,您必須神奇地將相機連線到記錄器,而 Qt 6 現在帶有更明確的 API 來設定捕獲管道。
- Qt 6 中的中心類是QMediaCaptureSession。錄製音訊/視訊或捕獲影象時始終需要此類。要設定錄音會話,您可以使用setAudioInput()將音訊輸入連線到會話,如果您想從相機錄製,請使用setCamera()將相機連線到它。
- 這裡要注意的一件事是QAudioInput和QCamera充當兩個輸入通道。使用QAudioInput::setDevice()或QCamera::setCameraDevice()選擇要使用的物理裝置。選擇裝置後,QAudioInput和QCamera允許您更改該裝置的屬性,例如設定音量或相機的解析度和幀速率。
- QMediaCaptureSession允許將音訊和視訊輸出連線到它以進行預覽和監視。要拍攝靜止影象,請使用setImageCapture()將QImageCapture物件連線到它。
- 要錄製音訊和視訊,請將QMediaRecorder連線到會話。QMediaRecorder允許通過指定一個請求記錄特定的檔案格式和編解碼器QMediaFormat。在 Qt 6 中,我們沒有在此處提供跨平臺 API,使用不同格式和編解碼器的列舉。
- 由於編解碼器支援取決於平臺,您還可以查詢QMediaFormat以獲取支援的檔案格式和編解碼器集。後端也將始終嘗試將請求的格式解析為支援的格式。
- 因此,例如,如果您請求帶有 H265 視訊編解碼器的 MPEG4 檔案,但不支援 H265,則它可能會回退到 H264 或其他受支援的編解碼器。
- 除了設定格式之外,您還可以在編碼器上設定其他屬性,例如質量、解析度和幀率。
QMediaCaptureSession session;
QCamera camera;
session.addCamera(&camera);
QImageCapture imageCapture;
session.addImageCapture(&imageCapture);
camera.start();
imageCapture.captureToFile(“myimage.jpg”);
QMediaRecorder recorder;
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();
(五)視訊管道
- 視訊管道已使用 Qt 6 完全重寫,試圖使其更易於用於自定義用例,並允許解碼和渲染的完整硬體加速以及在軟體中接收原始視訊資料。
- 這個 API 的大部分只能從 C++ 訪問,在 QML 端,有一個VideoOutput QML 元素,但是可以很容易地連線到著色器效果之類的東西,或者可以用作 Qt Quick 3D 中材質的 sourceItem。
- 如果您使用 Qt Widgets,則QVideoWidget類可用作那裡視訊的輸出表面。
- 對於更底層的訪問,C++ 端的中心類是QVideoSink。QVideoSink可用於從媒體播放器或捕獲會話接收單個視訊幀。 然後可以將單個QVideoFrame物件對映到記憶體中,使用者必須準備好處理各種 YUV 和 RGB 格式,可以使用QPainter渲染或可以轉換為QImage。
六、未來的工作
在 6.2 之後,我們將研究待辦事項中的幾個專案。這些想法的優先順序尚未完成,關於您的需求的反饋將在這裡幫助我們。我們的想法包括:
- 支援多視訊輸出
- 支援多攝像頭
- 支援多個音訊輸入
- 流媒體音訊/視訊
- 截圖
- 音訊混合
然而,目前,我們的大部分工作都集中在錯誤修復和為 Qt 6.2 做好一切準備上。由於較大的變化,在實現中仍然存在許多粗糙的邊緣,並且某些功能可能存在錯誤或缺少功能。我們的目標是在 6.2.0 中修復這些問題,但需要您的反饋才能這樣做。
最近釋出的 Qt 6.2 測試版確實有 Qt 多媒體的二進位制檔案,您可以輕鬆地嘗試和使用它們。我們非常感謝任何反饋,無論是在部落格上還是在 bugreports.qt.io。
「其他文章」
- Qt自定義控制元件整合到全平臺QtCreator效果圖
- Qt 5.15.6 釋出
- Qt編寫安防視訊監控系統66-子模組10網頁瀏覽
- Qt編寫安防視訊監控系統65-子模組9資料除錯
- Qt編寫安防視訊監控系統64-子模組8飛行軌跡
- Qt編寫視覺化大屏電子看板系統22-平滑曲線圖
- Qt編寫安防視訊監控系統63-子模組7懸浮地圖
- Qt6中重大改變的QtMultimedia多媒體模組
- Qt開發經驗小技巧171-175
- Qt編寫視覺化大屏電子看板系統21-資料轉曲線
- Qt編寫視覺化大屏電子看板系統20-橫向分組圖
- Qt Creator 5.0 釋出
- Qt編寫視覺化大屏電子看板系統19-橫向柱狀圖
- Qt開發經驗小技巧166-170
- Qt編寫安防視訊監控系統62-子模組6預置位
- Qt編寫視覺化大屏電子看板系統18-柱狀分組圖
- Qt編寫安防視訊監控系統61-子模組5裝置控制
- Qt編寫視覺化大屏電子看板系統17-柱狀堆積圖
- Qt開發經驗小技巧161-165
- Qt編寫安防視訊監控系統60-子模組4雲臺控制