《二十三》Qt 简单小项目---视频播放器

news/2024/5/20 15:36:29

QT 使用QMediaPlayer实现的简易视频播放器

效果如下:

功能点
  1. 播放指定视频
  2. 点击屏幕暂停/播放
  3. 开始/暂停/重置视频
  4. 拖拽到指定位置播放

类介绍

  •     需要在配置文件中加入Multimedia, MultimediaWidgets这俩个库。
  •     Multimedia:提供了一套用于处理音频、视频、摄像头和广播数据的API。
  •     MultimediaWidgets:提供了一些与多媒体相关的图形界面组件。
  •     QVideoProbe是Qt多媒体模块中的一个类,它用于监控视频流的输出。这个类允许你接收视频帧的数据,而不需要直接与视频输出设备交互。
  •     QMediaPlayer 使用生产者-消费者模型来处理媒体内容。它从媒体源(如文件或网络流)获取数据,然后通过播放控制接口(如播放、暂停、停止)和播放状态接口(如当前播放位置、总时长)来控制媒体内容的播放。
  •     使用 QMediaPlayer时,通常需要将其与一个或多个媒体输出组件结合使用,例如QVideoWidget用于视频播放,QAudioOutput用于音频播放。

注意:在Qt6中使用QMediaPlayer时,使用的是setSource函数设置视频资源,而Qt5中并没有这个函数,使用的是setMedia函数。而且有个非常坑的地方,Qt6设置完QVideoWidget直接使用没有问题,而Qt5就会存在问题。 

 信息栏会报错:

DirectShowPlayerService::doRender: Unresolved error code 0x80040266 

在window上需安装LAV解码器的,并放在Qt的安装目录下
在Linux上个人验证并不需要安装

解决办法:QT无法播放视频:报错:DirectShowPlayerService::doRender: Unresolved error code 0x80040266-CSDN博客

代码介绍

我们需要在pro文件中先添加:

 随后我们添加一个C++类,基类选择QVideoWidget,来定义一些鼠标和键盘事件:

qmyselfvideo.h
#include<QVideoWidget>
#include<QObject>
#include<QWidget>
#include<QMediaPlayer>#include<QKeyEvent>
#include<QMouseEvent>class QMySelfVideo : public QVideoWidget
{
public:QMySelfVideo(QWidget *parent=nullptr);void SetMediaPlayer(QMediaPlayer *player);private:QMediaPlayer  *theplayer;protected:void keyPressEvent(QKeyEvent *event);//键盘按键事件,当按键按下esc退出全屏void mousePressEvent(QMouseEvent *event);//鼠标按键时间,点击暂停和播放
};

qmyselfvideo.cpp

#include "qmyselfvideo.h"QMySelfVideo::QMySelfVideo(QWidget *parent):QVideoWidget(parent)
{}void QMySelfVideo::SetMediaPlayer(QMediaPlayer *player)
{//设置播放器操作theplayer=player;
}void QMySelfVideo::keyPressEvent(QKeyEvent *event)//当播放器为全屏的时候,我们按下esc就可以退出全屏
{if((event->key()==Qt::Key_Escape)&&(isFullScreen())){setFullScreen(false);event->accept();QVideoWidget::keyPressEvent(event);}
}void QMySelfVideo::mousePressEvent(QMouseEvent *event)//按下左键设置播放和暂停
{if(event->button()==Qt::LeftButton){if(theplayer->state()==QMediaPlayer::PlayingState){theplayer->pause();}else{theplayer->play();}}QVideoWidget::mousePressEvent(event);
}

 注意:我们要对graphicsView进行提升,提升的类名就是我们刚刚创建的C++类名,因为它的基类就是QVideoWidget。

 代码初始化定义:

