QT 播放器之VideoWidget

我们首先需要找到视频播放的类, 不会找不要紧~直接打开翻译 视频 ->Video ,播放 ->Play

组合起来就是 QVideoPlay或者 QPlayVideo,搜索文档看看,很好!并没有想要的类

那么搜索一下QVideo呢,滚动一下看到一个QVideoWidget,或许这个就是我们想要的?

打开该文档找一下,找到以下栗子~

QT 播放器之VideoWidget_第1张图片

OK,这么说 我们需要的就是 QMediaPlayer 媒体播放类了。

根据栗子写一遍,不错啊感觉已经满足了我的需要。但是当我在VideoWidget上面添加控件时却发现。。。这就是个辣鸡

根本就不能在VideoWidget上面添加控件,添加后会看到不到。要它何用!
看一下媒体播放类的 setVideoOutput 。可以看到这个函数重载3次

QT 播放器之VideoWidget_第2张图片

打开QGraphicsVideoItem类文档看看,感觉只是说视频作为一个媒体对象在QGraphicsScene显示而已,感觉没啥帮助。看下一个类

QT 播放器之VideoWidget_第3张图片

嗯,一眼看到一个视频帧!。想想。获得帧后直接在Widget绘制,这样就可以在视频上添加控件了

QT 播放器之VideoWidget_第4张图片

子类化后应该重写 supportedPixelFormats函数给出接受的格式和present函数接收到的帧信息,然后利用信号返回图像即可

#ifndef VIDEOSURFACE_H
#define VIDEOSURFACE_H

#include 

class VideoSurface : public QAbstractVideoSurface
{
    Q_OBJECT
public:
    explicit VideoSurface(QObject *parent = nullptr);

signals:
    void showImage(QImage img);
public slots:

    // QAbstractVideoSurface interface
public:
    QList supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const;
    bool present(const QVideoFrame &frame);
};

#endif // VIDEOSURFACE_H
#include "videosurface.h"

VideoSurface::VideoSurface(QObject *parent) : QAbstractVideoSurface(parent)
{

}

QList VideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const
{
    Q_UNUSED(type);
    QList list;
    list<

 

让我们来测试一下这个类是否达到我们的要求

#include "mainwindow.h"
#include "videosurface.h"
#include 
#include 
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    auto player = new QMediaPlayer;
    VideoSurface *video = new VideoSurface();
    player->setVideoOutput(video);

    QLabel label;
    label.resize(500,350);
    QPushButton *button = new QPushButton("23333",&label);
    label.show();

    QObject::connect(video,&VideoSurface::showImage,&label,[=,&label](QImage img){
        label.setPixmap(QPixmap::fromImage(img.scaled(label.width(),label.height())));
    });

    player->setMedia(QUrl::fromLocalFile("D:/fj/1.mp4"));
    player->play();

    return a.exec();
}

编译运行后。完美!~

QT 播放器之VideoWidget_第5张图片

 

有了视频帧后。接下来就是显示视频的Widget了,我希望该Widget有一下功能

  • 最重要的当然是接收Image然后绘制啦
  • 绘制的图像应该自适应WIdget
  • Widget上面应该有一个按钮,用来打开文件进行播放
  • 双击的时候应该可以把窗口全屏化
  • 当播放视频的时候,按钮肯定是要隐藏的啊
  • Widget没有图像的地方肯定不能空着啊比较难看,直接设置背景为黑色就行

 

自适应大小只需要使用QImage的缩放函数即可

img.scaled(width(),height(),Qt::KeepAspectRatio, Qt::SmoothTransformation);

使用QPainter 绘制图片,在设置帧的时候肯定需要update刷新一下Widget

    if(!img.isNull())
    {
        m_image = img.scaled(width(),height(),Qt::KeepAspectRatio, Qt::SmoothTransformation);
    }
    else
    {
        m_image = img;
    }
    update();

因为设置帧的时候已经进行缩放,所以绘制的时候只需要移动图片的位置到中间就行。

drawRect。底图是必须的,不然控件在上面移动会出现花屏现象

void VideoWidget::paintEvent(QPaintEvent *event)
{
    QPainter *painter = new QPainter();
    painter->begin(this);
    painter->setBrush(QBrush(QColor(0,0,0)));
    painter->drawRect(-1,-1,width()+1,height()+1);
    if(!m_image.isNull())
    {
        QRect target((width()-m_image.width())/2,(height()-m_image.height())/2,m_image.width(),m_image.height());
        painter->drawImage(target,m_image);
    }
    painter->end();
    QWidget::paintEvent(event);
}

按钮点击后当然是选择文件啦。此时就需要打开对话框了。查找一下文档, 文件对话框 ,直接就有QFileDialog

可以看到它有8个静态函数用来打开对话框,我现在需要的是打开一个文件然后进行播放。当然是getopenfile啦

然后QMediaPlayer setMedia 函数的参数要求是 QUrl  。所以我们需要的是 getopenfileurl

QT 播放器之VideoWidget_第6张图片

 

QUrl url = QFileDialog::getOpenFileUrl(nullptr,"select video file");

嗯。。测试了一下,打开后可以选择所有的类型的文件,但是我们不可能让用户选择所有文件。此时就需要使用该函数的第四个参数过滤一下文件类型

