QT多媒体开发(三):使用QMediaPlayer播放视频

server/2024/12/24 7:50:00/

QMediaPlayer 类不仅能播放音频文件,也可以播放各种常见的视频文件,如 MP4 文件和 WMV 文件。QMediaPlayer 能对视频文件进行解码,并在某个界面组件上显示视频帧。

使用 QMediaPlayer 播放视频时,必须用函数 setVideoOutput()设置用于显示视频的界面组件, 有 QVideoWidget 和 QGraphicsVideoItem 两种显示视频的组件:QVideoWidget 是 QWidget 的类, 是普通的界面组件;QGraphicsVideoItem 是适用于图形/视图架构的图形项。

注意还需要使用setAudioOutput()设置音频输出通道,否则播放视频时会没有声音。

使用QVideoWidget 类

由于使用QVideoWidget 实现全屏显示有一个问题,程序无法退出全屏显示,按 ESC 键也不起作用。所以可以从QVideoWidget 继承并自定义了一个类 TMyVideoWidget。

然后为这个自定义类重写keyPressEvent()事件和mousePressEvent()事件。实现在全屏状态下按 ESC 键可以退出全屏状态,在组件上点击鼠标可以暂停播放或继续播放。

该类的完整实现如下所示:

#ifndef TMYVIDEOWIDGET_H
#define TMYVIDEOWIDGET_H#include    <QObject>
#include    <QWidget>
#include    <QMediaPlayer>
#include    <QVideoWidget>class TMyVideoWidget : public QVideoWidget
{Q_OBJECT
private:QMediaPlayer    *m_player;
protected:void keyPressEvent(QKeyEvent *event);void mousePressEvent(QMouseEvent *event);
public:TMyVideoWidget(QWidget *parent =nullptr);void    setMediaPlayer(QMediaPlayer *player);
};#endif // TMYVIDEOWIDGET_H#include    "tmyvideowidget.h"
#include    <QKeyEvent>
#include    <QMouseEvent>void TMyVideoWidget::keyPressEvent(QKeyEvent *event)
{//按键事件处理函数,ESC退出全屏状态if ((event->key() == Qt::Key_Escape)&&(isFullScreen())){setFullScreen(false);       //退出全屏状态event->accept();QVideoWidget::keyPressEvent(event);}
}void TMyVideoWidget::mousePressEvent(QMouseEvent *event)
{//鼠标事件处理函数,单击时暂停或继续播放if (event->button()==Qt::LeftButton){if (m_player->playbackState()==QMediaPlayer::PlayingState)m_player->pause();elsem_player->play();}QVideoWidget::mousePressEvent(event);
}TMyVideoWidget::TMyVideoWidget(QWidget *parent):QVideoWidget(parent)
{}void TMyVideoWidget::setMediaPlayer(QMediaPlayer *player)
{//设置播放器m_player=player;
}

主窗口头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include    <QMainWindow>#include    <QtMultimedia>#include    "tmyvideowidget.h"QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTprivate:QMediaPlayer  *player;  //视频播放器QString  durationTime;QString  positionTime;public:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:
//自定义槽函数void do_stateChanged(QMediaPlayer::PlaybackState state);void do_durationChanged(qint64 duration);void do_positionChanged(qint64 position);void on_btnAdd_clicked();void on_btnPlay_clicked();void on_btnPause_clicked();void on_btnStop_clicked();void on_sliderVolumn_valueChanged(int value);void on_btnSound_clicked();void on_sliderPosition_valueChanged(int value);void on_pushButton_clicked();
private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

在主窗口构造函数中创建QMediaPlayer。使用setAudioOutput()函数设置音频输出通道,使用setVideoOutput()设置视频显示组件(上述自定义类),并设置显示组件关联的播放器。

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);player = new QMediaPlayer(this);        //创建视频播放器QAudioOutput *audioOutput= new QAudioOutput(this);player->setAudioOutput(audioOutput);        //设置音频输出通道player->setVideoOutput(ui->videoWidget);    //设置视频显示组件ui->videoWidget->setMediaPlayer(player); //设置显示组件的关联播放器connect(player,&QMediaPlayer::playbackStateChanged,this, &MainWindow::do_stateChanged);connect(player,&QMediaPlayer::positionChanged,this, &MainWindow::do_positionChanged);connect(player,&QMediaPlayer::durationChanged,this, &MainWindow::do_durationChanged);
}