#include <QMainWindow>
#include"qmyselfvideo.h"
#include<QMediaPlayer>
#include<QMediaPlaylist>
#include<QVideoWidget>
#include<QFileDialog>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:Ui::MainWindow *ui;QMediaPlayer *player;//播放器QString drtTime;//视频文件长度QString posTime;//播放视频的当前位置private slots:void OnStateButtonChanged(QMediaPlayer::State state);//控制按钮状态void OndrtTimeChanged(qint64 drt);//视频文件时间长度,更新变化void OnposTimeChanged(qint64 pos);//播放视频当前位置时间更新变化
}

 定义我们所需要的量,以及一些我们需要的槽函数来处理一些变化。

代码功能分析:

#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);player=new QMediaPlayer(this);player->setNotifyInterval(1000);player->setVideoOutput(ui->graphicsView);//视频显示组件ui->graphicsView->SetMediaPlayer(player);//设置显示组件的关联播放器
}

初始化,没什么好说的。

根据state的状态,来更新播放,暂停,停止按钮的状态:

void MainWindow::OnStateButtonChanged(QMediaPlayer::State state)
{ui->pushButton_play->setEnabled(!(state==QMediaPlayer::PlayingState));ui->pushButton_pause->setEnabled(state==QMediaPlayer::PlayingState);ui->pushButton_stop->setEnabled(state==QMediaPlayer::PlayingState);
}

根据视频的长度来显示时长,格式:已经播放的时长/总时长。时间是:分:秒。将设置好的时长显示在我们添加的label中显示

void MainWindow::OndrtTimeChanged(qint64 drt)
{ui->horizontalSlide_speedr->setMaximum(drt);int sec=drt/1000;//总时长int min=sec/60;//分sec=sec%60;//秒drtTime=QString::asprintf("%d:%d",min,sec);ui->label_speed->setText(posTime+"|"+drtTime);
}void MainWindow::OnposTimeChanged(qint64 pos)
{if(ui->horizontalSlide_speedr->isSliderDown()){return;//如果正在拖动滑动条,则直接退出}ui->horizontalSlide_speedr->setSliderPosition(pos);int sec=pos/1000;int min=sec/60;sec=sec%60;posTime=QString::asprintf("%d:%d",min,sec);ui->label_speed->setText(posTime+"|"+drtTime);
}

槽函数链接:

connect(player,SIGNAL(stateChanged(QMediaPlayer::State)),this,SLOT(OnStateButtonChanged(QMediaPlayer::State)));connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(OnposTimeChanged(qint64)));connect(player,SIGNAL(durationChanged(qint64)),this,SLOT(OndrtTimeChanged(qint64)));

根据状态改变来连接相应的槽函数 。

按钮滑动条槽函数 :

    void on_pushButton_open_clicked();//打开文件void on_pushButton_play_clicked();//播放void on_pushButton_pause_clicked();//暂停void on_pushButton_stop_clicked();//停止void on_pushButton_Volumn_clicked();//声音void on_horizontalSlider_Volumn_valueChanged(int value);//声音滑动条void on_horizontalSlide_speedr_valueChanged(int value);//进度条

对于open:

void MainWindow::on_pushButton_open_clicked()
{QString currentpath=QDir::homePath();//获得系统当前目录QString dlgtitle="请选择视频文件";QString filter="所有文件(*.*);;mp4文件(*.mp4)";//文件过滤器QString strfile=QFileDialog::getOpenFileName(this,dlgtitle,currentpath,filter);if(strfile.isEmpty()){return;}QFileInfo fileinfo(strfile);ui->label_name->setText(fileinfo.fileName());player->setMedia(QUrl::fromLocalFile(strfile));//设置播放文件player->play();
}

我们首先获取文件的位置路径,在设置文件过滤器来获取我们所需要的MP4文件格式,最后设置播放文件进行播放。

其他开始,暂停等一些按钮槽函数:

void MainWindow::on_pushButton_play_clicked()
{player->play();
}void MainWindow::on_pushButton_pause_clicked()
{player->pause();
}void MainWindow::on_pushButton_stop_clicked()
{player->stop();
}void MainWindow::on_pushButton_Volumn_clicked()
{bool bmute=player->isMuted();player->setMuted(!bmute);//根据是否静音来显示音量图标if(bmute){ui->pushButton_Volumn->setIcon(QIcon(":/icon/sound.png"));}else{ui->pushButton_Volumn->setIcon(QIcon(":/icon/mute.png"));}
}void MainWindow::on_horizontalSlider_Volumn_valueChanged(int value)
{player->setVolume(value);
}void MainWindow::on_horizontalSlide_speedr_valueChanged(int value)
{player->setPosition(value);
}

