当前位置: 首页 > article >正文

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

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();
        else
          m_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_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

private:
    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"));
    else
        ui->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"));
    else
        ui->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.kler.cn/a/454210.html

相关文章:

  • 15、【OS】【Nuttx】OS裁剪,运行指定程序,周期打印当前任务
  • javaweb 04 springmvc
  • Docker Run使用方法及参数详细说明
  • 每日小题打卡
  • c#中using语句
  • 【ES6复习笔记】集合Set(13)
  • 学习记录—正则表达式-基本语法
  • k8s,service如何找到容器
  • Visual Studio Code(VS Code)配置C/C++环境
  • 社交媒体形象打造中的“号设化”与开源AI智能名片商城小程序的应用
  • 嵌入式学习-QT-Day07
  • SQLite本地数据库的简介和适用场景——集成SpringBoot的图文说明
  • 【TaskBasics】- KRTS C++示例精讲(3)
  • 什么是 DevOps 自动化?
  • C++ STM32 F4xx USART LL库 DMA + IDLE ISR 驱动裸机 +FreeRTOS 任务通知
  • (六)循环神经网络_基本的RNN
  • Wireshark软件下载安装及基础
  • Nginx界的天花板-Oracle 中间件OHS 11g服务器环境搭建
  • JVM内存模型、垃圾回收机制及简单调优方式
  • 重温设计模式--10、单例模式
  • kubernetes存储架构之PV controller源码解读
  • 穿山甲等广告联盟依据哪些维度给APP、小程序结算广告变现收益
  • 【小菜鸟之—CEPH文件集群部署实践】
  • 【Redis】 数据淘汰策略
  • java中list和map区别
  • 国际版JAVA同城服务美容美发到店服务系统源码支持Android+IOS+H5