与音频播放一样,设置QMediaPlayer发射信号对应的槽函数。详细参考上一期音频播放

void MainWindow::do_stateChanged(QMediaPlayer::PlaybackState state)
{//播放器状态变化bool isPlaying = (state==QMediaPlayer::PlayingState);ui->btnPlay->setEnabled(!isPlaying);ui->btnPause->setEnabled(isPlaying);ui->btnStop->setEnabled(isPlaying);
}void MainWindow::do_durationChanged(qint64 duration)
{//文件时长变化ui->sliderPosition->setMaximum(duration);int   secs=duration/1000;   //秒int   mins=secs/60;         //分钟secs=secs % 60;             //余数秒durationTime=QString::asprintf("%d:%d",mins,secs);ui->LabRatio->setText(positionTime+"/"+durationTime);
}void MainWindow::do_positionChanged(qint64 position)
{//文件播放位置变化if (ui->sliderPosition->isSliderDown())return;     //如果正在拖动滑条,退出ui->sliderPosition->setSliderPosition(position);int   secs=position/1000;   //秒int   mins=secs/60;         //分钟secs=secs % 60;             //余数秒positionTime=QString::asprintf("%d:%d",mins,secs);ui->LabRatio->setText(positionTime+"/"+durationTime);
}

其他部分代码如下:


void MainWindow::on_btnAdd_clicked()
{//打开文件QString curPath=QDir::homePath();QString dlgTitle="选择视频文件";QString filter="视频文件(*.wmv, *.mp4);;所有文件(*.*)";QString aFile=QFileDialog::getOpenFileName(this,dlgTitle,curPath,filter);if (aFile.isEmpty())return;QFileInfo   fileInfo(aFile);ui->labCurMedia->setText(fileInfo.fileName());player->setSource(QUrl::fromLocalFile(aFile));  //设置播放文件player->play();
}void MainWindow::on_btnPlay_clicked()
{//播放player->play();
}void MainWindow::on_btnPause_clicked()
{//暂停player->pause();
}void MainWindow::on_btnStop_clicked()
{//停止player->stop();
}void MainWindow::on_sliderVolumn_valueChanged(int value)
{//调节音量player->audioOutput()->setVolume(value/100.0);
}void MainWindow::on_btnSound_clicked()
{//静音按钮bool mute=player->audioOutput()->isMuted();player->audioOutput()->setMuted(!mute);if (mute)ui->btnSound->setIcon(QIcon(":/images/images/volumn.bmp"));elseui->btnSound->setIcon(QIcon(":/images/images/mute.bmp"));
}void MainWindow::on_sliderPosition_valueChanged(int value)
{//播放位置player->setPosition(value);
}void MainWindow::on_pushButton_clicked()
{//全屏按钮ui->videoWidget->setFullScreen(true);
}

可以看到与播放音频时实现类似功能的代码基本相同。

使用QGraphicsVideoItem类

QGraphicsVideoItem 是 继承自 QGraphicsItem 的类,是适用于图形/视图架构的视频输出组件。因此,使用 QGraphicsVideoItem 组件显示视频时,可以在显示场景中将其和其他图形项组合显示,可以使用 QGraphicsItem 类的放 大、缩小、拖动、旋转等功能。

主窗口头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include    <QMainWindow>
#include    <QtMultimedia>
#include    <QGraphicsVideoItem>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{Q_OBJECT
private:QMediaPlayer  *player;QGraphicsVideoItem *videoItem;   //视频显示图形项QString  durationTime;QString  positionTime;
public:MainWindow(QWidget *parent = nullptr);~MainWindow();
private slots://自定义槽函数void do_stateChanged(QMediaPlayer::PlaybackState state);void do_durationChanged(qint64 duration);void do_positionChanged(qint64 position);void on_btnAdd_clicked();void on_btnPlay_clicked();void on_btnPause_clicked();void on_btnStop_clicked();void on_sliderVolumn_valueChanged(int value);void on_btnSound_clicked();void on_sliderPosition_valueChanged(int value);void on_btnZoomIn_clicked();void on_btnZoomOut_clicked();
private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

