Skip to content
项目
群组
代码片段
帮助
正在加载...
登录
切换导航
E
evcamera
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
OpsTeam
evcamera
Commits
61621d77
提交
61621d77
authored
5月 18, 2020
作者:
blu
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
refactor, bugfix, ptz implementation and more
上级
b92bb722
隐藏空白字符变更
内嵌
并排
正在显示
20 个修改的文件
包含
1012 行增加
和
263 行删除
+1012
-263
settings.json
.vscode/settings.json
+3
-1
MQTT.md
docs/MQTT.md
+82
-39
CMakeCache.txt
hi3518/CMakeCache.txt
+3
-0
CMakeLists.txt
hi3518/CMakeLists.txt
+2
-1
diff.json
hi3518/diff.json
+58
-0
evutils.cc
hi3518/evutils.cc
+119
-32
evutils.hpp
hi3518/evutils.hpp
+38
-9
internal_types.h
hi3518/internal_types.h
+39
-0
main.cc
hi3518/main.cc
+314
-122
main.mqtt.cc
hi3518/main.mqtt.cc
+4
-4
motion.cc
hi3518/motion.cc
+10
-3
motion.h
hi3518/motion.h
+5
-1
ptz.cc
hi3518/ptz.cc
+190
-0
ptz.h
hi3518/ptz.h
+38
-0
raw_tcp.cc
hi3518/raw_tcp.cc
+2
-2
smart.cc
hi3518/smart.cc
+66
-32
smart.h
hi3518/smart.h
+3
-1
evpacket.h
include/evpacket.h
+3
-0
mqtt_helper.hpp
include/mqtt_helper.hpp
+14
-2
videogateway.cc
server/videogateway.cc
+19
-14
没有找到文件。
.vscode/settings.json
浏览文件 @
61621d77
...
...
@@ -93,5 +93,6 @@
"forward_list"
:
"cpp"
,
"future"
:
"cpp"
,
"maque_mem.h"
:
"c"
}
},
"C_Cpp.errorSquiggles"
:
"Disabled"
}
\ No newline at end of file
docs/MQTT.md
浏览文件 @
61621d77
...
...
@@ -140,45 +140,40 @@ payload:
```
json
{
"time"
:
ts
,
"rid"
:
"<request_rid>"
,
"type"
:
"response"
,
"cata"
:
"config"
,
"sn"
:
"A000000Z"
,
"code"
:
0
,
"msg"
:
"OK"
,
"data"
:
{
"vgw"
:
"evcloudsvc.ilabservice.cloud:7123"
,
"mqtt"
:
"admin:password@evcloudsvc.ilabservice.cloud:11883"
,
"upload"
:
"evcloudsvc.ilabservice.cloud:10009"
,
"features"
:
{
"motion"
:
{
"enable"
:
1
,
"level"
:
3
,
//
1
-
6
"region"
:{
"minX"
:
0.1
,
"minY"
:
0.1
,
"maxX"
:
0.9
,
"maxY"
:
0.9
}
},
"record"
:{
"enable"
:
1
,
"interval"
:
30
,
//
seconds
of
one
slice
"duration"
:
24
//
hours
of
local
recording
},
"ai"
:{
"enable"
:
1
,
"face_thresh"
:
0.75
,
//
0
-
1
"human_thresh"
:
0.63
,
//
0
-
1
"region"
:{
"minX"
:
0.1
,
"minY"
:
0.1
,
"maxX"
:
0.9
,
"maxY"
:
0.9
}
"time"
:
1567669674
,
"cmd"
:
"config"
,
"rid"
:
"001231554A20"
,
"data"
:{
"sn"
:
"001231554A20"
,
"vgw"
:
"192.168.55.104:7123"
,
"mqtt"
:
"admin:vJ3zHqWrHbrqxVMT@evcloudsvc.ilabservice.cloud:11883"
,
"upload"
:
"evcloudsvc.ilabservice.cloud:10009"
,
"features"
:{
"push"
:
"1"
,
"motion"
:{
"enabled"
:
0
,
"region"
:{
"maxX"
:
0.7
,
"maxY"
:
0.7
,
"minX"
:
0.3
,
"minY"
:
0.3
},
"level"
:
4
},
"recordLen"
:
30
,
"ai"
:{
"enabled"
:
1
,
"faceThresh"
:
0.65
,
"humanThresh"
:
0.63
,
"region"
:{
"maxX"
:
1
,
"maxY"
:
1
,
"minX"
:
0
,
"minY"
:
0
}
}
}
}
}
}
```
...
...
@@ -196,7 +191,6 @@ REQUEST_VIDEOS_T
"cmd"
:
"upload_video"
,
"rid"
:
"<random_str>"
,
"data"
:
{
{
"start"
:
1567669674
,
"end"
:
1567668000
,
"type"
:
6
...
...
@@ -223,3 +217,52 @@ REQUEST_VIDEOS_T
}
```
### Report: AI Image
```
json
{
"category"
:
"ai_image"
,
"code"
:
0
,
"data"
:{
"data"
:
"<base64_string>"
,
"encoding"
:
"base64"
,
"format"
:
"JPG"
,
"type"
:
"image"
},
"msg"
:
"new ai capture: pic, idx = 0, toltal = 1"
,
"rid"
:
""
,
"sn"
:
"EVC001231554A20"
,
"time"
:
1589537073532
,
"type"
:
"report"
}
```
### Request: status
```
json
{
"time"
:
1567669674
,
"cmd"
:
"status"
,
"rid"
:
"001231554A20"
,
"data"
:
{}
}
```
### Request PTZ
```
json
{
"time"
:
1567669674
,
"cmd"
:
"ptz"
,
"rid"
:
"001231554A20"
,
"data"
:{
"action"
:
"left"
,
"degree"
:
10
}
}
```
hi3518/CMakeCache.txt
浏览文件 @
61621d77
...
...
@@ -200,6 +200,9 @@ mqtthelper_LIB_DEPENDS:STATIC=
//Dependencies for target
ntp_LIB_DEPENDS:STATIC=
//Dependencies for target
ptz_LIB_DEPENDS:STATIC=
//Dependencies for target
smart_LIB_DEPENDS:STATIC=
...
...
hi3518/CMakeLists.txt
浏览文件 @
61621d77
...
...
@@ -24,7 +24,8 @@ add_library(evutils STATIC evutils.cc)
add_library
(
mqtthelper STATIC ../include/mqtt_helper.cc
)
add_library
(
motion STATIC motion.cc
)
add_library
(
smart STATIC smart.cc
)
add_library
(
ptz STATIC ptz.cc
)
#add_library(util STATIC utils.cpp)
add_executable
(
evcamera main.cc
)
target_link_libraries
(
evcamera PUBLIC ntp paho-mqtt3a mqtthelper tcp_client evutils smart motion zmq
${
COMMON_LIBS
}
${
XM_LIBS
}
)
target_link_libraries
(
evcamera PUBLIC ntp paho-mqtt3a mqtthelper tcp_client evutils smart motion
ptz
zmq
${
COMMON_LIBS
}
${
XM_LIBS
}
)
hi3518/diff.json
0 → 100644
浏览文件 @
61621d77
[
{
"op"
:
"replace"
,
"path"
:
"/features/ai/faceThresh"
,
"value"
:
0.65
},
{
"op"
:
"replace"
,
"path"
:
"/features/motion/enabled"
,
"value"
:
0
},
{
"op"
:
"replace"
,
"path"
:
"/features/motion/level"
,
"value"
:
4
},
{
"op"
:
"replace"
,
"path"
:
"/features/motion/region/maxX"
,
"value"
:
0.7
},
{
"op"
:
"replace"
,
"path"
:
"/features/motion/region/maxY"
,
"value"
:
0.7
},
{
"op"
:
"replace"
,
"path"
:
"/features/motion/region/minX"
,
"value"
:
0.3
},
{
"op"
:
"replace"
,
"path"
:
"/features/motion/region/minY"
,
"value"
:
0.3
},
{
"op"
:
"replace"
,
"path"
:
"/features/push"
,
"value"
:
1
},
{
"op"
:
"replace"
,
"path"
:
"/mqtt"
,
"value"
:
"admin:vJ3zHqWrHbrqxVMT@evcloudsvc.ilabservice.cloud:11883"
},
{
"op"
:
"replace"
,
"path"
:
"/vgw"
,
"value"
:
"192.168.55.104:7123"
},
{
"op"
:
"add"
,
"path"
:
"/sn"
,
"value"
:
"001231554A20"
}
]
\ No newline at end of file
hi3518/evutils.cc
浏览文件 @
61621d77
...
...
@@ -28,9 +28,14 @@ const string consts::kMsgCmdGetConfig = "get_config";
const
string
consts
::
kMsgCmdReboot
=
"reboot"
;
const
string
consts
::
kMsgCmdPtz
=
"ptz"
;
const
string
consts
::
kMsgType
=
"type"
;
const
string
consts
::
kMsgTypeImage
=
"image"
;
const
string
consts
::
kMsgEncode
=
"encoding"
;
const
string
consts
::
kMsgEncodeBase64
=
"base64"
;
const
string
consts
::
kMsgFormat
=
"format"
;
const
string
consts
::
kMsgFormatJpeg
=
"JPG"
;
const
string
consts
::
kMsgCata
=
"category"
;
const
string
consts
::
kMsgTypeReport
=
"report"
;
const
string
consts
::
kMsgTypeResponse
=
"response"
;
const
string
consts
::
kMsgTypeResponse
=
"response"
;
const
string
consts
::
kMsgTime
=
"time"
;
const
string
consts
::
kMsgData
=
"data"
;
const
string
consts
::
kMsgRid
=
"rid"
;
...
...
@@ -44,8 +49,11 @@ const string consts::sub_topic = "evcamera/v1.0/request/";
const
string
consts
::
pub_topic_response
=
"evcamera/v1.0/response/"
;
const
string
consts
::
pub_topic_report
=
"evcamera/v1.0/report"
;
const
string
consts
::
mqtt_url
=
"tcp://admin:vJ3zHqWrHbrqxVMT@evcloudsvc.ilabservice.cloud:11883"
;
const
string
consts
::
vgw_addr
=
"tcp://evcloudsvc.ilabservice.cloud:7123"
;
const
string
consts
::
upload_addr
=
"tcp://evcloudsvc.ilabservice.cloud:10009"
;
consts
&
consts
::
self
(){
consts
&
consts
::
self
()
{
static
consts
cons
;
return
cons
;
}
...
...
@@ -58,7 +66,7 @@ string msg_field(const json &msg, const string &field)
bool
is_sdcard_avail
(
char
*
path
)
{
char
p
[]
=
"/sys/block/mmcblk0/size"
;
if
(
path
==
nullptr
){
if
(
path
==
nullptr
)
{
path
=
p
;
}
std
::
ifstream
fsize
(
path
);
...
...
@@ -66,7 +74,8 @@ bool is_sdcard_avail(char *path)
return
(
fsize
>>
size
)
&&
(
size
>
0
);
}
json
make_default_config
(){
json
make_default_cloud_config
()
{
return
R"(
{
"vgw":"evcloudsvc.ilabservice.cloud:7123",
...
...
@@ -101,9 +110,22 @@ json make_default_config(){
)"
_json
;
}
void
get_mac_addr
(
char
*
buf
,
char
*
intf
){
json
make_default_sys_extra_config
()
{
return
R"(
{
"ptz":{
"x": 177.5,
"y": 0
}
}
)"
_json
;
}
void
get_mac_addr
(
char
*
buf
,
char
*
intf
)
{
char
p
[]
=
"/sys/class/net/eth0/address"
;
if
(
intf
==
nullptr
){
if
(
intf
==
nullptr
)
{
intf
=
p
;
}
...
...
@@ -111,8 +133,8 @@ void get_mac_addr(char *buf, char *intf){
string
s
;
fsize
>>
s
;
int
i
=
0
;
for
(
auto
&
k
:
s
){
if
(
k
!=
':'
){
for
(
auto
&
k
:
s
)
{
if
(
k
!=
':'
)
{
*
(
buf
+
i
++
)
=
::
toupper
(
k
);
}
}
...
...
@@ -121,26 +143,27 @@ void get_mac_addr(char *buf, char *intf){
bool
get_sdcard_megabytes
(
uint64_t
&
total
,
uint64_t
&
free
,
char
*
path
)
{
struct
statvfs
stat
;
char
p
[]
=
"/mnt/sd"
;
if
(
path
==
nullptr
)
{
path
=
p
;
}
if
(
statvfs
(
path
,
&
stat
)
!=
0
)
{
// error happens, just quits here
return
false
;
}
/// NOTES: avoid trucating errors
total
=
(
stat
.
f_blocks
/
1024.0
)
*
(
stat
.
f_bsize
/
1024.0
);
free
=
(
stat
.
f_bavail
/
1024.0
)
*
(
stat
.
f_bsize
/
1024.0
);
spdlog
::
info
(
"sd: {} {} {} {} {} {} {}"
,
stat
.
f_bsize
,
stat
.
f_blocks
,
stat
.
f_bavail
,
stat
.
f_bfree
,
stat
.
f_favail
,
stat
.
f_ffree
,
stat
.
f_frsize
);
return
true
;
struct
statvfs
stat
;
char
p
[]
=
"/mnt/sd"
;
if
(
path
==
nullptr
)
{
path
=
p
;
}
if
(
statvfs
(
path
,
&
stat
)
!=
0
)
{
// error happens, just quits here
return
false
;
}
/// NOTES: avoid trucating errors
total
=
(
stat
.
f_blocks
/
1024.0
)
*
(
stat
.
f_bsize
/
1024.0
);
free
=
(
stat
.
f_bavail
/
1024.0
)
*
(
stat
.
f_bsize
/
1024.0
);
spdlog
::
info
(
"sd: {} {} {} {} {} {} {}"
,
stat
.
f_bsize
,
stat
.
f_blocks
,
stat
.
f_bavail
,
stat
.
f_bfree
,
stat
.
f_favail
,
stat
.
f_ffree
,
stat
.
f_frsize
);
return
true
;
}
/// returns negtive for failure, otherwise success
int
setupDealer
(
void
**
ctx
,
void
**
s
,
string
ident
,
string
addr
,
int
sndQS
,
int
timeoutMs
)
{
int
setupDealer
(
void
**
ctx
,
void
**
s
,
string
ident
,
string
addr
,
int
sndQS
,
int
timeoutMs
)
{
int
ret
=
0
;
*
ctx
=
zmq_ctx_new
();
*
s
=
zmq_socket
(
*
ctx
,
ZMQ_DEALER
);
...
...
@@ -151,7 +174,7 @@ int setupDealer(void **ctx, void **s, string ident, string addr, int sndQS, int
zmq_setsockopt
(
*
s
,
ZMQ_TCP_KEEPALIVE_INTVL
,
&
ret
,
sizeof
(
ret
));
ret
=
2
;
zmq_setsockopt
(
*
s
,
ZMQ_TCP_KEEPALIVE_CNT
,
&
ret
,
sizeof
(
ret
));
if
(
sndQS
!=
0
){
if
(
sndQS
!=
0
)
{
zmq_setsockopt
(
*
s
,
ZMQ_SNDHWM
,
&
sndQS
,
sizeof
(
sndQS
));
}
if
(
timeoutMs
!=
0
)
{
...
...
@@ -160,13 +183,14 @@ int setupDealer(void **ctx, void **s, string ident, string addr, int sndQS, int
}
zmq_setsockopt
(
*
s
,
ZMQ_RCVTIMEO
,
&
timeoutMs
,
sizeof
(
timeoutMs
));
}
ret
=
zmq_setsockopt
(
*
s
,
ZMQ_IDENTITY
,
ident
.
c_str
(),
ident
.
size
());
if
(
ret
<
0
)
{
zmq_close
(
*
s
);
zmq_ctx_destroy
(
*
ctx
);
spdlog
::
debug
(
"{} failed setsockopts ZMQ_ROUTING_ID to {}: {}"
,
ident
,
addr
,
zmq_strerror
(
zmq_errno
()));
}
else
{
}
else
{
ret
=
zmq_connect
(
*
s
,
addr
.
c_str
());
if
(
ret
!=
0
)
{
zmq_close
(
*
s
);
...
...
@@ -175,10 +199,11 @@ int setupDealer(void **ctx, void **s, string ident, string addr, int sndQS, int
}
}
return
ret
;
return
ret
;
}
int
setupRouter
(
void
**
ctx
,
void
**
s
,
string
addr
,
int
rcvQS
){
int
setupRouter
(
void
**
ctx
,
void
**
s
,
string
addr
,
int
rcvQS
)
{
int
ret
=
0
;
*
ctx
=
zmq_ctx_new
();
*
s
=
zmq_socket
(
*
ctx
,
ZMQ_ROUTER
);
...
...
@@ -199,7 +224,8 @@ int setupRouter(void **ctx, void **s, string addr, int rcvQS){
return
ret
;
}
int
z_recv_multiple
(
void
*
s
,
vector
<
uint8_t
>
&
buf
,
int
&
frames
)
{
int
z_recv_multiple
(
void
*
s
,
vector
<
uint8_t
>
&
buf
,
int
&
frames
)
{
int64_t
more
=
1
;
size_t
more_size
=
sizeof
(
more
);
int
ret
=
0
;
...
...
@@ -229,12 +255,72 @@ int z_recv_multiple(void *s, vector<uint8_t> &buf, int &frames) {
if
(
ret
<
0
||
(
frames
!=
0
&&
cnt
!=
frames
))
{
spdlog
::
error
(
"failed to recv msg: {}"
,
ret
<
0
?
zmq_strerror
(
ret
)
:
"invalid frames"
);
return
-
1
;
}
else
{
}
else
{
frames
=
cnt
;
}
return
0
;
}
namespace
_internal_
{
mutex
mutConfigFiles
;
}
/// mk MUST NOT be null when isMerge is true
string
save_json
(
json
&
data
,
string
path
,
bool
isMerge
,
fn_mk_default_json
mk
)
{
lock_guard
<
mutex
>
lk
(
_internal_
::
mutConfigFiles
);
string
rc
;
json
js
;
if
(
isMerge
)
{
rc
=
load_json
(
js
,
path
,
mk
);
if
(
!
rc
.
empty
())
{
return
rc
;
}
try
{
js
.
merge_or_update
(
data
);
}
catch
(
exception
&
e
)
{
rc
=
fmt
::
format
(
"failed to merge json: {}, {} + {}"
,
e
.
what
(),
js
.
to_string
(),
data
.
to_string
());
return
rc
;
}
}
ofstream
ocfg_
(
path
,
std
::
ios
::
trunc
);
if
(
ocfg_
.
is_open
())
{
ocfg_
<<
pretty_print
(
data
);
ocfg_
.
flush
();
ocfg_
.
close
();
}
else
{
rc
=
fmt
::
format
(
"failed to open configuration file: {}"
,
path
);
spdlog
::
error
(
rc
);
}
return
rc
;
}
string
load_json
(
json
&
config
,
string
path
,
fn_mk_default_json
mk
)
{
lock_guard
<
mutex
>
lk
(
_internal_
::
mutConfigFiles
);
string
rc
;
try
{
ifstream
cfg_
(
path
);
config
=
json
::
parse
(
cfg_
);
}
catch
(
exception
&
e
)
{
spdlog
::
error
(
"failed loading config: {}, force to make default config:
\n
{}"
,
e
.
what
(),
config
.
to_string
());
if
(
mk
!=
nullptr
)
{
config
=
mk
();
}
else
{
rc
=
"no default make config function provided"
;
spdlog
::
error
(
rc
);
}
}
return
rc
;
}
}
\ No newline at end of file
hi3518/evutils.hpp
浏览文件 @
61621d77
...
...
@@ -43,6 +43,11 @@ typedef struct consts{
static
const
string
kMsgCmdReboot
;
static
const
string
kMsgCmdPtz
;
static
const
string
kMsgType
;
static
const
string
kMsgTypeImage
;
static
const
string
kMsgEncode
;
static
const
string
kMsgEncodeBase64
;
static
const
string
kMsgFormat
;
static
const
string
kMsgFormatJpeg
;
static
const
string
kMsgCata
;
static
const
string
kMsgTypeReport
;
static
const
string
kMsgTypeResponse
;
...
...
@@ -60,12 +65,15 @@ typedef struct consts{
static
const
string
pub_topic_response
;
static
const
string
pub_topic_report
;
static
const
string
mqtt_url
;
static
const
string
vgw_addr
;
static
const
string
upload_addr
;
static
consts
&
self
();
}
consts
;
extern
string
msg_field
(
const
json
&
msg
,
const
string
&
field
);
extern
bool
is_sdcard_avail
(
char
*
path
=
nullptr
);
extern
json
make_default_config
();
extern
json
make_default_cloud_config
();
extern
json
make_default_sys_extra_config
();
extern
void
get_mac_addr
(
char
*
buf
,
char
*
intf
=
nullptr
);
extern
bool
get_sdcard_megabytes
(
uint64_t
&
total
,
uint64_t
&
free
,
char
*
path
=
nullptr
);
extern
int
setupDealer
(
void
**
ctx
,
void
**
s
,
string
ident
,
string
addr
,
int
sndQS
=
0
,
int
timeoutMs
=
-
1
);
...
...
@@ -82,6 +90,8 @@ private:
size_t
maxSize
;
mutex
mut
;
TN
oldestTs
;
int
freeMB
=
0
;
const
int
kReservedMB_
=
300
;
cb_remove_elem
<
TN
>
fn_remove
;
unsigned
long
cntInsert
=
0
;
public
:
...
...
@@ -93,16 +103,27 @@ public:
if
(
cntInsert
%
10
==
0
)
{
oldestTs
=
chrono
::
duration_cast
<
chrono
::
milliseconds
>
(
chrono
::
system_clock
::
now
().
time_since_epoch
()).
count
()
-
60
*
2
*
1000
*
maxSize
;
spdlog
::
info
(
"record: maxSlices {}, oldestTs {}"
,
maxSize
,
oldestTs
);
uint64_t
mt
,
mf
;
if
(
get_sdcard_megabytes
(
mt
,
mf
)){
freeMB
=
mf
;
}
else
{
freeMB
=
-
1
;
}
}
++
cntInsert
;
if
(
elem
<
oldestTs
)
{
if
(
fn
!=
nullptr
)
{
(
*
fn
)(
elem
);
}
else
if
(
fn_remove
!=
nullptr
)
{
(
*
fn_remove
)(
elem
);
/// ATTENTION: we don't remove old file unless it can't be hold
bool
forceRemoveOldFiles
=
false
;
if
(
forceRemoveOldFiles
){
if
(
elem
<
oldestTs
)
{
if
(
fn
!=
nullptr
)
{
(
*
fn
)(
elem
);
}
else
if
(
fn_remove
!=
nullptr
)
{
(
*
fn_remove
)(
elem
);
}
return
;
}
return
;
}
if
(
list_
.
size
()
==
0
)
{
...
...
@@ -125,7 +146,7 @@ public:
list_
.
insert
(
itr
.
base
(),
elem
);
}
if
(
list_
.
size
()
>
maxSize
)
{
if
(
list_
.
size
()
>
maxSize
||
(
freeMB
!=
-
1
&&
freeMB
<=
kReservedMB_
)
)
{
lock_guard
<
mutex
>
lg
(
mut
);
auto
ts
=
*
(
list_
.
begin
());
list_
.
erase
(
list_
.
begin
());
...
...
@@ -200,8 +221,15 @@ public:
{
return
list_
;
}
size_t
capacity
(){
return
maxSize
;
}
};
typedef
json
(
*
fn_mk_default_json
)();
extern
string
save_json
(
json
&
data
,
string
path
,
bool
isMerge
,
fn_mk_default_json
mk
=
nullptr
);
extern
string
load_json
(
json
&
config
,
string
path
,
fn_mk_default_json
mk
=
nullptr
);
}
#endif
\ No newline at end of file
hi3518/internal_types.h
0 → 100644
浏览文件 @
61621d77
#ifndef __INTER_TYPES_H__
#define __INTER_TYPES_H__
#include <mqtt_helper.hpp>
typedef
struct
ev_region_t
{
float
minx
;
float
miny
;
float
maxx
;
float
maxy
;
}
ev_region_t
;
typedef
struct
ev_module_config_t
{
int
stat_current
;
ev_region_t
region
;
bool
enabled
;
MqttHelper
*
pClient
;
union
{
struct
{
int
interval
;
// in seconds
}
record
;
struct
{
float
face_thresh
;
//[0,1]
float
human_thresh
;
int
image_report_interval
;
// max in seconds
}
ai
;
struct
{
int
level
;
// 1 - 6
}
motion
;
struct
{
int
fps
;
int
video_quality
;
int
bitrate_kb
;
int
bitrate_type
;
int
push
;
}
sys
;
}
module
;
}
ev_module_config_t
;
#endif
\ No newline at end of file
hi3518/main.cc
浏览文件 @
61621d77
...
...
@@ -20,6 +20,9 @@
#include <ghc/filesystem.hpp>
#include <mqtt_helper.hpp>
#include <signal.h>
#include <jsoncons_ext/jsonpatch/jsonpatch.hpp>
#include "internal_types.h"
#include "ptz.h"
using
namespace
std
;
using
namespace
jsoncons
;
...
...
@@ -38,6 +41,7 @@ char dev_sn[TERMINAL_SN_SIZE] = {0};
/// default video gateway info
int
videoQuality
=
MAQUE_IMG_QUALITY_BETTER
;
int
gFrameFPS
=
15
;
uint64_t
frameCntTotal
=
0
;
uint32_t
frameCntIframe
=
0
;
uint32_t
frameCntPframe
=
0
;
...
...
@@ -83,42 +87,22 @@ OrderedList<long long> *gRecFilesList = nullptr;
//
string
strMaQuePath
=
"/mnt/sd/Config/"
;
/// why using
singleton ?
because global vriable initialization order between files is undefined!
/// why using
get function
because global vriable initialization order between files is undefined!
/// this avoids getting empty result
string
strSDCardReservedPaths
[]
=
{
consts
::
self
().
recFilePath
,
strMaQuePath
};
/// flags used to stop modules
/// 0: stopped, 1: requested to stop, 2: runningstatic int
typedef
struct
ev_region_t
{
float
minx
;
float
miny
;
float
maxx
;
float
maxy
;
}
ev_region_t
;
typedef
struct
ev_module_config_t
{
int
stat_current
;
ev_region_t
region
;
bool
enabled
;
union
{
struct
{
int
interval
;
// in seconds
}
record
;
struct
{
float
face_thresh
;
//[0,1]
float
human_thresh
;
}
ai
;
struct
motion
{
int
level
;
// 1 - 6
}
motion
;
}
module
;
}
ev_module_config_t
;
vector
<
string
>
get_sdcard_resered_dirs
()
{
return
{
consts
::
recFilePath
,
strMaQuePath
};
}
static
ev_module_config_t
gConfigRecord
=
{
0
};
static
ev_module_config_t
gConfigAI
=
{
0
};
static
ev_module_config_t
gConfigMotion
=
{
0
};
static
ev_module_config_t
gConfigVideo
=
{
0
};
string
gMqttAddr
,
gVgwAddr
,
gUploadAddr
;
enum
EV_MSG_ERROR_CODE
{
EV_MSG_ERROR_NONE
,
EV_MSG_ERROR_INVALID_PARAM
,
EV_MSG_ERROR_EXCEPTION
,
EV_MSG_ERROR_UNSUPPORTED_CMD
,
EV_MSG_ERROR_CONTENT_SYNTAX
,
...
...
@@ -139,13 +123,6 @@ void clean_up(int sig)
fclose
(
args
.
recFD
);
}
// while (args.dataq->size() > 0) {
// DataItem elem = args.dataq->front();
// args.dataq->pop();
// MaQueVideoEncFrameInfo_s *pMem = (MaQueVideoEncFrameInfo_s *)elem.ud;
// MaQue_Demo_Mem_release(pMem->handleMem);
// }
//stop_md_bd();
LibXmMaQue_System_destroy
();
exit
(
1
);
...
...
@@ -161,6 +138,22 @@ bool is_big_endian(void)
return
bint
.
c
[
0
]
==
1
;
}
string
save_configuration
(
json
&
data
)
{
auto
rc
=
save_json
(
data
,
configFilePath
,
false
,
nullptr
);
if
(
!
rc
.
empty
())
{
spdlog
::
error
(
rc
);
}
return
rc
;
}
string
load_configuration
(
json
&
config
)
{
auto
rc
=
load_json
(
config
,
configFilePath
,
evutils
::
make_default_cloud_config
);
return
rc
;
}
MaQueVideoEncodeCfg_s
*
init_stream_cfg
(
MaQueVideoEncodeCfg_s
*
cfg
)
{
cfg
->
eVidComp
=
(
MaQueVideoCompress_e
)
-
1
;
...
...
@@ -281,27 +274,27 @@ void frame_send_entry(void *args)
int
ret
=
0
;
int
flagFail
=
3
;
// 1 - sub, 2 - dealer , 3 - both
// should never exit
while
(
1
){
while
(
1
)
{
/// TODO: check enable status
this_thread
::
sleep_for
(
4
s
);
if
(
false
){
if
(
false
)
{
continue
;
}
// setup dealer
if
(
flagFail
&
2
){
if
(
flagFail
&
2
)
{
ret
=
setupDealer
(
&
pDealerCtx
,
&
pDealer
,
string
(
dev_sn
),
vgwUrl
,
10
);
if
(
ret
<
0
)
{
spdlog
::
error
(
"failed to connect cloud vgw: {}"
,
vgwUrl
);
continue
;
}
spdlog
::
info
(
"success connect to vgw"
);
}
// setup sub
if
(
flagFail
&
1
){
if
(
flagFail
&
1
)
{
pSub
=
zmq_socket
(
pPubCtx
,
ZMQ_SUB
);
if
(
pSub
==
nullptr
)
{
spdlog
::
error
(
"failed to create frame sending socket"
);
...
...
@@ -342,7 +335,7 @@ void frame_send_entry(void *args)
zmq_close
(
pSub
);
pSub
=
nullptr
;
}
if
(
flagFail
&
2
){
if
(
flagFail
&
2
)
{
zmq_close
(
pDealer
);
zmq_ctx_destroy
(
pDealerCtx
);
pDealer
=
nullptr
;
...
...
@@ -351,14 +344,15 @@ void frame_send_entry(void *args)
}
}
void
print_ts_files
(
OrderedList
<
long
long
>
&
_list
)
{
void
print_ts_files
(
OrderedList
<
long
long
>
&
_list
)
{
spdlog
::
info
(
"print file ts {}:"
,
_list
.
items
().
size
());
int
cnt
=
0
;
printf
(
"
\t
"
);
for
(
auto
&
k
:
_list
.
items
()){
for
(
auto
&
k
:
_list
.
items
())
{
cnt
++
;
printf
(
"%lld, "
,
k
);
if
(
cnt
%
6
==
0
){
if
(
cnt
%
6
==
0
)
{
printf
(
"
\n\t
"
);
}
}
...
...
@@ -366,7 +360,8 @@ void print_ts_files(OrderedList<long long> &_list) {
}
void
load_sd_files
(
OrderedList
<
long
long
>
&
_list
){
void
load_sd_files
(
OrderedList
<
long
long
>
&
_list
)
{
auto
now
=
chrono
::
duration_cast
<
chrono
::
milliseconds
>
(
chrono
::
system_clock
::
now
().
time_since_epoch
()).
count
();
try
{
string
fname
,
baseName
;
...
...
@@ -374,11 +369,12 @@ void load_sd_files(OrderedList<long long> &_list){
fname
=
entry
.
path
().
c_str
();
if
(
entry
.
file_size
()
==
0
||
!
entry
.
is_regular_file
()
||
entry
.
path
().
extension
()
!=
".h264"
)
{
spdlog
::
warn
(
"load_sd_files skipped {} (empty/directory/!h264)"
,
entry
.
path
().
c_str
());
fs
::
remove
(
fname
);
continue
;
}
long
long
ts
=
stoll
(
entry
.
path
().
stem
().
string
());
if
(
ts
<
consts
::
TS_2020
){
if
(
ts
<
consts
::
TS_2020
)
{
/// TODO: files records when offline with no valid time got
fs
::
remove
(
entry
.
path
());
spdlog
::
warn
(
"remove records having invalid timestamp: {}"
,
ts
);
...
...
@@ -388,16 +384,17 @@ void load_sd_files(OrderedList<long long> &_list){
}
}
catch
(
exception
&
e
)
{
spdlog
::
error
(
"{}:{} load
VideoF
iles exception : {}"
,
__FILE__
,
__LINE__
,
e
.
what
());
spdlog
::
error
(
"{}:{} load
_sd_f
iles exception : {}"
,
__FILE__
,
__LINE__
,
e
.
what
());
}
}
void
remove_ts_file
(
long
long
ts
){
string
fname
=
to_string
(
ts
)
+
".h264"
;
void
remove_ts_file
(
long
long
ts
)
{
string
fname
=
consts
::
recFilePath
+
to_string
(
ts
)
+
".h264"
;
fs
::
remove
(
fname
);
}
void
record_video_entry
(
void
*
a
rgs
)
void
record_video_entry
(
ev_module_config_t
*
pA
rgs
)
{
int
ret
=
0
;
// this thread will never exit
...
...
@@ -408,7 +405,7 @@ void record_video_entry(void *args)
continue
;
}
uint64_t
total
=
0
,
avail
=
0
;
if
(
!
get_sdcard_megabytes
(
total
,
avail
)){
if
(
!
get_sdcard_megabytes
(
total
,
avail
))
{
spdlog
::
error
(
"failed to get sd card size"
);
continue
;
}
...
...
@@ -417,7 +414,8 @@ void record_video_entry(void *args)
// calc num of slices
// reserve 0.5GB space
ssize_t
maxSlices
=
(
total
-
512
)
/
10
;
// multipled by 1.5 because videos take less space in midnight (variable bitrate)
ssize_t
maxSlices
=
(
ssize_t
)((
total
-
512
)
/
10
*
1.5
);
gRecFilesList
=
new
OrderedList
<
long
long
>
(
maxSlices
,
remove_ts_file
);
// load existing videos
load_sd_files
(
*
gRecFilesList
);
...
...
@@ -455,18 +453,19 @@ void record_video_entry(void *args)
if
(
cnt
%
30
==
0
)
{
nowTs
=
chrono
::
duration_cast
<
chrono
::
milliseconds
>
(
chrono
::
system_clock
::
now
().
time_since_epoch
()).
count
();
}
if
(
nowTs
-
preTs
>
gConfigRecord
.
module
.
record
.
interval
*
1000
)
{
if
(
nowTs
-
preTs
>
pArgs
->
module
.
record
.
interval
*
1000
)
{
if
(
fp
!=
nullptr
)
{
if
(
fp
->
is_open
())
fp
->
close
();
delete
fp
;
}
fp
=
new
fstream
(
consts
::
recFilePath
+
to_string
(
nowTs
)
+
".h264"
,
std
::
ios
::
out
|
std
::
ios
::
binary
);
if
(
!
fp
->
is_open
()){
if
(
!
fp
->
is_open
())
{
spdlog
::
error
(
"failed to open record file"
);
delete
fp
;
fp
=
nullptr
;
}
else
{
}
else
{
gRecFilesList
->
insert
(
nowTs
);
}
preTs
=
nowTs
;
...
...
@@ -533,8 +532,8 @@ string verify_config(json &data)
::
close
(
socket
);
}
}
}
}
if
(
!
str
.
empty
())
{
spdlog
::
error
(
str
);
}
...
...
@@ -542,6 +541,146 @@ string verify_config(json &data)
return
str
;
}
/// TODO: we will figure out how to apply change without reboot.
/// this is a temprary implementaion for quich prototyping
string
apply_config
(
json
&
data
)
{
string
rc
;
try
{
/// make defaults
gConfigVideo
.
module
.
sys
.
fps
=
15
;
// secs
gConfigVideo
.
module
.
sys
.
video_quality
=
MAQUE_IMG_QUALITY_BETTER
;
gConfigRecord
.
module
.
record
.
interval
=
60
*
2
;
// 2 minutes interval
gConfigVideo
.
module
.
sys
.
bitrate_kb
=
1024
;
// 1Mbps
gConfigVideo
.
module
.
sys
.
bitrate_type
=
MAQUE_BITRATE_CTRL_VBR
;
gConfigVideo
.
module
.
sys
.
push
=
0
;
// motion
gConfigMotion
.
module
.
motion
.
level
=
3
;
gConfigMotion
.
enabled
=
1
;
gConfigMotion
.
region
=
{
0
,
0
,
1
,
1
};
// ai
gConfigAI
.
enabled
=
1
;
gConfigAI
.
region
=
{
0
,
0
,
1
,
1
};
gConfigAI
.
module
.
ai
.
face_thresh
=
0.7
;
gConfigAI
.
module
.
ai
.
human_thresh
=
0.7
;
gConfigAI
.
module
.
ai
.
image_report_interval
=
10
;
// no two reports within 10 seconds
// vgw
if
(
gJsonConfig
.
contains
(
consts
::
kMsgConfigVgw
))
{
gVgwAddr
=
gJsonConfig
[
consts
::
kMsgConfigVgw
].
as
<
string
>
();
}
else
{
gVgwAddr
=
consts
::
vgw_addr
;
}
// mqtt
if
(
gJsonConfig
.
contains
(
consts
::
kMsgConfigMqtt
))
{
gMqttAddr
=
gJsonConfig
[
consts
::
kMsgConfigMqtt
].
as
<
string
>
();
}
else
{
gMqttAddr
=
consts
::
mqtt_url
;
}
// uploader
if
(
gJsonConfig
.
contains
(
consts
::
kMsgConfigUpload
))
{
gUploadAddr
=
gJsonConfig
[
consts
::
kMsgConfigUpload
].
as
<
string
>
();
}
else
{
gUploadAddr
=
consts
::
upload_addr
;
}
if
(
gJsonConfig
.
contains
(
consts
::
kMsgConfigFeatures
))
{
json
&
cfgFeatures
=
gJsonConfig
[
consts
::
kMsgConfigFeatures
];
if
(
cfgFeatures
.
contains
(
"logLevel"
))
{
logLevel
=
spdlog
::
level
::
from_str
(
cfgFeatures
[
"logLevel"
].
as
<
string
>
());
spdlog
::
set_level
(
logLevel
);
}
// fps
if
(
cfgFeatures
.
contains
(
"fps"
))
{
gConfigVideo
.
module
.
sys
.
fps
=
cfgFeatures
[
"fps"
].
as
<
int
>
();
}
else
{
spdlog
::
warn
(
"no fps configuration, using default: {}"
,
gConfigVideo
.
module
.
sys
.
fps
);
}
// record
if
(
cfgFeatures
.
contains
(
"recordLen"
))
{
gConfigRecord
.
module
.
record
.
interval
=
cfgFeatures
[
"recordLen"
].
as
<
int
>
();
}
else
{
spdlog
::
warn
(
"no recordLen configuration, using default: {}"
,
gConfigRecord
.
module
.
record
.
interval
);
}
// quality
if
(
cfgFeatures
.
contains
(
"videoQuality"
))
{
gConfigVideo
.
module
.
sys
.
video_quality
=
cfgFeatures
[
"videoQuality"
].
as
<
int
>
();
}
else
{
spdlog
::
warn
(
"no video quality configuration, using default: {}"
,
gConfigVideo
.
module
.
sys
.
video_quality
);
}
// bitrate
if
(
cfgFeatures
.
contains
(
"bitrate"
))
{
gConfigVideo
.
module
.
sys
.
bitrate_kb
=
cfgFeatures
[
"bitrate"
].
as
<
int
>
();
}
else
{
spdlog
::
warn
(
"no video bitrate configuration, using default: {}"
,
gConfigVideo
.
module
.
sys
.
bitrate_kb
);
}
if
(
cfgFeatures
.
contains
(
"bitrateType"
))
{
gConfigVideo
.
module
.
sys
.
bitrate_type
=
cfgFeatures
[
"bitrateType"
].
as
<
int
>
();
}
else
{
spdlog
::
warn
(
"no video bitrate type configuration, using default: {}"
,
gConfigVideo
.
module
.
sys
.
bitrate_type
);
}
if
(
cfgFeatures
.
contains
(
"push"
))
{
gConfigVideo
.
module
.
sys
.
push
=
cfgFeatures
[
"push"
].
as
<
int
>
();
}
else
{
spdlog
::
warn
(
"no push configuration, using default: {}"
,
gConfigVideo
.
module
.
sys
.
push
);
}
// motion
if
(
cfgFeatures
.
contains
(
"motion"
))
{
json
&
motion
=
cfgFeatures
[
"motion"
];
if
(
motion
.
contains
(
"enabled"
))
{
gConfigMotion
.
enabled
=
motion
[
"enabled"
].
as
<
int
>
();
}
if
(
motion
.
contains
(
"level"
))
{
gConfigMotion
.
module
.
motion
.
level
=
motion
[
"level"
].
as
<
int
>
();
}
if
(
motion
.
contains
(
"region"
)
&&
motion
[
"region"
].
contains
(
"minX"
)
&&
motion
[
"region"
].
contains
(
"minY"
)
&&
motion
[
"region"
].
contains
(
"maxX"
)
&&
motion
[
"region"
].
contains
(
"maxY"
))
{
gConfigMotion
.
region
=
{
motion
[
"region"
][
"minX"
].
as
<
float
>
(),
motion
[
"region"
][
"minY"
].
as
<
float
>
(),
motion
[
"region"
][
"maxX"
].
as
<
float
>
(),
motion
[
"region"
][
"maxY"
].
as
<
float
>
()};
}
}
spdlog
::
info
(
"motion configuration: enabled {}, level {}, region ({},{}), ({}, {})"
,
gConfigMotion
.
enabled
,
gConfigMotion
.
module
.
motion
.
level
,
gConfigMotion
.
region
.
minx
,
gConfigMotion
.
region
.
miny
,
gConfigMotion
.
region
.
maxx
,
gConfigMotion
.
region
.
maxy
);
// ai
if
(
cfgFeatures
.
contains
(
"ai"
))
{
json
&
ai
=
cfgFeatures
[
"ai"
];
if
(
ai
.
contains
(
"enabled"
))
{
gConfigAI
.
enabled
=
ai
[
"enabled"
].
as
<
int
>
();
}
if
(
ai
.
contains
(
"faceThresh"
))
{
gConfigAI
.
module
.
ai
.
face_thresh
=
ai
[
"faceThresh"
].
as
<
float
>
();
}
if
(
ai
.
contains
(
"humanThresh"
))
{
gConfigAI
.
module
.
ai
.
human_thresh
=
ai
[
"humanThresh"
].
as
<
float
>
();
}
if
(
ai
.
contains
(
"region"
)
&&
ai
[
"region"
].
contains
(
"minX"
)
&&
ai
[
"region"
].
contains
(
"minY"
)
&&
ai
[
"region"
].
contains
(
"maxX"
)
&&
ai
[
"region"
].
contains
(
"maxY"
))
{
gConfigAI
.
region
=
{
ai
[
"region"
][
"minX"
].
as
<
float
>
(),
ai
[
"region"
][
"minY"
].
as
<
float
>
(),
ai
[
"region"
][
"maxX"
].
as
<
float
>
(),
ai
[
"region"
][
"maxY"
].
as
<
float
>
()};
}
}
}
}
catch
(
exception
&
e
)
{
/// TODO: save for reporting
rc
=
fmt
::
format
(
"failed to apply config: {}, {}"
,
e
.
what
(),
data
.
to_string
());
spdlog
::
error
(
rc
);
}
return
rc
;
}
/// handles all incoming request from cloud services
void
handle_mqtt_req
(
MqttHelper
*
hlp
,
const
void
*
const
data
,
int
len
,
string
topic
)
{
...
...
@@ -552,7 +691,7 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t
auto
js
=
json
::
parse
(
msg
);
auto
str
=
verify_request
(
js
);
if
(
!
str
.
empty
())
{
spdlog
::
warn
(
str
);
spdlog
::
error
(
str
);
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_report
,
EV_MSG_ERROR_CONTENT_SYNTAX
,
str
,
js
.
contains
(
consts
::
kMsgCmd
)
?
js
[
consts
::
kMsgCmd
].
as
<
string
>
()
:
string
(
""
),
js
.
contains
(
consts
::
kMsgRid
)
?
js
[
consts
::
kMsgRid
].
as
<
string
>
()
:
string
(
""
),
json
());
return
;
}
...
...
@@ -563,30 +702,64 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t
auto
data
=
js
[
consts
::
kMsgData
].
as
<
json
>
();
/// TODO: implements cmds
if
(
cmd
==
consts
::
kMsgCmdConfig
)
{
// apply config
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
0
,
"OK"
,
js
.
contains
(
consts
::
kMsgCmd
)
?
js
[
consts
::
kMsgCmd
].
as
<
string
>
()
:
string
(
""
),
js
.
contains
(
consts
::
kMsgRid
)
?
js
[
consts
::
kMsgRid
].
as
<
string
>
()
:
string
(
""
),
data
);
// verify configuration
auto
rv
=
verify_config
(
data
);
if
(
!
rv
.
empty
())
{
spdlog
::
error
(
"failed to apply config: {}, {}"
,
rv
,
data
.
to_string
());
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
EV_MSG_ERROR_INVALID_PARAM
,
rv
,
cmd
,
rid
,
data
);
}
else
{
// calc diff
auto
patch
=
jsonpatch
::
from_diff
(
gJsonConfig
,
data
);
if
(
patch
.
empty
())
{
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
0
,
"no diff to apply"
,
cmd
,
rid
,
data
);
}
else
{
// apply diff to tmp and verify
spdlog
::
info
(
"json diff: {}"
,
patch
.
to_string
());
auto
rc
=
verify_config
(
data
);
if
(
!
rc
.
empty
())
{
}
else
{
rc
=
apply_config
(
data
);
}
if
(
!
rc
.
empty
())
{
spdlog
::
error
(
rc
);
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
EV_MSG_ERROR_INVALID_PARAM
,
rc
,
cmd
,
rid
,
data
);
}
else
{
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
0
,
"rebooting to apply new config"
,
cmd
,
rid
,
data
);
/// TODO: using json diff to apply change without reboot
save_configuration
(
data
);
spdlog
::
info
(
"rebooting to apply new configuration"
);
system
(
"reboot"
);
}
}
}
}
else
if
(
cmd
==
consts
::
kMsgCmdUploadVideo
)
{
// upload video
if
(
gRecFilesList
==
nullptr
){
if
(
gRecFilesList
==
nullptr
)
{
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
-
1
,
"no sd card"
,
js
.
contains
(
consts
::
kMsgCmd
)
?
js
[
consts
::
kMsgCmd
].
as
<
string
>
()
:
string
(
""
),
js
.
contains
(
consts
::
kMsgRid
)
?
js
[
consts
::
kMsgRid
].
as
<
string
>
()
:
string
(
""
),
data
);
}
else
{
}
else
{
auto
tss
=
data
[
"start"
].
as
<
long
long
>
();
auto
tse
=
data
[
"end"
].
as
<
long
long
>
();
// guess unit in ms or s
if
(
tss
/
100000000000
==
0
){
if
(
tss
/
100000000000
==
0
)
{
tss
=
tss
*
1000
;
tse
=
tse
*
1000
;
}
long
long
offsetE
=
0
,
offsetS
=
0
;
auto
res
=
gRecFilesList
->
findByRange
(
tss
,
tse
,
offsetS
,
offsetE
);
if
(
res
.
empty
()){
if
(
res
.
empty
())
{
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
-
2
,
"no video found"
,
js
.
contains
(
consts
::
kMsgCmd
)
?
js
[
consts
::
kMsgCmd
].
as
<
string
>
()
:
string
(
""
),
js
.
contains
(
consts
::
kMsgRid
)
?
js
[
consts
::
kMsgRid
].
as
<
string
>
()
:
string
(
""
),
data
);
}
else
{
}
else
{
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
0
,
"OK"
,
js
.
contains
(
consts
::
consts
::
kMsgCmd
)
?
js
[
consts
::
kMsgCmd
].
as
<
string
>
()
:
string
(
""
),
js
.
contains
(
consts
::
kMsgRid
)
?
js
[
consts
::
kMsgRid
].
as
<
string
>
()
:
string
(
""
),
data
);
print_ts_files
(
*
gRecFilesList
);
printf
(
"matched
%lld, %lld:
\n\t
"
,
offsetS
,
offsetE
);
for
(
auto
&
k
:
res
){
printf
(
"matched
(%lld, %lld) with offsets %lld, %lld:
\n\t
"
,
tss
,
tse
,
offsetS
,
offsetE
);
for
(
auto
&
k
:
res
)
{
printf
(
"%lld, "
,
k
);
}
printf
(
"
\n
"
);
...
...
@@ -595,19 +768,51 @@ void handle_mqtt_req(MqttHelper *hlp, const void * const data, int len, string t
}
else
if
(
cmd
==
consts
::
kMsgCmdGetConfig
)
{
// response config
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
0
,
"OK"
,
js
.
contains
(
consts
::
kMsgCmd
)
?
js
[
consts
::
kMsgCmd
].
as
<
string
>
()
:
string
(
""
),
js
.
contains
(
consts
::
kMsgRid
)
?
js
[
consts
::
kMsgRid
].
as
<
string
>
()
:
string
(
""
),
data
);
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
0
,
"OK"
,
js
.
contains
(
consts
::
kMsgCmd
)
?
js
[
consts
::
kMsgCmd
].
as
<
string
>
()
:
string
(
""
),
js
.
contains
(
consts
::
kMsgRid
)
?
js
[
consts
::
kMsgRid
].
as
<
string
>
()
:
string
(
""
),
gJsonConfig
);
}
else
if
(
cmd
==
consts
::
kMsgCmdStatus
)
{
// response status
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
0
,
"OK"
,
js
.
contains
(
consts
::
kMsgCmd
)
?
js
[
consts
::
kMsgCmd
].
as
<
string
>
()
:
string
(
""
),
js
.
contains
(
consts
::
kMsgRid
)
?
js
[
consts
::
kMsgRid
].
as
<
string
>
()
:
string
(
""
),
data
);
json
stat
;
stat
[
"sd"
]
=
json
();
if
(
is_sdcard_avail
())
{
uint64_t
totalMB
=
0
,
freeMB
=
0
;
if
(
get_sdcard_megabytes
(
totalMB
,
freeMB
))
{
stat
[
"sd"
][
"MBfree"
]
=
freeMB
;
stat
[
"sd"
][
"MBTotal"
]
=
totalMB
;
}
}
// get first video ts
stat
[
"record"
]
=
json
();
auto
rec
=
gRecFilesList
->
items
();
stat
[
"record"
][
"capacity"
]
=
gRecFilesList
->
capacity
();
if
(
rec
.
size
()
>
0
)
{
stat
[
"record"
][
"num"
]
=
rec
.
size
();
stat
[
"record"
][
"first"
]
=
*
(
rec
.
begin
());
stat
[
"record"
][
"last"
]
=
*
((
rec
.
rbegin
()));
}
/// TODO: subsystems running status
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
0
,
"OK"
,
cmd
,
rid
,
stat
);
}
else
if
(
cmd
==
consts
::
kMsgCmdPtz
)
{
// response Ptz control
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
0
,
"OK"
,
js
.
contains
(
consts
::
kMsgCmd
)
?
js
[
consts
::
kMsgCmd
].
as
<
string
>
()
:
string
(
""
),
js
.
contains
(
consts
::
kMsgRid
)
?
js
[
consts
::
kMsgRid
].
as
<
string
>
()
:
string
(
""
),
data
);
}
else
if
(
cmd
==
"list_videos"
){
/// TODO:
if
(
!
data
.
contains
(
"action"
)
||
!
data
.
contains
(
"degree"
))
{
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
EV_MSG_ERROR_INVALID_PARAM
,
"invalid param in data field"
,
cmd
,
rid
,
data
);
return
;
}
str
=
ptz_move
(
data
[
"action"
].
as
<
string
>
(),
data
[
"degree"
].
as
<
float
>
());
if
(
!
str
.
empty
())
{
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
EV_MSG_ERROR_INVALID_PARAM
,
str
,
cmd
,
rid
,
data
);
return
;
}
MqttMgr
::
report_response_args
(
gMqttClient
,
consts
::
pub_topic_response
+
rid
,
0
,
"OK"
,
cmd
,
rid
,
data
);
}
else
if
(
cmd
==
"list_videos"
)
{
if
(
gRecFilesList
!=
nullptr
)
print_ts_files
(
*
gRecFilesList
);
else
{
else
{
spdlog
::
warn
(
"no local video files"
);
}
}
...
...
@@ -635,29 +840,18 @@ MqttHelper* start_mqtt(void *arg)
return
nullptr
;
}
client
->
subscribe
(
consts
::
sub_topic
+
dev_sn
,
handle_mqtt_req
,
false
);
/// TODO:
gConfigAI
.
pClient
=
client
;
gConfigMotion
.
pClient
=
client
;
gConfigRecord
.
pClient
=
client
;
gConfigVideo
.
pClient
=
client
;
return
client
;
}
//
void
updateConfigFile
(
json
&
config
){
ofstream
ocfg_
(
configFilePath
,
std
::
ios
::
trunc
);
ocfg_
<<
pretty_print
(
gJsonConfig
);
}
void
readConfigFile
(
json
&
config
){
try
{
ifstream
cfg_
(
configFilePath
);
gJsonConfig
=
json
::
parse
(
cfg_
);
}
catch
(
exception
&
e
){
gJsonConfig
=
evutils
::
make_default_config
();
spdlog
::
error
(
"failed get config: {}, force to make default config:
\n
{}"
,
e
.
what
(),
gJsonConfig
.
to_string
());
updateConfigFile
(
gJsonConfig
);
}
}
void
create_sd_directories
(){
void
create_sd_directories
()
{
// create record paths
for
(
auto
k
:
strSDCardReservedPaths
)
{
for
(
auto
k
:
get_sdcard_resered_dirs
())
{
spdlog
::
info
(
"create path: {}"
,
k
);
system
((
string
(
"mkdir -p "
)
+
k
).
c_str
());
}
...
...
@@ -667,6 +861,7 @@ void create_sd_directories(){
int
main
(
int
argc
,
char
*
argv
[])
{
int
ret
=
XM_SUCCESS
;
get_mac_addr
(
dev_sn
);
spdlog
::
info
(
"hi3518ev300, sn: {}, version: {}, BE: {}"
,
dev_sn
,
evutils
::
version
,
is_big_endian
());
...
...
@@ -695,8 +890,13 @@ int main(int argc, char *argv[])
}
/// TODO: load configuration
readConfigFile
(
gJsonConfig
);
load_configuration
(
gJsonConfig
);
verify_config
(
gJsonConfig
);
auto
rc
=
apply_config
(
gJsonConfig
);
if
(
!
rc
.
empty
())
{
spdlog
::
error
(
"failed to apply configuration: {}"
,
gJsonConfig
.
to_string
());
spdlog
::
error
(
"defaults is used instead"
);
}
auto
logLevel_
=
getenv
(
"LOG_LEVEL"
);
if
(
logLevel_
)
{
...
...
@@ -708,19 +908,10 @@ int main(int argc, char *argv[])
spdlog
::
set_level
(
logLevel
);
}
auto
videoQuality_
=
getenv
(
"QUALITY"
);
if
(
videoQuality_
)
{
videoQuality
=
atoi
(
videoQuality_
);
if
(
videoQuality
>=
MAQUE_IMG_QUALITY_NR
||
videoQuality
<
0
)
{
videoQuality
=
MAQUE_IMG_QUALITY_BETTER
;
}
}
// blocking update time, since time is critical to every other component
bool
bGotTime
=
false
;
time_t
stm
;
while
(
!
bGotTime
)
{
while
(
!
bGotTime
)
{
if
(
getNtpTime
(
&
stm
)
>=
0
)
{
spdlog
::
info
(
"ntp got time"
);
::
stime
(
&
stm
);
...
...
@@ -735,7 +926,7 @@ int main(int argc, char *argv[])
MaQue_Demo_Mem_Init
();
MaQueStartParam_s
startParam
=
{
MAQUE_VIDEO_STANDARD_PAL
,
{
MAQUE_VIDEO_COMPRESS_H264
,
MAQUE_VIDEO_COMPRESS_H265
}};
memcpy
(
startParam
.
aWritableDir
,
strMaQuePath
.
c_str
(),
sizeof
(
startParam
.
aWritableDir
));
::
memcpy
(
startParam
.
aWritableDir
,
strMaQuePath
.
c_str
(),
sizeof
(
startParam
.
aWritableDir
));
ret
=
LibXmMaQue_System_startUp
(
&
startParam
);
spdlog
::
info
(
"ret: {}"
,
ret
);
...
...
@@ -753,32 +944,32 @@ int main(int argc, char *argv[])
spdlog
::
info
(
"abt ret: {}"
,
ret
);
if
(
XM_SUCCESS
==
ret
)
{
spdlog
::
info
(
fmt
::
format
(
"capbilities: supported codecs {0:#b},"
"max fhd/s {0:d}, max res: {0:d}, per ch mres: {0:d}, {0:d}, {0:d}, {0:d}"
,
int
(
capb
.
videoEncTypeMask
),
int
(
capb
.
maxEncPowerX1080P
),
int
(
capb
.
eDecImageSizeMax
),
int
(
capb
.
astVidEncChnAbility
[
0
].
eCapSizeMax
),
int
(
capb
.
astVidEncChnAbility
[
1
].
eCapSizeMax
),
int
(
capb
.
astVidEncChnAbility
[
2
].
eCapSizeMax
),
int
(
capb
.
astVidEncChnAbility
[
3
].
eCapSizeMax
)));
"max fhd/s {0:d}, max res: {0:d}, per ch mres: {0:d}, {0:d}, {0:d}, {0:d}"
,
int
(
capb
.
videoEncTypeMask
),
int
(
capb
.
maxEncPowerX1080P
),
int
(
capb
.
eDecImageSizeMax
),
int
(
capb
.
astVidEncChnAbility
[
0
].
eCapSizeMax
),
int
(
capb
.
astVidEncChnAbility
[
1
].
eCapSizeMax
),
int
(
capb
.
astVidEncChnAbility
[
2
].
eCapSizeMax
),
int
(
capb
.
astVidEncChnAbility
[
3
].
eCapSizeMax
)));
}
//
MaQueVideoEncodeCfg_s
cfg
;
init_stream_cfg
(
&
cfg
);
cfg
.
nFps
=
15
;
cfg
.
nFps
=
gConfigVideo
.
module
.
sys
.
fps
;
cfg
.
eIFrmIntvType
=
IFRAME_INTV_TYPE_TIME
;
cfg
.
nIFrameInterval
=
10
;
cfg
.
eImageQuality
=
(
MaQueImageQuality_e
)
videoQ
uality
;
cfg
.
eImageQuality
=
(
MaQueImageQuality_e
)
gConfigVideo
.
module
.
sys
.
video_q
uality
;
cfg
.
eVidComp
=
MAQUE_VIDEO_COMPRESS_H264
;
cfg
.
eBitrateCtrl
=
MAQUE_BITRATE_CTRL_VBR
;
cfg
.
nBitRate
=
1024
;
// 1Mbps
cfg
.
eBitrateCtrl
=
(
MaQueBitrateCtrl_e
)
gConfigVideo
.
module
.
sys
.
bitrate_type
;
cfg
.
nBitRate
=
gConfigVideo
.
module
.
sys
.
bitrate_kb
;
ret
=
configure_stream
((
MaQueStreamChannel_e
)
0
,
&
cfg
);
spdlog
::
info
(
"cfg stream ret: {}"
,
ret
);
/// TODO: load or make defualt configuration
gConfigRecord
.
module
.
record
.
interval
=
60
*
2
;
// 2 minutes interval
ret
=
LibXmMaQue_VideoEnc_startStream
(
0
,
(
MaQueStreamChannel_e
)
0
,
cb_frame_proc
,
(
void
*
)
&
args
);
if
(
XM_SUCCESS
==
ret
)
{
spdlog
::
info
(
"created record task successfully"
);
}
/// start ptz service
ptz_service_start
();
signal
(
SIGINT
,
clean_up
);
// signal(SIGTERM, clean_up);
...
...
@@ -794,25 +985,25 @@ int main(int argc, char *argv[])
exit
(
1
);
}
/// TODO: configuration issues handling
if
(
msg_field
(
gJsonConfig
,
consts
::
kMsgConfigVgw
).
empty
()){
if
(
msg_field
(
gJsonConfig
,
consts
::
kMsgConfigVgw
).
empty
())
{
spdlog
::
error
(
"missing vgw config"
);
}
thread
thPush
=
thread
(
frame_send_entry
,
&
args
);
spdlog
::
info
(
"sizeof pkt header {}, sizeof tv {}"
,
sizeof
(
evpacket_t
),
sizeof
(
timeval
));
if
(
thPush
.
joinable
()){
if
(
thPush
.
joinable
())
{
thPush
.
detach
();
}
thread
thVideoRecord
=
thread
(
record_video_entry
,
nullptr
);
if
(
thVideoRecord
.
joinable
()){
thread
thVideoRecord
=
thread
(
record_video_entry
,
&
gConfigRecord
);
if
(
thVideoRecord
.
joinable
())
{
thVideoRecord
.
detach
();
}
start_md_bd
(
&
args
);
start_md_bd
(
&
gConfigMotion
);
/// subscribe to mqtt
gMqttClient
=
start_mqtt
(
nullptr
);
thread
thSmart
=
thread
(
maq_smart_task_entry
,
&
args
);
thread
thSmart
=
thread
(
maq_smart_task_entry
,
&
gConfigAI
);
thSmart
.
join
();
}
\ No newline at end of file
hi3518/main.mqtt.cc
浏览文件 @
61621d77
...
...
@@ -78,12 +78,12 @@ typedef struct ev_module_config_t {
union
{
struct
{
int
interval
;
// in seconds
}
record
;
}
record
;
struct
{
float
face_thresh
;
//[0,1]
float
human_thresh
;
}
ai
;
struct
motion
{
struct
motion
{
int
level
;
// 1 - 6
}
motion
;
}
module
;
...
...
@@ -353,7 +353,7 @@ void record_video_entry(void *args)
this_thread
::
sleep_for
(
10
s
);
continue
;
}
// setup sub
void
*
pSub
=
zmq_socket
(
pPubCtx
,
ZMQ_SUB
);
// ret = 1;
...
...
@@ -394,7 +394,7 @@ void record_video_entry(void *args)
delete
fp
;
}
fp
=
new
fstream
(
recFilePath
+
to_string
(
nowTs
),
std
::
ios
::
out
|
std
::
ios
::
binary
);
if
(
!
fp
->
is_open
()){
if
(
!
fp
->
is_open
())
{
spdlog
::
error
(
"failed to open record file"
);
delete
fp
;
fp
=
nullptr
;
...
...
hi3518/motion.cc
浏览文件 @
61621d77
...
...
@@ -7,6 +7,8 @@ extern "C" {
#include <stdio.h>
#include <spdlog/spdlog.h>
#include <evpacket.h>
#include "motion.h"
typedef
struct
{
MaQueMdParam_s
stMdParam
;
...
...
@@ -51,8 +53,13 @@ static XM_S32 cb_blind_detect(XM_VOID *pUserArg, MaQueBdResult_s *pstBdRes)
return
0
;
}
void
start_md_bd
(
void
*
a
rgs
)
void
start_md_bd
(
ev_module_config_t
*
pA
rgs
)
{
if
(
!
pArgs
->
enabled
)
{
spdlog
::
warn
(
"motion detect is disabled"
);
}
spdlog
::
info
(
"starting motion detect module"
);
MdModParam_s
mdParam
=
{
0
};
BdModParam_s
bdParam
=
{
0
};
...
...
@@ -62,9 +69,9 @@ void start_md_bd(void *args)
mdParam
.
stMdParam
.
y
=
48
;
mdParam
.
stMdParam
.
w
=
352
-
58
*
2
;
mdParam
.
stMdParam
.
h
=
288
-
48
*
2
;
mdParam
.
stMdParam
.
eMdAlarmlevel
=
2
;
// [1, 6]
mdParam
.
stMdParam
.
eMdAlarmlevel
=
pArgs
->
module
.
motion
.
level
;
// [1, 6]
bdParam
.
stBdParam
.
bEnabled
=
1
;
bdParam
.
stBdParam
.
eBdAlarmLevel
=
2
;
bdParam
.
stBdParam
.
eBdAlarmLevel
=
pArgs
->
module
.
motion
.
level
;
if
(
mdParam
.
stMdParam
.
bEnabled
)
{
LibXmMaQue_MD_create
(
0
);
...
...
hi3518/motion.h
浏览文件 @
61621d77
#ifndef __MOTION_H__
#define __MOTION_H__
#pragma once
void
start_md_bd
(
void
*
args
);
#include "internal_types.h"
void
start_md_bd
(
ev_module_config_t
*
pArgs
);
void
stop_md_bd
();
#endif
\ No newline at end of file
hi3518/ptz.cc
0 → 100644
浏览文件 @
61621d77
#include <libxmmaque_api.h>
#include <spdlog/spdlog.h>
#include <fmt/format.h>
#include "ptz.h"
#include <mutex>
#include "evutils.hpp"
#include <string.h>
using
namespace
std
;
using
namespace
evutils
;
using
namespace
jsoncons
;
mutex
gMut
;
map
<
string
,
int
>
mapDirection
=
{
{
"left"
,
MOTOR_MOVE_LEFT
},
{
"right"
,
MOTOR_MOVE_RIGHT
},
{
"up"
,
MOTOR_MOVE_UP
},
{
"down"
,
MOTOR_MOVE_DOWN
},
{
"upright"
,
MOTOR_MOVE_RIGHT
|
MOTOR_MOVE_UP
},
{
"upleft"
,
MOTOR_MOVE_LEFT
|
MOTOR_MOVE_UP
},
{
"downleft"
,
MOTOR_MOVE_LEFT
|
MOTOR_MOVE_DOWN
},
{
"downright"
,
MOTOR_MOVE_RIGHT
|
MOTOR_MOVE_DOWN
}
};
void
ptz_waitfor_idle
()
{
XM_U32
action
,
x
,
y
;
usleep
(
100
*
1000
);
while
(
1
)
{
if
(
0
==
LibXmMaQue_Motor_getPostion
(
&
action
,
&
x
,
&
y
))
{
if
(
MOTOR_IDLE
==
action
)
{
break
;
}
else
{
usleep
(
300
*
1000
);
}
}
}
}
string
ptz_service_start
()
{
static
int
first_startup
=
1
;
string
rc
;
spdlog
::
info
(
"start ptz service: calibration/re-locating"
);
if
(
LibXmMaQue_Motor_create
()
<
0
)
{
rc
=
"ptz failed start service"
;
return
rc
;
}
rc
=
ptz_load
();
if
(
!
rc
.
empty
())
{
return
rc
;
}
spdlog
::
info
(
"ptz start service finished."
);
return
rc
;
}
string
ptz_service_stop
()
{
LibXmMaQue_Motor_stop
();
LibXmMaQue_Motor_destroy
();
}
string
ptz_get_params
(
ptz_param_position
&
param
)
{
uint32_t
x
,
y
;
string
rc
;
if
(
LibXmMaQue_Motor_getMaxSteps
(
&
x
,
&
y
)
<
0
)
{
rc
=
"ptz failed to get max steps"
;
return
rc
;
}
uint32_t
direction
,
cx
,
cy
;
if
(
LibXmMaQue_Motor_getPostion
(
&
direction
,
&
cx
,
&
cy
)
<
0
)
{
rc
=
"ptz failed to get current position"
;
return
rc
;
}
param
.
min_x
=
0
;
param
.
max_x
=
x
;
param
.
step_x
=
EV_PTZ_X_DEGREE
/
x
;
param
.
current_x_deg
=
cx
*
param
.
step_x
;
param
.
current_x_steps
=
cx
;
param
.
min_y
=
0
;
param
.
max_y
=
y
;
param
.
step_y
=
EV_PTZ_Y_DEGREE
/
x
;
param
.
current_y_deg
=
cy
*
param
.
step_y
;
param
.
current_y_steps
=
cy
;
return
rc
;
}
static
const
string
extraSysConfigFile
=
"/etc/evsys.json"
;
string
ptz_save
()
{
ptz_param_position
pos
;
auto
rc
=
ptz_get_params
(
pos
);
if
(
!
rc
.
empty
())
{
return
rc
;
}
json
js
;
js
[
"ptz"
]
=
json
();
js
[
"ptz"
][
"x"
]
=
pos
.
current_x_steps
;
js
[
"ptz"
][
"y"
]
=
pos
.
current_y_steps
;
rc
=
save_json
(
js
,
extraSysConfigFile
,
true
,
evutils
::
make_default_sys_extra_config
);
return
rc
;
}
string
ptz_load
()
{
string
rc
;
json
js
;
rc
=
load_json
(
js
,
extraSysConfigFile
,
evutils
::
make_default_sys_extra_config
);
if
(
!
rc
.
empty
())
{
return
rc
;
}
auto
x
=
js
[
"ptz"
][
"x"
].
as
<
uint32_t
>
();
auto
y
=
js
[
"ptz"
][
"y"
].
as
<
uint32_t
>
();
if
(
LibXmMaQue_Motor_setPostion
(
x
,
y
))
{
rc
=
fmt
::
format
(
"failed to set position to {}, {}"
,
x
,
y
);
}
ptz_waitfor_idle
();
return
rc
;
}
string
ptz_move
(
string
dire
,
float
degree
)
{
lock_guard
<
mutex
>
lk
(
gMut
);
string
rc
;
if
(
mapDirection
.
count
(
dire
)
==
0
)
{
rc
=
fmt
::
format
(
"ptz move invalid direction: {}"
,
dire
);
return
rc
;
}
ptz_param_position
curr_pos
;
rc
=
ptz_get_params
(
curr_pos
);
if
(
!
rc
.
empty
())
{
return
rc
;
}
if
(
dire
==
"left"
||
dire
==
"rignt"
)
{
curr_pos
.
current_x_steps
=
(
degree
*
1.0
/
curr_pos
.
step_x
);
}
if
(
dire
==
"up"
||
dire
==
"down"
)
{
curr_pos
.
current_y_steps
=
(
degree
*
1.0
/
curr_pos
.
step_y
);
}
if
(
LibXmMaQue_Motor_move
(
mapDirection
[
"dire"
],
52
,
52
,
curr_pos
.
current_x_steps
,
curr_pos
.
current_y_steps
)
<
0
)
{
rc
=
fmt
::
format
(
"ptz failed to move {} {}: current({},{}), max({},{})"
,
dire
,
degree
,
curr_pos
.
current_x_deg
,
curr_pos
.
current_y_deg
,
355
,
0
);
if
(
!
rc
.
empty
())
{
return
rc
;
}
}
ptz_waitfor_idle
();
rc
=
ptz_save
();
return
rc
;
}
string
ptz_reset
()
{
lock_guard
<
mutex
>
lk
(
gMut
);
ptz_param_position
param
;
string
rc
;
rc
=
ptz_get_params
(
param
);
if
(
!
rc
.
empty
())
{
return
rc
;
}
auto
targetx
=
param
.
max_x
/
2
;
auto
targety
=
param
.
max_y
/
2
;
if
(
LibXmMaQue_Motor_setZero
())
{
rc
=
"ptz failed to relocate to (0,0)"
;
return
rc
;
}
if
(
LibXmMaQue_Motor_move
(
mapDirection
[
"upright"
],
52
,
52
,
targetx
,
targety
)
<
0
)
{
rc
=
fmt
::
format
(
"ptz failed move to center: {} {}"
,
targetx
,
targety
);
}
ptz_waitfor_idle
();
return
rc
;
}
\ No newline at end of file
hi3518/ptz.h
0 → 100644
浏览文件 @
61621d77
#ifndef __EV_PTZ_H__
#define __EV_PTZ_H__
#pragma once
#include <maque_motor.h>
#include <string.h>
/// PTZ
#define EV_PTZ_X_DEGREE 355
// N/A for xiongmai camera
#define EV_PTZ_Y_DEGREE -1
// N/A for xiongmai camera
#define EV_PTZ_Z_DEGREE -1
typedef
struct
ptz_param_position
{
int
min_x
;
// steps
int
max_x
;
int
min_y
;
int
max_y
;
// steps
float
step_x
;
// degree per step
float
step_y
;
int
current_x_deg
;
// in number of steps, not degree
int
current_x_steps
;
int
current_y_deg
;
int
current_y_steps
;
//
}
ptz_param_position
;
std
::
string
ptz_service_start
();
std
::
string
ptz_service_stop
();
std
::
string
ptz_reset
(
ptz_param_position
);
std
::
string
ptz_move
(
std
::
string
dire
,
float
degree
);
std
::
string
ptz_get_params
(
ptz_param_position
&
param
);
std
::
string
ptz_load
();
#endif
\ No newline at end of file
hi3518/raw_tcp.cc
浏览文件 @
61621d77
...
...
@@ -17,7 +17,7 @@ int raw_connect(std::string host, std::string port, int *socket_, int recv_timeo
hints
.
ai_flags
=
AI_NUMERICSERV
;
// port passed as as numeric value
hints
.
ai_protocol
=
0
;
spdlog
::
info
(
"raw
_connect"
);
spdlog
::
info
(
"raw
connect: {}:{}"
,
host
,
port
);
addrinfo
*
addrinfo_result
;
rv
=
::
getaddrinfo
(
host
.
c_str
(),
port
.
c_str
(),
&
hints
,
&
addrinfo_result
);
...
...
@@ -49,7 +49,7 @@ int raw_connect(std::string host, std::string port, int *socket_, int recv_timeo
spdlog
::
error
(
"setsockopt SO_SNDTIMEO failed"
);
return
-
1
;
}
rv
=
::
connect
(
*
socket_
,
rp
->
ai_addr
,
rp
->
ai_addrlen
);
if
(
rv
==
0
)
{
auto
addr
=
(
struct
sockaddr_in
*
)
rp
->
ai_addr
;
...
...
hi3518/smart.cc
浏览文件 @
61621d77
...
...
@@ -9,37 +9,64 @@ extern "C"
}
#include "mqtt_helper.hpp"
#include <jsoncons/json.hpp>
#include <vector>
#include <chrono>
#define DIV_UP(x, a) ( ((x) + ((a) - 1) ) / a )
using
namespace
std
;
using
namespace
jsoncons
;
#define DIV_UP(x, a) ( ((x) + ((a) - 1) ) / a )
#define SMART_CAP_MIN_SECS 10
long
long
smartTsLast
=
0
;
static
int
smartCnt
=
0
;
XM_S32
MaQue_JpegEnc_getFrame_callback
(
XM_VOID
*
pUserArg
,
MaQueSmartJpegFrame_s
*
pstJpegFrame
)
{
// if(smartCnt > 0) {
// smartCnt--;
// return 0;
// }
// smartCnt = 1000;
// XM_CHAR acFile[256] = {0};
// FILE *pFile;
// static XM_S32 jpeg_cnt = 0;
printf
(
"aClassName[%s] idx = %d, toltal = %d
\n
"
,
pstJpegFrame
->
aClassName
,
pstJpegFrame
->
nIndex
,
pstJpegFrame
->
nToltalJpeg
);
// if (jpeg_cnt < 30000) {
// sprintf(acFile, "ai/snap_%d.jpg", jpeg_cnt);
// pFile = fopen(acFile, "wb");
// if (pFile == NULL) {
// spdlog::error("open file err");
// return XM_FAILURE;
// }
// fwrite(pstJpegFrame->pBuffer, pstJpegFrame->nDataLen, 1, pFile);
// fflush(pFile);
// fclose(pFile);
// jpeg_cnt++;
// }
ev_module_config_t
*
mod
=
(
ev_module_config_t
*
)
pUserArg
;
auto
now
=
chrono
::
duration_cast
<
chrono
::
seconds
>
(
chrono
::
system_clock
::
now
().
time_since_epoch
()).
count
();
// no two capture within SMART_CAP_MIN_SECS seconds
if
(
now
-
smartTsLast
<
SMART_CAP_MIN_SECS
)
{
return
0
;
}
smartTsLast
=
now
;
json
js
;
string
str
=
fmt
::
format
(
"new ai capture: {}, idx = {}, toltal = {}"
,
pstJpegFrame
->
aClassName
,
pstJpegFrame
->
nIndex
,
pstJpegFrame
->
nToltalJpeg
);
spdlog
::
info
(
str
);
MaQueSmartTarget_s
stMaQueSmartTarget
=
{
0
};
// face
int
res
=
LibXmMaQue_SmartGetTarget
(
0
,
&
stMaQueSmartTarget
);
if
(
stMaQueSmartTarget
.
targetFDNum
>
0
)
{
js
[
"face"
]
=
json
();
js
[
"face"
][
"num"
]
=
stMaQueSmartTarget
.
targetFDNum
;
js
[
"face"
][
"minX"
]
=
stMaQueSmartTarget
.
aFDRect
[
0
].
s16X1
;
js
[
"face"
][
"minY"
]
=
stMaQueSmartTarget
.
aFDRect
[
0
].
s16Y1
;
js
[
"face"
][
"maxX"
]
=
stMaQueSmartTarget
.
aFDRect
[
0
].
s16X2
;
js
[
"face"
][
"maxY"
]
=
stMaQueSmartTarget
.
aFDRect
[
0
].
s16Y2
;
}
// pepole
if
(
stMaQueSmartTarget
.
targetPDNum
>
0
)
{
js
[
"pepole"
]
=
json
();
js
[
"pepole"
][
"num"
]
=
stMaQueSmartTarget
.
targetPDNum
;
js
[
"pepole"
][
"minX"
]
=
stMaQueSmartTarget
.
aPDRect
[
0
].
s16X1
;
js
[
"pepole"
][
"minY"
]
=
stMaQueSmartTarget
.
aPDRect
[
0
].
s16Y1
;
js
[
"pepole"
][
"maxX"
]
=
stMaQueSmartTarget
.
aPDRect
[
0
].
s16X2
;
js
[
"pepole"
][
"maxY"
]
=
stMaQueSmartTarget
.
aPDRect
[
0
].
s16Y2
;
}
if
(
mod
!=
nullptr
&&
mod
->
pClient
!=
nullptr
)
{
string
b64
;
vector
<
uint8_t
>
vec
(
pstJpegFrame
->
pBuffer
,
pstJpegFrame
->
pBuffer
+
pstJpegFrame
->
nDataLen
-
1
);
jsoncons
::
encode_base64
<
vector
<
uint8_t
>::
iterator
,
string
>
(
vec
.
begin
(),
vec
.
end
(),
b64
);
js
[
"data"
]
=
b64
;
js
[
consts
::
kMsgType
]
=
consts
::
kMsgTypeImage
;
js
[
consts
::
kMsgEncode
]
=
consts
::
kMsgEncodeBase64
;
js
[
consts
::
kMsgFormat
]
=
consts
::
kMsgFormatJpeg
;
MqttMgr
::
report_response_args
(
client
,
consts
::
pub_topic_response
+
client
->
id
,
0
,
str
,
"ai_image"
,
""
,
js
);
}
return
XM_SUCCESS
;
}
...
...
@@ -98,8 +125,13 @@ XM_S32 MaQue_Draw_OsdAreaRect(MaQueStreamChannel_e eStreamChn, XM_S32 enable, XM
return
XM_SUCCESS
;
}
void
maq_smart_task_entry
(
void
*
pArg
)
void
maq_smart_task_entry
(
ev_module_config_t
*
pArg
)
{
if
(
!
pArg
->
enabled
)
{
spdlog
::
warn
(
"ai detection is disabled"
);
return
;
}
spdlog
::
info
(
"starting ai detection task"
);
XM_S32
res
;
MaQueStreamChannel_e
eStreamChn
;
MaQueSmartParams_s
stMaQueSmartParams
;
...
...
@@ -228,13 +260,13 @@ void maq_smart_task_entry(void *pArg)
return
;
}
res
=
LibXmMaQue_SmartPDThreshold
(
0
,
p
dThreshold
);
res
=
LibXmMaQue_SmartPDThreshold
(
0
,
p
Arg
->
module
.
ai
.
human_thresh
);
if
(
XM_SUCCESS
!=
res
)
{
spdlog
::
error
(
"LibXmMaQue_SmartPDThreshold() Failed!"
);
return
;
}
res
=
LibXmMaQue_SmartFDThreshold
(
0
,
fdThreshold
);
res
=
LibXmMaQue_SmartFDThreshold
(
0
,
pArg
->
module
.
ai
.
face_thresh
);
if
(
XM_SUCCESS
!=
res
)
{
spdlog
::
error
(
"LibXmMaQue_SmartFDThreshold() Failed!"
);
return
;
...
...
@@ -242,11 +274,14 @@ void maq_smart_task_entry(void *pArg)
stCallback
.
eType
=
MAQUE_SMART_JPEG_ENCODE_LARGE
;
//MAQUE_SMART_JPEG_ENCODE_CUTOUT;
stCallback
.
eClass
=
MAQUE_SMART_JPEG_CLASS_NONE
;
//MAQUE_SMART_JPEG_CLASS_FD;
stCallback
.
stCallback
.
pCallbackArg
=
NULL
;
stCallback
.
stCallback
.
pCallbackArg
=
pArg
;
stCallback
.
stCallback
.
pCallbackFuncPtr
=
MaQue_JpegEnc_getFrame_callback
;
LibXmMaQue_SmartRegisterCallback
(
0
,
&
stCallback
);
while
(
1
)
{
this_thread
::
sleep_for
(
3
s
);
continue
;
res
=
LibXmMaQue_SmartGetTarget
(
0
,
&
stMaQueSmartTarget
);
if
(
XM_SUCCESS
!=
res
)
{
spdlog
::
error
(
"LibXmMaQue_SmartGetTarget() Failed!"
);
...
...
@@ -272,7 +307,6 @@ void maq_smart_task_entry(void *pArg)
if
(
stMaQueSmartTarget
.
targetFDNum
>
0
)
{
printf
(
"
\n\n
Face Detection : TotalNum %d
\n
"
,
stMaQueSmartTarget
.
targetFDNum
);
for
(
i
=
0
;
i
<
stMaQueSmartTarget
.
targetFDNum
;
i
++
)
{
printf
(
"(%d, %d), (%d, %d)
\n
"
,
stMaQueSmartTarget
.
aFDRect
[
i
].
s16X1
,
stMaQueSmartTarget
.
aFDRect
[
i
].
s16Y1
,
stMaQueSmartTarget
.
aFDRect
[
i
].
s16X2
,
stMaQueSmartTarget
.
aFDRect
[
i
].
s16Y2
);
...
...
hi3518/smart.h
浏览文件 @
61621d77
...
...
@@ -2,7 +2,8 @@
#define __EV_SMART_HPP__
#pragma once
#include "internal_types.h"
void
maq_smart_task_entry
(
void
*
pArg
);
void
maq_smart_task_entry
(
ev_module_config_t
*
pArg
);
#endif
\ No newline at end of file
include/evpacket.h
浏览文件 @
61621d77
...
...
@@ -61,4 +61,6 @@ static inline unsigned short crc16(const unsigned char* data_p, unsigned char le
return
crc
;
}
#endif
\ No newline at end of file
include/mqtt_helper.hpp
浏览文件 @
61621d77
...
...
@@ -28,6 +28,8 @@ using namespace std;
using
namespace
jsoncons
;
using
namespace
evutils
;
#define EV_MAX_PRINTABLE_SIZE 512
extern
void
on_connected
(
void
*
context
,
MQTTAsync_successData
*
response
);
extern
void
on_connlost
(
void
*
context
,
char
*
cause
);
extern
int
on_msgarrvd
(
void
*
context
,
char
*
topic
,
int
topicLen
,
MQTTAsync_message
*
message
);
...
...
@@ -142,7 +144,7 @@ public:
spdlog
::
debug
(
"mqtt url: proto: {}, host: {}, port: {}, user: {}, pass: {}"
,
uri
.
Protocol
,
uri
.
Host
,
uri
.
Port
,
uri
.
User
,
uri
.
Password
);
if
(
MQTTASYNC_SUCCESS
!=
MQTTAsync_create
(
&
client
,
addr
.
c_str
(),
(
string
(
"EVC"
)
+
id
).
c_str
(),
MQTTCLIENT_PERSISTENCE_NONE
,
NULL
))
{
if
(
MQTTASYNC_SUCCESS
!=
MQTTAsync_create
(
&
client
,
addr
.
c_str
(),
(
"EVC"
+
id
).
c_str
(),
MQTTCLIENT_PERSISTENCE_NONE
,
NULL
))
{
msg
=
"failed to async create mqtt"
;
spdlog
::
error
(
msg
);
throw
StrException
(
msg
);
...
...
@@ -303,7 +305,7 @@ class MqttMgr {
lock_guard
<
mutex
>
lg
(
MqttMgr
::
mut
);
try
{
if
(
MqttMgr
::
insts
.
count
(
key
)
==
0
){
auto
inst
=
new
MqttHelper
(
mqtt_url
,
"evc."
+
devsn
);
auto
inst
=
new
MqttHelper
(
mqtt_url
,
devsn
);
MqttMgr
::
insts
[
key
]
=
inst
;
}
else
{
//
...
...
@@ -345,6 +347,10 @@ class MqttMgr {
return
;
}
auto
rc
=
(
*
client
)[
topic
].
pub
(
message
.
c_str
(),
message
.
size
(),
2
,
false
);
if
(
message
.
size
()
>
EV_MAX_PRINTABLE_SIZE
){
string
ellipsis
=
" <...> "
;
message
=
message
.
substr
(
0
,
EV_MAX_PRINTABLE_SIZE
/
2
-
ellipsis
.
size
())
+
ellipsis
+
message
.
substr
(
EV_MAX_PRINTABLE_SIZE
/
2
,
EV_MAX_PRINTABLE_SIZE
/
2
);
}
if
(
rc
<
0
)
{
spdlog
::
error
(
"failed to pub mqtt message on {}: {}"
,
topic
,
message
);
}
...
...
@@ -398,6 +404,9 @@ class MqttMgr {
js
.
insert_or_assign
(
consts
::
kMsgCode
,
code
);
js
.
insert_or_assign
(
consts
::
kMsgMsg
,
message
);
js
.
insert_or_assign
(
consts
::
kMsgSn
,
client
->
id
);
if
(
!
data
.
empty
()){
js
.
insert_or_assign
(
consts
::
kMsgData
,
data
);
}
_report_response
(
client
,
topic
,
js
.
to_string
());
}
...
...
@@ -422,6 +431,9 @@ class MqttMgr {
js
.
insert_or_assign
(
consts
::
kMsgCode
,
code
);
js
.
insert_or_assign
(
consts
::
kMsgMsg
,
message
);
js
.
insert_or_assign
(
consts
::
kMsgSn
,
client
->
id
);
if
(
!
data
.
empty
()){
js
.
insert_or_assign
(
consts
::
kMsgData
,
data
);
}
_report_response
(
client
,
topic
,
js
.
to_string
());
}
...
...
server/videogateway.cc
浏览文件 @
61621d77
...
...
@@ -138,12 +138,13 @@ int write_packet(packet_processor_t *processor, char *data, int len)
pkt
.
size
=
len
;
AVRational
time_base
;
char
*
fps
=
getenv
(
"FPS"
);
if
(
processor
->
hdr
.
vpara
.
fps
>
0
&&
processor
->
hdr
.
vpara
.
fps
<
100
){
if
(
processor
->
hdr
.
vpara
.
fps
>
0
&&
processor
->
hdr
.
vpara
.
fps
<
100
)
{
time_base
.
den
=
processor
->
hdr
.
vpara
.
fps
;
}
else
{
}
else
{
time_base
.
den
=
15
;
}
if
(
fps
){
if
(
fps
)
{
time_base
.
den
=
atoi
(
fps
);
}
time_base
.
num
=
1
;
...
...
@@ -162,7 +163,8 @@ int write_packet(packet_processor_t *processor, char *data, int len)
}
int
setupRouter
(
void
**
ctx
,
void
**
s
,
string
addr
,
int
rcvQS
=
0
){
int
setupRouter
(
void
**
ctx
,
void
**
s
,
string
addr
,
int
rcvQS
=
0
)
{
int
ret
=
0
;
*
ctx
=
zmq_ctx_new
();
*
s
=
zmq_socket
(
*
ctx
,
ZMQ_ROUTER
);
...
...
@@ -183,7 +185,8 @@ int setupRouter(void **ctx, void **s, string addr, int rcvQS=0){
return
ret
;
}
int
z_recv_multiple
(
void
*
s
,
vector
<
uint8_t
>
&
buf
,
vector
<
int
>&
frameIdx
)
{
int
z_recv_multiple
(
void
*
s
,
vector
<
uint8_t
>
&
buf
,
vector
<
int
>&
frameIdx
)
{
int64_t
more
=
1
;
size_t
more_size
=
sizeof
(
more
);
int
ret
=
0
;
...
...
@@ -222,20 +225,21 @@ int z_recv_multiple(void *s, vector<uint8_t> &buf, vector<int>&frameIdx) {
packet_processor_t
globalProcess
=
{
0
};
void
dispatch
(
string
sn
,
zmq_msg_t
&
msg
){
void
dispatch
(
string
sn
,
zmq_msg_t
&
msg
)
{
evpacket_t
*
pkt
=
(
evpacket_t
*
)
zmq_msg_data
(
&
msg
);
globalProcess
.
packetId
++
;
//debugHex((char*)zmq_msg_data(&msg), 64);
auto
crc
=
pkt
->
meta
.
crc
;
pkt
->
meta
.
crc
=
0
;
auto
crc_
=
crc16
((
unsigned
char
*
)
pkt
,
sizeof
(
evpacket_t
));
if
(
crc
!=
crc_
){
if
(
crc
!=
crc_
)
{
spdlog
::
error
(
"invalid crc: {}"
,
pkt
->
meta
.
packet_id
);
return
;
}
if
(
globalProcess
.
pAvCtx
==
nullptr
&&
globalProcess
.
packetId
%
15
*
10
==
0
){
if
(
globalProcess
.
pAvCtx
==
nullptr
&&
globalProcess
.
packetId
%
15
*
10
==
0
)
{
int
rc
=
0
;
globalProcess
.
pAvCtx
=
rtsp_init
(
darwinUrl
+
sn
,
0
,
1080
,
1920
,
&
rc
);
if
(
globalProcess
.
pAvCtx
==
nullptr
||
rc
<
0
)
{
...
...
@@ -247,7 +251,7 @@ void dispatch(string sn, zmq_msg_t &msg){
int
ret
=
write_packet
(
&
globalProcess
,
(
char
*
)
zmq_msg_data
(
&
msg
)
+
sizeof
(
evpacket_t
),
zmq_msg_size
(
&
msg
)
-
sizeof
(
evpacket_t
)
);
if
(
ret
<
0
)
{
spdlog
::
error
(
"failed to send packet!"
);
if
(
globalProcess
.
pAvCtx
&&
globalProcess
.
pAvCtx
->
pb
)
{
if
(
globalProcess
.
pAvCtx
&&
globalProcess
.
pAvCtx
->
pb
)
{
avio_closep
(
&
globalProcess
.
pAvCtx
->
pb
);
}
if
(
globalProcess
.
pAvCtx
)
{
...
...
@@ -278,11 +282,11 @@ int main()
void
*
pRouterCtx
=
nullptr
,
*
pRouter
=
nullptr
/*, *pDealerCtx = nullptr, *pDealer = nullptr*/
;
setupRouter
(
&
pRouterCtx
,
&
pRouter
,
addr
,
10
);
while
(
1
){
while
(
1
)
{
int64_t
more
=
1
;
size_t
more_size
=
sizeof
(
more
);
int
ret
=
0
;
zmq_msg_t
msg
;
zmq_msg_t
msg
;
ret
=
zmq_msg_init
(
&
msg
);
if
(
ret
<
0
)
{
spdlog
::
debug
(
"failed to receive multiple msg on zmq_msg_init: {}"
,
zmq_strerror
(
zmq_errno
()));
...
...
@@ -309,11 +313,12 @@ int main()
break
;
}
dispatch
(
sn
,
msg
);
}
else
{
}
else
{
spdlog
::
error
(
"invalid packet fmt"
);
}
zmq_msg_close
(
&
msg
);
zmq_msg_close
(
&
msg
);
if
(
ret
<
0
)
{
spdlog
::
error
(
"failed to recv msg: {}"
,
ret
<
0
?
zmq_strerror
(
ret
)
:
"invalid frames"
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论