总结:

只是一个简单视频播放器,博主能力有限还在学习当中。大家可自行尝试修改改进。


http://www.mrgr.cn/p/07785441

相关文章

Streamlit:快速构建可视化网页(数据科学必备)

很多算法工程师在完成数据分析、模型训练或者项目总结的时候,往往只能通过ppt汇报,添加数据图表、截图模型实验结果等。如果想提供一个前端演示demo,通常可以搭建flask服务,但是flask需要学习很多前端知识,如css、html等,这又是一个深之又深的坑。那有没有什么工具能够跳…

「Dasha and Photos」Solution

简述题意 给定一个 n m n \times m nm 的方格&#xff0c;每个格子里有一个小写英文字母。 现在你有 k k k 个 n m n \times m nm 的方格&#xff0c;这些方格都是给定方格的基础上将左上角为 ( a i , b i ) (a_i,b_i) (ai​,bi​)&#xff0c;右下角为 ( c i , d i ) …

SpringBoot项目GraalVM迁移

一些背景 一直想把项目迁移到使用GraalVM构建出的原生应用上,但是在前段时间的一次尝试后,发现很难做到,其中一个最主要原因就在于我目前手头上没有X86架构的电脑。平时我使用的是一个M1处理器的MacBook,编译出的Docker镜像架构指令集也是Arm64的,无法在我的X86服务器启动…

Android Studio报错:Constant expression required

【出现的问题】&#xff1a; 使用JDK17以上版本&#xff0c;switch语句报错&#xff1a;Constant expression required 【解决方法】&#xff1a; 在gradle.properties配置文件下添加代码&#xff1a; android.nonFinalResIdsfalse 如图&#xff1a; 接着再点击右上角的Sync…

国内验签SSL证书——数据不出境,政务、高校、金融机构必备

涉及金融、政务、教育等重要领域的网站&#xff0c;国家要求是重要数据坚决不能出境。特别是《中华人民共和国网络安全法》的实施&#xff0c;国内验签SSL证书成为了提升网站安全性、保护用户数据和维护网站信誉的重要工具。 国内验签SSL证书的优势 1数据不出境 根据国家相关法…

基于springboot+mybatis+vue的项目实战之(后端+前后端联调)

步骤&#xff1a; 1、项目准备&#xff1a;创建数据库&#xff08;之前已经创建则忽略&#xff09;&#xff0c;以及数据库连接 2、建立项目结构文件夹 3、编写pojo文件 4、编写mapper文件&#xff0c;并测试sql语句是否正确 5、编写service文件 6、编写controller文件 …

PLC学习笔记

PLC学习笔记 前言一、一些基操知识二、GX works2编程2.1 位逻辑1.2 中间寄存器1.3 PLC的扫描方式 总结 前言 我这个人真的是太渴望知识了~ 一、一些基操知识 一般X表示输入&#xff0c;Y表示输出。一般八个为一组X0~X7M表示中间寄存器&#xff0c;M0~M7时间T、计数C 二、GX …

Java基于Spring Boot框架的课程管理系统(附源码,说明文档)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

董浩影评

本文来自博客园,作者:↑-↑-我-的-仓-鼠-↑-↑,转载请注明原文链接:https://www.cnblogs.com/donghao99/p/18182035

《视觉十四讲》例程运行记录(5)——运行ch8视觉里程计2光流法和直接法的实践例程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、运行ch8的例程代码1. 编译例程代码前的修改2. 编译例程3. 编译报错(1) 报错一&#xff1a;使用cmake .. 编译时出现(2) 报错二&#xff1a;make编译时出现(3) 报…

Rust | 实现 API 限速操作 Example

