Qt6替代廢棄QMediaPlaylist的解決方案
—— 之前使用Qt5,如今使用Qt6發(fā)現(xiàn)在Qt6里QMediaPlaylist已廢棄,所以網(wǎng)上搜了一下,找到了該博主的博客,感想博主的代碼,我在其基礎(chǔ)上增加和修改,以適配Qt5的寫法。
一、背景:Qt6 多媒體模塊的重大變更
Qt5 中常用的 QMediaPlaylist 類在 Qt6 中被正式移除,這給大量依賴該類實現(xiàn)音頻 / 視頻播放列表管理的項目帶來了兼容性問題。尤其對于棋牌、影音類應(yīng)用(如本文的斗地主項目),播放列表是核心功能模塊,急需一套輕量、兼容、易集成的替代方案。
本文基于實際項目經(jīng)驗,從零實現(xiàn)了一套 Qt6 專屬的 MediaPlaylist 類,完全復(fù)刻 QMediaPlaylist 核心能力,同時適配 Qt6 新的多媒體架構(gòu)(QMediaPlayer + QAudioOutput),解決音頻播放列表、循環(huán)切歌、播放模式控制等核心需求。
二、核心痛點分析
遷移 Qt5 音頻播放邏輯到 Qt6 時,主要面臨以下問題:
QMediaPlaylist直接移除,無官方替代類;- Qt6 多媒體架構(gòu)調(diào)整,
QMediaPlayer需手動綁定QAudioOutput,且播放狀態(tài)監(jiān)聽邏輯變更; - 原有播放模式(單曲循環(huán)、列表循環(huán)、單次播放)需重新實現(xiàn);
- 音頻索引切換、自動切歌等核心邏輯需手動封裝。
三、解決方案:自定義 MediaPlaylist 類實現(xiàn)
3.1 類設(shè)計思路
遵循 Qt 信號槽設(shè)計規(guī)范,封裝播放列表核心能力,核心設(shè)計目標(biāo):
- 兼容 Qt6
QMediaPlayer新架構(gòu); - 支持三種經(jīng)典播放模式;
- 自動監(jiān)聽播放完成狀態(tài),實現(xiàn)無感切歌;
- 提供簡潔的外部接口,最小化項目改造成本。
3.2 完整代碼實現(xiàn)
- 頭文件(ol_MediaPlaylist.h)
/****************************************************************************************/
/*
* 程序名:ol_MediaPlaylist.h
* 功能描述:Qt6 媒體播放列表類,替代廢棄的 QMediaPlaylist,支持以下特性:
* - 自動綁定 QMediaPlayer,監(jiān)聽播放完成狀態(tài)
* - 三種播放模式:單次播放、單曲循環(huán)、列表循環(huán)
* - 播放結(jié)束自動切換曲目/循環(huán)播放
* - 索引/媒體資源自動管理,適配 Qt6
* - 支持信號通知索引變化,與音頻播放器聯(lián)動
* 作者:ol
* 適用標(biāo)準(zhǔn):Qt 6.0及以上
*/
/****************************************************************************************/
#ifndef OL_MEDIAPLAYLIST_H
#define OL_MEDIAPLAYLIST_H
#include <QObject>
#include <QVector>
#include <QUrl>
#include <QMediaPlayer>
namespace ol
{
/**
* @brief 媒體播放列表類,適配 Qt6 QMediaPlayer
* 實現(xiàn)播放列表管理、自動循環(huán)切歌、播放模式控制,無需手動處理音源切換
*/
class MediaPlaylist : public QObject
{
Q_OBJECT
public:
/**
* @brief 播放模式枚舉
*/
enum class PlaybackMode : char
{
CurrentItemOnce, /**< 當(dāng)前曲目播放一次后自動停止 */
CurrentItemLoop, /**< 當(dāng)前曲目無限循環(huán)播放 */
SequentialLoop /**< 列表順序循環(huán),尾首自動銜接 */
};
private:
QVector<QUrl> m_mediaList; ///< 媒體資源 URL 列表
int m_currentIndex; ///< 當(dāng)前播放索引,-1 表示未選中
PlaybackMode m_playbackMode; ///< 當(dāng)前播放模式
QMediaPlayer* m_player; ///< 綁定的 Qt 媒體播放器
public:
/**
* @brief 構(gòu)造函數(shù)
* @param parent 父對象
*/
explicit MediaPlaylist(QObject* parent = nullptr);
/**
* @brief 向播放列表添加媒體資源
* @param media 媒體資源 URL(支持 qrc 資源/本地文件)
*/
void addMedia(const QUrl& media);
/**
* @brief 清空播放列表,重置索引
*/
void clear();
/**
* @brief 設(shè)置當(dāng)前播放索引(自動切換播放器音源)
* @param index 目標(biāo)播放索引
*/
void setCurrentIndex(int index);
/**
* @brief 獲取當(dāng)前播放索引
* @return 當(dāng)前索引,-1 表示無效
*/
inline int getCurrentIndex() const { return m_currentIndex; }
/**
* @brief 獲取當(dāng)前播放的媒體 URL
* @return 有效 URL / 空 QUrl
*/
QUrl getCurrentMedia() const;
/**
* @brief 獲取列表總媒體數(shù)量
* @return 媒體資源總數(shù)
*/
inline qsizetype getMediaCount() const { return m_mediaList.size(); }
/**
* @brief 設(shè)置播放模式
* @param mode 目標(biāo)播放模式
*/
inline void setPlaybackMode(PlaybackMode mode) { m_playbackMode = mode; }
/**
* @brief 獲取當(dāng)前播放模式
* @return 播放模式枚舉值
*/
inline PlaybackMode getPlaybackMode() const { return m_playbackMode; }
/**
* @brief 綁定 Qt 媒體播放器
* @param player 待綁定的 QMediaPlayer 對象
*/
void setPlayer(QMediaPlayer* player);
/**
* @brief 切換到下一首媒體
* @return 下一首媒體的 URL
*/
QUrl nextMedia();
/**
* @brief 切換到上一首媒體
* @return 上一首媒體的 URL
*/
QUrl previousMedia();
signals:
/**
* @brief 播放索引改變信號,用于用戶未來功能擴展
* @param newIndex 新的播放索引
*/
void currentIndexChanged(int newIndex);
private slots:
/**
* @brief 監(jiān)聽播放器狀態(tài),播放完成自動處理切歌/循環(huán)
* @param status 媒體播放狀態(tài)
*/
void onMediaStatusChanged(QMediaPlayer::MediaStatus status);
};
} // namespace ol
#endif // !OL_MEDIAPLAYLIST_H- 源文件(ol_MediaPlaylist.cpp)
/****************************************************************************************/
/*
* 程序名:ol_MediaPlaylist.cpp
* 功能描述:媒體播放列表類實現(xiàn)文件
* 作者:ol
*/
/****************************************************************************************/
#include "ol_MediaPlaylist.h"
#include <QMediaPlayer>
namespace ol
{
MediaPlaylist::MediaPlaylist(QObject* parent)
: QObject(parent), m_currentIndex(-1), m_playbackMode(PlaybackMode::CurrentItemOnce), m_player(nullptr)
{
}
void MediaPlaylist::addMedia(const QUrl& media)
{
m_mediaList.append(media);
if (m_currentIndex == -1) setCurrentIndex(0);
}
void MediaPlaylist::clear()
{
m_mediaList.clear();
m_currentIndex = -1;
emit currentIndexChanged(m_currentIndex);
}
void MediaPlaylist::setCurrentIndex(int index)
{
if (index >= 0 && index < m_mediaList.size() && index != m_currentIndex)
{
m_currentIndex = index;
emit currentIndexChanged(m_currentIndex);
// 自動切換播放器音源
if (m_player) m_player->setSource(getCurrentMedia());
}
}
QUrl MediaPlaylist::getCurrentMedia() const
{
if (m_currentIndex >= 0 && m_currentIndex < m_mediaList.size()) return m_mediaList.at(m_currentIndex);
return QUrl();
}
void MediaPlaylist::setPlayer(QMediaPlayer* player)
{
// 斷開舊播放器連接
if (m_player) disconnect(m_player, nullptr, this, nullptr);
m_player = player;
// 綁定狀態(tài)監(jiān)聽信號
if (m_player)
{
connect(m_player, &QMediaPlayer::mediaStatusChanged, this, &MediaPlaylist::onMediaStatusChanged);
// 默認(rèn)加載當(dāng)前音源
const QUrl url = getCurrentMedia();
if (url.isValid()) m_player->setSource(url);
}
}
QUrl MediaPlaylist::nextMedia()
{
if (m_mediaList.isEmpty()) return QUrl();
setCurrentIndex((m_currentIndex + 1) % m_mediaList.size());
return getCurrentMedia();
}
QUrl MediaPlaylist::previousMedia()
{
if (m_mediaList.isEmpty()) return QUrl();
setCurrentIndex((m_currentIndex - 1 + m_mediaList.size()) % m_mediaList.size());
return getCurrentMedia();
}
void MediaPlaylist::onMediaStatusChanged(QMediaPlayer::MediaStatus status)
{
// 僅處理播放完成狀態(tài)
if (status != QMediaPlayer::EndOfMedia || !m_player) return;
if (m_mediaList.isEmpty()) return;
switch (m_playbackMode)
{
case PlaybackMode::CurrentItemOnce:
m_player->stop();
break;
case PlaybackMode::CurrentItemLoop:
m_player->play();
break;
case PlaybackMode::SequentialLoop:
nextMedia();
m_player->play();
break;
}
}
} // namespace ol
四、核心功能解析
4.1 播放模式控制
復(fù)刻 Qt5 QMediaPlaylist 三種經(jīng)典模式,通過 PlaybackMode 枚舉實現(xiàn):
CurrentItemOnce:播放完成后自動停止;CurrentItemLoop:單曲無限循環(huán)(播放完成后重新播放);SequentialLoop:列表循環(huán)(播放完成自動切下一首,最后一首切回第一首)。
4.2 自動綁定播放器
通過 setPlayer 方法綁定 QMediaPlayer,實現(xiàn)兩個核心能力:
- 自動監(jiān)聽
mediaStatusChanged信號,無需外部手動處理播放完成事件; - 切換索引時自動調(diào)用
setSource,避免外部重復(fù)編寫音源切換邏輯。
4.3 索引安全管理
所有索引操作(setCurrentIndex/nextMedia/previousMedia)均做合法性校驗:
- 索引越界時不執(zhí)行任何操作;
- 空列表時返回空 URL,避免程序崩潰;
- 首次添加媒體自動選中第一個索引,降低使用成本。
五、項目集成示例
以實際項目中的 BGMControl 類為例,展示如何快速集成自定義 MediaPlaylist:
// 音頻控制類中初始化播放列表
BGMControl::BGMControl(QObject* parent) : QObject(parent)
{
// 初始化5組音頻單元(男女音效/BGM/輔助音效/結(jié)束音效)
for (int i = 0; i < 5; ++i)
{
QAudioOutput* output = new QAudioOutput(this);
QMediaPlayer* player = new QMediaPlayer(this);
ol::MediaPlaylist* playlist = new ol::MediaPlaylist(this);
// 綁定播放器與播放列表
player->setAudioOutput(output);
playlist->setPlayer(player);
output->setVolume(1.0f);
// 配置播放模式(BGM列表循環(huán),其他單次播放)
if (i == 2) {
playlist->setPlaybackMode(ol::MediaPlaylist::PlaybackMode::SequentialLoop);
} else {
playlist->setPlaybackMode(ol::MediaPlaylist::PlaybackMode::CurrentItemOnce);
}
m_outputs.push_back(output);
m_players.push_back(player);
m_playlists.push_back(playlist);
}
// 加載音頻資源
initPlayList();
}
// 啟動BGM示例
void BGMControl::startBGM(float volume)
{
m_outputs[2]->setVolume(volume);
m_playlists[2]->setCurrentIndex(0); // 選中第一個BGM
m_players[2]->play(); // 開始播放
}
六、總結(jié)
本文實現(xiàn)的 MediaPlaylist 類完全適配 Qt6 多媒體架構(gòu),核心優(yōu)勢:
- 低改造成本:接口設(shè)計貼近 Qt5
QMediaPlaylist,項目遷移時無需大幅修改業(yè)務(wù)邏輯; - 高穩(wěn)定性:完善的索引校驗、內(nèi)存管理,避免空指針 / 越界崩潰;
- 強擴展性:保留
currentIndexChanged信號,支持后續(xù) UI 同步、日志記錄等擴展; - 零依賴:僅依賴 Qt6 Core 和 Multimedia 模塊,無需第三方庫。
以上就是Qt6替代廢棄QMediaPlaylist的解決方案的詳細(xì)內(nèi)容,更多關(guān)于Qt6替代廢棄QMediaPlaylist的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
淺析C語言中strtol()函數(shù)與strtoul()函數(shù)的用法
這篇文章主要介紹了淺析C語言中strtol()函數(shù)與strtoul()函數(shù)的用法,注意其將字符串轉(zhuǎn)換成long型的區(qū)別,需要的朋友可以參考下2015-08-08
C++基于灰度圖上色GrayToColorFromOther的實現(xiàn)
本文主要介紹了C++基于灰度圖上色GrayToColorFromOther的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07
C語言科學(xué)計算入門之矩陣乘法的相關(guān)計算
這篇文章主要介紹了C語言科學(xué)計算入門之矩陣乘法的相關(guān)計算,文章中還介紹了矩陣相關(guān)的斯特拉森算法的實現(xiàn),需要的朋友可以參考下2015-12-12
C++多態(tài)的實現(xiàn)及原理詳細(xì)解析
C++的多態(tài)性用一句話概括就是:在基類的函數(shù)前加上virtual關(guān)鍵字,在派生類中重寫該函數(shù),運行時將會根據(jù)對象的實際類型來調(diào)用相應(yīng)的函數(shù)。如果對象類型是派生類,就調(diào)用派生類的函數(shù);如果對象類型是基類,就調(diào)用基類的函數(shù)2013-09-09
C++之CNoTrackObject類和new delete操作符的重載實例
這篇文章主要介紹了C++之CNoTrackObject類和new delete操作符的重載實例,是C++程序設(shè)計中比較重要的概念,需要的朋友可以參考下2014-10-10
linux下C語言中的mkdir函數(shù)與rmdir函數(shù)
以下是對C語言中的mkdir函數(shù)與rmdir函數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下2013-08-08

