@author: bbxwg
@Qt_version:5.11.1
@Time: 2024-07-05
目录
QT版本:5.11.1
视频播放器成效:
视频播放器功能:
QMediaPlayer介绍:
功能特性
MainWindow.h:
MainWindow.cpp:
ui设计:
缺点:
整合资源包地址:
QT版本:5.11.1
视频播放器成效:
编辑
视频播放器功能:
1. 支持外地导入文件,外地拖拽文件到列表中
2. 支持一键静音,一键返回上次音量
3. 支持空格暂停播放,ESC关闭窗口
4. 支持拖放进度条控制视频速度
5. 支持倍速播放
6. 支持一键清空列表
7. 支持快进10S,快退10S
8. 支持一键放大缩小
9. 支持点击列表元素播放视频
因为QMediaPlayer需要解码器去解析视频,而QT并不自带,所以我们需要去下载一下。
百度网盘:
链接:https://pan.baidu.com/s/1EoGhiNDOGkwaiJzjuY1zNw?pwd=qwer
提取码:qwer
GitHub:
Releases · Nevcairiel/LAVFilters (github.com)
编辑
安装在自己的QT目录下即可
编辑
QMediaPlayer介绍:
QMediaPlayer是Qt多媒体模块中的一个核心类,它提供了播放音频和视频内容的功能。这个类的设计旨在简化跨平台的媒体播放,使得开发者能够在多种操作系统(如Linux、Windows、macOS及移动平台)上轻松集成多媒体播放能力到他们的应用中,而无需关心底层实现细节。以下是关于QMediaPlayer的一些关键点:
功能特性
-
媒体播放:支持播放各种音频和视频文件格式,支持的格式依赖于底层操作系统提供的解码器。例如,在Linux下通常使用GStreamer,Windows下使用DirectShow,Android和iOS则分别使用它们各自的多媒体框架。
-
流媒体播放:除了本地文件,QMediaPlayer还能够播放网络流媒体资源,如HTTP直播流(HLS)、RTSP流等。
-
状态管理:QMediaPlayer提供了多种状态枚举,如Playing
、Paused
、Stopped
等,以及媒体状态(如LoadingMedia
、BufferingMedia
、StalledMedia
),允许开发者监控播放器的当前状态。
-
信号与槽:QMediaPlayer发出多种信号,如stateChanged()
、mediaStatusChanged()
,开发者可以通过连接这些信号到自定义的槽函数,实现对播放事件的响应和控制。
-
视频输出:为了显示视频内容,QMediaPlayer可以与QVideoWidget、QOpenGLWidget或自定义的QAbstractVideoSurface结合使用。
-
音频输出:音频可以通过默认音频输出播放,也可以通过QAudioOutput类进行更细致的控制,比如调整音量、选择音频输出设备等。
-
播放列表管理:虽然QMediaPlayer本身不直接管理播放列表,但它可以与QMimeData和QMediaPlaylist等类协作,实现播放列表功能。
-
资源与缓冲:支持媒体资源的加载、缓冲管理以及错误处理,可以通过属性和信号监测缓冲进度和错误状态。
我们还需要一个播放视频的组件,类似于被投屏的幕布,正是QVideoWidget,他可以接收QMediaPlayer解析的视频流。这里对于他仅仅只作用了接收的功能,在此就不细讲,大家有时间可以去了解一下。
MainWindow.h:
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//初始化
this->MediaInit();
}
MainWindow::~MainWindow()
{
delete ui;
}
// 初始化函数
void MainWindow::MediaInit() {
this->setWindowTitle("乌龟牌播放器");
this->setWindowIcon(QPixmap(":/Icon/Icon/tortoiseTitleIcon.png"));
// 初始化变量
Player = new QMediaPlayer(this);
videoWidget = new QVideoWidget(this);
DataList = new QListWidget(this);
Menu = new QMenu(this);
deleteAll = new QAction("删除全部", this);
// 功能性设置
DataList->setContextMenuPolicy(Qt::CustomContextMenu);
Menu->addAction(deleteAll);
ui->videoSlider->setSingleStep(0);
ui->Begin->setDisabled(true);
ui->back->setDisabled(true);
ui->advance->setDisabled(true);
this->setAcceptDrops(true);
// ui布局
this->DataList->setStyleSheet("QListView { font: 25 9pt Microsoft YaHei;border: 15px solid white;border-radius: 10px;}"
"QListView::item {height: 60px;}"
"QListView::item:hover {background-color: transparent;padding: 10px;border-left: 3px solid rgb(130, 130, 130);}"
"QListView::item:selected { background-color: transparent;color: black;padding: 10px;border-left: 3px solid black;}");
ui->horizontalLayout->addWidget(videoWidget,10);
ui->horizontalLayout->addWidget(DataList,0);
ui->fullScreen->setIcon(QPixmap(":/Icon/Icon/magnify.png"));
ui->fullScreen->setIconSize(QSize(20,20));
ui->Begin->setIcon(QPixmap(":/Icon/Icon/begin.png"));
ui->Begin->setIconSize(QSize(20,20));
ui->back->setIcon(QPixmap(":/Icon/Icon/back.png"));
ui->back->setIconSize(QSize(20,20));
ui->advance->setIcon(QPixmap(":/Icon/Icon/advance.png"));
ui->advance->setIconSize(QSize(20,20));
ui->volumeData->setIcon(QPixmap(":/Icon/Icon/volumeHigh.png"));
ui->volumeData->setIconSize(QSize(20,20));
// 信号
connect(DataList, &QListWidget::itemDoubleClicked, this, &MainWindow::onItemDoubleClicked);
connect(DataList, SIGNAL(customContextMenuRequested(QPoint)),this, SLOT(showListWidgetMenuSlot(QPoint)));
connect(deleteAll,SIGNAL(triggered()),this,SLOT(deleteAllData()));
connect(Player, SIGNAL(durationChanged(qint64)), this, SLOT(GetDuration(qint64)));
connect(Player, SIGNAL(positionChanged(qint64)), this, SLOT(upDateSlider(qint64)));
connect(Player, SIGNAL(error(QMediaPlayer::Error)),this,SLOT(slot_PlayError(QMediaPlayer::Error)));
connect(ui->volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(ChangeVoice(int)));
connect(ui->videoSlider, SIGNAL(sliderMoved(int)), this, SLOT(MoveVideo(int)));
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
event->accept();
}
void MainWindow::dragLeaveEvent(QDragLeaveEvent *event)
{
event->accept();
}
void MainWindow::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
}
void MainWindow::dropEvent(QDropEvent *event)
{
QString name;
QList<QUrl> urls;
QList<QUrl>::Iterator i;
urls = event->mimeData()->urls();
for(i = urls.begin(); i != urls.end(); ++i) {
name = i->path();
this->DataList->addItem(name);
}
Player->setMedia(QUrl::fromLocalFile(name));
Player->setVideoOutput(videoWidget);
Player->play();
}
// 错误提示
void MainWindow::slot_PlayError(QMediaPlayer::Error error) {
QString text;
if(QMediaPlayer::NoError==error)
{
text="正常解码!";
}
else if(QMediaPlayer::ResourceError==error)
{
text="媒体资源无法解析。";
}
else if(QMediaPlayer::FormatError==error)
{
text="不支持该媒体资源的格式,没有解码器!";
}
else if(QMediaPlayer::NetworkError==error)
{
text="发生网络错误。";
}
else if(QMediaPlayer::AccessDeniedError==error)
{
text="没有适当的权限来播放媒体资源。";
}
else if(QMediaPlayer::ServiceMissingError==error)
{
text="没有找到有效的播放服务,播放无法继续。";
}
QMessageBox::critical(this,"播放器提示",text,QMessageBox::Ok,QMessageBox::Ok);
}
// 更新进度条
void MainWindow::upDateSlider(qint64 position) {
ui->Begin->setDisabled(false);
ui->back->setDisabled(false);
ui->advance->setDisabled(false);
if(ui->videoSlider->isSliderDown()) {
return;
}
double num_p = position;
double num_d = Player->duration();
ui->videoSlider->setSliderPosition(100 * num_p / num_d);
QTime currentTime(0, 0, 0, 0);
currentTime = currentTime.addMSecs(position);
currentFormatTime = currentTime.toString("mm:ss");
ui->BeginTime->setText(currentFormatTime);
}
// 获取视频时间信息
void MainWindow::GetDuration(qint64 duration) {
QTime totalTime = QTime(0, 0, 0, 0);
totalTime = totalTime.addMSecs(duration);
totalFormatTime = totalTime.toString("mm:ss");
ui->EndTime->setText(totalFormatTime);
}
void MainWindow::showListWidgetMenuSlot(QPoint) {
Menu->exec(QCursor::pos());
}
// 清空列表
void MainWindow::deleteAllData() {
DataList->clear();
Player->stop();
ui->Begin->setIcon(QPixmap(":/Icon/Icon/begin.png"));
ui->Begin->setIconSize(QSize(20,20));
}
// 导入
void MainWindow::on_actionimport_file_triggered()
{
QString strCurrentPath = QDir::homePath();
QString stdDlgTitle = "请选择视频文件";
QString strFilter = "MP4 File(*.mp4);;All File(*.*)";
QString strAllFiles = QFileDialog::getOpenFileName(this, stdDlgTitle,
strCurrentPath,strFilter);
if(strAllFiles.isEmpty()) {
QMessageBox::information(this,"错误","打开视频文件失败,请重新检查",QMessageBox::Yes|QMessageBox::No);
return;
}
QFileInfo fileInfos(strAllFiles);
qDebug() << "File info: " << fileInfos.fileName() << ", path: " << fileInfos.filePath();
DataList->addItem(fileInfos.filePath());
Player->setMedia(QUrl::fromLocalFile(strAllFiles));
Player->setVideoOutput(videoWidget);
Player->play();
}
// 双击
void MainWindow::onItemDoubleClicked(QListWidgetItem * item) {
QString itemStr = item->text();
Player->setMedia(QUrl::fromLocalFile(itemStr));
Player->setVideoOutput(videoWidget);
Player->play();
}
// 开始/暂停
void MainWindow::on_Begin_clicked()
{
if(Player->state() == QMediaPlayer::PlayingState) {
ui->Begin->setIcon(QPixmap(":/Icon/Icon/begin.png"));
Player->pause();
} else {
ui->Begin->setIcon(QPixmap(":/Icon/Icon/pause.png"));
Player->play();
}
}
// 回退
void MainWindow::on_back_clicked()
{
qint64 currentpos = Player->position();
Player->setPosition(currentpos - 10000);//在原来的基础上前进10s
}
// 前进
void MainWindow::on_advance_clicked()
{
qint64 currentpos = Player->position();
Player->setPosition(currentpos + 10000);//在原来的基础上前进10s
}
// 全屏
void MainWindow::on_fullScreen_clicked()
{
if(this->isFullScreen()) {
this->showNormal();
ui->fullScreen->setIcon(QPixmap(":/Icon/Icon/magnify.png"));
} else {
this->showFullScreen();
ui->fullScreen->setIcon(QPixmap(":/Icon/Icon/lessen.png"));
}
}
// 倍速
void MainWindow::on_Speed_currentIndexChanged(const QString &arg1)
{
Player->setPlaybackRate(arg1.toDouble());
}
// 一键静音
void MainWindow::on_volumeData_clicked()
{
if(++flag_back_volume % 2 != 0) {
back_volume = ui->volumeValue->text().toInt();
}
if(ui->volumeValue->text().toInt() != 0) {
ui->volumeSlider->setValue(0);
Player->setVolume(0);
ui->volumeValue->setText(QString::number(0));
ui->volumeData->setIcon(QPixmap(":/Icon/Icon/volumeCross.png"));
} else {
ui->volumeSlider->setValue(back_volume);
Player->setVolume(back_volume);
ui->volumeValue->setText(QString::number(back_volume));
ui->volumeData->setIcon(QPixmap(":/Icon/Icon/volumeHigh.png"));
}
}
// 更新音量
void MainWindow::ChangeVoice(int volumeData) {
Player->setVolume(volumeData);
ui->volumeValue->setText(QString::number(volumeData));
if(volumeData == 0) {
ui->volumeData->setIcon(QPixmap(":/Icon/Icon/volumeCross.png"));
} else {
ui->volumeData->setIcon(QPixmap(":/Icon/Icon/volumeHigh.png"));
}
}
//更新视频进度
void MainWindow::MoveVideo(int videoData) {
double num_d = Player->duration();
Player->setPosition(videoData * 1000 * (num_d / 100000));
}
// 捕获键盘事件
void MainWindow::keyPressEvent(QKeyEvent *event) {
qDebug() << event->key();
switch (event->key()) {
case Qt::Key_Escape:
if(!this->isFullScreen()) {
QMessageBox:: StandardButton result= QMessageBox::information(this, "information", "是否要关闭窗口?",QMessageBox::Yes|QMessageBox::No);
if(result == QMessageBox::Yes) {
this->close();
}
} else {
on_fullScreen_clicked();
}
break;
case Qt::Key_Space:
on_Begin_clicked();
break;
default:
break;
}
}
void MainWindow::on_action_h_Help_triggered()
{
QDesktopServices::openUrl(QUrl(QString("https://blog.csdn.net/LKHzzzzz?spm=1000.2115.3001.5343")));
}
ui设计:
编辑
缺点:
我在最后的时候想实现一个鼠标预览并显示当前画面帧的功能,但是毕竟是QMediaPlayer解析的视频帧,而且QSlider并没有鼠标停留的这个信号,所以这两个类都需要我们去重写,虽然QMediaPlayer非常方便,但是在功能发展上确是有着不小的限制,如果我们使用一些协议类似于ffmpeg这种去解析感觉会更好,在解析速度优化上也可以更近一步。
整合资源包地址:
微信关注嵌入式工程之家回复乌龟牌播放器即可获得整合包哦~
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
评论(0)