Skip to content

Commit 55ac785

Browse files
Merge branch 'ai_server' of github.com:connortechnology/zoneminder into ai_server
2 parents e21f1dd + 108380a commit 55ac785

File tree

11 files changed

+228
-61
lines changed

11 files changed

+228
-61
lines changed

misc/zoneminder.gortc.service

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[Unit]
2+
Description=go2rtc for use with ZoneMinder
3+
After=network.target
4+
5+
[Service]
6+
# Does not have to be www-data. Could also be an unprivileged user
7+
User=root
8+
Type=simple
9+
#Where ever you put go2rtc
10+
WorkingDirectory=/opt/go2rtc
11+
# This first entry will get overwritten when you add streams and can get wiped out. Place the permanent config in the second file
12+
ExecStart=/opt/go2rtc/go2rtc_linux_arm64 -c go2rtc.yaml -c /etc/zm/go2rtc.yaml
13+
Restart=always
14+
RuntimeMaxSec=1d
15+
RestartSec=10
16+
Environment=TZ=:/etc/localtime
17+
TimeoutSec=600
18+
19+
[Install]
20+
WantedBy=multi-user.target
21+

scripts/ZoneMinder/lib/ZoneMinder/Event.pm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ sub delete {
419419
$ZoneMinder::Database::dbh->commit() if ! $in_transaction;
420420

421421
my $storage = $event->Storage();
422-
$storage->save({DiskSpace=>$storage->DiskSpace()-$event->DiskSpace()}) if $event->DiskSpace();
422+
$storage->save({DiskSpace=>$storage->DiskSpace()-$event->DiskSpace()}) if $event->DiskSpace() and $storage->Id();
423423
}
424424

425425
if ( ( $in_zmaudit or (!$Config{ZM_OPT_FAST_DELETE})) and $event->Storage()->DoDelete() ) {
@@ -782,8 +782,8 @@ sub MoveTo {
782782
$ZoneMinder::Database::dbh->commit() if !$was_in_transaction;
783783

784784
# Update storage diskspace. The triggers no longer do this. This is ... less important so do it outside the transaction
785-
$OldStorage->save({DiskSpace => $OldStorage->DiskSpace()-$old_diskspace}) if $old_diskspace;
786-
$NewStorage->save({DiskSpace => $NewStorage->DiskSpace()+$new_diskspace}) if $new_diskspace;
785+
$OldStorage->save({DiskSpace => $OldStorage->DiskSpace()-$old_diskspace}) if $old_diskspace and $OldStorage->Id();
786+
$NewStorage->save({DiskSpace => $NewStorage->DiskSpace()+$new_diskspace}) if $new_diskspace and $NewStorage->Id();
787787

788788
$self->delete_files($OldStorage);
789789
return $error;

src/zm_ai_server.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ void AIThread::Run() {
473473
packet->image_index = image_index;
474474

475475
{
476-
std::unique_lock<std::mutex> lck(mutex_);
476+
std::lock_guard<std::mutex> lck(mutex_);
477477
send_queue.push_back(packet);
478478
}
479479
Debug(4, "send queue size %zu", send_queue.size());
@@ -508,8 +508,7 @@ void AIThread::Run() {
508508
} // end if have a new image
509509
} // end while !zm_terminate
510510
if (monitor_->ShmValid()) shared_data->analysis_image_count = 0;
511-
} // end SpeedAIDetect
512-
511+
} // end void AIThread::Run()
513512