在主窗口构造函数中,像之前一样创建QMediaPlayer播放器并设置音频输出通道

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);player = new QMediaPlayer(this);       //创建播放器QAudioOutput *audioOutput= new QAudioOutput(this);player->setAudioOutput(audioOutput);   //设置音频输出通道QGraphicsScene *scene = new QGraphicsScene(this);   //创建场景ui->graphicsView->setScene(scene);     //为视图设置场景videoItem = new QGraphicsVideoItem;    //常见视频显示图形项videoItem->setSize(QSizeF(360, 240));videoItem->setFlags(QGraphicsItem::ItemIsMovable| QGraphicsItem::ItemIsSelectable);
//                        | QGraphicsItem::ItemIsFocusable);scene->addItem(videoItem);player->setVideoOutput(videoItem);      //设置视频显示图形项connect(player,&QMediaPlayer::playbackStateChanged,this, &MainWindow::do_stateChanged);connect(player,&QMediaPlayer::positionChanged,this, &MainWindow::do_positionChanged);connect(player,&QMediaPlayer::durationChanged,this, &MainWindow::do_durationChanged);QGraphicsSimpleTextItem   *item2=new QGraphicsSimpleTextItem("海风吹,海浪涌");QFont font=item2->font();font.setPointSize(20);item2->setFont(font);item2->setPos(0,0);item2->setBrush(QBrush(Qt::blue));item2->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
//                    | QGraphicsItem::ItemIsFocusable);scene->addItem(item2);//    //一个圆,中心位于scene的边缘
//    QGraphicsEllipseItem   *item3=new QGraphicsEllipseItem(50,50,50,50); //矩形框内创建椭圆,绘图项的局部坐标,左上角(-100,-50),宽200,高100
//    item3->setPos(100,100);
//    item3->setBrush(QBrush(Qt::red));
//    item3->setFlags(QGraphicsItem::ItemIsMovable
//                    | QGraphicsItem::ItemIsSelectable
//                    | QGraphicsItem::ItemIsFocusable);
//    scene->addItem(item3);
}

唯一需要注意的是,显示视频用的组件是QGraphicsVideoItem类型的,因此在使用setVideoOutput()函数时传入的参数是QGraphicsVideoItem的图形项。QGraphicsView组件已经嵌入在主窗口中,设置好场景和图形项后,使用方式与往期博客讲的图形/视图架构一致,视频窗口在这里也是一个图形项,在主窗口构造函数中可以设置初始化大小。

视频播放的其他部分与QVideoWidget 播放视频的例子基本一致,只是对于在QGraphicsView上显示的视频,可以扩展一些其他操作。


void MainWindow::do_stateChanged(QMediaPlayer::PlaybackState state)
{bool isPlaying = (state==QMediaPlayer::PlayingState);ui->btnPlay->setEnabled(!isPlaying);ui->btnPause->setEnabled(isPlaying);ui->btnStop->setEnabled(isPlaying);
}void MainWindow::do_durationChanged(qint64 duration)
{ui->sliderPosition->setMaximum(duration);int   secs=duration/1000;//秒int   mins=secs/60; //分钟secs=secs % 60;//余数秒durationTime=QString::asprintf("%d:%d",mins,secs);ui->LabRatio->setText(positionTime+"/"+durationTime);
}void MainWindow::do_positionChanged(qint64 position)
{if (ui->sliderPosition->isSliderDown())return;ui->sliderPosition->setSliderPosition(position);int   secs=position/1000;   //秒int   mins=secs/60;         //分钟secs=secs % 60;             //余数秒positionTime=QString::asprintf("%d:%d",mins,secs);ui->LabRatio->setText(positionTime+"/"+durationTime);
}void MainWindow::on_btnAdd_clicked()
{QString curPath=QDir::homePath();QString dlgTitle="选择视频文件";QString filter="视频文件(*.wmv, *.mp4);;所有文件(*.*)";QString aFile=QFileDialog::getOpenFileName(this,dlgTitle,curPath,filter);if (aFile.isEmpty())return;QFileInfo   fileInfo(aFile);ui->LabCurMedia->setText(fileInfo.fileName());player->setSource(QUrl::fromLocalFile(aFile));player->play();
}void MainWindow::on_btnPlay_clicked()
{player->play();
}void MainWindow::on_btnPause_clicked()
{player->pause();
}void MainWindow::on_btnStop_clicked()
{player->stop();
}void MainWindow::on_sliderVolumn_valueChanged(int value)
{player->audioOutput()->setVolume(value);
}void MainWindow::on_btnSound_clicked()
{bool mute=player->audioOutput()->isMuted();player->audioOutput()->setMuted(!mute);if (mute)ui->btnSound->setIcon(QIcon(":/images/images/volumn.bmp"));elseui->btnSound->setIcon(QIcon(":/images/images/mute.bmp"));
}void MainWindow::on_sliderPosition_valueChanged(int value)
{player->setPosition(value);
}void MainWindow::on_btnZoomIn_clicked()
{//放大qreal factor=videoItem->scale();videoItem->setScale(factor+0.1);
}void MainWindow::on_btnZoomOut_clicked()
{//缩小qreal factor=videoItem->scale();if (factor>=0.2)videoItem->setScale(factor-0.1);
}

