目录
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:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtWidgets> #include <QSlider> #include <QMouseEvent> #include <QFileDialog> #include <QMediaPlayer> #include <QVideoWidget> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); void MediaInit(); void dragEnterEvent(QDragEnterEvent *event); void dragLeaveEvent(QDragLeaveEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event); ~MainWindow(); private slots: void on_actionimport_file_triggered(); void on_Begin_clicked(); void onItemDoubleClicked(QListWidgetItem * item); void showListWidgetMenuSlot(QPoint); void deleteAllData(); void GetDuration(qint64); void upDateSlider(qint64); void slot_PlayError(QMediaPlayer::Error); void on_back_clicked(); void on_advance_clicked(); void ChangeVoice(int); void MoveVideo(int); void on_fullScreen_clicked(); void on_volumeData_clicked(); void on_action_h_Help_triggered(); void keyPressEvent(QKeyEvent *event); void on_Speed_currentIndexChanged(const QString &arg1); private: Ui::MainWindow *ui; QMediaPlayer *Player; QVideoWidget *videoWidget; QListWidget *DataList; QMenu *Menu; QAction *deleteAll; QString totalFormatTime; QString currentFormatTime; int back_volume = 0; int flag_back_volume = 0; }; #endif // 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这种去解析感觉会更好,在解析速度优化上也可以更近一步。
整合资源包地址:
微信关注嵌入式工程之家回复乌龟牌播放器即可获得整合包哦~