QT 播放器之VideoWidget
我們首先需要找到視頻播放的類, 不會找不要緊~直接打開翻譯 視頻?->Video ,播放 ->Play
組合起來就是 QVideoPlay或者 QPlayVideo,搜索文檔看看,很好!并沒有想要的類
那么搜索一下QVideo呢,滾動一下看到一個QVideoWidget,或許這個就是我們想要的?
打開該文檔找一下,找到以下栗子~
OK,這么說 我們需要的就是 QMediaPlayer 媒體播放類了。
根據栗子寫一遍,不錯啊感覺已經滿足了我的需要。但是當我在VideoWidget上面添加控件時卻發現。。。這就是個辣雞
根本就不能在VideoWidget上面添加控件,添加后會看到不到。要它何用!
看一下媒體播放類的 setVideoOutput 。可以看到這個函數重載3次
打開QGraphicsVideoItem類文檔看看,感覺只是說視頻作為一個媒體對象在QGraphicsScene顯示而已,感覺沒啥幫助。看下一個類
嗯,一眼看到一個視頻幀!。想想。獲得幀后直接在Widget繪制,這樣就可以在視頻上添加控件了
子類化后應該重寫 supportedPixelFormats函數給出接受的格式和present函數接收到的幀信息,然后利用信號返回圖像即可
#ifndef VIDEOSURFACE_H #define VIDEOSURFACE_H#include <QAbstractVideoSurface>class VideoSurface : public QAbstractVideoSurface {Q_OBJECT public:explicit VideoSurface(QObject *parent = nullptr);signals:void showImage(QImage img); public slots:// QAbstractVideoSurface interface public:QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const;bool present(const QVideoFrame &frame); };#endif // VIDEOSURFACE_H #include "videosurface.h"VideoSurface::VideoSurface(QObject *parent) : QAbstractVideoSurface(parent) {}QList<QVideoFrame::PixelFormat> VideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const {Q_UNUSED(type);QList<QVideoFrame::PixelFormat> list;list<<QVideoFrame::Format_RGB32<<QVideoFrame::Format_RGB32;return list; }bool VideoSurface::present(const QVideoFrame &frame) {if(frame.isValid()){QVideoFrame cloneFrame(frame);cloneFrame.map(QAbstractVideoBuffer::ReadOnly);QImage img(cloneFrame.bits(),cloneFrame.width(),cloneFrame.height(),QVideoFrame::imageFormatFromPixelFormat(cloneFrame.pixelFormat()));cloneFrame.unmap();emit showImage(img);return true;}return false; }?
讓我們來測試一下這個類是否達到我們的要求
#include "mainwindow.h" #include "videosurface.h" #include <QApplication> #include <QLabel> #include <QPushButton>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有一下功能
- 最重要的當然是接收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
?
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 <QString> #include <QMap>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<QString,QStringList> m_data; };#endif // FILEFILTER_H #include "filefilter.h"#include <QFile> #include <QJsonParseError> #include <QJsonArray> #include <QJsonObject> #include <QJsonValue> #include <QDebug> #include <QApplication>FileFilter::FileFilter() {}void FileFilter::addFilter(const QString &filePath) {QFile file(filePath);if(!file.open(QIODevice::Text|QIODevice::ReadOnly)){qDebug()<<QStringLiteral("not open file!");return;}QByteArray json = file.readAll();file.close();QJsonParseError json_error;QJsonDocument jsonDoc(QJsonDocument::fromJson(json, &json_error));if(json_error.error!=QJsonParseError::NoError){qDebug()<<json_error.errorString();return;}if(jsonDoc.isArray()){auto array = jsonDoc.array();for(auto i=array.begin();i!=array.end();i++){if((*i).isObject()){auto obj = (*i).toObject();auto key = obj.value(obj.keys().first());if(key.isArray()){auto values = key.toArray();QStringList list;for(auto j=values.begin();j!=values.end();j++){list<< "*."+(*j).toString();}m_data[obj.keys().first()]=list;}}}} }QStringList FileFilter::getFilter(const QString &key)const {return m_data[key]; }QString FileFilter::getFilterString(const QString &key)const {QString result;foreach (auto str, m_data[key]) {result.append(str+" ");}return result; }QStringList FileFilter::getFilterAll() const {QStringList result;foreach (auto key, m_data.keys()){result<<m_data[key];}return result; }QString FileFilter::getFilterString()const {QString result;foreach (auto key, m_data.keys()){result .append( getFilterString(key));}return result; }?
?
?
?
?
?
?
最后來看一下完整的代碼
#ifndef VIDEOWIDGET_H #define VIDEOWIDGET_H#include <QImage> #include <QWidget>QT_BEGIN_NAMESPACE class QPushButton; class FileFilter; QT_END_NAMESPACEclass 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 <QEvent> #include <QFileDialog> #include <QPainter> #include <QPushButton> #include <QWidget> #include <QDebug>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 播放器之VideoWidget的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 博客搬家
- 下一篇: 蓝桥杯、PAT、CCF CSP、团体程序