Qt Qml 中提供了丰盛的多媒体相干的模块:

类型形容
MediaPlayer为场景增加音频/视频播放性能。
CaptureSession创立一个用于捕捉音频/视频的会话。
Camera拜访连贯到零碎的相机。
AudioInput拜访连贯到零碎的音频输出。
AudioOutput拜访连贯到零碎的音频输入(扬声器、耳机)。
VideoOutput显示视频内容。
MediaRecorder记录来自 CaptureSession 的音频/视频。
ImageCapture从相机中捕获静止图像。
Video将视频播放性能增加到场景中, 应用 MediaPlayer 和 VideoOutput 类型来提供视频播放性能。

想要实现视频客户端,这里只需应用 VideoOutputMediaPlayer 即可。

个别本地播放的简略应用如下:

 Rectangle {     width: 800     height: 600     color: "black"     MediaPlayer {         id: player         source: "file://video.webm"         videoOutput: videoOutput     }     VideoOutput {         id: videoOutput         anchors.fill: parent     } }

然而这种形式依赖 MediaPlayer,而 MediaPlayer 依赖零碎 ( 本机平台 ) 提供的编解码器,成果不佳且没有扩展性,因而咱们采纳SkeyePlayerPro 做为后端播放器。

对于SkeyePlayerPro

       是视开科技开发和保护的全功能的流媒体播放器,反对 RTSP、RTMP、HTTP、HLS、UDP、RTP、File 等多种流媒体协定播放、反对本地文件播放,反对本地抓拍、本地录像、播放旋转、多屏播放、倍数播放等多种性能个性,外围基于 FFmpeg,稳固、高效、牢靠、可控,反对 Windows、Android、iOS 等多个平台,目前在多家教育、安防、行业型公司,都失去的利用,广受好评!

  • 反对高效 4K / 8K 解码。
  • 反对 CPU 软解 / GPU 硬解。
  • 反对视频如 H.264,H.265,MPEG4,MJPEG。
  • API 简略好用且易于集成。

Qt 中集成相当容易,.pro 退出上面命令即可:

#SkeyePlayerPro相干    LIBS += -L$$PWD/lib/Player \            -llibSkeyePlayer \            -llibSkeyePlayerPro    INCLUDEPATH += $$PWD/lib/Player/Src \                   $$PWD/lib/SkeyePlayer

另一方面,想要在 QML 中播放视频咱们须要本人实现一个提供视频帧的 QML 接口类,有两种办法:

  • 提供 QMediaObject 派生类属性,该属性须要具备可用的 QVideoRenderControl ,相似于上面:
class MyMediaPlayer : QObject {public:      QMediaObject *mediaObject();};
  • 基于 QObject 的类提供可写 videoSurface 属性,能够承受基于 QAbstractVideoSurface 的类,而后传递本人的 QVideoFrame 即可,这也正是我应用的办法:
