截屏的功能主要是借鉴了这位大佬的代码,
Qt QMediaPlayer + QAbstractVideoSurface 实现播放本地视频并截取帧图像_qvideowidget界面叠加_韭菜炒鸡蛋的博客-优快云博客w
然后做了一些优化,使截屏的帧更精准。
首先重写一个类VideoSurface,头文件源文件如下:
#ifndef VIDEOSURFACE_H
#define VIDEOSURFACE_H
#include <QObject>
#include <QAbstractVideoSurface>
class VideoSurface : public QAbstractVideoSurface
{
Q_OBJECT
public:
explicit VideoSurface(QObject *parent = 0);
~VideoSurface();
signals:
void showImage(QVideoFrame frame);
protected:
bool present(const QVideoFrame &frame);
QList<QVideoFrame::PixelFormat> supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType =
QAbstractVideoBuffer::NoHandle) const;
};
#endif // VIDEOSURFACE_H
#include "videosurface.h"
VideoSurface::VideoSurface(QObject *parent) : QAbstractVideoSurface(parent)
{
}
VideoSurface::~VideoSurface()
{
this->stop();
}
QList<QVideoFrame::PixelFormat> VideoSurface::supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType) const
{
Q_UNUSED(handleType);
QList<QVideoFrame::PixelFormat> listPixelFormats;
listPixelFormats << QVideoFrame::Format_ARGB32
<< QVideoFrame::Format_ARGB32_Premultiplied
<< QVideoFrame::Format_RGB32
<< QVideoFrame::Format_RGB24
<< QVideoFrame::Format_RGB565
<< QVideoFrame::Format_RGB555
<< QVideoFrame::Format_ARGB8565_Premultiplied
<< QVideoFrame::Format_BGRA32
<< QVideoFrame::Format_BGRA32_Premultiplied
<< QVideoFrame::Format_BGR32
<< QVideoFrame::Format_BGR24
<< QVideoFrame::Format_BGR565
<< QVideoFrame::Format_BGR555
<< QVideoFrame::Format_BGRA5658_Premultiplied
<< QVideoFrame::Format_AYUV444
<< QVideoFrame::Format_AYUV444_Premultiplied
<< QVideoFrame::Format_YUV444
<< QVideoFrame::Format_YUV420P
<< QVideoFrame::Format_YV12
<< QVideoFrame::Format_UYVY
<< QVideoFrame::Format_YUYV
<< QVideoFrame::Format_NV12
<< QVideoFrame::Format_NV21
<< QVideoFrame::Format_IMC1
<< QVideoFrame::Format_IMC2
<< QVideoFrame::Format_IMC3
<< QVideoFrame::Format_IMC4
<< QVideoFrame::Format_Y8
<< QVideoFrame::Format_Y16
<< QVideoFrame::Format_Jpeg
<< QVideoFrame::Format_CameraRaw
<< QVideoFrame::Format_AdobeDng;
//qDebug() << listPixelFormats;
// Return the formats you will support
return listPixelFormats;
}
bool VideoSurface::present(const QVideoFrame &frame)
{
if (frame.isValid())
{
emit showImage(frame);
return true;
}
return false;
}
然后这个类的使用方法如下(因为QAbstractVideoSurface会占用很高CPU,所以在不截图的时候用QVideoWidget来显示画面,当截图的时候用QAbstractVideoSurface来显示画面,截完图之后继续用QVideoWidget来显示画面,从而实现非必要时,不占用过多CPU资源):
private:
QMediaPlayer *m_mediaPlayer;
QVideoWidget *videoWidget=nullptr;
VideoSurface *m_videoSurface=nullptr;
public slots:
void onShowImage(QVideoFrame frame);
void VideoPlayer::onShowImage(QVideoFrame frame)
{
disconnect(m_videoSurface,SIGNAL(showImage(QVideoFrame)),
this, SLOT(onShowImage(QVideoFrame)));
int position = m_mediaPlayer->position();
QTime timeCrt = QTime(0,0,0);
timeCrt = timeCrt.addMSecs(position);
QString strFileName = timeCrt.toString("hh-mm-ss-zzz")+".jpg";
QString crtFileName = m_strPathList.at(m_nCrtFileIndex);
strFileName = crtFileName.mid(0,crtFileName.lastIndexOf('.'))+strFileName;
imageFromVideoFrame(frame).save(strFileName);
m_mediaPlayer->setVideoOutput(videoWidget);
m_mediaPlayer->pause();
m_mediaPlayer->setPosition(m_nPausePos);
}
void VideoPlayer::keyPressEvent(QKeyEvent *event)
{//按住Ctrl+S实现当前画面截屏
if(event->modifiers()==Qt::ControlModifier && event->key()==Qt::Key_S)
{
m_mediaPlayer->pause();
m_nPausePos = m_mediaPlayer->position();
connect(m_videoSurface,SIGNAL(showImage(QVideoFrame)),
this, SLOT(onShowImage(QVideoFrame)), Qt::QueuedConnection);
m_mediaPlayer->setVideoOutput(m_videoSurface);
m_mediaPlayer->setPosition(m_nPausePos);
m_mediaPlayer->pause();
}
}
我的源码地址:
https://download.youkuaiyun.com/download/weixin_43935474/87708655