[
	{"media":["asf","wm","wmp","wmv","wma"]},
	{"real":["ram","rm","rmvb","rpm","scm","ra","rp","rt","smi","smil"]},
	{"dvd":["dat","evo","vob","ifo"]},
	{"quickTime":["mov","qt","aif","aiff","3g2","3gp","3gp2","3gpp","arm"]},
	{"otherVideo":["bjd","ghd","amv","avi","bik","csf","d2v","dsm","dsv","ivf","m1v","m2p","m2ts","m2v","m4p","m4p","m4k","mkv","mp4","mpe","mpeg","mpg","mts","ogm","pmp","pmp2","pss","pva","ratDVD","smk","tp","tpr","ts","vg2","vid","vp6","vp7","wv","asm","avsts","divx","webm","iso","vp9","hevc","265"]},
	{"otherAudio":["aac","ac3","acc","act","ape","au","cda","dsa","dss","dts","flac","m4a","mac","mid","midi","mp2","mp3","mp5","mpa","mpga","mod","ogg","ofr","rmi","tak","tta","wav","aifc"]},
	{"animation":["swf","flv","flic","fli","flc"]}
]

上面是从暴风影音抄下来关联类型。我们只需要读取一下json就好,至于类名称 当然是 QJson文档啦   QJsonDocument

QT 播放器之VideoWidget_第7张图片

通过该类读取Json即可

#ifndef FILEFILTER_H
#define FILEFILTER_H

#include 
#include 

class FileFilter
{
public:
    FileFilter();
    void addFilter(const QString &filePath);
    QStringList getFilter(const QString &key) const;
    QString getFilterString(const QString &key)const;
    QStringList getFilterAll()const;
    QString getFilterString()const;

private:
    QMap m_data;
};

#endif // FILEFILTER_H
#include "filefilter.h"

#include 
#include 
#include 
#include 
#include 
#include 
#include 

FileFilter::FileFilter()
{

}

void FileFilter::addFilter(const QString &filePath)
{
    QFile file(filePath);
    if(!file.open(QIODevice::Text|QIODevice::ReadOnly))
    {
        qDebug()<

 

 

 

 

 

 

 

最后来看一下完整的代码

#ifndef VIDEOWIDGET_H
#define VIDEOWIDGET_H

#include 
#include 

QT_BEGIN_NAMESPACE
class QPushButton;
class FileFilter;
QT_END_NAMESPACE

class VideoWidget : public QWidget
{
    Q_OBJECT
public:
    explicit VideoWidget(QWidget *parent = nullptr);
    void setFileFilter(FileFilter *filter);
    void showOpenButton();
    void hideOpenButton();

signals:
    void doubleClieck();
    void openFile(const QUrl &url);

public slots:
    void setImage(QImage image);

private slots:
    void openUrl();

    // QWidget interface
protected:
    void mouseDoubleClickEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *event);
    void resizeEvent(QResizeEvent *event);

private:
    QImage m_image;
    QPushButton *m_openButon;
    FileFilter *m_fileFilter=nullptr;
};

#endif // VIDEOWIDGET_H
#include "filefilter.h"
#include "videowidget.h"
#include 
#include 
#include 
#include 
#include 
#include 

VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent)
{
    m_openButon = new QPushButton(QStringLiteral("打开文件"),this);
    m_openButon->resize(100,50);
    connect(m_openButon,&QPushButton::clicked,this,&VideoWidget::openUrl);

    setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);

    QPalette p = palette();
    p.setColor(QPalette::Window, Qt::black);
    setPalette(p);

    setAttribute(Qt::WA_OpaquePaintEvent);
}

void VideoWidget::setFileFilter(FileFilter *filter)
{
    m_fileFilter = filter;
}

void VideoWidget::showOpenButton()
{
    m_openButon->show();
}

void VideoWidget::hideOpenButton()
{
    m_openButon->hide();
}

void VideoWidget::setImage(QImage img)
{
    if(!img.isNull())
    {
        m_image = img.scaled(width(),height(),Qt::KeepAspectRatio, Qt::SmoothTransformation);
    }
    else
    {
        m_image = img;
    }
    update();
}

void VideoWidget::openUrl()
{
    QString filter=m_fileFilter?m_fileFilter->getFilterString():QString();
    QUrl url = QFileDialog::getOpenFileUrl(nullptr,"select video file",QUrl(),filter);

    if(url.isLocalFile())
    {
        emit openFile(url);
    }
}

void VideoWidget::mouseDoubleClickEvent(QMouseEvent *event)
{
    emit doubleClieck();
    QWidget::mouseDoubleClickEvent(event);
}

void VideoWidget::paintEvent(QPaintEvent *event)
{
    QPainter *painter = new QPainter();
    painter->begin(this);
    painter->setBrush(QBrush(QColor(0,0,0)));
    painter->drawRect(-1,-1,width()+1,height()+1);
    if(!m_image.isNull())
    {
        QRect target((width()-m_image.width())/2,(height()-m_image.height())/2,m_image.width(),m_image.height());
        painter->drawImage(target,m_image);
    }
    painter->end();
    QWidget::paintEvent(event);
}

void VideoWidget::resizeEvent(QResizeEvent *event)
{
    m_openButon->move((width()-m_openButon->width())/2, (height()-m_openButon->height())/2);
    QWidget::resizeEvent(event);
}

 

 

 

你可能感兴趣的:(QT,播放器,QMediaPlayer,视频帧,QT)