参考

QT6 C++开发指南


http://www.ppmy.cn/server/152709.html

相关文章

maven-resources-production:ratel-fast: java.lang.IndexOutOfBoundsException

Maven生产环境中遇到java.lang.IndexOutOfBoundsException的问题&#xff0c;尝试了重启电脑、重启IDEA等常规方法无效&#xff0c;最终通过直接重建工程解决了问题。 Rebuild Project 再启动OK

云起无垠荣获第八届“强网杯”高阶技术专项赛优秀奖

近日&#xff0c;第八届 “强网杯” 全国网络安全挑战赛线下赛于郑州高新区的网络安全科技馆赛博厅圆满落幕。云起无垠创始人兼 CEO 沈凯文博士在活动中发表了题为《安全智能体技术实践与内生安全问题思考》的精彩演讲。 沈凯文博士指出&#xff0c;当前数字化时代下网络安全领…

什么是事务

在数据库管理系统中&#xff0c;事务&#xff08;Transaction&#xff09;是执行一系列操作的最小工作单元&#xff0c;这些操作要么全部成功&#xff0c;要么全部失败。为了确保数据的一致性和完整性&#xff0c;事务被设计为具备四大特性&#xff0c;即原子性&#xff08;Ato…

Retrofit源码分析:动态代理获取Api接口实例,解析注解生成request,线程切换

目录 一&#xff0c;Retrofit的基本使用 1.定义api接口 2.创建Retrofit实例 3.获取api接口实例发起请求 二&#xff0c;静态代理和动态代理 1&#xff0c;静态代理 2&#xff0c;动态代理 三&#xff0c;动态代理获取Api接口实例 四&#xff0c;解析接口方法注解&…

解锁 GitBook 的奥秘:从入门到精通之旅

一、GitBook 初印象 在当今数字化时代&#xff0c;知识的传播与分享变得愈发便捷和多样化。GitBook 作为一款强大的文档编辑与电子书制作工具&#xff0c;正逐渐崭露头角&#xff0c;为广大创作者、开发者和知识爱好者提供了一个高效且灵活的平台。它不仅仅是一个简单的文档编写…

拓展AI超级智能后的人类生活场景

一、日常生活领域 &#xff08;一&#xff09;家居生活 在AI超级智能拓展之后&#xff0c;家居生活将发生翻天覆地的变化。清晨&#xff0c;当第一缕阳光透过智能窗帘的缝隙照进房间时&#xff0c;智能管家已经根据主人的生物钟和当天的日程安排&#xff0c;轻柔地播放起舒缓的…

重温设计模式--单例模式

文章目录 单例模式&#xff08;Singleton Pattern&#xff09;概述单例模式的实现方式及代码示例1. 饿汉式单例&#xff08;在程序启动时就创建实例&#xff09;2. 懒汉式单例&#xff08;在第一次使用时才创建实例&#xff09; 单例模式的注意事项应用场景 C代码懒汉模式-经典…

图像处理基础 | 格式转换.rgb转.jpg 灰度图 python

一般情况下 .rgb 格式的存储顺序&#xff1a; 颜色顺序&#xff1a; 一般情况下&#xff0c;.rgb 文件存储的是原始的 RGB 数据&#xff08;而不是 BGR 数据&#xff09;。即每个像素是由 R&#xff08;红色&#xff09;、G&#xff08;绿色&#xff09;、B&#xff08;蓝色&…