我们首先需要找到视频播放的类, 不会找不要紧~直接打开翻译 视频 ->Video ,播放 ->Play
组合起来就是 QVideoPlay或者 QPlayVideo,搜索文档看看,很好!并没有想要的类
那么搜索一下QVideo呢,滚动一下看到一个QVideoWidget,或许这个就是我们想要的?
打开该文档找一下,找到以下栗子~
OK,这么说 我们需要的就是 QMediaPlayer 媒体播放类了。
根据栗子写一遍,不错啊感觉已经满足了我的需要。但是当我在VideoWidget上面添加控件时却发现。。。这就是个辣鸡
根本就不能在VideoWidget上面添加控件,添加后会看到不到。要它何用!
看一下媒体播放类的 setVideoOutput 。可以看到这个函数重载3次
打开QGraphicsVideoItem类文档看看,感觉只是说视频作为一个媒体对象在QGraphicsScene显示而已,感觉没啥帮助。看下一个类
嗯,一眼看到一个视频帧!。想想。获得帧后直接在Widget绘制,这样就可以在视频上添加控件了
子类化后应该重写 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();
}
编译运行后。完美!~
有了视频帧后。接下来就是显示视频的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
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
通过该类读取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);
}