在这篇文章中,我们将讨论如何在 Rust 中实现 API 限速。当涉及到生产中的服务时,是为了确保不良行为者不会滥用 API——这就是 API 限速的作用所在。 我们将实现 “滑动窗口” 算法,通过动态周期来检查请求历史,并使用基本的内存 hashmap 来存储用户 IP 及其请求时间。我们…

synchronized关键字的底层原理

1synchronized关键字的底层原理 Monitor 举个例子&#xff1a; 1.线程1执行synchronized代码块&#xff0c;里面用到了lock(对象锁)。首先会让这个lock对象和monitor关联&#xff0c;判断monitor中的owner属性是否为null。如果为null直接获取对象锁。owner只能关联一个线程。 2…

【JUC】并发编程 Synchronized 锁升级原理

Synchronized如何实现同步/互斥的效果&#xff1f; monitorenter&#xff1a; 将锁对象对象头中Mark Word的前30bit替换成指向操作系统中与其关联的monitor对象&#xff0c;将锁记录位状态改为10 monitorexit&#xff1a; 将锁对象对象头中Mark Word进行重置&#xff0c;重新恢…

Tasks 和算子链

Flink中的每一个操作算子称为一个Task(任务),算子的每个具体实例则称为SubTask(子任务),SubTask是Flink中最小的处理单元,多个SubTask可能在不同的机器上执行。一个TaskManager进程包含一个或多个执行线程,用于执行SubTask。 TaskManager中的一个Task Slot对应一个执行…

MT3516W-ASEMI工业电源专用MT3516W

MT3516W-ASEMI工业电源专用MT3516W编辑:ll MT3516W-ASEMI工业电源专用MT3516W 型号:MT3516W 品牌:ASEMI 封装:MTW-5 最大重复峰值反向电压:1600V 最大正向平均整流电流(Vdss):35A 功率(Pd):大功率 芯片个数:5 引脚数量:5 类型:插件整流桥、整流方桥 正向浪涌电流:45…

IP SSL证书申请教程:实现HTTPS加密访问

随着网络安全意识的提高&#xff0c;HTTPS加密访问已经成为网站安全性的重要标准。通过安装SSL证书&#xff0c;网站可以实现数据的加密传输&#xff0c;有效保护用户隐私和数据安全。本文将详细介绍如何为IP地址申请SSL证书&#xff0c;并实现HTTPS加密访问。 一、准备工作 …

会充电的CANoe-赋能新能源汽车,高效完成即插即充(PnC)智能充电功能测试

ISO 15118-2标准中描述的PnC功能,可以实现插枪即充电,识别、计费信息、充电参数都通过高级别通信在EV和EVSE之间自动交换。简化了电动汽车的充电过程,提高了用户体验,为电动汽车行业带来了更智能、更便捷的充电解决方案。然而,电动汽车和充电站之间要实现自动通信和计费,…

数据结构(四)—— 堆和二叉树(上)

制作不易&#xff0c;三连支持一下呗&#xff01;&#xff01;&#xff01; 文章目录 前言一、树的概念及结构二、二叉树的概念及结构总结 前言 这篇博客我们将进行更加复杂的一种数据结构的学习——树形结构。 一、树的概念及结构 树是一种非线性的数据结构&#xff0c;它是…

03 插入排序

03 插入排序1.插入排序的含义类似扑克牌,假设认为0-0位置有序,再把0-1的位置变有序,循环直到所有的有序。每次拿取右侧的数字,一个一个对比放到左侧来。2.示例代码 def insertion_sort(arr):if arr is None or len(arr) < 2:returnfor i in range(1, len(arr)):# 0 ~ i-…

物联网工程毕业后没有一技之长,转行网络安全可行吗?

我21年毕业&#xff0c;大学专业是物联网工程&#xff0c;我相信很多人在象牙塔里都很迷茫&#xff0c;到了大三大四才开始慢慢焦虑自己该从事什么工作培养一技之长&#xff0c;或者是跟随大部队考研继续逃避社会&#xff0c;我选择了后者。21年7月拿到毕业证以后因为没有一技之…