Qt Qml 中提供了丰盛的多媒体相干的模块:
类型 | 形容 |
---|---|
MediaPlayer |
为场景增加音频 / 视频播放性能。 |
CaptureSession |
创立一个用于捕捉音频 / 视频的会话。 |
Camera |
拜访连贯到零碎的相机。 |
AudioInput |
拜访连贯到零碎的音频输出。 |
AudioOutput |
拜访连贯到零碎的音频输入(扬声器、耳机)。 |
VideoOutput |
显示视频内容。 |
MediaRecorder |
记录来自 CaptureSession 的音频 / 视频。 |
ImageCapture |
从相机中捕获静止图像。 |
Video |
将视频播放性能增加到场景中,应用 MediaPlayer 和 VideoOutput 类型来提供视频播放性能。 |
想要实现视频客户端,这里只需应用 VideoOutput
和 MediaPlayer
即可。
个别本地播放的简略应用如下:
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