514513
int draw_boxes(Image *in_image, Image *out_image, const nlohmann::json &coco_object, int font_size, int line_width=2) {
515514
out_image->Assign(*in_image);

src/zm_db.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ MYSQL_RES *zmDbFetch(const std::string &query) {
138138
}
139139

140140

141+
Debug(3, "Doing Fetch %s", query.c_str());
141142
int rc = mysql_query(&dbconn, query.c_str());
142143
if (rc) {
143144
std::string reason = mysql_error(&dbconn); // store for later because it will get clobbered by second attempt

src/zm_image.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5913,13 +5913,13 @@ int Image::draw_boxes(
59135913
if (coco_object.size()) {
59145914
for (auto it = coco_object.begin(); it != coco_object.end(); ++it) {
59155915
nlohmann::json detection = *it;
5916-
Debug(1, "CURL detections detection %s", detection.dump().c_str());
5917-
nlohmann::json bbox = detection["box"];
5916+
Debug(1, "detections detection %s", detection.dump().c_str());
5917+
nlohmann::json bbox = detection["box"] == nullptr ? detection["bbox"] : detection["box"];
59185918
if ( bbox == nullptr) {
59195919
Debug(1, "Null box");
59205920
continue;
59215921
}
5922-
Debug(1, "CURL detections box %s", bbox.dump().c_str());
5922+
Debug(1, "detections box %s", bbox.dump().c_str());
59235923
if ( bbox == nullptr) {
59245924
Debug(1, "Null box");
59255925
continue;
@@ -5931,7 +5931,7 @@ int Image::draw_boxes(
59315931
int x2 = bbox[2];
59325932
int y2 = bbox[3];
59335933
std::string coco_class = detection["class"];
5934-
float score = detection["confidence"];
5934+
float score = detection["confidence"] != nullptr ? detection["confidence"] : detection["score"];
59355935
std::string annotation = stringtf("%s %d%%", coco_class.c_str(), static_cast<int>(100*score));
59365936

59375937
#if 0

src/zm_monitor.cpp

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
#include "zm_utils.h"
3737
#include "zm_zone.h"
3838

39+
#define DEBUG_TIMING 1
40+
#define AI_IN_DECODE 0
41+
3942
#if ZM_HAS_V4L2
4043
#include "zm_local_camera.h"
4144
#endif // ZM_HAS_V4L2
@@ -302,6 +305,10 @@ Monitor::Monitor() :
302305
#if HAVE_QUADRA
303306
//quadra(nullptr),
304307
quadra_yolo(nullptr),
308+
#endif
309+
#if HAVE_MX_ACCL
310+
mx_accl(nullptr),
311+
mx_accl_job(nullptr),
305312
#endif
306313
//nlohmann::json last_detections;
307314
last_detection_count(0),
@@ -404,6 +411,8 @@ void Monitor::Load(MYSQL_ROW dbrow, bool load_zones = true, Purpose p = QUERY) {
404411
objectdetection = OBJECT_DETECTION_NONE;
405412
} else if (od == "memx") {
406413
objectdetection = OBJECT_DETECTION_MEMX;
414+
} else if (od == "mx_accl") {
415+
objectdetection = OBJECT_DETECTION_MX_ACCL;
407416
} else if (od == "quadra") {
408417
objectdetection = OBJECT_DETECTION_QUADRA;
409418
} else if (od == "speedai") {
@@ -2140,10 +2149,17 @@ int Monitor::Analyse() {
21402149
packet->ai_image = new Image(*analysis_image_buffer[packet->image_index % image_buffer_count]);
21412150
}
21422151
}
2152+
#if !AI_IN_DECODE
21432153
#if HAVE_QUADRA
2144-
else {
2145-
//std::pair<int, std::string> results = Analyse_Quadra(packet);
2154+
else if (objectdetection == OBJECT_DETECTION_QUADRA) {
2155+
std::pair<int, std::string> results = Analyse_Quadra(packet);
2156+
}
2157+
#endif
2158+
#if HAVE_MX_ACCL_H
2159+
else if (objectdetection == OBJECT_DETECTION_MX_ACCL) {
2160+
std::pair<int, std::string> results = Analyse_MxAccl(packet);
21462161
}
2162+
#endif
21472163
#endif
21482164
if (objectdetection == OBJECT_DETECTION_UVICORN) {
21492165
std::pair<int, std::string> results = Analyse_UVICORN(packet);
@@ -2423,7 +2439,11 @@ int Monitor::Analyse() {
24232439
packetqueue.clearPackets(packet);
24242440

24252441
unsigned int index = (shared_data->last_analysis_index+1) % image_buffer_count;
2426-
if (objectdetection == OBJECT_DETECTION_QUADRA || objectdetection == OBJECT_DETECTION_UVICORN) {
2442+
if (
2443+
objectdetection == OBJECT_DETECTION_QUADRA
2444+
|| objectdetection == OBJECT_DETECTION_MX_ACCL
2445+
|| objectdetection == OBJECT_DETECTION_UVICORN
2446+
) {
24272447
// Only do these if it's a video packet.
24282448
if (packet->ai_frame) {
24292449
analysis_image_buffer[index]->AVPixFormat(static_cast<AVPixelFormat>(packet->ai_frame->format));
@@ -2477,6 +2497,8 @@ int Monitor::Analyse() {
24772497
shared_data->last_analysis_index = index;
24782498
shared_data->last_read_index = index;
24792499
shared_data->analysis_image_count = analysis_image_count;
2500+
} else {
2501+
Warning("Unknown value for Object_Detection");
24802502
}
24812503
} else {
24822504
Debug(3, "Not video, not clearing packets");
@@ -2512,6 +2534,67 @@ int Monitor::Analyse() {
25122534
return 1;
25132535
} // end Monitor::Analyse
25142536

2537+
#if HAVE_MX_ACCL_H
2538+
std::pair<int, std::string> Monitor::Analyse_MxAccl(std::shared_ptr<ZMPacket> packet) {
2539+
int score = 0;
2540+
std::string cause;
2541+
2542+
if (packet->needs_hw_transfer(mVideoCodecContext))
2543+
packet->get_hwframe(mVideoCodecContext);
2544+
AVFrame *frame = packet->in_frame.get();
2545+
2546+
if (!mx_accl and mVideoCodecContext) {
2547+
mx_accl = new MxAccl();
2548+
if (!mx_accl->setup( "", (staticConfig.DIR_MODELS+"/"+objectdetection_model))) {
2549+
Warning("Failed setting up Mx_Accl");
2550+
delete mx_accl;
2551+
mx_accl = nullptr;
2552+
return std::make_pair(0, "");
2553+
}
2554+
mx_accl_job = mx_accl->get_job();
2555+
}
2556+
2557+
if (frame) {
2558+
if (!(shared_data->analysis_image_count % (motion_frame_skip+1))) {
2559+
#if DEBUG_TIMING
2560+
SystemTimePoint starttime = std::chrono::system_clock::now();
2561+
#endif
2562+
int ret = packet->image ? mx_accl->send_image(mx_accl_job, packet->image) : mx_accl->send_frame(mx_accl_job, frame);
2563+
if (ret <= 0) {
2564+
Debug(1, "Can't send_packet %d", packet->image_index);
2565+
return std::make_pair(ret, cause);
2566+
}
2567+
#if DEBUG_TIMING
2568+
SystemTimePoint endtime = std::chrono::system_clock::now();
2569+
if (endtime - starttime > Seconds(1)) {
2570+
Warning("AI is to slow: %.2f seconds", FPSeconds(endtime - starttime).count());
2571+
} else {
2572+
Debug(1, "AI took: %.2f seconds", FPSeconds(endtime - starttime).count());
2573+
}
2574+
#endif
2575+
last_detection_count = 2;
2576+
const nlohmann::json detections = mx_accl->receive_detections(mx_accl_job, objectdetection_object_threshold);
2577+
if (detections.size()) {
2578+
Image *ai_image = new Image(packet->in_frame.get(), packet->in_frame->width, packet->in_frame->height); //copies
2579+
ai_image->draw_boxes(detections, LabelSize(), LabelSize());
2580+
packet->ai_image = ai_image;
2581+
// Populate ai_frame as well
2582+
packet->ai_frame = av_frame_ptr(av_frame_alloc());
2583+
ai_image->PopulateFrame(packet->ai_frame.get());
2584+
packet->detections = detections;
2585+
}
2586+
} else { // skipping
2587+
if (last_detection_count>0) {
2588+
last_detection_count --;
2589+
//TODO last_detection shouldn't be AI specific
2590+
//quadra_yolo->draw_last_roi(packet);
2591+
}
2592+
} // end if skip_frame
2593+
} // end if has input_frame/hw_frame
2594+
return std::make_pair(score, cause);
2595+
} // end Monitor::Analyse_MxAccl(Packet)
2596+
#endif
2597+
25152598
#if HAVE_QUADRA
25162599
std::pair<int, std::string> Monitor::Analyse_Quadra(std::shared_ptr<ZMPacket> packet) {
25172600
int score = 0;
@@ -3581,14 +3664,18 @@ int Monitor::Decode() {
35813664
Debug(1, "Assigning %s for index %d to %s", packet->image->toString().c_str(), index, image_buffer[index]->toString().c_str());
35823665
image_buffer[index]->Assign(*(packet->image));
35833666
} else if (packet->in_frame) {
3584-
#if HAVE_QUADRA
3585-
//if (!quadra_yolo)
3586-
#endif
35873667
{
3668+
#if AI_IN_DECODE
3669+
35883670
#if HAVE_QUADRA
35893671
if (objectdetection == OBJECT_DETECTION_QUADRA) {
35903672
std::pair<int, std::string> results = Analyse_Quadra(packet);
35913673
}
3674+
#endif
3675+
#if HAVE_MX_ACCL_H
3676+
if (objectdetection == OBJECT_DETECTION_MX_ACCL) {
3677+
std::pair<int, std::string> results = Analyse_MxAccl(packet);
3678+
}
35923679
#endif
35933680
if (packet->ai_frame) {
35943681
Debug(1, "Assigning ai_frame for index %d", index);
@@ -3604,6 +3691,8 @@ int Monitor::Decode() {
36043691
image_buffer[index]->AVPixFormat(image_pixelformats[index] = static_cast<AVPixelFormat>(packet->in_frame->format));
36053692
image_buffer[index]->Assign(packet->in_frame.get());
36063693
}
3694+
#endif // AI_IN_DECODE
3695+
36073696
//if (packet->detections.size())
36083697
//zm_terminate = true;
36093698
if (objectdetection == OBJECT_DETECTION_SPEEDAI) {

src/zm_monitor.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ extern "C" {
5757
}
5858
#include "zm_netint_yolo.h"
5959
#endif
60+
#if HAVE_MX_ACCL_H
61+
#include "zm_mx_accl.h"
62+
#endif
6063

6164
class Group;
6265
class MonitorLinkExpression;
@@ -100,6 +103,7 @@ class Monitor : public std::enable_shared_from_this<Monitor> {
100103
OBJECT_DETECTION_SPEEDAI,
101104
OBJECT_DETECTION_UVICORN,
102105
OBJECT_DETECTION_MEMX,
106+
OBJECT_DETECTION_MX_ACCL,
103107
} ObjectDetectionOption;
104108

105109
typedef enum {
@@ -789,6 +793,10 @@ class Monitor : public std::enable_shared_from_this<Monitor> {
789793
//Quadra_Yolo *quadra;
790794
Quadra_Yolo *quadra_yolo;
791795
std::mutex quadra_mutex;
796+
#endif
797+
#if HAVE_MX_ACCL_H
798+
MxAccl *mx_accl;
799+
MxAccl::Job *mx_accl_job;
792800
#endif
793801
nlohmann::json last_detections;
794802
int last_detection_count;
@@ -1077,6 +1085,9 @@ class Monitor : public std::enable_shared_from_this<Monitor> {
10771085
bool CheckSignal( const Image *image );
10781086
int Analyse();
10791087
std::pair<int, std::string> Analyse_Quadra(std::shared_ptr<ZMPacket> packet);
1088+
#if HAVE_MX_ACCL_H
1089+
std::pair<int, std::string> Analyse_MxAccl(std::shared_ptr<ZMPacket> packet);
1090+
#endif
10801091
struct transfer
10811092
{
10821093
uint8_t *buf;

0 commit comments

Comments
 (0)