class VideoFrameProvider : public QObject{    Q_OBJECT        Q_PROPERTY(QAbstractVideoSurface *videoSurface READ videoSurface WRITE setVideoSurface)    Q_PROPERTY(QString videoUrl READ videoUrl WRITE setVideoUrl NOTIFY videoUrlChanged)    public:    VideoFrameProvider(QObject *parent = nullptr);    ~VideoFrameProvider();    QAbstractVideoSurface *videoSurface();    void setVideoSurface(QAbstractVideoSurface *surface);    QString videoUrl() const;    void setVideoUrl(const QString &url);        void setFormat(int width, int heigth, QVideoFrame::PixelFormat pixFormat);    signals:    void newVideoFrame(const char *frame);        void videoUrlChanged();    private slots:    void onNewVideoFrameReceived(const char *frame);    private:    //SkeyePlayerPro提供的回调    static int VideoFrameProvider::playCallback(SKEYE_CALLBACK_TYPE_ENUM callbackType, int channelId, void *userPtr, int mediaType, char *buf, SKEYE_FRAME_INFO *frameInfo);        QAbstractVideoSurface *m_surface = nullptr;    QVideoSurfaceFormat m_format;    QString m_videoUrl;    bool m_initFormat = false;}

要害实现,这里省略了一些 SkeyePlayerPro 的初始化和回调等等设置:

VideoFrameProvider::VideoFrameProvider(QObject *parent)    : QObject(parent){    connect(this, &VideoFrameProvider::newVideoFrame, this, &VideoFrameProvider::onNewVideoFrameReceived, Qt::QueuedConnection);}QAbstractVideoSurface *VideoFrameProvider::videoSurface(){    return m_surface;}void VideoFrameProvider::setVideoSurface(QAbstractVideoSurface *surface){    if (m_surface && m_surface != surface && m_surface->isActive()) {        m_surface->stop();    }    m_surface = surface;    if (m_surface && m_format.isValid()) {        m_format = m_surface->nearestFormat(m_format);        m_surface->start(m_format);    }}QString VideoFrameProvider::videoUrl() const{    return m_videoUrl;}void VideoFrameProvider::setVideoUrl(const QString &url){    if (m_videoUrl != url) {        m_videoUrl = url;        emit videoUrlChanged();    }}void VideoFrameProvider::setFormat(int width, int heigth, QVideoFrame::PixelFormat pixFormat){    QVideoSurfaceFormat format(QSize(width, heigth), pixFormat);    m_format = format;    if (m_surface) {        if (m_surface->isActive()) {            m_surface->stop();        }        m_format = m_surface->nearestFormat(format);        m_surface->start(m_format);    }}void VideoFrameProvider::onNewVideoFrameReceived(const char *frame){    int size = 0;    int width = m_format.frameWidth();    int height = m_format.frameHeight();    if (m_format.pixelFormat() == QVideoFrame::Format_YUV420P) {        size = width * height * 3 / 2;    }    QVideoFrame videoFrame(size, QSize(width, height), width, m_format.pixelFormat());    if (videoFrame.map(QAbstractVideoBuffer::WriteOnly)) {        memmove(videoFrame.bits(), frame, size);        videoFrame.unmap();    }    if (m_surface && m_surface->isActive()) {        if (!m_surface->present(videoFrame)) {            qDebug() << "VideoFrameProvider Suface Error:" << m_surface->error();        }    }}int VideoFrameProvider::playCallback(SKEYE_CALLBACK_TYPE_ENUM callbackType, int channelId, void *userPtr, int mediaType, char *buf, SKEYE_FRAME_INFO *frameInfo){    Q_UNUSED(channelId);    VideoFrameProvider *_this = reinterpret_cast<VideoFrameProvider *>(userPtr);    if (callbackType == SKEYE_TYPE_DECODE_DATA && mediaType == MEDIA_TYPE_VIDEO) {        auto frameWidth = frameInfo->width ;        auto frameHeight = frameInfo->height;        if (buf) {            if (!_this->m_initFormat) {                _this->setFormat(frameWidth, frameHeight, QVideoFrame::Format_YUV420P);                _this->m_initFormat = true;            }            emit _this->newVideoFrame(buf);        }    }    return 0;}

最初将下面的 MediaPlayer 替换为 VideoProvider 即可:

 Rectangle {     width: 800     height: 600     color: "black"     VideoFrameProvider {          id: provider         source: "rtsp://192.168.0.33:8554/channel=1"     }     VideoOutput {         id: videoOutput         anchors.fill: parent         source: provider     } }

对于SkeyeARS

SkeyeARS全景AR加强监视系统, 是视开科技开发的一款基于宽场景多路视频无缝拼接、视频实时加强、监督指标加强显示、指标主动跟踪、视频存储回放、近程数据传输和多通道全景视频同步显示等性能的综合视频AR加强监视系统,广泛应用于智慧交通、智慧城市、智慧机场等大场景智能监控畛域。

具体阐明:http://www.openskeye.cn/web/product/ars