QMediaPlayer+重写继承自QAbstractVideoSurface的类实现视频播放截图

文章介绍了如何使用Qt的QMediaPlayer和QAbstractVideoSurface类来实现本地视频播放及精确截取帧图像。通过自定义VideoSurface类优化了截屏的精度,并在不截图时使用QVideoWidget减少CPU占用。在触发截图时,利用信号和槽机制将视频输出切换到VideoSurface进行截屏,完成后切回QVideoWidget显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

截屏的功能主要是借鉴了这位大佬的代码,

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GreenHandBruce

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值