乐趣区

关于图像识别:Qt-Qml-开发超高清-4K8K-视频直播视频客户端

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

退出移动版