整个onvif模块大部分的功能都有了以后,除了在demo上点点按钮可以执行获取结果显示外,最终还是要应用到视频监控中,在按钮上点点和系统中后台自动运行是两码事,比如onvif校时和事件订阅,不会说是傻到在监控系统界面上提供按钮给用户点击才去执行,最多做的应该是系统设置中提供两个开关比如自动校时、事件订阅,可以方便的开启这几个功能。开启以后等监控系统启动后自动去处理,比如挨个对摄像机进行校时处理以及订阅事件,为了能够做到添加摄像机后自动立即应用,特意改成了在打开摄像机视频画面的时候,主动去实例化DeviceOnvif类(每个摄像机都对应一个实例)
最开始的做法是采用定时器去处理要指定的指令队列,后面发现速度不好控制,毕竟网络请求受网速和网络环境的影响,有时候100毫秒就执行完成了,有时候又需要300毫秒不等,尽管网络请求的时候已经设置了超时时间(这个时间一般设置成2-3秒,保证请求有足够的时候返回),这个时间有点大,如果按照这个网络请求超时时间来设定定时器,设备数量很多的时候太慢了,监控系统一般几十个设备是有的,这蜗牛一样的速度要处理到何年马月,而且每个摄像机有多个指令需要处理比如自动校时、事件订阅等。
那有没有一种机制可以尽最快的速度排队处理呢,答案是当然,这不就是线程擅长干的事情吗,使劲的干,休息多久自由msleep控制即可,网络环境好的情况下,20个设备的指令基本上在1s内完成的,这就能够满足用户的需求,毕竟用户打开软件后,大概率不想等待太长时间,就像能够看到所有摄像机时间自动校准好了,搞个摄像机报警也能立即通过onvif协议上报,该处理的都尽快处理完了。
QNetworkAccessManager类如果一开始不是在线程中new出来的,会提示不能在其他线程执行,这就需要在线程的run函数中调用QMetaObject::invokeMethod来执行对应的处理,一个万能的处理方法就是将需要执行的全部放在work函数中,搞个iswork标志位,进入该开始的时候将标志位iswork=true,处理结束后iswork=false,在run中先判断标志位是否为假,为假表示当前不在工作,则去调用work函数处理。这就规避了在线程中执行其他线程类对象函数的错误提示。
基本的处理思路
onvif主要的功能
onvif的处理流程
#include "onvifthread.h"
QScopedPointer<OnvifThread> OnvifThread::self;
OnvifThread *OnvifThread::Instance()
{
if (self.isNull()) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (self.isNull()) {
self.reset(new OnvifThread);
}
}
return self.data();
}
OnvifThread::OnvifThread(QObject *parent) : QThread(parent)
{
stopped = false;
working = false;
}
OnvifThread::~OnvifThread()
{
this->stop();
this->wait();
}
void OnvifThread::run()
{
while (!stopped) {
//先判断是否在工作
if (!working) {
//异步执行
QMetaObject::invokeMethod(this, "work");
}
//可以自行调整休息的时间
msleep(100);
}
stopped = false;
working = false;
}
void OnvifThread::stop()
{
stopped = true;
}
void OnvifThread::work()
{
//设置正在工作标志位
working = true;
if (devices.count() > 0) {
mutex.lock();
OnvifDevice *device = devices.takeFirst();
QString cmd = cmds.takeFirst();
QVariant data = datas.takeFirst();
mutex.unlock();
QList<QVariant> list = data.toList();
QString url = device->getOnvifAddr();
QString ip = OnvifHelper::getIP(url);
if (cmd == "remove") {
bool ok = OnvifHelper::onvifDevices.removeOne(device);
device->deleteLater();
qDebug() << TIMEMS << "执行移除对象" << ip << ok;
} else if (cmd == "systemReboot") {
QString result = device->systemReboot();
qDebug() << TIMEMS << "远程重启设备" << ip << result;
} else if (cmd == "setDateTime") {
//两种方式都设置下 一种是直接设置日期时间字符串 一种是触发NTP同步
bool ok = device->setDateTime(QDateTime::currentDateTime().toUTC());
//bool ok = device->setDateTime(QDateTime::currentDateTime().toUTC(), true);
qDebug() << TIMEMS << "设置设备时间" << ip << ok;
} else if (cmd == "getEvent") {
QString result = device->getEvent();
qDebug() << TIMEMS << "订阅报警事件" << ip << result;
} else if (cmd == "getProfile") {
QString result = device->getProfile();
qDebug() << TIMEMS << "获取配置文件" << ip << result;
} else if (cmd == "snapImage") {
QImage image = device->snapImage(device->getProfile());
emit receiveImage(url, image);
qDebug() << TIMEMS << "手动抓拍图片" << ip << (!image.isNull());
} else if (cmd == "getVideoSource") {
QString result = device->getVideoSource();
emit receiveResult(url, cmd, result);
qDebug() << TIMEMS << "获取视频参数" << ip << result;
} else if (cmd == "getImageSetting") {
int brightness, colorSaturation, contrast;
QString result = device->getImageSetting(brightness, colorSaturation, contrast);
QVariant data = (QList<QVariant>() << brightness << colorSaturation << contrast);
emit receiveResult(url, cmd, data);
qDebug() << TIMEMS << "获取图片参数" << ip << result;
} else if (cmd == "setImageSetting") {
int brightness = list.at(0).toInt();
int colorSaturation = list.at(1).toInt();
int contrast = list.at(2).toInt();
bool ok = device->setImageSetting(brightness, colorSaturation, contrast);
qDebug() << TIMEMS << "设置图片参数" << ip << ok;
}
}
working = false;
}
void OnvifThread::append(const OnvifDeviceUser &deviceUser, const QString &cmd, const QVariant &data)
{
mutex.lock();
//先解绑以及重新绑定事件
OnvifDevice *device = OnvifHelper::getOnvifDevice(deviceUser);
disconnect(device, SIGNAL(receiveEvent(QString, OnvifEventInfo)), this, SIGNAL(receiveEvent(QString, OnvifEventInfo)));
connect(device, SIGNAL(receiveEvent(QString, OnvifEventInfo)), this, SIGNAL(receiveEvent(QString, OnvifEventInfo)));
//添加到队列等待处理
devices << device;
cmds << cmd;
datas << data;
mutex.unlock();
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。