Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ModelZoo
deepstream-app
Commits
24460ef5
Commit
24460ef5
authored
Mar 20, 2026
by
das-qa
Browse files
Add python demo: deepstream-test1, deepstream-test2, deepstream-test3 and deepstream-test4
parent
77e9fc8c
Changes
169
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
5424 additions
and
6 deletions
+5424
-6
sugon_apps/python_app/apps/deepstream-test4/cfg_redis.txt
sugon_apps/python_app/apps/deepstream-test4/cfg_redis.txt
+25
-0
sugon_apps/python_app/apps/deepstream-test4/deepstream_test_4.py
...pps/python_app/apps/deepstream-test4/deepstream_test_4.py
+478
-0
sugon_apps/python_app/apps/deepstream-test4/dstest4_config.yml
..._apps/python_app/apps/deepstream-test4/dstest4_config.yml
+40
-0
sugon_apps/python_app/apps/deepstream-test4/dstest4_msgconv_config.txt
...thon_app/apps/deepstream-test4/dstest4_msgconv_config.txt
+48
-0
sugon_apps/python_app/apps/deepstream-test4/dstest4_msgconv_config.yml
...thon_app/apps/deepstream-test4/dstest4_msgconv_config.yml
+48
-0
sugon_apps/python_app/apps/deepstream-test4/dstest4_pgie_config.txt
.../python_app/apps/deepstream-test4/dstest4_pgie_config.txt
+79
-0
sugon_apps/python_app/apps/deepstream-test4/dstest4_pgie_nvinferserver_config.txt
...ps/deepstream-test4/dstest4_pgie_nvinferserver_config.txt
+74
-0
sugon_apps/python_app_nvidia
sugon_apps/python_app_nvidia
+1
-0
sugon_apps/sample_apps/deepstream-app/Makefile
sugon_apps/sample_apps/deepstream-app/Makefile
+71
-0
sugon_apps/sample_apps/deepstream-app/README
sugon_apps/sample_apps/deepstream-app/README
+78
-0
sugon_apps/sample_apps/deepstream-app/deepstream_app.c
sugon_apps/sample_apps/deepstream-app/deepstream_app.c
+2087
-0
sugon_apps/sample_apps/deepstream-app/deepstream_app.h
sugon_apps/sample_apps/deepstream-app/deepstream_app.h
+266
-0
sugon_apps/sample_apps/deepstream-app/deepstream_app_config_parser.c
...sample_apps/deepstream-app/deepstream_app_config_parser.c
+793
-0
sugon_apps/sample_apps/deepstream-app/deepstream_app_config_parser_yaml.cpp
...apps/deepstream-app/deepstream_app_config_parser_yaml.cpp
+452
-0
sugon_apps/sample_apps/deepstream-app/deepstream_app_main.c
sugon_apps/sample_apps/deepstream-app/deepstream_app_main.c
+876
-0
sugon_apps/sample_apps/deepstream-test1/dstest1_config.yml
sugon_apps/sample_apps/deepstream-test1/dstest1_config.yml
+2
-1
sugon_apps/sample_apps/deepstream-test1/dstest1_pgie_nvinferserver_config.txt
...ps/deepstream-test1/dstest1_pgie_nvinferserver_config.txt
+1
-1
sugon_apps/sample_apps/deepstream-test2/deepstream_test2_app.c
..._apps/sample_apps/deepstream-test2/deepstream_test2_app.c
+1
-1
sugon_apps/sample_apps/deepstream-test2/dstest2_config.yml
sugon_apps/sample_apps/deepstream-test2/dstest2_config.yml
+3
-2
sugon_apps/sample_apps/deepstream-test2/dstest2_pgie_nvinferserver_config.txt
...ps/deepstream-test2/dstest2_pgie_nvinferserver_config.txt
+1
-1
No files found.
sugon_apps/python_app/apps/deepstream-test4/cfg_redis.txt
0 → 100644
View file @
24460ef5
################################################################################
# SPDX-FileCopyrightText: Copyright (c) 2020-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################
[message-broker]
#hostname=localhost
#port=6379
#streamsize=10000
#payloadkey=metadata
#consumergroup=mygroup
#consumername=myname
#share-connection = 1
sugon_apps/python_app/apps/deepstream-test4/deepstream_test_4.py
0 → 100644
View file @
24460ef5
#!/usr/bin/env python3
################################################################################
# SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Python port of sugon_apps/sample_apps/deepstream-test4/deepstream_test4_app.c
#
# Pipeline (与 C 非 YAML 模式一致):
# filesrc -> h264parse -> mach264dec -> nvstreammux -> pgie -> nvdsosd -> tee
# tee -> queue -> nvmsgconv -> nvmsgbroker
# tee -> queue -> fakesink
#
# 说明:
# - 默认 pgie 为 nvinferserver,配置 dstest4_pgie_nvinferserver_config.txt(与 C 默认一致)
# 环境变量 DEEPSTREAM_PGIE=nvinfer 时使用 nvinfer + dstest4_pgie_config.txt
# - C 中 YAML 整表解析 (nvds_yml_parser) 本脚本未实现;请使用命令行参数
# python3.10 deepstream_test_4.py -i /workspace/shared_docker/video/cr7_1920x1080.h264 -p /opt/deepstream/lib/libnvds_mqtt_proto.so --conn-str="127.0.0.1;1883;/server/fromArm"
################################################################################
from
__future__
import
annotations
import
argparse
import
os
import
sys
sys
.
path
.
append
(
"../"
)
import
gi
gi
.
require_version
(
"Gst"
,
"1.0"
)
from
gi.repository
import
Gst
import
pyds
from
common.utils
import
long_to_uint64
MAX_DISPLAY_LEN
=
64
MAX_TIME_STAMP_LEN
=
32
PGIE_CLASS_ID_VEHICLE
=
0
PGIE_CLASS_ID_PERSON
=
2
MUXER_OUTPUT_WIDTH
=
1920
MUXER_OUTPUT_HEIGHT
=
1080
MUXER_BATCH_TIMEOUT_USEC
=
40000
MSCONV_CONFIG_FILE
=
"dstest4_msgconv_config.txt"
PGIE_CONFIG_NVINFERSERVER
=
"dstest4_pgie_nvinferserver_config.txt"
PGIE_CONFIG_NVINFER
=
"dstest4_pgie_config.txt"
pgie_classes_str
=
[
"Vehicle"
,
"TwoWheeler"
,
"Person"
,
"Roadsign"
]
DEFAULT_DECODER
=
os
.
environ
.
get
(
"DEEPSTREAM_DECODER"
,
"mach264dec"
)
# 仅用于规避少数环境下 EOS 后解释器退出阶段的段错误:
# export DEEPSTREAM_PYTHON_EXIT_HARD=1
FORCE_HARD_EXIT
=
os
.
environ
.
get
(
"DEEPSTREAM_PYTHON_EXIT_HARD"
,
"0"
)
==
"1"
# 运行期由 parse_args 设置,供 probe 使用
_frame_interval
=
30
_msg2p_meta
=
0
class
_RunState
:
def
__init__
(
self
):
self
.
pipeline
=
None
self
.
bus
=
None
self
.
is_running
=
False
self
.
osd_sink_pad
=
None
self
.
osd_probe_id
=
None
self
.
_cleaned
=
False
def
cleanup
(
self
):
# Backtrace 显示 coredump 发生在 gst_pad_remove_probe() 的 GI closure free 阶段。
# 因此这里避免显式 remove_probe,让 pipeline 进入 NULL 时由 GStreamer 统一清理。
# 同时将 _cleaned 提前置位,防止 EOS/ERROR/异常路径重入 cleanup 引发重复释放。
if
self
.
_cleaned
:
return
self
.
_cleaned
=
True
self
.
is_running
=
False
self
.
osd_probe_id
=
None
self
.
osd_sink_pad
=
None
if
self
.
bus
is
not
None
:
try
:
self
.
bus
.
set_flushing
(
True
)
except
Exception
:
pass
self
.
bus
=
None
if
self
.
pipeline
:
print
(
"Stopping pipeline..."
)
self
.
pipeline
.
set_state
(
Gst
.
State
.
NULL
)
self
.
pipeline
.
get_state
(
5
*
Gst
.
SECOND
)
print
(
"Pipeline stopped"
)
self
.
pipeline
=
None
def
handle_message
(
msg
:
Gst
.
Message
,
state
:
_RunState
)
->
None
:
t
=
msg
.
type
if
t
==
Gst
.
MessageType
.
EOS
:
print
(
"
\n
End of stream"
)
state
.
cleanup
()
if
FORCE_HARD_EXIT
:
os
.
_exit
(
0
)
elif
t
==
Gst
.
MessageType
.
ERROR
:
err
,
debug
=
msg
.
parse_error
()
print
(
f
"Error:
{
err
}
"
)
if
debug
:
print
(
f
"Debug:
{
debug
}
"
)
state
.
cleanup
()
elif
t
==
Gst
.
MessageType
.
WARNING
:
err
,
debug
=
msg
.
parse_warning
()
print
(
f
"Warning:
{
err
}
"
)
if
debug
:
print
(
f
"Debug:
{
debug
}
"
)
elif
t
==
Gst
.
MessageType
.
STATE_CHANGED
:
if
state
.
pipeline
and
msg
.
src
==
state
.
pipeline
:
o
,
n
,
_p
=
msg
.
parse_state_changed
()
print
(
f
"Pipeline state:
{
o
.
value_nick
}
->
{
n
.
value_nick
}
"
)
def
generate_vehicle_meta
(
data
):
obj
=
pyds
.
NvDsVehicleObject
.
cast
(
data
)
obj
.
type
=
"sedan"
obj
.
color
=
"blue"
obj
.
make
=
"Bugatti"
obj
.
model
=
"M"
obj
.
license
=
"XX1234"
obj
.
region
=
"CA"
return
obj
def
generate_person_meta
(
data
):
obj
=
pyds
.
NvDsPersonObject
.
cast
(
data
)
obj
.
age
=
45
obj
.
cap
=
"none"
obj
.
hair
=
"black"
obj
.
gender
=
"male"
obj
.
apparel
=
"formal"
return
obj
def
generate_event_msg_meta
(
data
,
class_id
):
meta
=
pyds
.
NvDsEventMsgMeta
.
cast
(
data
)
meta
.
sensorId
=
0
meta
.
placeId
=
0
meta
.
moduleId
=
0
meta
.
sensorStr
=
"sensor-0"
meta
.
ts
=
pyds
.
alloc_buffer
(
MAX_TIME_STAMP_LEN
+
1
)
pyds
.
generate_ts_rfc3339
(
meta
.
ts
,
MAX_TIME_STAMP_LEN
)
if
class_id
==
PGIE_CLASS_ID_VEHICLE
:
meta
.
type
=
pyds
.
NvDsEventType
.
NVDS_EVENT_MOVING
meta
.
objType
=
pyds
.
NvDsObjectType
.
NVDS_OBJECT_TYPE_VEHICLE
meta
.
objClassId
=
PGIE_CLASS_ID_VEHICLE
obj
=
pyds
.
alloc_nvds_vehicle_object
()
obj
=
generate_vehicle_meta
(
obj
)
meta
.
extMsg
=
obj
meta
.
extMsgSize
=
sys
.
getsizeof
(
pyds
.
NvDsVehicleObject
)
elif
class_id
==
PGIE_CLASS_ID_PERSON
:
meta
.
type
=
pyds
.
NvDsEventType
.
NVDS_EVENT_ENTRY
meta
.
objType
=
pyds
.
NvDsObjectType
.
NVDS_OBJECT_TYPE_PERSON
meta
.
objClassId
=
PGIE_CLASS_ID_PERSON
obj
=
pyds
.
alloc_nvds_person_object
()
obj
=
generate_person_meta
(
obj
)
meta
.
extMsg
=
obj
meta
.
extMsgSize
=
sys
.
getsizeof
(
pyds
.
NvDsPersonObject
)
return
meta
def
osd_sink_pad_buffer_probe
(
pad
,
info
,
u_data
):
"""与 C 中 osd_sink_pad_buffer_metadata_probe (msg2p_meta==0) 及 NVIDIA Python 样例对齐。"""
state
=
u_data
if
state
is
not
None
and
not
state
.
is_running
:
return
Gst
.
PadProbeReturn
.
OK
global
_frame_interval
,
_msg2p_meta
if
_msg2p_meta
!=
0
:
return
Gst
.
PadProbeReturn
.
OK
obj_counter
=
{
0
:
0
,
1
:
0
,
2
:
0
,
3
:
0
}
gst_buffer
=
info
.
get_buffer
()
if
not
gst_buffer
:
return
Gst
.
PadProbeReturn
.
OK
batch_meta
=
pyds
.
gst_buffer_get_nvds_batch_meta
(
hash
(
gst_buffer
))
if
not
batch_meta
:
return
Gst
.
PadProbeReturn
.
OK
frame_number
=
0
l_frame
=
batch_meta
.
frame_meta_list
while
l_frame
is
not
None
:
try
:
frame_meta
=
pyds
.
NvDsFrameMeta
.
cast
(
l_frame
.
data
)
except
StopIteration
:
break
is_first_object
=
True
frame_number
=
frame_meta
.
frame_num
l_obj
=
frame_meta
.
obj_meta_list
while
l_obj
is
not
None
:
try
:
obj_meta
=
pyds
.
NvDsObjectMeta
.
cast
(
l_obj
.
data
)
except
StopIteration
:
break
txt_params
=
obj_meta
.
text_params
cid
=
obj_meta
.
class_id
if
0
<=
cid
<
len
(
pgie_classes_str
):
txt_params
.
display_text
=
pgie_classes_str
[
cid
]
if
cid
in
obj_counter
:
obj_counter
[
cid
]
=
obj_counter
[
cid
]
+
1
txt_params
.
font_params
.
font_name
=
"Serif"
txt_params
.
font_params
.
font_size
=
10
txt_params
.
font_params
.
font_color
.
set
(
1.0
,
1.0
,
1.0
,
1.0
)
txt_params
.
set_bg_clr
=
1
txt_params
.
text_bg_clr
.
set
(
0.0
,
0.0
,
0.0
,
1.0
)
if
is_first_object
and
(
frame_number
%
_frame_interval
)
==
0
:
user_event_meta
=
pyds
.
nvds_acquire_user_meta_from_pool
(
batch_meta
)
if
user_event_meta
:
msg_meta
=
pyds
.
alloc_nvds_event_msg_meta
(
user_event_meta
)
msg_meta
.
bbox
.
top
=
obj_meta
.
rect_params
.
top
msg_meta
.
bbox
.
left
=
obj_meta
.
rect_params
.
left
msg_meta
.
bbox
.
width
=
obj_meta
.
rect_params
.
width
msg_meta
.
bbox
.
height
=
obj_meta
.
rect_params
.
height
msg_meta
.
frameId
=
frame_number
msg_meta
.
trackingId
=
long_to_uint64
(
obj_meta
.
object_id
)
msg_meta
.
confidence
=
obj_meta
.
confidence
msg_meta
=
generate_event_msg_meta
(
msg_meta
,
obj_meta
.
class_id
)
user_event_meta
.
user_meta_data
=
msg_meta
user_event_meta
.
base_meta
.
meta_type
=
pyds
.
NvDsMetaType
.
NVDS_EVENT_MSG_META
pyds
.
nvds_add_user_meta_to_frame
(
frame_meta
,
user_event_meta
)
is_first_object
=
False
try
:
l_obj
=
l_obj
.
next
except
StopIteration
:
break
try
:
l_frame
=
l_frame
.
next
except
StopIteration
:
break
print
(
"Frame Number ="
,
frame_number
,
"Vehicle Count ="
,
obj_counter
.
get
(
PGIE_CLASS_ID_VEHICLE
,
0
),
"Person Count ="
,
obj_counter
.
get
(
PGIE_CLASS_ID_PERSON
,
0
),
)
return
Gst
.
PadProbeReturn
.
OK
def
build_pipeline
(
args
:
argparse
.
Namespace
)
->
tuple
[
Gst
.
Pipeline
,
_RunState
]:
use_nvinfer
=
os
.
environ
.
get
(
"DEEPSTREAM_PGIE"
,
""
).
lower
()
==
"nvinfer"
if
use_nvinfer
:
pgie
=
Gst
.
ElementFactory
.
make
(
"nvinfer"
,
"primary-nvinference-engine"
)
pgie_cfg
=
PGIE_CONFIG_NVINFER
else
:
pgie
=
Gst
.
ElementFactory
.
make
(
"nvinferserver"
,
"primary-nvinference-engine"
)
pgie_cfg
=
PGIE_CONFIG_NVINFERSERVER
pipeline
=
Gst
.
Pipeline
.
new
(
"dstest4-pipeline"
)
source
=
Gst
.
ElementFactory
.
make
(
"filesrc"
,
"file-source"
)
h264parser
=
Gst
.
ElementFactory
.
make
(
"h264parse"
,
"h264-parser"
)
decoder
=
Gst
.
ElementFactory
.
make
(
DEFAULT_DECODER
,
"mach264dec-decoder"
)
streammux
=
Gst
.
ElementFactory
.
make
(
"nvstreammux"
,
"nvstreammux"
)
nvosd
=
Gst
.
ElementFactory
.
make
(
"nvdsosd"
,
"nv-onscreendisplay"
)
msgconv
=
Gst
.
ElementFactory
.
make
(
"nvmsgconv"
,
"nvmsg-converter"
)
msgbroker
=
Gst
.
ElementFactory
.
make
(
"nvmsgbroker"
,
"nvmsg-broker"
)
tee
=
Gst
.
ElementFactory
.
make
(
"tee"
,
"nvsink-tee"
)
queue1
=
Gst
.
ElementFactory
.
make
(
"queue"
,
"nvtee-que1"
)
queue2
=
Gst
.
ElementFactory
.
make
(
"queue"
,
"nvtee-que2"
)
sink
=
Gst
.
ElementFactory
.
make
(
"fakesink"
,
"nvvideo-renderer"
)
els
=
[
pipeline
,
source
,
h264parser
,
decoder
,
streammux
,
pgie
,
nvosd
,
msgconv
,
msgbroker
,
tee
,
queue1
,
queue2
,
sink
,
]
if
not
all
(
els
):
raise
RuntimeError
(
"One or more GStreamer elements could not be created"
)
source
.
set_property
(
"location"
,
args
.
input_file
)
streammux
.
set_property
(
"batch-size"
,
1
)
streammux
.
set_property
(
"width"
,
MUXER_OUTPUT_WIDTH
)
streammux
.
set_property
(
"height"
,
MUXER_OUTPUT_HEIGHT
)
streammux
.
set_property
(
"batched-push-timeout"
,
MUXER_BATCH_TIMEOUT_USEC
)
pgie
.
set_property
(
"config-file-path"
,
pgie_cfg
)
msgconv
.
set_property
(
"config"
,
MSCONV_CONFIG_FILE
)
msgconv
.
set_property
(
"payload-type"
,
args
.
schema_type
)
try
:
msgconv
.
set_property
(
"msg2p-newapi"
,
args
.
msg2p_meta
)
except
Exception
:
pass
try
:
msgconv
.
set_property
(
"frame-interval"
,
args
.
frame_interval
)
except
Exception
:
pass
msgbroker
.
set_property
(
"proto-lib"
,
args
.
proto_lib
)
msgbroker
.
set_property
(
"conn-str"
,
args
.
conn_str
)
msgbroker
.
set_property
(
"sync"
,
False
)
if
args
.
cfg_file
:
msgbroker
.
set_property
(
"config"
,
args
.
cfg_file
)
if
args
.
topic
:
msgbroker
.
set_property
(
"topic"
,
args
.
topic
)
sink
.
set_property
(
"sync"
,
True
)
for
e
in
(
source
,
h264parser
,
decoder
,
streammux
,
pgie
,
nvosd
,
tee
,
queue1
,
queue2
,
msgconv
,
msgbroker
,
sink
,
):
pipeline
.
add
(
e
)
if
not
source
.
link
(
h264parser
)
or
not
h264parser
.
link
(
decoder
):
raise
RuntimeError
(
"Failed to link decode chain"
)
sinkpad
=
streammux
.
request_pad_simple
(
"sink_0"
)
srcpad
=
decoder
.
get_static_pad
(
"src"
)
if
not
sinkpad
or
not
srcpad
:
raise
RuntimeError
(
"Failed to get mux/decoder pads"
)
if
srcpad
.
link
(
sinkpad
)
!=
Gst
.
PadLinkReturn
.
OK
:
raise
RuntimeError
(
"Failed to link decoder -> streammux"
)
# 与 C 一致:pgie 直连 nvdsosd(无 nvvideoconvert)
if
not
streammux
.
link
(
pgie
)
or
not
pgie
.
link
(
nvosd
)
or
not
nvosd
.
link
(
tee
):
raise
RuntimeError
(
"Failed to link mux -> pgie -> osd -> tee"
)
if
not
queue1
.
link
(
msgconv
)
or
not
msgconv
.
link
(
msgbroker
):
raise
RuntimeError
(
"Failed to link msg branch"
)
if
not
queue2
.
link
(
sink
):
raise
RuntimeError
(
"Failed to link queue2 -> sink"
)
q1_sink
=
queue1
.
get_static_pad
(
"sink"
)
q2_sink
=
queue2
.
get_static_pad
(
"sink"
)
tee_msg_pad
=
tee
.
request_pad_simple
(
"src_%u"
)
tee_render_pad
=
tee
.
request_pad_simple
(
"src_%u"
)
if
not
all
([
q1_sink
,
q2_sink
,
tee_msg_pad
,
tee_render_pad
]):
raise
RuntimeError
(
"Failed to get tee/queue pads"
)
if
tee_msg_pad
.
link
(
q1_sink
)
!=
Gst
.
PadLinkReturn
.
OK
:
raise
RuntimeError
(
"Failed to link tee -> queue1"
)
if
tee_render_pad
.
link
(
q2_sink
)
!=
Gst
.
PadLinkReturn
.
OK
:
raise
RuntimeError
(
"Failed to link tee -> queue2"
)
state
=
_RunState
()
state
.
pipeline
=
pipeline
state
.
is_running
=
True
osdsinkpad
=
nvosd
.
get_static_pad
(
"sink"
)
if
osdsinkpad
and
args
.
msg2p_meta
==
0
:
state
.
osd_sink_pad
=
osdsinkpad
state
.
osd_probe_id
=
osdsinkpad
.
add_probe
(
Gst
.
PadProbeType
.
BUFFER
,
osd_sink_pad_buffer_probe
,
state
)
elif
not
osdsinkpad
:
sys
.
stderr
.
write
(
"Warning: could not get nvdsosd sink pad
\n
"
)
return
pipeline
,
state
def
parse_args
()
->
argparse
.
Namespace
:
p
=
argparse
.
ArgumentParser
(
description
=
"DeepStream test4 (Python) — message broker + inference"
)
p
.
add_argument
(
"-i"
,
"--input-file"
,
required
=
True
,
help
=
"Input elementary H.264 file"
,
)
p
.
add_argument
(
"-p"
,
"--proto-lib"
,
required
=
True
,
help
=
"Absolute path to nvmsgbroker proto adaptor .so"
,
)
p
.
add_argument
(
"--conn-str"
,
default
=
"localhost;2181;testTopic"
,
help
=
"Broker connection string"
,
)
p
.
add_argument
(
"-c"
,
"--cfg-file"
,
default
=
None
,
help
=
"Adaptor config file for msgbroker"
)
p
.
add_argument
(
"-t"
,
"--topic"
,
default
=
None
,
help
=
"Message topic"
)
p
.
add_argument
(
"-s"
,
"--schema-type"
,
type
=
int
,
default
=
0
,
help
=
"nvmsgconv payload-type (0=full, 1=minimal, 2=protobuf per plugin)"
,
)
p
.
add_argument
(
"--msg2p-meta"
,
type
=
int
,
default
=
0
,
choices
=
(
0
,
1
),
help
=
"0=event NVDS_EVENT_MSG_META (default), 1=custom blob (Python 仅实现 0)"
,
)
p
.
add_argument
(
"--frame-interval"
,
type
=
int
,
default
=
30
,
help
=
"Attach event meta every N frames (first object), default 30"
,
)
args
=
p
.
parse_args
()
global
_frame_interval
,
_msg2p_meta
_frame_interval
=
args
.
frame_interval
_msg2p_meta
=
args
.
msg2p_meta
if
args
.
msg2p_meta
!=
0
:
print
(
"Note: msg2p-meta=1 (image/custom) path is not implemented; running without OSD probe."
)
return
args
def
main
()
->
int
:
args
=
parse_args
()
Gst
.
init
(
None
)
try
:
pipeline
,
state
=
build_pipeline
(
args
)
except
Exception
as
e
:
sys
.
stderr
.
write
(
f
"Failed to build pipeline:
{
e
}
\n
"
)
return
1
print
(
f
"Now playing:
{
args
.
input_file
}
"
)
ret
=
pipeline
.
set_state
(
Gst
.
State
.
PLAYING
)
if
ret
==
Gst
.
StateChangeReturn
.
FAILURE
:
sys
.
stderr
.
write
(
"Failed to set PLAYING
\n
"
)
state
.
cleanup
()
return
1
bus
=
pipeline
.
get_bus
()
state
.
bus
=
bus
print
(
"Running..."
)
try
:
while
state
.
is_running
:
try
:
msg
=
bus
.
timed_pop_filtered
(
100
*
Gst
.
MSECOND
,
Gst
.
MessageType
.
EOS
|
Gst
.
MessageType
.
ERROR
|
Gst
.
MessageType
.
WARNING
|
Gst
.
MessageType
.
STATE_CHANGED
,
)
if
msg
:
handle_message
(
msg
,
state
)
except
KeyboardInterrupt
:
print
(
"
\n
Interrupted"
)
state
.
cleanup
()
break
except
Exception
:
if
not
state
.
_cleaned
:
state
.
cleanup
()
raise
return
0
if
__name__
==
"__main__"
:
sys
.
exit
(
main
())
sugon_apps/python_app/apps/deepstream-test4/dstest4_config.yml
0 → 100644
View file @
24460ef5
################################################################################
# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
#
# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
# property and proprietary rights in and to this material, related
# documentation and any modifications thereto. Any use, reproduction,
# disclosure or distribution of this material and related documentation
# without an express license agreement from NVIDIA CORPORATION or
# its affiliates is strictly prohibited.
################################################################################
source
:
location
:
../../../streams/cr7_1920x1080.h264
streammux
:
batch-size
:
1
batched-push-timeout
:
40000
width
:
1920
height
:
1080
msgconv
:
#If you want to send images, please set the "payload-type: 1" and "msg2p-newapi: 1"
payload-type
:
1
msg2p-newapi
:
1
frame-interval
:
30
msgbroker
:
proto-lib
:
/opt/deepstream/lib/libnvds_mqtt_proto.so
conn-str
:
127.0.0.1;1883
topic
:
/server/fromArm
sync
:
0
sink
:
sync
:
1
# Inference using nvinferserver:
primary-gie
:
plugin-type
:
1
config-file-path
:
yolov5_nvinferserver_config.txt
sugon_apps/python_app/apps/deepstream-test4/dstest4_msgconv_config.txt
0 → 100644
View file @
24460ef5
################################################################################
# SPDX-FileCopyrightText: Copyright (c) 2018-2019 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
#
# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
# property and proprietary rights in and to this material, related
# documentation and any modifications thereto. Any use, reproduction,
# disclosure or distribution of this material and related documentation
# without an express license agreement from NVIDIA CORPORATION or
# its affiliates is strictly prohibited.
################################################################################
[sensor0]
enable=1
type=Camera
id=CAMERA_ID
location=45.293701447;-75.8303914499;48.1557479338
description="Entrance of Garage Right Lane"
coordinate=5.2;10.1;11.2
[place0]
enable=1
id=1
type=garage
name=XYZ
location=30.32;-40.55;100.0
coordinate=1.0;2.0;3.0
place-sub-field1=walsh
place-sub-field2=lane1
place-sub-field3=P2
[place1]
enable=1
id=1
type=garage
name=XYZ
location=28.47;47.46;1.53
coordinate=1.0;2.0;3.0
place-sub-field1="C-76-2"
place-sub-field2="LEV/EV/CP/ADA"
place-sub-field3=P2
[analytics0]
enable=1
id=XYZ
description="Vehicle Detection and License Plate Recognition"
source=OpenALR
version=1.0
\ No newline at end of file
sugon_apps/python_app/apps/deepstream-test4/dstest4_msgconv_config.yml
0 → 100644
View file @
24460ef5
################################################################################
# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
#
# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
# property and proprietary rights in and to this material, related
# documentation and any modifications thereto. Any use, reproduction,
# disclosure or distribution of this material and related documentation
# without an express license agreement from NVIDIA CORPORATION or
# its affiliates is strictly prohibited.
################################################################################
sensor0
:
enable
:
1
type
:
Camera
id
:
CAMERA_ID
location
:
45.293701447;-75.8303914499;48.1557479338
description
:
"
Entrance
of
Garage
Right
Lane"
coordinate
:
5.2;10.1;11.2
place0
:
enable
:
1
id
:
1
type
:
garage
name
:
XYZ
location
:
30.32;-40.55;100.0
coordinate
:
1.0;2.0;3.0
place-sub-field1
:
walsh
place-sub-field2
:
lane1
place-sub-field3
:
P2
place1
:
enable
:
1
id
:
1
type
:
garage
name
:
XYZ
location
:
28.47;47.46;1.53
coordinate
:
1.0;2.0;3.0
place-sub-field1
:
"
C-76-2"
place-sub-field2
:
"
LEV/EV/CP/ADA"
place-sub-field3
:
P2
analytics0
:
enable
:
1
id
:
XYZ
description
:
"
Vehicle
Detection
and
License
Plate
Recognition"
source
:
OpenALR
version
:
1.0
\ No newline at end of file
sugon_apps/python_app/apps/deepstream-test4/dstest4_pgie_config.txt
0 → 100755
View file @
24460ef5
################################################################################
# SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################
# Following properties are mandatory when engine files are not specified:
# int8-calib-file(Only in INT8)
# Caffemodel mandatory properties: model-file, proto-file, output-blob-names
# UFF: uff-file, input-dims, uff-input-blob-name, output-blob-names
# ONNX: onnx-file
#
# Mandatory properties for detectors:
# num-detected-classes
#
# Optional properties for detectors:
# cluster-mode(Default=Group Rectangles), interval(Primary mode only, Default=0)
# custom-lib-path,
# parse-bbox-func-name
#
# Mandatory properties for classifiers:
# classifier-threshold, is-classifier
#
# Optional properties for classifiers:
# classifier-async-mode(Secondary mode only, Default=false)
#
# Optional properties in secondary mode:
# operate-on-gie-id(Default=0), operate-on-class-ids(Defaults to all classes),
# input-object-min-width, input-object-min-height, input-object-max-width,
# input-object-max-height
#
# Following properties are always recommended:
# batch-size(Default=1)
#
# Other optional properties:
# net-scale-factor(Default=1), network-mode(Default=0 i.e FP32),
# model-color-format(Default=0 i.e. RGB) model-engine-file, labelfile-path,
# mean-file, gie-unique-id(Default=0), offsets, process-mode (Default=1 i.e. primary),
# custom-lib-path, network-mode(Default=0 i.e FP32)
#
# The values in the config file are overridden by values set through GObject
# properties.
[property]
gpu-id=0
net-scale-factor=0.00392156862745098
onnx-file=../../../../samples/models/Primary_Detector/resnet18_trafficcamnet_pruned.onnx
model-engine-file=../../../../samples/models/Primary_Detector/resnet18_trafficcamnet_pruned.onnx_b1_gpu0_fp16.engine
labelfile-path=../../../../samples/models/Primary_Detector/labels.txt
int8-calib-file=../../../../samples/models/Primary_Detector/cal_trt.bin
batch-size=1
process-mode=1
model-color-format=0
## 0=FP32, 1=INT8, 2=FP16 mode
network-mode=2
num-detected-classes=4
interval=0
process-mode=1
model-color-format=0
gie-unique-id=1
#scaling-filter=0
#scaling-compute-hw=0
cluster-mode=2
[class-attrs-all]
pre-cluster-threshold=0.2
topk=20
nms-iou-threshold=0.5
sugon_apps/python_app/apps/deepstream-test4/dstest4_pgie_nvinferserver_config.txt
0 → 100644
View file @
24460ef5
################################################################################
# SPDX-FileCopyrightText: Copyright (c) 2018-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
#
# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
# property and proprietary rights in and to this material, related
# documentation and any modifications thereto. Any use, reproduction,
# disclosure or distribution of this material and related documentation
# without an express license agreement from NVIDIA CORPORATION or
# its affiliates is strictly prohibited.
################################################################################
infer_config {
unique_id: 1
gpu_ids: [0]
max_batch_size: 30
backend {
inputs: [ {
name: "input_1:0"
}]
outputs: [
{name: "output_cov/Sigmoid:0"},
{name: "output_bbox/BiasAdd:0"}
]
triton {
model_name: "Primary_Detector"
version: 1
model_repo {
root: "../../../../sugon_samples/triton_model_repo"
strict_model_config: true
backend_dir: "/opt/deepstream/third_party/backends"
}
}
}
preprocess {
network_format: MEDIA_FORMAT_NONE
tensor_order: TENSOR_ORDER_LINEAR
tensor_name: "input_1:0"
maintain_aspect_ratio: 0
frame_scaling_hw: FRAME_SCALING_HW_DEFAULT
frame_scaling_filter: 1
normalize {
scale_factor: 0.00392156862745098
channel_offsets: [0, 0, 0]
}
}
postprocess {
labelfile_path: "../../../../sugon_samples/labels/Primary_Detector/labels.txt"
detection {
num_detected_classes: 4
per_class_params {
key: 0
value { pre_threshold: 0.4 }
}
nms {
confidence_threshold:0.2
topk:20
iou_threshold:0.5
}
}
}
extra {
copy_input_to_host_buffers: false
output_buffer_pool_size: 2
}
}
input_control {
process_mode: PROCESS_MODE_FULL_FRAME
operate_on_gie_id: -1
interval: 0
}
python_app_nvidia
@
9b27f02f
Subproject commit 9b27f02ffea46a3ded2ad26b3eea27ef3e2dfded
sugon_apps/sample_apps/deepstream-app/Makefile
0 → 100644
View file @
24460ef5
################################################################################
# SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: LicenseRef-NvidiaProprietary
#
# NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
# property and proprietary rights in and to this material, related
# documentation and any modifications thereto. Any use, reproduction,
# disclosure or distribution of this material and related documentation
# without an express license agreement from NVIDIA CORPORATION or
# its affiliates is strictly prohibited.
################################################################################
CUDA_VER
?=
ifeq
($(CUDA_VER),)
$(error
"CUDA_VER is not set"
)
endif
APP
:=
deepstream-app
TARGET_DEVICE
=
$(
shell
gcc
-dumpmachine
|
cut
-f1
-d
-
)
NVDS_VERSION
:=
7.1
LIB_INSTALL_DIR
?=
/opt/nvidia/deepstream/deepstream-
$(NVDS_VERSION)
/lib/
APP_INSTALL_DIR
?=
/opt/nvidia/deepstream/deepstream-
$(NVDS_VERSION)
/bin/
ifeq
($(TARGET_DEVICE),aarch64)
CFLAGS
:=
-DPLATFORM_TEGRA
endif
SRCS
:=
$(
wildcard
*
.c
)
$(
wildcard
*
.cpp
)
SRCS
+=
$(
wildcard
../../apps-common/src/
*
.c
)
SRCS
+=
$(
wildcard
../../apps-common/src/deepstream-yaml/
*
.cpp
)
INCS
:=
$(
wildcard
*
.h
)
PKGS
:=
gstreamer-1.0 gstreamer-video-1.0 x11 json-glib-1.0
OBJS
:=
$(SRCS:.c=.o)
OBJS
:=
$(OBJS:.cpp=.o)
CFLAGS
+=
-I
./
-I
../../apps-common/includes
\
-I
../../../includes
-DDS_VERSION_MINOR
=
1
-DDS_VERSION_MAJOR
=
5
\
-I
/usr/local/cuda-
$(CUDA_VER)
/include
LIBS
:=
-L
/usr/local/cuda-
$(CUDA_VER)
/lib64/
-lcudart
LIBS
+=
-L
$(LIB_INSTALL_DIR)
-lnvdsgst_meta
-lnvds_meta
-lnvdsgst_helper
-lnvdsgst_customhelper
\
-lnvdsgst_smartrecord
-lnvds_utils
-lnvds_msgbroker
-lm
-lyaml-cpp
\
-lcuda
-lgstrtspserver-1
.0
-ldl
-Wl
,-rpath,
$(LIB_INSTALL_DIR)
CFLAGS
+=
$(
shell
pkg-config
--cflags
$(PKGS)
)
LIBS
+=
$(
shell
pkg-config
--libs
$(PKGS)
)
all
:
$(APP)
%.o
:
%.c $(INCS) Makefile
$(CC)
-c
-o
$@
$(CFLAGS)
$<
%.o
:
%.cpp $(INCS) Makefile
$(CXX)
-c
-o
$@
$(CFLAGS)
$<
$(APP)
:
$(OBJS) Makefile
$(CXX)
-o
$(APP)
$(OBJS)
$(LIBS)
install
:
$(APP)
cp
-rv
$(APP)
$(APP_INSTALL_DIR)
clean
:
rm
-rf
$(OBJS)
$(APP)
sugon_apps/sample_apps/deepstream-app/README
0 → 100644
View file @
24460ef5
*****************************************************************************
* SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LicenseRef-NvidiaProprietary
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*****************************************************************************
*****************************************************************************
deepstream-app
README
*****************************************************************************
===============================================================================
1. Prerequisites:
===============================================================================
Follow these procedures to use the deepstream-app application for native
compilation.
You must have the following development packages installed
GStreamer-1.0
GStreamer-1.0 Base Plugins
GStreamer-1.0 gstrtspserver
X11 client-side library
Glib json library - json-glib-1.0
yaml-cpp
EGL graphics interface lib - libegl-mesa0
1. To install these packages, execute the following command:
sudo apt-get install libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev \
libgstrtspserver-1.0-dev libx11-dev libjson-glib-dev libyaml-cpp-dev \
libgbm1 libglapi-mesa libgles2-mesa-dev
Note:
Minimum installation version for libgbm1, libglapi-mesa and libgles2-mesa-dev
should be >= 23.0.4-0ubuntu1~22.04.1
===============================================================================
2. Purpose:
===============================================================================
This document shall describe about the sample deepstream application.
The application demonstrates, how to use multiple sources for use
cases like object detection, tracking, smart recording etc.
===============================================================================
3. To compile:
===============================================================================
$ Set CUDA_VER in the MakeFile as per platform.
For both Jetson & x86, CUDA_VER=12.6
$ sudo make (sudo not required in case of docker containers)
===============================================================================
4. Usage:
===============================================================================
Run the application by executing the command:
./deepstream-app -c <config-file>
Please refer "../../apps-common/includes/deepstream_config.h" to modify
application parameters like maximum number of sources etc.
NOTE:
1. Prerequisites to use nvdrmvideosink (Jetson only)
a. Ensure that X server is not running.
Command to stop X server:
$sudo service gdm stop
$sudo pkill -9 Xorg
b. If "Could not get EGL display connection" error is encountered,
use command $unset DISPLAY
c. Ensure that a display device is connected to the Jetson board.
sugon_apps/sample_apps/deepstream-app/deepstream_app.c
0 → 100644
View file @
24460ef5
/*
* SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LicenseRef-NvidiaProprietary
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*/
#include <gst/gst.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <unistd.h>
#include "deepstream_app.h"
#define MAX_DISPLAY_LEN 64
static
guint
demux_batch_num
=
0
;
GST_DEBUG_CATEGORY_EXTERN
(
NVDS_APP
);
GQuark
_dsmeta_quark
;
#define CEIL(a,b) ((a + b - 1) / b)
/**
* @brief Add the (nvmsgconv->nvmsgbroker) sink-bin to the
* overall DS pipeline (if any configured) and link the same to
* common_elements.tee (This tee connects
* the common analytics path to Tiler/display-sink and
* to configured broker sink if any)
* NOTE: This API shall return TRUE if there are no
* broker sinks to add to pipeline
*
* @param appCtx [IN]
* @return TRUE if succussful; FALSE otherwise
*/
static
gboolean
add_and_link_broker_sink
(
AppCtx
*
appCtx
);
/**
* @brief Checks if there are any [sink] groups
* configured for source_id=provided source_id
* NOTE: source_id key and this API is valid only when we
* disable [tiler] and thus use demuxer for individual
* stream out
* @param config [IN] The DS Pipeline configuration struct
* @param source_id [IN] Source ID for which a specific [sink]
* group is searched for
*/
static
gboolean
is_sink_available_for_source_id
(
NvDsConfig
*
config
,
guint
source_id
);
static
NvDsSensorInfo
*
s_sensor_info_create
(
NvDsSensorInfo
*
sensor_info
);
static
void
s_sensor_info_destroy
(
NvDsSensorInfo
*
sensor_info
);
static
NvDsSensorInfo
*
s_sensor_info_create
(
NvDsSensorInfo
*
sensor_info
)
{
NvDsSensorInfo
*
sensorInfoToHash
=
(
NvDsSensorInfo
*
)
g_malloc0
(
sizeof
(
NvDsSensorInfo
));
*
sensorInfoToHash
=
*
sensor_info
;
sensorInfoToHash
->
sensor_id
=
(
gchar
const
*
)
g_strdup
(
sensor_info
->
sensor_id
);
sensorInfoToHash
->
sensor_name
=
(
gchar
const
*
)
g_strdup
(
sensor_info
->
sensor_name
);
sensorInfoToHash
->
uri
=
(
gchar
const
*
)
g_strdup
(
sensor_info
->
uri
);
return
sensorInfoToHash
;
}
static
void
s_sensor_info_destroy
(
NvDsSensorInfo
*
sensor_info
)
{
if
(
!
sensor_info
)
return
;
if
(
sensor_info
->
sensor_id
)
{
g_free
((
void
*
)
sensor_info
->
sensor_id
);
}
if
(
sensor_info
->
sensor_name
)
{
g_free
((
void
*
)
sensor_info
->
sensor_name
);
}
g_free
(
sensor_info
);
}
static
void
s_sensor_info_callback_stream_added
(
AppCtx
*
appCtx
,
NvDsSensorInfo
*
sensorInfo
)
{
NvDsSensorInfo
*
sensorInfoToHash
=
s_sensor_info_create
(
sensorInfo
);
/** save the sensor info into the hash map */
g_hash_table_insert
(
appCtx
->
sensorInfoHash
,
sensorInfo
->
source_id
+
(
char
*
)
NULL
,
sensorInfoToHash
);
}
static
void
s_sensor_info_callback_stream_removed
(
AppCtx
*
appCtx
,
NvDsSensorInfo
*
sensorInfo
)
{
NvDsSensorInfo
*
sensorInfoFromHash
=
get_sensor_info
(
appCtx
,
sensorInfo
->
source_id
);
/** remove the sensor info from the hash map */
if
(
sensorInfoFromHash
)
{
g_hash_table_remove
(
appCtx
->
sensorInfoHash
,
sensorInfo
->
source_id
+
(
gchar
*
)
NULL
);
s_sensor_info_destroy
(
sensorInfoFromHash
);
}
}
NvDsSensorInfo
*
get_sensor_info
(
AppCtx
*
appCtx
,
guint
source_id
)
{
NvDsSensorInfo
*
sensorInfo
=
(
NvDsSensorInfo
*
)
g_hash_table_lookup
(
appCtx
->
sensorInfoHash
,
source_id
+
(
gchar
*
)
NULL
);
return
sensorInfo
;
}
/*Note: Below callbacks/functions defined for FPS logging,
* when nvmultiurisrcbin is being used*/
static
NvDsFPSSensorInfo
*
s_fps_sensor_info_create
(
NvDsFPSSensorInfo
*
sensor_info
);
NvDsFPSSensorInfo
*
get_fps_sensor_info
(
AppCtx
*
appCtx
,
guint
source_id
);
static
void
s_fps_sensor_info_destroy
(
NvDsFPSSensorInfo
*
sensor_info
);
static
NvDsFPSSensorInfo
*
s_fps_sensor_info_create
(
NvDsFPSSensorInfo
*
sensor_info
)
{
NvDsFPSSensorInfo
*
fpssensorInfoToHash
=
(
NvDsFPSSensorInfo
*
)
g_malloc0
(
sizeof
(
NvDsFPSSensorInfo
));
*
fpssensorInfoToHash
=
*
sensor_info
;
fpssensorInfoToHash
->
uri
=
(
gchar
const
*
)
g_strdup
(
sensor_info
->
uri
);
fpssensorInfoToHash
->
source_id
=
sensor_info
->
source_id
;
fpssensorInfoToHash
->
sensor_id
=
(
gchar
const
*
)
g_strdup
(
sensor_info
->
sensor_id
);
fpssensorInfoToHash
->
sensor_name
=
(
gchar
const
*
)
g_strdup
(
sensor_info
->
sensor_name
);
return
fpssensorInfoToHash
;
}
static
void
s_fps_sensor_info_destroy
(
NvDsFPSSensorInfo
*
sensor_info
)
{
if
(
!
sensor_info
)
return
;
if
(
sensor_info
->
sensor_id
)
{
g_free
((
void
*
)
sensor_info
->
sensor_id
);
}
if
(
sensor_info
->
sensor_name
)
{
g_free
((
void
*
)
sensor_info
->
sensor_name
);
}
if
(
sensor_info
->
uri
)
{
g_free
((
void
*
)
sensor_info
->
uri
);
}
g_free
(
sensor_info
);
}
static
void
s_fps_sensor_info_callback_stream_added
(
AppCtx
*
appCtx
,
NvDsFPSSensorInfo
*
sensorInfo
)
{
NvDsFPSSensorInfo
*
fpssensorInfoToHash
=
s_fps_sensor_info_create
(
sensorInfo
);
/** save the sensor info into the hash map */
g_hash_table_insert
(
appCtx
->
perf_struct
.
FPSInfoHash
,
GUINT_TO_POINTER
(
sensorInfo
->
source_id
),
fpssensorInfoToHash
);
}
NvDsFPSSensorInfo
*
get_fps_sensor_info
(
AppCtx
*
appCtx
,
guint
source_id
)
{
NvDsFPSSensorInfo
*
sensorInfo
=
(
NvDsFPSSensorInfo
*
)
g_hash_table_lookup
(
appCtx
->
perf_struct
.
FPSInfoHash
,
GUINT_TO_POINTER
(
source_id
));
return
sensorInfo
;
}
static
void
s_fps_sensor_info_callback_stream_removed
(
AppCtx
*
appCtx
,
NvDsFPSSensorInfo
*
sensorInfo
)
{
NvDsFPSSensorInfo
*
fpsensorInfoFromHash
=
get_fps_sensor_info
(
appCtx
,
sensorInfo
->
source_id
);
/** remove the sensor info from the hash map */
if
(
fpsensorInfoFromHash
)
{
g_hash_table_remove
(
appCtx
->
perf_struct
.
FPSInfoHash
,
GUINT_TO_POINTER
(
sensorInfo
->
source_id
));
s_fps_sensor_info_destroy
(
fpsensorInfoFromHash
);
}
}
/**
* callback function to receive messages from components
* in the pipeline.
*/
static
gboolean
bus_callback
(
GstBus
*
bus
,
GstMessage
*
message
,
gpointer
data
)
{
AppCtx
*
appCtx
=
(
AppCtx
*
)
data
;
GST_CAT_DEBUG
(
NVDS_APP
,
"Received message on bus: source %s, msg_type %s"
,
GST_MESSAGE_SRC_NAME
(
message
),
GST_MESSAGE_TYPE_NAME
(
message
));
switch
(
GST_MESSAGE_TYPE
(
message
))
{
case
GST_MESSAGE_INFO
:{
GError
*
error
=
NULL
;
gchar
*
debuginfo
=
NULL
;
gst_message_parse_info
(
message
,
&
error
,
&
debuginfo
);
g_printerr
(
"INFO from %s: %s
\n
"
,
GST_OBJECT_NAME
(
message
->
src
),
error
->
message
);
if
(
debuginfo
)
{
g_printerr
(
"Debug info: %s
\n
"
,
debuginfo
);
}
g_error_free
(
error
);
g_free
(
debuginfo
);
break
;
}
case
GST_MESSAGE_WARNING
:{
GError
*
error
=
NULL
;
gchar
*
debuginfo
=
NULL
;
gst_message_parse_warning
(
message
,
&
error
,
&
debuginfo
);
g_printerr
(
"WARNING from %s: %s
\n
"
,
GST_OBJECT_NAME
(
message
->
src
),
error
->
message
);
if
(
debuginfo
)
{
g_printerr
(
"Debug info: %s
\n
"
,
debuginfo
);
}
g_error_free
(
error
);
g_free
(
debuginfo
);
break
;
}
case
GST_MESSAGE_ERROR
:{
GError
*
error
=
NULL
;
gchar
*
debuginfo
=
NULL
;
const
gchar
*
attempts_error
=
"Reconnection attempts exceeded for all sources or EOS received."
;
guint
i
=
0
;
gst_message_parse_error
(
message
,
&
error
,
&
debuginfo
);
if
(
strstr
(
error
->
message
,
attempts_error
))
{
g_print
(
"Reconnection attempt exceeded or EOS received for all sources."
" Exiting.
\n
"
);
g_error_free
(
error
);
g_free
(
debuginfo
);
appCtx
->
return_value
=
0
;
appCtx
->
quit
=
TRUE
;
return
TRUE
;
}
g_printerr
(
"ERROR from %s: %s
\n
"
,
GST_OBJECT_NAME
(
message
->
src
),
error
->
message
);
if
(
debuginfo
)
{
g_printerr
(
"Debug info: %s
\n
"
,
debuginfo
);
}
NvDsSrcParentBin
*
bin
=
&
appCtx
->
pipeline
.
multi_src_bin
;
GstElement
*
msg_src_elem
=
(
GstElement
*
)
GST_MESSAGE_SRC
(
message
);
gboolean
bin_found
=
FALSE
;
/* Find the source bin which generated the error. */
while
(
msg_src_elem
&&
!
bin_found
)
{
for
(
i
=
0
;
i
<
bin
->
num_bins
&&
!
bin_found
;
i
++
)
{
if
(
bin
->
sub_bins
[
i
].
src_elem
==
msg_src_elem
||
bin
->
sub_bins
[
i
].
bin
==
msg_src_elem
)
{
bin_found
=
TRUE
;
break
;
}
}
msg_src_elem
=
GST_ELEMENT_PARENT
(
msg_src_elem
);
}
if
((
i
!=
bin
->
num_bins
)
&&
(
appCtx
->
config
.
multi_source_config
[
0
].
type
==
NV_DS_SOURCE_RTSP
))
{
// Error from one of RTSP source.
NvDsSrcBin
*
subBin
=
&
bin
->
sub_bins
[
i
];
if
(
!
subBin
->
reconfiguring
||
g_strrstr
(
debuginfo
,
"500 (Internal Server Error)"
))
{
subBin
->
reconfiguring
=
TRUE
;
g_timeout_add
(
0
,
reset_source_pipeline
,
subBin
);
}
g_error_free
(
error
);
g_free
(
debuginfo
);
return
TRUE
;
}
if
(
appCtx
->
config
.
multi_source_config
[
0
].
type
==
NV_DS_SOURCE_CAMERA_V4L2
)
{
if
(
g_strrstr
(
debuginfo
,
"reason not-negotiated (-4)"
))
{
NVGSTDS_INFO_MSG_V
(
"incorrect camera parameters provided, please provide supported resolution and frame rate
\n
"
);
}
if
(
g_strrstr
(
debuginfo
,
"Buffer pool activation failed"
))
{
NVGSTDS_INFO_MSG_V
(
"usb bandwidth might be saturated
\n
"
);
}
}
g_error_free
(
error
);
g_free
(
debuginfo
);
appCtx
->
return_value
=
-
1
;
appCtx
->
quit
=
TRUE
;
break
;
}
case
GST_MESSAGE_STATE_CHANGED
:{
GstState
oldstate
,
newstate
;
gst_message_parse_state_changed
(
message
,
&
oldstate
,
&
newstate
,
NULL
);
if
(
GST_ELEMENT
(
GST_MESSAGE_SRC
(
message
))
==
appCtx
->
pipeline
.
pipeline
)
{
switch
(
newstate
)
{
case
GST_STATE_PLAYING
:
NVGSTDS_INFO_MSG_V
(
"Pipeline running
\n
"
);
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS
(
GST_BIN
(
appCtx
->
pipeline
.
pipeline
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"ds-app-playing"
);
break
;
case
GST_STATE_PAUSED
:
if
(
oldstate
==
GST_STATE_PLAYING
)
{
NVGSTDS_INFO_MSG_V
(
"Pipeline paused
\n
"
);
}
break
;
case
GST_STATE_READY
:
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS
(
GST_BIN
(
appCtx
->
pipeline
.
pipeline
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"ds-app-ready"
);
if
(
oldstate
==
GST_STATE_NULL
)
{
NVGSTDS_INFO_MSG_V
(
"Pipeline ready
\n
"
);
}
else
{
NVGSTDS_INFO_MSG_V
(
"Pipeline stopped
\n
"
);
}
break
;
case
GST_STATE_NULL
:
g_mutex_lock
(
&
appCtx
->
app_lock
);
g_cond_broadcast
(
&
appCtx
->
app_cond
);
g_mutex_unlock
(
&
appCtx
->
app_lock
);
break
;
default:
break
;
}
}
break
;
}
case
GST_MESSAGE_EOS
:{
/*
* In normal scenario, this would use g_main_loop_quit() to exit the
* loop and release the resources. Since this application might be
* running multiple pipelines through configuration files, it should wait
* till all pipelines are done.
*/
if
(
appCtx
->
config
.
use_nvmultiurisrcbin
)
{
appCtx
->
eos_received
=
TRUE
;
gboolean
app_quit
=
TRUE
;
for
(
int
i
=
0
;
i
<
MAX_SOURCE_BINS
;
i
++
)
{
if
(
appCtx
->
config
.
multi_source_config
[
i
].
type
==
NV_DS_SOURCE_RTSP
)
{
if
(
appCtx
->
config
.
multi_source_config
[
i
].
rtsp_reconnect_attempt_exceeded
!=
TRUE
)
{
app_quit
=
FALSE
;
}
else
{
app_quit
=
TRUE
;
}
}
}
if
(
app_quit
)
{
appCtx
->
quit
=
TRUE
;
NVGSTDS_INFO_MSG_V
(
"Received EOS. Exiting ...
\n
"
);
return
FALSE
;
}
else
{
NVGSTDS_INFO_MSG_V
(
"Received EOS ...
\n
"
);
}
}
else
{
NVGSTDS_INFO_MSG_V
(
"Received EOS. Exiting ...
\n
"
);
appCtx
->
quit
=
TRUE
;
return
FALSE
;
}
break
;
}
case
GST_MESSAGE_ELEMENT
:{
if
(
gst_nvmessage_is_force_pipeline_eos
(
message
))
{
gboolean
app_quit
=
FALSE
;
if
(
gst_nvmessage_parse_force_pipeline_eos
(
message
,
&
app_quit
))
{
if
(
app_quit
)
appCtx
->
quit
=
TRUE
;
}
}
if
(
gst_nvmessage_is_stream_add
(
message
))
{
g_mutex_lock
(
&
(
appCtx
->
perf_struct
).
struct_lock
);
appCtx
->
config
.
num_source_sub_bins
++
;
NvDsSensorInfo
sensorInfo
=
{
0
};
gst_nvmessage_parse_stream_add
(
message
,
&
sensorInfo
);
g_print
(
"new stream added [%d:%s:%s]
\n\n\n\n
"
,
sensorInfo
.
source_id
,
sensorInfo
.
sensor_id
,
sensorInfo
.
sensor_name
);
/** Callback */
s_sensor_info_callback_stream_added
(
appCtx
,
&
sensorInfo
);
gboolean
is_rtsp
=
g_str_has_prefix
(
sensorInfo
.
uri
,
"rtsp://"
);
gboolean
is_ipc
=
g_str_has_prefix
(
sensorInfo
.
uri
,
"ipc://"
);
appCtx
->
config
.
multi_source_config
[
sensorInfo
.
source_id
].
uri
=
g_strdup
(
sensorInfo
.
uri
);
if
(
is_rtsp
)
{
appCtx
->
config
.
multi_source_config
[
sensorInfo
.
source_id
].
type
=
NV_DS_SOURCE_RTSP
;
}
else
if
(
is_ipc
)
{
appCtx
->
config
.
multi_source_config
[
sensorInfo
.
source_id
].
type
=
NV_DS_SOURCE_IPC
;
}
else
{
appCtx
->
config
.
multi_source_config
[
sensorInfo
.
source_id
].
type
=
NV_DS_SOURCE_URI
;
}
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS
(
GST_BIN
(
appCtx
->
pipeline
.
pipeline
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"ds-app-added"
);
NvDsFPSSensorInfo
fpssensorInfo
=
{
0
};
gst_nvmessage_parse_fps_stream_add
(
message
,
&
fpssensorInfo
);
s_fps_sensor_info_callback_stream_added
(
appCtx
,
&
fpssensorInfo
);
g_mutex_unlock
(
&
(
appCtx
->
perf_struct
).
struct_lock
);
}
if
(
gst_nvmessage_is_stream_remove
(
message
))
{
g_mutex_lock
(
&
(
appCtx
->
perf_struct
).
struct_lock
);
appCtx
->
config
.
num_source_sub_bins
--
;
NvDsSensorInfo
sensorInfo
=
{
0
};
gst_nvmessage_parse_stream_remove
(
message
,
&
sensorInfo
);
g_print
(
"new stream removed [%d:%s]
\n\n\n\n
"
,
sensorInfo
.
source_id
,
sensorInfo
.
sensor_id
);
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS
(
GST_BIN
(
appCtx
->
pipeline
.
pipeline
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"ds-app-removed"
);
/** Callback */
s_sensor_info_callback_stream_removed
(
appCtx
,
&
sensorInfo
);
NvDsFPSSensorInfo
fpssensorInfo
=
{
0
};
gst_nvmessage_parse_fps_stream_remove
(
message
,
&
fpssensorInfo
);
s_fps_sensor_info_callback_stream_removed
(
appCtx
,
&
fpssensorInfo
);
g_mutex_unlock
(
&
(
appCtx
->
perf_struct
).
struct_lock
);
}
if
(
gst_nvmessage_is_reconnect_attempt_exceeded
(
message
))
{
NvDsRtspAttemptsInfo
rtsp_info
=
{
0
};
gboolean
rec_attempt_exceeded_for_all
=
TRUE
;
if
(
gst_nvmessage_parse_reconnect_attempt_exceeded
(
message
,
&
rtsp_info
))
{
if
(
rtsp_info
.
attempt_exceeded
)
{
appCtx
->
config
.
multi_source_config
[
rtsp_info
.
source_id
].
rtsp_reconnect_attempt_exceeded
=
rtsp_info
.
attempt_exceeded
;
NVGSTDS_INFO_MSG_V
(
"rtsp reconnect attempt exceeded for source_id : %d
\n
"
,
rtsp_info
.
source_id
);
}
if
(
appCtx
->
eos_received
)
{
for
(
int
i
=
0
;
i
<
MAX_SOURCE_BINS
;
i
++
)
{
if
(
appCtx
->
config
.
multi_source_config
[
i
].
type
==
NV_DS_SOURCE_RTSP
)
{
if
(
appCtx
->
config
.
multi_source_config
[
i
].
rtsp_reconnect_attempt_exceeded
!=
TRUE
)
{
rec_attempt_exceeded_for_all
=
FALSE
;
}
}
}
if
(
rec_attempt_exceeded_for_all
)
{
NVGSTDS_INFO_MSG_V
(
"Exiting ...
\n
"
);
appCtx
->
quit
=
TRUE
;
return
FALSE
;
}
}
}
}
break
;
}
default:
break
;
}
return
TRUE
;
}
/**
* Function to dump bounding box data in kitti format. For this to work,
* property "gie-kitti-output-dir" must be set in configuration file.
* Data of different sources and frames is dumped in separate file.
*/
static
void
write_kitti_output
(
AppCtx
*
appCtx
,
NvDsBatchMeta
*
batch_meta
)
{
gchar
bbox_file
[
1024
]
=
{
0
};
FILE
*
bbox_params_dump_file
=
NULL
;
if
(
!
appCtx
->
config
.
bbox_dir_path
)
return
;
for
(
NvDsMetaList
*
l_frame
=
batch_meta
->
frame_meta_list
;
l_frame
!=
NULL
;
l_frame
=
l_frame
->
next
)
{
NvDsFrameMeta
*
frame_meta
=
(
NvDsFrameMeta
*
)
l_frame
->
data
;
guint
stream_id
=
frame_meta
->
pad_index
;
g_snprintf
(
bbox_file
,
sizeof
(
bbox_file
)
-
1
,
"%s/%02u_%03u_%06lu.txt"
,
appCtx
->
config
.
bbox_dir_path
,
appCtx
->
index
,
stream_id
,
(
gulong
)
frame_meta
->
frame_num
);
bbox_params_dump_file
=
fopen
(
bbox_file
,
"w"
);
if
(
!
bbox_params_dump_file
)
continue
;
for
(
NvDsMetaList
*
l_obj
=
frame_meta
->
obj_meta_list
;
l_obj
!=
NULL
;
l_obj
=
l_obj
->
next
)
{
NvDsObjectMeta
*
obj
=
(
NvDsObjectMeta
*
)
l_obj
->
data
;
float
left
=
obj
->
rect_params
.
left
;
float
top
=
obj
->
rect_params
.
top
;
float
right
=
left
+
obj
->
rect_params
.
width
;
float
bottom
=
top
+
obj
->
rect_params
.
height
;
// Here confidence stores detection confidence, since dump gie output
// is before tracker plugin
float
confidence
=
obj
->
confidence
;
fprintf
(
bbox_params_dump_file
,
"%s 0.0 0 0.0 %f %f %f %f 0.0 0.0 0.0 0.0 0.0 0.0 0.0 %f
\n
"
,
obj
->
obj_label
,
left
,
top
,
right
,
bottom
,
confidence
);
}
fclose
(
bbox_params_dump_file
);
}
}
/**
* Function to dump past frame objs in kitti format.
*/
static
void
write_kitti_past_track_output
(
AppCtx
*
appCtx
,
NvDsBatchMeta
*
batch_meta
)
{
if
(
!
appCtx
->
config
.
kitti_track_dir_path
)
return
;
// dump past frame tracked objects appending current frame objects
gchar
bbox_file
[
1024
]
=
{
0
};
FILE
*
bbox_params_dump_file
=
NULL
;
NvDsTargetMiscDataBatch
*
pPastFrameObjBatch
=
NULL
;
NvDsUserMetaList
*
bmeta_list
=
NULL
;
NvDsUserMeta
*
user_meta
=
NULL
;
for
(
bmeta_list
=
batch_meta
->
batch_user_meta_list
;
bmeta_list
!=
NULL
;
bmeta_list
=
bmeta_list
->
next
)
{
user_meta
=
(
NvDsUserMeta
*
)
bmeta_list
->
data
;
if
(
user_meta
&&
user_meta
->
base_meta
.
meta_type
==
NVDS_TRACKER_PAST_FRAME_META
)
{
pPastFrameObjBatch
=
(
NvDsTargetMiscDataBatch
*
)
(
user_meta
->
user_meta_data
);
for
(
uint
si
=
0
;
si
<
pPastFrameObjBatch
->
numFilled
;
si
++
)
{
NvDsTargetMiscDataStream
*
objStream
=
(
pPastFrameObjBatch
->
list
)
+
si
;
guint
stream_id
=
(
guint
)
(
objStream
->
streamID
);
for
(
uint
li
=
0
;
li
<
objStream
->
numFilled
;
li
++
)
{
NvDsTargetMiscDataObject
*
objList
=
(
objStream
->
list
)
+
li
;
for
(
uint
oi
=
0
;
oi
<
objList
->
numObj
;
oi
++
)
{
NvDsTargetMiscDataFrame
*
obj
=
(
objList
->
list
)
+
oi
;
g_snprintf
(
bbox_file
,
sizeof
(
bbox_file
)
-
1
,
"%s/%02u_%03u_%06lu.txt"
,
appCtx
->
config
.
kitti_track_dir_path
,
appCtx
->
index
,
stream_id
,
(
gulong
)
obj
->
frameNum
);
float
left
=
obj
->
tBbox
.
left
;
float
right
=
left
+
obj
->
tBbox
.
width
;
float
top
=
obj
->
tBbox
.
top
;
float
bottom
=
top
+
obj
->
tBbox
.
height
;
// Past frame object confidence given by tracker
float
confidence
=
obj
->
confidence
;
bbox_params_dump_file
=
fopen
(
bbox_file
,
"a"
);
if
(
!
bbox_params_dump_file
)
{
continue
;
}
fprintf
(
bbox_params_dump_file
,
"%s %lu 0.0 0 0.0 %f %f %f %f 0.0 0.0 0.0 0.0 0.0 0.0 0.0 %f
\n
"
,
objList
->
objLabel
,
objList
->
uniqueId
,
left
,
top
,
right
,
bottom
,
confidence
);
fclose
(
bbox_params_dump_file
);
}
}
}
}
}
}
/**
* Function to dump bounding box data in kitti format with tracking ID added.
* For this to work, property "kitti-track-output-dir" must be set in configuration file.
* Data of different sources and frames is dumped in separate file.
*/
static
void
write_kitti_track_output
(
AppCtx
*
appCtx
,
NvDsBatchMeta
*
batch_meta
)
{
gchar
bbox_file
[
1024
]
=
{
0
};
FILE
*
bbox_params_dump_file
=
NULL
;
if
(
!
appCtx
->
config
.
kitti_track_dir_path
)
return
;
for
(
NvDsMetaList
*
l_frame
=
batch_meta
->
frame_meta_list
;
l_frame
!=
NULL
;
l_frame
=
l_frame
->
next
)
{
NvDsFrameMeta
*
frame_meta
=
(
NvDsFrameMeta
*
)
l_frame
->
data
;
guint
stream_id
=
frame_meta
->
pad_index
;
g_snprintf
(
bbox_file
,
sizeof
(
bbox_file
)
-
1
,
"%s/%02u_%03u_%06lu.txt"
,
appCtx
->
config
.
kitti_track_dir_path
,
appCtx
->
index
,
stream_id
,
(
gulong
)
frame_meta
->
frame_num
);
bbox_params_dump_file
=
fopen
(
bbox_file
,
"w"
);
if
(
!
bbox_params_dump_file
)
continue
;
for
(
NvDsMetaList
*
l_obj
=
frame_meta
->
obj_meta_list
;
l_obj
!=
NULL
;
l_obj
=
l_obj
->
next
)
{
NvDsObjectMeta
*
obj
=
(
NvDsObjectMeta
*
)
l_obj
->
data
;
float
left
=
obj
->
tracker_bbox_info
.
org_bbox_coords
.
left
;
float
top
=
obj
->
tracker_bbox_info
.
org_bbox_coords
.
top
;
float
right
=
left
+
obj
->
tracker_bbox_info
.
org_bbox_coords
.
width
;
float
bottom
=
top
+
obj
->
tracker_bbox_info
.
org_bbox_coords
.
height
;
// Here confidence stores tracker confidence value for tracker output
float
confidence
=
obj
->
tracker_confidence
;
guint64
id
=
obj
->
object_id
;
bool
write_proj_info
=
false
;
float
visibility
=
-
1
.
0
,
x_img_foot
=
-
1
.
0
,
y_img_foot
=
-
1
.
0
;
// Attach projected object info if stored in user meta
for
(
NvDsUserMetaList
*
l_obj_user
=
obj
->
obj_user_meta_list
;
l_obj_user
!=
NULL
;
l_obj_user
=
l_obj_user
->
next
)
{
NvDsUserMeta
*
user_meta
=
(
NvDsUserMeta
*
)
l_obj_user
->
data
;
if
(
user_meta
&&
user_meta
->
base_meta
.
meta_type
==
NVDS_OBJ_VISIBILITY
&&
user_meta
->
user_meta_data
)
{
write_proj_info
=
true
;
visibility
=
*
((
float
*
)
(
user_meta
->
user_meta_data
));
}
else
if
(
user_meta
&&
user_meta
->
base_meta
.
meta_type
==
NVDS_OBJ_IMAGE_FOOT_LOCATION
&&
user_meta
->
user_meta_data
)
{
write_proj_info
=
true
;
x_img_foot
=
((
float
*
)
(
user_meta
->
user_meta_data
))[
0
];
y_img_foot
=
((
float
*
)
(
user_meta
->
user_meta_data
))[
1
];
}
}
if
(
write_proj_info
)
{
fprintf
(
bbox_params_dump_file
,
"%s %lu 0.0 0 0.0 %f %f %f %f 0.0 0.0 0.0 0.0 0.0 0.0 0.0 %f %f %f %f
\n
"
,
obj
->
obj_label
,
id
,
left
,
top
,
right
,
bottom
,
confidence
,
visibility
,
x_img_foot
,
y_img_foot
);
}
else
{
fprintf
(
bbox_params_dump_file
,
"%s %lu 0.0 0 0.0 %f %f %f %f 0.0 0.0 0.0 0.0 0.0 0.0 0.0 %f
\n
"
,
obj
->
obj_label
,
id
,
left
,
top
,
right
,
bottom
,
confidence
);
}
}
fclose
(
bbox_params_dump_file
);
}
}
/**
* Function to dump object ReID embeddings to files when the tracker outputs
* ReID embeddings into user meta. For this to work, property "reid-track-output-dir"
* must be set in configuration file.
* Data of different sources and frames is dumped in separate file.
*/
static
void
write_reid_track_output
(
AppCtx
*
appCtx
,
NvDsBatchMeta
*
batch_meta
)
{
if
(
!
appCtx
->
config
.
reid_track_dir_path
)
return
;
gchar
reid_file
[
1024
]
=
{
0
};
FILE
*
reid_params_dump_file
=
NULL
;
/** Save the reid embedding for each frame. */
for
(
NvDsMetaList
*
l_frame
=
batch_meta
->
frame_meta_list
;
l_frame
!=
NULL
;
l_frame
=
l_frame
->
next
)
{
NvDsFrameMeta
*
frame_meta
=
(
NvDsFrameMeta
*
)
l_frame
->
data
;
/** Create dump file name. */
guint
stream_id
=
frame_meta
->
pad_index
;
g_snprintf
(
reid_file
,
sizeof
(
reid_file
)
-
1
,
"%s/%02u_%03u_%06lu.txt"
,
appCtx
->
config
.
reid_track_dir_path
,
appCtx
->
index
,
stream_id
,
(
gulong
)
frame_meta
->
frame_num
);
reid_params_dump_file
=
fopen
(
reid_file
,
"w"
);
if
(
!
reid_params_dump_file
)
continue
;
/** Save the reid embedding for each object. */
for
(
NvDsMetaList
*
l_obj
=
frame_meta
->
obj_meta_list
;
l_obj
!=
NULL
;
l_obj
=
l_obj
->
next
)
{
NvDsObjectMeta
*
obj
=
(
NvDsObjectMeta
*
)
l_obj
->
data
;
guint64
id
=
obj
->
object_id
;
for
(
NvDsUserMetaList
*
l_obj_user
=
obj
->
obj_user_meta_list
;
l_obj_user
!=
NULL
;
l_obj_user
=
l_obj_user
->
next
)
{
/** Find the object's reid embedding index in user meta. */
NvDsUserMeta
*
user_meta
=
(
NvDsUserMeta
*
)
l_obj_user
->
data
;
if
(
user_meta
&&
user_meta
->
base_meta
.
meta_type
==
NVDS_TRACKER_OBJ_REID_META
&&
user_meta
->
user_meta_data
)
{
NvDsObjReid
*
pReidObj
=
(
NvDsObjReid
*
)
(
user_meta
->
user_meta_data
);
if
(
pReidObj
!=
NULL
&&
pReidObj
->
ptr_host
!=
NULL
&&
pReidObj
->
featureSize
>
0
)
{
fprintf
(
reid_params_dump_file
,
"%lu"
,
id
);
for
(
guint
ele_i
=
0
;
ele_i
<
pReidObj
->
featureSize
;
ele_i
++
)
{
fprintf
(
reid_params_dump_file
,
" %f"
,
pReidObj
->
ptr_host
[
ele_i
]);
}
fprintf
(
reid_params_dump_file
,
"
\n
"
);
}
}
}
}
fclose
(
reid_params_dump_file
);
}
}
/**
* Function to dump terminated object information to files when the tracker outputs
* terminated track info into user meta. For this to work, property "terminated_track_output_path"
* must be set in configuration file.
* Data of different sources and frames is dumped in separate file.
*/
static
void
write_terminated_track_output
(
AppCtx
*
appCtx
,
NvDsBatchMeta
*
batch_meta
)
{
if
(
!
appCtx
->
config
.
terminated_track_output_path
)
return
;
gchar
term_file
[
1024
]
=
{
0
};
FILE
*
term_params_dump_file
=
NULL
;
/** Find batch terminted tensor in batch user meta. */
GList
*
pTerminatedTrackList
=
NULL
;
// list of pointers to NvDsTargetMiscDataBatch
NvDsTargetMiscDataBatch
*
pTerminatedTrackBatch
=
NULL
;
for
(
NvDsUserMetaList
*
l_batch_user
=
batch_meta
->
batch_user_meta_list
;
l_batch_user
!=
NULL
;
l_batch_user
=
l_batch_user
->
next
)
{
NvDsUserMeta
*
user_meta
=
(
NvDsUserMeta
*
)
l_batch_user
->
data
;
if
(
user_meta
&&
user_meta
->
base_meta
.
meta_type
==
NVDS_TRACKER_TERMINATED_LIST_META
)
{
pTerminatedTrackBatch
=
(
NvDsTargetMiscDataBatch
*
)
(
user_meta
->
user_meta_data
);
pTerminatedTrackList
=
g_list_append
(
pTerminatedTrackList
,
pTerminatedTrackBatch
);
}
}
if
(
!
pTerminatedTrackList
)
return
;
/** Save the Terminated data for each frame. */
for
(
NvDsMetaList
*
l_frame
=
batch_meta
->
frame_meta_list
;
l_frame
!=
NULL
;
l_frame
=
l_frame
->
next
)
{
NvDsFrameMeta
*
frame_meta
=
(
NvDsFrameMeta
*
)
l_frame
->
data
;
for
(
GList
*
l
=
pTerminatedTrackList
;
l
!=
NULL
;
l
=
l
->
next
)
{
pTerminatedTrackBatch
=
(
NvDsTargetMiscDataBatch
*
)
(
l
->
data
);
for
(
uint
si
=
0
;
si
<
pTerminatedTrackBatch
->
numFilled
;
si
++
)
{
NvDsTargetMiscDataStream
*
objStream
=
(
pTerminatedTrackBatch
->
list
)
+
si
;
guint
stream_id
=
(
guint
)(
objStream
->
streamID
);
if
(
frame_meta
->
pad_index
!=
stream_id
)
continue
;
g_snprintf
(
term_file
,
sizeof
(
term_file
)
-
1
,
"%s/%02u_%03u_%06lu.txt"
,
appCtx
->
config
.
terminated_track_output_path
,
appCtx
->
index
,
stream_id
,
(
gulong
)
frame_meta
->
frame_num
);
term_params_dump_file
=
fopen
(
term_file
,
"w"
);
if
(
!
term_params_dump_file
)
continue
;
for
(
uint
li
=
0
;
li
<
objStream
->
numFilled
;
li
++
)
{
NvDsTargetMiscDataObject
*
objList
=
(
objStream
->
list
)
+
li
;
fprintf
(
term_params_dump_file
,
"Target: %ld,%d,%hu
\n
"
,
objList
->
uniqueId
,
objList
->
classId
,
stream_id
);
for
(
uint
oi
=
0
;
oi
<
objList
->
numObj
;
oi
++
)
{
NvDsTargetMiscDataFrame
*
obj
=
(
objList
->
list
)
+
oi
;
float
left
=
obj
->
tBbox
.
left
;
float
right
=
left
+
obj
->
tBbox
.
width
;
float
top
=
obj
->
tBbox
.
top
;
float
bottom
=
top
+
obj
->
tBbox
.
height
;
fprintf
(
term_params_dump_file
,
"%u %lu %u 0 0.0 %f %f %f %f 0.0 0.0 0.0 0.0 0.0 0.0 0.0 %f %d %f
\n
"
,
obj
->
frameNum
,
objList
->
uniqueId
,
objList
->
classId
,
left
,
top
,
right
,
bottom
,
obj
->
confidence
,
obj
->
trackerState
,
obj
->
visibility
);
}
}
fprintf
(
term_params_dump_file
,
"
\n
"
);
fclose
(
term_params_dump_file
);
}
}
}
g_list_free
(
pTerminatedTrackList
);
}
/**
* Function to dump terminated object information to files when the tracker outputs
* terminated track info into user meta. For this to work, property "terminated_track_output_path"
* must be set in configuration file.
* Data of different sources and frames is dumped in separate file.
*/
static
void
write_shadow_track_output
(
AppCtx
*
appCtx
,
NvDsBatchMeta
*
batch_meta
)
{
if
(
!
appCtx
->
config
.
shadow_track_output_path
)
return
;
gchar
term_file
[
1024
]
=
{
0
};
FILE
*
shadow_dump_file
=
NULL
;
/** Find shadow tracked tensor in batch user meta. */
GList
*
pShadowTrackList
=
NULL
;
// list of pointers to NvDsTargetMiscDataBatch
NvDsTargetMiscDataBatch
*
pShadowTrackBatch
=
NULL
;
for
(
NvDsUserMetaList
*
l_batch_user
=
batch_meta
->
batch_user_meta_list
;
l_batch_user
!=
NULL
;
l_batch_user
=
l_batch_user
->
next
)
{
NvDsUserMeta
*
user_meta
=
(
NvDsUserMeta
*
)
l_batch_user
->
data
;
if
(
user_meta
&&
user_meta
->
base_meta
.
meta_type
==
NVDS_TRACKER_SHADOW_LIST_META
)
{
// std::cout << "Found Shadow Data" << std::endl;
pShadowTrackBatch
=
(
NvDsTargetMiscDataBatch
*
)
(
user_meta
->
user_meta_data
);
pShadowTrackList
=
g_list_append
(
pShadowTrackList
,
pShadowTrackBatch
);
}
}
if
(
!
pShadowTrackList
)
return
;
/** Save the Terminated data for each frame. */
for
(
NvDsMetaList
*
l_frame
=
batch_meta
->
frame_meta_list
;
l_frame
!=
NULL
;
l_frame
=
l_frame
->
next
)
{
NvDsFrameMeta
*
frame_meta
=
(
NvDsFrameMeta
*
)
l_frame
->
data
;
for
(
GList
*
l
=
pShadowTrackList
;
l
!=
NULL
;
l
=
l
->
next
)
{
pShadowTrackBatch
=
(
NvDsTargetMiscDataBatch
*
)
(
l
->
data
);
for
(
uint
si
=
0
;
si
<
pShadowTrackBatch
->
numFilled
;
si
++
)
{
NvDsTargetMiscDataStream
*
objStream
=
(
pShadowTrackBatch
->
list
)
+
si
;
guint
stream_id
=
(
guint
)(
objStream
->
streamID
);
if
(
frame_meta
->
pad_index
!=
stream_id
)
continue
;
g_snprintf
(
term_file
,
sizeof
(
term_file
)
-
1
,
"%s/%02u_%03u_%06lu.txt"
,
appCtx
->
config
.
shadow_track_output_path
,
appCtx
->
index
,
stream_id
,
(
gulong
)
frame_meta
->
frame_num
);
shadow_dump_file
=
fopen
(
term_file
,
"w"
);
if
(
!
shadow_dump_file
)
continue
;
for
(
uint
li
=
0
;
li
<
objStream
->
numFilled
;
li
++
)
{
NvDsTargetMiscDataObject
*
objList
=
(
objStream
->
list
)
+
li
;
if
(
objList
->
numObj
>
0
)
{
NvDsTargetMiscDataFrame
*
obj
=
(
objList
->
list
);
// get first element only
float
left
=
obj
->
tBbox
.
left
;
float
right
=
left
+
obj
->
tBbox
.
width
;
float
top
=
obj
->
tBbox
.
top
;
float
bottom
=
top
+
obj
->
tBbox
.
height
;
fprintf
(
shadow_dump_file
,
"%u %lu %u 0 0.0 %f %f %f %f 0.0 0.0 0.0 0.0 0.0 0.0 0.0 %f %d %f
\n
"
,
obj
->
frameNum
,
objList
->
uniqueId
,
objList
->
classId
,
left
,
top
,
right
,
bottom
,
obj
->
confidence
,
obj
->
trackerState
,
obj
->
visibility
);
}
}
fclose
(
shadow_dump_file
);
}
}
}
g_list_free
(
pShadowTrackList
);
}
static
gint
component_id_compare_func
(
gconstpointer
a
,
gconstpointer
b
)
{
NvDsClassifierMeta
*
cmetaa
=
(
NvDsClassifierMeta
*
)
a
;
NvDsClassifierMeta
*
cmetab
=
(
NvDsClassifierMeta
*
)
b
;
if
(
cmetaa
->
unique_component_id
<
cmetab
->
unique_component_id
)
return
-
1
;
if
(
cmetaa
->
unique_component_id
>
cmetab
->
unique_component_id
)
return
1
;
return
0
;
}
/**
* Function to process the attached metadata. This is just for demonstration
* and can be removed if not required.
* Here it demonstrates to use bounding boxes of different color and size for
* different type / class of objects.
* It also demonstrates how to join the different labels(PGIE + SGIEs)
* of an object to form a single string.
*/
static
void
process_meta
(
AppCtx
*
appCtx
,
NvDsBatchMeta
*
batch_meta
)
{
// For single source always display text either with demuxer or with tiler
if
(
!
appCtx
->
config
.
tiled_display_config
.
enable
||
appCtx
->
config
.
num_source_sub_bins
==
1
)
{
appCtx
->
show_bbox_text
=
1
;
}
for
(
NvDsMetaList
*
l_frame
=
batch_meta
->
frame_meta_list
;
l_frame
!=
NULL
;
l_frame
=
l_frame
->
next
)
{
NvDsFrameMeta
*
frame_meta
=
(
NvDsFrameMeta
*
)
l_frame
->
data
;
for
(
NvDsMetaList
*
l_obj
=
frame_meta
->
obj_meta_list
;
l_obj
!=
NULL
;
l_obj
=
l_obj
->
next
)
{
NvDsObjectMeta
*
obj
=
(
NvDsObjectMeta
*
)
l_obj
->
data
;
gint
class_index
=
obj
->
class_id
;
NvDsGieConfig
*
gie_config
=
NULL
;
gchar
*
str_ins_pos
=
NULL
;
if
(
obj
->
unique_component_id
==
(
gint
)
appCtx
->
config
.
primary_gie_config
.
unique_id
)
{
gie_config
=
&
appCtx
->
config
.
primary_gie_config
;
}
else
{
for
(
gint
i
=
0
;
i
<
(
gint
)
appCtx
->
config
.
num_secondary_gie_sub_bins
;
i
++
)
{
gie_config
=
&
appCtx
->
config
.
secondary_gie_sub_bin_config
[
i
];
if
(
obj
->
unique_component_id
==
(
gint
)
gie_config
->
unique_id
)
{
break
;
}
gie_config
=
NULL
;
}
}
g_free
(
obj
->
text_params
.
display_text
);
obj
->
text_params
.
display_text
=
NULL
;
if
(
gie_config
!=
NULL
)
{
if
(
g_hash_table_contains
(
gie_config
->
bbox_border_color_table
,
class_index
+
(
gchar
*
)
NULL
))
{
obj
->
rect_params
.
border_color
=
*
((
NvOSD_ColorParams
*
)
g_hash_table_lookup
(
gie_config
->
bbox_border_color_table
,
class_index
+
(
gchar
*
)
NULL
));
}
else
{
obj
->
rect_params
.
border_color
=
gie_config
->
bbox_border_color
;
}
obj
->
rect_params
.
border_width
=
appCtx
->
config
.
osd_config
.
border_width
;
if
(
g_hash_table_contains
(
gie_config
->
bbox_bg_color_table
,
class_index
+
(
gchar
*
)
NULL
))
{
obj
->
rect_params
.
has_bg_color
=
1
;
obj
->
rect_params
.
bg_color
=
*
((
NvOSD_ColorParams
*
)
g_hash_table_lookup
(
gie_config
->
bbox_bg_color_table
,
class_index
+
(
gchar
*
)
NULL
));
}
else
{
obj
->
rect_params
.
has_bg_color
=
0
;
}
}
if
(
!
appCtx
->
show_bbox_text
)
continue
;
obj
->
text_params
.
x_offset
=
obj
->
rect_params
.
left
;
obj
->
text_params
.
y_offset
=
obj
->
rect_params
.
top
-
30
;
obj
->
text_params
.
font_params
.
font_color
=
appCtx
->
config
.
osd_config
.
text_color
;
obj
->
text_params
.
font_params
.
font_size
=
appCtx
->
config
.
osd_config
.
text_size
;
obj
->
text_params
.
font_params
.
font_name
=
appCtx
->
config
.
osd_config
.
font
;
if
(
appCtx
->
config
.
osd_config
.
text_has_bg
)
{
obj
->
text_params
.
set_bg_clr
=
1
;
obj
->
text_params
.
text_bg_clr
=
appCtx
->
config
.
osd_config
.
text_bg_color
;
}
obj
->
text_params
.
display_text
=
(
char
*
)
g_malloc
(
128
);
obj
->
text_params
.
display_text
[
0
]
=
'\0'
;
str_ins_pos
=
obj
->
text_params
.
display_text
;
if
(
obj
->
obj_label
[
0
]
!=
'\0'
)
sprintf
(
str_ins_pos
,
"%s"
,
obj
->
obj_label
);
str_ins_pos
+=
strlen
(
str_ins_pos
);
if
(
obj
->
object_id
!=
UNTRACKED_OBJECT_ID
)
{
/** object_id is a 64-bit sequential value;
* but considering the display aesthetic,
* trimming to lower 32-bits */
if
(
appCtx
->
config
.
tracker_config
.
display_tracking_id
)
{
guint64
const
LOW_32_MASK
=
0x00000000FFFFFFFF
;
sprintf
(
str_ins_pos
,
" %lu"
,
(
obj
->
object_id
&
LOW_32_MASK
));
str_ins_pos
+=
strlen
(
str_ins_pos
);
}
}
obj
->
classifier_meta_list
=
g_list_sort
(
obj
->
classifier_meta_list
,
component_id_compare_func
);
for
(
NvDsMetaList
*
l_class
=
obj
->
classifier_meta_list
;
l_class
!=
NULL
;
l_class
=
l_class
->
next
)
{
NvDsClassifierMeta
*
cmeta
=
(
NvDsClassifierMeta
*
)
l_class
->
data
;
for
(
NvDsMetaList
*
l_label
=
cmeta
->
label_info_list
;
l_label
!=
NULL
;
l_label
=
l_label
->
next
)
{
NvDsLabelInfo
*
label
=
(
NvDsLabelInfo
*
)
l_label
->
data
;
if
(
label
->
pResult_label
)
{
sprintf
(
str_ins_pos
,
" %s"
,
label
->
pResult_label
);
}
else
if
(
label
->
result_label
[
0
]
!=
'\0'
)
{
sprintf
(
str_ins_pos
,
" %s"
,
label
->
result_label
);
}
str_ins_pos
+=
strlen
(
str_ins_pos
);
}
}
}
}
}
/**
* Function which processes the inferred buffer and its metadata.
* It also gives opportunity to attach application specific
* metadata (e.g. clock, analytics output etc.).
*/
static
void
process_buffer
(
GstBuffer
*
buf
,
AppCtx
*
appCtx
,
guint
index
)
{
NvDsBatchMeta
*
batch_meta
=
gst_buffer_get_nvds_batch_meta
(
buf
);
if
(
!
batch_meta
)
{
NVGSTDS_WARN_MSG_V
(
"Batch meta not found for buffer %p"
,
buf
);
return
;
}
process_meta
(
appCtx
,
batch_meta
);
//NvDsInstanceData *data = &appCtx->instance_data[index];
//guint i;
// data->frame_num++;
/* Opportunity to modify the processed metadata or do analytics based on
* type of object e.g. maintaining count of particular type of car.
*/
if
(
appCtx
->
all_bbox_generated_cb
)
{
appCtx
->
all_bbox_generated_cb
(
appCtx
,
buf
,
batch_meta
,
index
);
}
//data->bbox_list_size = 0;
/*
* callback to attach application specific additional metadata.
*/
if
(
appCtx
->
overlay_graphics_cb
)
{
appCtx
->
overlay_graphics_cb
(
appCtx
,
buf
,
batch_meta
,
index
);
}
}
/**
* Buffer probe function to get the results of primary infer.
* Here it demonstrates the use by dumping bounding box coordinates in
* kitti format.
*/
static
GstPadProbeReturn
gie_primary_processing_done_buf_prob
(
GstPad
*
pad
,
GstPadProbeInfo
*
info
,
gpointer
u_data
)
{
GstBuffer
*
buf
=
(
GstBuffer
*
)
info
->
data
;
AppCtx
*
appCtx
=
(
AppCtx
*
)
u_data
;
NvDsBatchMeta
*
batch_meta
=
gst_buffer_get_nvds_batch_meta
(
buf
);
if
(
!
batch_meta
)
{
NVGSTDS_WARN_MSG_V
(
"Batch meta not found for buffer %p"
,
buf
);
return
GST_PAD_PROBE_OK
;
}
write_kitti_output
(
appCtx
,
batch_meta
);
return
GST_PAD_PROBE_OK
;
}
/**
* Probe function to get results after all inferences(Primary + Secondary)
* are done. This will be just before OSD or sink (in case OSD is disabled).
*/
static
GstPadProbeReturn
gie_processing_done_buf_prob
(
GstPad
*
pad
,
GstPadProbeInfo
*
info
,
gpointer
u_data
)
{
GstBuffer
*
buf
=
(
GstBuffer
*
)
info
->
data
;
NvDsInstanceBin
*
bin
=
(
NvDsInstanceBin
*
)
u_data
;
guint
index
=
bin
->
index
;
AppCtx
*
appCtx
=
bin
->
appCtx
;
if
(
gst_buffer_is_writable
(
buf
))
process_buffer
(
buf
,
appCtx
,
index
);
return
GST_PAD_PROBE_OK
;
}
/**
* Buffer probe function after tracker.
*/
static
GstPadProbeReturn
analytics_done_buf_prob
(
GstPad
*
pad
,
GstPadProbeInfo
*
info
,
gpointer
u_data
)
{
NvDsInstanceBin
*
bin
=
(
NvDsInstanceBin
*
)
u_data
;
guint
index
=
bin
->
index
;
AppCtx
*
appCtx
=
bin
->
appCtx
;
GstBuffer
*
buf
=
(
GstBuffer
*
)
info
->
data
;
NvDsBatchMeta
*
batch_meta
=
gst_buffer_get_nvds_batch_meta
(
buf
);
if
(
!
batch_meta
)
{
NVGSTDS_WARN_MSG_V
(
"Batch meta not found for buffer %p"
,
buf
);
return
GST_PAD_PROBE_OK
;
}
/*
* Output KITTI labels with tracking ID if configured to do so.
*/
write_kitti_track_output
(
appCtx
,
batch_meta
);
write_kitti_past_track_output
(
appCtx
,
batch_meta
);
write_reid_track_output
(
appCtx
,
batch_meta
);
write_terminated_track_output
(
appCtx
,
batch_meta
);
write_shadow_track_output
(
appCtx
,
batch_meta
);
if
(
appCtx
->
bbox_generated_post_analytics_cb
)
{
appCtx
->
bbox_generated_post_analytics_cb
(
appCtx
,
buf
,
batch_meta
,
index
);
}
return
GST_PAD_PROBE_OK
;
}
static
GstPadProbeReturn
latency_measurement_buf_prob
(
GstPad
*
pad
,
GstPadProbeInfo
*
info
,
gpointer
u_data
)
{
AppCtx
*
appCtx
=
(
AppCtx
*
)
u_data
;
guint
i
=
0
,
num_sources_in_batch
=
0
;
if
(
nvds_enable_latency_measurement
)
{
GstBuffer
*
buf
=
(
GstBuffer
*
)
info
->
data
;
NvDsFrameLatencyInfo
*
latency_info
=
NULL
;
g_mutex_lock
(
&
appCtx
->
latency_lock
);
latency_info
=
appCtx
->
latency_info
;
guint64
batch_num
=
GPOINTER_TO_SIZE
(
g_object_get_data
(
G_OBJECT
(
pad
),
"latency-batch-num"
));
g_print
(
"
\n
************BATCH-NUM = %lu**************
\n
"
,
batch_num
);
num_sources_in_batch
=
nvds_measure_buffer_latency
(
buf
,
latency_info
);
for
(
i
=
0
;
i
<
num_sources_in_batch
;
i
++
)
{
g_print
(
"Source id = %d Frame_num = %d Frame latency = %lf (ms)
\n
"
,
latency_info
[
i
].
source_id
,
latency_info
[
i
].
frame_num
,
latency_info
[
i
].
latency
);
}
g_mutex_unlock
(
&
appCtx
->
latency_lock
);
g_object_set_data
(
G_OBJECT
(
pad
),
"latency-batch-num"
,
GSIZE_TO_POINTER
(
batch_num
+
1
));
}
return
GST_PAD_PROBE_OK
;
}
static
GstPadProbeReturn
demux_latency_measurement_buf_prob
(
GstPad
*
pad
,
GstPadProbeInfo
*
info
,
gpointer
u_data
)
{
AppCtx
*
appCtx
=
(
AppCtx
*
)
u_data
;
guint
i
=
0
,
num_sources_in_batch
=
0
;
if
(
nvds_enable_latency_measurement
)
{
GstBuffer
*
buf
=
(
GstBuffer
*
)
info
->
data
;
NvDsFrameLatencyInfo
*
latency_info
=
NULL
;
g_mutex_lock
(
&
appCtx
->
latency_lock
);
latency_info
=
appCtx
->
latency_info
;
g_print
(
"
\n
************DEMUX BATCH-NUM = %d**************
\n
"
,
demux_batch_num
);
num_sources_in_batch
=
nvds_measure_buffer_latency
(
buf
,
latency_info
);
for
(
i
=
0
;
i
<
num_sources_in_batch
;
i
++
)
{
g_print
(
"Source id = %d Frame_num = %d Frame latency = %lf (ms)
\n
"
,
latency_info
[
i
].
source_id
,
latency_info
[
i
].
frame_num
,
latency_info
[
i
].
latency
);
}
g_mutex_unlock
(
&
appCtx
->
latency_lock
);
demux_batch_num
++
;
}
return
GST_PAD_PROBE_OK
;
}
static
gboolean
add_and_link_broker_sink
(
AppCtx
*
appCtx
)
{
NvDsConfig
*
config
=
&
appCtx
->
config
;
/** Only first instance_bin broker sink
* employed as there's only one analytics path for N sources
* NOTE: There shall be only one [sink] group
* with type=6 (NV_DS_SINK_MSG_CONV_BROKER)
* a) Multiple of them does not make sense as we have only
* one analytics pipe generating the data for broker sink
* b) If Multiple broker sinks are configured by the user
* in config file, only the first in the order of
* appearance will be considered
* and others shall be ignored
* c) Ideally it should be documented (or obvious) that:
* multiple [sink] groups with type=6 (NV_DS_SINK_MSG_CONV_BROKER)
* is invalid
*/
NvDsInstanceBin
*
instance_bin
=
&
appCtx
->
pipeline
.
instance_bins
[
0
];
NvDsPipeline
*
pipeline
=
&
appCtx
->
pipeline
;
for
(
guint
i
=
0
;
i
<
config
->
num_sink_sub_bins
;
i
++
)
{
if
(
config
->
sink_bin_sub_bin_config
[
i
].
type
==
NV_DS_SINK_MSG_CONV_BROKER
)
{
if
(
!
pipeline
->
common_elements
.
tee
)
{
NVGSTDS_ERR_MSG_V
(
"%s failed; broker added without analytics; check config file
\n
"
,
__func__
);
return
FALSE
;
}
/** add the broker sink bin to pipeline */
if
(
!
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
instance_bin
->
sink_bin
.
sub_bins
[
i
].
bin
))
{
return
FALSE
;
}
/** link the broker sink bin to the common_elements tee
* (The tee after nvinfer -> tracker (optional) -> sgies (optional) block) */
if
(
!
link_element_to_tee_src_pad
(
pipeline
->
common_elements
.
tee
,
instance_bin
->
sink_bin
.
sub_bins
[
i
].
bin
))
{
return
FALSE
;
}
}
}
return
TRUE
;
}
static
gboolean
create_demux_pipeline
(
AppCtx
*
appCtx
,
guint
index
)
{
gboolean
ret
=
FALSE
;
NvDsConfig
*
config
=
&
appCtx
->
config
;
NvDsInstanceBin
*
instance_bin
=
&
appCtx
->
pipeline
.
demux_instance_bins
[
index
];
GstElement
*
last_elem
;
gchar
elem_name
[
32
];
instance_bin
->
index
=
index
;
instance_bin
->
appCtx
=
appCtx
;
g_snprintf
(
elem_name
,
32
,
"processing_demux_bin_%d"
,
index
);
instance_bin
->
bin
=
gst_bin_new
(
elem_name
);
if
(
!
create_demux_sink_bin
(
config
->
num_sink_sub_bins
,
config
->
sink_bin_sub_bin_config
,
&
instance_bin
->
demux_sink_bin
,
config
->
sink_bin_sub_bin_config
[
index
].
source_id
))
{
goto
done
;
}
gst_bin_add
(
GST_BIN
(
instance_bin
->
bin
),
instance_bin
->
demux_sink_bin
.
bin
);
last_elem
=
instance_bin
->
demux_sink_bin
.
bin
;
if
(
config
->
osd_config
.
enable
)
{
if
(
!
create_osd_bin
(
&
config
->
osd_config
,
&
instance_bin
->
osd_bin
))
{
goto
done
;
}
gst_bin_add
(
GST_BIN
(
instance_bin
->
bin
),
instance_bin
->
osd_bin
.
bin
);
NVGSTDS_LINK_ELEMENT
(
instance_bin
->
osd_bin
.
bin
,
last_elem
);
last_elem
=
instance_bin
->
osd_bin
.
bin
;
}
NVGSTDS_BIN_ADD_GHOST_PAD
(
instance_bin
->
bin
,
last_elem
,
"sink"
);
if
(
config
->
osd_config
.
enable
)
{
NVGSTDS_ELEM_ADD_PROBE
(
instance_bin
->
all_bbox_buffer_probe_id
,
instance_bin
->
osd_bin
.
nvosd
,
"sink"
,
gie_processing_done_buf_prob
,
GST_PAD_PROBE_TYPE_BUFFER
,
instance_bin
);
}
else
{
NVGSTDS_ELEM_ADD_PROBE
(
instance_bin
->
all_bbox_buffer_probe_id
,
instance_bin
->
demux_sink_bin
.
bin
,
"sink"
,
gie_processing_done_buf_prob
,
GST_PAD_PROBE_TYPE_BUFFER
,
instance_bin
);
}
ret
=
TRUE
;
done:
if
(
!
ret
)
{
NVGSTDS_ERR_MSG_V
(
"%s failed"
,
__func__
);
}
return
ret
;
}
/**
* Function to add components to pipeline which are dependent on number
* of streams. These components work on single buffer. If tiling is being
* used then single instance will be created otherwise < N > such instances
* will be created for < N > streams
*/
static
gboolean
create_processing_instance
(
AppCtx
*
appCtx
,
guint
index
)
{
gboolean
ret
=
FALSE
;
NvDsConfig
*
config
=
&
appCtx
->
config
;
NvDsInstanceBin
*
instance_bin
=
&
appCtx
->
pipeline
.
instance_bins
[
index
];
GstElement
*
last_elem
;
gchar
elem_name
[
32
];
instance_bin
->
index
=
index
;
instance_bin
->
appCtx
=
appCtx
;
g_snprintf
(
elem_name
,
32
,
"processing_bin_%d"
,
index
);
instance_bin
->
bin
=
gst_bin_new
(
elem_name
);
if
(
!
create_sink_bin
(
config
->
num_sink_sub_bins
,
config
->
sink_bin_sub_bin_config
,
&
instance_bin
->
sink_bin
,
index
))
{
goto
done
;
}
gst_bin_add
(
GST_BIN
(
instance_bin
->
bin
),
instance_bin
->
sink_bin
.
bin
);
last_elem
=
instance_bin
->
sink_bin
.
bin
;
if
(
config
->
osd_config
.
enable
)
{
if
(
!
create_osd_bin
(
&
config
->
osd_config
,
&
instance_bin
->
osd_bin
))
{
goto
done
;
}
gst_bin_add
(
GST_BIN
(
instance_bin
->
bin
),
instance_bin
->
osd_bin
.
bin
);
NVGSTDS_LINK_ELEMENT
(
instance_bin
->
osd_bin
.
bin
,
last_elem
);
last_elem
=
instance_bin
->
osd_bin
.
bin
;
}
NVGSTDS_BIN_ADD_GHOST_PAD
(
instance_bin
->
bin
,
last_elem
,
"sink"
);
if
(
config
->
osd_config
.
enable
)
{
NVGSTDS_ELEM_ADD_PROBE
(
instance_bin
->
all_bbox_buffer_probe_id
,
instance_bin
->
osd_bin
.
nvosd
,
"sink"
,
gie_processing_done_buf_prob
,
GST_PAD_PROBE_TYPE_BUFFER
,
instance_bin
);
}
else
{
NVGSTDS_ELEM_ADD_PROBE
(
instance_bin
->
all_bbox_buffer_probe_id
,
instance_bin
->
sink_bin
.
bin
,
"sink"
,
gie_processing_done_buf_prob
,
GST_PAD_PROBE_TYPE_BUFFER
,
instance_bin
);
}
ret
=
TRUE
;
done:
if
(
!
ret
)
{
NVGSTDS_ERR_MSG_V
(
"%s failed"
,
__func__
);
}
return
ret
;
}
/**
* Function to create common elements(Primary infer, tracker, secondary infer)
* of the pipeline. These components operate on muxed data from all the
* streams. So they are independent of number of streams in the pipeline.
*/
static
gboolean
create_common_elements
(
NvDsConfig
*
config
,
NvDsPipeline
*
pipeline
,
GstElement
**
sink_elem
,
GstElement
**
src_elem
,
bbox_generated_callback
bbox_generated_post_analytics_cb
)
{
gboolean
ret
=
FALSE
;
*
sink_elem
=
*
src_elem
=
NULL
;
if
(
config
->
segvisual_config
.
enable
)
{
if
(
!
create_segvisual_bin
(
&
config
->
segvisual_config
,
&
pipeline
->
common_elements
.
segvisual_bin
))
{
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
common_elements
.
segvisual_bin
.
bin
);
if
(
!*
src_elem
)
{
*
src_elem
=
pipeline
->
common_elements
.
segvisual_bin
.
bin
;
}
if
(
*
sink_elem
)
{
NVGSTDS_LINK_ELEMENT
(
pipeline
->
common_elements
.
segvisual_bin
.
bin
,
*
sink_elem
);
}
*
sink_elem
=
pipeline
->
common_elements
.
segvisual_bin
.
bin
;
}
if
(
config
->
primary_gie_config
.
enable
)
{
if
(
config
->
num_secondary_gie_sub_bins
>
0
)
{
/** if using nvmultiurisrcbin, override batch-size config for sgie */
if
(
config
->
use_nvmultiurisrcbin
)
{
for
(
guint
i
=
0
;
i
<
config
->
num_secondary_gie_sub_bins
;
i
++
)
{
config
->
secondary_gie_sub_bin_config
[
i
].
batch_size
=
config
->
sgie_batch_size
;
}
}
if
(
!
create_secondary_gie_bin
(
config
->
num_secondary_gie_sub_bins
,
config
->
primary_gie_config
.
unique_id
,
config
->
secondary_gie_sub_bin_config
,
&
pipeline
->
common_elements
.
secondary_gie_bin
))
{
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
common_elements
.
secondary_gie_bin
.
bin
);
if
(
!*
src_elem
)
{
*
src_elem
=
pipeline
->
common_elements
.
secondary_gie_bin
.
bin
;
}
if
(
*
sink_elem
)
{
NVGSTDS_LINK_ELEMENT
(
pipeline
->
common_elements
.
secondary_gie_bin
.
bin
,
*
sink_elem
);
}
*
sink_elem
=
pipeline
->
common_elements
.
secondary_gie_bin
.
bin
;
}
}
if
(
config
->
primary_gie_config
.
enable
)
{
if
(
config
->
num_secondary_preprocess_sub_bins
>
0
)
{
if
(
!
create_secondary_preprocess_bin
(
config
->
num_secondary_preprocess_sub_bins
,
config
->
primary_gie_config
.
unique_id
,
config
->
secondary_preprocess_sub_bin_config
,
&
pipeline
->
common_elements
.
secondary_preprocess_bin
))
{
g_print
(
"creating secondary_preprocess bin failed
\n
"
);
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
common_elements
.
secondary_preprocess_bin
.
bin
);
if
(
!*
src_elem
)
{
*
src_elem
=
pipeline
->
common_elements
.
secondary_preprocess_bin
.
bin
;
}
if
(
*
sink_elem
)
{
NVGSTDS_LINK_ELEMENT
(
pipeline
->
common_elements
.
secondary_preprocess_bin
.
bin
,
*
sink_elem
);
}
*
sink_elem
=
pipeline
->
common_elements
.
secondary_preprocess_bin
.
bin
;
}
}
if
(
config
->
dsanalytics_config
.
enable
)
{
if
(
!
create_dsanalytics_bin
(
&
config
->
dsanalytics_config
,
&
pipeline
->
common_elements
.
dsanalytics_bin
))
{
g_print
(
"creating dsanalytics bin failed
\n
"
);
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
common_elements
.
dsanalytics_bin
.
bin
);
if
(
!*
src_elem
)
{
*
src_elem
=
pipeline
->
common_elements
.
dsanalytics_bin
.
bin
;
}
if
(
*
sink_elem
)
{
NVGSTDS_LINK_ELEMENT
(
pipeline
->
common_elements
.
dsanalytics_bin
.
bin
,
*
sink_elem
);
}
*
sink_elem
=
pipeline
->
common_elements
.
dsanalytics_bin
.
bin
;
}
if
(
config
->
tracker_config
.
enable
)
{
if
(
!
create_tracking_bin
(
&
config
->
tracker_config
,
&
pipeline
->
common_elements
.
tracker_bin
))
{
g_print
(
"creating tracker bin failed
\n
"
);
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
common_elements
.
tracker_bin
.
bin
);
if
(
!*
src_elem
)
{
*
src_elem
=
pipeline
->
common_elements
.
tracker_bin
.
bin
;
}
if
(
*
sink_elem
)
{
NVGSTDS_LINK_ELEMENT
(
pipeline
->
common_elements
.
tracker_bin
.
bin
,
*
sink_elem
);
}
*
sink_elem
=
pipeline
->
common_elements
.
tracker_bin
.
bin
;
}
if
(
config
->
primary_gie_config
.
enable
)
{
/** if using nvmultiurisrcbin, override batch-size config for pgie */
if
(
config
->
use_nvmultiurisrcbin
)
{
config
->
primary_gie_config
.
batch_size
=
config
->
max_batch_size
;
}
if
(
!
create_primary_gie_bin
(
&
config
->
primary_gie_config
,
&
pipeline
->
common_elements
.
primary_gie_bin
))
{
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
common_elements
.
primary_gie_bin
.
bin
);
if
(
*
sink_elem
)
{
NVGSTDS_LINK_ELEMENT
(
pipeline
->
common_elements
.
primary_gie_bin
.
bin
,
*
sink_elem
);
}
*
sink_elem
=
pipeline
->
common_elements
.
primary_gie_bin
.
bin
;
if
(
!*
src_elem
)
{
*
src_elem
=
pipeline
->
common_elements
.
primary_gie_bin
.
bin
;
}
NVGSTDS_ELEM_ADD_PROBE
(
pipeline
->
common_elements
.
primary_bbox_buffer_probe_id
,
pipeline
->
common_elements
.
primary_gie_bin
.
bin
,
"src"
,
gie_primary_processing_done_buf_prob
,
GST_PAD_PROBE_TYPE_BUFFER
,
pipeline
->
common_elements
.
appCtx
);
}
if
(
config
->
preprocess_config
.
enable
)
{
if
(
!
create_preprocess_bin
(
&
config
->
preprocess_config
,
&
pipeline
->
common_elements
.
preprocess_bin
))
{
g_print
(
"creating preprocess bin failed
\n
"
);
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
common_elements
.
preprocess_bin
.
bin
);
if
(
!*
src_elem
)
{
*
src_elem
=
pipeline
->
common_elements
.
preprocess_bin
.
bin
;
}
if
(
*
sink_elem
)
{
NVGSTDS_LINK_ELEMENT
(
pipeline
->
common_elements
.
preprocess_bin
.
bin
,
*
sink_elem
);
}
*
sink_elem
=
pipeline
->
common_elements
.
preprocess_bin
.
bin
;
}
if
(
*
src_elem
)
{
NVGSTDS_ELEM_ADD_PROBE
(
pipeline
->
common_elements
.
primary_bbox_buffer_probe_id
,
*
src_elem
,
"src"
,
analytics_done_buf_prob
,
GST_PAD_PROBE_TYPE_BUFFER
,
&
pipeline
->
common_elements
);
/* Add common message converter */
if
(
config
->
msg_conv_config
.
enable
)
{
NvDsSinkMsgConvBrokerConfig
*
convConfig
=
&
config
->
msg_conv_config
;
pipeline
->
common_elements
.
msg_conv
=
gst_element_factory_make
(
NVDS_ELEM_MSG_CONV
,
"common_msg_conv"
);
if
(
!
pipeline
->
common_elements
.
msg_conv
)
{
NVGSTDS_ERR_MSG_V
(
"Failed to create element 'common_msg_conv'"
);
goto
done
;
}
g_object_set
(
G_OBJECT
(
pipeline
->
common_elements
.
msg_conv
),
"config"
,
convConfig
->
config_file_path
,
"msg2p-lib"
,
(
convConfig
->
conv_msg2p_lib
?
convConfig
->
conv_msg2p_lib
:
"null"
),
"payload-type"
,
convConfig
->
conv_payload_type
,
"comp-id"
,
convConfig
->
conv_comp_id
,
"debug-payload-dir"
,
convConfig
->
debug_payload_dir
,
"multiple-payloads"
,
convConfig
->
multiple_payloads
,
"msg2p-newapi"
,
convConfig
->
conv_msg2p_new_api
,
"frame-interval"
,
convConfig
->
conv_frame_interval
,
NULL
);
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
common_elements
.
msg_conv
);
NVGSTDS_LINK_ELEMENT
(
*
src_elem
,
pipeline
->
common_elements
.
msg_conv
);
*
src_elem
=
pipeline
->
common_elements
.
msg_conv
;
}
pipeline
->
common_elements
.
tee
=
gst_element_factory_make
(
NVDS_ELEM_TEE
,
"common_analytics_tee"
);
if
(
!
pipeline
->
common_elements
.
tee
)
{
NVGSTDS_ERR_MSG_V
(
"Failed to create element 'common_analytics_tee'"
);
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
common_elements
.
tee
);
NVGSTDS_LINK_ELEMENT
(
*
src_elem
,
pipeline
->
common_elements
.
tee
);
*
src_elem
=
pipeline
->
common_elements
.
tee
;
}
ret
=
TRUE
;
done:
return
ret
;
}
static
gboolean
is_sink_available_for_source_id
(
NvDsConfig
*
config
,
guint
source_id
)
{
for
(
guint
j
=
0
;
j
<
config
->
num_sink_sub_bins
;
j
++
)
{
if
(
config
->
sink_bin_sub_bin_config
[
j
].
enable
&&
config
->
sink_bin_sub_bin_config
[
j
].
source_id
==
source_id
&&
config
->
sink_bin_sub_bin_config
[
j
].
link_to_demux
==
FALSE
)
{
return
TRUE
;
}
}
return
FALSE
;
}
/**
* Main function to create the pipeline.
*/
gboolean
create_pipeline
(
AppCtx
*
appCtx
,
bbox_generated_callback
bbox_generated_post_analytics_cb
,
bbox_generated_callback
all_bbox_generated_cb
,
perf_callback
perf_cb
,
overlay_graphics_callback
overlay_graphics_cb
)
{
gboolean
ret
=
FALSE
;
NvDsPipeline
*
pipeline
=
&
appCtx
->
pipeline
;
NvDsConfig
*
config
=
&
appCtx
->
config
;
GstBus
*
bus
;
GstElement
*
last_elem
;
GstElement
*
tmp_elem1
;
GstElement
*
tmp_elem2
;
guint
i
;
GstPad
*
fps_pad
=
NULL
;
gulong
latency_probe_id
;
_dsmeta_quark
=
g_quark_from_static_string
(
NVDS_META_STRING
);
appCtx
->
all_bbox_generated_cb
=
all_bbox_generated_cb
;
appCtx
->
bbox_generated_post_analytics_cb
=
bbox_generated_post_analytics_cb
;
appCtx
->
overlay_graphics_cb
=
overlay_graphics_cb
;
appCtx
->
sensorInfoHash
=
g_hash_table_new
(
NULL
,
NULL
);
appCtx
->
perf_struct
.
FPSInfoHash
=
g_hash_table_new_full
(
g_direct_hash
,
g_direct_equal
,
NULL
,
NULL
);
if
(
config
->
osd_config
.
num_out_buffers
<
8
)
{
config
->
osd_config
.
num_out_buffers
=
8
;
}
pipeline
->
pipeline
=
gst_pipeline_new
(
"pipeline"
);
if
(
!
pipeline
->
pipeline
)
{
NVGSTDS_ERR_MSG_V
(
"Failed to create pipeline"
);
goto
done
;
}
bus
=
gst_pipeline_get_bus
(
GST_PIPELINE
(
pipeline
->
pipeline
));
pipeline
->
bus_id
=
gst_bus_add_watch
(
bus
,
bus_callback
,
appCtx
);
gst_object_unref
(
bus
);
if
(
config
->
file_loop
)
{
/* Let each source bin know it needs to loop. */
guint
i
;
for
(
i
=
0
;
i
<
config
->
num_source_sub_bins
;
i
++
)
config
->
multi_source_config
[
i
].
loop
=
TRUE
;
}
for
(
guint
i
=
0
;
i
<
config
->
num_sink_sub_bins
;
i
++
)
{
NvDsSinkSubBinConfig
*
sink_config
=
&
config
->
sink_bin_sub_bin_config
[
i
];
switch
(
sink_config
->
type
)
{
case
NV_DS_SINK_FAKE
:
#ifndef IS_TEGRA
case
NV_DS_SINK_RENDER_EGL
:
#else
case
NV_DS_SINK_RENDER_3D
:
#endif
case
NV_DS_SINK_RENDER_DRM
:
/* Set the "qos" property of sink, if not explicitly specified in the
config. */
if
(
!
sink_config
->
render_config
.
qos_value_specified
)
{
sink_config
->
render_config
.
qos
=
FALSE
;
}
default:
break
;
}
}
/*
* Add muxer and < N > source components to the pipeline based
* on the settings in configuration file.
*/
if
(
config
->
use_nvmultiurisrcbin
)
{
if
(
config
->
num_source_sub_bins
>
0
){
if
(
!
create_nvmultiurisrcbin_bin
(
config
->
num_source_sub_bins
,
config
->
multi_source_config
,
&
pipeline
->
multi_src_bin
))
goto
done
;
}
else
{
if
(
!
config
->
source_attr_all_parsed
)
{
NVGSTDS_ERR_MSG_V
(
"[source-attr-all] config group not set, needs to be configured"
);
goto
done
;
}
if
(
!
create_nvmultiurisrcbin_bin
(
config
->
num_source_sub_bins
,
&
config
->
source_attr_all_config
,
&
pipeline
->
multi_src_bin
))
goto
done
;
//[source-list] added with num-source-bins=0; This means source-bin
//will be created and be waiting for source adds over REST API
//mark num-source-bins=1 as one source-bin is indeed created
config
->
num_source_sub_bins
=
1
;
}
/** set properties for nvmultiurisrcbin */
if
(
config
->
uri_list
)
{
gchar
*
uri_list_comma_sep
=
g_strjoinv
(
","
,
config
->
uri_list
);
g_object_set
(
pipeline
->
multi_src_bin
.
nvmultiurisrcbin
,
"uri-list"
,
uri_list_comma_sep
,
NULL
);
g_free
(
uri_list_comma_sep
);
}
if
(
config
->
sensor_id_list
)
{
gchar
*
uri_list_comma_sep
=
g_strjoinv
(
","
,
config
->
sensor_id_list
);
g_object_set
(
pipeline
->
multi_src_bin
.
nvmultiurisrcbin
,
"sensor-id-list"
,
uri_list_comma_sep
,
NULL
);
g_free
(
uri_list_comma_sep
);
}
if
(
config
->
sensor_name_list
)
{
gchar
*
uri_list_comma_sep
=
g_strjoinv
(
","
,
config
->
sensor_name_list
);
g_object_set
(
pipeline
->
multi_src_bin
.
nvmultiurisrcbin
,
"sensor-name-list"
,
uri_list_comma_sep
,
NULL
);
g_free
(
uri_list_comma_sep
);
}
g_object_set
(
pipeline
->
multi_src_bin
.
nvmultiurisrcbin
,
"max-batch-size"
,
config
->
max_batch_size
,
NULL
);
g_object_set
(
pipeline
->
multi_src_bin
.
nvmultiurisrcbin
,
"ip-address"
,
config
->
http_ip
,
NULL
);
g_object_set
(
pipeline
->
multi_src_bin
.
nvmultiurisrcbin
,
"port"
,
config
->
http_port
,
NULL
);
g_object_set
(
pipeline
->
multi_src_bin
.
nvmultiurisrcbin
,
"extract-sei-type5-data-dec"
,
config
->
extract_sei_type5_data
,
NULL
);
g_object_set
(
pipeline
->
multi_src_bin
.
nvmultiurisrcbin
,
"low-latency-mode"
,
config
->
low_latency_mode
,
NULL
);
g_object_set
(
pipeline
->
multi_src_bin
.
nvmultiurisrcbin
,
"sei-uuid"
,
config
->
sei_uuid
,
NULL
);
}
else
{
if
(
!
create_multi_source_bin
(
config
->
num_source_sub_bins
,
config
->
multi_source_config
,
&
pipeline
->
multi_src_bin
))
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
multi_src_bin
.
bin
);
if
(
config
->
streammux_config
.
is_parsed
)
{
if
(
config
->
use_nvmultiurisrcbin
)
{
config
->
streammux_config
.
use_nvmultiurisrcbin
=
TRUE
;
/** overriding mux_config.batch_size to max_batch_size */
config
->
streammux_config
.
batch_size
=
config
->
max_batch_size
;
}
if
(
!
set_streammux_properties
(
&
config
->
streammux_config
,
pipeline
->
multi_src_bin
.
streammux
))
{
NVGSTDS_WARN_MSG_V
(
"Failed to set streammux properties"
);
}
}
if
(
appCtx
->
latency_info
==
NULL
)
{
appCtx
->
latency_info
=
(
NvDsFrameLatencyInfo
*
)
calloc
(
1
,
config
->
streammux_config
.
batch_size
*
sizeof
(
NvDsFrameLatencyInfo
));
}
/** a tee after the tiler which shall be connected to sink(s) */
pipeline
->
tiler_tee
=
gst_element_factory_make
(
NVDS_ELEM_TEE
,
"tiler_tee"
);
if
(
!
pipeline
->
tiler_tee
)
{
NVGSTDS_ERR_MSG_V
(
"Failed to create element 'tiler_tee'"
);
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
tiler_tee
);
/** Tiler + Demux in Parallel Use-Case */
if
(
config
->
tiled_display_config
.
enable
==
NV_DS_TILED_DISPLAY_ENABLE_WITH_PARALLEL_DEMUX
)
{
pipeline
->
demuxer
=
gst_element_factory_make
(
NVDS_ELEM_STREAM_DEMUX
,
"demuxer"
);
if
(
!
pipeline
->
demuxer
)
{
NVGSTDS_ERR_MSG_V
(
"Failed to create element 'demuxer'"
);
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
demuxer
);
/** NOTE:
* demux output is supported for only one source
* If multiple [sink] groups are configured with
* link_to_demux=1, only the first [sink]
* shall be constructed for all occurences of
* [sink] groups with link_to_demux=1
*/
{
gchar
pad_name
[
16
];
GstPad
*
demux_src_pad
;
i
=
0
;
if
(
!
create_demux_pipeline
(
appCtx
,
i
))
{
goto
done
;
}
for
(
i
=
0
;
i
<
config
->
num_sink_sub_bins
;
i
++
)
{
if
(
config
->
sink_bin_sub_bin_config
[
i
].
link_to_demux
==
TRUE
)
{
g_snprintf
(
pad_name
,
16
,
"src_%02d"
,
config
->
sink_bin_sub_bin_config
[
i
].
source_id
);
break
;
}
}
if
(
i
>=
config
->
num_sink_sub_bins
)
{
g_print
(
"
\n\n
Error : sink for demux (use link-to-demux-only property) is not provided in the config file
\n\n
"
);
goto
done
;
}
i
=
0
;
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
demux_instance_bins
[
i
].
bin
);
demux_src_pad
=
gst_element_request_pad_simple
(
pipeline
->
demuxer
,
pad_name
);
NVGSTDS_LINK_ELEMENT_FULL
(
pipeline
->
demuxer
,
pad_name
,
pipeline
->
demux_instance_bins
[
i
].
bin
,
"sink"
);
gst_object_unref
(
demux_src_pad
);
NVGSTDS_ELEM_ADD_PROBE
(
latency_probe_id
,
appCtx
->
pipeline
.
demux_instance_bins
[
i
].
demux_sink_bin
.
bin
,
"sink"
,
demux_latency_measurement_buf_prob
,
GST_PAD_PROBE_TYPE_BUFFER
,
appCtx
);
latency_probe_id
=
latency_probe_id
;
}
last_elem
=
pipeline
->
demuxer
;
link_element_to_tee_src_pad
(
pipeline
->
tiler_tee
,
last_elem
);
last_elem
=
pipeline
->
tiler_tee
;
}
if
(
config
->
tiled_display_config
.
enable
)
{
/* Tiler will generate a single composited buffer for all sources. So need
* to create only one processing instance. */
if
(
!
create_processing_instance
(
appCtx
,
0
))
{
goto
done
;
}
// create and add tiling component to pipeline.
if
(
config
->
tiled_display_config
.
columns
*
config
->
tiled_display_config
.
rows
<
config
->
num_source_sub_bins
)
{
if
(
config
->
tiled_display_config
.
columns
==
0
)
{
config
->
tiled_display_config
.
columns
=
(
guint
)
(
sqrt
(
config
->
num_source_sub_bins
)
+
0
.
5
);
}
config
->
tiled_display_config
.
rows
=
(
guint
)
ceil
(
1
.
0
*
config
->
num_source_sub_bins
/
config
->
tiled_display_config
.
columns
);
NVGSTDS_WARN_MSG_V
(
"Num of Tiles less than number of sources, readjusting to "
"%u rows, %u columns"
,
config
->
tiled_display_config
.
rows
,
config
->
tiled_display_config
.
columns
);
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
instance_bins
[
0
].
bin
);
last_elem
=
pipeline
->
instance_bins
[
0
].
bin
;
if
(
!
create_tiled_display_bin
(
&
config
->
tiled_display_config
,
&
pipeline
->
tiled_display_bin
))
{
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
tiled_display_bin
.
bin
);
NVGSTDS_LINK_ELEMENT
(
pipeline
->
tiled_display_bin
.
bin
,
last_elem
);
last_elem
=
pipeline
->
tiled_display_bin
.
bin
;
link_element_to_tee_src_pad
(
pipeline
->
tiler_tee
,
pipeline
->
tiled_display_bin
.
bin
);
last_elem
=
pipeline
->
tiler_tee
;
NVGSTDS_ELEM_ADD_PROBE
(
latency_probe_id
,
pipeline
->
instance_bins
->
sink_bin
.
sub_bins
[
0
].
sink
,
"sink"
,
latency_measurement_buf_prob
,
GST_PAD_PROBE_TYPE_BUFFER
,
appCtx
);
latency_probe_id
=
latency_probe_id
;
}
else
{
/*
* Create demuxer only if tiled display is disabled.
*/
pipeline
->
demuxer
=
gst_element_factory_make
(
NVDS_ELEM_STREAM_DEMUX
,
"demuxer"
);
if
(
!
pipeline
->
demuxer
)
{
NVGSTDS_ERR_MSG_V
(
"Failed to create element 'demuxer'"
);
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
demuxer
);
for
(
i
=
0
;
i
<
config
->
num_source_sub_bins
;
i
++
)
{
gchar
pad_name
[
16
];
GstPad
*
demux_src_pad
;
/* Check if any sink has been configured to render/encode output for
* source index `i`. The processing instance for that source will be
* created only if atleast one sink has been configured as such.
*/
if
(
!
is_sink_available_for_source_id
(
config
,
i
))
continue
;
if
(
!
create_processing_instance
(
appCtx
,
i
))
{
goto
done
;
}
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
instance_bins
[
i
].
bin
);
g_snprintf
(
pad_name
,
16
,
"src_%02d"
,
i
);
demux_src_pad
=
gst_element_request_pad_simple
(
pipeline
->
demuxer
,
pad_name
);
NVGSTDS_LINK_ELEMENT_FULL
(
pipeline
->
demuxer
,
pad_name
,
pipeline
->
instance_bins
[
i
].
bin
,
"sink"
);
gst_object_unref
(
demux_src_pad
);
for
(
int
k
=
0
;
k
<
MAX_SINK_BINS
;
k
++
)
{
if
(
pipeline
->
instance_bins
[
i
].
sink_bin
.
sub_bins
[
k
].
sink
)
{
NVGSTDS_ELEM_ADD_PROBE
(
latency_probe_id
,
pipeline
->
instance_bins
[
i
].
sink_bin
.
sub_bins
[
k
].
sink
,
"sink"
,
latency_measurement_buf_prob
,
GST_PAD_PROBE_TYPE_BUFFER
,
appCtx
);
break
;
}
}
latency_probe_id
=
latency_probe_id
;
}
last_elem
=
pipeline
->
demuxer
;
}
if
(
config
->
tiled_display_config
.
enable
==
NV_DS_TILED_DISPLAY_DISABLE
)
{
fps_pad
=
gst_element_get_static_pad
(
pipeline
->
demuxer
,
"sink"
);
}
else
{
fps_pad
=
gst_element_get_static_pad
(
pipeline
->
tiled_display_bin
.
bin
,
"sink"
);
}
pipeline
->
common_elements
.
appCtx
=
appCtx
;
// Decide where in the pipeline the element should be added and add only if
// enabled
if
(
config
->
dsexample_config
.
enable
)
{
// Create dsexample element bin and set properties
if
(
!
create_dsexample_bin
(
&
config
->
dsexample_config
,
&
pipeline
->
dsexample_bin
))
{
goto
done
;
}
// Add dsexample bin to instance bin
gst_bin_add
(
GST_BIN
(
pipeline
->
pipeline
),
pipeline
->
dsexample_bin
.
bin
);
// Link this bin to the last element in the bin
NVGSTDS_LINK_ELEMENT
(
pipeline
->
dsexample_bin
.
bin
,
last_elem
);
// Set this bin as the last element
last_elem
=
pipeline
->
dsexample_bin
.
bin
;
}
// create and add common components to pipeline.
if
(
!
create_common_elements
(
config
,
pipeline
,
&
tmp_elem1
,
&
tmp_elem2
,
bbox_generated_post_analytics_cb
))
{
goto
done
;
}
if
(
!
add_and_link_broker_sink
(
appCtx
))
{
goto
done
;
}
if
(
tmp_elem2
)
{
NVGSTDS_LINK_ELEMENT
(
tmp_elem2
,
last_elem
);
last_elem
=
tmp_elem1
;
}
NVGSTDS_LINK_ELEMENT
(
pipeline
->
multi_src_bin
.
bin
,
last_elem
);
// enable performance measurement and add call back function to receive
// performance data.
if
(
config
->
enable_perf_measurement
)
{
appCtx
->
perf_struct
.
context
=
appCtx
;
if
(
config
->
use_nvmultiurisrcbin
)
{
appCtx
->
perf_struct
.
stream_name_display
=
config
->
stream_name_display
;
appCtx
->
perf_struct
.
use_nvmultiurisrcbin
=
config
->
use_nvmultiurisrcbin
;
enable_perf_measurement
(
&
appCtx
->
perf_struct
,
fps_pad
,
config
->
max_batch_size
,
config
->
perf_measurement_interval_sec
,
config
->
multi_source_config
[
0
].
dewarper_config
.
num_surfaces_per_frame
,
perf_cb
);
}
else
{
enable_perf_measurement
(
&
appCtx
->
perf_struct
,
fps_pad
,
pipeline
->
multi_src_bin
.
num_bins
,
config
->
perf_measurement_interval_sec
,
config
->
multi_source_config
[
0
].
dewarper_config
.
num_surfaces_per_frame
,
perf_cb
);
}
}
latency_probe_id
=
latency_probe_id
;
if
(
config
->
num_message_consumers
)
{
for
(
i
=
0
;
i
<
config
->
num_message_consumers
;
i
++
)
{
appCtx
->
c2d_ctx
[
i
]
=
start_cloud_to_device_messaging
(
&
config
->
message_consumer_config
[
i
],
NULL
,
&
appCtx
->
pipeline
.
multi_src_bin
);
if
(
appCtx
->
c2d_ctx
[
i
]
==
NULL
)
{
NVGSTDS_ERR_MSG_V
(
"Failed to create message consumer"
);
goto
done
;
}
}
}
GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS
(
GST_BIN
(
appCtx
->
pipeline
.
pipeline
),
GST_DEBUG_GRAPH_SHOW_ALL
,
"ds-app-null"
);
g_mutex_init
(
&
appCtx
->
app_lock
);
g_cond_init
(
&
appCtx
->
app_cond
);
g_mutex_init
(
&
appCtx
->
latency_lock
);
ret
=
TRUE
;
done:
if
(
fps_pad
)
gst_object_unref
(
fps_pad
);
if
(
!
ret
)
{
NVGSTDS_ERR_MSG_V
(
"%s failed"
,
__func__
);
}
return
ret
;
}
/**
* Function to destroy pipeline and release the resources, probes etc.
*/
void
destroy_pipeline
(
AppCtx
*
appCtx
)
{
gint64
end_time
;
NvDsConfig
*
config
=
&
appCtx
->
config
;
guint
i
;
GstBus
*
bus
=
NULL
;
end_time
=
g_get_monotonic_time
()
+
G_TIME_SPAN_SECOND
;
if
(
!
appCtx
)
return
;
gst_element_send_event
(
appCtx
->
pipeline
.
pipeline
,
gst_event_new_eos
());
sleep
(
1
);
g_mutex_lock
(
&
appCtx
->
app_lock
);
if
(
appCtx
->
pipeline
.
pipeline
)
{
destroy_smart_record_bin
(
&
appCtx
->
pipeline
.
multi_src_bin
);
bus
=
gst_pipeline_get_bus
(
GST_PIPELINE
(
appCtx
->
pipeline
.
pipeline
));
while
(
TRUE
)
{
GstMessage
*
message
=
gst_bus_pop
(
bus
);
if
(
message
==
NULL
||
GST_MESSAGE_TYPE
(
message
)
==
GST_MESSAGE_EOS
)
break
;
else
if
(
GST_MESSAGE_TYPE
(
message
)
==
GST_MESSAGE_ERROR
)
bus_callback
(
bus
,
message
,
appCtx
);
else
gst_message_unref
(
message
);
}
gst_object_unref
(
bus
);
gst_element_set_state
(
appCtx
->
pipeline
.
pipeline
,
GST_STATE_NULL
);
}
g_cond_wait_until
(
&
appCtx
->
app_cond
,
&
appCtx
->
app_lock
,
end_time
);
g_mutex_unlock
(
&
appCtx
->
app_lock
);
for
(
i
=
0
;
i
<
appCtx
->
config
.
num_source_sub_bins
;
i
++
)
{
NvDsInstanceBin
*
bin
=
&
appCtx
->
pipeline
.
instance_bins
[
i
];
if
(
config
->
osd_config
.
enable
)
{
NVGSTDS_ELEM_REMOVE_PROBE
(
bin
->
all_bbox_buffer_probe_id
,
bin
->
osd_bin
.
nvosd
,
"sink"
);
}
else
{
NVGSTDS_ELEM_REMOVE_PROBE
(
bin
->
all_bbox_buffer_probe_id
,
bin
->
sink_bin
.
bin
,
"sink"
);
}
if
(
config
->
primary_gie_config
.
enable
)
{
NVGSTDS_ELEM_REMOVE_PROBE
(
bin
->
primary_bbox_buffer_probe_id
,
bin
->
primary_gie_bin
.
bin
,
"src"
);
}
}
if
(
appCtx
->
latency_info
==
NULL
)
{
free
(
appCtx
->
latency_info
);
appCtx
->
latency_info
=
NULL
;
}
if
(
appCtx
->
sensorInfoHash
)
{
g_hash_table_destroy
(
appCtx
->
sensorInfoHash
);
}
if
(
appCtx
->
perf_struct
.
FPSInfoHash
)
{
g_hash_table_destroy
(
appCtx
->
perf_struct
.
FPSInfoHash
);
}
destroy_sink_bin
();
g_mutex_clear
(
&
appCtx
->
latency_lock
);
if
(
appCtx
->
pipeline
.
pipeline
)
{
bus
=
gst_pipeline_get_bus
(
GST_PIPELINE
(
appCtx
->
pipeline
.
pipeline
));
gst_bus_remove_watch
(
bus
);
gst_object_unref
(
bus
);
gst_object_unref
(
appCtx
->
pipeline
.
pipeline
);
appCtx
->
pipeline
.
pipeline
=
NULL
;
pause_perf_measurement
(
&
appCtx
->
perf_struct
);
//for pipeline-recreate, reset rtsp srouce's depay, such as rtph264depay.
NvDsSrcParentBin
*
pbin
=
&
appCtx
->
pipeline
.
multi_src_bin
;
if
(
pbin
){
NvDsSrcBin
*
src_bin
;
for
(
i
=
0
;
i
<
MAX_SOURCE_BINS
;
i
++
)
{
src_bin
=
&
pbin
->
sub_bins
[
i
];
if
(
src_bin
&&
src_bin
->
config
&&
src_bin
->
config
->
type
==
NV_DS_SOURCE_RTSP
){
src_bin
->
depay
=
NULL
;
}
}
}
}
if
(
config
->
num_message_consumers
)
{
for
(
i
=
0
;
i
<
config
->
num_message_consumers
;
i
++
)
{
if
(
appCtx
->
c2d_ctx
[
i
])
stop_cloud_to_device_messaging
(
appCtx
->
c2d_ctx
[
i
]);
}
}
}
gboolean
pause_pipeline
(
AppCtx
*
appCtx
)
{
GstState
cur
;
GstState
pending
;
GstStateChangeReturn
ret
;
GstClockTime
timeout
=
5
*
GST_SECOND
/
1000
;
ret
=
gst_element_get_state
(
appCtx
->
pipeline
.
pipeline
,
&
cur
,
&
pending
,
timeout
);
if
(
ret
==
GST_STATE_CHANGE_ASYNC
)
{
return
FALSE
;
}
if
(
cur
==
GST_STATE_PAUSED
)
{
return
TRUE
;
}
else
if
(
cur
==
GST_STATE_PLAYING
)
{
gst_element_set_state
(
appCtx
->
pipeline
.
pipeline
,
GST_STATE_PAUSED
);
gst_element_get_state
(
appCtx
->
pipeline
.
pipeline
,
&
cur
,
&
pending
,
GST_CLOCK_TIME_NONE
);
pause_perf_measurement
(
&
appCtx
->
perf_struct
);
return
TRUE
;
}
else
{
return
FALSE
;
}
}
gboolean
resume_pipeline
(
AppCtx
*
appCtx
)
{
GstState
cur
;
GstState
pending
;
GstStateChangeReturn
ret
;
GstClockTime
timeout
=
5
*
GST_SECOND
/
1000
;
ret
=
gst_element_get_state
(
appCtx
->
pipeline
.
pipeline
,
&
cur
,
&
pending
,
timeout
);
if
(
ret
==
GST_STATE_CHANGE_ASYNC
)
{
return
FALSE
;
}
if
(
cur
==
GST_STATE_PLAYING
)
{
return
TRUE
;
}
else
if
(
cur
==
GST_STATE_PAUSED
)
{
gst_element_set_state
(
appCtx
->
pipeline
.
pipeline
,
GST_STATE_PLAYING
);
gst_element_get_state
(
appCtx
->
pipeline
.
pipeline
,
&
cur
,
&
pending
,
GST_CLOCK_TIME_NONE
);
resume_perf_measurement
(
&
appCtx
->
perf_struct
);
return
TRUE
;
}
else
{
return
FALSE
;
}
}
sugon_apps/sample_apps/deepstream-app/deepstream_app.h
0 → 100644
View file @
24460ef5
/*
* SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LicenseRef-NvidiaProprietary
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*/
#ifndef __NVGSTDS_APP_H__
#define __NVGSTDS_APP_H__
#include <gst/gst.h>
#include <stdio.h>
#include "deepstream_app_version.h"
#include "deepstream_common.h"
#include "deepstream_config.h"
#include "deepstream_osd.h"
#include "deepstream_segvisual.h"
#include "deepstream_perf.h"
#include "deepstream_preprocess.h"
#include "deepstream_primary_gie.h"
#include "deepstream_sinks.h"
#include "deepstream_sources.h"
#include "deepstream_streammux.h"
#include "deepstream_tiled_display.h"
#include "deepstream_dsanalytics.h"
#include "deepstream_dsexample.h"
#include "deepstream_tracker.h"
#include "deepstream_secondary_gie.h"
#include "deepstream_secondary_preprocess.h"
#include "deepstream_c2d_msg.h"
#include "deepstream_image_save.h"
#include "gst-nvdscustommessage.h"
#include "gst-nvdscommonconfig.h"
#ifdef __cplusplus
extern
"C"
{
#endif
typedef
struct
_AppCtx
AppCtx
;
typedef
void
(
*
bbox_generated_callback
)
(
AppCtx
*
appCtx
,
GstBuffer
*
buf
,
NvDsBatchMeta
*
batch_meta
,
guint
index
);
typedef
gboolean
(
*
overlay_graphics_callback
)
(
AppCtx
*
appCtx
,
GstBuffer
*
buf
,
NvDsBatchMeta
*
batch_meta
,
guint
index
);
typedef
struct
{
guint
index
;
gulong
all_bbox_buffer_probe_id
;
gulong
primary_bbox_buffer_probe_id
;
gulong
fps_buffer_probe_id
;
GstElement
*
bin
;
GstElement
*
tee
;
GstElement
*
msg_conv
;
NvDsPreProcessBin
preprocess_bin
;
NvDsPrimaryGieBin
primary_gie_bin
;
NvDsOSDBin
osd_bin
;
NvDsSegVisualBin
segvisual_bin
;
NvDsSecondaryGieBin
secondary_gie_bin
;
NvDsSecondaryPreProcessBin
secondary_preprocess_bin
;
NvDsTrackerBin
tracker_bin
;
NvDsSinkBin
sink_bin
;
NvDsSinkBin
demux_sink_bin
;
NvDsDsAnalyticsBin
dsanalytics_bin
;
NvDsDsExampleBin
dsexample_bin
;
AppCtx
*
appCtx
;
}
NvDsInstanceBin
;
typedef
struct
{
gulong
primary_bbox_buffer_probe_id
;
guint
bus_id
;
GstElement
*
pipeline
;
NvDsSrcParentBin
multi_src_bin
;
NvDsInstanceBin
instance_bins
[
MAX_SOURCE_BINS
];
NvDsInstanceBin
demux_instance_bins
[
MAX_SOURCE_BINS
];
NvDsInstanceBin
common_elements
;
GstElement
*
tiler_tee
;
NvDsTiledDisplayBin
tiled_display_bin
;
GstElement
*
demuxer
;
NvDsDsExampleBin
dsexample_bin
;
AppCtx
*
appCtx
;
}
NvDsPipeline
;
typedef
struct
{
gboolean
enable_perf_measurement
;
gint
file_loop
;
gint
pipeline_recreate_sec
;
gboolean
source_list_enabled
;
guint
total_num_sources
;
guint
num_source_sub_bins
;
guint
num_secondary_gie_sub_bins
;
guint
num_secondary_preprocess_sub_bins
;
guint
num_sink_sub_bins
;
guint
num_message_consumers
;
guint
perf_measurement_interval_sec
;
guint
sgie_batch_size
;
gboolean
extract_sei_type5_data
;
gchar
*
sei_uuid
;
gboolean
low_latency_mode
;
gchar
*
bbox_dir_path
;
gchar
*
kitti_track_dir_path
;
gchar
*
reid_track_dir_path
;
gchar
*
terminated_track_output_path
;
gchar
*
shadow_track_output_path
;
gchar
**
uri_list
;
gchar
**
sensor_id_list
;
gchar
**
sensor_name_list
;
NvDsSourceConfig
multi_source_config
[
MAX_SOURCE_BINS
];
NvDsStreammuxConfig
streammux_config
;
NvDsOSDConfig
osd_config
;
NvDsSegVisualConfig
segvisual_config
;
NvDsPreProcessConfig
preprocess_config
;
NvDsPreProcessConfig
secondary_preprocess_sub_bin_config
[
MAX_SECONDARY_PREPROCESS_BINS
];
NvDsGieConfig
primary_gie_config
;
NvDsTrackerConfig
tracker_config
;
NvDsGieConfig
secondary_gie_sub_bin_config
[
MAX_SECONDARY_GIE_BINS
];
NvDsSinkSubBinConfig
sink_bin_sub_bin_config
[
MAX_SINK_BINS
];
NvDsMsgConsumerConfig
message_consumer_config
[
MAX_MESSAGE_CONSUMERS
];
NvDsTiledDisplayConfig
tiled_display_config
;
NvDsDsAnalyticsConfig
dsanalytics_config
;
NvDsDsExampleConfig
dsexample_config
;
NvDsSinkMsgConvBrokerConfig
msg_conv_config
;
NvDsImageSave
image_save_config
;
/** To support nvmultiurisrcbin */
gboolean
use_nvmultiurisrcbin
;
gboolean
stream_name_display
;
guint
max_batch_size
;
gchar
*
http_ip
;
gchar
*
http_port
;
gboolean
source_attr_all_parsed
;
NvDsSourceConfig
source_attr_all_config
;
/** To set Global GPU ID for all the componenents at once if needed
* This will be used in case gpu_id prop is not set for a component
* if gpu_id prop is set for a component, global_gpu_id will be overridden by it */
gint
global_gpu_id
;
}
NvDsConfig
;
typedef
struct
{
gulong
frame_num
;
}
NvDsInstanceData
;
struct
_AppCtx
{
gboolean
version
;
gboolean
cintr
;
gboolean
show_bbox_text
;
gboolean
seeking
;
gboolean
quit
;
gint
person_class_id
;
gint
car_class_id
;
gint
return_value
;
guint
index
;
gint
active_source_index
;
GMutex
app_lock
;
GCond
app_cond
;
NvDsPipeline
pipeline
;
NvDsConfig
config
;
NvDsConfig
override_config
;
NvDsInstanceData
instance_data
[
MAX_SOURCE_BINS
];
NvDsC2DContext
*
c2d_ctx
[
MAX_MESSAGE_CONSUMERS
];
NvDsAppPerfStructInt
perf_struct
;
bbox_generated_callback
bbox_generated_post_analytics_cb
;
bbox_generated_callback
all_bbox_generated_cb
;
overlay_graphics_callback
overlay_graphics_cb
;
NvDsFrameLatencyInfo
*
latency_info
;
GMutex
latency_lock
;
GThread
*
ota_handler_thread
;
guint
ota_inotify_fd
;
guint
ota_watch_desc
;
/** Hash table to save NvDsSensorInfo
* obtained with REST API stream/add, remove operations
* The key is souce_id */
GHashTable
*
sensorInfoHash
;
gboolean
eos_received
;
};
/**
* @brief Create DS Anyalytics Pipeline per the appCtx
* configurations
* @param appCtx [IN/OUT] The application context
* providing the config info and where the
* pipeline resources are maintained
* @param bbox_generated_post_analytics_cb [IN] This callback
* shall be triggered after analytics
* (PGIE, Tracker or the last SGIE appearing
* in the pipeline)
* More info: create_common_elements()
* @param all_bbox_generated_cb [IN]
* @param perf_cb [IN]
* @param overlay_graphics_cb [IN]
*/
gboolean
create_pipeline
(
AppCtx
*
appCtx
,
bbox_generated_callback
bbox_generated_post_analytics_cb
,
bbox_generated_callback
all_bbox_generated_cb
,
perf_callback
perf_cb
,
overlay_graphics_callback
overlay_graphics_cb
);
gboolean
pause_pipeline
(
AppCtx
*
appCtx
);
gboolean
resume_pipeline
(
AppCtx
*
appCtx
);
gboolean
seek_pipeline
(
AppCtx
*
appCtx
,
glong
milliseconds
,
gboolean
seek_is_relative
);
void
toggle_show_bbox_text
(
AppCtx
*
appCtx
);
void
destroy_pipeline
(
AppCtx
*
appCtx
);
void
restart_pipeline
(
AppCtx
*
appCtx
);
/**
* Function to read properties from configuration file.
*
* @param[in] config pointer to @ref NvDsConfig
* @param[in] cfg_file_path path of configuration file.
*
* @return true if parsed successfully.
*/
gboolean
parse_config_file
(
NvDsConfig
*
config
,
gchar
*
cfg_file_path
);
/**
* Function to read properties from YML configuration file.
*
* @param[in] config pointer to @ref NvDsConfig
* @param[in] cfg_file_path path of configuration file.
*
* @return true if parsed successfully.
*/
gboolean
parse_config_file_yaml
(
NvDsConfig
*
config
,
gchar
*
cfg_file_path
);
/**
* Function to procure the NvDsSensorInfo for the source_id
* that was added using the nvmultiurisrcbin REST API
*
* @param[in] appCtx [IN/OUT] The application context
* providing the config info and where the
* pipeline resources are maintained
* @param[in] source_id [IN] The unique source_id found in NvDsFrameMeta
*
* @return [transfer-floating] The NvDsSensorInfo for the source_id
* that was added using the nvmultiurisrcbin REST API.
* Please note that the returned pointer
* will be valid only until the stream is removed.
*/
NvDsSensorInfo
*
get_sensor_info
(
AppCtx
*
appCtx
,
guint
source_id
);
#ifdef __cplusplus
}
#endif
#endif
sugon_apps/sample_apps/deepstream-app/deepstream_app_config_parser.c
0 → 100644
View file @
24460ef5
/*
* SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LicenseRef-NvidiaProprietary
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*/
#include <string.h>
#include "deepstream_app.h"
#include "deepstream_config_file_parser.h"
#define CONFIG_GROUP_APP "application"
#define CONFIG_GROUP_APP_ENABLE_PERF_MEASUREMENT "enable-perf-measurement"
#define CONFIG_GROUP_APP_PERF_MEASUREMENT_INTERVAL "perf-measurement-interval-sec"
#define CONFIG_GROUP_APP_GIE_OUTPUT_DIR "gie-kitti-output-dir"
#define CONFIG_GROUP_APP_GIE_TRACK_OUTPUT_DIR "kitti-track-output-dir"
#define CONFIG_GROUP_APP_REID_TRACK_OUTPUT_DIR "reid-track-output-dir"
#define CONFIG_GROUP_APP_GLOBAL_GPU_ID "global-gpu-id"
#define CONFIG_GROUP_APP_TERMINATED_TRACK_OUTPUT_DIR "terminated-track-output-dir"
#define CONFIG_GROUP_APP_SHADOW_TRACK_OUTPUT_DIR "shadow-track-output-dir"
#define CONFIG_GROUP_TESTS "tests"
#define CONFIG_GROUP_TESTS_FILE_LOOP "file-loop"
#define CONFIG_GROUP_TESTS_PIPELINE_RECREATE_SEC "pipeline-recreate-sec"
#define CONFIG_GROUP_SOURCE_SGIE_BATCH_SIZE "sgie-batch-size"
GST_DEBUG_CATEGORY_EXTERN
(
APP_CFG_PARSER_CAT
);
#define CHECK_ERROR(error) \
if (error) { \
GST_CAT_ERROR (APP_CFG_PARSER_CAT, "%s", error->message); \
goto done; \
}
static
gboolean
parse_source_list
(
NvDsConfig
*
config
,
GKeyFile
*
key_file
,
gchar
*
cfg_file_path
)
{
gboolean
ret
=
FALSE
;
gchar
**
keys
=
NULL
;
gchar
**
key
=
NULL
;
GError
*
error
=
NULL
;
gsize
num_strings_uri
=
0
;
gsize
num_strings_sensor_id
=
0
;
gsize
num_strings_sensor_name
=
0
;
keys
=
g_key_file_get_keys
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
NULL
,
&
error
);
CHECK_ERROR
(
error
);
for
(
key
=
keys
;
*
key
;
key
++
)
{
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_LIST_NUM_SOURCE_BINS
))
{
config
->
total_num_sources
=
g_key_file_get_integer
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_NUM_SOURCE_BINS
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_LIST_URI_LIST
))
{
config
->
uri_list
=
g_key_file_get_string_list
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_URI_LIST
,
&
num_strings_uri
,
&
error
);
if
(
num_strings_uri
>
MAX_SOURCE_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d sources"
,
MAX_SOURCE_BINS
);
goto
done
;
}
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_LIST_SENSOR_ID_LIST
))
{
config
->
sensor_id_list
=
g_key_file_get_string_list
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_SENSOR_ID_LIST
,
&
num_strings_sensor_id
,
&
error
);
if
(
num_strings_sensor_id
>
MAX_SOURCE_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d sources"
,
MAX_SOURCE_BINS
);
goto
done
;
}
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_LIST_SENSOR_NAME_LIST
))
{
config
->
sensor_name_list
=
g_key_file_get_string_list
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_SENSOR_NAME_LIST
,
&
num_strings_sensor_name
,
&
error
);
if
(
num_strings_sensor_name
>
MAX_SOURCE_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d sources"
,
MAX_SOURCE_BINS
);
goto
done
;
}
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_LIST_USE_NVMULTIURISRCBIN
))
{
config
->
use_nvmultiurisrcbin
=
g_key_file_get_boolean
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_USE_NVMULTIURISRCBIN
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_LIST_STREAM_NAME_DISPLAY
))
{
config
->
stream_name_display
=
g_key_file_get_boolean
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_STREAM_NAME_DISPLAY
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_LIST_HTTP_IP
))
{
config
->
http_ip
=
g_key_file_get_string
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_HTTP_IP
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_LIST_HTTP_PORT
))
{
config
->
http_port
=
g_key_file_get_string
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_HTTP_PORT
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_LIST_MAX_BATCH_SIZE
))
{
config
->
max_batch_size
=
g_key_file_get_integer
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_MAX_BATCH_SIZE
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_SGIE_BATCH_SIZE
))
{
config
->
sgie_batch_size
=
g_key_file_get_integer
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_SGIE_BATCH_SIZE
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_EXTRACT_SEI_TYPE5_DATA
))
{
config
->
extract_sei_type5_data
=
g_key_file_get_integer
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_EXTRACT_SEI_TYPE5_DATA
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_LIST_LOW_LATENCY_MODE
))
{
config
->
low_latency_mode
=
g_key_file_get_integer
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_LOW_LATENCY_MODE
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_SOURCE_SEI_UUID
))
{
config
->
sei_uuid
=
g_key_file_get_string
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_SEI_UUID
,
&
error
);
CHECK_ERROR
(
error
);
}
else
{
NVGSTDS_WARN_MSG_V
(
"Unknown key '%s' for group [%s]"
,
*
key
,
CONFIG_GROUP_SOURCE_LIST
);
}
}
if
(
g_key_file_has_key
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_URI_LIST
,
&
error
))
{
if
(
g_key_file_has_key
(
key_file
,
CONFIG_GROUP_SOURCE_LIST
,
CONFIG_GROUP_SOURCE_LIST_NUM_SOURCE_BINS
,
&
error
))
{
if
(
num_strings_uri
!=
config
->
total_num_sources
)
{
NVGSTDS_ERR_MSG_V
(
"Mismatch in URIs provided and num-source-bins."
);
goto
done
;
}
if
(
num_strings_sensor_id
!=
config
->
total_num_sources
)
{
NVGSTDS_ERR_MSG_V
(
"Mismatch in Sensor IDs provided and num-source-bins."
);
goto
done
;
}
if
(
num_strings_sensor_name
!=
config
->
total_num_sources
)
{
NVGSTDS_ERR_MSG_V
(
"Mismatch in Sensor Names provided and num-source-bins."
);
goto
done
;
}
}
else
{
config
->
total_num_sources
=
num_strings_uri
;
}
}
ret
=
TRUE
;
done:
if
(
error
)
{
g_error_free
(
error
);
}
if
(
keys
)
{
g_strfreev
(
keys
);
}
if
(
!
ret
)
{
NVGSTDS_ERR_MSG_V
(
"%s failed"
,
__func__
);
}
return
ret
;
}
static
gboolean
set_source_all_configs
(
NvDsConfig
*
config
,
gchar
*
cfg_file_path
)
{
guint
i
=
0
;
for
(
i
=
0
;
i
<
config
->
total_num_sources
;
i
++
)
{
config
->
multi_source_config
[
i
]
=
config
->
source_attr_all_config
;
config
->
multi_source_config
[
i
].
camera_id
=
i
;
if
(
config
->
uri_list
)
{
char
*
uri
=
config
->
uri_list
[
i
];
if
(
!
uri
)
{
NVGSTDS_ERR_MSG_V
(
"uri %d entry of list is NULL, use valid uri separated by ';' with the source-list section"
,
(
i
+
1
));
return
FALSE
;
}
if
(
g_str_has_prefix
(
config
->
uri_list
[
i
],
"file://"
))
{
config
->
multi_source_config
[
i
].
type
=
NV_DS_SOURCE_URI
;
config
->
multi_source_config
[
i
].
uri
=
g_strdup
(
uri
+
7
);
config
->
multi_source_config
[
i
].
uri
=
g_strdup_printf
(
"file://%s"
,
get_absolute_file_path
(
cfg_file_path
,
config
->
multi_source_config
[
i
].
uri
));
}
else
if
(
g_str_has_prefix
(
config
->
uri_list
[
i
],
"rtsp://"
))
{
config
->
multi_source_config
[
i
].
type
=
NV_DS_SOURCE_RTSP
;
config
->
multi_source_config
[
i
].
uri
=
config
->
uri_list
[
i
];
}
else
{
gchar
*
source_id_start_ptr
=
uri
+
4
;
gchar
*
source_id_end_ptr
=
NULL
;
long
camera_id
=
g_ascii_strtoull
(
source_id_start_ptr
,
&
source_id_end_ptr
,
10
);
if
(
source_id_start_ptr
==
source_id_end_ptr
||
*
source_id_end_ptr
!=
'\0'
)
{
NVGSTDS_ERR_MSG_V
(
"Incorrect URI for camera source %s. FORMAT: <usb/csi>:<dev_node/sensor_id>"
,
uri
);
return
FALSE
;
}
if
(
g_str_has_prefix
(
config
->
uri_list
[
i
],
"csi:"
))
{
config
->
multi_source_config
[
i
].
type
=
NV_DS_SOURCE_CAMERA_CSI
;
config
->
multi_source_config
[
i
].
camera_csi_sensor_id
=
camera_id
;
}
else
if
(
g_str_has_prefix
(
config
->
uri_list
[
i
],
"usb:"
))
{
config
->
multi_source_config
[
i
].
type
=
NV_DS_SOURCE_CAMERA_V4L2
;
config
->
multi_source_config
[
i
].
camera_v4l2_dev_node
=
camera_id
;
}
else
{
NVGSTDS_ERR_MSG_V
(
"URI %d (%s) not in proper format."
,
i
,
config
->
uri_list
[
i
]);
return
FALSE
;
}
}
}
}
return
TRUE
;
}
static
gboolean
parse_tests
(
NvDsConfig
*
config
,
GKeyFile
*
key_file
)
{
gboolean
ret
=
FALSE
;
gchar
**
keys
=
NULL
;
gchar
**
key
=
NULL
;
GError
*
error
=
NULL
;
keys
=
g_key_file_get_keys
(
key_file
,
CONFIG_GROUP_TESTS
,
NULL
,
&
error
);
CHECK_ERROR
(
error
);
for
(
key
=
keys
;
*
key
;
key
++
)
{
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_TESTS_FILE_LOOP
))
{
config
->
file_loop
=
g_key_file_get_integer
(
key_file
,
CONFIG_GROUP_TESTS
,
CONFIG_GROUP_TESTS_FILE_LOOP
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_TESTS_PIPELINE_RECREATE_SEC
))
{
config
->
pipeline_recreate_sec
=
g_key_file_get_integer
(
key_file
,
CONFIG_GROUP_TESTS
,
CONFIG_GROUP_TESTS_PIPELINE_RECREATE_SEC
,
&
error
);
CHECK_ERROR
(
error
);
}
else
{
NVGSTDS_WARN_MSG_V
(
"Unknown key '%s' for group [%s]"
,
*
key
,
CONFIG_GROUP_TESTS
);
}
}
ret
=
TRUE
;
done:
if
(
error
)
{
g_error_free
(
error
);
}
if
(
keys
)
{
g_strfreev
(
keys
);
}
if
(
!
ret
)
{
NVGSTDS_ERR_MSG_V
(
"%s failed"
,
__func__
);
}
return
ret
;
}
static
gboolean
parse_app
(
NvDsConfig
*
config
,
GKeyFile
*
key_file
,
gchar
*
cfg_file_path
)
{
gboolean
ret
=
FALSE
;
gchar
**
keys
=
NULL
;
gchar
**
key
=
NULL
;
GError
*
error
=
NULL
;
keys
=
g_key_file_get_keys
(
key_file
,
CONFIG_GROUP_APP
,
NULL
,
&
error
);
CHECK_ERROR
(
error
);
for
(
key
=
keys
;
*
key
;
key
++
)
{
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_APP_ENABLE_PERF_MEASUREMENT
))
{
config
->
enable_perf_measurement
=
g_key_file_get_integer
(
key_file
,
CONFIG_GROUP_APP
,
CONFIG_GROUP_APP_ENABLE_PERF_MEASUREMENT
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_APP_PERF_MEASUREMENT_INTERVAL
))
{
config
->
perf_measurement_interval_sec
=
g_key_file_get_integer
(
key_file
,
CONFIG_GROUP_APP
,
CONFIG_GROUP_APP_PERF_MEASUREMENT_INTERVAL
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_APP_GIE_OUTPUT_DIR
))
{
config
->
bbox_dir_path
=
get_absolute_file_path
(
cfg_file_path
,
g_key_file_get_string
(
key_file
,
CONFIG_GROUP_APP
,
CONFIG_GROUP_APP_GIE_OUTPUT_DIR
,
&
error
));
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_APP_GIE_TRACK_OUTPUT_DIR
))
{
config
->
kitti_track_dir_path
=
get_absolute_file_path
(
cfg_file_path
,
g_key_file_get_string
(
key_file
,
CONFIG_GROUP_APP
,
CONFIG_GROUP_APP_GIE_TRACK_OUTPUT_DIR
,
&
error
));
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_APP_REID_TRACK_OUTPUT_DIR
))
{
config
->
reid_track_dir_path
=
get_absolute_file_path
(
cfg_file_path
,
g_key_file_get_string
(
key_file
,
CONFIG_GROUP_APP
,
CONFIG_GROUP_APP_REID_TRACK_OUTPUT_DIR
,
&
error
));
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_APP_GLOBAL_GPU_ID
))
{
/** App Level GPU ID is set here if it is present in APP LEVEL config group
* if gpu_id prop is not set for any component, this global_gpu_id will be used */
config
->
global_gpu_id
=
g_key_file_get_integer
(
key_file
,
CONFIG_GROUP_APP
,
CONFIG_GROUP_APP_GLOBAL_GPU_ID
,
&
error
);
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_APP_TERMINATED_TRACK_OUTPUT_DIR
))
{
config
->
terminated_track_output_path
=
get_absolute_file_path
(
cfg_file_path
,
g_key_file_get_string
(
key_file
,
CONFIG_GROUP_APP
,
CONFIG_GROUP_APP_TERMINATED_TRACK_OUTPUT_DIR
,
&
error
));
CHECK_ERROR
(
error
);
}
else
if
(
!
g_strcmp0
(
*
key
,
CONFIG_GROUP_APP_SHADOW_TRACK_OUTPUT_DIR
))
{
config
->
shadow_track_output_path
=
get_absolute_file_path
(
cfg_file_path
,
g_key_file_get_string
(
key_file
,
CONFIG_GROUP_APP
,
CONFIG_GROUP_APP_SHADOW_TRACK_OUTPUT_DIR
,
&
error
));
CHECK_ERROR
(
error
);
}
else
{
NVGSTDS_WARN_MSG_V
(
"Unknown key '%s' for group [%s]"
,
*
key
,
CONFIG_GROUP_APP
);
}
}
ret
=
TRUE
;
done:
if
(
error
)
{
g_error_free
(
error
);
}
if
(
keys
)
{
g_strfreev
(
keys
);
}
if
(
!
ret
)
{
NVGSTDS_ERR_MSG_V
(
"%s failed"
,
__func__
);
}
return
ret
;
}
gboolean
parse_config_file
(
NvDsConfig
*
config
,
gchar
*
cfg_file_path
)
{
GKeyFile
*
cfg_file
=
g_key_file_new
();
GError
*
error
=
NULL
;
gboolean
ret
=
FALSE
;
gchar
**
groups
=
NULL
;
gchar
**
group
;
guint
i
,
j
;
guint
num_dewarper_source
=
0
;
config
->
source_list_enabled
=
FALSE
;
config
->
source_attr_all_parsed
=
FALSE
;
/** Initialize global gpu id to -1 */
config
->
global_gpu_id
=
-
1
;
if
(
!
APP_CFG_PARSER_CAT
)
{
GST_DEBUG_CATEGORY_INIT
(
APP_CFG_PARSER_CAT
,
"NVDS_CFG_PARSER"
,
0
,
NULL
);
}
if
(
!
g_key_file_load_from_file
(
cfg_file
,
cfg_file_path
,
G_KEY_FILE_NONE
,
&
error
))
{
GST_CAT_ERROR
(
APP_CFG_PARSER_CAT
,
"Failed to load uri file: %s"
,
error
->
message
);
goto
done
;
}
/** App group parsing at top level to set global_gpu_id (if available)
* before any other group parsing */
if
(
g_key_file_has_group
(
cfg_file
,
CONFIG_GROUP_APP
))
{
if
(
!
parse_app
(
config
,
cfg_file
,
cfg_file_path
))
{
GST_CAT_ERROR
(
APP_CFG_PARSER_CAT
,
"Failed to parse '%s' group"
,
CONFIG_GROUP_APP
);
goto
done
;
}
}
if
(
g_key_file_has_group
(
cfg_file
,
CONFIG_GROUP_SOURCE_LIST
))
{
if
(
!
parse_source_list
(
config
,
cfg_file
,
cfg_file_path
))
{
GST_CAT_ERROR
(
APP_CFG_PARSER_CAT
,
"Failed to parse '%s' group"
,
CONFIG_GROUP_SOURCE_LIST
);
goto
done
;
}
config
->
num_source_sub_bins
=
config
->
total_num_sources
;
config
->
source_list_enabled
=
TRUE
;
if
(
!
g_key_file_has_group
(
cfg_file
,
CONFIG_GROUP_SOURCE_ALL
))
{
NVGSTDS_ERR_MSG_V
(
"[source-attr-all] group not present."
);
ret
=
FALSE
;
goto
done
;
}
g_key_file_remove_group
(
cfg_file
,
CONFIG_GROUP_SOURCE_LIST
,
&
error
);
}
if
(
g_key_file_has_group
(
cfg_file
,
CONFIG_GROUP_SOURCE_ALL
))
{
/** set gpu_id for source component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
source_attr_all_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for source component is present,
* it will override the value set using global_gpu_id in parse_source function */
if
(
!
parse_source
(
&
config
->
source_attr_all_config
,
cfg_file
,
(
gchar
*
)
CONFIG_GROUP_SOURCE_ALL
,
cfg_file_path
))
{
GST_CAT_ERROR
(
APP_CFG_PARSER_CAT
,
"Failed to parse '%s' group"
,
CONFIG_GROUP_SOURCE_LIST
);
goto
done
;
}
config
->
source_attr_all_parsed
=
TRUE
;
if
(
!
set_source_all_configs
(
config
,
cfg_file_path
))
{
ret
=
FALSE
;
goto
done
;
}
g_key_file_remove_group
(
cfg_file
,
CONFIG_GROUP_SOURCE_ALL
,
&
error
);
}
groups
=
g_key_file_get_groups
(
cfg_file
,
NULL
);
for
(
group
=
groups
;
*
group
;
group
++
)
{
gboolean
parse_err
=
FALSE
;
GST_CAT_DEBUG
(
APP_CFG_PARSER_CAT
,
"Parsing group: %s"
,
*
group
);
if
(
!
strncmp
(
*
group
,
CONFIG_GROUP_SOURCE
,
sizeof
(
CONFIG_GROUP_SOURCE
)
-
1
))
{
if
(
config
->
num_source_sub_bins
==
MAX_SOURCE_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d sources"
,
MAX_SOURCE_BINS
);
ret
=
FALSE
;
goto
done
;
}
gchar
*
source_id_start_ptr
=
*
group
+
strlen
(
CONFIG_GROUP_SOURCE
);
gchar
*
source_id_end_ptr
=
NULL
;
guint
index
=
g_ascii_strtoull
(
source_id_start_ptr
,
&
source_id_end_ptr
,
10
);
if
(
source_id_start_ptr
==
source_id_end_ptr
||
*
source_id_end_ptr
!=
'\0'
)
{
NVGSTDS_ERR_MSG_V
(
"Source group
\"
[%s]
\"
is not in the form
\"
[source<%%d>]
\"
"
,
*
group
);
ret
=
FALSE
;
goto
done
;
}
guint
source_id
=
0
;
if
(
config
->
source_list_enabled
)
{
if
(
index
>=
config
->
total_num_sources
)
{
NVGSTDS_ERR_MSG_V
(
"Invalid source group index %d, index cannot exceed %d"
,
index
,
config
->
total_num_sources
);
ret
=
FALSE
;
goto
done
;
}
source_id
=
index
;
NVGSTDS_INFO_MSG_V
(
"Some parameters to be overwritten for group [%s]"
,
*
group
);
}
else
{
source_id
=
config
->
num_source_sub_bins
;
}
/** set gpu_id for source component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
multi_source_config
[
source_id
].
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for source component is present,
* it will override the value set using global_gpu_id in parse_source function */
parse_err
=
!
parse_source
(
&
config
->
multi_source_config
[
source_id
],
cfg_file
,
*
group
,
cfg_file_path
);
if
(
config
->
source_list_enabled
&&
config
->
multi_source_config
[
source_id
].
type
==
NV_DS_SOURCE_URI_MULTIPLE
)
{
NVGSTDS_ERR_MSG_V
(
"MultiURI support not available if [source-list] is provided"
);
ret
=
FALSE
;
goto
done
;
}
if
(
config
->
multi_source_config
[
source_id
].
enable
&&
!
config
->
source_list_enabled
)
{
config
->
num_source_sub_bins
++
;
}
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_STREAMMUX
))
{
/** set gpu_id for streammux component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
streammux_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for streammux component is present,
* it will override the value set using global_gpu_id in parse_streammux function */
parse_err
=
!
parse_streammux
(
&
config
->
streammux_config
,
cfg_file
,
cfg_file_path
);
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_OSD
))
{
/** set gpu_id for osd component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
osd_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for osd component is present,
* it will override the value set using global_gpu_id in parse_osd function */
parse_err
=
!
parse_osd
(
&
config
->
osd_config
,
cfg_file
);
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_SEGVISUAL
))
{
/** set gpu_id for segvisual component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
segvisual_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for segvisual component is present,
* it will override the value set using global_gpu_id in parse_segvisual function */
parse_err
=
!
parse_segvisual
(
&
config
->
segvisual_config
,
cfg_file
);
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_PREPROCESS
))
{
parse_err
=
!
parse_preprocess
(
&
config
->
preprocess_config
,
cfg_file
,
*
group
,
cfg_file_path
);
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_PRIMARY_GIE
))
{
/** set gpu_id for primary gie component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
primary_gie_config
.
gpu_id
=
config
->
global_gpu_id
;
config
->
primary_gie_config
.
is_gpu_id_set
=
TRUE
;
}
/** if gpu_id for primary gie component is present,
* it will override the value set using global_gpu_id in parse_gie function */
parse_err
=
!
parse_gie
(
&
config
->
primary_gie_config
,
cfg_file
,
(
gchar
*
)
CONFIG_GROUP_PRIMARY_GIE
,
cfg_file_path
);
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_TRACKER
))
{
/** set gpu_id for tracker component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
tracker_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for tracker component is present,
* it will override the value set using global_gpu_id in parse_tracker function */
parse_err
=
!
parse_tracker
(
&
config
->
tracker_config
,
cfg_file
,
cfg_file_path
);
}
if
(
!
strncmp
(
*
group
,
CONFIG_GROUP_SECONDARY_GIE
,
sizeof
(
CONFIG_GROUP_SECONDARY_GIE
)
-
1
))
{
if
(
config
->
num_secondary_gie_sub_bins
==
MAX_SECONDARY_GIE_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d secondary GIEs"
,
MAX_SECONDARY_GIE_BINS
);
ret
=
FALSE
;
goto
done
;
}
/** set gpu_id for secondary gie component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
secondary_gie_sub_bin_config
[
config
->
num_secondary_gie_sub_bins
].
gpu_id
=
config
->
global_gpu_id
;
config
->
secondary_gie_sub_bin_config
[
config
->
num_secondary_gie_sub_bins
].
is_gpu_id_set
=
TRUE
;
}
/** if gpu_id for secondary gie component is present,
* it will override the value set using global_gpu_id in parse_gie function */
parse_err
=
!
parse_gie
(
&
config
->
secondary_gie_sub_bin_config
[
config
->
num_secondary_gie_sub_bins
],
cfg_file
,
*
group
,
cfg_file_path
);
if
(
config
->
secondary_gie_sub_bin_config
[
config
->
num_secondary_gie_sub_bins
].
enable
)
{
config
->
num_secondary_gie_sub_bins
++
;
}
}
if
(
!
strncmp
(
*
group
,
CONFIG_GROUP_SECONDARY_PREPROCESS
,
sizeof
(
CONFIG_GROUP_SECONDARY_PREPROCESS
)
-
1
))
{
if
(
config
->
num_secondary_preprocess_sub_bins
==
MAX_SECONDARY_PREPROCESS_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d secondary PREPROCESSs"
,
MAX_SECONDARY_PREPROCESS_BINS
);
ret
=
FALSE
;
goto
done
;
}
parse_err
=
!
parse_preprocess
(
&
config
->
secondary_preprocess_sub_bin_config
[
config
->
num_secondary_preprocess_sub_bins
],
cfg_file
,
*
group
,
cfg_file_path
);
if
(
config
->
secondary_preprocess_sub_bin_config
[
config
->
num_secondary_preprocess_sub_bins
].
enable
)
{
config
->
num_secondary_preprocess_sub_bins
++
;
}
}
if
(
!
strncmp
(
*
group
,
CONFIG_GROUP_SINK
,
sizeof
(
CONFIG_GROUP_SINK
)
-
1
))
{
if
(
config
->
num_sink_sub_bins
==
MAX_SINK_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d sinks"
,
MAX_SINK_BINS
);
ret
=
FALSE
;
goto
done
;
}
/** set gpu_id for sink component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
GError
*
error
=
NULL
;
if
(
g_key_file_get_integer
(
cfg_file
,
*
group
,
"enable"
,
&
error
)
==
TRUE
&&
error
==
NULL
)
{
config
->
sink_bin_sub_bin_config
[
config
->
num_sink_sub_bins
].
encoder_config
.
gpu_id
=
config
->
sink_bin_sub_bin_config
[
config
->
num_sink_sub_bins
].
render_config
.
gpu_id
=
config
->
global_gpu_id
;
}
}
/** if gpu_id for sink component is present,
* it will override the value set using global_gpu_id in parse_sink function */
parse_err
=
!
parse_sink
(
&
config
->
sink_bin_sub_bin_config
[
config
->
num_sink_sub_bins
],
cfg_file
,
*
group
,
cfg_file_path
);
if
(
config
->
sink_bin_sub_bin_config
[
config
->
num_sink_sub_bins
].
enable
)
{
config
->
num_sink_sub_bins
++
;
}
}
if
(
!
strncmp
(
*
group
,
CONFIG_GROUP_MSG_CONSUMER
,
sizeof
(
CONFIG_GROUP_MSG_CONSUMER
)
-
1
))
{
if
(
config
->
num_message_consumers
==
MAX_MESSAGE_CONSUMERS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d consumers"
,
MAX_MESSAGE_CONSUMERS
);
ret
=
FALSE
;
goto
done
;
}
parse_err
=
!
parse_msgconsumer
(
&
config
->
message_consumer_config
[
config
->
num_message_consumers
],
cfg_file
,
*
group
,
cfg_file_path
);
if
(
config
->
message_consumer_config
[
config
->
num_message_consumers
].
enable
)
{
config
->
num_message_consumers
++
;
}
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_TILED_DISPLAY
))
{
/** set gpu_id for tiled display component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
tiled_display_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for tiled display component is present,
* it will override the value set using global_gpu_id in parse_tiled_display function */
parse_err
=
!
parse_tiled_display
(
&
config
->
tiled_display_config
,
cfg_file
);
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_IMG_SAVE
))
{
/** set gpu_id for image save component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
image_save_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for image save component is present,
* it will override the value set using global_gpu_id in parse_image_save function */
parse_err
=
!
parse_image_save
(
&
config
->
image_save_config
,
cfg_file
,
*
group
,
cfg_file_path
);
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_DSANALYTICS
))
{
parse_err
=
!
parse_dsanalytics
(
&
config
->
dsanalytics_config
,
cfg_file
,
cfg_file_path
);
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_DSEXAMPLE
))
{
/** set gpu_id for dsexample component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
dsexample_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for dsexample component is present,
* it will override the value set using global_gpu_id in parse_dsexample function */
parse_err
=
!
parse_dsexample
(
&
config
->
dsexample_config
,
cfg_file
);
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_MSG_CONVERTER
))
{
parse_err
=
!
parse_msgconv
(
&
config
->
msg_conv_config
,
cfg_file
,
*
group
,
cfg_file_path
);
}
if
(
!
g_strcmp0
(
*
group
,
CONFIG_GROUP_TESTS
))
{
parse_err
=
!
parse_tests
(
config
,
cfg_file
);
}
if
(
!
strncmp
(
*
group
,
CONFIG_GROUP_DEWARPER
,
strlen
(
*
group
)
-
1
))
{
guint
source_id
=
0
;
{
gchar
*
source_id_start_ptr
=
*
group
+
strlen
(
CONFIG_GROUP_DEWARPER
);
gchar
*
source_id_end_ptr
=
NULL
;
source_id
=
g_ascii_strtoull
(
source_id_start_ptr
,
&
source_id_end_ptr
,
10
);
if
(
source_id_start_ptr
==
source_id_end_ptr
||
*
source_id_end_ptr
!=
'\0'
)
{
NVGSTDS_ERR_MSG_V
(
"dewarper group
\"
[%s]
\"
is not in the form
\"
[dewarper<%%d>]
\"
"
,
*
group
);
ret
=
FALSE
;
goto
done
;}
}
/** set gpu_id for dewarper component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
multi_source_config
[
source_id
].
dewarper_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for dewarper component is present,
* it will override the value set using global_gpu_id in parse_dewarper function */
parse_err
=
!
parse_dewarper
(
&
config
->
multi_source_config
[
source_id
].
dewarper_config
,
cfg_file
,
cfg_file_path
,
*
group
);
if
(
config
->
multi_source_config
[
source_id
].
dewarper_config
.
enable
)
num_dewarper_source
++
;
if
(
num_dewarper_source
>
config
->
num_source_sub_bins
)
{
NVGSTDS_ERR_MSG_V
(
"Dewarper max numbers %u should be less than number of sources %u"
,
num_dewarper_source
,
config
->
num_source_sub_bins
);
ret
=
FALSE
;
goto
done
;
}
}
if
(
parse_err
)
{
GST_CAT_ERROR
(
APP_CFG_PARSER_CAT
,
"Failed to parse '%s' group"
,
*
group
);
goto
done
;
}
}
/* Updating batch size when source list is enabled */
if
(
config
->
source_list_enabled
==
TRUE
)
{
/* For streammux and pgie, batch size is set to number of sources */
config
->
streammux_config
.
batch_size
=
config
->
num_source_sub_bins
;
config
->
primary_gie_config
.
batch_size
=
config
->
num_source_sub_bins
;
if
(
config
->
sgie_batch_size
!=
0
)
{
for
(
i
=
0
;
i
<
config
->
num_secondary_gie_sub_bins
;
i
++
)
{
config
->
secondary_gie_sub_bin_config
[
i
].
batch_size
=
config
->
sgie_batch_size
;
}
}
}
for
(
i
=
0
;
i
<
config
->
num_secondary_gie_sub_bins
;
i
++
)
{
if
(
config
->
secondary_gie_sub_bin_config
[
i
].
unique_id
==
config
->
primary_gie_config
.
unique_id
)
{
NVGSTDS_ERR_MSG_V
(
"Non unique gie ids found"
);
ret
=
FALSE
;
goto
done
;
}
}
for
(
i
=
0
;
i
<
config
->
num_secondary_gie_sub_bins
;
i
++
)
{
for
(
j
=
i
+
1
;
j
<
config
->
num_secondary_gie_sub_bins
;
j
++
)
{
if
(
config
->
secondary_gie_sub_bin_config
[
i
].
unique_id
==
config
->
secondary_gie_sub_bin_config
[
j
].
unique_id
)
{
NVGSTDS_ERR_MSG_V
(
"Non unique gie id %d found"
,
config
->
secondary_gie_sub_bin_config
[
i
].
unique_id
);
ret
=
FALSE
;
goto
done
;
}
}
}
for
(
i
=
0
;
i
<
config
->
num_source_sub_bins
;
i
++
)
{
if
(
config
->
multi_source_config
[
i
].
type
==
NV_DS_SOURCE_URI_MULTIPLE
)
{
if
(
config
->
multi_source_config
[
i
].
num_sources
<
1
)
{
config
->
multi_source_config
[
i
].
num_sources
=
1
;
}
for
(
j
=
1
;
j
<
config
->
multi_source_config
[
i
].
num_sources
;
j
++
)
{
if
(
config
->
num_source_sub_bins
==
MAX_SOURCE_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d sources"
,
MAX_SOURCE_BINS
);
ret
=
FALSE
;
goto
done
;
}
memcpy
(
&
config
->
multi_source_config
[
config
->
num_source_sub_bins
],
&
config
->
multi_source_config
[
i
],
sizeof
(
config
->
multi_source_config
[
i
]));
config
->
multi_source_config
[
config
->
num_source_sub_bins
].
type
=
NV_DS_SOURCE_URI
;
config
->
multi_source_config
[
config
->
num_source_sub_bins
].
uri
=
g_strdup_printf
(
config
->
multi_source_config
[
config
->
num_source_sub_bins
].
uri
,
j
);
config
->
num_source_sub_bins
++
;
}
config
->
multi_source_config
[
i
].
type
=
NV_DS_SOURCE_URI
;
config
->
multi_source_config
[
i
].
uri
=
g_strdup_printf
(
config
->
multi_source_config
[
i
].
uri
,
0
);
}
}
ret
=
TRUE
;
done:
if
(
cfg_file
)
{
g_key_file_free
(
cfg_file
);
}
if
(
groups
)
{
g_strfreev
(
groups
);
}
if
(
error
)
{
g_error_free
(
error
);
}
if
(
!
ret
)
{
NVGSTDS_ERR_MSG_V
(
"%s failed"
,
__func__
);
}
return
ret
;
}
sugon_apps/sample_apps/deepstream-app/deepstream_app_config_parser_yaml.cpp
0 → 100644
View file @
24460ef5
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LicenseRef-NvidiaProprietary
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*/
#include <string>
#include <cstring>
#include "deepstream_app.h"
#include "deepstream_config_yaml.h"
#include <iostream>
#include <stdlib.h>
#include <fstream>
using
std
::
cout
;
using
std
::
endl
;
static
gboolean
parse_tests_yaml
(
NvDsConfig
*
config
,
gchar
*
cfg_file_path
)
{
gboolean
ret
=
FALSE
;
YAML
::
Node
configyml
=
YAML
::
LoadFile
(
cfg_file_path
);
for
(
YAML
::
const_iterator
itr
=
configyml
[
"tests"
].
begin
();
itr
!=
configyml
[
"tests"
].
end
();
++
itr
)
{
std
::
string
paramKey
=
itr
->
first
.
as
<
std
::
string
>
();
if
(
paramKey
==
"file-loop"
)
{
config
->
file_loop
=
itr
->
second
.
as
<
gint
>
();
}
else
{
cout
<<
"Unknown key "
<<
paramKey
<<
" for group tests"
<<
endl
;
}
}
ret
=
TRUE
;
if
(
!
ret
)
{
cout
<<
__func__
<<
" failed"
<<
endl
;
}
return
ret
;
}
static
gboolean
parse_app_yaml
(
NvDsConfig
*
config
,
gchar
*
cfg_file_path
)
{
gboolean
ret
=
FALSE
;
YAML
::
Node
configyml
=
YAML
::
LoadFile
(
cfg_file_path
);
for
(
YAML
::
const_iterator
itr
=
configyml
[
"application"
].
begin
();
itr
!=
configyml
[
"application"
].
end
();
++
itr
)
{
std
::
string
paramKey
=
itr
->
first
.
as
<
std
::
string
>
();
if
(
paramKey
==
"enable-perf-measurement"
)
{
config
->
enable_perf_measurement
=
itr
->
second
.
as
<
gboolean
>
();
}
else
if
(
paramKey
==
"perf-measurement-interval-sec"
)
{
config
->
perf_measurement_interval_sec
=
itr
->
second
.
as
<
guint
>
();
}
else
if
(
paramKey
==
"gie-kitti-output-dir"
)
{
std
::
string
temp
=
itr
->
second
.
as
<
std
::
string
>
();
char
*
str
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
std
::
strncpy
(
str
,
temp
.
c_str
(),
1023
);
config
->
bbox_dir_path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
get_absolute_file_path_yaml
(
cfg_file_path
,
str
,
config
->
bbox_dir_path
);
g_free
(
str
);
}
else
if
(
paramKey
==
"kitti-track-output-dir"
)
{
std
::
string
temp
=
itr
->
second
.
as
<
std
::
string
>
();
char
*
str
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
std
::
strncpy
(
str
,
temp
.
c_str
(),
1023
);
config
->
kitti_track_dir_path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
get_absolute_file_path_yaml
(
cfg_file_path
,
str
,
config
->
kitti_track_dir_path
);
g_free
(
str
);
}
else
if
(
paramKey
==
"reid-track-output-dir"
)
{
std
::
string
temp
=
itr
->
second
.
as
<
std
::
string
>
();
char
*
str
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
std
::
strncpy
(
str
,
temp
.
c_str
(),
1023
);
config
->
reid_track_dir_path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
get_absolute_file_path_yaml
(
cfg_file_path
,
str
,
config
->
reid_track_dir_path
);
g_free
(
str
);
}
else
if
(
paramKey
==
"global-gpu-id"
)
{
/** App Level GPU ID is set here if it is present in APP LEVEL config group
* if gpu_id prop is not set for any component, this global_gpu_id will be used */
config
->
global_gpu_id
=
itr
->
second
.
as
<
guint
>
();
}
else
if
(
paramKey
==
"terminated-track-output-dir"
)
{
std
::
string
temp
=
itr
->
second
.
as
<
std
::
string
>
();
char
*
str
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
std
::
strncpy
(
str
,
temp
.
c_str
(),
1023
);
config
->
terminated_track_output_path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
get_absolute_file_path_yaml
(
cfg_file_path
,
str
,
config
->
terminated_track_output_path
);
g_free
(
str
);
}
else
if
(
paramKey
==
"shadow-track-output-dir"
)
{
std
::
string
temp
=
itr
->
second
.
as
<
std
::
string
>
();
char
*
str
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
std
::
strncpy
(
str
,
temp
.
c_str
(),
1023
);
config
->
shadow_track_output_path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
get_absolute_file_path_yaml
(
cfg_file_path
,
str
,
config
->
shadow_track_output_path
);
g_free
(
str
);
}
else
{
cout
<<
"Unknown key "
<<
paramKey
<<
" for group application"
<<
endl
;
}
}
ret
=
TRUE
;
if
(
!
ret
)
{
cout
<<
__func__
<<
" failed"
<<
endl
;
}
return
ret
;
}
static
std
::
vector
<
std
::
string
>
split_csv_entries
(
std
::
string
input
)
{
std
::
vector
<
int
>
positions
;
for
(
unsigned
int
i
=
0
;
i
<
input
.
size
();
i
++
)
{
if
(
input
[
i
]
==
','
)
positions
.
push_back
(
i
);
}
std
::
vector
<
std
::
string
>
ret
;
int
prev
=
0
;
for
(
auto
&
j
:
positions
)
{
std
::
string
temp
=
input
.
substr
(
prev
,
j
-
prev
);
ret
.
push_back
(
temp
);
prev
=
j
+
1
;
}
ret
.
push_back
(
input
.
substr
(
prev
,
input
.
size
()
-
prev
));
return
ret
;
}
gboolean
parse_config_file_yaml
(
NvDsConfig
*
config
,
gchar
*
cfg_file_path
)
{
gboolean
parse_err
=
false
;
gboolean
ret
=
FALSE
;
YAML
::
Node
configyml
=
YAML
::
LoadFile
(
cfg_file_path
);
std
::
string
source_str
=
"source"
;
std
::
string
sink_str
=
"sink"
;
std
::
string
sgie_str
=
"secondary-gie"
;
std
::
string
msgcons_str
=
"message-consumer"
;
std
::
string
dewarper_str
=
"dewarper"
;
config
->
source_list_enabled
=
FALSE
;
/** Initialize global gpu id to -1 */
config
->
global_gpu_id
=
-
1
;
/** App group parsing at top level to set global_gpu_id (if available)
* before any other group parsing */
if
(
configyml
[
"application"
])
{
parse_err
=
!
parse_app_yaml
(
config
,
cfg_file_path
);
}
for
(
YAML
::
const_iterator
itr
=
configyml
.
begin
();
itr
!=
configyml
.
end
();
++
itr
)
{
std
::
string
paramKey
=
itr
->
first
.
as
<
std
::
string
>
();
if
(
paramKey
==
"source"
)
{
if
(
configyml
[
"source"
][
"csv-file-path"
])
{
std
::
string
csv_file_path
=
configyml
[
"source"
][
"csv-file-path"
].
as
<
std
::
string
>
();
char
*
str
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
std
::
strncpy
(
str
,
csv_file_path
.
c_str
(),
1023
);
char
*
abs_csv_path
=
(
char
*
)
malloc
(
sizeof
(
char
)
*
1024
);
get_absolute_file_path_yaml
(
cfg_file_path
,
str
,
abs_csv_path
);
g_free
(
str
);
std
::
ifstream
inputFile
(
abs_csv_path
);
if
(
!
inputFile
.
is_open
())
{
cout
<<
"Couldn't open CSV file "
<<
abs_csv_path
<<
endl
;
}
std
::
string
line
,
temp
;
/* Separating header field and inserting as strings into the vector.
*/
while
(
getline
(
inputFile
,
line
)){
gboolean
is_comment
=
false
;
size_t
space_count
=
0
;
for
(
char
c
:
line
)
{
if
(
c
!=
' '
&&
c
!=
'\t'
)
{
if
(
c
!=
'#'
)
{
is_comment
=
false
;
}
else
{
is_comment
=
true
;
}
break
;
}
else
{
space_count
++
;
}
}
if
(
!
is_comment
&&
space_count
<
line
.
length
())
break
;
}
std
::
vector
<
std
::
string
>
headers
=
split_csv_entries
(
line
);
/*Parsing each csv entry as an input source */
while
(
getline
(
inputFile
,
line
))
{
std
::
vector
<
std
::
string
>
source_values
=
split_csv_entries
(
line
);
if
(
config
->
num_source_sub_bins
==
MAX_SOURCE_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d sources"
,
MAX_SOURCE_BINS
);
ret
=
FALSE
;
goto
done
;
}
guint
source_id
=
0
;
source_id
=
config
->
num_source_sub_bins
;
/** set gpu_id for source component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
multi_source_config
[
source_id
].
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for source component is present,
* it will override the value set using global_gpu_id in parse_source_yaml function */
parse_err
=
!
parse_source_yaml
(
&
config
->
multi_source_config
[
source_id
],
headers
,
source_values
,
cfg_file_path
);
if
(
config
->
multi_source_config
[
source_id
].
enable
)
config
->
num_source_sub_bins
++
;
}
}
else
{
NVGSTDS_ERR_MSG_V
(
"CSV file not specified
\n
"
);
ret
=
FALSE
;
goto
done
;
}
}
else
if
(
paramKey
==
"streammux"
)
{
/** set gpu_id for streammux component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
streammux_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for streammux component is present,
* it will override the value set using global_gpu_id in parse_streammux_yaml function */
parse_err
=
!
parse_streammux_yaml
(
&
config
->
streammux_config
,
cfg_file_path
);
}
else
if
(
paramKey
==
"osd"
)
{
/** set gpu_id for osd component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
osd_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for osd component is present,
* it will override the value set using global_gpu_id in parse_osd_yaml function */
parse_err
=
!
parse_osd_yaml
(
&
config
->
osd_config
,
cfg_file_path
);
}
else
if
(
paramKey
==
"segvisual"
)
{
/** set gpu_id for segvisual component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
segvisual_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for segvisual component is present,
* it will override the value set using global_gpu_id in parse_segvisual_yaml function */
parse_err
=
!
parse_segvisual_yaml
(
&
config
->
segvisual_config
,
cfg_file_path
);
}
else
if
(
paramKey
==
"pre-process"
)
{
parse_err
=
!
parse_preprocess_yaml
(
&
config
->
preprocess_config
,
cfg_file_path
);
}
else
if
(
paramKey
==
"primary-gie"
)
{
/** set gpu_id for primary gie component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
primary_gie_config
.
gpu_id
=
config
->
global_gpu_id
;
config
->
primary_gie_config
.
is_gpu_id_set
=
TRUE
;
}
/** if gpu_id for primary gie component is present,
* it will override the value set using global_gpu_id in parse_gie_yaml function */
parse_err
=
!
parse_gie_yaml
(
&
config
->
primary_gie_config
,
paramKey
,
cfg_file_path
);
}
else
if
(
paramKey
==
"tracker"
)
{
/** set gpu_id for tracker component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
tracker_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for tracker component is present,
* it will override the value set using global_gpu_id in parse_tracker_yaml function */
parse_err
=
!
parse_tracker_yaml
(
&
config
->
tracker_config
,
cfg_file_path
);
}
else
if
(
paramKey
.
compare
(
0
,
sgie_str
.
size
(),
sgie_str
)
==
0
)
{
if
(
config
->
num_secondary_gie_sub_bins
==
MAX_SECONDARY_GIE_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d secondary GIEs"
,
MAX_SECONDARY_GIE_BINS
);
ret
=
FALSE
;
goto
done
;
}
/* set gpu_id for secondary gie component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
secondary_gie_sub_bin_config
[
config
->
num_secondary_gie_sub_bins
].
gpu_id
=
config
->
global_gpu_id
;
config
->
secondary_gie_sub_bin_config
[
config
->
num_secondary_gie_sub_bins
].
is_gpu_id_set
=
TRUE
;
}
/** if gpu_id for secondary gie component is present,
* it will override the value set using global_gpu_id in parse_gie_yaml function */
parse_err
=
!
parse_gie_yaml
(
&
config
->
secondary_gie_sub_bin_config
[
config
->
num_secondary_gie_sub_bins
],
paramKey
,
cfg_file_path
);
if
(
config
->
secondary_gie_sub_bin_config
[
config
->
num_secondary_gie_sub_bins
].
enable
){
config
->
num_secondary_gie_sub_bins
++
;
}
}
else
if
(
paramKey
.
compare
(
0
,
sink_str
.
size
(),
sink_str
)
==
0
)
{
if
(
config
->
num_sink_sub_bins
==
MAX_SINK_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d sinks"
,
MAX_SINK_BINS
);
ret
=
FALSE
;
goto
done
;
}
/* set gpu_id for sink component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
&&
configyml
[
paramKey
][
"enable"
].
as
<
gboolean
>
())
{
config
->
sink_bin_sub_bin_config
[
config
->
num_sink_sub_bins
].
encoder_config
.
gpu_id
=
config
->
sink_bin_sub_bin_config
[
config
->
num_sink_sub_bins
].
render_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for sink component is present,
* it will override the value set using global_gpu_id in parse_sink_yaml function */
parse_err
=
!
parse_sink_yaml
(
&
config
->
sink_bin_sub_bin_config
[
config
->
num_sink_sub_bins
],
paramKey
,
cfg_file_path
);
if
(
config
->
sink_bin_sub_bin_config
[
config
->
num_sink_sub_bins
].
enable
)
{
config
->
num_sink_sub_bins
++
;
}
}
else
if
(
paramKey
.
compare
(
0
,
msgcons_str
.
size
(),
msgcons_str
)
==
0
)
{
if
(
config
->
num_message_consumers
==
MAX_MESSAGE_CONSUMERS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d consumers"
,
MAX_MESSAGE_CONSUMERS
);
ret
=
FALSE
;
goto
done
;
}
parse_err
=
!
parse_msgconsumer_yaml
(
&
config
->
message_consumer_config
[
config
->
num_message_consumers
],
paramKey
,
cfg_file_path
);
if
(
config
->
message_consumer_config
[
config
->
num_message_consumers
].
enable
)
{
config
->
num_message_consumers
++
;
}
}
else
if
(
paramKey
==
"tiled-display"
)
{
/* set gpu_id for tiled display component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
tiled_display_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for tiled display component is present,
* it will override the value set using global_gpu_id in parse_tiled_display_yaml function */
parse_err
=
!
parse_tiled_display_yaml
(
&
config
->
tiled_display_config
,
cfg_file_path
);
}
else
if
(
paramKey
==
"img-save"
)
{
/** set gpu_id for image save component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
image_save_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for image save component is present,
* it will override the value set using global_gpu_id in parse_image_save_yaml function */
parse_err
=
!
parse_image_save_yaml
(
&
config
->
image_save_config
,
cfg_file_path
);
}
else
if
(
paramKey
==
"nvds-analytics"
)
{
parse_err
=
!
parse_dsanalytics_yaml
(
&
config
->
dsanalytics_config
,
cfg_file_path
);
}
else
if
(
paramKey
==
"ds-example"
)
{
/** set gpu_id for dsexample component using global_gpu_id(if available) */
if
(
config
->
global_gpu_id
!=
-
1
)
{
config
->
dsexample_config
.
gpu_id
=
config
->
global_gpu_id
;
}
/** if gpu_id for dsexample component is present,
* it will override the value set using global_gpu_id in parse_dsexample_yaml function */
parse_err
=
!
parse_dsexample_yaml
(
&
config
->
dsexample_config
,
cfg_file_path
);
}
else
if
(
paramKey
==
"message-converter"
)
{
parse_err
=
!
parse_msgconv_yaml
(
&
config
->
msg_conv_config
,
paramKey
,
cfg_file_path
);
}
else
if
(
paramKey
==
"tests"
)
{
parse_err
=
!
parse_tests_yaml
(
config
,
cfg_file_path
);
}
else
if
(
paramKey
.
compare
(
0
,
dewarper_str
.
size
(),
dewarper_str
)
==
0
)
{
size_t
start
=
paramKey
.
find
(
dewarper_str
);
int
source_id
=
0
;
if
(
start
!=
std
::
string
::
npos
)
{
std
::
string
index_str
=
paramKey
.
substr
(
start
+
dewarper_str
.
length
(),
paramKey
.
length
()
-
start
-
dewarper_str
.
length
());
source_id
=
std
::
stoi
(
index_str
);
parse_dewarper_yaml
(
&
config
->
multi_source_config
[
source_id
].
dewarper_config
,
paramKey
,
cfg_file_path
);
}
else
{
NVGSTDS_ERR_MSG_V
(
"Dewarper key is wrong ! "
);
parse_err
=
true
;
}
}
if
(
parse_err
)
{
cout
<<
"failed parsing"
<<
endl
;
goto
done
;
}
}
/* Updating batch size when source list is enabled */
/* if (config->source_list_enabled == TRUE) {
// For streammux and pgie, batch size is set to number of sources
config->streammux_config.batch_size = config->num_source_sub_bins;
config->primary_gie_config.batch_size = config->num_source_sub_bins;
if (config->sgie_batch_size != 0) {
for (i = 0; i < config->num_secondary_gie_sub_bins; i++) {
config->secondary_gie_sub_bin_config[i].batch_size = config->sgie_batch_size;
}
}
} */
unsigned
int
i
,
j
;
for
(
i
=
0
;
i
<
config
->
num_secondary_gie_sub_bins
;
i
++
)
{
if
(
config
->
secondary_gie_sub_bin_config
[
i
].
unique_id
==
config
->
primary_gie_config
.
unique_id
)
{
NVGSTDS_ERR_MSG_V
(
"Non unique gie ids found"
);
ret
=
FALSE
;
goto
done
;
}
}
for
(
i
=
0
;
i
<
config
->
num_secondary_gie_sub_bins
;
i
++
)
{
for
(
j
=
i
+
1
;
j
<
config
->
num_secondary_gie_sub_bins
;
j
++
)
{
if
(
config
->
secondary_gie_sub_bin_config
[
i
].
unique_id
==
config
->
secondary_gie_sub_bin_config
[
j
].
unique_id
)
{
NVGSTDS_ERR_MSG_V
(
"Non unique gie id %d found"
,
config
->
secondary_gie_sub_bin_config
[
i
].
unique_id
);
ret
=
FALSE
;
goto
done
;
}
}
}
for
(
i
=
0
;
i
<
config
->
num_source_sub_bins
;
i
++
)
{
if
(
config
->
multi_source_config
[
i
].
type
==
NV_DS_SOURCE_URI_MULTIPLE
)
{
if
(
config
->
multi_source_config
[
i
].
num_sources
<
1
)
{
config
->
multi_source_config
[
i
].
num_sources
=
1
;
}
for
(
j
=
1
;
j
<
config
->
multi_source_config
[
i
].
num_sources
;
j
++
)
{
if
(
config
->
num_source_sub_bins
==
MAX_SOURCE_BINS
)
{
NVGSTDS_ERR_MSG_V
(
"App supports max %d sources"
,
MAX_SOURCE_BINS
);
ret
=
FALSE
;
goto
done
;
}
memcpy
(
&
config
->
multi_source_config
[
config
->
num_source_sub_bins
],
&
config
->
multi_source_config
[
i
],
sizeof
(
config
->
multi_source_config
[
i
]));
config
->
multi_source_config
[
config
->
num_source_sub_bins
].
type
=
NV_DS_SOURCE_URI
;
config
->
multi_source_config
[
config
->
num_source_sub_bins
].
uri
=
g_strdup_printf
(
config
->
multi_source_config
[
config
->
num_source_sub_bins
].
uri
,
j
);
config
->
num_source_sub_bins
++
;
}
config
->
multi_source_config
[
i
].
type
=
NV_DS_SOURCE_URI
;
config
->
multi_source_config
[
i
].
uri
=
g_strdup_printf
(
config
->
multi_source_config
[
i
].
uri
,
0
);
}
}
ret
=
TRUE
;
done:
if
(
!
ret
)
{
cout
<<
__func__
<<
" failed"
<<
endl
;
}
return
ret
;
}
sugon_apps/sample_apps/deepstream-app/deepstream_app_main.c
0 → 100644
View file @
24460ef5
/*
* SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: LicenseRef-NvidiaProprietary
*
* NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
* property and proprietary rights in and to this material, related
* documentation and any modifications thereto. Any use, reproduction,
* disclosure or distribution of this material and related documentation
* without an express license agreement from NVIDIA CORPORATION or
* its affiliates is strictly prohibited.
*/
#include "deepstream_app.h"
#include "deepstream_config_file_parser.h"
#include <cuda_runtime_api.h>
#include "nvds_version.h"
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define MAX_INSTANCES 128
#define APP_TITLE "DeepStream"
#define DEFAULT_X_WINDOW_WIDTH 1920
#define DEFAULT_X_WINDOW_HEIGHT 1080
AppCtx
*
appCtx
[
MAX_INSTANCES
];
static
guint
cintr
=
FALSE
;
static
GMainLoop
*
main_loop
=
NULL
;
static
gchar
**
cfg_files
=
NULL
;
static
gchar
**
input_uris
=
NULL
;
static
gboolean
print_version
=
FALSE
;
static
gboolean
show_bbox_text
=
FALSE
;
static
gboolean
print_dependencies_version
=
FALSE
;
static
gboolean
quit
=
FALSE
;
static
gint
return_value
=
0
;
static
guint
num_instances
;
static
guint
num_input_uris
;
static
GMutex
fps_lock
;
static
gdouble
fps
[
MAX_SOURCE_BINS
];
static
gdouble
fps_avg
[
MAX_SOURCE_BINS
];
static
Display
*
display
=
NULL
;
static
Window
windows
[
MAX_INSTANCES
]
=
{
0
};
static
GThread
*
x_event_thread
=
NULL
;
static
GMutex
disp_lock
;
static
guint
rrow
,
rcol
,
rcfg
;
static
gboolean
rrowsel
=
FALSE
,
selecting
=
FALSE
;
GST_DEBUG_CATEGORY
(
NVDS_APP
);
GOptionEntry
entries
[]
=
{
{
"version"
,
'v'
,
0
,
G_OPTION_ARG_NONE
,
&
print_version
,
"Print DeepStreamSDK version"
,
NULL
}
,
{
"tiledtext"
,
't'
,
0
,
G_OPTION_ARG_NONE
,
&
show_bbox_text
,
"Display Bounding box labels in tiled mode"
,
NULL
}
,
{
"version-all"
,
0
,
0
,
G_OPTION_ARG_NONE
,
&
print_dependencies_version
,
"Print DeepStreamSDK and dependencies version"
,
NULL
}
,
{
"cfg-file"
,
'c'
,
0
,
G_OPTION_ARG_FILENAME_ARRAY
,
&
cfg_files
,
"Set the config file"
,
NULL
}
,
{
"input-uri"
,
'i'
,
0
,
G_OPTION_ARG_FILENAME_ARRAY
,
&
input_uris
,
"Set the input uri (file://stream or rtsp://stream)"
,
NULL
}
,
{
NULL
}
,
};
/**
* Callback function to be called once all inferences (Primary + Secondary)
* are done. This is opportunity to modify content of the metadata.
* e.g. Here Person is being replaced with Man/Woman and corresponding counts
* are being maintained. It should be modified according to network classes
* or can be removed altogether if not required.
*/
static
void
all_bbox_generated
(
AppCtx
*
appCtx
,
GstBuffer
*
buf
,
NvDsBatchMeta
*
batch_meta
,
guint
index
)
{
guint
num_male
=
0
;
guint
num_female
=
0
;
guint
num_objects
[
128
];
memset
(
num_objects
,
0
,
sizeof
(
num_objects
));
for
(
NvDsMetaList
*
l_frame
=
batch_meta
->
frame_meta_list
;
l_frame
!=
NULL
;
l_frame
=
l_frame
->
next
)
{
NvDsFrameMeta
*
frame_meta
=
l_frame
->
data
;
for
(
NvDsMetaList
*
l_obj
=
frame_meta
->
obj_meta_list
;
l_obj
!=
NULL
;
l_obj
=
l_obj
->
next
)
{
NvDsObjectMeta
*
obj
=
(
NvDsObjectMeta
*
)
l_obj
->
data
;
if
(
obj
->
unique_component_id
==
(
gint
)
appCtx
->
config
.
primary_gie_config
.
unique_id
)
{
if
(
obj
->
class_id
>=
0
&&
obj
->
class_id
<
128
)
{
num_objects
[
obj
->
class_id
]
++
;
}
if
(
appCtx
->
person_class_id
>
-
1
&&
obj
->
class_id
==
appCtx
->
person_class_id
)
{
if
(
strstr
(
obj
->
text_params
.
display_text
,
"Man"
))
{
str_replace
(
obj
->
text_params
.
display_text
,
"Man"
,
""
);
str_replace
(
obj
->
text_params
.
display_text
,
"Person"
,
"Man"
);
num_male
++
;
}
else
if
(
strstr
(
obj
->
text_params
.
display_text
,
"Woman"
))
{
str_replace
(
obj
->
text_params
.
display_text
,
"Woman"
,
""
);
str_replace
(
obj
->
text_params
.
display_text
,
"Person"
,
"Woman"
);
num_female
++
;
}
}
}
}
}
}
/**
* Function to handle program interrupt signal.
* It installs default handler after handling the interrupt.
*/
static
void
_intr_handler
(
int
signum
)
{
struct
sigaction
action
;
NVGSTDS_ERR_MSG_V
(
"User Interrupted..
\n
"
);
memset
(
&
action
,
0
,
sizeof
(
action
));
action
.
sa_handler
=
SIG_DFL
;
sigaction
(
SIGINT
,
&
action
,
NULL
);
cintr
=
TRUE
;
}
/**
* callback function to print the performance numbers of each stream.
*/
static
void
perf_cb
(
gpointer
context
,
NvDsAppPerfStruct
*
str
)
{
static
guint
header_print_cnt
=
0
;
guint
i
;
AppCtx
*
appCtx
=
(
AppCtx
*
)
context
;
guint
numf
=
str
->
num_instances
;
g_mutex_lock
(
&
fps_lock
);
for
(
i
=
0
;
i
<
numf
;
i
++
)
{
fps
[
i
]
=
str
->
fps
[
i
];
fps_avg
[
i
]
=
str
->
fps_avg
[
i
];
}
if
(
header_print_cnt
%
20
==
0
)
{
g_print
(
"
\n
**PERF: "
);
for
(
i
=
0
;
i
<
numf
;
i
++
)
{
g_print
(
"FPS %d (Avg)
\t
"
,
i
);
}
g_print
(
"
\n
"
);
header_print_cnt
=
0
;
}
header_print_cnt
++
;
if
(
num_instances
>
1
)
g_print
(
"PERF(%d): "
,
appCtx
->
index
);
else
g_print
(
"**PERF: "
);
for
(
i
=
0
;
i
<
numf
;
i
++
)
{
g_print
(
"%.2f (%.2f)
\t
"
,
fps
[
i
],
fps_avg
[
i
]);
}
g_print
(
"
\n
"
);
g_mutex_unlock
(
&
fps_lock
);
}
/**
* Loop function to check the status of interrupts.
* It comes out of loop if application got interrupted.
*/
static
gboolean
check_for_interrupt
(
gpointer
data
)
{
if
(
quit
)
{
return
FALSE
;
}
if
(
cintr
)
{
cintr
=
FALSE
;
quit
=
TRUE
;
g_main_loop_quit
(
main_loop
);
return
FALSE
;
}
return
TRUE
;
}
/*
* Function to install custom handler for program interrupt signal.
*/
static
void
_intr_setup
(
void
)
{
struct
sigaction
action
;
memset
(
&
action
,
0
,
sizeof
(
action
));
action
.
sa_handler
=
_intr_handler
;
sigaction
(
SIGINT
,
&
action
,
NULL
);
}
static
gboolean
kbhit
(
void
)
{
struct
timeval
tv
;
fd_set
rdfs
;
tv
.
tv_sec
=
0
;
tv
.
tv_usec
=
0
;
FD_ZERO
(
&
rdfs
);
FD_SET
(
STDIN_FILENO
,
&
rdfs
);
select
(
STDIN_FILENO
+
1
,
&
rdfs
,
NULL
,
NULL
,
&
tv
);
return
FD_ISSET
(
STDIN_FILENO
,
&
rdfs
);
}
/*
* Function to enable / disable the canonical mode of terminal.
* In non canonical mode input is available immediately (without the user
* having to type a line-delimiter character).
*/
static
void
changemode
(
int
dir
)
{
static
struct
termios
oldt
,
newt
;
if
(
dir
==
1
)
{
tcgetattr
(
STDIN_FILENO
,
&
oldt
);
newt
=
oldt
;
newt
.
c_lflag
&=
~
(
ICANON
);
tcsetattr
(
STDIN_FILENO
,
TCSANOW
,
&
newt
);
}
else
tcsetattr
(
STDIN_FILENO
,
TCSANOW
,
&
oldt
);
}
static
void
print_runtime_commands
(
void
)
{
g_print
(
"
\n
Runtime commands:
\n
"
"
\t
h: Print this help
\n
"
"
\t
q: Quit
\n\n
"
"
\t
p: Pause
\n
"
"
\t
r: Resume
\n\n
"
);
if
(
appCtx
[
0
]
->
config
.
tiled_display_config
.
enable
)
{
g_print
(
"NOTE: To expand a source in the 2D tiled display and view object details,"
" left-click on the source.
\n
"
" To go back to the tiled display, right-click anywhere on the window.
\n\n
"
);
}
}
/**
* Loop function to check keyboard inputs and status of each pipeline.
*/
static
gboolean
event_thread_func
(
gpointer
arg
)
{
guint
i
;
gboolean
ret
=
TRUE
;
// Check if all instances have quit
for
(
i
=
0
;
i
<
num_instances
;
i
++
)
{
if
(
!
appCtx
[
i
]
->
quit
)
break
;
}
if
(
i
==
num_instances
)
{
quit
=
TRUE
;
g_main_loop_quit
(
main_loop
);
return
FALSE
;
}
// Check for keyboard input
if
(
!
kbhit
())
{
//continue;
return
TRUE
;
}
int
c
=
fgetc
(
stdin
);
g_print
(
"
\n
"
);
gint
source_id
;
GstElement
*
tiler
=
appCtx
[
rcfg
]
->
pipeline
.
tiled_display_bin
.
tiler
;
if
(
appCtx
[
rcfg
]
->
config
.
tiled_display_config
.
enable
)
{
g_object_get
(
G_OBJECT
(
tiler
),
"show-source"
,
&
source_id
,
NULL
);
if
(
selecting
)
{
if
(
rrowsel
==
FALSE
)
{
if
(
c
>=
'0'
&&
c
<=
'9'
)
{
rrow
=
c
-
'0'
;
if
(
rrow
<
appCtx
[
rcfg
]
->
config
.
tiled_display_config
.
rows
){
g_print
(
"--selecting source row %d--
\n
"
,
rrow
);
rrowsel
=
TRUE
;
}
else
{
g_print
(
"--selected source row %d out of bound, reenter
\n
"
,
rrow
);
}
}
}
else
{
if
(
c
>=
'0'
&&
c
<=
'9'
)
{
unsigned
int
tile_num_columns
=
appCtx
[
rcfg
]
->
config
.
tiled_display_config
.
columns
;
rcol
=
c
-
'0'
;
if
(
rcol
<
tile_num_columns
){
selecting
=
FALSE
;
rrowsel
=
FALSE
;
source_id
=
tile_num_columns
*
rrow
+
rcol
;
g_print
(
"--selecting source col %d sou=%d--
\n
"
,
rcol
,
source_id
);
if
(
source_id
>=
(
gint
)
appCtx
[
rcfg
]
->
config
.
num_source_sub_bins
)
{
source_id
=
-
1
;
}
else
{
appCtx
[
rcfg
]
->
show_bbox_text
=
TRUE
;
appCtx
[
rcfg
]
->
active_source_index
=
source_id
;
g_object_set
(
G_OBJECT
(
tiler
),
"show-source"
,
source_id
,
NULL
);
}
}
else
{
g_print
(
"--selected source col %d out of bound, reenter
\n
"
,
rcol
);
}
}
}
}
}
switch
(
c
)
{
case
'h'
:
print_runtime_commands
();
break
;
case
'p'
:
for
(
i
=
0
;
i
<
num_instances
;
i
++
)
pause_pipeline
(
appCtx
[
i
]);
break
;
case
'r'
:
for
(
i
=
0
;
i
<
num_instances
;
i
++
)
resume_pipeline
(
appCtx
[
i
]);
break
;
case
'q'
:
quit
=
TRUE
;
g_main_loop_quit
(
main_loop
);
ret
=
FALSE
;
break
;
case
'c'
:
if
(
appCtx
[
rcfg
]
->
config
.
tiled_display_config
.
enable
&&
selecting
==
FALSE
&&
source_id
==
-
1
)
{
g_print
(
"--selecting config file --
\n
"
);
c
=
fgetc
(
stdin
);
if
(
c
>=
'0'
&&
c
<=
'9'
)
{
rcfg
=
c
-
'0'
;
if
(
rcfg
<
num_instances
)
{
g_print
(
"--selecting config %d--
\n
"
,
rcfg
);
}
else
{
g_print
(
"--selected config file %d out of bound, reenter
\n
"
,
rcfg
);
rcfg
=
0
;
}
}
}
break
;
case
'z'
:
if
(
appCtx
[
rcfg
]
->
config
.
tiled_display_config
.
enable
&&
source_id
==
-
1
&&
selecting
==
FALSE
)
{
g_print
(
"--selecting source --
\n
"
);
selecting
=
TRUE
;
}
else
{
if
(
!
show_bbox_text
)
appCtx
[
rcfg
]
->
show_bbox_text
=
FALSE
;
g_object_set
(
G_OBJECT
(
tiler
),
"show-source"
,
-
1
,
NULL
);
appCtx
[
rcfg
]
->
active_source_index
=
-
1
;
selecting
=
FALSE
;
rcfg
=
0
;
g_print
(
"--tiled mode --
\n
"
);
}
break
;
default:
break
;
}
return
ret
;
}
static
int
get_source_id_from_coordinates
(
float
x_rel
,
float
y_rel
,
AppCtx
*
appCtx
)
{
int
tile_num_rows
=
appCtx
->
config
.
tiled_display_config
.
rows
;
int
tile_num_columns
=
appCtx
->
config
.
tiled_display_config
.
columns
;
int
source_id
=
(
int
)
(
x_rel
*
tile_num_columns
);
source_id
+=
((
int
)
(
y_rel
*
tile_num_rows
))
*
tile_num_columns
;
/* Don't allow clicks on empty tiles. */
if
(
source_id
>=
(
gint
)
appCtx
->
config
.
num_source_sub_bins
)
source_id
=
-
1
;
return
source_id
;
}
/**
* Thread to monitor X window events.
*/
static
gpointer
nvds_x_event_thread
(
gpointer
data
)
{
g_mutex_lock
(
&
disp_lock
);
while
(
display
)
{
XEvent
e
;
guint
index
;
memset
(
&
e
,
0
,
sizeof
(
XEvent
));
while
(
XPending
(
display
))
{
XNextEvent
(
display
,
&
e
);
switch
(
e
.
type
)
{
case
ButtonPress
:
{
XWindowAttributes
win_attr
;
XButtonEvent
ev
=
e
.
xbutton
;
gint
source_id
;
GstElement
*
tiler
;
memset
(
&
win_attr
,
0
,
sizeof
(
XWindowAttributes
));
XGetWindowAttributes
(
display
,
ev
.
window
,
&
win_attr
);
for
(
index
=
0
;
index
<
MAX_INSTANCES
;
index
++
)
if
(
ev
.
window
==
windows
[
index
])
break
;
tiler
=
appCtx
[
index
]
->
pipeline
.
tiled_display_bin
.
tiler
;
g_object_get
(
G_OBJECT
(
tiler
),
"show-source"
,
&
source_id
,
NULL
);
if
(
ev
.
button
==
Button1
&&
source_id
==
-
1
&&
(
index
>=
0
&&
index
<
MAX_INSTANCES
))
{
source_id
=
get_source_id_from_coordinates
(
ev
.
x
*
1
.
0
/
win_attr
.
width
,
ev
.
y
*
1
.
0
/
win_attr
.
height
,
appCtx
[
index
]);
if
(
source_id
>
-
1
)
{
g_object_set
(
G_OBJECT
(
tiler
),
"show-source"
,
source_id
,
NULL
);
appCtx
[
index
]
->
active_source_index
=
source_id
;
appCtx
[
index
]
->
show_bbox_text
=
TRUE
;
}
}
else
if
(
ev
.
button
==
Button3
)
{
g_object_set
(
G_OBJECT
(
tiler
),
"show-source"
,
-
1
,
NULL
);
appCtx
[
index
]
->
active_source_index
=
-
1
;
if
(
!
show_bbox_text
)
appCtx
[
index
]
->
show_bbox_text
=
FALSE
;
}
}
break
;
case
KeyRelease
:
case
KeyPress
:
{
KeySym
p
,
r
,
q
;
guint
i
;
p
=
XKeysymToKeycode
(
display
,
XK_P
);
r
=
XKeysymToKeycode
(
display
,
XK_R
);
q
=
XKeysymToKeycode
(
display
,
XK_Q
);
if
(
e
.
xkey
.
keycode
==
p
)
{
for
(
i
=
0
;
i
<
num_instances
;
i
++
)
pause_pipeline
(
appCtx
[
i
]);
break
;
}
if
(
e
.
xkey
.
keycode
==
r
)
{
for
(
i
=
0
;
i
<
num_instances
;
i
++
)
resume_pipeline
(
appCtx
[
i
]);
break
;
}
if
(
e
.
xkey
.
keycode
==
q
)
{
quit
=
TRUE
;
g_main_loop_quit
(
main_loop
);
}
}
break
;
case
ClientMessage
:
{
Atom
wm_delete
;
for
(
index
=
0
;
index
<
MAX_INSTANCES
;
index
++
)
if
(
e
.
xclient
.
window
==
windows
[
index
])
break
;
wm_delete
=
XInternAtom
(
display
,
"WM_DELETE_WINDOW"
,
1
);
if
(
wm_delete
!=
None
&&
wm_delete
==
(
Atom
)
e
.
xclient
.
data
.
l
[
0
])
{
quit
=
TRUE
;
g_main_loop_quit
(
main_loop
);
}
}
break
;
}
}
g_mutex_unlock
(
&
disp_lock
);
g_usleep
(
G_USEC_PER_SEC
/
20
);
g_mutex_lock
(
&
disp_lock
);
}
g_mutex_unlock
(
&
disp_lock
);
return
NULL
;
}
/**
* callback function to add application specific metadata.
* Here it demonstrates how to display the URI of source in addition to
* the text generated after inference.
*/
static
gboolean
overlay_graphics
(
AppCtx
*
appCtx
,
GstBuffer
*
buf
,
NvDsBatchMeta
*
batch_meta
,
guint
index
)
{
int
srcIndex
=
appCtx
->
active_source_index
;
if
(
srcIndex
==
-
1
)
return
TRUE
;
NvDsFrameLatencyInfo
*
latency_info
=
NULL
;
NvDsDisplayMeta
*
display_meta
=
nvds_acquire_display_meta_from_pool
(
batch_meta
);
display_meta
->
num_labels
=
1
;
display_meta
->
text_params
[
0
].
display_text
=
g_strdup_printf
(
"Source: %s"
,
appCtx
->
config
.
multi_source_config
[
srcIndex
].
uri
);
display_meta
->
text_params
[
0
].
y_offset
=
20
;
display_meta
->
text_params
[
0
].
x_offset
=
20
;
display_meta
->
text_params
[
0
].
font_params
.
font_color
=
(
NvOSD_ColorParams
)
{
0
,
1
,
0
,
1
};
display_meta
->
text_params
[
0
].
font_params
.
font_size
=
appCtx
->
config
.
osd_config
.
text_size
*
1
.
5
;
display_meta
->
text_params
[
0
].
font_params
.
font_name
=
"Serif"
;
display_meta
->
text_params
[
0
].
set_bg_clr
=
1
;
display_meta
->
text_params
[
0
].
text_bg_clr
=
(
NvOSD_ColorParams
)
{
0
,
0
,
0
,
1
.
0
};
if
(
nvds_enable_latency_measurement
)
{
g_mutex_lock
(
&
appCtx
->
latency_lock
);
latency_info
=
&
appCtx
->
latency_info
[
index
];
display_meta
->
num_labels
++
;
display_meta
->
text_params
[
1
].
display_text
=
g_strdup_printf
(
"Latency: %lf"
,
latency_info
->
latency
);
g_mutex_unlock
(
&
appCtx
->
latency_lock
);
display_meta
->
text_params
[
1
].
y_offset
=
(
display_meta
->
text_params
[
0
].
y_offset
*
2
)
+
display_meta
->
text_params
[
0
].
font_params
.
font_size
;
display_meta
->
text_params
[
1
].
x_offset
=
20
;
display_meta
->
text_params
[
1
].
font_params
.
font_color
=
(
NvOSD_ColorParams
)
{
0
,
1
,
0
,
1
};
display_meta
->
text_params
[
1
].
font_params
.
font_size
=
appCtx
->
config
.
osd_config
.
text_size
*
1
.
5
;
display_meta
->
text_params
[
1
].
font_params
.
font_name
=
"Arial"
;
display_meta
->
text_params
[
1
].
set_bg_clr
=
1
;
display_meta
->
text_params
[
1
].
text_bg_clr
=
(
NvOSD_ColorParams
)
{
0
,
0
,
0
,
1
.
0
};
}
nvds_add_display_meta_to_frame
(
nvds_get_nth_frame_meta
(
batch_meta
->
frame_meta_list
,
0
),
display_meta
);
return
TRUE
;
}
static
gboolean
recreate_pipeline_thread_func
(
gpointer
arg
)
{
guint
i
;
gboolean
ret
=
TRUE
;
AppCtx
*
appCtx
=
(
AppCtx
*
)
arg
;
g_print
(
"Destroy pipeline
\n
"
);
destroy_pipeline
(
appCtx
);
g_print
(
"Recreate pipeline
\n
"
);
if
(
!
create_pipeline
(
appCtx
,
NULL
,
all_bbox_generated
,
perf_cb
,
overlay_graphics
))
{
NVGSTDS_ERR_MSG_V
(
"Failed to create pipeline"
);
return_value
=
-
1
;
return
FALSE
;
}
if
(
gst_element_set_state
(
appCtx
->
pipeline
.
pipeline
,
GST_STATE_PAUSED
)
==
GST_STATE_CHANGE_FAILURE
)
{
NVGSTDS_ERR_MSG_V
(
"Failed to set pipeline to PAUSED"
);
return_value
=
-
1
;
return
FALSE
;
}
for
(
i
=
0
;
i
<
appCtx
->
config
.
num_sink_sub_bins
;
i
++
)
{
if
(
!
GST_IS_VIDEO_OVERLAY
(
appCtx
->
pipeline
.
instance_bins
[
0
].
sink_bin
.
sub_bins
[
i
].
sink
))
{
continue
;
}
gst_video_overlay_set_window_handle
(
GST_VIDEO_OVERLAY
(
appCtx
->
pipeline
.
instance_bins
[
0
].
sink_bin
.
sub_bins
[
i
].
sink
),
(
gulong
)
windows
[
appCtx
->
index
]);
gst_video_overlay_expose
(
GST_VIDEO_OVERLAY
(
appCtx
->
pipeline
.
instance_bins
[
0
].
sink_bin
.
sub_bins
[
i
].
sink
));
}
if
(
gst_element_set_state
(
appCtx
->
pipeline
.
pipeline
,
GST_STATE_PLAYING
)
==
GST_STATE_CHANGE_FAILURE
)
{
g_print
(
"
\n
can't set pipeline to playing state.
\n
"
);
return_value
=
-
1
;
return
FALSE
;
}
return
ret
;
}
int
main
(
int
argc
,
char
*
argv
[])
{
GOptionContext
*
ctx
=
NULL
;
GOptionGroup
*
group
=
NULL
;
GError
*
error
=
NULL
;
guint
i
;
ctx
=
g_option_context_new
(
"Nvidia DeepStream Demo"
);
group
=
g_option_group_new
(
"abc"
,
NULL
,
NULL
,
NULL
,
NULL
);
g_option_group_add_entries
(
group
,
entries
);
g_option_context_set_main_group
(
ctx
,
group
);
g_option_context_add_group
(
ctx
,
gst_init_get_option_group
());
GST_DEBUG_CATEGORY_INIT
(
NVDS_APP
,
"NVDS_APP"
,
0
,
NULL
);
int
current_device
=
-
1
;
cudaGetDevice
(
&
current_device
);
struct
cudaDeviceProp
prop
;
cudaGetDeviceProperties
(
&
prop
,
current_device
);
if
(
!
g_option_context_parse
(
ctx
,
&
argc
,
&
argv
,
&
error
))
{
NVGSTDS_ERR_MSG_V
(
"%s"
,
error
->
message
);
return
-
1
;
}
if
(
print_version
)
{
g_print
(
"deepstream-app version %d.%d.%d
\n
"
,
NVDS_APP_VERSION_MAJOR
,
NVDS_APP_VERSION_MINOR
,
NVDS_APP_VERSION_MICRO
);
nvds_version_print
();
return
0
;
}
if
(
print_dependencies_version
)
{
g_print
(
"deepstream-app version %d.%d.%d
\n
"
,
NVDS_APP_VERSION_MAJOR
,
NVDS_APP_VERSION_MINOR
,
NVDS_APP_VERSION_MICRO
);
nvds_version_print
();
nvds_dependencies_version_print
();
return
0
;
}
if
(
cfg_files
)
{
num_instances
=
g_strv_length
(
cfg_files
);
}
if
(
input_uris
)
{
num_input_uris
=
g_strv_length
(
input_uris
);
}
if
(
!
cfg_files
||
num_instances
==
0
)
{
NVGSTDS_ERR_MSG_V
(
"Specify config file with -c option"
);
return_value
=
-
1
;
goto
done
;
}
for
(
i
=
0
;
i
<
num_instances
;
i
++
)
{
appCtx
[
i
]
=
g_malloc0
(
sizeof
(
AppCtx
));
appCtx
[
i
]
->
person_class_id
=
-
1
;
appCtx
[
i
]
->
car_class_id
=
-
1
;
appCtx
[
i
]
->
index
=
i
;
appCtx
[
i
]
->
active_source_index
=
-
1
;
if
(
show_bbox_text
)
{
appCtx
[
i
]
->
show_bbox_text
=
TRUE
;
}
if
(
input_uris
&&
input_uris
[
i
])
{
appCtx
[
i
]
->
config
.
multi_source_config
[
0
].
uri
=
g_strdup_printf
(
"%s"
,
input_uris
[
i
]);
g_free
(
input_uris
[
i
]);
}
if
(
g_str_has_suffix
(
cfg_files
[
i
],
".yml"
)
||
g_str_has_suffix
(
cfg_files
[
i
],
".yaml"
))
{
if
(
!
parse_config_file_yaml
(
&
appCtx
[
i
]
->
config
,
cfg_files
[
i
]))
{
NVGSTDS_ERR_MSG_V
(
"Failed to parse config file '%s'"
,
cfg_files
[
i
]);
appCtx
[
i
]
->
return_value
=
-
1
;
goto
done
;
}
}
else
if
(
g_str_has_suffix
(
cfg_files
[
i
],
".txt"
))
{
if
(
!
parse_config_file
(
&
appCtx
[
i
]
->
config
,
cfg_files
[
i
]))
{
NVGSTDS_ERR_MSG_V
(
"Failed to parse config file '%s'"
,
cfg_files
[
i
]);
appCtx
[
i
]
->
return_value
=
-
1
;
goto
done
;
}
}
}
for
(
i
=
0
;
i
<
num_instances
;
i
++
)
{
if
(
!
create_pipeline
(
appCtx
[
i
],
NULL
,
all_bbox_generated
,
perf_cb
,
overlay_graphics
))
{
NVGSTDS_ERR_MSG_V
(
"Failed to create pipeline"
);
return_value
=
-
1
;
goto
done
;
}
}
main_loop
=
g_main_loop_new
(
NULL
,
FALSE
);
_intr_setup
();
g_timeout_add
(
400
,
check_for_interrupt
,
NULL
);
g_mutex_init
(
&
disp_lock
);
display
=
XOpenDisplay
(
NULL
);
for
(
i
=
0
;
i
<
num_instances
;
i
++
)
{
guint
j
;
#if defined(__aarch64__)
if
(
gst_element_set_state
(
appCtx
[
i
]
->
pipeline
.
pipeline
,
GST_STATE_PAUSED
)
==
GST_STATE_CHANGE_FAILURE
)
{
NVGSTDS_ERR_MSG_V
(
"Failed to set pipeline to PAUSED"
);
return_value
=
-
1
;
goto
done
;
}
#endif
for
(
j
=
0
;
j
<
appCtx
[
i
]
->
config
.
num_sink_sub_bins
;
j
++
)
{
XTextProperty
xproperty
;
gchar
*
title
;
guint
width
,
height
;
XSizeHints
hints
=
{
0
};
if
(
!
GST_IS_VIDEO_OVERLAY
(
appCtx
[
i
]
->
pipeline
.
instance_bins
[
0
].
sink_bin
.
sub_bins
[
j
].
sink
))
{
continue
;
}
if
(
!
display
)
{
NVGSTDS_ERR_MSG_V
(
"Could not open X Display"
);
return_value
=
-
1
;
goto
done
;
}
if
(
appCtx
[
i
]
->
config
.
sink_bin_sub_bin_config
[
j
].
render_config
.
width
)
width
=
appCtx
[
i
]
->
config
.
sink_bin_sub_bin_config
[
j
].
render_config
.
width
;
else
width
=
appCtx
[
i
]
->
config
.
tiled_display_config
.
width
;
if
(
appCtx
[
i
]
->
config
.
sink_bin_sub_bin_config
[
j
].
render_config
.
height
)
height
=
appCtx
[
i
]
->
config
.
sink_bin_sub_bin_config
[
j
].
render_config
.
height
;
else
height
=
appCtx
[
i
]
->
config
.
tiled_display_config
.
height
;
width
=
(
width
)
?
width
:
DEFAULT_X_WINDOW_WIDTH
;
height
=
(
height
)
?
height
:
DEFAULT_X_WINDOW_HEIGHT
;
hints
.
flags
=
PPosition
|
PSize
;
hints
.
x
=
appCtx
[
i
]
->
config
.
sink_bin_sub_bin_config
[
j
].
render_config
.
offset_x
;
hints
.
y
=
appCtx
[
i
]
->
config
.
sink_bin_sub_bin_config
[
j
].
render_config
.
offset_y
;
hints
.
width
=
width
;
hints
.
height
=
height
;
windows
[
i
]
=
XCreateSimpleWindow
(
display
,
RootWindow
(
display
,
DefaultScreen
(
display
)),
hints
.
x
,
hints
.
y
,
width
,
height
,
2
,
0x00000000
,
0x00000000
);
XSetNormalHints
(
display
,
windows
[
i
],
&
hints
);
if
(
num_instances
>
1
)
title
=
g_strdup_printf
(
APP_TITLE
"-%d"
,
i
);
else
title
=
g_strdup
(
APP_TITLE
);
if
(
XStringListToTextProperty
((
char
**
)
&
title
,
1
,
&
xproperty
)
!=
0
)
{
XSetWMName
(
display
,
windows
[
i
],
&
xproperty
);
XFree
(
xproperty
.
value
);
}
XSetWindowAttributes
attr
=
{
0
};
if
((
appCtx
[
i
]
->
config
.
tiled_display_config
.
enable
&&
appCtx
[
i
]
->
config
.
tiled_display_config
.
rows
*
appCtx
[
i
]
->
config
.
tiled_display_config
.
columns
==
1
)
||
(
appCtx
[
i
]
->
config
.
tiled_display_config
.
enable
==
0
))
{
attr
.
event_mask
=
KeyPress
;
}
else
if
(
appCtx
[
i
]
->
config
.
tiled_display_config
.
enable
)
{
attr
.
event_mask
=
ButtonPress
|
KeyRelease
;
}
XChangeWindowAttributes
(
display
,
windows
[
i
],
CWEventMask
,
&
attr
);
Atom
wmDeleteMessage
=
XInternAtom
(
display
,
"WM_DELETE_WINDOW"
,
False
);
if
(
wmDeleteMessage
!=
None
)
{
XSetWMProtocols
(
display
,
windows
[
i
],
&
wmDeleteMessage
,
1
);
}
XMapRaised
(
display
,
windows
[
i
]);
XSync
(
display
,
1
);
//discard the events for now
gst_video_overlay_set_window_handle
(
GST_VIDEO_OVERLAY
(
appCtx
[
i
]
->
pipeline
.
instance_bins
[
0
].
sink_bin
.
sub_bins
[
j
].
sink
),
(
gulong
)
windows
[
i
]);
gst_video_overlay_expose
(
GST_VIDEO_OVERLAY
(
appCtx
[
i
]
->
pipeline
.
instance_bins
[
0
].
sink_bin
.
sub_bins
[
j
].
sink
));
if
(
!
x_event_thread
)
x_event_thread
=
g_thread_new
(
"nvds-window-event-thread"
,
nvds_x_event_thread
,
NULL
);
}
#if !defined(__aarch64__)
if
(
!
prop
.
integrated
)
{
if
(
gst_element_set_state
(
appCtx
[
i
]
->
pipeline
.
pipeline
,
GST_STATE_PAUSED
)
==
GST_STATE_CHANGE_FAILURE
)
{
NVGSTDS_ERR_MSG_V
(
"Failed to set pipeline to PAUSED"
);
return_value
=
-
1
;
goto
done
;
}
}
#endif
}
/* Dont try to set playing state if error is observed */
if
(
return_value
!=
-
1
)
{
for
(
i
=
0
;
i
<
num_instances
;
i
++
)
{
if
(
gst_element_set_state
(
appCtx
[
i
]
->
pipeline
.
pipeline
,
GST_STATE_PLAYING
)
==
GST_STATE_CHANGE_FAILURE
)
{
g_print
(
"
\n
can't set pipeline to playing state.
\n
"
);
return_value
=
-
1
;
goto
done
;
}
if
(
appCtx
[
i
]
->
config
.
pipeline_recreate_sec
)
g_timeout_add_seconds
(
appCtx
[
i
]
->
config
.
pipeline_recreate_sec
,
recreate_pipeline_thread_func
,
appCtx
[
i
]);
}
}
print_runtime_commands
();
changemode
(
1
);
g_timeout_add
(
40
,
event_thread_func
,
NULL
);
g_main_loop_run
(
main_loop
);
changemode
(
0
);
done:
g_print
(
"Quitting
\n
"
);
for
(
i
=
0
;
i
<
num_instances
;
i
++
)
{
if
(
appCtx
[
i
]
->
return_value
==
-
1
)
return_value
=
-
1
;
destroy_pipeline
(
appCtx
[
i
]);
g_mutex_lock
(
&
disp_lock
);
if
(
windows
[
i
])
XDestroyWindow
(
display
,
windows
[
i
]);
windows
[
i
]
=
0
;
g_mutex_unlock
(
&
disp_lock
);
g_free
(
appCtx
[
i
]);
}
g_mutex_lock
(
&
disp_lock
);
if
(
display
)
XCloseDisplay
(
display
);
display
=
NULL
;
g_mutex_unlock
(
&
disp_lock
);
g_mutex_clear
(
&
disp_lock
);
if
(
main_loop
)
{
g_main_loop_unref
(
main_loop
);
}
if
(
ctx
)
{
g_option_context_free
(
ctx
);
}
if
(
return_value
==
0
)
{
g_print
(
"App run successful
\n
"
);
}
else
{
g_print
(
"App run failed
\n
"
);
}
gst_deinit
();
return
return_value
;
}
sugon_apps/sample_apps/deepstream-test1/dstest1_config.yml
View file @
24460ef5
...
...
@@ -14,10 +14,11 @@ source:
location
:
../../../streams/cr7_1920x1080.h264
streammux
:
batch-size
:
1
batch-size
:
5
batched-push-timeout
:
40000
width
:
1920
height
:
1080
gpu-id
:
2
## Inference using nvinferserver:
primary-gie
:
...
...
sugon_apps/sample_apps/deepstream-test1/dstest1_pgie_nvinferserver_config.txt
View file @
24460ef5
...
...
@@ -12,7 +12,7 @@
infer_config {
unique_id: 1
gpu_ids: [
0
]
gpu_ids: [
2
]
max_batch_size: 30
backend {
inputs: [ {
...
...
sugon_apps/sample_apps/deepstream-test2/deepstream_test2_app.c
View file @
24460ef5
...
...
@@ -409,7 +409,7 @@ main (int argc, char *argv[])
g_object_set
(
G_OBJECT
(
source
),
"location"
,
argv
[
1
],
NULL
);
g_object_set
(
G_OBJECT
(
streammux
),
"batch-size"
,
1
,
NULL
);
g_object_set
(
G_OBJECT
(
streammux
),
"gpu-id"
,
3
,
NULL
);
g_object_set
(
G_OBJECT
(
streammux
),
"width"
,
MUXER_OUTPUT_WIDTH
,
"height"
,
MUXER_OUTPUT_HEIGHT
,
"batched-push-timeout"
,
MUXER_BATCH_TIMEOUT_USEC
,
NULL
);
...
...
sugon_apps/sample_apps/deepstream-test2/dstest2_config.yml
View file @
24460ef5
...
...
@@ -18,16 +18,17 @@ streammux:
batched-push-timeout
:
40000
width
:
1920
height
:
1080
gpu-id
:
3
tracker
:
tracker-width
:
960
tracker-height
:
544
gpu-id
:
0
gpu-id
:
3
ll-lib-file
:
/opt/deepstream/lib/libnvds_nvmultiobjecttracker.so
# ll-config-file required to set different tracker types
# ll-config-file: ../../../../samples/configs/deepstream-app/config_tracker_IOU.yml
ll-config-file
:
../../../
../
samples/configs/deepstream-app/config_tracker_NvSORT.yml
ll-config-file
:
../../../
sugon_
samples/configs/deepstream-app/config_tracker_NvSORT.yml
# ll-config-file: ../../../../samples/configs/deepstream-app/config_tracker_NvDCF_perf.yml
# ll-config-file: ../../../../samples/configs/deepstream-app/config_tracker_NvDCF_accuracy.yml
# ll-config-file: ../../../../samples/configs/deepstream-app/config_tracker_NvDeepSORT.yml
...
...
sugon_apps/sample_apps/deepstream-test2/dstest2_pgie_nvinferserver_config.txt
View file @
24460ef5
...
...
@@ -12,7 +12,7 @@
infer_config {
unique_id: 1
gpu_ids: [
0
]
gpu_ids: [
3
]
max_batch_size: 30
backend {
inputs: [ {
...
...
Prev
1
…
3
4
5
6
7
8
9
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment